plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/000077500000000000000000000000001321604176500215175ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/.gitignore000066400000000000000000000000111321604176500234770ustar00rootroot00000000000000*~ \#*\# plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/AUTHORS.TXT000066400000000000000000000014121321604176500232430ustar00rootroot00000000000000Plastimatch is a collaborative effort. Contributors include: MGH: Greg Sharp, Ziji Wu, Marta Peroni, Justin Lee, Rui Li, Nadya Shusharina, Joost Verburg, Matt Bieniosek, Qi Yang, Willem Rohl-Hill, Justin Phillips, Yang-Kyun Park, Karl Fritscher Drexel: Nagarajan Kandasamy, Harman Singh, Christopher Sagedy, James Shackleford, Chatura Atapattu, Dustin Houck, Ronald O'Brien, Michael Partel OHSU: Anthony Eden, Junan Zhang radART/Salzburg: Phil Steininger, Markus Neuner, Heinz Deutschmann UNICZ: Paolo Zaffino POLIMI: Chiara Paganelli, Maxime Desplanques Ga Tech: Yifei Lou Queen's U: Andras Lasso, Csaba Pinter If you have contributed to plastimatch, and you would like to add your name, please email to Greg Sharp, gcsharp a@t partners dot org. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/CMakeLists.txt000066400000000000000000001030041321604176500242550ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## Welcome to the Plastimatch CMakeLists.txt file ##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (plastimatch) ## The version here should be equal to the "most recent release" set (PLM_VERSION_MAJOR "1") set (PLM_VERSION_MINOR "7") set (PLM_VERSION_PATCH "0") #set (PLM_RELEASE_VERSION FALSE) set (PLM_RELEASE_VERSION TRUE) ##----------------------------------------------------------------------------- ## Set up CMake defaults ##----------------------------------------------------------------------------- cmake_minimum_required (VERSION 2.8.12) # CMP0003: Libraries linked via full path no longer produce linker search # paths. if (POLICY CMP0003) cmake_policy (SET CMP0003 NEW) endif () # CMP0012: if() recognizes numbers and boolean constants. # GCS 2012-03-04: This is added to suppress ITK warning if (POLICY CMP0012) cmake_policy (SET CMP0012 NEW) endif () # CMP0017: Prefer files from the CMake module directory when including # from there. if (POLICY CMP0017) cmake_policy (SET CMP0017 NEW) endif () # CMP0054: Quoted variables no longer dereferenced # GCS 2017-11-02: This is added to suppress Qt warnings if (POLICY CMP0054) cmake_policy (SET CMP0054 NEW) endif () ##----------------------------------------------------------------------------- ## CMake include files ##----------------------------------------------------------------------------- set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) ##----------------------------------------------------------------------------- ## Prevent in-source build ##----------------------------------------------------------------------------- include (PreventInSourceBuilds) ##----------------------------------------------------------------------------- ## Macros and functions used in this script ##----------------------------------------------------------------------------- include (PlmMacros) include (SuperbuildOptions) ##----------------------------------------------------------------------------- ## Define default build type as Release ##----------------------------------------------------------------------------- if (NOT CMAKE_BUILD_TYPE) set (CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) endif () sb_variable (CMAKE_BUILD_TYPE) ##----------------------------------------------------------------------------- ## Define plastimatch configuration variables ##----------------------------------------------------------------------------- sb_option (PLM_CONFIG_DISABLE_CUDA "Set to ON to build without CUDA" OFF) option (PLM_CONFIG_DISABLE_DCMTK "Set to ON to build without DCMTK" OFF) option (PLM_CONFIG_DISABLE_FATM "Set to ON to build without FATM" ON) option (PLM_CONFIG_DISABLE_MONDOSHOT "Disable building mondoshot" ON) sb_option (PLM_CONFIG_DISABLE_OPENCL "Set to ON to build without OpenCL" OFF) sb_option (PLM_CONFIG_DISABLE_OPENMP "Set to ON to build without OpenMP" OFF) option (PLM_CONFIG_DISABLE_PLASTIMATCH "Disable building plastimatch" OFF) option (PLM_CONFIG_DISABLE_QT "Set to ON to build without QT" OFF) sb_option (PLM_CONFIG_DISABLE_SSE2 "Set to ON to build without SSE" OFF) option (PLM_CONFIG_ENABLE_MATLAB "Set to ON to build Matlab plugins" OFF) option (PLM_CONFIG_BUILD_QT_PLUGINS "Build QT4 Designer Plugins?" OFF) sb_option (PLM_CONFIG_DEBIAN_BUILD "Set to ON to configure build for debian" OFF) option (PLM_CONFIG_LIBRARY_BUILD "Set to ON to build only libraries" OFF) option (PLM_CONFIG_NOMANIFEST "Set to ON to build windows DLLs without manifests" OFF) option (PLM_CONFIG_ENABLE_SUPERBUILD "Set to ON to allow src/plastimatch to be built using nested superbuild" ON) # Plastimatch software configuration options option (PLM_CONFIG_CLANG_COMPLETE "Generate .clang_complete for hipster Vim-ers" OFF) option (PLM_CONFIG_DISABLE_VISCOUS "Disable experimental viscous fluid registration algorithm" ON) option (PLM_CONFIG_ENABLE_PLASTIMATCH_QT "Enable experimental plastimatch_qt executable" OFF) sb_option (PLM_CONFIG_PREFER_PATCHED_ITK "Prefer to use the patched version of certain ITK files" ON) sb_option (PLM_CONFIG_VOL_LIST "Native support for volumes with irregular slice thicknesses" OFF) # Plastimatch legacy options sb_option (PLM_CONFIG_LEGACY_BSPLINE_EXTEND "Use legacy code for extending b-spline domain" OFF) sb_option (PLM_CONFIG_LEGACY_BSPLINE_XFORM_IO "Use legacy code for reading and writing b-spline xform files" OFF) sb_option (PLM_CONFIG_LEGACY_MI_METRIC "For ITK metrics, the legacy implementation of the mi metric is Viola-Wells to Mattes" OFF) sb_option (PLM_CONFIG_LEGACY_PROJ_GEO "Use legacy method for specifying projection geometry" ON) # Compile and link options sb_option (BUILD_SHARED_LIBS "Build plastimatch as shared library" OFF) # Choose whether to build against included and/or superbuild libraries # instead of system libraries sb_option_enum (PLM_SYSTEM_DCMTK "Prefer DCMTK provided by operating system" PREFERRED NO PREFERRED YES) sb_option (PLM_PREFER_SYSTEM_DLIB "Prefer the system dlib over the included dlib" ON) sb_option_enum (PLM_SYSTEM_ITK "Prefer ITK provided by operating system" PREFERRED NO PREFERRED YES) # Testing sb_option (PLM_BUILD_TESTING "Enable regression testing" ON) # Installer Options option (PLM_INSTALL_RPATH "Add full RPATH to install" OFF) sb_option (PLM_CONFIG_INSTALL_LIBRARIES "Include libraries in install" ON) # Packaging option (PLM_PACKAGE_32BIT "Set this when building 32-bit packages on a 64-bit machine" OFF) option (PLM_PACKAGE_NSIS "Set to ON when packaging binaries with NSIS" OFF) option (PLM_PACKAGE_WIX "Set to ON when packaging binaries with WIX" OFF) sb_option (PLM_PACKAGE_LEGACY_CMAKE_CONFIG "Use the old code for creating PlastimatchConfig.cmake and friends" OFF) # Use legacy packaging if cmake version is < 3.0 if (CMAKE_VERSION VERSION_LESS "3.0") set (PLM_PACKAGE_LEGACY_CMAKE_CONFIG ON CACHE BOOL "Use legacy packaging routines") endif () # Override some options if library build is selected if (PLM_CONFIG_LIBRARY_BUILD) set (PLM_CONFIG_DISABLE_FATM ON) set (PLM_CONFIG_DISABLE_MONDOSHOT ON) endif () ##----------------------------------------------------------------------------- ## Setup important locations ##----------------------------------------------------------------------------- sb_set (PLM_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") sb_set (PLM_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") # Offer the user the choice of overriding the installation directories set (PLM_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") set (PLM_INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") set (PLM_INSTALL_INCLUDE_DIR include/plastimatch CACHE PATH "Installation directory for header files") if (WIN32 AND NOT CYGWIN) set (DEF_INSTALL_CMAKE_DIR CMake) else() set (DEF_INSTALL_CMAKE_DIR lib/cmake/plastimatch) endif() set (PLM_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") mark_as_advanced ( PLM_INSTALL_LIB_DIR PLM_INSTALL_BIN_DIR PLM_INSTALL_INCLUDE_DIR PLM_INSTALL_CMAKE_DIR) # GCS 2015-07-08. The below workflow is described here: # http://www.cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file # However, it creates install targets with absolute paths, which is # not allowed for NSIS targets. # It is possible this is resolved by newer documentation, which is referred # by the above link: # http://www.cmake.org/cmake/help/git-master/manual/cmake-packages.7.html#creating-packages # Needs further investigation # Make relative install paths absolute (needed later on) if (PLM_PACKAGE_LEGACY_CMAKE_CONFIG) foreach (p LIB BIN INCLUDE CMAKE) set (var PLM_INSTALL_${p}_DIR) if (NOT IS_ABSOLUTE "${${var}}") set (${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") endif () endforeach () endif () ##----------------------------------------------------------------------------- ## CMake include files ##----------------------------------------------------------------------------- include (CTest) include (CheckFunctionExists) # http://www.cmake.org/pipermail/cmake/2008-December/025886.html # http://www.cmake.org/Bug/view.php?id=15117 set (CMAKE_INSTALL_OPENMP_LIBRARIES ON) if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 3.1) include (InstallRequiredSystemLibrariesPatched) else () include (InstallRequiredSystemLibraries) endif () # Superbuild include (ExternalProject) ##----------------------------------------------------------------------------- ## Disable spurious warnings on MSVC (version 8 & higher) ##----------------------------------------------------------------------------- if (WIN32 AND NOT CYGWIN AND NOT MINGW) add_definitions( -D_CRT_FAR_MAPPINGS_NO_DEPRECATE -D_CRT_IS_WCTYPE_NO_DEPRECATE -D_CRT_MANAGED_FP_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_DEPRECATE_GLOBALS -D_CRT_SETERRORMODE_BEEP_SLEEP_NO_DEPRECATE -D_CRT_TIME_FUNCTIONS_NO_DEPRECATE -D_CRT_VCCLRIT_NO_DEPRECATE -D_SCL_SECURE_NO_DEPRECATE # _SCL_SECURE_NO_DEPRECATE became _SCL_SECURE_NO_WARNINGS in VC9 -D_SCL_SECURE_NO_WARNINGS ) endif () ##----------------------------------------------------------------------------- ## Compile with -fPIC is needed for amd64 and other platforms ##----------------------------------------------------------------------------- plm_set_pic_flags () ##----------------------------------------------------------------------------- ## Extra paths ##----------------------------------------------------------------------------- set (PLM_TESTING_SOURCE_DIR "${CMAKE_SOURCE_DIR}/Testing") set (PLM_TESTING_DATA_DIR "${CMAKE_SOURCE_DIR}/Testing/Data") set (PLM_TESTING_DOWNLOAD_DATA_DIR "${CMAKE_BINARY_DIR}/TestData") set (PLM_BUILD_TESTING_DIR "${CMAKE_BINARY_DIR}/Testing") ##----------------------------------------------------------------------------- ## Set the math library ##----------------------------------------------------------------------------- if (UNIX) set (MATH_LIB -lm) else () set (MATH_LIB) endif () ##----------------------------------------------------------------------------- ## Libdl ##----------------------------------------------------------------------------- # Some systems such as pcBSD don't have libdl find_library (LIBDL_FOUND dl) ##----------------------------------------------------------------------------- ## DCMTK ##----------------------------------------------------------------------------- ## If it is a modern version of DCMTK, such as found in Slicer build, ## it will have a working version of DCMTKConfig.cmake. ## In this case, we can use the modern find_package variant. ## Otherwise we use the old hacked version of FindDCMTK.cmake. if (NOT PLM_CONFIG_DISABLE_DCMTK) if (PLM_SYSTEM_DCMTK STREQUAL "YES") if (DCMTK_DIR AND EXISTS "${DCMTK_DIR}/DCMTKConfig.cmake") find_package (DCMTK NO_MODULE REQUIRED) else () find_package (DCMTK_legacy REQUIRED) endif () elseif (PLM_SYSTEM_DCMTK STREQUAL "PREFERRED") if (DCMTK_DIR AND EXISTS "${DCMTK_DIR}/DCMTKConfig.cmake") find_package (DCMTK NO_MODULE QUIET) else () find_package (DCMTK_legacy QUIET) endif () endif () if (NOT DCMTK_FOUND AND NOT PLM_SYSTEM_DCMTK STREQUAL "YES") include (SuperBuild/External_DCMTK.cmake) message (STATUS "DCMTK will be downloaded and built.") else () if (DCMTK_FOUND) message (STATUS "DCMTK version ${DCMTK_VERSION} found.") else () message (STATUS "DCMTK not found.") endif () endif () endif () # Workaround for CMake bug in FindDCMTK. This was fixed some time between # 3.4.3 and 3.7.2 # if (CMAKE_VERSION VERSION_LESS "3.7.2" AND DCMTK_ofstd_INCLUDE_DIR) # get_filename_component(_tmp ${DCMTK_ofstd_INCLUDE_DIR} PATH) # get_filename_component(_tmp ${_tmp} PATH) # list (APPEND DCMTK_INCLUDE_DIRS ${_tmp}) # endif () ##----------------------------------------------------------------------------- ## Search for libraries ##----------------------------------------------------------------------------- find_package (Etags) find_package (FFTW) find_package (Git) find_package (Kaze) find_package (Liblbfgs) find_package (NLopt) if (PLM_CONFIG_ENABLE_MATLAB) find_package (Matlab) else () set (MATLAB_FOUND false) endif () find_package (Octave) if (NOT PLM_CONFIG_DISABLE_OPENCL) find_package (OpenCL) endif () if (NOT PLM_CONFIG_DISABLE_OPENMP) find_package (OpenMP) endif () if (PLM_CONFIG_DEBIAN_BUILD) set (SQLITE_FOUND false) else () find_package (SQLite) endif () if (NOT PLM_CONFIG_DISABLE_SSE2) find_package (SSE) # SSE Extensions for CPU else () set (SSE2_FOUND false) endif () find_package (TR1) find_package (wxWidgets) ##----------------------------------------------------------------------------- ## Use local libsbfgs if not found ##----------------------------------------------------------------------------- if (NOT LIBLBFGS_FOUND) add_subdirectory (libs/liblbfgs-1.9) sb_set (LIBLBFGS_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/libs/liblbfgs-1.9/include") sb_set (LIBLBFGS_LIBRARIES lbfgs) link_directories (${CMAKE_CURRENT_BINARY_DIR}/libs/liblbfgs-1.9) sb_set (LIBLBFGS_FOUND TRUE) endif () ##----------------------------------------------------------------------------- ## Use local sqlite if not found ##----------------------------------------------------------------------------- if (NOT SQLITE_FOUND AND NOT PLM_CONFIG_DEBIAN_BUILD) add_subdirectory (libs/sqlite-3.6.21) set (SQLITE_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/libs/sqlite-3.6.21") set (SQLITE_LIBRARIES sqlite3) set (SQLITE_FOUND TRUE) endif () #----------------------------------------------------------------------------- ## Only use local devillard ##----------------------------------------------------------------------------- sb_set (DEVILLARD_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/libs/devillard") add_subdirectory (libs/devillard) ##----------------------------------------------------------------------------- ## Only use local inih ##----------------------------------------------------------------------------- sb_set (INIH_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/libs/inih-r29") add_subdirectory (libs/inih-r29) ##----------------------------------------------------------------------------- ## LUA 5.1.4 ##----------------------------------------------------------------------------- # We can't use debian's lua 5.1 because it doesn't contain lobject.h #add_subdirectory (libs/lua-5.1.4) #set (LUA_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/libs/lua-5.1.4/src") #link_directories (${CMAKE_CURRENT_BINARY_DIR}/libs/lua-5.1.4) # for history, etc in plastimatch tty mode #find_package (Readline) #find_library (TERMCAP_LIBRARY termcap) ##----------------------------------------------------------------------------- ## Only use local specfun ##----------------------------------------------------------------------------- add_subdirectory (libs/specfun) link_directories (${CMAKE_CURRENT_BINARY_DIR}/libs/specfun) sb_set (SPECFUN_FOUND TRUE) ##----------------------------------------------------------------------------- ## Only use local msinttypes ##----------------------------------------------------------------------------- sb_set (MSINTTYPES_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/libs") ##----------------------------------------------------------------------------- ## Only use local nkidecompress ##----------------------------------------------------------------------------- sb_set (NKIDECOMPRESS_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/libs/nkidecompress") add_subdirectory (libs/nkidecompress) ##----------------------------------------------------------------------------- ## Special CUDA processing ##----------------------------------------------------------------------------- if (PLM_CONFIG_DISABLE_CUDA) set (CUDA_FOUND false) else () find_package (CUDA_wrap) set (CUDA_FOUND ${CUDA_FOUND} CACHE BOOL "Did we find cuda?") if (CUDA_FOUND) cuda_include_directories (${CMAKE_CURRENT_SOURCE_DIR}) endif () endif () ##----------------------------------------------------------------------------- ## Thrust ##----------------------------------------------------------------------------- find_package (Thrust) ##----------------------------------------------------------------------------- ## JAS 10.28.2010 ## nvcc automatically passed the flag -malign-double to gcc when compiling .cu ## files. This can be a problem when structs are shared between ## .c & .cu files on 32-bit machines. So, we pass -malign-double to gcc ## for .c files as well so that everybody is using the same alignment. ## -malign-double is automatically passed to gcc for 64-bit architectures. ## ## GCS 2010-10-30 ## -malign-double should only be enabled for 32-bit machines. gcc 4.1.2 ## gives an error if it is used on x86_64. ## ## GCS 2011-07-21 ## -malign-double is not compatible with ITK. Need a fix soon... ## ## JAS 2011-07-23 ## I have disabled -malign-double passing to gcc/g++ compiled objects and ## have taken to manually byte aligning structures that are passed to ## nvcc compiled objects. (See double_align8 typedef in bspline.h) ## Hopefully this will solve the problem. ##----------------------------------------------------------------------------- #if (CUDA_FOUND AND CMAKE_COMPILER_IS_GNUCC AND MACHINE_IS_32_BIT) # if (CMAKE_C_FLAGS) # set (CMAKE_C_FLAGS "-malign-double") # else () # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -malign-double") # endif () # if (CMAKE_CXX_FLAGS) # set (CMAKE_CXX_FLAGS "-malign-double") # else () # set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -malign-double") # endif () #endif () ##----------------------------------------------------------------------------- ## Doxygen ##----------------------------------------------------------------------------- find_package (Doxygen) ##----------------------------------------------------------------------------- ## For shared libraries, we enable dynamic loading of cuda, opencl ## Note: we can't use BUILD_SHARED_LIBS directly, because it conflicts ## with the ITK header files ##----------------------------------------------------------------------------- set (PLM_USE_GPU_PLUGINS OFF) if (BUILD_SHARED_LIBS) set (PLM_USE_GPU_PLUGINS ON) endif () ##----------------------------------------------------------------------------- ## Special linking instructions on unix ## http://www.cmake.org/Wiki/CMake_RPATH_handling ##----------------------------------------------------------------------------- if (PLM_INSTALL_RPATH) # use, i.e. don't skip the full RPATH for the build tree set (CMAKE_SKIP_BUILD_RPATH FALSE) # when building, don't use the install RPATH already # (but later on when installing) set (CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) # the RPATH to be used when installing set (CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") # add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH set (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) endif () ##----------------------------------------------------------------------------- ## User feedback on which languages and libraries were found ##----------------------------------------------------------------------------- if (wxWidgets_FOUND) message (STATUS "Looking for wxWidgets - found.") else () message (STATUS "Looking for wxWidgets - not found.") endif () if (Matlab_FOUND) message (STATUS "Looking for Matlab - found.") else () message (STATUS "Looking for Matlab - not found.") endif () if (OCTAVE_FOUND) message (STATUS "Looking for Octave - found.") else () message (STATUS "Looking for Octave - not found.") endif () ##----------------------------------------------------------------------------- ## Set version string ##----------------------------------------------------------------------------- set (PLM_BASIC_VERSION_STRING "${PLM_VERSION_MAJOR}.${PLM_VERSION_MINOR}.${PLM_VERSION_PATCH}") set (PLASTIMATCH_VERSION_STRING "${PLM_VERSION_MAJOR}.${PLM_VERSION_MINOR}.${PLM_VERSION_PATCH}") if (NOT PLM_RELEASE_VERSION) set (PLASTIMATCH_VERSION_STRING "${PLASTIMATCH_VERSION_STRING}-dev") endif () if (EXISTS "${CMAKE_SOURCE_DIR}/.git" AND GIT_FOUND) execute_process ( COMMAND #${GIT_EXECUTABLE} rev-list --first-parent --count HEAD ${GIT_EXECUTABLE} describe --always WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" RESULT_VARIABLE git_result OUTPUT_VARIABLE git_version ERROR_VARIABLE git_error OUTPUT_STRIP_TRAILING_WHITESPACE ) if (${git_result} EQUAL 0) set (PLASTIMATCH_VERSION_STRING "${PLASTIMATCH_VERSION_STRING} (${git_version})") endif () message (STATUS "Plastimatch version is ${git_version}") endif () ##----------------------------------------------------------------------------- ## ITK ##----------------------------------------------------------------------------- if (PLM_SYSTEM_ITK STREQUAL "YES") find_package (ITK REQUIRED) elseif (PLM_SYSTEM_ITK STREQUAL "PREFERRED") find_package (ITK QUIET) endif () if (NOT ITK_FOUND AND NOT PLM_SYSTEM_ITK STREQUAL "YES") message (STATUS "ITK will be downloaded and built.") include (SuperBuild/External_ITK.cmake) endif () if (ITK_FOUND) include (HandleITK) endif () ##----------------------------------------------------------------------------- ## GDCM ##----------------------------------------------------------------------------- if (NOT DCMTK_FOUND AND ITK_FOUND) # The default case is that ITK_USE_SYSTEM_GDCM was used, # the gdcm use file was already loaded from UseITK.cmake, and therefore # GDCM_VERSION is already known. If this is not the case, we look # in the ITK build dir for the header file which contains the version. if (NOT GDCM_VERSION) unset (GDCM_CONFIGURE_H CACHE) find_file (GDCM_CONFIGURE_H gdcmConfigure.h PATHS ${ITK_INCLUDE_DIRS}) if (GDCM_CONFIGURE_H) file (STRINGS "${GDCM_CONFIGURE_H}" GDCM_VERSION REGEX "^#define GDCM_VERSION *\"([^\"]*)\"") string (REGEX REPLACE "[^\"]*\"([^\"]*)\".*" "\\1" GDCM_VERSION "${GDCM_VERSION}") endif () # When GDCM config file does not configure correctly, the value of # the version might be "@GDCM_VERSION@". if ("${GDCM_VERSION}" STREQUAL "\@GDCM_VERSION@") set (GDCM_VERSION "2.0") endif () set (GDCM_FOUND 1) endif () if (GDCM_VERSION) message (STATUS "GDCM version ${GDCM_VERSION} found") else () message (FATAL_ERROR "Found ITK, but didn't find GDCM") endif () if (GDCM_VERSION VERSION_LESS "2.0") set (GDCM_VERSION_1 1) else () set (GDCM_VERSION_2 1) endif () else () # No itk? Use dcmtk instead endif () ##----------------------------------------------------------------------------- ## QT ##----------------------------------------------------------------------------- if (PLM_CONFIG_DISABLE_QT) set (QT4_FOUND false) set (QT5_FOUND false) else () find_package (Qt4 4.6.3 QUIET COMPONENTS QtCore QtGui QtDesigner) find_package (Qt5 QUIET COMPONENTS Core Gui Designer Network Widgets) endif () if (QT4_FOUND) # Test Qt install to make sure it can build and run a test program include (CheckQt) check_qt (QT_TEST_COMPILE_SUCCEEDED) if (NOT QT_TEST_COMPILE_SUCCEEDED) message (STATUS "Qt failed to compile a test program") set (QT4_FOUND false) endif () endif () if (QT4_FOUND) # Debian qtchooser is broken, so we disable. # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=730423 execute_process ( COMMAND rcc RESULT_VARIABLE rcc_result OUTPUT_VARIABLE rcc_output ERROR_VARIABLE rcc_error) if (${rcc_error} MATCHES "could not find a Qt installation") message (STATUS "Sorry, your Qt build environment is broken") set (QT4_FOUND FALSE) else () message (STATUS "Looking for Qt4 - found") #include (${QT_USE_FILE}) endif () else () message (STATUS "Looking for Qt4 - not found") endif () if (Qt5_FOUND) message (STATUS "Looking for Qt5 - found") else () message (STATUS "Looking for Qt5 - not found") endif () ##----------------------------------------------------------------------------- ## Only use local rapidjson ##----------------------------------------------------------------------------- set (RAPIDJSON_DIR "${CMAKE_SOURCE_DIR}/libs/rapidjson-2015-03-22") if (EXISTS "${RAPIDJSON_DIR}" AND IS_DIRECTORY "${RAPIDJSON_DIR}") set (RAPIDJSON_INCLUDE_DIR "${RAPIDJSON_DIR}/include" ) set (RAPIDJSON_FOUND true) endif () ##----------------------------------------------------------------------------- ## libyaml ##----------------------------------------------------------------------------- find_package (LibYAML) ##----------------------------------------------------------------------------- ## Configure include files ##----------------------------------------------------------------------------- set (PLM_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) ##----------------------------------------------------------------------------- ## Subdirectories ##----------------------------------------------------------------------------- add_subdirectory (src) ##----------------------------------------------------------------------------- ## Additional install files ##----------------------------------------------------------------------------- if (ITK_FOUND) file (GLOB DLLFILES "${ITK_DIR}/bin/release/*.dll") if (DLLFILES) install (FILES ${DLLFILES} DESTINATION bin) endif () endif () #Add QT dlls to Install if (QT4_FOUND) if (UNIX) # YKP: should be implemented soon else () set (QT4_CORE_DLL_WIN "${QT_LIBRARY_DIR}/QtCore4.dll") set (QT4_GUI_DLL_WIN "${QT_LIBRARY_DIR}/QtGui4.dll") if (EXISTS "${QT4_CORE_DLL_WIN}") install (FILES "${QT4_CORE_DLL_WIN}" DESTINATION bin) endif () if (EXISTS "${QT4_GUI_DLL_WIN}") install (FILES "${QT4_GUI_DLL_WIN}" DESTINATION bin) endif () endif () endif () #Add FFT dlls to Install if (FFTW_FOUND) if (EXISTS "${FFTW_DIR}/libfftw3-3.dll") install (FILES "${FFTW_DIR}/libfftw3-3.dll" DESTINATION bin) endif () #YKP 05/27/2016: no need of libfftw3f-3.dll and libfftw3l-3.dll? endif () # Add sample directory/files to Install Only for windows users if (WIN32 OR WIN64) set (PLM_WINDOWS_INSTALL_DIR "${CMAKE_SOURCE_DIR}/extra/windows-install") install (DIRECTORY "${PLM_WINDOWS_INSTALL_DIR}/sample" DESTINATION bin) install (FILES "${PLM_WINDOWS_INSTALL_DIR}/launch_cmd_prompt.bat" DESTINATION bin) endif () # JAS 2011.01.24 # I have moved the documentation DESTINATION from # /usr/doc to /usr/share/doc/plastimatch/ for Linux/UNIX if (UNIX) # FHS compliant path for Linux/UNIX set (DOC_DESTINATION "share/doc/plastimatch") else () # Just throw TXTs into a doc folder for Windows set (DOC_DESTINATION "doc") endif () install (FILES README.TXT src/plastimatch/COPYRIGHT.TXT DESTINATION ${DOC_DESTINATION} ) # Debian doesn't like INSTALL, LICENSE included in documentation if (NOT PLM_CONFIG_DEBIAN_BUILD) install (FILES INSTALL.TXT src/plastimatch/LICENSE.TXT DESTINATION ${DOC_DESTINATION} ) endif () ##----------------------------------------------------------------------------- ## MAKE UNINSTALL ##----------------------------------------------------------------------------- if (UNIX) configure_file ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target (uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) endif () ##----------------------------------------------------------------------------- ## Regression testing ##----------------------------------------------------------------------------- ## * Tests need to be launched from a script, because CTest is not able ## to add the ITK DLL directory to the path. We use CMAKE as scripting ## language to avoid requirement of outside package (e.g. python) ## * "Release" is hard coded. There is (apparently) no easy way to ## avoid this (i.e. no good suggestions on CMake/CTest email list. ## This is the purpose of the PATH_HACK code below. ##----------------------------------------------------------------------------- if (WIN32 AND NOT CYGWIN AND NOT MINGW) set (PLM_PLASTIMATCH_PATH ${PLM_BINARY_DIR}/Release) set (PLM_PLASTIMATCH_TESTING_PATH ${PLM_BINARY_DIR}/Testing/Release) set (PLM_FFTW_PATH ${FFTW_DIR}) # At some point in time (presumably around ITK 4.1), ITK stopped # creating the variable ITK_LIBRARY_DIRS. Therefore, we have to # use another method to find the ITK directory needed to run tests. if (NOT ITK_FOUND) set (PLM_ITK_LIBRARY_PATH_HACK -DITK_LIBRARY_PATH=${PLM_BINARY_DIR}/ITK-build/bin/Release) elseif (${ITK_VERSION} VERSION_LESS "4.1") set (PLM_ITK_LIBRARY_PATH_HACK -DITK_LIBRARY_PATH=${ITK_LIBRARY_DIRS}/Release) else () string (REGEX REPLACE "/[^/]*$" "" ITK_LIBRARY_DIRS_41 "${ITK_CONFIG_TARGETS_FILE}") set (PLM_ITK_LIBRARY_PATH_HACK -DITK_LIBRARY_PATH=${ITK_LIBRARY_DIRS_41}/bin/Release) endif () set (PLM_PLASTIMATCH_PATH_HACK -DPLM_PLASTIMATCH_PATH=${PLM_PLASTIMATCH_PATH}) set (PLM_FFTW_PATH_HACK -DPLM_FFTW_PATH=${PLM_FFTW_PATH}) else () set (PLM_PLASTIMATCH_PATH ${PLM_BINARY_DIR}) set (PLM_PLASTIMATCH_TESTING_PATH ${PLM_BINARY_DIR}/Testing) set (PLM_FFTW_PATH "${FFTW_DIR}") set (PLM_ITK_LIBRARY_PATH_HACK "") set (PLM_PLASTIMATCH_PATH_HACK "") set (PLM_FFTW_PATH_HACK "") endif () macro (PLM_ADD_TEST PLM_TEST_NAME PLM_TEST_COMMAND PARMS) # Optional extra parameters are passed through ${ARGN} # Allowed EXTRA_PARMS are: # "-DWORKING_DIR=XXX;-DEXPECTED_ERRNO=XXX" set (EXTRA_PARMS ${ARGV3}) # CMake doesn't allow "=" to be passed in a -D parameter. So we substitute # with replacement string, which will get substituted back within the # cmake script itself string (REPLACE "=" "&equal&" TMP_PARMS "${PARMS}") add_test (${PLM_TEST_NAME} ${CMAKE_COMMAND} -DPLM_TEST_NAME=${PLM_TEST_NAME} ${PLM_ITK_LIBRARY_PATH_HACK} ${PLM_PLASTIMATCH_PATH_HACK} ${PLM_FFTW_PATH_HACK} -DPLM_TEST_COMMAND=${PLM_TEST_COMMAND} -DPLM_TESTING_SOURCE_DIR=${PLM_TESTING_SOURCE_DIR} -DPLM_BUILD_TESTING_DIR=${PLM_BUILD_TESTING_DIR} "-DPARMS=${TMP_PARMS}" ${EXTRA_PARMS} -P ${CMAKE_SOURCE_DIR}/cmake/RUN_CTEST.cmake ) # message (STATUS "${CMAKE_COMMAND} -DPLM_TEST_NAME=${PLM_TEST_NAME} ${PLM_ITK_LIBRARY_PATH_HACK} ${PLM_PLASTIMATCH_PATH_HACK} ${PLM_FFTW_PATH_HACK} -DPLM_TEST_COMMAND=${PLM_TEST_COMMAND} -DPLM_TESTING_SOURCE_DIR=${PLM_TESTING_SOURCE_DIR} -DPLM_BUILD_TESTING_DIR=${PLM_BUILD_TESTING_DIR} \"-DPARMS=${TMP_PARMS}\" ${EXTRA_PARMS} -P ${CMAKE_SOURCE_DIR}/cmake/RUN_CTEST.cmake") endmacro () # Figure out which tests to ignore # Note: we need two copies, because unix users might run "make test" # in either directory. MSVC uses the one in ${CMAKE_BINARY_DIR}. configure_file ( ${PLM_TESTING_SOURCE_DIR}/CTestCustom.cmake.in ${CMAKE_BINARY_DIR}/CTestCustom.cmake @ONLY) configure_file ( ${PLM_TESTING_SOURCE_DIR}/CTestCustom.cmake.in ${CMAKE_BINARY_DIR}/Testing/CTestCustom.cmake @ONLY) if (PLM_BUILD_TESTING) enable_testing () add_subdirectory (Testing) # Copy the lconv script if (EXISTS "${CMAKE_SOURCE_DIR}/extra/devtools/run_lcov.sh") configure_file ( "${CMAKE_SOURCE_DIR}/extra/devtools/run_lcov.sh" "${CMAKE_BINARY_DIR}/run_lcov.sh" COPYONLY) endif () endif () ##----------------------------------------------------------------------------- ## Packaging ##----------------------------------------------------------------------------- ## Simple version: "make package_source" to create tarball ## ## Advanced version: to generate... ## * zip : cpack -G ZIP ## * tar.bz2: cpack -G TBZ2 ## ## ...from within your build directory ##----------------------------------------------------------------------------- # Choose generator if (PLM_PACKAGE_WIX) set (CPACK_GENERATOR "WIX") elseif (PLM_PACKAGE_NSIS) set (CPACK_GENERATOR "NSIS") else () set (CPACK_GENERATOR "ZIP") endif () set (CPACK_SOURCE_GENERATOR "TBZ2") # For WiX install, and possibly for debian -dev targets, # we should properly set up the install components. # Until then, let's just kill it set (CPACK_MONOLITHIC_INSTALL 1) # General stuff set (CPACK_INSTALL_PREFIX "") set (CPACK_PACKAGE_CONTACT "plastimatch@googlegroups.com") set (CPACK_PACKAGE_NAME "plastimatch") set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Plastimatch - A Medical Imaging Application") set (CPACK_PACKAGE_VENDOR "Plastimatch Dev Team") set (CPACK_PACKAGE_VERSION_MAJOR "${PLM_VERSION_MAJOR}") set (CPACK_PACKAGE_VERSION_MINOR "${PLM_VERSION_MINOR}") set (CPACK_PACKAGE_VERSION_PATCH "${PLM_VERSION_PATCH}") set (CPACK_PACKAGE_VERSION_TWEAK ${PLASTIMATCH_REPOSITORY_VERSION}) set (CPACK_SOURCE_IGNORE_FILES "/\\\\.git" "/\\\\.svn" "~$" ) # NSIS stuff #set(CPACK_NSIS_INSTALLED_ICON_NAME "${APP_LOW_NAME}.ico") set (CPACK_NSIS_HELP_LINK "http://plastimatch.org") set (CPACK_NSIS_URL_INFO_ABOUT "http://plastimatch.org") set (CPACK_NSIS_CONTACT "plastimatch@googlegroups.com") set (PLM_NSIS_VERSION_STRING "${PLM_VERSION_MAJOR}.${PLM_VERSION_MINOR}.${PLM_VERSION_PATCH} (${PLASTIMATCH_REPOSITORY_VERSION})") # WIX stuff set (CPACK_WIX_HELP_LINK "http://plastimatch.org") set (CPACK_WIX_UPGRADE_GUID "AA7C7964-14D7-4890-9CD1-EA1D80E4DC8C") set (CPACK_WIX_LICENSE_RTF "${PLM_WINDOWS_INSTALL_DIR}/License.rtf") set (CPACK_WIX_UI_BANNER "${PLM_WINDOWS_INSTALL_DIR}/plm_logo.jpg") set (CPACK_WIX_UI_DIALOG "${PLM_WINDOWS_INSTALL_DIR}/plm_logo_GUI.jpg") # ZIP stuff if (CPACK_GENERATOR STREQUAL "ZIP") set (CPACK_SET_DESTDIR ON) endif () include (CPack) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/CTestConfig.cmake000066400000000000000000000017041321604176500246730ustar00rootroot00000000000000## This file should be placed in the root directory of your project. ## Then modify the CMakeLists.txt file in the root directory of your ## project to incorporate the testing dashboard. ## # The following are required to uses Dart and the Cdash dashboard ## ENABLE_TESTING() ## INCLUDE(CTest) set(CTEST_PROJECT_NAME "Plastimatch") set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "cdash.tshack.net") set(CTEST_DROP_LOCATION "/submit.php?project=Plastimatch") set(CTEST_DROP_SITE_CDASH TRUE) #set(CTEST_DROP_METHOD "http") #set(CTEST_DROP_SITE "my.cdash.org") #set(CTEST_DROP_LOCATION "/submit.php?project=Plastimatch") #set(CTEST_DROP_SITE_CDASH TRUE) #set(CTEST_DROP_METHOD "http") #if(SITE STREQUAL "newspeak") # set(CTEST_DROP_SITE "cdash.tshack.net") #else() # set(CTEST_DROP_SITE "my.cdash.org") #endif() #set(CTEST_DROP_LOCATION "/submit.php?project=Plastimatch") #set(CTEST_DROP_SITE_CDASH TRUE) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/INSTALL.TXT000066400000000000000000000000761321604176500232310ustar00rootroot00000000000000Please visit http://plastimatch.org/ for install information. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/LICENSE.TXT000066400000000000000000000002451321604176500232030ustar00rootroot00000000000000Plastimatch and uno-2-3-reg are distributed under BSD-style licenses. Please see src/plastimatch/LICENSE.TXT and src/uno-2-3-reg/LICENSE.txt for license details. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/README.TXT000066400000000000000000000017661321604176500230670ustar00rootroot00000000000000 *** Welcome to Plastimatch *** Plastimatch is a computer software application which has been designed for volumetric (usually medical) image processing and radiation therapy therapy applications. It can be used for the following purposes: 1) Deformable registration 2) Atlas-based segmentation 3) Image conversion and manipulation 4) Vector field conversion and manipulation 5) Gamma analysis 6) Dose calculation 7) Registration analysis (Jacobian) 8) Segmentation analysis (Dice, Hausdorff) 9) Many other things For online documentation, please visit: http://plastimatch.org Questions, comments, bug reports? Please post: https://groups.google.com/d/forum/plastimatch Plastimatch is open source software, and can be used, modified, and distributed, without cost, under a BSD-style license. This software is intended for research use only, and is not approved by the Food and Drug Administration (FDA) for clinical use. Please see LICENSE.TXT for details. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/SuperBuild/000077500000000000000000000000001321604176500235755ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/SuperBuild/External_DCMTK.cmake000066400000000000000000000025531321604176500273100ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## Download DCMTK from internet and compile ##----------------------------------------------------------------------------- set (proj DCMTK) set (dcmtk_url ftp://dicom.offis.de/pub/dicom/offis/software/dcmtk/dcmtk362/dcmtk-3.6.2.tar.gz) set (dcmtk_md5sum d219a4152772985191c9b89d75302d12) ExternalProject_Add (${proj} DOWNLOAD_DIR ${proj}-download URL ${dcmtk_url} URL_MD5 ${dcmtk_md5sum} SOURCE_DIR ${proj} BINARY_DIR ${proj}-build CMAKE_GENERATOR ${gen} CMAKE_ARGS -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} # -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=${CMAKE_CXX_STANDARD_REQUIRED} -DCMAKE_CXX_EXTENSIONS:BOOL=${CMAKE_CXX_EXTENSIONS} -DBUILD_APPS:BOOL=OFF ## GCS 2017-12-14: "Temporarily" force static library to reduce changes ## needed to run regression tests on Windows. When time allows, ## this should be built as a shared library. # -DBUILD_SHARED_LIBS:BOOL=ON -DBUILD_SHARED_LIBS:BOOL=OFF -DDCMTK_OVERWRITE_WIN32_COMPILER_FLAGS:BOOL=OFF INSTALL_COMMAND "" ) set (DCMTK_DIR ${CMAKE_BINARY_DIR}/${proj}-build) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/SuperBuild/External_ITK.cmake000077500000000000000000000022131321604176500270710ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## Download ITK from internet and compile ##----------------------------------------------------------------------------- set (proj ITK) set (itk_url https://downloads.sourceforge.net/project/itk/itk/4.12/InsightToolkit-4.12.2.tar.gz) set (itk_md5sum 758206eeb458d11b7ba2d81d8a3ce212) ExternalProject_Add (${proj} DOWNLOAD_DIR ${proj}-download URL ${itk_url} URL_MD5 ${itk_md5sum} SOURCE_DIR ${proj} BINARY_DIR ${proj}-build CMAKE_GENERATOR ${gen} CMAKE_ARGS -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} # -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=${CMAKE_CXX_STANDARD_REQUIRED} -DCMAKE_CXX_EXTENSIONS:BOOL=${CMAKE_CXX_EXTENSIONS} -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=ON -DBUILD_TESTING:BOOL=OFF -DModule_ITKReview:BOOL=ON INSTALL_COMMAND "" ) set (ITK_DIR ${CMAKE_BINARY_DIR}/${proj}-build) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/000077500000000000000000000000001321604176500231345ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/CMakeLists.txt000077500000000000000000005462451321604176500257170ustar00rootroot00000000000000project (PLM_Testing) ## ------------------------------------------------------------------------- ## TODO: create targets like "make check plm-reg-bsp-a" ## http://stackoverflow.com/questions/733475/cmake-ctest-make-test-doesnt-build-tests ## ------------------------------------------------------------------------- ## ------------------------------------------------------------------------- ## Note on test dependencies. Some versions of cmake (e.g. Windows cmake ## version 2.8.2) have a bug where the dependency graph is created ## incorrectly. Specifically, if B depends on A, and C depends on ## both A and B, the graph will be generated incorrectly. ## ------------------------------------------------------------------------- ## ------------------------------------------------------------------------- ## Test and data download options ## ------------------------------------------------------------------------- option (PLM_REDUCED_TESTS "Run fewer tests (used when debugging tests)" OFF) option (PLM_DOWNLOAD_TEST_DATA "Additional testing data (download from internet)" OFF) ##----------------------------------------------------------------------------- ## Configure test input files ##----------------------------------------------------------------------------- set (CONFIG_FILE_LIST "plm-bsp-mse-c.txt" "plm-bsp-mse-h.txt" "plm-bsp-mse-k.txt" "plm-bsp-mse-l.txt" "plm-bsp-mi-c.txt" "plm-bsp-mi-k.txt" "plm-bsp-gm-k.txt" "plm-bsp-dmap-k.txt" "plm-bsp-sm-multi-a.txt" "plm-bsp-cuda.txt" "plm-bsp-rect.txt" "plm-bsp-resume.txt" "plm-bsp-logfile.txt" "plm-bsp-dcos-a.txt" "plm-bsp-dcos-b.txt" "plm-bsp-dcos-c.txt" "plm-bsp-dcos-d.txt" "plm-bsp-dcos-e.txt" "plm-bsp-dcos-f.txt" "plm-bsp-landmark-a.txt" "plm-bsp-landmark-b.txt" "plm-bsp-landmark-c.txt" "plm-bsp-landmark-d.txt" "plm-bsp-landmark-e.txt" "plm-bsp-double.txt" "plm-bsp-regularize-numeric.txt" "plm-reg-align-center.txt" "plm-reg-itk-translation.txt" "plm-reg-roi-a.txt" "plm-reg-roi-b.txt" "plm-reg-roi-c.txt" "plm-reg-roi-d.txt" "plm-reg-roi-e.txt" "plm-reg-stiffness-a.txt" "plm-reg-multi-a.txt" "plm-reg-multi-b.txt" "plm-reg-dv-itk-translation.txt" "plm-reg-itk-rigid-a.txt" "plm-reg-itk-rigid-b.txt" "plm-reg-itk-similarity.txt" "plm-reg-itk-bspline.txt" "plm-reg-process-a.txt" "plm-reg-trans-a.txt" "plm-reg-trans-b.txt" "plm-reg-trans-mi-a.txt" "plm-reg-autores-a.txt" "plm-reg-autores-b.txt" "plm-reg-gw-a.txt" "proton-dose-1.txt" "proton-dose-2.txt" "proton-dose-4.txt" "proton-dose-5a.txt" "proton-dose-5d.txt" "proton-dose-6a.txt" "speedtest-a.txt" "wed-a.txt" "wed-b.txt" "wed-c.txt" ) foreach (CONFIG_FILE ${CONFIG_FILE_LIST}) string (REGEX REPLACE "\\.txt$" "" PLM_TEST_NAME ${CONFIG_FILE}) configure_file ("${PLM_TESTING_DATA_DIR}/${CONFIG_FILE}" "${PLM_BUILD_TESTING_DIR}/${CONFIG_FILE}" @ONLY) endforeach () ## ------------------------------------------------------------------------- ## Testing macros ## ------------------------------------------------------------------------- macro (plmtest_check_interval test_name stdout_file regex_string lower_thresh upper_thresh) string (REPLACE "\\" "\\\\" regex_escaped "${regex_string}") add_test (${test_name} ${CMAKE_COMMAND} "-DINFILE=${stdout_file}" "-DREGEX=${regex_escaped}" "-DLOWER_THRESH=${lower_thresh}" "-DUPPER_THRESH=${upper_thresh}" -P "${PLM_TESTING_SOURCE_DIR}/PlmCheckInterval.cmake" ) endmacro () macro (plmtest_check_string test_name stdout_file regex_string match_string) string (REPLACE "\\" "\\\\" regex_escaped "${regex_string}") add_test (${test_name} ${CMAKE_COMMAND} "-DINFILE=${stdout_file}" "-DREGEX=${regex_escaped}" "-DMATCH_STRING=${match_string}" -P "${PLM_TESTING_SOURCE_DIR}/PlmCheckString.cmake" ) endmacro () macro (plmtest_debug test_name stdout_file stderr_file) add_test (${test_name} ${CMAKE_COMMAND} "-DSTDOUT_FILE=${stdout_file}" "-DSTDERR_FILE=${stderr_file}" -P "${PLM_TESTING_SOURCE_DIR}/PlmTestDebug.cmake" ) endmacro () ## ------------------------------------------------------------------------- ## Download data sets ## ------------------------------------------------------------------------- macro (plm_download_and_extract DOWNLOAD_URL DOWNLOAD_FILENAME DOWNLOAD_DIR) if (NOT IS_DIRECTORY "${PLM_TESTING_DOWNLOAD_DATA_DIR}") file (MAKE_DIRECTORY "${PLM_TESTING_DOWNLOAD_DATA_DIR}") endif () set (download_retries 3) while (NOT EXISTS ${DOWNLOAD_FILENAME} AND download_retries) message (STATUS "Downloading test data: ${DOWNLOAD_FILENAME}") file (DOWNLOAD "${DOWNLOAD_URL}" "${DOWNLOAD_FILENAME}" STATUS download_status) message (STATUS "Download status[${download_retries}]: ${download_status}") list (GET download_status 0 dl_status) if (dl_status) math (EXPR download_retries "${download_retries}-1") endif () endwhile () if (NOT EXISTS ${DOWNLOAD_DIR}) message (STATUS "Untarring test data: ${DOWNLOAD_FILENAME}") execute_process ( COMMAND ${CMAKE_COMMAND} "-E" "tar" "xvzf" "${DOWNLOAD_FILENAME}" WORKING_DIRECTORY ${PLM_BUILD_TESTING_DIR} RESULT_VARIABLE untar_result OUTPUT_VARIABLE untar_output ERROR_VARIABLE untar_error) message (STATUS "Untar command returned: ${untar_result}\n${untar_output}\n${untar_error}") endif () endmacro () if (PLM_DOWNLOAD_TEST_DATA) plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/dicomrt-33-structures.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/dicomrt-33-structures.tar.gz" "${PLM_BUILD_TESTING_DIR}/dicomrt-33-structures") plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/dicomrt-aw-4.4-foot.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/dicomrt-aw-4.4-foot.tar.gz" "${PLM_BUILD_TESTING_DIR}/dicomrt-aw-4.4-foot") plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/dicomrt-corvus-6.2.2.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/dicomrt-corvus-6.2.2.tar.gz" "${PLM_BUILD_TESTING_DIR}/dicomrt-corvus-6.2.2") plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/dicomrt-pinnacle3-8.2g-rando.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/dicomrt-pinnacle3-8.2g-rando.tar.gz" "${PLM_BUILD_TESTING_DIR}/dicomrt-pinnacle3-8.2g-rando") plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/dicomrt-xio-4.33.02-chest-phantom.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/dicomrt-xio-4.33.02-chest-phantom.tar.gz" "${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.33.02-chest-phantom") plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/dicomrt-xio-4.60-irregular-spacing.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/dicomrt-xio-4.60-irregular-spacing.tar.gz" "${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.60-irregular-spacing") plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/headphantom.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/headphantom.tar.gz" "${PLM_BUILD_TESTING_DIR}/headphantom") plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/rtog-corvus-6.2.2.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/rtog-corvus-6.2.2.tar.gz" "${PLM_BUILD_TESTING_DIR}/rtog-corvus-6.2.2") plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/varian-catphan-subset.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/varian-catphan-subset.tar.gz" "${PLM_BUILD_TESTING_DIR}/varian-catphan-subset") plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/xio-4.33.02-chest-phantom.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/xio-4.33.02-chest-phantom.tar.gz" "${PLM_BUILD_TESTING_DIR}/xio-4.33.02-chest-phantom") plm_download_and_extract ( "https://sourceforge.net/projects/plastimatch/files/Sample%20Data/xio-4.60-irregular-spacing.tar.gz/download" "${PLM_TESTING_DOWNLOAD_DATA_DIR}/xio-4.60-irregular-spacing.tar.gz" "${PLM_BUILD_TESTING_DIR}/xio-4.60-irregular-spacing") endif () ## ------------------------------------------------------------------------- ## Custom test command ## ------------------------------------------------------------------------- add_custom_target (speedtest ${CMAKE_COMMAND} -DPLM_PLASTIMATCH_PATH="${PLM_PLASTIMATCH_PATH}" -DPLM_BUILD_TESTING_DIR="${PLM_BUILD_TESTING_DIR}" -P "${PLM_TESTING_SOURCE_DIR}/PlmSpeedTest.cmake" ) ## ------------------------------------------------------------------------- ## Test cases ## ------------------------------------------------------------------------- ## Create synthetic images ## black-1 All black, slightly different geometry ## donut-1 Centered donut ## gabor-xx Fibonacci Gabor ## gauss-1 Centered gauss ## gauss-2 Off-center gauss ## gauss-3 Inverted gauss ## gauss-4 Gauss with inverted pixel spacing ## gauss-5 Even more off-center gauss ## gauss-6 Off-center gauss, in off-center world coordinates ## gauss-7 Off-center gauss with wider sigma ## gauss-ushort-1 Centered gauss, ushort ## gauss-ushort-2 Off-center gauss, ushort ## lung-1 Synthetic lung, tumor position 0 ## lung-2 Synthetic lung, tumor position -5 ## gw-lung-a Synthetic lung, tumor position -5, in gw dir ## gw-lung-b Synthetic lung, tumor position 0, in gw dir ## gw-lung-c Synthetic lung, tumor position +5, in gw dir ## ptv-1 rect PTV target for dose calculation ## ptv-2 rect PTV target for dose calculation, smaller geometry ## rect-1 Inverted rect, centered ## rect-2 Standard rect, off-center ## rect-3 Standard rect, centered ## rect-4 Uchar rect, centered ## rect-5 Standard rect, centered, direction cosines alt-1 ## rect-6 Standard rect, centered, direction cosines alt-2 ## rect-7 Standard rect, centered, direction cosines alt-3 ## rect-8 Uchar rect, off-center ## rect-9 Uchar rect, centered, higher resolution ## rect-10-roi-1 ## rect-10-roi-2 ## rect-10 ## rect-11 ## rect-11-roi ## rect-12 Small rect, bg=0, fg=10 ## rect-13 Small rect, bg=0, fg=11 ## rect-14 Small, off-center rect, bg=0, fg=10 ## rect-15 Standard rect, slicer direction cosines ## rect-16 Off-center rect, slicer direction cosines ## rect-17 Water phantom, resolution 5x5x5, for dose calculation ## rect-18 Water phantom, very low resolution 20x20, dose calc. ## rect-19 Standard, but larger rectangle ## rectarr-01 Two rectangles, both centered ## rectarr-02 Two rectangles, lower rect offset ## rectarr-m-01 Upper mask for rectarr-01 and rectarr-02 ## rectarr-m-02 Lower mask for rectarr-01 and rectarr-02 ## rectarr-03 Two rectangles, both centered (for testing gamma) ## rectarr-04 Two rectangles, lower rect offset (for testing gamma) ## roi-1 left = 0, right = 1 ## rgc-1 rect range compensator for dose calculation ## sphere-1 Uchar sphere, bg=0, fg=255 ## sphere-2 Standard sphere, centered ## sphere-3 Standard, bg=0, fg=1 ## sphere-4 Standard, radius = 150 ## ------------------------------------------------------------------------- set (SYNTH_MHA_SIZE 38) plm_add_test ( "black-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/black-1.mha;--output-type;float;--pattern;rect;--origin;-25 -25 -25;--dim;40 40 40;--volume-size;50 50 50;--background;-1000;--foreground;-1000" ) plm_add_test ( "donut-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/donut-1.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/donut-1-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/donut-1-ss-list.txt;--output-type;float;--pattern;donut;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--donut-radius;10 10 10;--background;-1000;--foreground;0;--dicom-with-uids;false;--output-dicom;${PLM_BUILD_TESTING_DIR}/donut-1-dicom;--output-prefix;${PLM_BUILD_TESTING_DIR}/donut-1-prefix/" ) plm_add_test ( "gabor-01" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gabor-01.mha;--pattern;gabor;--origin;-5 -5 -5;--dim;11 11 11;--spacing;1 1 1;--gabor-k-fib;0 1;--gauss-center;0 0 0;--gauss-std;3 3 3;--background;0;--foreground;1" ) plm_add_test ( "gauss-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output-type;float;--pattern;gauss;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;-1000;--foreground;0;--gauss-center;0 0 0;--gauss-std;10 10 10" ) plm_add_test ( "gauss-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-2.mha;--output-type;float;--pattern;gauss;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;-1000;--foreground;0;--gauss-center;10 0 0;--gauss-std;10 10 10" ) plm_add_test ( "gauss-3" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-3.mha;--output-type;float;--pattern;gauss;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;0;--foreground;-1000;--gauss-center;10 0 0;--gauss-std;10 10 10" ) plm_add_test ( "gauss-4" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-4.mha;--output-type;float;--pattern;gauss;--origin;+25 +25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--spacing;-1.31579 -1.31579 2;--background;-1000;--foreground;0;--gauss-center;0 0 0;--gauss-std;10 10 10" ) plm_add_test ( "gauss-5" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-5.mha;--output-type;float;--pattern;gauss;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;-1000;--foreground;0;--gauss-center;20 0 0;--gauss-std;10 10 10" ) plm_add_test ( "gauss-6" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-6.mha;--output-type;float;--pattern;gauss;--origin;-15 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;-1000;--foreground;0;--gauss-center;10 0 0;--gauss-std;10 10 10" ) plm_add_test ( "gauss-7" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-7.mha;--output-type;float;--pattern;gauss;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;-1000;--foreground;0;--gauss-center;10 0 0;--gauss-std;20 20 20" ) plm_add_test ( "gauss-double-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-double-1.mha;--output-type;double;--pattern;gauss;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;0;--foreground;1000;--gauss-center;0 0 0;--gauss-std;10 10 10" ) plm_add_test ( "gauss-double-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-double-2.mha;--output-type;double;--pattern;gauss;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;0;--foreground;1000;--gauss-center;10 0 0;--gauss-std;10 10 10" ) plm_add_test ( "gauss-ushort-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-ushort-1.mha;--output-type;ushort;--pattern;gauss;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;0;--foreground;1000;--gauss-center;0 0 0;--gauss-std;10 10 10" ) plm_add_test ( "gauss-ushort-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gauss-ushort-2.mha;--output-type;ushort;--pattern;gauss;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;0;--foreground;1000;--gauss-center;10 0 0;--gauss-std;10 10 10" ) plm_add_test ( "lung-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--dicom-with-uids;false;--output;${PLM_BUILD_TESTING_DIR}/lung-1.mha;--output-prefix;${PLM_BUILD_TESTING_DIR}/lung-1-prefix;--output-dicom;${PLM_BUILD_TESTING_DIR}/lung-1-dicom;--pattern;lung;--lung-tumor-pos;0" ) plm_add_test ( "lung-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--dicom-with-uids;false;--output;${PLM_BUILD_TESTING_DIR}/lung-2.mha;--output-dicom;${PLM_BUILD_TESTING_DIR}/lung-2-dicom;--pattern;lung;--lung-tumor-pos;-5" ) plm_add_test ( "gw-lung-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gw/lung-a.mha;--pattern;lung;--lung-tumor-pos;-5" ) plm_add_test ( "gw-lung-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gw/lung-b.mha;--pattern;lung;--lung-tumor-pos;0" ) plm_add_test ( "gw-lung-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/gw/lung-c.mha;--pattern;lung;--lung-tumor-pos;5" ) plm_add_test ( "ptv-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/ptv-1.mha;--pattern;rect;--dim;60 60 60;--background;0;--foreground;6;--rect-size;20 20 20;--origin;-150 -150 -150;--spacing;5 5 5" ) plm_add_test ( "ptv-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/ptv-2.mha;--pattern;rect;--dim;40 40 40;--background;0;--foreground;6;--rect-size;20 20 20;--origin;-100 -100 -100;--spacing;5 5 5" ) plm_add_test ( "rect-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--dicom-with-uids;false;--output;${PLM_BUILD_TESTING_DIR}/rect-1.mha;--output-type;float;--output-dose-img;${PLM_BUILD_TESTING_DIR}/rect-1-dose-img.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/rect-1-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/rect-1-ss-list.txt;--output-dicom;${PLM_BUILD_TESTING_DIR}/rect-1-dicom;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;0;--foreground;-1000" ) plm_add_test ( "rect-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-2.mha;--output-type;float;--output-dicom;${PLM_BUILD_TESTING_DIR}/rect-2-dicom;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--rect-size;-30 70 -50 50 -50 50" ) plm_add_test ( "rect-2s" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--spacing;13.158 13.158 13.158;--rect-size; 200 200 200;--output;${PLM_BUILD_TESTING_DIR}/rect-2s.mha" ) plm_add_test ( "rect-3" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-3.mha;--output-type;float;--output-dicom;${PLM_BUILD_TESTING_DIR}/rect-3-dicom;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--rect-size;-50 50 -50 50 -50 50" ) plm_add_test ( "rect-4" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-4.mha;--output-type;uchar;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;0;--foreground;1;--rect-size;-50 50 -50 50 -50 50" ) plm_add_test ( "rect-5" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-5.mha;--output-type;float;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--rect-size;-50 50 -50 50 -50 50;--origin;-300 -150 -250;--direction-cosines;rotated-1" ) plm_add_test ( "rect-6" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-6.mha;--output-type;float;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--rect-size;-50 50 -50 50 -50 50;--origin;0 -300 -200;--direction-cosines;rotated-2" ) plm_add_test ( "rect-7" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-7.mha;--output-type;float;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--rect-size;-50 50 -50 50 -50 50;--origin;100 300 -100;--direction-cosines;rotated-3" ) plm_add_test ( "rect-8" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-8.mha;--output-type;uchar;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;0;--foreground;1;--rect-size;-30 70 -50 50 -50 50" ) plm_add_test ( "rect-9" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-9.mha;--output-type;uchar;--pattern;rect;--dim;47 47 47;--background;0;--foreground;1;--rect-size;-50 50 -50 50 -50 50" ) plm_add_test ( "rect-10" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-10.mha;--output-type;float;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--rect-size;-200 50 -50 50 -50 50" ) plm_add_test ( "rect-10-roi-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-10-roi-1.mha;--output-type;uchar;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;0;--foreground;1;--rect-size;-60 60 -60 60 -60 60" ) plm_add_test ( "rect-10-roi-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-10-roi-2.mha;--output-type;uchar;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;0;--foreground;1;--rect-size;-220 60 -60 60 -60 60" ) plm_add_test ( "rect-11" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-11.mha;--output-type;float;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;0;--foreground;-1000;--rect-size;-40 60 -40 60 -40 60" ) plm_add_test ( "rect-11-roi" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-11-roi.mha;--output-type;uchar;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;0;--foreground;1;--rect-size;-50 80 -50 80 -50 80" ) plm_add_test ( "rect-12" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-12.mha;--output-type;float;--pattern;rect;--dim;20 20 20;--origin;-9.5 -9.5 -9.5;--spacing;1 1 1;--background;0;--foreground;10;--rect-size;-4.5 4.5 -4.5 4.5 -4.5 4.5" ) plm_add_test ( "rect-13" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-13.mha;--output-type;float;--pattern;rect;--dim;20 20 20;--origin;-9.5 -9.5 -9.5;--spacing;1 1 1;--background;0;--foreground;11;--rect-size;-4.5 4.5 -4.5 4.5 -4.5 4.5" ) plm_add_test ( "rect-14" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-14.mha;--output-type;float;--pattern;rect;--dim;20 20 20;--origin;-9.5 -9.5 -9.5;--spacing;1 1 1;--background;0;--foreground;10;--rect-size;-2.5 6.5 -4.5 4.5 -4.5 4.5" ) plm_add_test ( "rect-15" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-15.mha;--output-type;float;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--rect-size;-50 50 -50 50 -50 50;--origin;243.421 243.421 -243.421;--spacing;13.1579 13.1579 13.1579;--direction-cosines;-1 0 0 0 -1 0 0 0 1" ) plm_add_test ( "rect-16" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-16.mha;--output-type;float;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--rect-size;-30 70 -50 50 -50 50;--origin;243.421 243.421 -243.421;--spacing;13.1579 13.1579 13.1579;--direction-cosines;-1 0 0 0 -1 0 0 0 1" ) plm_add_test ( "rect-17" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-17.mha;--pattern;rect;--dim;60 60 60;--background;-1000;--foreground;0;--rect-size;-100 100 -100 100 -100 100;--origin;-150 -150 -150;--spacing;5 5 5" ) plm_add_test ( "rect-18" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-18.mha;--pattern;rect;--dim;15 15 15;--background;-1000;--foreground;0;--rect-size;-100 100 -100 100 -100 100;--origin;-150 -150 -150;--spacing;20 20 20" ) plm_add_test ( "rect-19" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rect-19.mha;--output-type;float;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--rect-size;-150 150 -150 150 -150 150" ) plm_add_test ( "rectarr-01-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rectarr-01-a.mha;--output-type;float;--pattern;rect;--dim;30 50 30;--background;-1000;--foreground;0;--rect-size;-5 5 -15 -5 -5 5;--origin;-14.5 -24.5 -14.5;--spacing;1 1 1" ) plm_add_test ( "rectarr-01" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--input;${PLM_BUILD_TESTING_DIR}/rectarr-01-a.mha;--output;${PLM_BUILD_TESTING_DIR}/rectarr-01.mha;--output-type;float;--pattern;rect;--background;-1000;--foreground;0;--rect-size;-5 5 5 15 -5 5" ) plm_add_test ( "rectarr-02" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--input;${PLM_BUILD_TESTING_DIR}/rectarr-01-a.mha;--output;${PLM_BUILD_TESTING_DIR}/rectarr-02.mha;--output-type;float;--pattern;rect;--background;-1000;--foreground;0;--rect-size;-10 0 5 15 -5 5" ) set_property (TEST rectarr-01 APPEND PROPERTY DEPENDS rectarr-01-a) set_property (TEST rectarr-02 APPEND PROPERTY DEPENDS rectarr-01-a) plm_add_test ( "rectarr-m-01" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--fixed;rectarr-01-a.mha;--output;${PLM_BUILD_TESTING_DIR}/rectarr-m-01.mha;--output-type;uchar;--pattern;rect;--background;0;--foreground;1;--rect-size;-13 13 -20 0 -13 13" ) plm_add_test ( "rectarr-m-02" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--fixed;rectarr-01-a.mha;--output;${PLM_BUILD_TESTING_DIR}/rectarr-m-02.mha;--output-type;uchar;--pattern;rect;--background;0;--foreground;1;--rect-size;-13 13 0 20 -13 13" ) set_property (TEST rectarr-m-01 APPEND PROPERTY DEPENDS rectarr-01-a) set_property (TEST rectarr-m-02 APPEND PROPERTY DEPENDS rectarr-01-a) plm_add_test ( "rectarr-03-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rectarr-03-a.mha;--output-type;float;--pattern;rect;--dim;30 50 30;--background;0;--foreground;70;--rect-size;-5 5 -15 -5 -5 5;--origin;-14.5 -24.5 -14.5;--spacing;1 1 1" ) plm_add_test ( "rectarr-03" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--input;${PLM_BUILD_TESTING_DIR}/rectarr-03-a.mha;--output;${PLM_BUILD_TESTING_DIR}/rectarr-03.mha;--output-type;float;--pattern;rect;--background;0;--foreground;50;--rect-size;-5 5 5 15 -5 5" ) plm_add_test ( "rectarr-04" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--input;${PLM_BUILD_TESTING_DIR}/rectarr-03-a.mha;--output;${PLM_BUILD_TESTING_DIR}/rectarr-04.mha;--output-type;float;--pattern;rect;--background;0;--foreground;50;--rect-size;-10 0 5 15 -5 5" ) set_property (TEST rectarr-03 APPEND PROPERTY DEPENDS rectarr-03-a) set_property (TEST rectarr-04 APPEND PROPERTY DEPENDS rectarr-03-a) plm_add_test ( "rgc-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/rgc-1.mha;--output-type;float;--pattern;rect;--dim;10 10 1;--background;0;--foreground;30;--rect-size;0 10 0 5 0 0;--origin;0 0 0;--spacing;1 1 1" ) plm_add_test ( "roi-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/roi-1.mha;--output-type;uchar;--pattern;rect;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;0;--foreground;1;--rect-size;0 300 -300 300 -300 300" ) plm_add_test ( "sphere-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/sphere-1.mha;--output-type;uchar;--pattern;sphere;--origin;-25 -25 -25;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--volume-size;50 50 50;--background;0;--foreground;255;--sphere-center;0 0 0;--sphere-radius;10 10 10" ) plm_add_test ( "sphere-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/sphere-2.mha;--output-type;float;--pattern;sphere;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--sphere-center;0 0 0;--sphere-radius;50 50 50" ) plm_add_test ( "sphere-3" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/sphere-3.mha;--output-type;float;--pattern;sphere;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;0;--foreground;1;--sphere-center;0 0 0;--sphere-radius;50 50 50" ) plm_add_test ( "sphere-4" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/sphere-4.mha;--output-type;float;--pattern;sphere;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE};--background;-1000;--foreground;0;--sphere-center;0 0 0;--sphere-radius;150 150 150" ) plm_add_test ( "xramp-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/xramp-1.mha;--output-type;float;--pattern;xramp;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE}" ) plm_add_test ( "yramp-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/yramp-1.mha;--output-type;float;--pattern;yramp;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE}" ) plm_add_test ( "zramp-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth;--output;${PLM_BUILD_TESTING_DIR}/zramp-1.mha;--output-type;float;--pattern;zramp;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE}" ) ## ------------------------------------------------------------------------- ## Create synthetic vector fields ## vf-zero Zero vector field ## vf-trans-1 Translation x direction, 1cm ## vf-trans-2 Translation y direction, 1cm ## vf-radial-1 Radial warp, 1cm ## vf-gauss-1 Gaussian warp, 10cm std, 1cm x, 2cm y ## ------------------------------------------------------------------------- plm_add_test ( "vf-zero" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth-vf;--output;${PLM_BUILD_TESTING_DIR}/vf-zero.mha;--xf-zero;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE}" ) plm_add_test ( "vf-trans-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth-vf;--output;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha;--xf-trans;10 0 0;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE}" ) plm_add_test ( "vf-trans-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth-vf;--output;${PLM_BUILD_TESTING_DIR}/vf-trans-2.mha;--xf-trans;0 10 0;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE}" ) plm_add_test ( "vf-radial-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth-vf;--output;${PLM_BUILD_TESTING_DIR}/vf-radial-1.mha;--xf-radial;--radial-center;0 0 0;--radial-mag;10;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE}" ) plm_add_test ( "vf-gaussian-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "synth-vf;--output;${PLM_BUILD_TESTING_DIR}/vf-gaussian-1.mha;--xf-gauss;--gauss-center;0 0 0;--gauss-mag;10 20 0;--gauss-std;100 100 100;--dim;${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE} ${SYNTH_MHA_SIZE}" ) ## ------------------------------------------------------------------------- ## Test synthetic vector fields ## ------------------------------------------------------------------------- plm_add_test ( "vf-zero-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/vf-zero.mha" ) plmtest_check_interval ("vf-zero-check" "${PLM_BUILD_TESTING_DIR}/vf-zero-stats.stdout.txt" "Mean abs: *([-0-9.]*)" "0.000" "0.000" ) set_property (TEST vf-zero-stats APPEND PROPERTY DEPENDS vf-zero) set_property (TEST vf-zero-check APPEND PROPERTY DEPENDS vf-zero-stats) plm_add_test ( "vf-trans-1-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha" ) plmtest_check_interval ("vf-trans-1-check" "${PLM_BUILD_TESTING_DIR}/vf-trans-1-stats.stdout.txt" "Mean: *([-0-9.]*)" "10.000" "10.000" ) set_property (TEST vf-trans-1-stats APPEND PROPERTY DEPENDS vf-trans-1) set_property (TEST vf-trans-1-check APPEND PROPERTY DEPENDS vf-trans-1-stats) plm_add_test ( "vf-trans-2-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/vf-trans-2.mha" ) plmtest_check_interval ("vf-trans-2-check" "${PLM_BUILD_TESTING_DIR}/vf-trans-2-stats.stdout.txt" "Mean: *[-0-9.]* *([-0-9.]*)" "10.000" "10.000" ) set_property (TEST vf-trans-2-stats APPEND PROPERTY DEPENDS vf-trans-2) set_property (TEST vf-trans-2-check APPEND PROPERTY DEPENDS vf-trans-2-stats) plm_add_test ( "vf-radial-1-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/vf-radial-1.mha" ) plmtest_check_interval ("vf-radial-1-check" "${PLM_BUILD_TESTING_DIR}/vf-radial-1-stats.stdout.txt" "Mean abs: *([-0-9.]*)" "5.15" "5.16" ) set_property (TEST vf-radial-1-stats APPEND PROPERTY DEPENDS vf-radial-1) set_property (TEST vf-radial-1-check APPEND PROPERTY DEPENDS vf-radial-1-stats) ## ------------------------------------------------------------------------- ## bspline - bspline algorithm flavors ## ------------------------------------------------------------------------- plm_add_test ( "bspline-c" ${PLM_PLASTIMATCH_PATH}/bspline "-a;steepest;-m;10;-f;c;-x;${PLM_BUILD_TESTING_DIR}/bspline_c_xf.txt;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;${PLM_BUILD_TESTING_DIR}/gauss-2.mha" ) plmtest_check_interval (bspline-c-check "${PLM_BUILD_TESTING_DIR}/bspline-c.stdout.txt" "^\\\\[.*, 10] MSE *([0-9.]*)" "1168.25" "1168.35" ) set_property (TEST bspline-c APPEND PROPERTY DEPENDS gauss-1) set_property (TEST bspline-c APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (bspline-c-check PROPERTIES DEPENDS bspline-c) plm_add_test ( "bspline-g" ${PLM_PLASTIMATCH_PATH}/bspline "-a;steepest;-m;10;-f;g;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;${PLM_BUILD_TESTING_DIR}/gauss-2.mha" ) plmtest_check_interval (bspline-g-check "${PLM_BUILD_TESTING_DIR}/bspline-g.stdout.txt" "^\\\\[.*, 10] MSE *([0-9.]*)" "1168.25" "1168.35" ) set_property (TEST bspline-g APPEND PROPERTY DEPENDS gauss-1) set_property (TEST bspline-g APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (bspline-g-check PROPERTIES DEPENDS bspline-g) plm_add_test ( "bspline-h" ${PLM_PLASTIMATCH_PATH}/bspline "-a;steepest;-m;10;-f;h;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;${PLM_BUILD_TESTING_DIR}/gauss-2.mha" ) plmtest_check_interval (bspline-h-check "${PLM_BUILD_TESTING_DIR}/bspline-h.stdout.txt" "^\\\\[.*, 10] MSE *([0-9.]*)" "1168.25" "1168.35" ) set_property (TEST bspline-h APPEND PROPERTY DEPENDS gauss-1) set_property (TEST bspline-h APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (bspline-h-check PROPERTIES DEPENDS bspline-h) plm_add_test ( "bspline-mi-c-1" ${PLM_PLASTIMATCH_PATH}/bspline "-a;steepest;-m;10;-f;c;-M;mi;-B;20 20;-O;${PLM_BUILD_TESTING_DIR}/bspline-mi-c-1.mha;-x;${PLM_BUILD_TESTING_DIR}/bspline-mi-c-1.txt;-V;${PLM_BUILD_TESTING_DIR}/bspline-mi-c-1-vf.mha;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;${PLM_BUILD_TESTING_DIR}/gauss-3.mha" ) plmtest_check_interval (bspline-mi-c-1-check "${PLM_BUILD_TESTING_DIR}/bspline-mi-c-1.stdout.txt" "^\\\\[.*, 10] *MI *([-0-9.]*)" "-0.795" "-0.791" ) set_property (TEST bspline-mi-c-1 APPEND PROPERTY DEPENDS gauss-1) set_property (TEST bspline-mi-c-1 APPEND PROPERTY DEPENDS gauss-3) set_tests_properties (bspline-mi-c-1-check PROPERTIES DEPENDS bspline-mi-c-1) plm_add_test ( "bspline-mi-c-2" ${PLM_PLASTIMATCH_PATH}/bspline "-a;steepest;-m;10;-f;c;-M;mi;-O;${PLM_BUILD_TESTING_DIR}/bspline-mi-c-2.mha;${PLM_BUILD_TESTING_DIR}/rect-1.mha;${PLM_BUILD_TESTING_DIR}/rect-2.mha" ) ## Without DOUBLE_HIST defined, output is 0.031 ## With DOUBLE_HIST defined, output is 0.032 plmtest_check_interval (bspline-mi-c-2-check "${PLM_BUILD_TESTING_DIR}/bspline-mi-c-2.stdout.txt" "^\\\\[.*, 10] *MI *([-0-9.]*)" "-0.035" "-0.031" ) set_tests_properties (bspline-mi-c-2 PROPERTIES DEPENDS "rect-1;rect-2") set_tests_properties (bspline-mi-c-2-check PROPERTIES DEPENDS bspline-mi-c-2) ## ------------------------------------------------------------------------- ## demons ## demons-a gauss-1.mha, gauss-2.mha ## demons-cuda-a gauss-1.mha, gauss-2.mha ## *** 2011-10-30 ## Debian ARM gives value of 2.02. Normally the returned value ## is about 2.15, which would be tested for a range of 2.1 to 2.2 ## This has been changed to 1.95 to let ARM test pass. ## ------------------------------------------------------------------------- plm_add_test ( "demons-a" ${PLM_PLASTIMATCH_PATH}/demons "-m;50;-s;3;-f;5 5 5;-O;${PLM_BUILD_TESTING_DIR}/demons-a.mha;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;${PLM_BUILD_TESTING_DIR}/gauss-2.mha" ) plmtest_check_interval (demons-a-check "${PLM_BUILD_TESTING_DIR}/demons-a.stdout.txt" "^Mean: *([0-9.]*)" "3.4" "3.5" # "1.95" # "2.2" ) set_property (TEST demons-a APPEND PROPERTY DEPENDS gauss-1) set_property (TEST demons-a APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (demons-a-check PROPERTIES DEPENDS demons-a) plm_add_test ( "demons-cuda-a" ${PLM_PLASTIMATCH_PATH}/demons "-A;cuda;-m;50;-s;3;-f;5 5 5;-O;${PLM_BUILD_TESTING_DIR}/demons-cuda-a.mha;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;${PLM_BUILD_TESTING_DIR}/gauss-2.mha" ) plmtest_check_interval (demons-cuda-a-check "${PLM_BUILD_TESTING_DIR}/demons-cuda-a.stdout.txt" "^Mean: *([0-9.]*)" "2.1" "2.2" ) set_property (TEST demons-cuda-a APPEND PROPERTY DEPENDS gauss-1) set_property (TEST demons-cuda-a APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (demons-cuda-a-check PROPERTIES DEPENDS demons-cuda-a) ## ------------------------------------------------------------------------- ## drr ## drr-a gauss-1.mha (normal image), exact ## drr-b gauss-1.mha (normal image), uniform ## drr-c gauss-4.mha (negative spacing), exact ## drr-d gauss-4.mha (negative spacing), uniform ## drr-cuda gauss-1.mha, uniform ## drr-opencl gauss-1.mha, uniform ## ------------------------------------------------------------------------- plm_add_test ( "drr-a" ${PLM_PLASTIMATCH_PATH}/drr "-a;20;-O;${PLM_BUILD_TESTING_DIR}/drr-a/out_;${PLM_BUILD_TESTING_DIR}/gauss-1.mha" ) plm_add_test ( "drr-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/drr-a/out_0010.pfm" ) plmtest_check_interval ("drr-a-check" "${PLM_BUILD_TESTING_DIR}/drr-a-stats.stdout.txt" "MAX *([-0-9.]*)" "0.045" "0.055" ) set_tests_properties (drr-a PROPERTIES DEPENDS gauss-1) set_tests_properties (drr-a-stats PROPERTIES DEPENDS drr-a) set_tests_properties (drr-a-check PROPERTIES DEPENDS drr-a-stats) plm_add_test ( "drr-b" ${PLM_PLASTIMATCH_PATH}/drr "-a;20;-O;${PLM_BUILD_TESTING_DIR}/drr-b/out_;-i;uniform;${PLM_BUILD_TESTING_DIR}/gauss-1.mha" ) plm_add_test ( "drr-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;drr-b/out_0010.pfm" ) plmtest_check_interval ("drr-b-check" "${PLM_BUILD_TESTING_DIR}/drr-b-stats.stdout.txt" "MAX *([-0-9.]*)" "0.045" "0.055" ) set_tests_properties (drr-b PROPERTIES DEPENDS gauss-1) set_tests_properties (drr-b-stats PROPERTIES DEPENDS drr-b) set_tests_properties (drr-b-check PROPERTIES DEPENDS drr-b-stats) plm_add_test ( "drr-c" ${PLM_PLASTIMATCH_PATH}/drr "-a;20;-O;${PLM_BUILD_TESTING_DIR}/drr-c/out_;${PLM_BUILD_TESTING_DIR}/gauss-4.mha" ) plm_add_test ( "drr-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;drr-c/out_0010.pfm" ) plmtest_check_interval ("drr-c-check" "${PLM_BUILD_TESTING_DIR}/drr-c-stats.stdout.txt" "MAX *([-0-9.]*)" "0.045" "0.055" ) set_tests_properties (drr-c PROPERTIES DEPENDS gauss-4) set_tests_properties (drr-c-stats PROPERTIES DEPENDS drr-c) set_tests_properties (drr-c-check PROPERTIES DEPENDS drr-c-stats) plm_add_test ( "drr-d" ${PLM_PLASTIMATCH_PATH}/drr "-a;20;-O;${PLM_BUILD_TESTING_DIR}/drr-d/out_;-i;uniform;${PLM_BUILD_TESTING_DIR}/gauss-4.mha" ) plm_add_test ( "drr-d-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;drr-d/out_0010.pfm" ) plmtest_check_interval ("drr-d-check" "${PLM_BUILD_TESTING_DIR}/drr-d-stats.stdout.txt" "MAX *([-0-9.]*)" "0.045" "0.055" ) set_tests_properties (drr-d PROPERTIES DEPENDS gauss-1) set_tests_properties (drr-d-stats PROPERTIES DEPENDS drr-d) set_tests_properties (drr-d-check PROPERTIES DEPENDS drr-d-stats) plm_add_test ( "drr-cuda" ${PLM_PLASTIMATCH_PATH}/drr "-A;cuda;-a;20;-O;${PLM_BUILD_TESTING_DIR}/drr-cuda/out_;${PLM_BUILD_TESTING_DIR}/gauss-1.mha" ) plm_add_test ( "drr-cuda-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/drr-cuda/out_0010.pfm" ) plmtest_check_interval ("drr-cuda-check" "${PLM_BUILD_TESTING_DIR}/drr-cuda-stats.stdout.txt" "MAX *([-0-9.]*)" "0.045" "0.055" ) set_tests_properties (drr-cuda PROPERTIES DEPENDS gauss-1) set_tests_properties (drr-cuda-stats PROPERTIES DEPENDS drr-cuda) set_tests_properties (drr-cuda-check PROPERTIES DEPENDS drr-cuda-stats) plm_add_test ( "drr-opencl" ${PLM_PLASTIMATCH_PATH}/drr "-A;opencl;-a;20;-O;${PLM_BUILD_TESTING_DIR}/drr-opencl/out_;${PLM_BUILD_TESTING_DIR}/gauss-1.mha" ) plm_add_test ( "drr-opencl-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/drr-opencl/out_0010.pfm" ) plmtest_check_interval ("drr-opencl-check" "${PLM_BUILD_TESTING_DIR}/drr-opencl-stats.stdout.txt" "MAX *([-0-9.]*)" "0.045" "0.055" ) set_tests_properties (drr-opencl PROPERTIES DEPENDS gauss-1) set_tests_properties (drr-opencl-stats PROPERTIES DEPENDS drr-opencl) set_tests_properties (drr-opencl-check PROPERTIES DEPENDS drr-opencl-stats) ## ------------------------------------------------------------------------- ## fdk - all tests using fdk filtered backprojection ## fdk-cpu-a CPU reconstruction of synthetic data, flavor a ## fdk-cpu-b CPU reconstruction of Varian data, no filtering ## fdk-cpu-c CPU reconstruction of Varian data, fftw filtering ## fdk-cpu-d CPU reconstruction of synthetic data, flavor 0 ## fdk-cuda-a GPU reconstruction of synthetic data using CUDA ## [fdk-cuda-b GPU reconstruction of Varian data using CUDA ## fdk-opencl-a GPU reconstruction of synthetic data using OpenCL ## ------------------------------------------------------------------------- plm_add_test ( "fdk-cpu-a" ${PLM_PLASTIMATCH_PATH}/fdk "-I;${PLM_BUILD_TESTING_DIR}/drr-a;-f;none;-a;0 19;-O;${PLM_BUILD_TESTING_DIR}/fdk-cpu-a.mha" ) plm_add_test ( "fdk-cpu-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/fdk-cpu-a.mha" ) plmtest_check_interval ("fdk-cpu-a-check" "${PLM_BUILD_TESTING_DIR}/fdk-cpu-a-stats.stdout.txt" "MAX *([-0-9.]*)" "-987.5" "-986.5" ) set_tests_properties (fdk-cpu-a PROPERTIES DEPENDS drr-a) set_tests_properties (fdk-cpu-a-stats PROPERTIES DEPENDS fdk-cpu-a) set_tests_properties (fdk-cpu-a-check PROPERTIES DEPENDS fdk-cpu-a-stats) plm_add_test ( "fdk-cpu-b" ${PLM_PLASTIMATCH_PATH}/fdk "-I;${PLM_BUILD_TESTING_DIR}/varian-catphan-subset;-f;none;-a;0 20 670;-O;${PLM_BUILD_TESTING_DIR}/fdk-cpu-b.mha" ) plm_add_test ( "fdk-cpu-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/fdk-cpu-b.mha" ) plmtest_check_interval ("fdk-cpu-b-check" "${PLM_BUILD_TESTING_DIR}/fdk-cpu-b-stats.stdout.txt" "AVE *([-0-9.]*)" "-708.1" "-707.5" ) set_tests_properties (fdk-cpu-b-stats PROPERTIES DEPENDS fdk-cpu-b) set_tests_properties (fdk-cpu-b-check PROPERTIES DEPENDS fdk-cpu-b-stats) plm_add_test ( "fdk-cpu-c" ${PLM_PLASTIMATCH_PATH}/fdk "-I;${PLM_BUILD_TESTING_DIR}/varian-catphan-subset;-f;ramp;-a;0 50 670;-O;${PLM_BUILD_TESTING_DIR}/fdk-cpu-c.mha" ) plm_add_test ( "fdk-cpu-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/fdk-cpu-c.mha" ) plmtest_check_interval ("fdk-cpu-c-check" "${PLM_BUILD_TESTING_DIR}/fdk-cpu-c-stats.stdout.txt" "AVE *([-0-9.]*)" "-982.3" "-981.5" ) set_tests_properties (fdk-cpu-c-stats PROPERTIES DEPENDS fdk-cpu-c) set_tests_properties (fdk-cpu-c-check PROPERTIES DEPENDS fdk-cpu-c-stats) plm_add_test ( "fdk-cpu-d" ${PLM_PLASTIMATCH_PATH}/fdk "-I;${PLM_BUILD_TESTING_DIR}/drr-a;-X;0;-f;none;-a;0 19;-O;${PLM_BUILD_TESTING_DIR}/fdk-cpu-d.mha" ) plm_add_test ( "fdk-cpu-d-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/fdk-cpu-d.mha" ) plmtest_check_interval ("fdk-cpu-d-check" "${PLM_BUILD_TESTING_DIR}/fdk-cpu-d-stats.stdout.txt" "MAX *([-0-9.]*)" "-987.5" "-986.5" ) set_tests_properties (fdk-cpu-d PROPERTIES DEPENDS drr-a) set_tests_properties (fdk-cpu-d-stats PROPERTIES DEPENDS fdk-cpu-d) set_tests_properties (fdk-cpu-d-check PROPERTIES DEPENDS fdk-cpu-d-stats) plm_add_test ( "fdk-cuda-a" ${PLM_PLASTIMATCH_PATH}/fdk "-I;${PLM_BUILD_TESTING_DIR}/drr-a;-f;none;-A;cuda;-a;0 19;-O;${PLM_BUILD_TESTING_DIR}/fdk-cuda-a.mha" ) plm_add_test ( "fdk-cuda-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/fdk-cuda-a.mha" ) plmtest_check_interval ("fdk-cuda-a-check" "${PLM_BUILD_TESTING_DIR}/fdk-cuda-a-stats.stdout.txt" "MAX *([-0-9.]*)" "-987.5" "-986.5" ) set_tests_properties (fdk-cuda-a PROPERTIES DEPENDS drr-a) set_tests_properties (fdk-cuda-a-stats PROPERTIES DEPENDS fdk-cuda-a) set_tests_properties (fdk-cuda-a-check PROPERTIES DEPENDS fdk-cuda-a-stats) plm_add_test ( "fdk-opencl-a" ${PLM_PLASTIMATCH_PATH}/fdk "-I;${PLM_BUILD_TESTING_DIR}/drr-a;-f;none;-A;opencl;-a;0 19;-O;${PLM_BUILD_TESTING_DIR}/fdk-opencl-a.mha" ) plm_add_test ( "fdk-opencl-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/fdk-opencl-a.mha" ) plmtest_check_interval ("fdk-opencl-a-check" "${PLM_BUILD_TESTING_DIR}/fdk-opencl-a-stats.stdout.txt" "MAX *([-0-9.]*)" "-987.5" "-986.5" ) set_tests_properties (fdk-opencl-a PROPERTIES DEPENDS drr-a) set_tests_properties (fdk-opencl-a-stats PROPERTIES DEPENDS fdk-opencl-a) set_tests_properties (fdk-opencl-a-check PROPERTIES DEPENDS fdk-opencl-a-stats) ## ------------------------------------------------------------------------- ## fdk_tutorial - run the fdk tutorial ## ------------------------------------------------------------------------- plm_add_test ( "fdk-tutorial-a" ${PLM_PLASTIMATCH_PATH}/drr "-t;pfm;-a;60;-N;3;-g;1000 1500;-r;100 100;-z;300 300;-I;${PLM_BUILD_TESTING_DIR}/headphantom/headphantom.mha;-O;${PLM_BUILD_TESTING_DIR}/fdk-tutorial-a/" ) plm_add_test ( "fdk-tutorial-b" ${PLM_PLASTIMATCH_PATH}/fdk "-f;none;-r;100 100 100;-I;${PLM_BUILD_TESTING_DIR}/fdk-tutorial-a;-O;${PLM_BUILD_TESTING_DIR}/fdk-tutorial-b.mha" ) plm_add_test ( "fdk-tutorial-b-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/fdk-tutorial-b.mha" ) plmtest_check_interval ("fdk-tutorial-b-check-1" "${PLM_BUILD_TESTING_DIR}/fdk-tutorial-b-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-955.8" "-954.8" ) plm_add_test ( "fdk-tutorial-c" ${PLM_PLASTIMATCH_PATH}/fdk "-f;ramp;-r;100 100 100;-I;${PLM_BUILD_TESTING_DIR}/fdk-tutorial-a;-O;${PLM_BUILD_TESTING_DIR}/fdk-tutorial-c.mha" ) plm_add_test ( "fdk-tutorial-c-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/fdk-tutorial-c.mha" ) plmtest_check_interval ("fdk-tutorial-c-check-1" "${PLM_BUILD_TESTING_DIR}/fdk-tutorial-c-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-999.0" "-998.0" ) set_tests_properties (fdk-tutorial-b PROPERTIES DEPENDS fdk-tutorial-a) set_tests_properties (fdk-tutorial-b-stats-1 PROPERTIES DEPENDS fdk-tutorial-b) set_tests_properties (fdk-tutorial-b-check-1 PROPERTIES DEPENDS fdk-tutorial-b-stats-1) set_tests_properties (fdk-tutorial-c PROPERTIES DEPENDS fdk-tutorial-a) set_tests_properties (fdk-tutorial-c-stats-1 PROPERTIES DEPENDS fdk-tutorial-c) set_tests_properties (fdk-tutorial-c-check-1 PROPERTIES DEPENDS fdk-tutorial-c-stats-1) ## ------------------------------------------------------------------------- ## landmark_warp a: itk tps, slicer fcsv ## landmark_warp b: wendland rbf, slicer fcsv ## landmark_warp c: gauss rbf, slicer fcsv ## landmark_warp d: itk tps, slicer fcsv, -L option ## ------------------------------------------------------------------------- plm_add_test ( "landmark-warp-a" ${PLM_PLASTIMATCH_PATH}/landmark_warp "-a;tps;-f;${PLM_TESTING_DATA_DIR}/fiducials-rect-2.fcsv;-m;${PLM_TESTING_DATA_DIR}/fiducials-rect-3.fcsv;-I;${PLM_BUILD_TESTING_DIR}/rect-3.mha;-O;${PLM_BUILD_TESTING_DIR}/landmark-warp-a-img.mha;-V;${PLM_BUILD_TESTING_DIR}/landmark-warp-a-vf.mha" ) plm_add_test ( "landmark-warp-a-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/landmark-warp-a-img.mha" ) plmtest_check_interval ("landmark-warp-a-check-1" "${PLM_BUILD_TESTING_DIR}/landmark-warp-a-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-992.0" "-991.5" ) plm_add_test ( "landmark-warp-a-stats-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/landmark-warp-a-vf.mha" ) plmtest_check_interval ("landmark-warp-a-check-2" "${PLM_BUILD_TESTING_DIR}/landmark-warp-a-stats-2.stdout.txt" "Mean: *([-0-9.]*)" "-23.2" "-22.7" ) set_tests_properties (landmark-warp-a PROPERTIES DEPENDS rect-3) set_tests_properties (landmark-warp-a-stats-1 PROPERTIES DEPENDS landmark-warp-a) set_tests_properties (landmark-warp-a-check-1 PROPERTIES DEPENDS landmark-warp-a-stats-1) set_tests_properties (landmark-warp-a-stats-2 PROPERTIES DEPENDS landmark-warp-a) set_tests_properties (landmark-warp-a-check-2 PROPERTIES DEPENDS landmark-warp-a-stats-2) plm_add_test ( "landmark-warp-b" ${PLM_PLASTIMATCH_PATH}/landmark_warp "-a;wendland;-f;${PLM_TESTING_DATA_DIR}/fiducials-rect-2.fcsv;-m;${PLM_TESTING_DATA_DIR}/fiducials-rect-3.fcsv;-I;${PLM_BUILD_TESTING_DIR}/rect-3.mha;-O;${PLM_BUILD_TESTING_DIR}/landmark-warp-b-img.mha;-V;${PLM_BUILD_TESTING_DIR}/landmark-warp-b-vf.mha;-r;90;-d;0;-Y;0.0" ) plm_add_test ( "landmark-warp-b-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/landmark-warp-b-img.mha" ) plmtest_check_interval ("landmark-warp-b-check-1" "${PLM_BUILD_TESTING_DIR}/landmark-warp-b-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-992.2" "-991.8" ) plm_add_test ( "landmark-warp-b-stats-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/landmark-warp-b-vf.mha" ) plmtest_check_interval ("landmark-warp-b-check-2" "${PLM_BUILD_TESTING_DIR}/landmark-warp-b-stats-2.stdout.txt" "Mean: *([-0-9.]*)" "-1.55" "-1.4" ) set_tests_properties (landmark-warp-b PROPERTIES DEPENDS rect-3) set_tests_properties (landmark-warp-b-stats-1 PROPERTIES DEPENDS landmark-warp-b) set_tests_properties (landmark-warp-b-check-1 PROPERTIES DEPENDS landmark-warp-b-stats-1) set_tests_properties (landmark-warp-b-stats-2 PROPERTIES DEPENDS landmark-warp-b) set_tests_properties (landmark-warp-b-check-2 PROPERTIES DEPENDS landmark-warp-b-stats-2) plm_add_test ( "landmark-warp-c" ${PLM_PLASTIMATCH_PATH}/landmark_warp "-a;gauss;-f;${PLM_TESTING_DATA_DIR}/fiducials-rect-2.fcsv;-m;${PLM_TESTING_DATA_DIR}/fiducials-rect-3.fcsv;-I;${PLM_BUILD_TESTING_DIR}/rect-3.mha;-O;${PLM_BUILD_TESTING_DIR}/landmark-warp-c-img.mha;-V;${PLM_BUILD_TESTING_DIR}/landmark-warp-c-vf.mha;-r;74;-d;0;-Y;1.0" ) plm_add_test ( "landmark-warp-c-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/landmark-warp-c-img.mha" ) plmtest_check_interval ("landmark-warp-c-check-1" "${PLM_BUILD_TESTING_DIR}/landmark-warp-c-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-992.0" "-991.5" ) plm_add_test ( "landmark-warp-c-stats-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/landmark-warp-c-vf.mha" ) plmtest_check_interval ("landmark-warp-c-check-2" "${PLM_BUILD_TESTING_DIR}/landmark-warp-c-stats-2.stdout.txt" "Mean: *([-0-9.]*)" "-1.6" "-1.5" ) set_tests_properties (landmark-warp-c PROPERTIES DEPENDS rect-3) set_tests_properties (landmark-warp-c-stats-1 PROPERTIES DEPENDS landmark-warp-c) set_tests_properties (landmark-warp-c-check-1 PROPERTIES DEPENDS landmark-warp-c-stats-1) set_tests_properties (landmark-warp-c-stats-2 PROPERTIES DEPENDS landmark-warp-c) set_tests_properties (landmark-warp-c-check-2 PROPERTIES DEPENDS landmark-warp-c-stats-2) plm_add_test ( "landmark-warp-d" ${PLM_PLASTIMATCH_PATH}/landmark_warp "-a;tps;-f;${PLM_TESTING_DATA_DIR}/fiducials-rect-2.fcsv;-m;${PLM_TESTING_DATA_DIR}/fiducials-rect-3.fcsv;-I;${PLM_BUILD_TESTING_DIR}/rect-3.mha;-O;${PLM_BUILD_TESTING_DIR}/landmark-warp-d-img.mha;-V;${PLM_BUILD_TESTING_DIR}/landmark-warp-d-vf.mha;-L;${PLM_BUILD_TESTING_DIR}/landmark-warp-d.fcsv" ) set_tests_properties (landmark-warp-d PROPERTIES DEPENDS rect-3) ## ------------------------------------------------------------------------- ## plastimatch add, plastimatch average ## plm-add-a Add two images ## plm-add-b Average two images ## plm-add-vf-a Add two vector fields ## plm-add-vf-b Average two vector fields ## ------------------------------------------------------------------------- plm_add_test ( "plm-add-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "add;--output;${PLM_BUILD_TESTING_DIR}/plm-add-a.nrrd;${PLM_BUILD_TESTING_DIR}/rect-1.mha;${PLM_BUILD_TESTING_DIR}/rect-3.mha" ) plm_add_test ( "plm-add-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-add-a.nrrd" ) plmtest_check_interval ("plm-add-a-check" "${PLM_BUILD_TESTING_DIR}/plm-add-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-1000.1" "-999.9" ) set_tests_properties (plm-add-a PROPERTIES DEPENDS "rect-1;rect-3") set_tests_properties (plm-add-a-stats PROPERTIES DEPENDS plm-add-a) set_tests_properties (plm-add-a-check PROPERTIES DEPENDS plm-add-a-stats) plm_add_test ( "plm-add-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "average;--output;${PLM_BUILD_TESTING_DIR}/plm-add-b.nrrd;${PLM_BUILD_TESTING_DIR}/rect-1.mha;${PLM_BUILD_TESTING_DIR}/rect-3.mha" ) plm_add_test ( "plm-add-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-add-b.nrrd" ) plmtest_check_interval ("plm-add-b-check" "${PLM_BUILD_TESTING_DIR}/plm-add-b-stats.stdout.txt" "AVE *([-0-9.]*)" "-500.1" "-499.9" ) set_tests_properties (plm-add-b PROPERTIES DEPENDS "rect-1;rect-3") set_tests_properties (plm-add-b-stats PROPERTIES DEPENDS plm-add-b) set_tests_properties (plm-add-b-check PROPERTIES DEPENDS plm-add-b-stats) plm_add_test ( "plm-add-vf-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "add;--output;${PLM_BUILD_TESTING_DIR}/plm-add-vf-a.nrrd;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha" ) plm_add_test ( "plm-add-vf-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-add-vf-a.nrrd" ) plmtest_check_interval ("plm-add-vf-a-check" "${PLM_BUILD_TESTING_DIR}/plm-add-vf-a-stats.stdout.txt" "Mean: *([-0-9.]*)" "20.000" "20.000" ) set_tests_properties (plm-add-vf-a PROPERTIES DEPENDS vf-trans-1) set_tests_properties (plm-add-vf-a-stats PROPERTIES DEPENDS plm-add-vf-a) set_tests_properties (plm-add-vf-a-check PROPERTIES DEPENDS plm-add-vf-a-stats) plm_add_test ( "plm-add-vf-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "average;--output;${PLM_BUILD_TESTING_DIR}/plm-add-vf-b.nrrd;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha;${PLM_BUILD_TESTING_DIR}/vf-trans-2.mha" ) plm_add_test ( "plm-add-vf-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-add-vf-b.nrrd" ) plmtest_check_interval ("plm-add-vf-b-check" "${PLM_BUILD_TESTING_DIR}/plm-add-vf-b-stats.stdout.txt" "Mean: *([-0-9.]*)" "5.000" "5.000" ) set_tests_properties (plm-add-vf-b PROPERTIES DEPENDS "vf-trans-1;vf-trans-2") set_tests_properties (plm-add-vf-b-stats PROPERTIES DEPENDS plm-add-vf-b) set_tests_properties (plm-add-vf-b-check PROPERTIES DEPENDS plm-add-vf-b-stats) ## ------------------------------------------------------------------------- ## plastimatch boundary ## plm-boundary-a: sphere ## ------------------------------------------------------------------------- plm_add_test ( "plm-boundary-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "boundary;--output;${PLM_BUILD_TESTING_DIR}/plm-boundary-a.nrrd;${PLM_BUILD_TESTING_DIR}/sphere-1.mha" ) plm_add_test ( "plm-boundary-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-boundary-a.nrrd" ) plmtest_check_interval ("plm-boundary-a-check" "${PLM_BUILD_TESTING_DIR}/plm-boundary-a-stats.stdout.txt" "NONZERO *([-0-9.]*)" "546" "546" ) set_tests_properties (plm-boundary-a PROPERTIES DEPENDS sphere-1) set_tests_properties (plm-boundary-a-stats PROPERTIES DEPENDS plm-boundary-a) set_tests_properties (plm-boundary-a-check PROPERTIES DEPENDS plm-boundary-a-stats) ## ------------------------------------------------------------------------- ## plastimatch convert dicom (and dicom rt) ## plm convert dicom a: (rect) input rtss, no fixed image, no ct reference ## plm convert dicom b: set metadata patient position to FFS ## plm convert dicom c: make prefix images from lung-1 ## plm convert dicom d: error testing on non-existant directory ## plm convert dicom e: error testing on directory without dicom files ## plm convert dicom f: dicom rtss -> dicom rtss, with referenced ct ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-dicom-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/rect-1-dicom/rtss.dcm;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-a-ss.mha;--output-ss-list;plm-convert-dicom-a-ss.txt;--output-cxt;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-a.cxt;--output-prefix;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-a-prefix" ) plm_add_test ( "plm-convert-dicom-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-a-ss.mha" ) plmtest_check_interval ( "plm-convert-dicom-a-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-a-stats.stdout.txt" " 0 *NVOX *([-0-9.]*)" "1648003" "1648003" ) set_tests_properties (plm-convert-dicom-a PROPERTIES DEPENDS rect-1) set_tests_properties (plm-convert-dicom-a-stats PROPERTIES DEPENDS plm-convert-dicom-a) set_tests_properties (plm-convert-dicom-a-check PROPERTIES DEPENDS plm-convert-dicom-a-stats) plm_add_test ( "plm-convert-dicom-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--dicom-with-uids;false;--input;${PLM_BUILD_TESTING_DIR}/rect-1-dicom;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-b-dicom;--metadata;0018,5100=FFS" ) plm_add_test ( "plm-convert-dicom-b-stats" ${PLM_PLASTIMATCH_PATH}/dicom_info "--input;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-b-dicom/image0000.dcm" ) plmtest_check_string ("plm-convert-dicom-b-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-b-stats.stdout.txt" "Patient Position . (.*[^ ]) *$" "FFS" ) set_tests_properties (plm-convert-dicom-b PROPERTIES DEPENDS rect-1) set_tests_properties (plm-convert-dicom-b-stats PROPERTIES DEPENDS plm-convert-dicom-b) set_tests_properties (plm-convert-dicom-b-check PROPERTIES DEPENDS plm-convert-dicom-b-stats) plm_add_test ( "plm-convert-dicom-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/lung-1-dicom/;--output-prefix;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-c-prefix" ) plm_add_test ( "plm-convert-dicom-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-c-prefix/Tumor.mha" ) plmtest_check_interval ( "plm-convert-dicom-c-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-c-stats.stdout.txt" "NONZERO *([-0-9.]*)" "280" "280" ) set_tests_properties (plm-convert-dicom-c PROPERTIES DEPENDS lung-1) set_tests_properties (plm-convert-dicom-c-stats PROPERTIES DEPENDS plm-convert-dicom-c) set_tests_properties (plm-convert-dicom-c-check PROPERTIES DEPENDS plm-convert-dicom-c-stats) plm_add_test ( "plm-convert-dicom-d" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/non-existant-directory/;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-d.nrrd" "-DEXPECTED_ERRNO=1" ) plm_add_test ( "plm-convert-dicom-e" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/tmp/;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-e.nrrd" "-DEXPECTED_ERRNO=1" ) plm_add_test ( "plm-convert-dicom-f" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/rect-1-dicom/rtss.dcm;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-f-dicom;--referenced-ct;${PLM_BUILD_TESTING_DIR}/rect-2-dicom" ) ## GCS FIX: Normally, I would want to probe the dicom data to see if they ## match. But dicom_info only works with images, not rtss. set_tests_properties (plm-convert-dicom-f PROPERTIES DEPENDS "rect-1;rect2") ## ------------------------------------------------------------------------- ## These tests are designed to check the handling of overlapping structures ## in DICOM-RT format. The tests assume that the original synthetic donut ## DICOM-RT files are generated without keyholing. ## plm-convert-dicom-donut-a From DICOM to ss-img (or semantics) ## plm-convert-dicom-donut-b From DICOM to ss-img (xor semantics) ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-dicom-donut-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/donut-1-dicom;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-donut-a-ss.nrrd" ) plm_add_test ( "plm-convert-dicom-donut-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-donut-a-ss.nrrd" ) plmtest_check_interval ( "plm-convert-dicom-donut-a-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-donut-a-stats.stdout.txt" "S *0 *NVOX *([-0-9.]*)" "2623" "2623" ) plm_add_test ( "plm-convert-dicom-donut-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/donut-1-dicom;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-donut-b-ss.nrrd;--xor-contours" ) plm_add_test ( "plm-convert-dicom-donut-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-donut-b-ss.nrrd" ) plmtest_check_interval ( "plm-convert-dicom-donut-b-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-donut-b-stats.stdout.txt" "S *0 *NVOX *([-0-9.]*)" "1924" "1924" ) set_tests_properties (plm-convert-dicom-donut-a PROPERTIES DEPENDS donut-1) set_tests_properties (plm-convert-dicom-donut-a-stats PROPERTIES DEPENDS plm-convert-dicom-donut-a) set_tests_properties (plm-convert-dicom-donut-a-check PROPERTIES DEPENDS plm-convert-dicom-donut-a-stats) set_tests_properties (plm-convert-dicom-donut-b PROPERTIES DEPENDS donut-1) set_tests_properties (plm-convert-dicom-donut-b-stats PROPERTIES DEPENDS plm-convert-dicom-donut-b) set_tests_properties (plm-convert-dicom-donut-b-check PROPERTIES DEPENDS plm-convert-dicom-donut-b-stats) ## ------------------------------------------------------------------------- ## These tests are designed to check the handling of overlapping structures ## in DICOM-RT format. Converts donut topology structure into keyholized ## rtstruct. ## plm-convert-dicom-donut-c From ss-img to DICOM ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-dicom-donut-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/donut-1.mha;--input-ss-img;${PLM_BUILD_TESTING_DIR}/donut-1-ss.mha;--input-ss-list;${PLM_BUILD_TESTING_DIR}/donut-1-ss-list.txt;--dicom-with-uids;false;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-donut-c" ) set_tests_properties (plm-convert-dicom-donut-c PROPERTIES DEPENDS donut-1) ## ------------------------------------------------------------------------- ## plastimatch convert rtog (corvus) ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-rtog-corvus-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/rtog-corvus-6.2.2;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-rtog-corvus-a.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-rtog-corvus-a-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-convert-rtog-corvus-a-ss.txt;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-rtog-corvus-a-dose.mha" ) ## ------------------------------------------------------------------------- ## plastimatch convert dicom-rt (aw) ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-dicom-aw-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--dicom-with-uids;false;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-aw-4.4-foot/20101202HFS;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-a.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-a-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-a-ss.txt;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-a-dose.mha;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-a-dicom" ) plm_add_test ( "plm-convert-dicom-aw-a-stats" ${PLM_PLASTIMATCH_PATH}/dicom_info "--input;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-a-dicom/image0000.dcm" ) plmtest_check_string ("plm-convert-dicom-aw-a-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-a-stats.stdout.txt" "^Patient's Name . (.*[^ ]) *$" "PHANTOM^HFS" ) plm_add_test ( "plm-convert-dicom-aw-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-aw-4.4-foot/20101202FFS;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-b.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-b-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-b-ss.txt;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-aw-b-dose.mha" ) set_tests_properties (plm-convert-dicom-aw-a-stats PROPERTIES DEPENDS plm-convert-dicom-aw-a) set_tests_properties (plm-convert-dicom-aw-a-check PROPERTIES DEPENDS plm-convert-dicom-aw-a-stats) ## ------------------------------------------------------------------------- ## plastimatch convert dicom-rt (cerr) ## ------------------------------------------------------------------------- # plm_add_test ( # "plm-convert-dicom-cerr-a" # ${PLM_PLASTIMATCH_PATH}/plastimatch # "convert;--input;${PLM_BUILD_TESTING_DIR}/chest-phantom-dicomrt-CERR4pt0beta2_25_Jan_2011;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-cerr-a.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-cerr-a-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-cerr-a-ss.txt;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-cerr-a-dose.mha" # ) ## ------------------------------------------------------------------------- ## plastimatch convert dicom-rt (corvus) ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-dicom-corvus-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-corvus-6.2.2;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-corvus-a.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-corvus-a-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-corvus-a-ss.txt;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-corvus-a-dose.mha" ) ## ------------------------------------------------------------------------- ## plastimatch convert dicom-rt (pinnacle) ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-dicom-pinnacle-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-pinnacle3-8.2g-rando;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-pinnacle-a.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-pinnacle-a-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-pinnacle-a-ss.txt;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-pinnacle-a-dose.mha" ) ## ------------------------------------------------------------------------- ## plastimatch-convert-dicom-xio (xio) ## plm-convert-dicom-xio-a: ct only ## plm-convert-dicom-xio-b: rtss -> ss_img, with referenced-ct ## plm-convert-dicom-xio-c: rtss -> ss_img, with fixed image reference ## plm-convert-dicom-xio-d: dose only, native sampling rate ## plm-convert-dicom-xio-e: input xio dicom, output plm dicom ## plm-convert-dicom-xio-f: input plm dicom, output plm dicom ## plm-convert-dicom-xio-g: all inputs, image outputs ## plm-warp-dicom-xio-a: all inputs, bspline transform, all outputs ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-dicom-xio-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.33.02-chest-phantom;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-a.mha" ) plm_add_test ( "plm-convert-dicom-xio-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-a.mha" ) plmtest_check_interval ("plm-convert-dicom-xio-a-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-667.5" "-666.6" ) set_tests_properties (plm-convert-dicom-xio-a-stats PROPERTIES DEPENDS plm-convert-dicom-xio-a) set_tests_properties (plm-convert-dicom-xio-a-check PROPERTIES DEPENDS plm-convert-dicom-xio-a-stats) plm_add_test ( "plm-convert-dicom-xio-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.33.02-chest-phantom/SS.rtp1.12.20080627A.5.dcm;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-b-ss.mha;--referenced-ct;${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.33.02-chest-phantom" ) plm_add_test ( "plm-convert-dicom-xio-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-b-ss.mha" ) plmtest_check_interval ("plm-convert-dicom-xio-b-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-b-stats.stdout.txt" "S *1 *NVOX *([-0-9.]*)" "62767" "62767" ) set_tests_properties (plm-convert-dicom-xio-b-stats PROPERTIES DEPENDS plm-convert-dicom-xio-b) set_tests_properties (plm-convert-dicom-xio-b-check PROPERTIES DEPENDS plm-convert-dicom-xio-b-stats) plm_add_test ( "plm-convert-dicom-xio-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.33.02-chest-phantom/SS.rtp1.12.20080627A.5.dcm;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-c-ss.mha;--fixed;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-a.mha;--output-cxt;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-c.cxt" ) plm_add_test ( "plm-convert-dicom-xio-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-c-ss.mha" ) # To be resolved. Why do dicom-xio-b and dicom-xio-c give different answers? plmtest_check_interval ("plm-convert-dicom-xio-c-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-c-stats.stdout.txt" "S *1 *NVOX *([-0-9.]*)" "62769" "62769" ) set_tests_properties (plm-convert-dicom-xio-c PROPERTIES DEPENDS plm-convert-dicom-xio-a) set_tests_properties (plm-convert-dicom-xio-c-stats PROPERTIES DEPENDS plm-convert-dicom-xio-c) set_tests_properties (plm-convert-dicom-xio-c-check PROPERTIES DEPENDS plm-convert-dicom-xio-c-stats) plm_add_test ( "plm-convert-dicom-xio-d" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.33.02-chest-phantom/DOSE.20080627A.TRAINING4FLD.dcm;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-d-dose-img.mha" ) plm_add_test ( "plm-convert-dicom-xio-d-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-d-dose-img.mha" ) plmtest_check_interval ("plm-convert-dicom-xio-d-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-d-stats.stdout.txt" "MAX *([-0-9.]*)" "42.1" "42.2" ) set_tests_properties (plm-convert-dicom-xio-d-stats PROPERTIES DEPENDS plm-convert-dicom-xio-d) set_tests_properties (plm-convert-dicom-xio-d-check PROPERTIES DEPENDS plm-convert-dicom-xio-d-stats) plm_add_test ( "plm-convert-dicom-xio-e" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.33.02-chest-phantom;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-e-dicom;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-e-dose-img.mha" ) plm_add_test ( "plm-convert-dicom-xio-f" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-e-dicom;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-f-dicom;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-f-dose-img.mha" ) plm_add_test ( "plm-convert-dicom-xio-f-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "compare;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-e-dose-img.mha;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-f-dose-img.mha" ) plmtest_check_interval ("plm-convert-dicom-xio-f-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-f-stats.stdout.txt" "MAE *([-0-9.]*)" "0.000" "0.005" ) set_tests_properties (plm-convert-dicom-xio-f PROPERTIES DEPENDS plm-convert-dicom-xio-e) set_tests_properties (plm-convert-dicom-xio-f-stats PROPERTIES DEPENDS plm-convert-dicom-xio-f) set_tests_properties (plm-convert-dicom-xio-f-check PROPERTIES DEPENDS plm-convert-dicom-xio-f-stats) plm_add_test ( "plm-convert-dicom-xio-g" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.33.02-chest-phantom;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-g.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-g-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-g-ss.txt;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-xio-g-dose.mha" ) plm_add_test ( "plm-warp-dicom-xio-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--xf;${PLM_TESTING_DATA_DIR}/xf-bspline-chest-phantom.txt;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.33.02-chest-phantom;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a-dicom;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a-ss.nrrd;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a-ss.txt;--output-labelmap;${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a-labelmap.nrrd;--output-img;${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a-img.nrrd;--output-prefix;${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a;--output-cxt;${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a.cxt;--default-value;0" ) plm_add_test ( "plm-warp-dicom-xio-a-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a-img.nrrd" ) plmtest_check_interval ("plm-warp-dicom-xio-a-check-1" "${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-661.9" "-661.4" ) plm_add_test ( "plm-warp-dicom-xio-a-stats-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a-ss.nrrd" ) plmtest_check_interval ("plm-warp-dicom-xio-a-check-2" "${PLM_BUILD_TESTING_DIR}/plm-warp-dicom-xio-a-stats-2.stdout.txt" "S *1 *NVOX *([-0-9.]*)" "1971" "1971" ) set_tests_properties (plm-warp-dicom-xio-a-stats-1 PROPERTIES DEPENDS plm-warp-dicom-xio-a) set_tests_properties (plm-warp-dicom-xio-a-check-1 PROPERTIES DEPENDS plm-warp-dicom-xio-a-stats-1) set_tests_properties (plm-warp-dicom-xio-a-stats-2 PROPERTIES DEPENDS plm-warp-dicom-xio-a) set_tests_properties (plm-warp-dicom-xio-a-check-2 PROPERTIES DEPENDS plm-warp-dicom-xio-a-stats-2) ## ------------------------------------------------------------------------- ## plastimatch-convert-dicom-irregular (xio, irregular slice spacing) ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-dicom-irregular-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/xio-4.60-irregular-spacing;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-irregular-a.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-irregular-a-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-irregular-a-ss.txt;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-irregular-a-dose.mha" ) ## ------------------------------------------------------------------------- ## plm-convert-dicom-33 (mim, 33 structures) ## plm-convert-dicom-33-a (native method, depends on configuration) ## plm-convert-dicom-33-b (force unsigned long) ## plm-convert-dicom-33-c (force uchar_vec) ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-dicom-33-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/dicomrt-33-structures;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-33-a.mha;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-33-a-ss.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-33-a-ss.txt;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-33-a-dicom" ) plm_add_test ( "plm-convert-dicom-33-a-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "header;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-33-a-ss.mha" ) plm_add_test ( "plm-convert-dicom-33-a-stats-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-33-a-ss.mha" ) plmtest_check_string ("plm-convert-dicom-33-a-check-1" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-33-a-stats-1.stdout.txt" "^Planes . (.*[^ ]) *$" "5" ) plmtest_check_interval ("plm-convert-dicom-33-a-check-2" "${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-33-a-stats-2.stdout.txt" "S *28 *NVOX *([-0-9.]*)" "130" "130" ) set_tests_properties (plm-convert-dicom-33-a-stats-1 PROPERTIES DEPENDS plm-convert-dicom-33-a) set_tests_properties (plm-convert-dicom-33-a-stats-2 PROPERTIES DEPENDS plm-convert-dicom-33-a) set_tests_properties (plm-convert-dicom-33-a-check-1 PROPERTIES DEPENDS plm-convert-dicom-33-a-stats-1) set_tests_properties (plm-convert-dicom-33-a-check-2 PROPERTIES DEPENDS plm-convert-dicom-33-a-stats-2) ## ------------------------------------------------------------------------- ## plastimatch-convert-cxt ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-cxt" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/plm-convert-dicom-a.cxt;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-convert-cxt.mha;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-convert-cxt.txt" ) plm_add_test ( "plm-convert-cxt-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-cxt.mha" ) # There is a bug in the dicom converter, whereby the image in the # same directory is not parsed to find rasterization size. This # test should be modified when that bug is fixed. plmtest_check_interval ("plm-convert-cxt-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-cxt-stats.stdout.txt" "S *0 *NVOX *([-0-9.]*)" "1648003" "1648003" ) set_tests_properties (plm-convert-cxt PROPERTIES DEPENDS plm-convert-dicom-a) set_tests_properties (plm-convert-cxt-stats PROPERTIES DEPENDS plm-convert-cxt) set_tests_properties (plm-convert-cxt-check PROPERTIES DEPENDS plm-convert-cxt-stats) ## ------------------------------------------------------------------------- ## plm-convert-xio ## plm-convert-xio-a ## plm-convert-xio-b ## (2014-10-13) These used to convert to AVG between -667.5 to -666.6, ## but now the AVG is -665.638611. Would be good to test with phantom ## to make sure the conversion is good. ## plm-warp-xio-a ## (2014-10-13) Ditto. AVG was between -661.5 to -661.4, but now ## is -660.018921 ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-xio-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/xio-4.33.02-chest-phantom;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-xio-a.mha;--output-xio;${PLM_BUILD_TESTING_DIR}/plm-convert-xio-a-xio-output;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-convert-xio-a-dicom;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-xio-a-dose.mha" ) plm_add_test ( "plm-convert-xio-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-xio-a.mha" ) plmtest_check_interval ("plm-convert-xio-a-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-xio-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-667.5" "-665.2" ) set_tests_properties (plm-convert-xio-a-stats PROPERTIES DEPENDS plm-convert-xio-a) set_tests_properties (plm-convert-xio-a-check PROPERTIES DEPENDS plm-convert-xio-a-stats) plm_add_test ( "plm-convert-xio-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input;${PLM_BUILD_TESTING_DIR}/xio-4.33.02-chest-phantom/20080627A/plan/TRAINING4FLD;--output-img;${PLM_BUILD_TESTING_DIR}/plm-convert-xio-b.mha;--output-xio;${PLM_BUILD_TESTING_DIR}/plm-convert-xio-b-xio-output;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-convert-xio-b-dicom" ) plm_add_test ( "plm-convert-xio-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-xio-b.mha" ) plmtest_check_interval ("plm-convert-xio-b-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-xio-b-stats.stdout.txt" "AVE *([-0-9.]*)" "-667.5" "-665.2" ) set_tests_properties (plm-convert-xio-b-stats PROPERTIES DEPENDS plm-convert-xio-b) set_tests_properties (plm-convert-xio-b-check PROPERTIES DEPENDS plm-convert-xio-b-stats) plm_add_test ( "plm-warp-xio-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--xf;${PLM_TESTING_DATA_DIR}/xf-bspline-chest-phantom.txt;--input;${PLM_BUILD_TESTING_DIR}/xio-4.33.02-chest-phantom;--output-xio;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-xio;--output-ss-img;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-ss.nrrd;--output-ss-list;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-ss.txt;--output-labelmap;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-labelmap.nrrd;--output-img;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-img.nrrd;--output-prefix;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a;--output-cxt;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a.cxt;--output-colormap;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a.ctbl;--default-value;0" ) plm_add_test ( "plm-warp-xio-a-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-img.nrrd" ) plmtest_check_interval ("plm-warp-xio-a-check-1" "${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-661.5" "-659.9" ) plm_add_test ( "plm-warp-xio-a-stats-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a/Patient.mha" ) plmtest_check_interval ("plm-warp-xio-a-check-2" "${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-stats-2.stdout.txt" "AVE *([-0-9.]*)" "0.385" "0.395" ) plm_add_test ( "plm-warp-xio-a-stats-3" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-labelmap.nrrd" ) plmtest_check_interval ("plm-warp-xio-a-check-3" "${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-stats-3.stdout.txt" "AVE *([-0-9.]*)" "0.67" "0.68" ) plm_add_test ( "plm-warp-xio-a-stats-4" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-ss.nrrd" ) plmtest_check_interval ("plm-warp-xio-a-check-4" "${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-stats-4.stdout.txt" "S *1 *NVOX *([-0-9.]*)" "1970" "1971" ) add_test ("plm-warp-xio-a-check-5" ${CMAKE_COMMAND} -E compare_files "${PLM_TESTING_DATA_DIR}/plm-warp-xio-a-ss.txt" "${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a-ss.txt") add_test ("plm-warp-xio-a-check-6" ${CMAKE_COMMAND} -E compare_files "${PLM_TESTING_DATA_DIR}/plm-warp-xio-a.ctbl" "${PLM_BUILD_TESTING_DIR}/plm-warp-xio-a.ctbl") set_tests_properties (plm-warp-xio-a-stats-1 PROPERTIES DEPENDS plm-warp-xio-a) set_tests_properties (plm-warp-xio-a-check-1 PROPERTIES DEPENDS plm-warp-xio-a-stats-1) set_tests_properties (plm-warp-xio-a-stats-2 PROPERTIES DEPENDS plm-warp-xio-a) set_tests_properties (plm-warp-xio-a-check-2 PROPERTIES DEPENDS plm-warp-xio-a-stats-2) set_tests_properties (plm-warp-xio-a-stats-3 PROPERTIES DEPENDS plm-warp-xio-a) set_tests_properties (plm-warp-xio-a-check-3 PROPERTIES DEPENDS plm-warp-xio-a-stats-3) set_tests_properties (plm-warp-xio-a-stats-4 PROPERTIES DEPENDS plm-warp-xio-a) set_tests_properties (plm-warp-xio-a-check-4 PROPERTIES DEPENDS plm-warp-xio-a-stats-4) set_tests_properties (plm-warp-xio-a-check-5 PROPERTIES DEPENDS plm-warp-xio-a) set_tests_properties (plm-warp-xio-a-check-6 PROPERTIES DEPENDS plm-warp-xio-a) ## ------------------------------------------------------------------------- ## plastimatch-convert-prefix-fcsv ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-prefix-fcsv" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input-ss-img;${PLM_BUILD_TESTING_DIR}/donut-1-ss.mha;--output-prefix-fcsv;${PLM_BUILD_TESTING_DIR}/plm-convert-prefix-fcsv" ) set_tests_properties (plm-convert-prefix-fcsv PROPERTIES DEPENDS donut-1) ## ------------------------------------------------------------------------- ## plastimatch-convert-dose-scale ## ------------------------------------------------------------------------- plm_add_test ( "plm-convert-dose-scale" ${PLM_PLASTIMATCH_PATH}/plastimatch "convert;--input-dose-img;${PLM_BUILD_TESTING_DIR}/sphere-3.mha;--output-dose-img;${PLM_BUILD_TESTING_DIR}/plm-convert-dose-scale.mha;--dose-scale;77.7" ) plm_add_test ( "plm-convert-dose-scale-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-convert-dose-scale.mha" ) plmtest_check_interval ("plm-convert-dose-scale-check" "${PLM_BUILD_TESTING_DIR}/plm-convert-dose-scale-stats.stdout.txt" "MAX *([-0-9.]*)" "77.699" "77.7" ) set_tests_properties (plm-convert-dose-scale PROPERTIES DEPENDS sphere-3) set_tests_properties (plm-convert-dose-scale-stats PROPERTIES DEPENDS plm-convert-dose-scale) set_tests_properties (plm-convert-dose-scale-check PROPERTIES DEPENDS plm-convert-dose-scale-stats) ## ------------------------------------------------------------------------- ## plm-dice-a dice, centered and off-centered rect ## plm-dice-b dice, centered rects of different resolution ## plm-dice-c HD, centered and off-centered rect ## plm-dice-d 95 HD, centered and off-centered rect ## ------------------------------------------------------------------------- plm_add_test ( "plm-dice-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "dice;${PLM_BUILD_TESTING_DIR}/rect-4.mha;${PLM_BUILD_TESTING_DIR}/rect-8.mha" ) plmtest_check_interval ("plm-dice-a-check-1" "${PLM_BUILD_TESTING_DIR}/plm-dice-a.stdout.txt" "^DICE: *([-0-9.]*)" "0.799" "0.801" ) set_tests_properties (plm-dice-a PROPERTIES DEPENDS "rect-4;rect-8") set_tests_properties (plm-dice-a-check-1 PROPERTIES DEPENDS "plm-dice-a") plm_add_test ( "plm-dice-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "dice;${PLM_BUILD_TESTING_DIR}/rect-4.mha;${PLM_BUILD_TESTING_DIR}/rect-9.mha" ) plmtest_check_interval ("plm-dice-b-check-1" "${PLM_BUILD_TESTING_DIR}/plm-dice-b.stdout.txt" "^DICE: *([-0-9.]*)" "0.999" "1.000" ) set_tests_properties (plm-dice-b PROPERTIES DEPENDS "rect-4;rect-9") set_tests_properties (plm-dice-b-check-1 PROPERTIES DEPENDS "plm-dice-b") plm_add_test ( "plm-dice-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "dice;--hausdorff;${PLM_BUILD_TESTING_DIR}/rect-4.mha;${PLM_BUILD_TESTING_DIR}/rect-8.mha" ) plmtest_check_interval ("plm-dice-c-check-1" "${PLM_BUILD_TESTING_DIR}/plm-dice-c.stdout.txt" "^Hausdorff distance = *([-0-9.]*)" "26.31" "26.32" ) plmtest_check_interval ("plm-dice-c-check-2" "${PLM_BUILD_TESTING_DIR}/plm-dice-c.stdout.txt" "^Avg average Hausdorff distance = *([-0-9.]*)" "3.40" "3.41" ) set_tests_properties (plm-dice-c PROPERTIES DEPENDS "rect-4;rect-8") set_tests_properties (plm-dice-c-check-1 PROPERTIES DEPENDS "plm-dice-c") set_tests_properties (plm-dice-c-check-2 PROPERTIES DEPENDS "plm-dice-c") ## ------------------------------------------------------------------------- ## plm-dmap-a distance map, itk maurer ## plm-dmap-b distance map, native danielsson ## ------------------------------------------------------------------------- plm_add_test ( "plm-dmap-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "dmap;--algorithm;maurer;--input;${PLM_BUILD_TESTING_DIR}/rect-4.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-dmap-a.mha" ) set_tests_properties (plm-dmap-a PROPERTIES DEPENDS "rect-4") plm_add_test ( "plm-dmap-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "dmap;--algorithm;danielsson;--input;${PLM_BUILD_TESTING_DIR}/rect-4.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-dmap-b.mha" ) set_tests_properties (plm-dmap-b PROPERTIES DEPENDS "rect-4") ## ------------------------------------------------------------------------- ## plm-dvh-a ss-img, without ss-list ## plm-dvh-b ss-img, with ss-list ## ------------------------------------------------------------------------- plm_add_test ( "plm-dvh-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "dvh;--input-ss-img;${PLM_BUILD_TESTING_DIR}/rect-1-ss.mha;--input-dose;${PLM_BUILD_TESTING_DIR}/rect-1-dose-img.mha;--output-csv;${PLM_BUILD_TESTING_DIR}/plm-dvh-a.csv" ) plmtest_check_interval ("plm-dvh-a-check-1" "${PLM_BUILD_TESTING_DIR}/plm-dvh-a.csv" "^15,([-0-9.]*)," "0.999" "1.0" ) plmtest_check_interval ("plm-dvh-a-check-2" "${PLM_BUILD_TESTING_DIR}/plm-dvh-a.csv" "^15.5,([-0-9.]*)," "0.0" "0.001" ) set_tests_properties (plm-dvh-a PROPERTIES DEPENDS "rect-1") set_tests_properties (plm-dvh-a-check-1 PROPERTIES DEPENDS "plm-dvh-a") set_tests_properties (plm-dvh-a-check-2 PROPERTIES DEPENDS "plm-dvh-a") plm_add_test ( "plm-dvh-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "dvh;--input-ss-img;${PLM_BUILD_TESTING_DIR}/rect-1-ss.mha;--input-ss-list;${PLM_BUILD_TESTING_DIR}/rect-1-ss-list.txt;--input-dose;${PLM_BUILD_TESTING_DIR}/rect-1-dose-img.mha;--output-csv;${PLM_BUILD_TESTING_DIR}/plm-dvh-b.csv" ) plmtest_check_interval ("plm-dvh-b-check-1" "${PLM_BUILD_TESTING_DIR}/plm-dvh-b.csv" "^15,([-0-9.]*)" "0.999" "1.0" ) plmtest_check_interval ("plm-dvh-b-check-2" "${PLM_BUILD_TESTING_DIR}/plm-dvh-b.csv" "^15.5,([-0-9.]*)" "0.0" "0.001" ) set_tests_properties (plm-dvh-b PROPERTIES DEPENDS "rect-1") set_tests_properties (plm-dvh-b-check-1 PROPERTIES DEPENDS "plm-dvh-b") set_tests_properties (plm-dvh-b-check-2 PROPERTIES DEPENDS "plm-dvh-b") ## ------------------------------------------------------------------------- ## plastimatch fill/mask ## ------------------------------------------------------------------------- plm_add_test ( "plm-fill-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "fill;--input;${PLM_BUILD_TESTING_DIR}/rect-1.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-fill-a.mha;--mask;${PLM_BUILD_TESTING_DIR}/rect-4.mha" ) plm_add_test ( "plm-fill-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-fill-a.mha" ) plmtest_check_interval ("plm-fill-a-check" "${PLM_BUILD_TESTING_DIR}/plm-fill-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-0.1" "+0.1" ) set_tests_properties (plm-fill-a PROPERTIES DEPENDS "rect-1;rect-4") set_tests_properties (plm-fill-a-stats PROPERTIES DEPENDS plm-fill-a) set_tests_properties (plm-fill-a-check PROPERTIES DEPENDS plm-fill-a-stats) plm_add_test ( "plm-mask-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "mask;--input;${PLM_BUILD_TESTING_DIR}/rect-1.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-mask-a.mha;--mask;${PLM_BUILD_TESTING_DIR}/rect-4.mha;--mask-value;-1000" ) plm_add_test ( "plm-mask-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-mask-a.mha" ) plmtest_check_interval ("plm-mask-a-check" "${PLM_BUILD_TESTING_DIR}/plm-mask-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-1000.1" "-999.9" ) set_tests_properties (plm-mask-a PROPERTIES DEPENDS "rect-1;rect-4") set_tests_properties (plm-mask-a-stats PROPERTIES DEPENDS plm-mask-a) set_tests_properties (plm-mask-a-check PROPERTIES DEPENDS plm-mask-a-stats) ## ------------------------------------------------------------------------- ## plm-gamma-a centered and off-center rectangle, centered as reference ## plm-gamma-b centered rectangles with different dosees ## plm-gamma-c analysis using dose threshold on both images ## plm-gamma-d analysis using dose threshold on ref only ## ------------------------------------------------------------------------- plm_add_test ( "plm-gamma-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "gamma;--compute-full-region;--output;${PLM_BUILD_TESTING_DIR}/plm-gamma-a.mha;${PLM_BUILD_TESTING_DIR}/rect-12.mha;${PLM_BUILD_TESTING_DIR}/rect-14.mha" ) plm_add_test ( "plm-gamma-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-gamma-a.mha" ) plmtest_check_interval ("plm-gamma-a-check" "${PLM_BUILD_TESTING_DIR}/plm-gamma-a-stats.stdout.txt" "AVE *([-0-9.]*)" "0.023" "0.024" ) set_tests_properties (plm-gamma-a PROPERTIES DEPENDS "rect-12;rect-14") set_tests_properties (plm-gamma-a-stats PROPERTIES DEPENDS plm-gamma-a) set_tests_properties (plm-gamma-a-check PROPERTIES DEPENDS plm-gamma-a-stats) plm_add_test ( "plm-gamma-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "gamma;--output;${PLM_BUILD_TESTING_DIR}/plm-gamma-b.mha;${PLM_BUILD_TESTING_DIR}/rect-12.mha;${PLM_BUILD_TESTING_DIR}/rect-13.mha" ) plm_add_test ( "plm-gamma-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-gamma-b.mha" ) plmtest_check_interval ("plm-gamma-b-check" "${PLM_BUILD_TESTING_DIR}/plm-gamma-b-stats.stdout.txt" "AVE *([-0-9.]*)" "0.245" "0.255" ) set_tests_properties (plm-gamma-b PROPERTIES DEPENDS "rect-12;rect-13") set_tests_properties (plm-gamma-b-stats PROPERTIES DEPENDS plm-gamma-b) set_tests_properties (plm-gamma-b-check PROPERTIES DEPENDS plm-gamma-b-stats) plm_add_test ( "plm-gamma-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "gamma;--output;${PLM_BUILD_TESTING_DIR}/plm-gamma-c.mha;${PLM_BUILD_TESTING_DIR}/rectarr-03.mha;${PLM_BUILD_TESTING_DIR}/rectarr-04.mha" ) plmtest_check_interval ("plm-gamma-c-check" "${PLM_BUILD_TESTING_DIR}/plm-gamma-c.stdout.txt" "Pass rate = *([-0-9.]*)" "90.6" "90.8" ) set_tests_properties (plm-gamma-c PROPERTIES DEPENDS "rectarr-03;rectarr-04") set_tests_properties (plm-gamma-c-check PROPERTIES DEPENDS plm-gamma-c) plm_add_test ( "plm-gamma-d" ${PLM_PLASTIMATCH_PATH}/plastimatch "gamma;--output;${PLM_BUILD_TESTING_DIR}/plm-gamma-d.mha;--ref-only-threshold;${PLM_BUILD_TESTING_DIR}/rectarr-03.mha;${PLM_BUILD_TESTING_DIR}/rectarr-04.mha" ) plmtest_check_interval ("plm-gamma-d-check" "${PLM_BUILD_TESTING_DIR}/plm-gamma-d.stdout.txt" "Pass rate = *([-0-9.]*)" "89.9" "90.1" ) set_tests_properties (plm-gamma-d PROPERTIES DEPENDS "rectarr-03;rectarr-04") set_tests_properties (plm-gamma-d-check PROPERTIES DEPENDS plm-gamma-d) ## ------------------------------------------------------------------------- ## plastimatch maximum ## plm-maximum Set image containing maximum pixel values across list of images ## ------------------------------------------------------------------------- plm_add_test ( "plm-maximum-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "maximum;--output;${PLM_BUILD_TESTING_DIR}/plm-maximum-a.nrrd;${PLM_BUILD_TESTING_DIR}/rect-1.mha;${PLM_BUILD_TESTING_DIR}/rect-3.mha" ) plm_add_test ( "plm-maximum-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-maximum-a.nrrd" ) plmtest_check_interval ("plm-maximum-a-check" "${PLM_BUILD_TESTING_DIR}/plm-maximum-a-stats.stdout.txt" "AVE *([-0-9.]*)" "0.0" "0.0" ) set_tests_properties (plm-maximum-a PROPERTIES DEPENDS "rect-1;rect-3") set_tests_properties (plm-maximum-a-stats PROPERTIES DEPENDS plm-maximum-a) set_tests_properties (plm-maximum-a-check PROPERTIES DEPENDS plm-maximum-a-stats) ## ------------------------------------------------------------------------- ## plastimatch multiply ## plm-multiply-a Multiply two images ## plm-multiply-vf-a Multiply two vector fields ## ------------------------------------------------------------------------- plm_add_test ( "plm-multiply-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "multiply;--output;${PLM_BUILD_TESTING_DIR}/plm-multiply-a.nrrd;${PLM_BUILD_TESTING_DIR}/rect-1.mha;${PLM_BUILD_TESTING_DIR}/rect-3.mha" ) plm_add_test ( "plm-multiply-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-multiply-a.nrrd" ) plmtest_check_interval ("plm-multiply-a-check" "${PLM_BUILD_TESTING_DIR}/plm-multiply-a-stats.stdout.txt" "AVE *([-0-9.]*)" "0.0" "0.0" ) set_tests_properties (plm-multiply-a PROPERTIES DEPENDS "rect-1;rect-3") set_tests_properties (plm-multiply-a-stats PROPERTIES DEPENDS plm-multiply-a) set_tests_properties (plm-multiply-a-check PROPERTIES DEPENDS plm-multiply-a-stats) plm_add_test ( "plm-multiply-vf-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "multiply;--output;${PLM_BUILD_TESTING_DIR}/plm-multiply-vf-a.nrrd;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha" ) plm_add_test ( "plm-multiply-vf-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-multiply-vf-a.nrrd" ) plmtest_check_interval ("plm-multiply-vf-a-check" "${PLM_BUILD_TESTING_DIR}/plm-multiply-vf-a-stats.stdout.txt" "Mean: *([-0-9.]*)" "100.000" "100.000" ) set_tests_properties (plm-multiply-vf-a PROPERTIES DEPENDS vf-trans-1) set_tests_properties (plm-multiply-vf-a-stats PROPERTIES DEPENDS plm-multiply-vf-a) set_tests_properties (plm-multiply-vf-a-check PROPERTIES DEPENDS plm-multiply-vf-a-stats) ## ------------------------------------------------------------------------- ## plastimatch usage ## ------------------------------------------------------------------------- plm_add_test ( "plm-usage" ${PLM_PLASTIMATCH_PATH}/plastimatch "" ) ## ------------------------------------------------------------------------- ## plastimatch register (group 1) - basic functionality ## plm-reg-align-center ## plm-reg-itk-translation ## plm-reg-itk-rigid-a ## plm-reg-itk-rigid-b ## plm-reg-itk-bspline ## plm-reg-itk-demons ## ------------------------------------------------------------------------- # For Nocedal optimizer set (PLM_BSPLINE_TEST_LOWER_THRESH "-746.0") set (PLM_BSPLINE_TEST_UPPER_THRESH "-744.5") # For Liblbfgs optimizer #set (PLM_BSPLINE_TEST_LOWER_THRESH "-706.0") #set (PLM_BSPLINE_TEST_UPPER_THRESH "-704.5") plm_add_test ( "plm-reg-align-center" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-align-center.txt" ) plm_add_test ( "plm-reg-align-center-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "compare;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;${PLM_BUILD_TESTING_DIR}/plm-reg-align-center-img.mha" ) plmtest_check_interval ("plm-reg-align-center-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-align-center-stats.stdout.txt" "MAE *([-0-9.]*)" "-0.005" "0.005" ) set_property (TEST plm-reg-align-center APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-reg-align-center APPEND PROPERTY DEPENDS gauss-6) set_tests_properties (plm-reg-align-center-stats PROPERTIES DEPENDS plm-reg-align-center) set_tests_properties (plm-reg-align-center-check PROPERTIES DEPENDS plm-reg-align-center-stats) plm_add_test ( "plm-reg-itk-translation" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-translation.txt" ) plm_add_test ( "plm-reg-itk-translation-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-itk-translation-img.mha" ) plmtest_check_interval ("plm-reg-itk-translation-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-translation-stats.stdout.txt" "AVE *([-0-9.]*)" "-677.6" "-677.5" ) set_property (TEST plm-reg-itk-translation APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-reg-itk-translation APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-reg-itk-translation-stats PROPERTIES DEPENDS plm-reg-itk-translation) set_tests_properties (plm-reg-itk-translation-check PROPERTIES DEPENDS plm-reg-itk-translation-stats) plm_add_test ( "plm-reg-itk-rigid-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-rigid-a.txt" ) plm_add_test ( "plm-reg-itk-rigid-a-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-itk-rigid-a-intermediate-img.mha" ) plmtest_check_interval ("plm-reg-itk-rigid-a-check-1" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-rigid-a-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-939.3" "-939.1" ) plm_add_test ( "plm-reg-itk-rigid-a-stats-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-itk-rigid-a-img.mha" ) plmtest_check_interval ("plm-reg-itk-rigid-a-check-2" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-rigid-a-stats-2.stdout.txt" "AVE *([-0-9.]*)" "-939.3" "-939.1" ) set_tests_properties (plm-reg-itk-rigid-a PROPERTIES DEPENDS "rect-2;rect-3") set_tests_properties (plm-reg-itk-rigid-a-stats-1 PROPERTIES DEPENDS plm-reg-itk-rigid-a) set_tests_properties (plm-reg-itk-rigid-a-check-1 PROPERTIES DEPENDS plm-reg-itk-rigid-a-stats-1) set_tests_properties (plm-reg-itk-rigid-a-stats-2 PROPERTIES DEPENDS plm-reg-itk-rigid-a) set_tests_properties (plm-reg-itk-rigid-a-check-2 PROPERTIES DEPENDS plm-reg-itk-rigid-a-stats-2) plm_add_test ( "plm-reg-itk-similarity" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-similarity.txt" ) plm_add_test ( "plm-reg-itk-similarity-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-itk-similarity-intermediate-img.mha" ) plmtest_check_interval ("plm-reg-itk-similarity-check-1" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-similarity-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-981.3" "-981.1" ) plm_add_test ( "plm-reg-itk-similarity-stats-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-itk-similarity-img.mha" ) plmtest_check_interval ("plm-reg-itk-similarity-check-2" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-similarity-stats-2.stdout.txt" "AVE *([-0-9.]*)" "-940.8" "-940.5" ) set_tests_properties (plm-reg-itk-similarity PROPERTIES DEPENDS "rect-2s;rect-2") set_tests_properties (plm-reg-itk-similarity-stats-1 PROPERTIES DEPENDS plm-reg-itk-similarity) set_tests_properties (plm-reg-itk-similarity-check-1 PROPERTIES DEPENDS plm-reg-itk-similarity-stats-1) set_tests_properties (plm-reg-itk-similarity-stats-2 PROPERTIES DEPENDS plm-reg-itk-similarity) set_tests_properties (plm-reg-itk-similarity-check-2 PROPERTIES DEPENDS plm-reg-itk-similarity-stats-2) plm_add_test ( "plm-reg-itk-rigid-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-rigid-b.txt" ) plm_add_test ( "plm-reg-itk-rigid-b-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-itk-rigid-b-intermediate-img.mha" ) plmtest_check_interval ("plm-reg-itk-rigid-b-check-1" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-rigid-b-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-939.3" "-939.1" ) set_tests_properties (plm-reg-itk-rigid-b PROPERTIES DEPENDS "rect-1;rect-2") set_tests_properties (plm-reg-itk-rigid-b-stats-1 PROPERTIES DEPENDS plm-reg-itk-rigid-b) set_tests_properties (plm-reg-itk-rigid-b-check-1 PROPERTIES DEPENDS plm-reg-itk-rigid-b-stats-1) plm_add_test ( "plm-reg-itk-bspline" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-bspline.txt" ) plm_add_test ( "plm-reg-itk-bspline-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-itk-bspline-img.mha" ) plmtest_check_interval ("plm-reg-itk-bspline-check-1" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-bspline-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-764.0" "-763.6" ) set_property (TEST plm-reg-itk-bspline APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-reg-itk-bspline APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-reg-itk-bspline-stats-1 PROPERTIES DEPENDS plm-reg-itk-bspline) set_tests_properties (plm-reg-itk-bspline-check-1 PROPERTIES DEPENDS plm-reg-itk-bspline-stats-1) plm_add_test ( "plm-reg-itk-demons" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-reg-itk-demons.txt" ) plmtest_check_interval ("plm-reg-itk-demons-check-1" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-demons.stdout.txt" "VF_AVG +[^ ] +([-0-9.]*)" "31.85" "34.95" ) plm_add_test ( "plm-reg-itk-demons-stats-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-itk-demons-img.mha" ) plmtest_check_interval ("plm-reg-itk-demons-check-2" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-demons-stats-2.stdout.txt" "AVE *([-0-9.]*)" "-755.3" "-754.6" ) set_property (TEST plm-reg-itk-demons PROPERTY DEPENDS "gauss-1;gauss-2") set_tests_properties (plm-reg-itk-demons-check-1 PROPERTIES DEPENDS plm-reg-itk-demons) set_tests_properties (plm-reg-itk-demons-stats-2 PROPERTIES DEPENDS plm-reg-itk-demons) set_tests_properties (plm-reg-itk-demons-check-2 PROPERTIES DEPENDS plm-reg-itk-demons-stats-2) plm_add_test ( "plm-reg-itk-demons-diff" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-reg-itk-demons-diff.txt" ) plmtest_check_interval ("plm-reg-itk-demons-diff-check-1" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-demons-diff.stdout.txt" "VF_AVG +[^ ] +([-0-9.]*)" "31.2" "31.3" ) set_property (TEST plm-reg-itk-demons-diff PROPERTY DEPENDS "gauss-1;gauss-2") set_tests_properties (plm-reg-itk-demons-diff-check-1 PROPERTIES DEPENDS plm-reg-itk-demons-diff) plm_add_test ( "plm-reg-itk-demons-logd" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-reg-itk-demons-logd.txt" ) plmtest_check_interval ("plm-reg-itk-demons-logd-check-1" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-demons-logd.stdout.txt" "VF_AVG +[^ ] +([-0-9.]*)" "32.65" "32.75" ) set_property (TEST plm-reg-itk-demons-logd PROPERTY DEPENDS "gauss-1;gauss-2") set_tests_properties (plm-reg-itk-demons-logd-check-1 PROPERTIES DEPENDS plm-reg-itk-demons-logd) plm_add_test ( "plm-reg-itk-demons-sym-logd" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-reg-itk-demons-sym-logd.txt" ) plmtest_check_interval ("plm-reg-itk-demons-sym-logd-check-1" "${PLM_BUILD_TESTING_DIR}/plm-reg-itk-demons-sym-logd.stdout.txt" "VF_AVG +[^ ] +([-0-9.]*)" "31.85" "35.95" ) set_property (TEST plm-reg-itk-demons-sym-logd PROPERTY DEPENDS "gauss-1;gauss-2") set_tests_properties (plm-reg-itk-demons-sym-logd-check-1 PROPERTIES DEPENDS plm-reg-itk-demons-sym-logd) ## ------------------------------------------------------------------------- ## plastimatch register (group 2) ## plm-bsp-mse-c ## plm-bsp-mse-h ## plm-bsp-mse-k ## plm-bsp-mse-l ## plm-bsp-openmp ## plm-bsp-cuda ## plm-bsp-resume ## plm-bsp-logfile ## plm-bsp-ushort ## plm-bsp-double ## plm-bsp-itk-output ## plm-bsp-char-output ## ------------------------------------------------------------------------- plm_add_test ( "plm-bsp-mse-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-c.txt" ) plm_add_test ( "plm-bsp-mse-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-c-img.mha" ) plmtest_check_interval ("plm-bsp-mse-c-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-c-stats.stdout.txt" "AVE *([-0-9.]*)" "${PLM_BSPLINE_TEST_LOWER_THRESH}" "${PLM_BSPLINE_TEST_UPPER_THRESH}" ) set_property (TEST plm-bsp-mse-c APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-mse-c APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-bsp-mse-c-stats PROPERTIES DEPENDS plm-bsp-mse-c) set_tests_properties (plm-bsp-mse-c-check PROPERTIES DEPENDS plm-bsp-mse-c-stats) plm_add_test ( "plm-bsp-mse-h" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-h.txt" ) plm_add_test ( "plm-bsp-mse-h-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-h-img.mha" ) plmtest_check_interval ("plm-bsp-mse-h-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-h-stats.stdout.txt" "AVE *([-0-9.]*)" "${PLM_BSPLINE_TEST_LOWER_THRESH}" "${PLM_BSPLINE_TEST_UPPER_THRESH}" ) set_property (TEST plm-bsp-mse-h APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-mse-h APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-bsp-mse-h-stats PROPERTIES DEPENDS plm-bsp-mse-h) set_tests_properties (plm-bsp-mse-h-check PROPERTIES DEPENDS plm-bsp-mse-h-stats) plm_add_test ( "plm-bsp-mse-k" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-k.txt" ) plm_add_test ( "plm-bsp-mse-k-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-k-img.mha" ) plmtest_check_interval ("plm-bsp-mse-k-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-k-stats.stdout.txt" "AVE *([-0-9.]*)" "${PLM_BSPLINE_TEST_LOWER_THRESH}" "${PLM_BSPLINE_TEST_UPPER_THRESH}" ) set_property (TEST plm-bsp-mse-k APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-mse-k APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-bsp-mse-k-stats PROPERTIES DEPENDS plm-bsp-mse-k) set_tests_properties (plm-bsp-mse-k-check PROPERTIES DEPENDS plm-bsp-mse-k-stats) plm_add_test ( "plm-bsp-mse-l" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-l.txt" ) plm_add_test ( "plm-bsp-mse-l-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-l-img.mha" ) plmtest_check_interval ("plm-bsp-mse-l-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-l-stats.stdout.txt" "AVE *([-0-9.]*)" "${PLM_BSPLINE_TEST_LOWER_THRESH}" "${PLM_BSPLINE_TEST_UPPER_THRESH}" ) set_property (TEST plm-bsp-mse-l APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-mse-l APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-bsp-mse-l-stats PROPERTIES DEPENDS plm-bsp-mse-l) set_tests_properties (plm-bsp-mse-l-check PROPERTIES DEPENDS plm-bsp-mse-l-stats) ## This test (and bsp-mi-k) fails on windows with 2008 compiler. plm_add_test ( "plm-bsp-mi-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-mi-c.txt" ) plm_add_test ( "plm-bsp-mi-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-mi-c-img.mha" ) plmtest_check_interval ("plm-bsp-mi-c-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-mi-c-stats.stdout.txt" "AVE *([-0-9.]*)" "-114.0" "-113.0" ) set_property (TEST plm-bsp-mi-c APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-mi-c APPEND PROPERTY DEPENDS gauss-3) set_tests_properties (plm-bsp-mi-c-stats PROPERTIES DEPENDS plm-bsp-mi-c) set_tests_properties (plm-bsp-mi-c-check PROPERTIES DEPENDS plm-bsp-mi-c-stats) plm_add_test ( "plm-bsp-mi-k" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-mi-k.txt" ) plm_add_test ( "plm-bsp-mi-k-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-mi-k-img.mha" ) plmtest_check_interval ("plm-bsp-mi-k-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-mi-k-stats.stdout.txt" "AVE *([-0-9.]*)" "-114.0" "-113.0" ) set_property (TEST plm-bsp-mi-k APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-mi-k APPEND PROPERTY DEPENDS gauss-3) set_tests_properties (plm-bsp-mi-k-stats PROPERTIES DEPENDS plm-bsp-mi-k) set_tests_properties (plm-bsp-mi-k-check PROPERTIES DEPENDS plm-bsp-mi-k-stats) plm_add_test ( "plm-bsp-gm-k" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-gm-k.txt" ) plm_add_test ( "plm-bsp-gm-k-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-gm-k-img.mha" ) plmtest_check_interval ("plm-bsp-gm-k-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-gm-k-stats.stdout.txt" "AVE *([-0-9.]*)" "-122.5" "-121.5" ) set_property (TEST plm-bsp-gm-k APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-gm-k APPEND PROPERTY DEPENDS gauss-3) set_tests_properties (plm-bsp-gm-k-stats PROPERTIES DEPENDS plm-bsp-gm-k) set_tests_properties (plm-bsp-gm-k-check PROPERTIES DEPENDS plm-bsp-gm-k-stats) # plm_add_test ( # "plm-bsp-dmap-k" # ${PLM_PLASTIMATCH_PATH}/plastimatch # "${PLM_BUILD_TESTING_DIR}/plm-bsp-dmap-k.txt" # ) # plm_add_test ( # "plm-bsp-dmap-k-stats" # ${PLM_PLASTIMATCH_PATH}/plastimatch # "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-dmap-k-img.mha" # ) # plmtest_check_interval ("plm-bsp-dmap-k-check" # "${PLM_BUILD_TESTING_DIR}/plm-bsp-dmap-k-stats.stdout.txt" # "AVE *([-0-9.]*)" # "-122.5" # "-121.5" # ) # set_property (TEST plm-bsp-dmap-k APPEND PROPERTY DEPENDS rect-4) # set_property (TEST plm-bsp-dmap-k APPEND PROPERTY DEPENDS rect-8) # set_tests_properties (plm-bsp-dmap-k-stats PROPERTIES # DEPENDS plm-bsp-dmap-k) # set_tests_properties (plm-bsp-dmap-k-check PROPERTIES # DEPENDS plm-bsp-dmap-k-stats) plm_add_test ( "plm-bsp-sm-multi-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-sm-multi-a.txt" ) plm_add_test ( "plm-bsp-sm-multi-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-sm-multi-a-img.mha" ) # plmtest_check_interval ("plm-bsp-sm-multi-a-check" # "${PLM_BUILD_TESTING_DIR}/plm-bsp-sm-multi-a-stats.stdout.txt" # "AVE *([-0-9.]*)" # "-122.5" # "-121.5" # ) set_property (TEST plm-bsp-sm-multi-a APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-sm-multi-a APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-bsp-sm-multi-a-stats PROPERTIES DEPENDS plm-bsp-sm-multi-a) # set_tests_properties (plm-bsp-sm-multi-a-check PROPERTIES # DEPENDS plm-bsp-sm-multi-a-stats) plm_add_test ( "plm-bsp-openmp" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-bsp-openmp.txt" ) plm_add_test ( "plm-bsp-openmp-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-openmp-img.mha" ) plmtest_check_interval ("plm-bsp-openmp-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-openmp-stats.stdout.txt" "AVE *([-0-9.]*)" "${PLM_BSPLINE_TEST_LOWER_THRESH}" "${PLM_BSPLINE_TEST_UPPER_THRESH}" ) set_property (TEST plm-bsp-openmp APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-openmp APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-bsp-openmp-stats PROPERTIES DEPENDS plm-bsp-openmp) set_tests_properties (plm-bsp-openmp-check PROPERTIES DEPENDS plm-bsp-openmp-stats) plm_add_test ( "plm-bsp-cuda" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-cuda.txt" ) plm_add_test ( "plm-bsp-cuda-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-cuda-img.nrrd" ) plmtest_check_interval ("plm-bsp-cuda-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-cuda-stats.stdout.txt" "AVE *([-0-9.]*)" "${PLM_BSPLINE_TEST_LOWER_THRESH}" "${PLM_BSPLINE_TEST_UPPER_THRESH}" ) set_property (TEST plm-bsp-cuda APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-cuda APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-bsp-cuda-stats PROPERTIES DEPENDS plm-bsp-cuda) set_tests_properties (plm-bsp-cuda-check PROPERTIES DEPENDS plm-bsp-cuda-stats) plm_add_test ( "plm-bsp-resume" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-resume.txt" ) plm_add_test ( "plm-bsp-resume-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-resume-img.mha" ) # plmtest_check_interval ("plm-bsp-resume-check" # "${PLM_BUILD_TESTING_DIR}/plm-bsp-resume-stats.stdout.txt" # "AVE *([-0-9.]*)" # "${PLM_BSPLINE_TEST_LOWER_THRESH}" # "${PLM_BSPLINE_TEST_UPPER_THRESH}" # ) set_property (TEST plm-bsp-resume APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-resume APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-bsp-resume-stats PROPERTIES DEPENDS plm-bsp-resume) # set_tests_properties (plm-bsp-resume-check PROPERTIES # DEPENDS plm-bsp-resume-stats) plm_add_test ( "plm-bsp-logfile" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-logfile.txt" ) plmtest_check_interval ("plm-bsp-logfile-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-logfile-logfile.txt" "\\\\[.*, 5] MSE *([-0-9.]*)" "281.5" "282.5" ) set_property (TEST plm-bsp-logfile APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-logfile APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-bsp-logfile-check PROPERTIES DEPENDS plm-bsp-logfile) plm_add_test ( "plm-bsp-ushort" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-bsp-ushort.txt" ) plm_add_test ( "plm-bsp-ushort-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-ushort-img.mha" ) plmtest_check_interval ("plm-bsp-ushort-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-ushort-stats.stdout.txt" "AVE *([-0-9.]*)" "106.6" "107.6" ) set_tests_properties (plm-bsp-ushort PROPERTIES DEPENDS "gauss-ushort-1;gauss-ushort-2") set_property (TEST plm-bsp-ushort APPEND PROPERTY DEPENDS gauss-ushort-1) set_property (TEST plm-bsp-ushort APPEND PROPERTY DEPENDS gauss-ushort-2) set_tests_properties (plm-bsp-ushort-stats PROPERTIES DEPENDS plm-bsp-ushort) set_tests_properties (plm-bsp-ushort-check PROPERTIES DEPENDS plm-bsp-ushort-stats) plm_add_test ( "plm-bsp-double" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-double.txt" ) plm_add_test ( "plm-bsp-double-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-double-img.mha" ) plmtest_check_interval ("plm-bsp-double-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-double-stats.stdout.txt" "AVE *([-0-9.]*)" "107.6" "108.6" ) set_tests_properties (plm-bsp-double PROPERTIES DEPENDS "gauss-double-1;gauss-double-2") set_tests_properties (plm-bsp-double-stats PROPERTIES DEPENDS plm-bsp-double) set_tests_properties (plm-bsp-double-check PROPERTIES DEPENDS plm-bsp-double-stats) plm_add_test ( "plm-bsp-itk-output" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-bsp-itk-output.txt" ) set_property (TEST plm-bsp-itk-output APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-bsp-itk-output APPEND PROPERTY DEPENDS gauss-2) plm_add_test ( "plm-bsp-char-output" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-bsp-char-output.txt" ) plm_add_test ( "plm-bsp-char-output-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-char-output.mha" ) plmtest_check_interval ( "plm-bsp-char-output-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-char-output-stats.stdout.txt" "MIN *([-0-9.]*)" "-128.1" "-127.9" ) set_tests_properties (plm-bsp-char-output PROPERTIES DEPENDS "rect-2;rect-3") set_tests_properties (plm-bsp-char-output-stats PROPERTIES DEPENDS plm-bsp-char-output) set_tests_properties (plm-bsp-char-output-check PROPERTIES DEPENDS plm-bsp-char-output-stats) ## ------------------------------------------------------------------------- ## plastimatch register (group 3) ## register-bsp-rect ## register-bsp-regularize-none ## register-bsp-regularize-analytic ## register-bsp-regularize-numeric ## ------------------------------------------------------------------------- plm_add_test ( "plm-bsp-rect" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-rect.txt" ) set_tests_properties (plm-bsp-rect PROPERTIES DEPENDS "rect-2;rect-3") plm_add_test ( "plm-bsp-regularize-none" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-bsp-regularize-none.txt" ) plm_add_test ( "plm-bsp-regularize-none-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-regularize-none-vf.mha" ) plmtest_check_interval ( "plm-bsp-regularize-none-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-regularize-none-stats.stdout.txt" "MINJAC *([-0-9.]*)" "0.31" "0.32" ) set_tests_properties (plm-bsp-regularize-none PROPERTIES DEPENDS "rect-3;sphere-2") set_tests_properties (plm-bsp-regularize-none-stats PROPERTIES DEPENDS plm-bsp-regularize-none) set_tests_properties (plm-bsp-regularize-none-check PROPERTIES DEPENDS plm-bsp-regularize-none-stats) plm_add_test ( "plm-bsp-regularize-analytic" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-bsp-regularize-analytic.txt" ) plm_add_test ( "plm-bsp-regularize-analytic-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-regularize-analytic-vf.mha" ) plmtest_check_interval ( "plm-bsp-regularize-analytic-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-regularize-analytic-stats.stdout.txt" "MINJAC *([-0-9.]*)" "0.415" "0.425" ) set_tests_properties (plm-bsp-regularize-analytic PROPERTIES DEPENDS "rect-3;sphere-2") set_tests_properties (plm-bsp-regularize-analytic-stats PROPERTIES DEPENDS plm-bsp-regularize-analytic) set_tests_properties (plm-bsp-regularize-analytic-check PROPERTIES DEPENDS plm-bsp-regularize-analytic-stats) plm_add_test ( "plm-bsp-regularize-numeric" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-regularize-numeric.txt" ) plm_add_test ( "plm-bsp-regularize-numeric-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-regularize-numeric-vf.mha" ) plmtest_check_interval ( "plm-bsp-regularize-numeric-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-regularize-numeric-stats.stdout.txt" "MINJAC *([-0-9.]*)" "0.440" "0.445" ) set_tests_properties (plm-bsp-regularize-numeric PROPERTIES DEPENDS "rect-3;sphere-2") set_tests_properties (plm-bsp-regularize-numeric-stats PROPERTIES DEPENDS plm-bsp-regularize-numeric) set_tests_properties (plm-bsp-regularize-numeric-check PROPERTIES DEPENDS plm-bsp-regularize-numeric-stats) ## ------------------------------------------------------------------------- ## plastimatch register (group 4) ## plm-bsp-landmark-a ## plm-bsp-landmark-b ## plm-bsp-landmark-c Same as "b", but landmarks in stage ## plm-bsp-landmark-d Same as "b", but landmarks within file ## plm-bsp-landmark-e Same as "b", but txt instead of fcsv ## ------------------------------------------------------------------------- plm_add_test ( "plm-bsp-landmark-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-a.txt" ) set_tests_properties (plm-bsp-landmark-a PROPERTIES DEPENDS "rect-2;sphere-2") plm_add_test ( "plm-bsp-landmark-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-b.txt" ) plm_add_test ( "plm-bsp-landmark-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-b-img.mha" ) plmtest_check_interval ( "plm-bsp-landmark-b-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-b-stats.stdout.txt" "AVE *([-0-9.]*)" "-991.5" "-991.0" ) set_tests_properties (plm-bsp-landmark-b PROPERTIES DEPENDS "rect-15;rect-16") set_tests_properties (plm-bsp-landmark-b-stats PROPERTIES DEPENDS plm-bsp-landmark-b) set_tests_properties (plm-bsp-landmark-b-check PROPERTIES DEPENDS plm-bsp-landmark-b-stats) plm_add_test ( "plm-bsp-landmark-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-c.txt" ) plm_add_test ( "plm-bsp-landmark-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-c-img.mha" ) plmtest_check_interval ( "plm-bsp-landmark-c-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-c-stats.stdout.txt" "AVE *([-0-9.]*)" "-991.5" "-991.0" ) set_tests_properties (plm-bsp-landmark-c PROPERTIES DEPENDS "rect-15;rect-16") set_tests_properties (plm-bsp-landmark-c-stats PROPERTIES DEPENDS plm-bsp-landmark-c) set_tests_properties (plm-bsp-landmark-c-check PROPERTIES DEPENDS plm-bsp-landmark-c-stats) plm_add_test ( "plm-bsp-landmark-d" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-d.txt" ) plm_add_test ( "plm-bsp-landmark-d-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-d-img.mha" ) plmtest_check_interval ( "plm-bsp-landmark-d-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-d-stats.stdout.txt" "AVE *([-0-9.]*)" "-991.5" "-991.0" ) set_tests_properties (plm-bsp-landmark-d PROPERTIES DEPENDS "rect-15;rect-16") set_tests_properties (plm-bsp-landmark-d-stats PROPERTIES DEPENDS plm-bsp-landmark-d) set_tests_properties (plm-bsp-landmark-d-check PROPERTIES DEPENDS plm-bsp-landmark-d-stats) plm_add_test ( "plm-bsp-landmark-e" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-e.txt" ) plm_add_test ( "plm-bsp-landmark-e-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-e-img.mha" ) plmtest_check_interval ( "plm-bsp-landmark-e-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-landmark-e-stats.stdout.txt" "AVE *([-0-9.]*)" "-991.5" "-991.0" ) set_tests_properties (plm-bsp-landmark-e PROPERTIES DEPENDS "rect-15;rect-16") set_tests_properties (plm-bsp-landmark-e-stats PROPERTIES DEPENDS plm-bsp-landmark-e) set_tests_properties (plm-bsp-landmark-e-check PROPERTIES DEPENDS plm-bsp-landmark-e-stats) ## ------------------------------------------------------------------------- ## plastimatch register (group 5) ## plm-bsp-dcos-a fixed=standard moving=rotated, flavor=g ## plm-bsp-dcos-b fixed=rotated moving=standard, flavor=g ## plm-bsp-dcos-c fixed=standard moving=rotated, flavor=c ## plm-bsp-dcos-d fixed=rotated moving=standard, flavor=c ## plm-bsp-dcos-e fixed=standard moving=rotated, flavor=h ## plm-bsp-dcos-f fixed=rotated moving=standard, flavor=h ## ------------------------------------------------------------------------- plm_add_test ( "plm-bsp-dcos-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-a.txt" ) plm_add_test ( "plm-bsp-dcos-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-a-img.nrrd" ) plmtest_check_interval ( "plm-bsp-dcos-a-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-816" "-815" ) set_tests_properties (plm-bsp-dcos-a PROPERTIES DEPENDS "rect-2;rect-5") set_tests_properties (plm-bsp-dcos-a-stats PROPERTIES DEPENDS plm-bsp-dcos-a) set_tests_properties (plm-bsp-dcos-a-check PROPERTIES DEPENDS plm-bsp-dcos-a-stats) plm_add_test ( "plm-bsp-dcos-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-b.txt" ) plm_add_test ( "plm-bsp-dcos-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-b-img.nrrd" ) plmtest_check_interval ( "plm-bsp-dcos-b-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-b-stats.stdout.txt" "AVE *([-0-9.]*)" "-796.8" "-795.8" ) set_tests_properties (plm-bsp-dcos-b PROPERTIES DEPENDS "rect-2;rect-5") set_tests_properties (plm-bsp-dcos-b-stats PROPERTIES DEPENDS plm-bsp-dcos-b) set_tests_properties (plm-bsp-dcos-b-check PROPERTIES DEPENDS plm-bsp-dcos-b-stats) plm_add_test ( "plm-bsp-dcos-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-c.txt" ) plm_add_test ( "plm-bsp-dcos-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-c-img.nrrd" ) plmtest_check_interval ( "plm-bsp-dcos-c-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-c-stats.stdout.txt" "AVE *([-0-9.]*)" "-816" "-815" ) set_tests_properties (plm-bsp-dcos-c PROPERTIES DEPENDS "rect-2;rect-5") set_tests_properties (plm-bsp-dcos-c-stats PROPERTIES DEPENDS plm-bsp-dcos-c) set_tests_properties (plm-bsp-dcos-c-check PROPERTIES DEPENDS plm-bsp-dcos-c-stats) plm_add_test ( "plm-bsp-dcos-d" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-d.txt" ) plm_add_test ( "plm-bsp-dcos-d-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-d-img.nrrd" ) plmtest_check_interval ( "plm-bsp-dcos-d-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-d-stats.stdout.txt" "AVE *([-0-9.]*)" "-796.8" "-795.8" ) set_tests_properties (plm-bsp-dcos-d PROPERTIES DEPENDS "rect-2;rect-5") set_tests_properties (plm-bsp-dcos-d-stats PROPERTIES DEPENDS plm-bsp-dcos-d) set_tests_properties (plm-bsp-dcos-d-check PROPERTIES DEPENDS plm-bsp-dcos-d-stats) plm_add_test ( "plm-bsp-dcos-e" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-e.txt" ) plm_add_test ( "plm-bsp-dcos-e-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-e-img.nrrd" ) plmtest_check_interval ( "plm-bsp-dcos-e-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-e-stats.stdout.txt" "AVE *([-0-9.]*)" "-816" "-815" ) set_tests_properties (plm-bsp-dcos-e PROPERTIES DEPENDS "rect-2;rect-5") set_tests_properties (plm-bsp-dcos-e-stats PROPERTIES DEPENDS plm-bsp-dcos-e) set_tests_properties (plm-bsp-dcos-e-check PROPERTIES DEPENDS plm-bsp-dcos-e-stats) plm_add_test ( "plm-bsp-dcos-f" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-f.txt" ) plm_add_test ( "plm-bsp-dcos-f-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-f-img.nrrd" ) plmtest_check_interval ( "plm-bsp-dcos-f-check" "${PLM_BUILD_TESTING_DIR}/plm-bsp-dcos-f-stats.stdout.txt" "AVE *([-0-9.]*)" "-796.8" "-795.8" ) set_tests_properties (plm-bsp-dcos-f PROPERTIES DEPENDS "rect-2;rect-5") set_tests_properties (plm-bsp-dcos-f-stats PROPERTIES DEPENDS plm-bsp-dcos-f) set_tests_properties (plm-bsp-dcos-f-check PROPERTIES DEPENDS plm-bsp-dcos-f-stats) ## ------------------------------------------------------------------------- ## plastimatch register (group 6) ## plm-reg-multi-a versor, then demons ## plm-reg-multi-b two b-spline stages ## ------------------------------------------------------------------------- plm_add_test ( "plm-reg-multi-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-multi-a.txt" ) plm_add_test ( "plm-reg-multi-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-multi-a-vf.nrrd" ) plmtest_check_interval ( "plm-reg-multi-a-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-multi-a-stats.stdout.txt" "Mean: *([-0-9.]*)" "-22" "-18" ) set_tests_properties (plm-reg-multi-a PROPERTIES DEPENDS "rect-2;sphere-2") set_tests_properties (plm-reg-multi-a-stats PROPERTIES DEPENDS plm-reg-multi-a) set_tests_properties (plm-reg-multi-a-check PROPERTIES DEPENDS plm-reg-multi-a-stats) plm_add_test ( "plm-reg-multi-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-multi-b.txt" ) plm_add_test ( "plm-reg-multi-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-multi-b-img.nrrd" ) plmtest_check_interval ( "plm-reg-multi-b-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-multi-b-stats.stdout.txt" "AVE *([-0-9.]*)" "-987" "-984" ) set_tests_properties (plm-reg-multi-b PROPERTIES DEPENDS "rect-2;sphere-2") set_tests_properties (plm-reg-multi-b-stats PROPERTIES DEPENDS plm-reg-multi-b) set_tests_properties (plm-reg-multi-b-check PROPERTIES DEPENDS plm-reg-multi-b-stats) ## ------------------------------------------------------------------------- ## plastimatch register (group 7) - check default value ## plm-reg-dv-itk-translation ## ------------------------------------------------------------------------- plm_add_test ( "plm-reg-dv-itk-translation" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-dv-itk-translation.txt" ) plm_add_test ( "plm-reg-dv-itk-translation-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-dv-itk-translation-img.nrrd" ) plmtest_check_interval ("plm-reg-dv-itk-translation-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-dv-itk-translation-stats.stdout.txt" "AVE *([-0-9.]*)" "-467.1" "-366.9" ) set_property (TEST plm-reg-dv-itk-translation APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-reg-dv-itk-translation APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-reg-dv-itk-translation-stats PROPERTIES DEPENDS plm-reg-dv-itk-translation) set_tests_properties (plm-reg-dv-itk-translation-check PROPERTIES DEPENDS plm-reg-dv-itk-translation-stats) ## ------------------------------------------------------------------------- ## plastimatch register (group 8) ## plm-reg-roi-a bspline + mi ## plm-reg-roi-b itk ## plm-reg-roi-c b-spline, upper rectangle ## plm-reg-roi-d b-spline, lower rectangle ## plm-reg-roi-e itk (no roi), b-spline (roi) ## plm-reg-stiffness-a b-spline, rect vs sphere ## ------------------------------------------------------------------------- plm_add_test ( "plm-reg-roi-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-roi-a.txt" ) set_tests_properties (plm-reg-roi-a PROPERTIES DEPENDS "rect-10;rect-10-mask-1;rect-11;rect-11-mask") plm_add_test ( "plm-reg-roi-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-roi-b.txt" ) set_tests_properties (plm-reg-roi-b PROPERTIES DEPENDS "rectarr-01;rectarr-02;rectarr-m-01") plm_add_test ( "plm-reg-roi-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-roi-c.txt" ) set_tests_properties (plm-reg-roi-c PROPERTIES DEPENDS "rectarr-01;rectarr-02;rectarr-m-01") plm_add_test ( "plm-reg-roi-d" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-roi-d.txt" ) set_tests_properties (plm-reg-roi-d PROPERTIES DEPENDS "rectarr-01;rectarr-02;rectarr-m-02") plm_add_test ( "plm-reg-roi-e" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-roi-e.txt" ) set_tests_properties (plm-reg-roi-e PROPERTIES DEPENDS "rectarr-01;rectarr-02;rectarr-m-02") plm_add_test ( "plm-reg-stiffness-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "register;${PLM_BUILD_TESTING_DIR}/plm-reg-stiffness-a.txt" ) set_tests_properties (plm-reg-stiffness-a PROPERTIES DEPENDS "rect-19;roi-1;sphere-4") ## ------------------------------------------------------------------------- ## plastimatch register (group 9) ## plm-reg-process-a ## ------------------------------------------------------------------------- plm_add_test ( "plm-reg-process-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-process-a.txt" ) plm_add_test ( "plm-reg-process-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-process-a.mha" ) plmtest_check_interval ("plm-reg-process-a-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-process-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-491.0" "-490.0" ) set_property (TEST plm-reg-process-a APPEND PROPERTY DEPENDS gauss-1) set_tests_properties (plm-reg-process-a-stats PROPERTIES DEPENDS plm-reg-process-a) set_tests_properties (plm-reg-process-a-check PROPERTIES DEPENDS plm-reg-process-a-stats) ## ------------------------------------------------------------------------- ## plastimatch register (group 10) ## plm-reg-trans-a Translation with grid search (mse, legacy form) ## plm-reg-trans-b Translation with grid search (mse, new form) ## plm-reg-trans-mi-a Translation with grid search (mutual information) ## ------------------------------------------------------------------------- plm_add_test ( "plm-reg-trans-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-trans-a.txt" ) plm_add_test ( "plm-reg-trans-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-trans-a.mha" ) plmtest_check_interval ("plm-reg-trans-a-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-trans-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-661.75" "-661.65" ) set_property (TEST plm-reg-trans-a APPEND PROPERTY DEPENDS gauss-1) set_tests_properties (plm-reg-trans-a-stats PROPERTIES DEPENDS plm-reg-trans-a) set_tests_properties (plm-reg-trans-a-check PROPERTIES DEPENDS plm-reg-trans-a-stats) plm_add_test ( "plm-reg-trans-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-trans-b.txt" ) plm_add_test ( "plm-reg-trans-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-trans-b.mha" ) plmtest_check_interval ("plm-reg-trans-b-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-trans-b-stats.stdout.txt" "AVE *([-0-9.]*)" "-661.75" "-661.65" ) set_property (TEST plm-reg-trans-b APPEND PROPERTY DEPENDS gauss-1) set_tests_properties (plm-reg-trans-b-stats PROPERTIES DEPENDS plm-reg-trans-b) set_tests_properties (plm-reg-trans-b-check PROPERTIES DEPENDS plm-reg-trans-b-stats) plm_add_test ( "plm-reg-trans-mi-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-trans-mi-a.txt" ) plm_add_test ( "plm-reg-trans-mi-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-trans-mi-a.mha" ) plmtest_check_interval ("plm-reg-trans-mi-a-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-trans-mi-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-612.75" "-612.60" ) set_tests_properties (plm-reg-trans-mi-a PROPERTIES DEPENDS "gauss-1;gauss-2") set_tests_properties (plm-reg-trans-mi-a-stats PROPERTIES DEPENDS plm-reg-trans-mi-a) set_tests_properties (plm-reg-trans-mi-a-check PROPERTIES DEPENDS plm-reg-trans-mi-a-stats) ## ------------------------------------------------------------------------- ## plastimatch register (group 11) ## plm-reg-autores-a Manually set sampling rate using mm ## plm-reg-autores-b Manually set sampling rate using pct ## ------------------------------------------------------------------------- plm_add_test ( "plm-reg-autores-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-autores-a.txt" ) plm_add_test ( "plm-reg-autores-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-autores-a.mha" ) plmtest_check_interval ("plm-reg-autores-a-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-autores-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-597.6" "-597.5" ) set_property (TEST plm-reg-autores-a APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-reg-autores-a APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-reg-autores-a-stats PROPERTIES DEPENDS plm-reg-autores-a) set_tests_properties (plm-reg-autores-a-check PROPERTIES DEPENDS plm-reg-autores-a-stats) plm_add_test ( "plm-reg-autores-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_BUILD_TESTING_DIR}/plm-reg-autores-b.txt" ) plm_add_test ( "plm-reg-autores-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-reg-autores-b.mha" ) plmtest_check_interval ("plm-reg-autores-b-check" "${PLM_BUILD_TESTING_DIR}/plm-reg-autores-b-stats.stdout.txt" "AVE *([-0-9.]*)" "-597.5" "-597.4" ) set_property (TEST plm-reg-autores-b APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-reg-autores-b APPEND PROPERTY DEPENDS gauss-2) set_tests_properties (plm-reg-autores-b-stats PROPERTIES DEPENDS plm-reg-autores-b) set_tests_properties (plm-reg-autores-b-check PROPERTIES DEPENDS plm-reg-autores-b-stats) ## ------------------------------------------------------------------------- ## plastimatch register (group 12) ## plm-reg-gw-a Groupwise registration ## ------------------------------------------------------------------------- # plm_add_test ( # "plm-reg-gw-a" # ${PLM_PLASTIMATCH_PATH}/plastimatch # "${PLM_BUILD_TESTING_DIR}/plm-reg-gw-a.txt" # ) ## ------------------------------------------------------------------------- ## plastimatch compose ## This test uses registers from gauss-1 to gauss-2 which are done above, ## and composes with results from an registration from gauss-2 to ## gauss-5. The composed vf should be correctly align gauss-1 to gauss-5. ## ## plm-reg-compose Make vf for testing composition ## plm-compose-a Compose translation and vector field ## plm-compose-b Compose vector field and vector field ## plm-compose-c Compose bspline and vector field ## ## Remark: these tests are correct, in the sense that they work as ## implemented. Transformation vectors which are not defined are ## set to zero in plastimatch, and this causes artifacts in the composed ## vector field. ## ------------------------------------------------------------------------- plm_add_test ( "plm-reg-compose" ${PLM_PLASTIMATCH_PATH}/plastimatch "${PLM_TESTING_DATA_DIR}/plm-reg-compose.txt" ) set_tests_properties (plm-reg-compose PROPERTIES DEPENDS "gauss-2;gauss-5") plm_add_test ( "plm-compose-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "compose;${PLM_BUILD_TESTING_DIR}/plm-reg-itk-translation-xf.txt;${PLM_BUILD_TESTING_DIR}/plm-reg-compose-vf.mha;${PLM_BUILD_TESTING_DIR}/plm-compose-a-vf.mha" ) plm_add_test ( "plm-compose-a-warp" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--input;${PLM_BUILD_TESTING_DIR}/gauss-5.mha;--xf;${PLM_BUILD_TESTING_DIR}/plm-compose-a-vf.mha;--output-img;${PLM_BUILD_TESTING_DIR}/plm-compose-a-warp.mha" ) plm_add_test ( "plm-compose-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-compose-a-vf.mha" ) plmtest_check_interval ("plm-compose-a-check" "${PLM_BUILD_TESTING_DIR}/plm-compose-a-stats.stdout.txt" "Mean: *([-0-9.]*)" "13.75" "13.85" ) set_tests_properties (plm-compose-a PROPERTIES DEPENDS "plm-reg-itk-translation;plm-reg-compose") set_tests_properties (plm-compose-a-warp PROPERTIES DEPENDS plm-compose-a) set_tests_properties (plm-compose-a-stats PROPERTIES DEPENDS plm-compose-a) set_tests_properties (plm-compose-a-check PROPERTIES DEPENDS plm-compose-a-stats) plm_add_test ( "plm-compose-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "compose;${PLM_BUILD_TESTING_DIR}/plm-reg-itk-translation-vf.mha;${PLM_BUILD_TESTING_DIR}/plm-reg-compose-vf.mha;${PLM_BUILD_TESTING_DIR}/plm-compose-b-vf.mha" ) plm_add_test ( "plm-compose-b-warp" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--input;${PLM_BUILD_TESTING_DIR}/gauss-5.mha;--xf;${PLM_BUILD_TESTING_DIR}/plm-compose-b-vf.mha;--output-img;${PLM_BUILD_TESTING_DIR}/plm-compose-b-warp.mha" ) plm_add_test ( "plm-compose-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-compose-b-vf.mha" ) plmtest_check_interval ("plm-compose-b-check" "${PLM_BUILD_TESTING_DIR}/plm-compose-b-stats.stdout.txt" "Mean: *([-0-9.]*)" "13.75" "13.85" ) set_tests_properties (plm-compose-b PROPERTIES DEPENDS "plm-reg-itk-translation;plm-reg-compose") set_tests_properties (plm-compose-b-warp PROPERTIES DEPENDS plm-compose-b) set_tests_properties (plm-compose-b-stats PROPERTIES DEPENDS plm-compose-b) set_tests_properties (plm-compose-b-check PROPERTIES DEPENDS plm-compose-b-stats) plm_add_test ( "plm-compose-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "compose;${PLM_BUILD_TESTING_DIR}/plm-bsp-mse-h-xf.txt;${PLM_BUILD_TESTING_DIR}/plm-reg-compose-vf.mha;${PLM_BUILD_TESTING_DIR}/plm-compose-c-vf.mha" ) plm_add_test ( "plm-compose-c-warp" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--input;${PLM_BUILD_TESTING_DIR}/gauss-5.mha;--xf;${PLM_BUILD_TESTING_DIR}/plm-compose-c-vf.mha;--output-img;${PLM_BUILD_TESTING_DIR}/plm-compose-c-warp.mha" ) plm_add_test ( "plm-compose-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-compose-c-vf.mha" ) plmtest_check_interval ("plm-compose-c-check" "${PLM_BUILD_TESTING_DIR}/plm-compose-c-stats.stdout.txt" "Mean: *([-0-9.]*)" "12.5" "12.6" ) set_tests_properties (plm-compose-c PROPERTIES DEPENDS "gauss-5;plm-bsp-mse-h;plm-reg-compose") set_tests_properties (plm-compose-c-warp PROPERTIES DEPENDS plm-compose-c) set_tests_properties (plm-compose-c-stats PROPERTIES DEPENDS plm-compose-c) set_tests_properties (plm-compose-c-check PROPERTIES DEPENDS plm-compose-c-stats) ## ------------------------------------------------------------------------- ## plm-resample-a Image, subsample ## plm-resample-b Image, resample to fixed ## plm-resample-c Vector field, resample to fixed ## ------------------------------------------------------------------------- plm_add_test ( "plm-resample-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "resample;--input;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-resample-a.mha;--output-type;float;--subsample;2 2 2" ) plm_add_test ( "plm-resample-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-resample-a.mha" ) plmtest_check_interval ("plm-resample-a-check" "${PLM_BUILD_TESTING_DIR}/plm-resample-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-879.0" "-878.0" ) set_tests_properties (plm-resample-a PROPERTIES DEPENDS gauss-1) set_tests_properties (plm-resample-a-stats PROPERTIES DEPENDS plm-resample-a) set_tests_properties (plm-resample-a-check PROPERTIES DEPENDS plm-resample-a-stats) plm_add_test ( "plm-resample-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "resample;--input;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-resample-b.mha;--output-type;float;--fixed;${PLM_BUILD_TESTING_DIR}/black-1.mha" ) plm_add_test ( "plm-resample-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-resample-b.mha" ) plmtest_check_interval ("plm-resample-b-check" "${PLM_BUILD_TESTING_DIR}/plm-resample-b-stats.stdout.txt" "AVE *([-0-9.]*)" "-879.0" "-878.0" ) set_property (TEST plm-resample-b APPEND PROPERTY DEPENDS gauss-1) set_property (TEST plm-resample-b APPEND PROPERTY DEPENDS black-1) set_tests_properties (plm-resample-b-stats PROPERTIES DEPENDS plm-resample-b) set_tests_properties (plm-resample-b-check PROPERTIES DEPENDS plm-resample-b-stats) plm_add_test ( "plm-resample-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "resample;--input;${PLM_BUILD_TESTING_DIR}/bspline-mi-c-1-vf.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-resample-c-vf.mha;--fixed;${PLM_BUILD_TESTING_DIR}/black-1.mha" ) plm_add_test ( "plm-resample-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-resample-c-vf.mha" ) plmtest_check_interval ("plm-resample-c-check" "${PLM_BUILD_TESTING_DIR}/plm-resample-c-stats.stdout.txt" "Mean: *([-0-9.]*)" "6.67" "6.74" ) set_tests_properties (plm-resample-c PROPERTIES DEPENDS "bspline-mi-c-1;black-1") set_tests_properties (plm-resample-c-stats PROPERTIES DEPENDS plm-resample-c) set_tests_properties (plm-resample-c-check PROPERTIES DEPENDS plm-resample-c-stats) ## ------------------------------------------------------------------------- ## plastimatch scale ## plm-scale-a Scale an image ## plm-scale-vf-a Scale a vector field ## ------------------------------------------------------------------------- plm_add_test ( "plm-scale-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "scale;--output;${PLM_BUILD_TESTING_DIR}/plm-scale-a.nrrd;--weight;0.4;${PLM_BUILD_TESTING_DIR}/rect-1.mha" ) plm_add_test ( "plm-scale-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-scale-a.nrrd" ) plmtest_check_interval ("plm-scale-a-check" "${PLM_BUILD_TESTING_DIR}/plm-scale-a-stats.stdout.txt" "AVE *([-0-9.]*)" "-3.735" "-3.730" ) set_tests_properties (plm-scale-a PROPERTIES DEPENDS "rect-1") set_tests_properties (plm-scale-a-stats PROPERTIES DEPENDS plm-scale-a) set_tests_properties (plm-scale-a-check PROPERTIES DEPENDS plm-scale-a-stats) plm_add_test ( "plm-scale-vf-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "scale;--output;${PLM_BUILD_TESTING_DIR}/plm-scale-vf-a.nrrd;--weight;0.4;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha" ) plm_add_test ( "plm-scale-vf-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-scale-vf-a.nrrd" ) plmtest_check_interval ("plm-scale-vf-a-check" "${PLM_BUILD_TESTING_DIR}/plm-scale-vf-a-stats.stdout.txt" "Mean: *([-0-9.]*)" "4.000" "4.000" ) set_tests_properties (plm-scale-vf-a PROPERTIES DEPENDS vf-trans-1) set_tests_properties (plm-scale-vf-a-stats PROPERTIES DEPENDS plm-scale-vf-a) set_tests_properties (plm-scale-vf-a-check PROPERTIES DEPENDS plm-scale-vf-a-stats) ## ------------------------------------------------------------------------- ## plastimatch sift ## plm-sift-a Run SIFT on rect ## ------------------------------------------------------------------------- plm_add_test ( "plm-sift-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "sift;--output-ps-1;${PLM_BUILD_TESTING_DIR}/plm-sift-a-ps-1.fcsv;--output-ps-2;${PLM_BUILD_TESTING_DIR}/plm-sift-a-ps-2.fcsv;--output-match-1;${PLM_BUILD_TESTING_DIR}/plm-sift-a-match-1.fcsv;--output-match-2;${PLM_BUILD_TESTING_DIR}/plm-sift-a-match-2.fcsv;${PLM_BUILD_TESTING_DIR}/lung-1.mha;${PLM_BUILD_TESTING_DIR}/lung-2.mha" ) plmtest_check_string ("plm-sift-a-check-1" "${PLM_BUILD_TESTING_DIR}/plm-sift-a-match-1.fcsv" "^p1-1,(.*)" "-7.500,7.500,-17.500" ) plmtest_check_string ("plm-sift-a-check-2" "${PLM_BUILD_TESTING_DIR}/plm-sift-a-match-2.fcsv" "^p1-1,(.*)" "-7.500,7.500,-22.500" ) set_tests_properties (plm-sift-a PROPERTIES DEPENDS "lung-1;lung-2") set_tests_properties (plm-sift-a-check-1 PROPERTIES DEPENDS plm-sift-a) set_tests_properties (plm-sift-a-check-2 PROPERTIES DEPENDS plm-sift-a) ## ------------------------------------------------------------------------- ## plm-thumbnail-a: make png file of sphere ## plm-thumbnail-b: make png file of gauss ## plm-thumbnail-c: make png file of gauss (auto-adjust) ## ------------------------------------------------------------------------- plm_add_test ( "plm-thumbnail-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "thumbnail;--input;${PLM_BUILD_TESTING_DIR}/sphere-1.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-thumbnail-a.png;--spacing;2" ) plm_add_test ( "plm-thumbnail-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-thumbnail-a.png" ) plmtest_check_interval ("plm-thumbnail-a-check" "${PLM_BUILD_TESTING_DIR}/plm-thumbnail-a-stats.stdout.txt" "AVE *([-0-9.]*)" "76.85" "76.95" ) set_tests_properties (plm-thumbnail-a PROPERTIES DEPENDS sphere-1) set_tests_properties (plm-thumbnail-a-stats PROPERTIES DEPENDS plm-thumbnail-a) set_tests_properties (plm-thumbnail-a-check PROPERTIES DEPENDS plm-thumbnail-a-stats) plm_add_test ( "plm-thumbnail-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "thumbnail;--input;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-thumbnail-b.png;--spacing;2" ) plm_add_test ( "plm-thumbnail-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-thumbnail-b.png" ) plmtest_check_interval ("plm-thumbnail-b-check" "${PLM_BUILD_TESTING_DIR}/plm-thumbnail-b-stats.stdout.txt" "AVE *([-0-9.]*)" "0.0" "0.0" ) set_tests_properties (plm-thumbnail-b PROPERTIES DEPENDS gauss-1) set_tests_properties (plm-thumbnail-b-stats PROPERTIES DEPENDS plm-thumbnail-b) set_tests_properties (plm-thumbnail-b-check PROPERTIES DEPENDS plm-thumbnail-b-stats) plm_add_test ( "plm-thumbnail-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "thumbnail;--input;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-thumbnail-c.png;--spacing;2;--auto-adjust" ) plm_add_test ( "plm-thumbnail-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-thumbnail-c.png" ) plmtest_check_interval ("plm-thumbnail-c-check" "${PLM_BUILD_TESTING_DIR}/plm-thumbnail-c-stats.stdout.txt" "AVE *([-0-9.]*)" "8.1" "8.3" ) set_tests_properties (plm-thumbnail-c PROPERTIES DEPENDS gauss-1) set_tests_properties (plm-thumbnail-c-stats PROPERTIES DEPENDS plm-thumbnail-c) set_tests_properties (plm-thumbnail-c-check PROPERTIES DEPENDS plm-thumbnail-c-stats) ## ------------------------------------------------------------------------- ## plm-union ## ------------------------------------------------------------------------- plm_add_test ( "plm-union" ${PLM_PLASTIMATCH_PATH}/plastimatch "union;--output;${PLM_BUILD_TESTING_DIR}/plm-union.mha;${PLM_BUILD_TESTING_DIR}/rect-10-roi-1.mha;${PLM_BUILD_TESTING_DIR}/rect-11-roi.mha" ) plm_add_test ( "plm-union-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-union.mha" ) plmtest_check_interval ("plm-union-check" "${PLM_BUILD_TESTING_DIR}/plm-union-stats.stdout.txt" "NONZERO *([-0-9.]*)" "1271" "1271" ) set_tests_properties (plm-union PROPERTIES DEPENDS "rect-10-roi-1;rect-11-roi") set_tests_properties (plm-union-stats PROPERTIES DEPENDS plm-union) set_tests_properties (plm-union-check PROPERTIES DEPENDS plm-union-stats) ## ------------------------------------------------------------------------- ## plm-threshold-a ## plm-threshold-b ## plm-threshold-c ## ------------------------------------------------------------------------- plm_add_test ( "plm-threshold-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "threshold;--input;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-threshold-a.mha;--above;-888" ) plm_add_test ( "plm-threshold-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-threshold-a.mha" ) plmtest_check_interval ("plm-threshold-a-check" "${PLM_BUILD_TESTING_DIR}/plm-threshold-a-stats.stdout.txt" "AVE *([-0-9.]*)" "0.306" "0.308" ) set_tests_properties (plm-threshold-a PROPERTIES DEPENDS "gauss-1") set_tests_properties (plm-threshold-a-stats PROPERTIES DEPENDS plm-threshold-a) set_tests_properties (plm-threshold-a-check PROPERTIES DEPENDS plm-threshold-a-stats) plm_add_test ( "plm-threshold-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "threshold;--input;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-threshold-b.mha;--below;-900" ) plm_add_test ( "plm-threshold-b-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-threshold-b.mha" ) plmtest_check_interval ("plm-threshold-b-check" "${PLM_BUILD_TESTING_DIR}/plm-threshold-b-stats.stdout.txt" "AVE *([-0-9.]*)" "0.670" "0.672" ) set_tests_properties (plm-threshold-b PROPERTIES DEPENDS "gauss-1") set_tests_properties (plm-threshold-b-stats PROPERTIES DEPENDS plm-threshold-b) set_tests_properties (plm-threshold-b-check PROPERTIES DEPENDS plm-threshold-b-stats) plm_add_test ( "plm-threshold-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "threshold;--input;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-threshold-c.mha;--range;-900,-888" ) plm_add_test ( "plm-threshold-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-threshold-c.mha" ) plmtest_check_interval ("plm-threshold-c-check" "${PLM_BUILD_TESTING_DIR}/plm-threshold-c-stats.stdout.txt" "NONZERO *([-0-9.]*)" "1206" "1206" ) set_tests_properties (plm-threshold-c PROPERTIES DEPENDS "gauss-1") set_tests_properties (plm-threshold-c-stats PROPERTIES DEPENDS plm-threshold-c) set_tests_properties (plm-threshold-c-check PROPERTIES DEPENDS plm-threshold-c-stats) ## ------------------------------------------------------------------------- ## plastimatch warp pointset ## plm-warp-pointset-a: xf = bspline, output fcsv ## plm-warp-pointset-b: xf = bspline, output txt ## plm-warp-pointset-c: xf = vf, output fcsv ## ------------------------------------------------------------------------- plm_add_test ( "plm-warp-pointset-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--xf;${PLM_BUILD_TESTING_DIR}/plm-bsp-rect-xf.txt;--input;${PLM_TESTING_DATA_DIR}/fiducials-rect-2.fcsv;--output-pointset;${PLM_BUILD_TESTING_DIR}/plm-warp-pointset-a.fcsv" ) plm_add_test ( "plm-warp-pointset-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--xf;${PLM_BUILD_TESTING_DIR}/plm-bsp-rect-xf.txt;--input;${PLM_TESTING_DATA_DIR}/fiducials-rect-2.fcsv;--output-pointset;${PLM_BUILD_TESTING_DIR}/plm-warp-pointset-b.txt" ) plm_add_test ( "plm-warp-pointset-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--xf;${PLM_BUILD_TESTING_DIR}/landmark-warp-c-vf.mha;--input;${PLM_TESTING_DATA_DIR}/fiducials-rect-2.fcsv;--output-pointset;${PLM_BUILD_TESTING_DIR}/plm-warp-landmark-c.fcsv" ) set_tests_properties (plm-warp-pointset-a PROPERTIES DEPENDS plm-bsp-rect) set_tests_properties (plm-warp-pointset-b PROPERTIES DEPENDS plm-bsp-rect) set_tests_properties (plm-warp-pointset-c PROPERTIES DEPENDS landmark-warp-c) ## ------------------------------------------------------------------------- ## plastimatch warp ## plm warp a: xf = bspline, algorithm = itk ## plm warp b: xf = bspline, algorithm = native ## plm warp c: xf = bspline, algorithm = itk, interp = nn ## plm warp d: xf = bspline, algorithm = native, interp = nn ## plm warp e: input = xio, multiple outputs ## plm warp f: input = dicom, multiple outputs ## plm warp g: xf = translation ## plm warp h: xf = translation, ushort images ## plm warp i: xf = translation, double images ## ------------------------------------------------------------------------- plm_add_test ( "plm-warp-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--algorithm;itk;--xf;${PLM_BUILD_TESTING_DIR}/bspline_c_xf.txt;--output-vf;${PLM_BUILD_TESTING_DIR}/plm-warp-a-vf.mha;--input;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output-img;${PLM_BUILD_TESTING_DIR}/plm-warp-a.mha" ) plm_add_test ( "plm-warp-a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-a-vf.mha" ) plmtest_check_interval ("plm-warp-a-check" "${PLM_BUILD_TESTING_DIR}/plm-warp-a-stats.stdout.txt" "Mean: *([-0-9.]*)" "5.77" "5.78" ) ## Note: don't include dependency on gauss-1 as workaround for cmake bug. set_property (TEST plm-warp-a APPEND PROPERTY DEPENDS bspline-c) #set_property (TEST plm-warp-a APPEND PROPERTY DEPENDS gauss-1) set_tests_properties (plm-warp-a-stats PROPERTIES DEPENDS plm-warp-a) set_tests_properties (plm-warp-a-check PROPERTIES DEPENDS plm-warp-a-stats) plm_add_test ( "plm-warp-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--xf;${PLM_BUILD_TESTING_DIR}/bspline_c_xf.txt;--output-vf;${PLM_BUILD_TESTING_DIR}/plm-warp-b-vf.mha;--input;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output-img;${PLM_BUILD_TESTING_DIR}/plm-warp-b.mha;--default-value;0" ) plm_add_test ( "plm-warp-b-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-b-vf.mha" ) plmtest_check_interval ("plm-warp-b-check-1" "${PLM_BUILD_TESTING_DIR}/plm-warp-b-stats-1.stdout.txt" "Mean: *([-0-9.]*)" "5.77" "5.78" ) plm_add_test ( "plm-warp-b-stats-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-b.mha" ) plmtest_check_interval ("plm-warp-b-check-2" "${PLM_BUILD_TESTING_DIR}/plm-warp-b-stats-2.stdout.txt" "AVE *([-0-9.]*)" "-775.7" "-775.6" ) ## Note: don't include dependency on gauss-1 as workaround for cmake bug. set_property (TEST plm-warp-b APPEND PROPERTY DEPENDS bspline-c) #set_property (TEST plm-warp-b APPEND PROPERTY DEPENDS gauss-1) set_tests_properties (plm-warp-b-stats-1 PROPERTIES DEPENDS plm-warp-b) set_tests_properties (plm-warp-b-check-1 PROPERTIES DEPENDS plm-warp-b-stats-1) set_tests_properties (plm-warp-b-stats-2 PROPERTIES DEPENDS plm-warp-b) set_tests_properties (plm-warp-b-check-2 PROPERTIES DEPENDS plm-warp-b-stats-2) plm_add_test ( "plm-warp-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--algorithm;itk;--xf;${PLM_BUILD_TESTING_DIR}/bspline_c_xf.txt;--output-vf;${PLM_BUILD_TESTING_DIR}/plm-warp-c-vf.mha;--input;${PLM_BUILD_TESTING_DIR}/sphere-1.mha;--output-img;${PLM_BUILD_TESTING_DIR}/plm-warp-c.mha;--interpolation;nn;--default-value;0" ) plm_add_test ( "plm-warp-c-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-c.mha" ) plmtest_check_interval ("plm-warp-c-check" "${PLM_BUILD_TESTING_DIR}/plm-warp-c-stats.stdout.txt" "AVE *([-0-9.]*)" "9.2" "9.3" ) set_tests_properties (plm-warp-c PROPERTIES DEPENDS "bspline-c;sphere-1") set_tests_properties (plm-warp-c-stats PROPERTIES DEPENDS plm-warp-c) set_tests_properties (plm-warp-c-check PROPERTIES DEPENDS plm-warp-c-stats) plm_add_test ( "plm-warp-d" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--xf;${PLM_BUILD_TESTING_DIR}/bspline_c_xf.txt;--output-vf;${PLM_BUILD_TESTING_DIR}/plm-warp-d-vf.mha;--input;${PLM_BUILD_TESTING_DIR}/sphere-1.mha;--output-img;${PLM_BUILD_TESTING_DIR}/plm-warp-d.mha;--interpolation;nn;--default-value;0" ) plm_add_test ( "plm-warp-d-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-warp-d.mha" ) plmtest_check_interval ("plm-warp-d-check" "${PLM_BUILD_TESTING_DIR}/plm-warp-d-stats.stdout.txt" "AVE *([-0-9.]*)" "9.2" "9.3" ) set_tests_properties (plm-warp-d PROPERTIES DEPENDS "bspline-c;sphere-1") set_tests_properties (plm-warp-d-stats PROPERTIES DEPENDS plm-warp-d) set_tests_properties (plm-warp-d-check PROPERTIES DEPENDS plm-warp-d-stats) plm_add_test ( "plm-warp-g" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--xf;${PLM_TESTING_DATA_DIR}/xf-translation-1.txt;--input;${PLM_BUILD_TESTING_DIR}/gauss-1.mha;--output-img;${PLM_BUILD_TESTING_DIR}/plm-warp-g-img.nrrd;--default-value;0" ) plm_add_test ( "plm-warp-g-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;plm-warp-g-img.nrrd" ) plmtest_check_interval ("plm-warp-g-check-1" "${PLM_BUILD_TESTING_DIR}/plm-warp-g-stats-1.stdout.txt" "AVE *([-0-9.]*)" "-675.5" "-674.5" ) set_tests_properties (plm-warp-g PROPERTIES DEPENDS gauss-1) set_tests_properties (plm-warp-g-stats-1 PROPERTIES DEPENDS plm-warp-g) set_tests_properties (plm-warp-g-check-1 PROPERTIES DEPENDS plm-warp-g-stats-1) plm_add_test ( "plm-warp-h" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--xf;${PLM_TESTING_DATA_DIR}/xf-translation-1.txt;--input;${PLM_BUILD_TESTING_DIR}/gauss-ushort-1.mha;--output-img;${PLM_BUILD_TESTING_DIR}/plm-warp-h-img.nrrd;--default-value;0" ) plm_add_test ( "plm-warp-h-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;plm-warp-h-img.nrrd" ) plmtest_check_interval ("plm-warp-h-check-1" "${PLM_BUILD_TESTING_DIR}/plm-warp-h-stats-1.stdout.txt" "AVE *([-0-9.]*)" "113.5" "114.0" ) set_tests_properties (plm-warp-h PROPERTIES DEPENDS gauss-ushort-1) set_tests_properties (plm-warp-h-stats-1 PROPERTIES DEPENDS plm-warp-h) set_tests_properties (plm-warp-h-check-1 PROPERTIES DEPENDS plm-warp-h-stats-1) plm_add_test ( "plm-warp-i" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--xf;${PLM_TESTING_DATA_DIR}/xf-translation-1.txt;--input;${PLM_BUILD_TESTING_DIR}/gauss-double-1.mha;--output-img;${PLM_BUILD_TESTING_DIR}/plm-warp-i-img.nrrd;--default-value;0" ) plm_add_test ( "plm-warp-i-stats-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;plm-warp-i-img.nrrd" ) plmtest_check_interval ("plm-warp-i-check-1" "${PLM_BUILD_TESTING_DIR}/plm-warp-i-stats-1.stdout.txt" "AVE *([-0-9.]*)" "114.4" "114.7" ) set_tests_properties (plm-warp-i PROPERTIES DEPENDS gauss-double-1) set_tests_properties (plm-warp-i-stats-1 PROPERTIES DEPENDS plm-warp-i) set_tests_properties (plm-warp-i-check-1 PROPERTIES DEPENDS plm-warp-i-stats-1) ## ------------------------------------------------------------------------- ## plm-xf-convert-a plm bspline to vf ## plm-xf-convert-b vf to plm bspline ## plm-xf-convert-c plm bspline to vf ## plm-xf-convert-d plm bspline to itk bspline ## plm-xf-convert-e itk rigid to dicom rigid (referenced dicom images) ## plm-xf-convert-f itk rigid to dicom rigid (exported dicom images) ## ------------------------------------------------------------------------- plm_add_test ( "plm-xf-convert-a" ${PLM_PLASTIMATCH_PATH}/plastimatch "xf-convert;--input;${PLM_TESTING_DATA_DIR}/xf-bspline-1.txt;--output;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-a-vf.mha;--output-type;vf;--dim;4 4 4;--origin;-187.5 -187.5 -187.5;--spacing;125 125 125;" ) plm_add_test ( "plm-xf-convert-b" ${PLM_PLASTIMATCH_PATH}/plastimatch "xf-convert;--input;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-a-vf.mha;--output;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-b.txt;--output-type;bspline;--dim;4 4 4;--origin;-187.5 -187.5 -187.5;--spacing;125 125 125;--grid-spacing;10 10 10" ) set_tests_properties (plm-xf-convert-b PROPERTIES DEPENDS plm-xf-convert-a) plm_add_test ( "plm-xf-convert-c" ${PLM_PLASTIMATCH_PATH}/plastimatch "xf-convert;--input;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-b.txt;--output;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-c-vf.mha;--output-type;vf;--dim;4 4 4;--origin;-187.5 -187.5 -187.5;--spacing;125 125 125" ) set_tests_properties (plm-xf-convert-c PROPERTIES DEPENDS plm-xf-convert-b) plm_add_test ( "plm-xf-convert-d" ${PLM_PLASTIMATCH_PATH}/plastimatch "xf-convert;--input;${PLM_TESTING_DATA_DIR}/plm-xf-convert.txt;--output;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-d-xf.tfm;--output-type;itk_bspline" ) plm_add_test ( "plm-xf-convert-d-warp-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--input;${PLM_BUILD_TESTING_DIR}/gauss-2.mha;--xf;${PLM_TESTING_DATA_DIR}/plm-xf-convert.txt;--output-img;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-d-warp-1.nrrd" ) plm_add_test ( "plm-xf-convert-d-warp-1-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-d-warp-1.nrrd" ) plmtest_check_interval ( "plm-xf-convert-d-warp-1-check" "${PLM_BUILD_TESTING_DIR}/plm-xf-convert-d-warp-1-stats.stdout.txt" "AVE *([-0-9.]*)" "-745.8" "-744.8" ) plm_add_test ( "plm-xf-convert-d-warp-2" ${PLM_PLASTIMATCH_PATH}/plastimatch "warp;--input;${PLM_BUILD_TESTING_DIR}/gauss-2.mha;--xf;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-d-xf.tfm;--output-img;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-d-warp-2.nrrd" ) plm_add_test ( "plm-xf-convert-d-warp-2-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-d-warp-2.nrrd" ) plmtest_check_interval ( "plm-xf-convert-d-warp-2-check" "${PLM_BUILD_TESTING_DIR}/plm-xf-convert-d-warp-2-stats.stdout.txt" "AVE *([-0-9.]*)" # GCS 2011-10-08. The ITK B-spline resampling method is very poor, and # gives different results on different platforms. Probably we need # to convert all ITK B-splines to native, and resample using the # native method. "-751.0" # "-745.8" "-744.8" ) set_tests_properties (plm-xf-convert-d-warp-1 PROPERTIES DEPENDS gauss-2) set_tests_properties (plm-xf-convert-d-warp-1-stats PROPERTIES DEPENDS plm-xf-convert-d-warp-1) set_tests_properties (plm-xf-convert-d-warp-1-check PROPERTIES DEPENDS plm-xf-convert-d-warp-1-stats) set_tests_properties (plm-xf-convert-d-warp-2 PROPERTIES DEPENDS "gauss-2;plm-xf-convert-d") set_tests_properties (plm-xf-convert-d-warp-2-stats PROPERTIES DEPENDS plm-xf-convert-d-warp-2) set_tests_properties (plm-xf-convert-d-warp-2-check PROPERTIES DEPENDS plm-xf-convert-d-warp-2-stats) plm_add_test ( "plm-xf-convert-e" ${PLM_PLASTIMATCH_PATH}/plastimatch "xf-convert;--input;${PLM_TESTING_DATA_DIR}/itk-rigid-a.tfm;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-e;--fixed-rcs;${PLM_BUILD_TESTING_DIR}/rect-2-dicom;--moving-rcs;${PLM_BUILD_TESTING_DIR}/rect-3-dicom" ) set_tests_properties (plm-xf-convert-e PROPERTIES DEPENDS "rect-2;rect-3") plm_add_test ( "plm-xf-convert-f" ${PLM_PLASTIMATCH_PATH}/plastimatch "xf-convert;--input;${PLM_TESTING_DATA_DIR}/itk-rigid-a.tfm;--output-dicom;${PLM_BUILD_TESTING_DIR}/plm-xf-convert-f;--fixed-image;${PLM_BUILD_TESTING_DIR}/rect-2.mha;--moving-image;${PLM_BUILD_TESTING_DIR}/rect-3.mha" ) set_tests_properties (plm-xf-convert-f PROPERTIES DEPENDS "rect-2;rect-3") ## ------------------------------------------------------------------------- ## vf-invert ## ------------------------------------------------------------------------- ## vf-invert-zero-1 invert zero vector field ## vf-invert-trans-1 invert translation x direction, 1cm ## vf-invert-gauss-1 invert gaussian warp, 10cm std, 1cm x, 2cm y ## ------------------------------------------------------------------------- plm_add_test ( "vf-invert-zero-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "vf-invert;--input;${PLM_BUILD_TESTING_DIR}/vf-zero.mha;--fixed;${PLM_BUILD_TESTING_DIR}/vf-zero.mha;--output;${PLM_BUILD_TESTING_DIR}/vf-invert-zero-1.mha" ) plm_add_test ( "vf-invert-zero-1-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/vf-invert-zero-1.mha" ) plmtest_check_interval ("vf-invert-zero-1-check" "${PLM_BUILD_TESTING_DIR}/vf-invert-zero-1-stats.stdout.txt" "Mean abs: *([-0-9.]*)" "0.000" "0.000" ) set_tests_properties (vf-invert-zero-1 PROPERTIES DEPENDS vf-zero) set_tests_properties (vf-invert-zero-1-stats PROPERTIES DEPENDS vf-invert-zero-1) set_tests_properties (vf-invert-zero-1-check PROPERTIES DEPENDS vf-invert-zero-1-stats) plm_add_test ( "vf-invert-trans-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "vf-invert;--input;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha;--fixed;${PLM_BUILD_TESTING_DIR}/vf-trans-1.mha;--output;${PLM_BUILD_TESTING_DIR}/vf-invert-trans-1.mha;--iterations;10" ) plm_add_test ( "vf-invert-trans-1-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/vf-invert-trans-1.mha" ) plmtest_check_interval ("vf-invert-trans-1-check" "${PLM_BUILD_TESTING_DIR}/vf-invert-trans-1-stats.stdout.txt" "Mean: *([-0-9.]*)" "-10.0" "-9.9" ) set_tests_properties (vf-invert-trans-1 PROPERTIES DEPENDS vf-trans-1) set_tests_properties (vf-invert-trans-1-stats PROPERTIES DEPENDS vf-invert-trans-1) set_tests_properties (vf-invert-trans-1-check PROPERTIES DEPENDS vf-invert-trans-1-stats) ## ------------------------------------------------------------------------- ## bragg-curve ## proton-dose-1 Flavor a, sobp ## proton-dose-5a Flavor a, sobp target with aperture and rgc ## proton-dose-5d Flavor d, sobp target with aperture and rgc ## proton-dose-6a Flavor a, target geometry differs from CT geometry ## ------------------------------------------------------------------------- plm_add_test ( "bragg-curve" ${PLM_PLASTIMATCH_PATH}/bragg_curve "-O;${PLM_BUILD_TESTING_DIR}/bragg-curve.txt" ) add_test (bragg-curve-check ${CMAKE_COMMAND} -E compare_files "${PLM_TESTING_DATA_DIR}/bragg-curve.txt" "${PLM_BUILD_TESTING_DIR}/bragg-curve.txt") set_tests_properties (bragg-curve-check PROPERTIES DEPENDS bragg-curve) plm_add_test ( "proton-dose-1" ${PLM_PLASTIMATCH_PATH}/plastimatch "dose;${PLM_BUILD_TESTING_DIR}/proton-dose-1.txt" ) plm_add_test ( "proton-dose-1-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/proton-dose-1.mha" ) plmtest_check_interval ("proton-dose-1-check" "${PLM_BUILD_TESTING_DIR}/proton-dose-1-stats.stdout.txt" "AVE *([-0-9.]*)" "0.140" "0.145" ) set_tests_properties (proton-dose-1 PROPERTIES DEPENDS rect-17) set_tests_properties (proton-dose-1-stats PROPERTIES DEPENDS proton-dose-1) set_tests_properties (proton-dose-1-check PROPERTIES DEPENDS proton-dose-1-stats) plm_add_test ( "proton-dose-5a" ${PLM_PLASTIMATCH_PATH}/plastimatch "dose;${PLM_BUILD_TESTING_DIR}/proton-dose-5a.txt" ) plm_add_test ( "proton-dose-5a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/proton-dose-5a.mha" ) plmtest_check_interval ("proton-dose-5a-check" "${PLM_BUILD_TESTING_DIR}/proton-dose-5a-stats.stdout.txt" "AVE *([-0-9.]*)" "0.26" "0.27" ) set_tests_properties (proton-dose-5a PROPERTIES DEPENDS rect-17) set_tests_properties (proton-dose-5a PROPERTIES DEPENDS ptv-1) set_tests_properties (proton-dose-5a-stats PROPERTIES DEPENDS proton-dose-5a) set_tests_properties (proton-dose-5a-check PROPERTIES DEPENDS proton-dose-5a-stats) plm_add_test ( "proton-dose-5d" ${PLM_PLASTIMATCH_PATH}/plastimatch "dose;${PLM_BUILD_TESTING_DIR}/proton-dose-5d.txt" ) plm_add_test ( "proton-dose-5d-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/proton-dose-5d.mha" ) plmtest_check_interval ("proton-dose-5d-check" "${PLM_BUILD_TESTING_DIR}/proton-dose-5d-stats.stdout.txt" "AVE *([-0-9.]*)" "0.38" "0.39" ) set_tests_properties (proton-dose-5d PROPERTIES DEPENDS rect-17) set_tests_properties (proton-dose-5d PROPERTIES DEPENDS ptv-1) set_tests_properties (proton-dose-5d-stats PROPERTIES DEPENDS proton-dose-5d) set_tests_properties (proton-dose-5d-check PROPERTIES DEPENDS proton-dose-5d-stats) plm_add_test ( "proton-dose-6a" ${PLM_PLASTIMATCH_PATH}/plastimatch "dose;${PLM_BUILD_TESTING_DIR}/proton-dose-6a.txt" ) plm_add_test ( "proton-dose-6a-stats" ${PLM_PLASTIMATCH_PATH}/plastimatch "stats;${PLM_BUILD_TESTING_DIR}/proton-dose-6a.mha" ) plmtest_check_interval ("proton-dose-6a-check" "${PLM_BUILD_TESTING_DIR}/proton-dose-6a-stats.stdout.txt" "AVE *([-0-9.]*)" "0.26" "0.27" ) set_tests_properties (proton-dose-6a PROPERTIES DEPENDS rect-17) set_tests_properties (proton-dose-6a PROPERTIES DEPENDS ptv-2) set_tests_properties (proton-dose-6a-stats PROPERTIES DEPENDS proton-dose-6a) set_tests_properties (proton-dose-6a-check PROPERTIES DEPENDS proton-dose-6a-stats) ## ------------------------------------------------------------------------- ## wed-a ct to proj-wed, proj-ct, and wed-ct ## wed-b load saved proj-wed, compute proj-ct and wed-ct ## wed-c proj-wed to dew-ct ## ------------------------------------------------------------------------- plm_add_test ( "wed-a" ${PLM_PLASTIMATCH_PATH}/wed "${PLM_BUILD_TESTING_DIR}/wed-a.txt" ) set_tests_properties (wed-a PROPERTIES DEPENDS lung-1) plm_add_test ( "wed-b" ${PLM_PLASTIMATCH_PATH}/wed "${PLM_BUILD_TESTING_DIR}/wed-b.txt" ) set_tests_properties (wed-b PROPERTIES DEPENDS lung-1) set_tests_properties (wed-b PROPERTIES DEPENDS wed-a) plm_add_test ( "wed-c" ${PLM_PLASTIMATCH_PATH}/wed "${PLM_BUILD_TESTING_DIR}/wed-c.txt" ) set_tests_properties (wed-c PROPERTIES DEPENDS lung-1) set_tests_properties (wed-c PROPERTIES DEPENDS wed-a) ## ------------------------------------------------------------------------- ## i hate myself ## ------------------------------------------------------------------------- if (${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "^(ppc|powerpc)") plmtest_debug (debug-fdk-cpu-a "${PLM_BUILD_TESTING_DIR}/fdk-cpu-a.stdout.txt" "${PLM_BUILD_TESTING_DIR}/fdk-cpu-a.stderr.txt") plmtest_debug (debug-fdk-cpu-a-stats "${PLM_BUILD_TESTING_DIR}/fdk-cpu-a-stats.stdout.txt" "${PLM_BUILD_TESTING_DIR}/fdk-cpu-a-stats.stderr.txt") set_tests_properties (debug-fdk-cpu-a PROPERTIES DEPENDS fdk-cpu-a) set_tests_properties (debug-fdk-cpu-a-stats PROPERTIES DEPENDS fdk-cpu-a-stats) plmtest_debug (debug-landmark-warp-b "${PLM_BUILD_TESTING_DIR}/landmark-warp-b.stdout.txt" "${PLM_BUILD_TESTING_DIR}/landmark-warp-b.stderr.txt") plmtest_debug (debug-landmark-warp-b-stats "${PLM_BUILD_TESTING_DIR}/landmark-warp-b-stats.stdout.txt" "${PLM_BUILD_TESTING_DIR}/landmark-warp-b-stats.stderr.txt") set_tests_properties (debug-landmark-warp-b PROPERTIES DEPENDS landmark-warp-b) set_tests_properties (debug-landmark-warp-b-stats PROPERTIES DEPENDS landmark-warp-b-stats) plmtest_debug (debug-plm-bsp-char-output "${PLM_BUILD_TESTING_DIR}/plm-bsp-char-output.stdout.txt" "${PLM_BUILD_TESTING_DIR}/plm-bsp-char-output.stderr.txt") plmtest_debug (debug-plm-bsp-char-output-stats "${PLM_BUILD_TESTING_DIR}/plm-bsp-char-output-stats.stdout.txt" "${PLM_BUILD_TESTING_DIR}/plm-bsp-char-output-stats.stderr.txt") set_tests_properties (debug-plm-bsp-char-output PROPERTIES DEPENDS plm-bsp-char-output) set_tests_properties (debug-plm-bsp-char-output-stats PROPERTIES DEPENDS plm-bsp-char-output-stats) endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/CTestCustom.cmake.in000066400000000000000000000440231321604176500267630ustar00rootroot00000000000000set (PLM_CONFIG_DEBIAN_BUILD @PLM_CONFIG_DEBIAN_BUILD@) set (CMAKE_Fortran_COMPILER_WORKS @CMAKE_Fortran_COMPILER_WORKS@) set (CUDA_FOUND @CUDA_FOUND@) set (FFTW_FOUND @FFTW_FOUND@) set (ITK_VERSION "@ITK_VERSION@") set (OPENCL_FOUND @OPENCL_FOUND@) set (PLM_DCM_USE_DCMTK "@PLM_DCM_USE_DCMTK@") set (PLM_DCM_USE_GDCM1 "@PLM_DCM_USE_GDCM1@") set (PLM_DCM_USE_GDCM2 "@PLM_DCM_USE_GDCM2@") set (PLM_PLASTIMATCH_PATH "@PLM_PLASTIMATCH_PATH@") set (PLM_PLASTIMATCH_PATH_HACK "@PLM_PLASTIMATCH_PATH_HACK@") set (PLM_REDUCED_TESTS @PLM_REDUCED_TESTS@) set (PLM_TEST_DICOM @PLM_TEST_DICOM@) set (PLM_BUILD_TESTING_DIR "@PLM_BUILD_TESTING_DIR@") set (CMAKE_HOST_SYSTEM_PROCESSOR "@CMAKE_HOST_SYSTEM_PROCESSOR@") ## If we don't have functioning CUDA, don't run CUDA tests set (RUN_CUDA_TESTS OFF) if (CUDA_FOUND) execute_process (COMMAND "${PLM_PLASTIMATCH_PATH}/cuda_probe" RESULT_VARIABLE CUDA_PROBE_RESULT OUTPUT_VARIABLE CUDA_PROBE_STDOUT ERROR_VARIABLE CUDA_PROBE_STDERR ) file (WRITE "${PLM_BUILD_TESTING_DIR}/cuda_probe_result.txt" "${CUDA_PROBE_RESULT}") file (WRITE "${PLM_BUILD_TESTING_DIR}/cuda_probe_stdout.txt" "${CUDA_PROBE_STDOUT}") file (WRITE "${PLM_BUILD_TESTING_DIR}/cuda_probe_stderr.txt" "${CUDA_PROBE_STDERR}") string (REGEX MATCH "NOT cuda capable" CUDA_PROBE_NOT_CAPABLE "${CUDA_PROBE_STDOUT}") if (NOT CUDA_PROBE_RESULT AND NOT CUDA_PROBE_NOT_CAPABLE) set (RUN_CUDA_TESTS ON) endif () endif () ## If we don't have functioning OpenCL, don't run OpenCL tests set (RUN_OPENCL_TESTS OFF) if (OPENCL_FOUND) execute_process (COMMAND "${PLM_PLASTIMATCH_PATH}/opencl_probe" RESULT_VARIABLE OPENCL_PROBE_RESULT OUTPUT_VARIABLE OPENCL_PROBE_STDOUT ERROR_VARIABLE OPENCL_PROBE_STDERR ) file (WRITE "${PLM_BUILD_TESTING_DIR}/opencl_probe_result.txt" "${OPENCL_PROBE_RESULT}") file (WRITE "${PLM_BUILD_TESTING_DIR}/opencl_probe_stdout.txt" "${OPENCL_PROBE_STDOUT}") file (WRITE "${PLM_BUILD_TESTING_DIR}/opencl_probe_stderr.txt" "${OPENCL_PROBE_STDERR}") string (REGEX MATCH "Opencl does not work" OPENCL_PROBE_NOT_CAPABLE "${OPENCL_PROBE_STDOUT}") if (NOT OPENCL_PROBE_RESULT AND NOT OPENCL_PROBE_NOT_CAPABLE) set (RUN_OPENCL_TESTS ON) endif () endif () # In ITK 3.20.1 (official release), masked registration is broken if (NOT ${ITK_VERSION} VERSION_GREATER "3.20.1") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-reg-roi-b" ) endif () # plm-convert-rtog-corvus-a doen't work yet set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-rtog-corvus-a" ) # drr-d doesn't work yet set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "drr-d" "drr-d-stats" "drr-d-check" ) # plm-reg-itk-rigid-b doesn't work yet set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-reg-itk-rigid-b" "plm-reg-itk-rigid-b-stats-1" "plm-reg-itk-rigid-b-check-1" ) ## If we don't have a fortran compiler, don't test bragg_curve if (NOT CMAKE_Fortran_COMPILER_WORKS) set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "bragg-curve" "bragg-curve-check" ) endif () ## If we didn't get XiO dicom-rt test data, don't run these tests if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/dicomrt-xio-4.33.02-chest-phantom") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-dicom-xio-a" "plm-convert-dicom-xio-a-stats" "plm-convert-dicom-xio-a-check" "plm-convert-dicom-xio-b" "plm-convert-dicom-xio-b-stats" "plm-convert-dicom-xio-b-check" "plm-convert-dicom-xio-c" "plm-convert-dicom-xio-c-stats" "plm-convert-dicom-xio-c-check" "plm-convert-dicom-xio-d" "plm-convert-dicom-xio-d-stats" "plm-convert-dicom-xio-d-check" "plm-convert-dicom-xio-e" "plm-convert-dicom-xio-f" "plm-convert-dicom-xio-f-stats" "plm-convert-dicom-xio-f-check" "plm-convert-dicom-xio-g" "plm-warp-dicom-xio-a" "plm-warp-dicom-xio-a-stats-1" "plm-warp-dicom-xio-a-check-1" "plm-warp-dicom-xio-a-stats-2" "plm-warp-dicom-xio-a-check-2" ) endif () ## If we didn't get xio test data, don't run xio tests if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/xio-4.33.02-chest-phantom") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-xio-a" "plm-convert-xio-a-stats" "plm-convert-xio-a-check" "plm-convert-xio-b" "plm-convert-xio-b-stats" "plm-convert-xio-b-check" "plm-warp-xio-a" "plm-warp-xio-a-stats-1" "plm-warp-xio-a-check-1" "plm-warp-xio-a-stats-2" "plm-warp-xio-a-check-2" "plm-warp-xio-a-stats-3" "plm-warp-xio-a-check-3" "plm-warp-xio-a-stats-4" "plm-warp-xio-a-check-4" "plm-warp-xio-a-check-5" "plm-warp-xio-a-check-6" ) endif () ## If we didn't get rtog (corvus) test data, don't run these tests if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/rtog-corvus-6.2.2") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-rtog-corvus-a" ) endif () ## If we didn't get aw (foot) test data, don't run these tests if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/dicomrt-aw-4.4-foot") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-dicom-aw-a" "plm-convert-dicom-aw-a-stats" "plm-convert-dicom-aw-a-check" "plm-convert-dicom-aw-b" ) endif () ## If we didn't get cerr test data, don't run these tests # if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/chest-phantom-dicomrt-CERR4pt0beta2_25_Jan_2011") # set (CTEST_CUSTOM_TESTS_IGNORE # ${CTEST_CUSTOM_TESTS_IGNORE} # "plm-convert-dicom-cerr-a" # ) # endif () ## If we didn't get corvus test data, don't run these tests if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/dicomrt-corvus-6.2.2") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-dicom-corvus-a" ) endif () ## If we didn't get xio irregular test data, don't run these tests if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/xio-4.60-irregular-spacing") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-dicom-irregular-a" ) endif () ## If we didn't get pinnacle test data, don't run these tests if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/dicomrt-pinnacle3-8.2g-rando") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-dicom-pinnacle-a" ) endif () ## If we didn't get test data w 33 structures, don't run these tests if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/dicomrt-33-structures") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-dicom-33-a" "plm-convert-dicom-33-a-stats-1" "plm-convert-dicom-33-a-stats-2" "plm-convert-dicom-33-a-check-1" "plm-convert-dicom-33-a-check-2" ) endif () ## If we didn't get varian fdk test data, don't run these tests if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/varian-catphan-subset") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "fdk-cpu-b" "fdk-cpu-b-stats" "fdk-cpu-b-check" "fdk-cpu-c" "fdk-cpu-c-stats" "fdk-cpu-c-check" ) endif () ## If we didn't get headphantom test data, don't run these tests if (NOT EXISTS "${PLM_BUILD_TESTING_DIR}/headphantom") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "fdk-tutorial-a" "fdk-tutorial-b" "fdk-tutorial-b-stats-1" "fdk-tutorial-b-check-1" "fdk-tutorial-c" "fdk-tutorial-c-stats-1" "fdk-tutorial-c-check-1" ) endif () ## If we don't have fftw, don't run these tests if (NOT FFTW_FOUND) set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "fdk-cpu-c" "fdk-cpu-c-stats" "fdk-cpu-c-check" "fdk-tutorial-c" "fdk-tutorial-c-stats-1" "fdk-tutorial-c-check-1" ) endif () ## If we didn't compile with cuda, don't run these tests if (NOT RUN_CUDA_TESTS) set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "demons-cuda-a" "demons-cuda-a-check" "drr-cuda" "drr-cuda-stats" "drr-cuda-check" "fdk-cuda-a" "fdk-cuda-a-stats" "fdk-cuda-a-check" "plm-bsp-cuda" "plm-bsp-cuda-stats" "plm-bsp-cuda-check" ) endif () ## If we didn't compile with opencl, don't run these tests if (NOT RUN_OPENCL_TESTS) set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "drr-opencl" "drr-opencl-stats" "drr-opencl-check" "fdk-opencl-a" "fdk-opencl-a-stats" "fdk-opencl-a-check" ) endif () ## If we are using DCMTK, don't run these tests if (PLM_DCM_USE_DCMTK) set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-dicom-b-stats" "plm-convert-dicom-b-check" ) endif () ## If we're not using dcmtk for dicom, don't run these tests if (NOT PLM_DCM_USE_DCMTK) set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-dicom-irregular-a" ) endif () ## If we only have GDCM 2, don't run these tests if (PLM_DCM_USE_GDCM2) set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "plm-convert-dicom-donut-a" "plm-convert-dicom-donut-a-stats" "plm-convert-dicom-donut-a-check" "plm-convert-dicom-donut-b" "plm-convert-dicom-donut-b-stats" "plm-convert-dicom-donut-b-check" "plm-convert-dicom-a" "plm-convert-dicom-a-stats" "plm-convert-dicom-a-check" "plm-convert-dicom-b" "plm-convert-dicom-b-stats" "plm-convert-dicom-b-check" "plm-convert-dicom-c" "plm-convert-dicom-c-stats" "plm-convert-dicom-c-check" "plm-convert-dicom-f" "plm-convert-cxt" "plm-convert-cxt-stats" "plm-convert-cxt-check" ) endif () ## Dose calculation not yet supported on debian if (PLM_CONFIG_DEBIAN_BUILD) set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "proton-dose-1" "proton-dose-1-stats" "proton-dose-1-check" "proton-dose-2" "proton-dose-2-stats" "proton-dose-2-check" "proton-dose-3" "proton-dose-3-stats" "proton-dose-3-check" "proton-dose-5a" "proton-dose-5a-stats" "proton-dose-5a-check" "proton-dose-5d" "proton-dose-5d-stats" "proton-dose-5d-check" "proton-dose-5g" "proton-dose-5g-stats" "proton-dose-5g-check" "proton-dose-6a" "proton-dose-6a-stats" "proton-dose-6a-check" ) endif () ## Debian on MIPS causes timeout because the build machine is too slow. ## So we just skip these tests if (PLM_CONFIG_DEBIAN_BUILD AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips") set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "bspline-mi-c-1" "bspline-mi-c-1-check" "bspline-mi-c-2" "bspline-mi-c-2-check" "fdk-cpu-d" "fdk-cpu-d-stats" "fdk-cpu-d-check" "plm-bsp-regularize-numeric" "plm-bsp-regularize-numeric-stats" "plm-bsp-regularize-numeric-check" "plm-resample-c" ## GCS FIX: This depends on mi-c-1 "plm-resample-c-stats" "plm-resample-c-check" ) endif () ## Don't delete from the list, comment out instead. if (PLM_REDUCED_TESTS) set (CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} "black-1" "donut-1" "gauss-1" "gauss-2" "gauss-3" "gauss-4" "gauss-5" "gauss-6" "gauss-ushort-1" "gauss-ushort-2" "gauss-double-1" "gauss-double-2" "rect-1" "rect-2" "rect-3" "rect-4" "rect-5" "rect-6" "rect-7" "sphere-1" "sphere-2" "sphere-3" "vf-zero" "vf-trans-1" "vf-radial-1" "vf-zero-stats" "vf-zero-check" "vf-trans-1-stats" "vf-trans-1-check" "vf-radial-1-stats" "vf-radial-1-check" "bspline-c" "bspline-c-check" "bspline-g" "bspline-g-check" "bspline-h" "bspline-h-check" "bspline-mi-c-1" "bspline-mi-c-1-check" "bspline-mi-c-2" "bspline-mi-c-2-check" "demons-a" "demons-a-check" "demons-cuda-a" "demons-cuda-a-check" "drr-a" "drr-a-stats" "drr-a-check" "drr-b" "drr-b-stats" "drr-b-check" "drr-c" "drr-c-stats" "drr-c-check" "drr-cuda" "drr-cuda-stats" "drr-cuda-check" "drr-opencl" "drr-opencl-stats" "drr-opencl-check" "fdk-cpu-a" "fdk-cpu-a-stats" "fdk-cpu-a-check" "fdk-cpu-b" "fdk-cpu-b-stats" "fdk-cpu-b-check" "fdk-cpu-c" "fdk-cpu-c-stats" "fdk-cpu-c-check" "fdk-cpu-d" "fdk-cpu-d-stats" "fdk-cpu-d-check" "fdk-cuda-a" "fdk-cuda-a-stats" "fdk-cuda-a-check" "fdk-opencl-a" "fdk-opencl-a-stats" "fdk-opencl-a-check" "fdk-tutorial-a" "fdk-tutorial-b" "fdk-tutorial-b-stats-1" "fdk-tutorial-b-check-1" "fdk-tutorial-c" "fdk-tutorial-c-stats-1" "fdk-tutorial-c-check-1" "landmark-warp-a" "landmark-warp-a-stats-1" "landmark-warp-a-check-1" "landmark-warp-a-stats-2" "landmark-warp-a-check-2" "landmark-warp-b" "landmark-warp-b-stats-1" "landmark-warp-b-check-1" "landmark-warp-b-stats-2" "landmark-warp-b-check-2" "landmark-warp-c" "landmark-warp-c-stats-1" "landmark-warp-c-check-1" "landmark-warp-c-stats-2" "landmark-warp-c-check-2" "plm-convert-dicom-a" "plm-convert-dicom-a-stats" "plm-convert-dicom-a-check" "plm-convert-dicom-b" "plm-convert-dicom-b-stats" "plm-convert-dicom-b-check" "plm-convert-rtog-corvus-a" "plm-convert-dicom-aw-a" "plm-convert-dicom-aw-a-stats" "plm-convert-dicom-aw-a-check" "plm-convert-dicom-aw-b" "plm-convert-dicom-cerr-a" "plm-convert-dicom-corvus-a" "plm-convert-dicom-pinnacle-a" "plm-convert-dicom-xio-a" "plm-convert-dicom-xio-a-stats" "plm-convert-dicom-xio-a-check" "plm-convert-dicom-xio-b" "plm-convert-dicom-xio-b-stats" "plm-convert-dicom-xio-b-check" "plm-convert-dicom-xio-c" "plm-convert-dicom-xio-c-stats" "plm-convert-dicom-xio-c-check" "plm-convert-dicom-xio-d" "plm-convert-dicom-xio-d-stats" "plm-convert-dicom-xio-d-check" "plm-convert-dicom-xio-e" "plm-convert-dicom-xio-f" "plm-convert-dicom-xio-f-stats" "plm-convert-dicom-xio-f-check" "plm-warp-dicom-xio-a" "plm-warp-dicom-xio-a-stats-1" "plm-warp-dicom-xio-a-check-1" "plm-warp-dicom-xio-a-stats-2" "plm-warp-dicom-xio-a-check-2" "plm-convert-cxt" "plm-convert-cxt-stats" "plm-convert-cxt-check" "plm-convert-xio-a" "plm-convert-xio-a-stats" "plm-convert-xio-a-check" "plm-convert-xio-b" "plm-convert-xio-b-stats" "plm-convert-xio-b-check" "plm-warp-xio-a" "plm-warp-xio-a-stats-1" "plm-warp-xio-a-check-1" "plm-warp-xio-a-stats-2" "plm-warp-xio-a-check-2" "plm-warp-xio-a-stats-3" "plm-warp-xio-a-check-3" "plm-warp-xio-a-stats-4" "plm-warp-xio-a-check-4" "plm-warp-xio-a-check-5" "plm-warp-xio-a-check-6" "plm-convert-prefix-fcsv" "plm-fill-a" "plm-fill-a-stats" "plm-fill-a-check" "plm-mask-a" "plm-mask-a-stats" "plm-mask-a-check" "plm-usage" "plm-reg-align-center" "plm-reg-align-center-stats" "plm-reg-align-center-check" "plm-reg-itk-translation" "plm-reg-itk-translation-stats" "plm-reg-itk-translation-check" "plm-reg-itk-rigid" "plm-reg-itk-rigid-stats-1" "plm-reg-itk-rigid-check-1" "plm-reg-itk-rigid-stats-2" "plm-reg-itk-rigid-check-2" "plm-reg-itk-bspline" "plm-reg-itk-bspline-stats-1" "plm-reg-itk-bspline-check-1" "plm-reg-itk-demons" "plm-reg-itk-demons-check-1" "plm-reg-itk-demons-stats-2" "plm-reg-itk-demons-check-2" "plm-bspline-single-c" "plm-bspline-single-c-stats" "plm-bspline-single-c-check" "plm-bspline-single-h" "plm-bspline-single-h-stats" "plm-bspline-single-h-check" "plm-bspline-openmp" "plm-bspline-openmp-stats" "plm-bsp-openmp-check" "plm-bsp-cuda" "plm-bsp-cuda-stats" "plm-bsp-cuda-check" "plm-reg-bspline-ushort" "plm-reg-bspline-ushort-stats" "plm-reg-bspline-ushort-check" "plm-reg-bspline-double" "plm-reg-bspline-double-stats" "plm-reg-bspline-double-check" "plm-reg-bspline-itk-output" "plm-reg-bspline-char-output" "plm-reg-bspline-char-output-stats" "plm-reg-bspline-char-output-check" "plm-bsp-rect" "plm-bsp-regularize-none" "plm-bsp-regularize-none-stats" "plm-bsp-regularize-none-check" "plm-bsp-regularize-analytic" "plm-bsp-regularize-analytic-stats" "plm-bsp-regularize-analytic-check" "plm-bsp-regularize-numeric" "plm-bsp-regularize-numeric-stats" "plm-bsp-regularize-numeric-check" "plm-bsp-landmark-a" # "plm-bsp-dcos-a" # "plm-bsp-dcos-a-stats" # "plm-bsp-dcos-a-check" "plm-bsp-dcos-b" "plm-bsp-dcos-b-stats" "plm-bsp-dcos-b-check" "plm-reg-compose" "plm-compose-a" "plm-compose-a-warp" "plm-compose-a-stats" "plm-compose-a-check" "plm-compose-b" "plm-compose-b-warp" "plm-compose-b-stats" "plm-compose-b-check" "plm-compose-c" "plm-compose-c-warp" "plm-compose-c-stats" "plm-compose-c-check" "plm-resample-a" "plm-resample-a-stats" "plm-resample-a-check" "plm-resample-b" "plm-resample-b-stats" "plm-resample-b-check" "plm-resample-c" "plm-resample-c-stats" "plm-resample-c-check" "plm-warp-pointset-a" "plm-warp-pointset-b" "plm-warp-pointset-c" "plm-warp-a" "plm-warp-a-stats" "plm-warp-a-check" "plm-warp-b" "plm-warp-b-stats-1" "plm-warp-b-check-1" "plm-warp-b-stats-2" "plm-warp-b-check-2" "plm-warp-c" "plm-warp-c-stats" "plm-warp-c-check" "plm-warp-d" "plm-warp-d-stats" "plm-warp-d-check" "plm-warp-g" "plm-warp-g-stats-1" "plm-warp-g-check-1" "plm-warp-h" "plm-warp-h-stats-1" "plm-warp-h-check-1" "plm-warp-i" "plm-warp-i-stats-1" "plm-warp-i-check-1" "plm-xf-convert-a" "plm-xf-convert-b" "plm-xf-convert-c" "plm-xf-convert-d" "plm-xf-convert-d-warp-1" "plm-xf-convert-d-warp-1-stats" "plm-xf-convert-d-warp-1-check" "plm-xf-convert-d-warp-2" "plm-xf-convert-d-warp-2-stats" "plm-xf-convert-d-warp-2-check" "plm-drr-api-a" "plm-registration-api-a" "bragg-curve" "bragg-curve-check" "proton-dose" ) endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/000077500000000000000000000000001321604176500240055ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/bragg-curve.txt000066400000000000000000000130311321604176500267500ustar00rootroot000000000000000.000000 6.029332 1.000000 6.028974 2.000000 6.028638 3.000000 6.028323 4.000000 6.028029 5.000000 6.027757 6.000000 6.027506 7.000000 6.027278 8.000000 6.027072 9.000000 6.026889 10.000000 6.026729 11.000000 6.026591 12.000000 6.026478 13.000000 6.026387 14.000000 6.026321 15.000000 6.026279 16.000000 6.026262 17.000000 6.026269 18.000000 6.026302 19.000000 6.026360 20.000000 6.026444 21.000000 6.026554 22.000000 6.026690 23.000000 6.026852 24.000000 6.027042 25.000000 6.027259 26.000000 6.027504 27.000000 6.027777 28.000000 6.028078 29.000000 6.028407 30.000000 6.028766 31.000000 6.029154 32.000000 6.029572 33.000000 6.030020 34.000000 6.030498 35.000000 6.031007 36.000000 6.031548 37.000000 6.032120 38.000000 6.032725 39.000000 6.033361 40.000000 6.034031 41.000000 6.034734 42.000000 6.035471 43.000000 6.036241 44.000000 6.037047 45.000000 6.037887 46.000000 6.038764 47.000000 6.039676 48.000000 6.040624 49.000000 6.041610 50.000000 6.042632 51.000000 6.043693 52.000000 6.044793 53.000000 6.045931 54.000000 6.047109 55.000000 6.048326 56.000000 6.049585 57.000000 6.050884 58.000000 6.052225 59.000000 6.053609 60.000000 6.055035 61.000000 6.056505 62.000000 6.058018 63.000000 6.059577 64.000000 6.061180 65.000000 6.062830 66.000000 6.064526 67.000000 6.066270 68.000000 6.068061 69.000000 6.069901 70.000000 6.071790 71.000000 6.073729 72.000000 6.075719 73.000000 6.077761 74.000000 6.079855 75.000000 6.082002 76.000000 6.084202 77.000000 6.086457 78.000000 6.088768 79.000000 6.091135 80.000000 6.093559 81.000000 6.096041 82.000000 6.098582 83.000000 6.101183 84.000000 6.103844 85.000000 6.106567 86.000000 6.109353 87.000000 6.112202 88.000000 6.115116 89.000000 6.118095 90.000000 6.121141 91.000000 6.124255 92.000000 6.127437 93.000000 6.130690 94.000000 6.134013 95.000000 6.137409 96.000000 6.140878 97.000000 6.144422 98.000000 6.148041 99.000000 6.151738 100.000000 6.155512 101.000000 6.159367 102.000000 6.163303 103.000000 6.167321 104.000000 6.171423 105.000000 6.175610 106.000000 6.179884 107.000000 6.184246 108.000000 6.188698 109.000000 6.193242 110.000000 6.197878 111.000000 6.202609 112.000000 6.207437 113.000000 6.212363 114.000000 6.217388 115.000000 6.222516 116.000000 6.227747 117.000000 6.233083 118.000000 6.238527 119.000000 6.244081 120.000000 6.249746 121.000000 6.255525 122.000000 6.261420 123.000000 6.267433 124.000000 6.273566 125.000000 6.279822 126.000000 6.286203 127.000000 6.292712 128.000000 6.299351 129.000000 6.306123 130.000000 6.313030 131.000000 6.320075 132.000000 6.327262 133.000000 6.334592 134.000000 6.342069 135.000000 6.349697 136.000000 6.357477 137.000000 6.365414 138.000000 6.373511 139.000000 6.381771 140.000000 6.390197 141.000000 6.398795 142.000000 6.407566 143.000000 6.416515 144.000000 6.425646 145.000000 6.434964 146.000000 6.444471 147.000000 6.454174 148.000000 6.464076 149.000000 6.474181 150.000000 6.484496 151.000000 6.495024 152.000000 6.505770 153.000000 6.516741 154.000000 6.527941 155.000000 6.539376 156.000000 6.551053 157.000000 6.562976 158.000000 6.575152 159.000000 6.587588 160.000000 6.600290 161.000000 6.613266 162.000000 6.626522 163.000000 6.640065 164.000000 6.653905 165.000000 6.668047 166.000000 6.682501 167.000000 6.697276 168.000000 6.712380 169.000000 6.727822 170.000000 6.743612 171.000000 6.759760 172.000000 6.776277 173.000000 6.793172 174.000000 6.810458 175.000000 6.828146 176.000000 6.846248 177.000000 6.864778 178.000000 6.883747 179.000000 6.903170 180.000000 6.923062 181.000000 6.943436 182.000000 6.964310 183.000000 6.985699 184.000000 7.007621 185.000000 7.030093 186.000000 7.053135 187.000000 7.076765 188.000000 7.101005 189.000000 7.125877 190.000000 7.151402 191.000000 7.177605 192.000000 7.204511 193.000000 7.232146 194.000000 7.260538 195.000000 7.289716 196.000000 7.319711 197.000000 7.350556 198.000000 7.382285 199.000000 7.414934 200.000000 7.448541 201.000000 7.483147 202.000000 7.518796 203.000000 7.555532 204.000000 7.593404 205.000000 7.632464 206.000000 7.672767 207.000000 7.714370 208.000000 7.757336 209.000000 7.801732 210.000000 7.847628 211.000000 7.895100 212.000000 7.944230 213.000000 7.995106 214.000000 8.047820 215.000000 8.102475 216.000000 8.159179 217.000000 8.218050 218.000000 8.279215 219.000000 8.342813 220.000000 8.408992 221.000000 8.477917 222.000000 8.549765 223.000000 8.624730 224.000000 8.703024 225.000000 8.784881 226.000000 8.870558 227.000000 8.960339 228.000000 9.054536 229.000000 9.153499 230.000000 9.257615 231.000000 9.367318 232.000000 9.483093 233.000000 9.605489 234.000000 9.735123 235.000000 9.892121 236.000000 10.041432 237.000000 10.200885 238.000000 10.371646 239.000000 10.555082 240.000000 10.752807 241.000000 10.966744 242.000000 11.199211 243.000000 11.453032 244.000000 11.731698 245.000000 12.039592 246.000000 12.382327 247.000000 12.767270 248.000000 13.204401 249.000000 13.707821 250.000000 14.298440 251.000000 15.008450 252.000000 15.886894 253.000000 17.000585 254.000000 18.414663 255.000000 20.129971 256.000000 21.973172 257.000000 23.498048 258.000000 24.024044 259.000000 22.904579 260.000000 19.927784 261.000000 15.555265 262.000000 10.757678 263.000000 6.532159 264.000000 3.460129 265.000000 1.591549 266.000000 0.633560 267.000000 0.217735 268.000000 0.064483 269.000000 0.016433 270.000000 0.003600 271.000000 0.000677 272.000000 0.000109 273.000000 0.000015 274.000000 0.000002 275.000000 0.000000 276.000000 0.000000 277.000000 0.000000 278.000000 0.000000 279.000000 0.000000 280.000000 0.000000 281.000000 0.000000 282.000000 0.000000 283.000000 0.000000 284.000000 0.000000 285.000000 0.000000 286.000000 0.000000 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/fiducials-rect-2.fcsv000077500000000000000000000012321321604176500277260ustar00rootroot00000000000000# Fiducial List file /home/gsharp/fiducials-rect-2.fcsv # version = 2 # name = fiducials-rect-2 # numPoints = 8 # symbolScale = 5 # symbolType = 12 # visibility = 1 # textScale = 4.5 # color = 0.4,1,1 # selectedColor = 1,0.5,0.5 # opacity = 1 # ambient = 0 # diffuse = 1 # specular = 0 # power = 1 # locked = 0 # numberingScheme = 0 # columns = label,x,y,z,sel,vis rect-2-0,26.2717,52.1629,46.0528,1,0 rect-2-1,-65.8702,52.5436,46.053,1,0 rect-2-2,-65.8702,-52.5439,46.053,1,0 rect-2-3,25.5102,-53.6862,46.053,1,0 rect-2-4,25.891,52.1629,-46.0525,1,0 rect-2-5,-66.6317,53.3051,-46.053,1,0 rect-2-6,-65.8702,-53.3054,-46.053,1,0 rect-2-7,25.1295,-53.6862,-46.053,1,0 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/fiducials-rect-2.txt000077500000000000000000000003051321604176500276040ustar00rootroot00000000000000-26.2717 -52.1629 46.0528 65.8702 -52.5436 46.053 65.8702 52.5439 46.053 -25.5102 53.6862 46.053 -25.891 -52.1629 -46.0525 66.6317 -53.3051 -46.053 65.8702 53.3054 -46.053 -25.1295 53.6862 -46.053 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/fiducials-rect-3.fcsv000077500000000000000000000012331321604176500277300ustar00rootroot00000000000000# Fiducial List file /home/gsharp/fiducials-rect-3.fcsv # version = 2 # name = fiducials-rect-3 # numPoints = 8 # symbolScale = 5 # symbolType = 12 # visibility = 1 # textScale = 4.5 # color = 0.4,1,1 # selectedColor = 1,0.5,0.5 # opacity = 1 # ambient = 0 # diffuse = 1 # specular = 0 # power = 1 # locked = 0 # numberingScheme = 0 # columns = label,x,y,z,sel,vis rect-3-0,51.7821,52.1629,46.0528,1,1 rect-3-1,-52.5439,52.1629,46.053,1,1 rect-3-2,-53.3054,-53.6862,46.053,1,1 rect-3-3,52.5436,-52.9247,46.053,1,1 rect-3-4,52.5436,52.1629,-46.0525,1,1 rect-3-5,-53.3054,51.7821,-46.053,1,1 rect-3-6,-52.1632,-53.3054,-46.053,1,1 rect-3-7,52.9244,-53.3054,-46.053,1,1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/fiducials-rect-3.txt000077500000000000000000000003061321604176500276060ustar00rootroot00000000000000-51.7821 -52.1629 46.0528 52.5439 -52.1629 46.053 53.3054 53.6862 46.053 -52.5436 52.9247 46.053 -52.5436 -52.1629 -46.0525 53.3054 -51.7821 -46.053 52.1632 53.3054 -46.053 -52.9244 53.3054 -46.053 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/itk-rigid-a.tfm000066400000000000000000000002101321604176500266070ustar00rootroot00000000000000#Insight Transform File V1.0 # Transform 0 Transform: VersorRigid3DTransform_double_3_3 Parameters: 0 0 0 20 0 0 FixedParameters: 0 0 0 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/itk-rigid-b.tfm000066400000000000000000000002141321604176500266140ustar00rootroot00000000000000#Insight Transform File V1.0 # Transform 0 Transform: VersorRigid3DTransform_double_3_3 Parameters: 0.5236 0 0 0 0 0 FixedParameters: 0 0 0 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-char-output.txt000077500000000000000000000003521321604176500303740ustar00rootroot00000000000000[GLOBAL] fixed=rect-2.mha moving=rect-3.mha img_out=plm-bsp-char-output.mha img_out_type=char [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-cuda.txt000077500000000000000000000006101321604176500270320ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-cuda-vf.nrrd xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-cuda-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-cuda-img.nrrd [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=cuda max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-dcos-a.txt000077500000000000000000000006071321604176500272720ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-2.mha moving=@PLM_BUILD_TESTING_DIR@/rect-5.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-a-vf.nrrd xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-a-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-a-img.nrrd [STAGE] xform=bspline optim=lbfgsb impl=plastimatch flavor=g max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-dcos-b.txt000077500000000000000000000006071321604176500272730ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-5.mha moving=@PLM_BUILD_TESTING_DIR@/rect-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-b-vf.nrrd xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-b-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-b-img.nrrd [STAGE] xform=bspline optim=lbfgsb impl=plastimatch flavor=g max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-dcos-c.txt000077500000000000000000000006071321604176500272740ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-2.mha moving=@PLM_BUILD_TESTING_DIR@/rect-5.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-c-vf.nrrd xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-c-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-c-img.nrrd [STAGE] xform=bspline optim=lbfgsb impl=plastimatch flavor=c max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-dcos-d.txt000077500000000000000000000006071321604176500272750ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-5.mha moving=@PLM_BUILD_TESTING_DIR@/rect-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-d-vf.nrrd xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-d-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-d-img.nrrd [STAGE] xform=bspline optim=lbfgsb impl=plastimatch flavor=c max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-dcos-e.txt000077500000000000000000000006071321604176500272760ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-2.mha moving=@PLM_BUILD_TESTING_DIR@/rect-5.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-e-vf.nrrd xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-e-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-e-img.nrrd [STAGE] xform=bspline optim=lbfgsb impl=plastimatch flavor=h max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-dcos-f.txt000077500000000000000000000006071321604176500272770ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-5.mha moving=@PLM_BUILD_TESTING_DIR@/rect-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-f-vf.nrrd xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-f-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-dcos-f-img.nrrd [STAGE] xform=bspline optim=lbfgsb impl=plastimatch flavor=h max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-dmap-k.txt000066400000000000000000000005341321604176500272710ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-4.mha moving=@PLM_BUILD_TESTING_DIR@/rect-8.mha vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.mha [STAGE] xform=bspline alg_flavor=k metric=dmap max_its=20 grid_spac=10 10 10 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-double.txt000077500000000000000000000006351321604176500273770ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-double-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-double-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-double-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-double-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-double-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-gm-k.txt000066400000000000000000000006171321604176500267550ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-3.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-gm-k-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-gm-k-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-gm-k-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single alg_flavor=k metric=gm max_its=20 grad_tol=0.1 grid_spac=10 10 10 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-itk-output.txt000077500000000000000000000003531321604176500302470ustar00rootroot00000000000000[GLOBAL] fixed=gauss-1.mha moving=gauss-2.mha xf_out_itk=true xform_out=plm-bsp-itk-output.tfm [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-landmark-a.txt000077500000000000000000000011511321604176500301260ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-2.mha moving=@PLM_BUILD_TESTING_DIR@/sphere-2.mha fixed_landmarks=@PLM_TESTING_DATA_DIR@/fiducials-rect-2.fcsv moving_landmarks=@PLM_TESTING_DATA_DIR@/fiducials-rect-3.fcsv vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.mha warped_landmarks=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-warped.fcsv [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single landmark_stiffness=1.0 max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-landmark-b.txt000066400000000000000000000011521321604176500301250ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-15.mha moving=@PLM_BUILD_TESTING_DIR@/rect-16.mha vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.mha fixed_landmarks=@PLM_TESTING_DATA_DIR@/fiducials-rect-3.fcsv moving_landmarks=@PLM_TESTING_DATA_DIR@/fiducials-rect-2.fcsv warped_landmarks=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-warped.fcsv [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single landmark_stiffness=1.0 max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-landmark-c.txt000066400000000000000000000011551321604176500301310ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-15.mha moving=@PLM_BUILD_TESTING_DIR@/rect-16.mha vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single landmark_stiffness=1.0 max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 fixed_landmarks=@PLM_TESTING_DATA_DIR@/fiducials-rect-3.fcsv moving_landmarks=@PLM_TESTING_DATA_DIR@/fiducials-rect-2.fcsv warped_landmarks=@PLM_BUILD_TESTING_DIR@/plm-bsp-landmark-c-warped.fcsv plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-landmark-d.txt000077500000000000000000000015351321604176500301370ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-15.mha moving=@PLM_BUILD_TESTING_DIR@/rect-16.mha vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single landmark_stiffness=1.0 max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 fixed_landmark_list=51.7821,52.1629,46.0528;-52.5439,52.1629,46.053;-53.3054,-53.6862,46.053;52.5436,-52.9247,46.053;52.5436,52.1629,-46.0525;-53.3054,51.7821,-46.053;-52.1632,-53.3054,-46.053;52.9244,-53.3054,-46.053 moving_landmark_list=26.2717,52.1629,46.0528;-65.8702,52.5436,46.053;-65.8702,-52.5439,46.053;25.5102,-53.6862,46.053;25.891,52.1629,-46.0525;-66.6317,53.3051,-46.053;-65.8702,-53.3054,-46.053;25.1295,-53.6862,-46.053 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-landmark-e.txt000077500000000000000000000011501321604176500301310ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-15.mha moving=@PLM_BUILD_TESTING_DIR@/rect-16.mha vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.mha fixed_landmarks=@PLM_TESTING_DATA_DIR@/fiducials-rect-3.txt moving_landmarks=@PLM_TESTING_DATA_DIR@/fiducials-rect-2.txt warped_landmarks=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-warped.fcsv [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single landmark_stiffness=1.0 max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-logfile.txt000077500000000000000000000007001321604176500275370ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-logfile-vf.nrrd xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-logfile-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-logfile-img.nrrd logfile=@PLM_BUILD_TESTING_DIR@/plm-bsp-logfile-logfile.txt [STAGE] xform=bspline optim=lbfgsb impl=plastimatch max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-mi-c.txt000077500000000000000000000010111321604176500267370ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-3.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mi-c-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mi-c-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mi-c-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single alg_flavor=c metric=mi # Floating point rounding differences cause this test case to # diverge beyond about 10 function evaluations #max_its=20 max_its=10 grad_tol=0.1 grid_spac=10 10 10 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-mi-k.txt000066400000000000000000000010111321604176500267440ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-3.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mi-k-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mi-k-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mi-k-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single alg_flavor=k metric=mi # Floating point rounding differences cause this test case to # diverge beyond about 10 function evaluations #max_its=20 max_its=10 grad_tol=0.1 grid_spac=10 10 10 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-mse-c.txt000077500000000000000000000006311321604176500271250ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-c-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-c-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-c-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single alg_flavor=c max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-mse-h.txt000077500000000000000000000006311321604176500271320ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-h-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-h-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-h-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single alg_flavor=h max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-mse-k.txt000077500000000000000000000006311321604176500271350ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-k-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-k-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-k-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single alg_flavor=k max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-mse-l.txt000077500000000000000000000006311321604176500271360ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-l-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-l-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-mse-l-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single alg_flavor=l max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-openmp.txt000077500000000000000000000004261321604176500274210ustar00rootroot00000000000000[GLOBAL] fixed=gauss-1.mha moving=gauss-2.mha vf_out=plm-bsp-openmp-vf.mha xform_out=plm-bsp-openmp-xf.txt img_out=plm-bsp-openmp-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=openmp max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-rect.txt000077500000000000000000000005651321604176500270640ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-2.mha moving=@PLM_BUILD_TESTING_DIR@/rect-3.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-rect-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-rect-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-rect-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plm-bsp-regularize-analytic.txt000077500000000000000000000005061321604176500320160ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data[GLOBAL] fixed=rect-3.mha moving=sphere-2.mha vf_out=plm-bsp-regularize-analytic-vf.mha xform_out=plm-bsp-regularize-analytic-xf.txt img_out=plm-bsp-regularize-analytic-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch max_its=5 convergence_tol=3 grad_tol=0.1 regularization_lambda=1.0 grid_spac=30 30 30 res=1 1 1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-regularize-none.txt000077500000000000000000000004641321604176500312330ustar00rootroot00000000000000[GLOBAL] fixed=rect-3.mha moving=sphere-2.mha vf_out=plm-bsp-regularize-none-vf.mha xform_out=plm-bsp-regularize-none-xf.txt img_out=plm-bsp-regularize-none-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch max_its=5 convergence_tol=3 grad_tol=0.1 regularization=none grid_spac=30 30 30 res=1 1 1 plm-bsp-regularize-numeric.txt000077500000000000000000000006621321604176500316570ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-3.mha moving=@PLM_BUILD_TESTING_DIR@/sphere-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch max_its=5 convergence_tol=3 grad_tol=0.1 regularization=numeric regularization_lambda=1.0 grid_spac=30 30 30 res=1 1 1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-resume.txt000077500000000000000000000006561321604176500274300ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-resume-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-resume-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-bsp-resume-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single alg_flavor=c max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 [STAGE] resume=1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-sm-multi-a.txt000077500000000000000000000011041321604176500301020ustar00rootroot00000000000000[GLOBAL] fixed[0]=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving[0]=@PLM_BUILD_TESTING_DIR@/gauss-2.mha fixed[1]=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving[1]=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single alg_flavor=c metric[0]=gm metric[1]=mi metric_lambda[0]=0.1 metric_lambda[1]=100 max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-bsp-ushort.txt000077500000000000000000000004441321604176500274470ustar00rootroot00000000000000[GLOBAL] fixed=gauss-ushort-1.mha moving=gauss-ushort-2.mha vf_out=plm-bsp-ushort-vf.mha xform_out=plm-bsp-ushort-xf.txt img_out=plm-bsp-ushort-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-align-center.txt000077500000000000000000000003541321604176500304640ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-6.mha xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.mha [STAGE] xform=align_center plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-autores-a.txt000077500000000000000000000003601321604176500300110ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-autores-a.mha [STAGE] xform=translation impl=plastimatch gridsearch_min_overlap=0.8 0.8 0.8 res_mm=3 3 3 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-autores-b.txt000077500000000000000000000003571321604176500300200ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-autores-b.mha [STAGE] xform=translation impl=plastimatch gridsearch_min_overlap=0.8 0.8 0.8 res_pct=0.5 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-compose.txt000077500000000000000000000004061321604176500275570ustar00rootroot00000000000000[GLOBAL] fixed=gauss-2.mha moving=gauss-5.mha vf_out=plm-reg-compose-vf.mha xform_out=plm-reg-compose.txt img_out=plm-reg-compose-img.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch max_its=10 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plm-reg-dv-itk-translation.txt000077500000000000000000000006541321604176500315720ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-dv-itk-translation-vf.nrrd xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-dv-itk-translation-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-dv-itk-translation-img.nrrd default_value = 1000 [STAGE] xform=translation optim=rsg impl=itk max_its=5 convergence_tol=3 grad_tol=0.1 res=2 2 2 max_step=10 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-gw-a.txt000077500000000000000000000002121321604176500267400ustar00rootroot00000000000000[GLOBAL] group_dir=@PLM_BUILD_TESTING_DIR@/gw [STAGE] xform=translation impl=plastimatch gridsearch_min_overlap=0.8 0.8 0.8 res_mm=3 3 3 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-itk-bspline.txt000077500000000000000000000005621321604176500303360ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-bspline-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-bspline-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-bspline-img.mha [STAGE] xform=bspline optim=lbfgsb impl=itk max_its=5 convergence_tol=3 grad_tol=0.1 res=1 1 1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-itk-demons-diff.txt000066400000000000000000000005741321604176500310750ustar00rootroot00000000000000[GLOBAL] fixed=gauss-1.mha moving=gauss-2.mha vf_out=plm-reg-itk-demons-diff-vf.mha img_out=plm-reg-itk-demons-diff-img.mha [STAGE] xform=vf impl=itk optim=demons optim_subtype=diffeomorphic demons_gradient_type=symmetric demons_std_update_field=1.5 demons_std_deformation_field=1.5 demons_smooth_deformation_field=1 demons_smooth_update_field=1 demons_step_length=2; max_its=5 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-itk-demons-logd.txt000066400000000000000000000006311321604176500311040ustar00rootroot00000000000000[GLOBAL] fixed=gauss-1.mha moving=gauss-2.mha vf_out=plm-reg-itk-demons-logd-vf.mha img_out=plm-reg-itk-demons-logd-img.mha [STAGE] xform=vf impl=itk optim=demons optim_subtype=log_domain demons_gradient_type=symmetric demons_std_update_field=1.5 demons_std_deformation_field=1.5 demons_smooth_deformation_field=1 demons_smooth_update_field=1 demons_step_length=2; num_approx_terms_log_demons=2; max_its=5 plm-reg-itk-demons-sym-logd.txt000066400000000000000000000006441321604176500316370ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data[GLOBAL] fixed=gauss-1.mha moving=gauss-2.mha vf_out=plm-reg-itk-demons-sym-logd-vf.mha img_out=plm-reg-itk-demons-sym-logd-img.mha [STAGE] xform=vf impl=itk optim=demons optim_subtype=sym_log_domain demons_gradient_type=symmetric demons_std_update_field=1.5 demons_std_deformation_field=1.5 demons_smooth_deformation_field=1 demons_smooth_update_field=1 demons_step_length=2; num_approx_terms_log_demons=2; max_its=5 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-itk-demons.txt000077500000000000000000000006071321604176500301670ustar00rootroot00000000000000[GLOBAL] fixed=gauss-1.mha moving=gauss-2.mha vf_out=plm-reg-itk-demons-vf.mha img_out=plm-reg-itk-demons-img.mha [STAGE] xform=vf impl=itk optim=demons optim_subtype=fsf demons_gradient_type=symmetric demons_std_update_field=1.5 demons_std_deformation_field=1.5 demons_smooth_deformation_field=1 demons_smooth_update_field=1 demons_step_length=2; num_approx_terms_log_demons=2; max_its=5 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-itk-rigid-a.txt000077500000000000000000000010111321604176500302040ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-3.mha moving=@PLM_BUILD_TESTING_DIR@/rect-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-rigid-a-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-rigid-a-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-rigid-a-img.mha [STAGE] xform=rigid optim=versor impl=itk max_its=5 convergence_tol=3 grad_tol=0.1 res=2 2 2 img_out=plm-reg-itk-rigid-a-intermediate-img.mha max_step=10 [STAGE] xform=rigid optim=versor impl=itk max_its=5 convergence_tol=3 grad_tol=0.1 res=1 1 1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-itk-rigid-b.txt000077500000000000000000000005711321604176500302170ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-1.mha moving=@PLM_BUILD_TESTING_DIR@/rect-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-rigid-b-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-rigid-b-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-rigid-b-img.mha [STAGE] xform=rigid optim=versor metric=nmi impl=itk max_its=5 convergence_tol=3 grad_tol=0.1 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-itk-similarity.txt000077500000000000000000000013371321604176500310710ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-2s.mha moving=@PLM_BUILD_TESTING_DIR@/rect-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-similarity-a-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-similarity-a-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-similarity-a-img.mha [STAGE] xform=similarity optim=oneplusone impl=itk translation_scale_factor=1 rotation_scale_factor=0.003 scaling_scale_factor=0.1 min_its=5 max_its=10 grad_tol=0.001 res=2 2 2 img_out=plm-reg-itk-similarity-intermediate-img.mha [STAGE] xform=similarity optim=oneplusone impl=itk rotation_scale_factor=0.005 translation_scale_factor=1 scaling_scale_factor=0.1 min_its=5 max_its=10 grad_tol=0.001 res=1 1 1 img_out=plm-reg-itk-similarity-img.mha plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-itk-translation.txt000077500000000000000000000006131321604176500312350ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-translation-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-translation-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-itk-translation-img.mha [STAGE] xform=translation optim=rsg impl=itk max_its=5 convergence_tol=3 grad_tol=0.1 res=2 2 2 max_step=10 plm-reg-mask-hist_minmax-a.txt000077500000000000000000000007701321604176500315260ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-10.mha moving=@PLM_BUILD_TESTING_DIR@/rect-11.mha moving_mask=@PLM_BUILD_TESTING_DIR@/rect-11-mask.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-mask-a-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-mask-a-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-mask-a-img.mha [STAGE] xform=bspline optim=lbfgsb metric=mi mi_fixed_minVal=-100 mi_fixed_maxVal=100 impl=plastimatch threading=single max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=1 1 1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-multi-a.txt000077500000000000000000000007301321604176500274620ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-2.mha moving=@PLM_BUILD_TESTING_DIR@/sphere-2.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-multi-a-vf.nrrd img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-multi-a-img.nrrd [STAGE] xform=rigid optim=versor impl=itk max_its=5 convergence_tol=3 grad_tol=0.1 res=2 2 2 img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-multi-a-stage-1.mha max_step=10 [STAGE] xform=vf optim=demons impl=plastimatch max_its=5 convergence_tol=3 grad_tol=0.1 res=1 1 1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-multi-b.txt000077500000000000000000000003731321604176500274660ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-2.mha moving=@PLM_BUILD_TESTING_DIR@/sphere-2.mha img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.nrrd [STAGE] xform=bspline impl=plastimatch max_its=20 res=4 4 4 [STAGE] grid_spac=10 10 10 res=1 1 1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-process-a.txt000066400000000000000000000003301321604176500277770ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-1.mha img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-process-a.mha [PROCESS] action=adjust images=fixed,moving parms=-inf,0,-500,-500 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-roi-a.txt000077500000000000000000000007771321604176500271340ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-10.mha moving=@PLM_BUILD_TESTING_DIR@/rect-11.mha fixed_mask=@PLM_BUILD_TESTING_DIR@/rect-10-roi-1.mha moving_mask=@PLM_BUILD_TESTING_DIR@/rect-11-roi.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-a-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-a-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-a-img.mha [STAGE] xform=bspline optim=lbfgsb metric=mi impl=plastimatch threading=single max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=1 1 1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-roi-b.txt000066400000000000000000000007051321604176500271210ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rectarr-01.mha moving=@PLM_BUILD_TESTING_DIR@/rectarr-02.mha fixed_mask=@PLM_BUILD_TESTING_DIR@/rectarr-m-01.mha moving_mask=@PLM_BUILD_TESTING_DIR@/rectarr-m-01.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-b-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-b-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-b-img.mha [STAGE] xform=align_center [STAGE] xform=translation optim=rsg max_its=10 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-roi-c.txt000066400000000000000000000007111321604176500271170ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rectarr-01.mha moving=@PLM_BUILD_TESTING_DIR@/rectarr-02.mha fixed_mask=@PLM_BUILD_TESTING_DIR@/rectarr-m-01.mha #moving_mask=@PLM_BUILD_TESTING_DIR@/rectarr-m-01.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-c-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-c-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-c-img.mha [STAGE] xform=bspline res=2 2 2 max_its=10 regularization_lambda=0.1 grid_spac=10 10 10 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-roi-d.txt000077500000000000000000000007111321604176500271230ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rectarr-01.mha moving=@PLM_BUILD_TESTING_DIR@/rectarr-02.mha fixed_mask=@PLM_BUILD_TESTING_DIR@/rectarr-m-02.mha #moving_mask=@PLM_BUILD_TESTING_DIR@/rectarr-m-02.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-d-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-d-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-d-img.mha [STAGE] xform=bspline res=2 2 2 max_its=10 regularization_lambda=0.1 grid_spac=10 10 10 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-roi-e.txt000077500000000000000000000010121321604176500271170ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rectarr-01.mha moving=@PLM_BUILD_TESTING_DIR@/rectarr-02.mha vf_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-e-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-e-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/plm-reg-roi-e-img.mha [STAGE] xform=translation optim=rsg max_its=10 res=2 2 2 [STAGE] xform=bspline res=2 2 2 max_its=5 regularization_lambda=0.1 grid_spac=10 10 10 fixed_roi=@PLM_BUILD_TESTING_DIR@/rectarr-m-02.mha [STAGE] fixed_roi_enable=false [STAGE] fixed_roi_enable=true plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-stiffness-a.txt000077500000000000000000000006501321604176500303350ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/rect-19.mha moving=@PLM_BUILD_TESTING_DIR@/sphere-4.mha fixed_stiffness=@PLM_BUILD_TESTING_DIR@/roi-1.mha vf_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-vf.mha xform_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-xf.txt img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-img.mha [STAGE] xform=bspline res=2 2 2 max_its=5 regularization=numeric regularization_lambda=0.1 grid_spac=10 10 10 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-trans-a.txt000066400000000000000000000003731321604176500274570ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@.mha [STAGE] xform=translation impl=plastimatch gridsearch_min_overlap=0.8 0.8 0.8 res=1 1 1 num_substages=2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-trans-b.txt000066400000000000000000000005721321604176500274610ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@.mha [STAGE] xform=translation impl=plastimatch optim=grid_search gridsearch_strategy=global gridsearch_min_overlap=0.8 0.8 0.8 res=1 1 1 [STAGE] xform=translation impl=plastimatch optim=grid_search gridsearch_strategy=local res=1 1 1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-reg-trans-mi-a.txt000066400000000000000000000006041321604176500300570ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha img_out=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@.mha [STAGE] xform=translation impl=plastimatch optim=grid_search metric=mi gridsearch_strategy=global gridsearch_min_overlap=0.8 0.8 0.8 res=1 1 1 [STAGE] xform=translation impl=plastimatch optim=grid_search gridsearch_strategy=local res=1 1 1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-warp-xio-a-ss.txt000077500000000000000000000007611321604176500277520ustar00rootroot000000000000000|255 0 0|Patient 1|255 255 0|Tumor -1|255 0 255|Planning vol 1 -1|0 255 255|Treatment vol -1|0 255 0|Target vol. 1 -1|0 0 255|Target vol. 2 -1|255 128 128|Target vol. 3 2|255 255 128|R Lung 3|255 128 255|L Lung -1|128 255 255|Esophagus -1|128 255 128|Trachea -1|128 128 255|Bronchus 4|200 128 128|Spinal Cord -1|200 200 128|L Breast -1|200 128 200|R Breast -1|128 200 200|Rib -1|128 200 128|Vertebral Body -1|128 128 200|Sternum -1|200 255 255|Lymph node -1|200 200 255|Heart -1|200 255 200|IMC plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-warp-xio-a.ctbl000077500000000000000000000011301321604176500274230ustar00rootroot000000000000000 Background 0 0 0 255 1 Patient 255 0 0 255 2 Tumor 255 255 0 255 3 R_Lung 255 255 128 255 4 L_Lung 255 128 255 255 5 Spinal_Cord 200 128 128 255 6 Planning_vol_1 255 0 255 255 7 Treatment_vol 0 255 255 255 8 Target_vol__1 0 255 0 255 9 Target_vol__2 0 0 255 255 10 Target_vol__3_ 255 128 128 255 11 Esophagus 128 255 255 255 12 Trachea 128 255 128 255 13 Bronchus 128 128 255 255 14 L_Breast 200 200 128 255 15 R_Breast 200 128 200 255 16 Rib 128 200 200 255 17 Vertebral_Body 128 200 128 255 18 Sternum 128 128 200 255 19 Lymph_node 200 255 255 255 20 Heart 200 200 255 255 21 IMC 200 255 200 255 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/plm-xf-convert.txt000077500000000000000000000213611321604176500274350ustar00rootroot00000000000000MGH_GPUIT_BSP img_origin = -24.342106 -24.342106 -24.342106 img_spacing = 2.631580 2.631580 2.631580 img_dim = 19 19 19 roi_offset = 0 0 0 roi_dim = 19 19 19 vox_per_rgn = 11 11 11 0.00005556219548452646 0.00151265214662998915 0.00300385942682623863 0.00098407734185457230 0.00002222894545411691 0.00234375731088221073 0.06267559528350830078 0.12386275082826614380 0.04104099795222282410 0.00092683627735823393 0.00510352104902267456 0.13629497587680816650 0.26923903822898864746 0.08936871588230133057 0.00202122749760746956 0.00104397418908774853 0.02802153490483760834 0.05534959584474563599 0.01828078366816043854 0.00041319240699522197 0.00000470462600787869 0.00013061727804597467 0.00026290919049642980 0.00008622915629530326 0.00000195663824342773 0.00234375754371285439 0.06267562508583068848 0.12386266142129898071 0.04104102030396461487 0.00092683662660419941 0.09430193901062011719 2.51501727104187011719 5.08213758468627929688 1.75521540641784667969 0.04010540619492530823 0.20259864628314971924 5.42697429656982421875 11.04108428955078125000 3.84529709815979003906 0.08813928812742233276 0.04159926623106002808 1.12002158164978027344 2.27039122581481933594 0.78343850374221801758 0.01793027669191360474 0.00020004113321192563 0.00547708896920084953 0.01090386509895324707 0.00355900381691753864 0.00007952531450428069 0.00510352151468396187 0.13629490137100219727 0.26923909783363342285 0.08936873823404312134 0.00202122773043811321 0.20259869098663330078 5.42697715759277343750 11.04108810424804687500 3.84529733657836914062 0.08813928812742233276 0.43353089690208435059 11.68789958953857421875 23.98505973815917968750 8.43510246276855468750 0.19397164881229400635 0.08910620957612991333 2.41430711746215820312 4.93159484863281250000 1.71686172485351562500 0.03942051529884338379 0.00043647285201586783 0.01194199454039335251 0.02372201159596443176 0.00772782787680625916 0.00017235115228686482 0.00104397395625710487 0.02802152745425701141 0.05534960702061653137 0.01828077435493469238 0.00041319234878756106 0.04159928858280181885 1.12002098560333251953 2.27039098739624023438 0.78343850374221801758 0.01793028227984905243 0.08910623192787170410 2.41430878639221191406 4.93159627914428710938 1.71686184406280517578 0.03942050784826278687 0.01830678619444370270 0.49846130609512329102 1.01402926445007324219 0.34967356920242309570 0.00801716372370719910 0.00008917860395740718 0.00245057186111807823 0.00487321289256215096 0.00158404104877263308 0.00003537128941388801 0.00000470462555313134 0.00013061733625363559 0.00026290898676961660 0.00008622911991551518 0.00000195663756130671 0.00020004123507533222 0.00547708477824926376 0.01090387068688869476 0.00355900241993367672 0.00007952533633215353 0.00043647291022352874 0.01194199267774820328 0.02372202090919017792 0.00772782973945140839 0.00017235119594261050 0.00008917858212953433 0.00245057232677936554 0.00487321428954601288 0.00158404104877263308 0.00003537129305186681 0.00000039678801044829 0.00001120062461268390 0.00002288233918079641 0.00000756666531742667 0.00000017377742267399 0.00003516795914038084 0.00105865136720240116 -0.00037415680708363652 -0.00129135383758693933 -0.00003317876689834520 0.00050521665252745152 0.01490548998117446899 -0.00599085865542292595 -0.01840278692543506622 -0.00046000463771633804 -0.00011675532732624561 -0.00400486215949058533 0.00175880384631454945 0.00551376026123762131 0.00014502886915579438 -0.00029589878977276385 -0.00893048010766506195 0.00377432443201541901 0.01133843697607517242 0.00028597644995898008 -0.00000401970646635164 -0.00011952246859436855 0.00005173769386601634 0.00015269605501089245 0.00000393759728467558 0.00145197205711156130 0.04330607503652572632 -0.01857506856322288513 -0.05462514609098434448 -0.00136276683770120144 0.02037221565842628479 0.59098994731903076172 -0.33253228664398193359 -0.79171252250671386719 -0.01920054294168949127 -0.00242669763974845409 -0.12310612201690673828 0.11775102466344833374 0.23839271068572998047 0.00646410975605249405 -0.01090305298566818237 -0.33692669868469238281 0.21897868812084197998 0.48830193281173706055 0.01210230588912963867 -0.00016618089284747839 -0.00489634694531559944 0.00240040034987032413 0.00636864732950925827 0.00015843790606595576 0.00313646881841123104 0.09376609325408935547 -0.04102135077118873596 -0.11897326260805130005 -0.00296115851961076260 0.04371245950460433960 1.26983702182769775391 -0.75194197893142700195 -1.73155438899993896484 -0.04192204400897026062 -0.00375876016914844513 -0.24510757625102996826 0.26465752720832824707 0.51639235019683837891 0.01423308718949556351 -0.02273828350007534027 -0.71434921026229858398 0.49579754471778869629 1.06606483459472656250 0.02647282555699348450 -0.00035899408976547420 -0.01059388369321823120 0.00527576543390750885 0.01383319031447172165 0.00034245228744111955 0.00064158951863646507 0.01928168162703514099 -0.00792277138680219650 -0.02419333904981613159 -0.00060671393293887377 0.00896570272743701935 0.26223865151405334473 -0.14457061886787414551 -0.35133659839630126953 -0.00857396982610225677 -0.00083092635031789541 -0.05170398578047752380 0.05009058117866516113 0.10404615104198455811 0.00288258236832916737 -0.00469069834798574448 -0.14803348481655120850 0.09520944207906723022 0.21602798998355865479 0.00540287280455231667 -0.00007337159331655130 -0.00217514601536095142 0.00103934074286371469 0.00282000307925045490 0.00007034606824163347 0.00000296390953735681 0.00008868607255863026 -0.00003650657163234428 -0.00011273133713984862 -0.00000294342112283630 0.00004278844062355347 0.00126183696556836367 -0.00053868035320192575 -0.00159372331108897924 -0.00004064858512720093 -0.00001078649711416801 -0.00034999917261302471 0.00014739431207999587 0.00046357724932022393 0.00001195960339828162 -0.00002544431845308281 -0.00076075067045167089 0.00033482667640782893 0.00097620801534503698 0.00002490856240910944 -0.00000033741255833775 -0.00000994013771560276 0.00000516924319526879 0.00001341598454018822 0.00000035108740803480 0.00003516796641633846 0.00105865148361772299 -0.00037415421684272587 -0.00129135372117161751 -0.00003317875598440878 0.00145197240635752678 0.04330609366297721863 -0.01857507973909378052 -0.05462514236569404602 -0.00136276683770120144 0.00313646835274994373 0.09376614540815353394 -0.04102130234241485596 -0.11897325515747070312 -0.00296115898527204990 0.00064159044995903969 0.01928170397877693176 -0.00792278721928596497 -0.02419333532452583313 -0.00060671399114653468 0.00000296390862786211 0.00008868601435096934 -0.00003650685175671242 -0.00011273143172729760 -0.00000294342157758365 0.00050521717639639974 0.01490549650043249130 -0.00599087448790669441 -0.01840279623866081238 -0.00046000457950867712 0.02037223428487777710 0.59099066257476806641 -0.33253175020217895508 -0.79171240329742431641 -0.01920053921639919281 0.04371250048279762268 1.26983582973480224609 -0.75194442272186279297 -1.73155498504638671875 -0.04192204773426055908 0.00896572042256593704 0.26223856210708618164 -0.14457072317600250244 -0.35133659839630126953 -0.00857396703213453293 0.00004278846972738393 0.00126183556858450174 -0.00053868914255872369 -0.00159372529014945030 -0.00004064859240315855 -0.00011675640416797251 -0.00400487566366791725 0.00175871024839580059 0.00551376258954405785 0.00014502884005196393 -0.00242670648731291294 -0.12310531735420227051 0.11774965375661849976 0.23839253187179565430 0.00646409718319773674 -0.00375870894640684128 -0.24510690569877624512 0.26465997099876403809 0.51639264822006225586 0.01423308532685041428 -0.00083093962166458368 -0.05170385539531707764 0.05009029433131217957 0.10404626280069351196 0.00288258562795817852 -0.00001078648620023159 -0.00035000016214326024 0.00014739103789906949 0.00046357815153896809 0.00001195962977362797 -0.00029589902260340750 -0.00893048476427793503 0.00377431279048323631 0.01133843138813972473 0.00028597662458196282 -0.01090306695550680161 -0.33692690730094909668 0.21897813677787780762 0.48830154538154602051 0.01210230682045221329 -0.02273826487362384796 -0.71435004472732543945 0.49579602479934692383 1.06606459617614746094 0.02647281810641288757 -0.00469069695100188255 -0.14803352952003479004 0.09520934522151947021 0.21602806448936462402 0.00540287187322974205 -0.00002544432391005103 -0.00076075003016740084 0.00033482658909633756 0.00097620720043778419 0.00002490856786607765 -0.00000401970646635164 -0.00011952264321735129 0.00005173711178940721 0.00015269595314748585 0.00000393759773942293 -0.00016618100926280022 -0.00489635113626718521 0.00240038568153977394 0.00636864406988024712 0.00015843786241021007 -0.00035899443901143968 -0.01059388369321823120 0.00527574541047215462 0.01383318938314914703 0.00034245228744111955 -0.00007337162969633937 -0.00217514624819159508 0.00103934318758547306 0.00282000261358916759 0.00007034606096567586 -0.00000033741261518117 -0.00000994013862509746 0.00000516926229465753 0.00001341598726867232 0.00000035108737961309 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/proton-dose-1.txt000077500000000000000000000006241321604176500271620ustar00rootroot00000000000000[PLAN] patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@.mha dose_prescription = 70 [BEAM] flavor = a homo_approx = n source = 0 -2000 0 isocenter = 0 0 0 aperture_origin = -10 -10 aperture_offset = 1500 aperture_spacing = 1 1 aperture_resolution = 21 21 source_size = 0 prescription_min_max = 70 90 #[PEAK] #energy=100.0000 #spread=1.000000 #weight=1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/proton-dose-2.txt000066400000000000000000000006741321604176500271650ustar00rootroot00000000000000[PLAN] patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha target = @PLM_BUILD_TESTING_DIR@/ptv-1.mha dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@.mha [BEAM] flavor = f homo_approx = n source = 0 -2000 0 isocenter = 0 0 0 aperture_offset = 1500 aperture_origin = -75 -75 aperture_spacing = 3.75 3.75 aperture_resolution = 41 41 aperture_smearing = 5 source_size = 0 [PEAK] energy=100.00000 spread=1.000000 weight=1.0 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/proton-dose-3.txt000066400000000000000000000010531321604176500271560ustar00rootroot00000000000000#this file will create two beams (0° and 180°), both made of two protons peaks [PLAN] patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@.mha [BEAM] flavor = g homo_approx = n source = 0 -2000 0 isocenter = 0 0 0 aperture_origin = -10 -10 aperture_offset = 1500 aperture_spacing = 2 2 aperture_resolution = 11 11 source_size = 0 [PEAK] energy=100.00000 spread=1.000000 weight=.5 [PEAK] energy=80.00000 spread=1.000000 weight=.5 [BEAM] source = 0 2000 0 [PEAK] energy=120.00000 spread=1.000000 weight=1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/proton-dose-4.txt000066400000000000000000000006651321604176500271670ustar00rootroot00000000000000[PLAN] patient = @PLM_BUILD_TESTING_DIR@/rect-18.mha dose_out = @PLM_BUILD_TESTING_DIR@/proton-dose4.mha [BEAM] flavor = h homo_approx = n depth_dose_z_max = 400 source = 0 -2200 0 isocenter = 0 0 0 aperture_origin = -37.5 -37.5 aperture_offset = 1500 aperture_spacing = 7.5 7.5 aperture_resolution = 10 10 range_compensator_file_in = @PLM_BUILD_TESTING_DIR@/rgc-1.mha source_size = 0 [PEAK] energy=100.0000 spread=1.000000 weight=1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/proton-dose-5a.txt000066400000000000000000000005611321604176500273240ustar00rootroot00000000000000[PLAN] patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha target = @PLM_BUILD_TESTING_DIR@/ptv-1.mha dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@.mha [BEAM] flavor = a homo_approx = n source = 0 -2000 0 isocenter = 0 0 0 aperture_offset = 1500 aperture_origin = -75 -75 aperture_spacing = 3.75 3.75 aperture_resolution = 41 41 aperture_smearing = 5 source_size = 0 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/proton-dose-5d.txt000077500000000000000000000006031321604176500273270ustar00rootroot00000000000000[PLAN] patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha target = @PLM_BUILD_TESTING_DIR@/ptv-1.mha dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@.mha [BEAM] flavor = d homo_approx = n source = 0 -2000 0 isocenter = 0 0 0 aperture_offset = 1500 aperture_origin = -75 -75 aperture_spacing = 3.75 3.75 aperture_resolution = 41 41 aperture_smearing = 5 source_size = 0 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/proton-dose-6a.txt000066400000000000000000000005611321604176500273250ustar00rootroot00000000000000[PLAN] patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha target = @PLM_BUILD_TESTING_DIR@/ptv-2.mha dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@.mha [BEAM] flavor = a homo_approx = n source = 0 -2000 0 isocenter = 0 0 0 aperture_offset = 1500 aperture_origin = -75 -75 aperture_spacing = 3.75 3.75 aperture_resolution = 41 41 aperture_smearing = 5 source_size = 0 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/proton-dose-7a.txt000077500000000000000000000005531321604176500273320ustar00rootroot00000000000000[PLAN] patient = @PLM_BUILD_TESTING_DIR@/rect-17.mha dose_out = @PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@.mha dose_prescription = 70 [BEAM] flavor = a homo_approx = n source = 0 -2000 0 isocenter = 0 0 0 aperture_origin = -20 -20 aperture_offset = 1500 aperture_spacing = 1 1 aperture_resolution = 41 41 source_size = 0 spot = -5,0,120,6.0,1.5 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/speedtest-a.txt000077500000000000000000000004061321604176500267670ustar00rootroot00000000000000[GLOBAL] fixed=@PLM_BUILD_TESTING_DIR@/gauss-1.mha moving=@PLM_BUILD_TESTING_DIR@/gauss-2.mha [STAGE] xform=bspline optim=lbfgsb impl=plastimatch threading=single alg_flavor=c max_its=5 convergence_tol=3 grad_tol=0.1 grid_spac=30 30 30 res=2 2 2 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/wed-a.txt000077500000000000000000000007231321604176500255500ustar00rootroot00000000000000[INPUT SETTINGS] ct=@PLM_BUILD_TESTING_DIR@/lung-1.mha target=@PLM_BUILD_TESTING_DIR@/lung-1-prefix/Tumor.mha skin=@PLM_BUILD_TESTING_DIR@/lung-1-prefix/Body.mha [OUTPUT SETTINGS] proj_ct=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-proj-ct.rpl proj_wed=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-proj-wed.rpl wed_ct=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-wed-ct.mha [BEAM] pos=-2270.5 0 0 isocenter=0 0 0 res=1 [APERTURE] offset=1700 center=49.5 49.5 resolution=100 100 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/wed-b.txt000077500000000000000000000007341321604176500255530ustar00rootroot00000000000000[INPUT SETTINGS] ct=@PLM_BUILD_TESTING_DIR@/lung-1.mha proj_wed=@PLM_BUILD_TESTING_DIR@/wed-a-proj-wed.rpl target=@PLM_BUILD_TESTING_DIR@/lung-1-prefix/Tumor.mha skin=@PLM_BUILD_TESTING_DIR@/lung-1-prefix/Body.mha [OUTPUT SETTINGS] proj_ct=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-proj-ct.rpl wed_ct=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-wed-ct.mha [BEAM] pos=-2270.5 0 0 isocenter=0 0 0 res=1 [APERTURE] offset=1700 center=49.5 49.5 resolution=100 100 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/wed-c.txt000077500000000000000000000006371321604176500255560ustar00rootroot00000000000000[INPUT SETTINGS] ct=@PLM_BUILD_TESTING_DIR@/lung-1.mha proj_wed=@PLM_BUILD_TESTING_DIR@/wed-a-proj-wed.mha target=@PLM_BUILD_TESTING_DIR@/lung-1-prefix/Tumor.mha skin=@PLM_BUILD_TESTING_DIR@/lung-1-prefix/Body.mha [OUTPUT SETTINGS] dew_ct=@PLM_BUILD_TESTING_DIR@/@PLM_TEST_NAME@-dew-ct.mha [BEAM] pos=-2270.5 0 0 isocenter=0 0 0 res=1 [APERTURE] offset=1700 center=49.5 49.5 resolution=100 100 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/xf-bspline-1.txt000077500000000000000000000111101321604176500267500ustar00rootroot00000000000000MGH_GPUIT_BSP img_origin = -187.500000 -187.500000 -187.500000 img_spacing = 125.000000 125.000000 125.000000 img_dim = 4 4 4 roi_offset = 0 0 0 roi_dim = 4 4 4 vox_per_rgn = 4 4 4 0.00874600000679492950 0.11050000041723251343 0.09998899698257446289 0.00655200006440281868 0.10134900361299514771 1.27551305294036865234 1.15204703807830810547 0.07538300007581710815 0.07454200088977813721 0.93482702970504760742 0.84315299987792968750 0.05510399863123893738 0.00242500007152557373 0.03017600066959857941 0.02714600041508674622 0.00176999997347593307 0.10134900361299514771 1.27551305294036865234 1.15204703807830810547 0.07538300007581710815 1.17439401149749755859 14.72306156158447265625 13.27355575561523437500 0.86731898784637451172 0.86369997262954711914 10.79030609130859375000 9.71448040008544921875 0.63399302959442138672 0.02808799967169761658 0.34829100966453552246 0.31275799870491027832 0.02036000043153762817 0.07454200088977813721 0.93482702970504760742 0.84315299987792968750 0.05510399863123893738 0.86369997262954711914 10.79030990600585937500 9.71447944641113281250 0.63399302959442138672 0.63515400886535644531 7.90784692764282226562 7.10962390899658203125 0.46343401074409484863 0.02065199986100196838 0.25523498654365539551 0.22888700664043426514 0.01488300040364265442 0.00242500007152557373 0.03017600066959857941 0.02714600041508674622 0.00176999997347593307 0.02808799967169761658 0.34829199314117431641 0.31275799870491027832 0.02036000043153762817 0.02065199986100196838 0.25523599982261657715 0.22888700664043426514 0.01488300040364265442 0.00067099998705089092 0.00823699962347745895 0.00736800022423267365 0.00047800000174902380 0.00529599981382489204 0.03303800150752067566 0.00280799996107816696 -0.00156899995636194944 0.01283700019121170044 0.08370699733495712280 0.01064299978315830231 -0.00367000000551342964 -0.01673400029540061951 -0.10062699764966964722 -0.00534400017932057381 0.00502000004053115845 -0.00211800006218254566 -0.01288899965584278107 -0.00081300002057105303 0.00063399999635294080 0.06116399914026260376 0.38170999288558959961 0.03296700119972229004 -0.01804899983108043671 0.14831300079822540283 0.96726202964782714844 0.12418899685144424438 -0.04222400113940238953 -0.19320300221443176270 -1.16221404075622558594 -0.06328000128269195557 0.05775700137019157410 -0.02445200085639953613 -0.14888100326061248779 -0.00960000045597553253 0.00729400012642145157 0.04472799971699714661 0.27827298641204833984 0.02320099994540214539 -0.01322900038212537766 0.10846900194883346558 0.70512801408767700195 0.08843400329351425171 -0.03095999918878078461 -0.14126099646091461182 -0.84725302457809448242 -0.04361300170421600342 0.04232100024819374084 -0.01787899993360042572 -0.10853599756956100464 -0.00667499983683228493 0.00534499995410442352 0.00143099995329976082 0.00879300013184547424 0.00061500002630054951 -0.00042900000698864460 0.00346900010481476784 0.02227300032973289490 0.00249899993650615215 -0.00100599997676908970 -0.00451799994334578514 -0.02678200043737888336 -0.00102199998218566179 0.00137099996209144592 -0.00057199998991563916 -0.00343000004068017006 -0.00016500000492669642 0.00017299999308306724 0.00529599981382489204 0.03303800150752067566 0.00280799996107816696 -0.00156899995636194944 0.06116399914026260376 0.38170799612998962402 0.03296500071883201599 -0.01804899983108043671 0.04472799971699714661 0.27827200293540954590 0.02319999970495700836 -0.01322900038212537766 0.00143099995329976082 0.00879300013184547424 0.00061500002630054951 -0.00042900000698864460 0.01283700019121170044 0.08370699733495712280 0.01064299978315830231 -0.00367000000551342964 0.14831200242042541504 0.96725302934646606445 0.12418299913406372070 -0.04222400113940238953 0.10846900194883346558 0.70512300729751586914 0.08842899650335311890 -0.03095999918878078461 0.00346900010481476784 0.02227300032973289490 0.00249899993650615215 -0.00100599997676908970 -0.01673400029540061951 -0.10062800347805023193 -0.00534400017932057381 0.00502000004053115845 -0.19320300221443176270 -1.16221904754638671875 -0.06328199803829193115 0.05775700137019157410 -0.14126099646091461182 -0.84725701808929443359 -0.04361499845981597900 0.04232100024819374084 -0.00451799994334578514 -0.02678200043737888336 -0.00102199998218566179 0.00137099996209144592 -0.00211800006218254566 -0.01288899965584278107 -0.00081300002057105303 0.00063399999635294080 -0.02445200085639953613 -0.14888200163841247559 -0.00960000045597553253 0.00729400012642145157 -0.01787899993360042572 -0.10853599756956100464 -0.00667499983683228493 0.00534499995410442352 -0.00057199998991563916 -0.00343000004068017006 -0.00016500000492669642 0.00017299999308306724 xf-bspline-chest-phantom.txt000077500000000000000000007447521321604176500313340ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/DataMGH_GPUIT_BSP img_origin = -178.939346 -178.939346 -166.550003 img_spacing = 2.812400 2.812400 5.000000 img_dim = 128 128 60 roi_offset = 0 0 0 roi_dim = 128 128 60 vox_per_rgn = 7 7 4 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000004 0.000007 0.000003 0.000000 -0.000003 -0.000002 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000004 0.000063 0.000354 0.000691 0.000497 0.000168 0.000088 -0.000120 -0.000172 -0.000061 -0.000022 -0.000001 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000038 0.000494 0.001492 0.002367 0.002224 0.001218 0.000658 0.000447 0.000046 -0.000205 -0.000309 -0.000412 -0.000207 -0.000019 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000044 0.000357 0.002563 0.002922 0.002083 0.001473 0.000879 0.000762 0.000394 0.000242 0.000279 0.000071 -0.000505 -0.000858 -0.000273 -0.000030 -0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000052 -0.001217 -0.001529 0.001343 0.000952 -0.002772 -0.007158 -0.002309 0.001029 0.000161 -0.002864 -0.004124 -0.001033 0.000210 -0.000077 -0.000879 -0.000635 -0.000045 -0.000000 0.000000 0.000000 -0.000007 -0.000776 -0.004075 -0.003055 -0.016591 -0.073361 -0.106373 -0.052634 0.066557 0.010243 -0.088758 -0.169278 -0.295590 -0.284327 -0.084562 -0.004170 -0.000796 -0.001624 -0.000386 -0.000008 0.000000 0.000000 -0.000191 -0.003359 -0.004635 -0.032536 -0.204387 -0.089797 0.215908 0.246897 0.215785 0.016923 -0.179504 -0.354851 -0.790620 -1.251480 -0.838274 -0.232417 -0.018144 -0.001083 -0.001424 -0.000148 -0.000000 0.000000 -0.000811 -0.006341 -0.023640 -0.104628 -0.037513 0.271331 0.106586 -0.004758 0.012152 -0.000087 -0.007166 -0.143975 -0.375743 -0.845444 -1.518405 -1.411998 -0.366090 -0.010445 -0.002031 -0.000565 -0.000004 0.000000 -0.000623 -0.011198 -0.336585 -0.305964 0.077970 -1.369756 -1.513529 -1.257423 -0.994162 -0.643387 0.030332 -0.366640 -0.986930 -1.027643 -0.913366 -2.043725 -1.443802 -0.163516 -0.002121 -0.001523 -0.000052 0.000000 -0.000065 -0.088723 -1.019610 -0.294234 -0.192292 -1.970397 -0.675786 -1.613125 -1.653512 -1.830302 -0.669391 -0.273924 -1.123758 -2.101438 -0.556661 -1.315163 -2.324301 -0.489992 -0.002500 -0.001780 -0.000091 0.000000 -0.000026 -0.262955 -1.438110 -0.077631 0.136255 -0.264539 0.198145 -0.254270 -0.014922 -1.307202 -1.527735 -0.557105 -0.146871 -0.988813 -0.258816 -0.662858 -2.068455 -0.473065 0.007911 -0.000309 -0.000017 0.000000 -0.000071 -0.394442 -1.645664 -0.188398 0.259093 0.127181 0.005950 0.002009 0.001295 -0.265904 -0.203874 -0.260624 0.463837 0.355310 0.037770 -0.438573 -1.764392 -0.288319 0.028443 -0.000118 -0.000006 0.000000 -0.000640 -0.424637 -1.783796 -0.406838 0.201134 0.154403 0.025730 -0.003012 -0.064147 -0.074936 0.006580 -0.033358 0.224754 0.176816 0.120334 -0.421218 -1.620659 -0.142412 0.034083 -0.001920 -0.000108 0.000000 -0.001096 -0.322870 -2.030301 -1.323825 -0.073451 0.171083 0.173257 -0.007954 0.090938 0.658438 0.711125 0.199900 0.140719 0.129622 0.048138 -0.596854 -1.208514 0.146155 0.019034 -0.003673 -0.000125 0.000000 -0.000710 -0.125150 -1.520860 -2.196796 -0.625992 -0.005102 0.099779 -0.013089 0.293621 1.050816 1.390031 0.357942 0.105852 0.069958 -0.059042 -0.804205 -0.453235 0.233990 -0.001643 -0.002658 -0.000027 0.000000 -0.000161 -0.018495 -0.479455 -1.492921 -1.218789 -0.409833 -0.074775 -0.019533 0.064031 0.077285 0.124068 0.040124 0.027071 -0.001037 0.231672 0.040231 -0.013299 0.049523 -0.005302 -0.000814 -0.000001 0.000000 -0.000008 -0.001201 -0.041146 -0.282231 -0.526620 -0.406919 -0.161470 0.033823 0.223562 -0.064722 -0.405388 -0.149097 0.135170 0.324311 0.634953 0.402794 0.025746 -0.004536 -0.002140 -0.000075 -0.000000 0.000000 -0.000000 -0.000078 -0.002842 -0.042517 -0.090449 -0.060341 -0.029743 0.009557 0.066552 0.014007 -0.072051 -0.038284 0.044194 0.090021 0.093625 0.088738 0.015515 -0.004554 -0.000206 -0.000001 0.000000 0.000000 0.000000 -0.000001 -0.000714 -0.045077 -0.103987 -0.036408 -0.004242 -0.000687 0.001566 0.001339 -0.004040 -0.004477 -0.001470 0.007071 0.045349 0.150297 0.063151 -0.000393 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000033 -0.004038 -0.014789 -0.016498 -0.008482 -0.000213 0.000033 0.000652 -0.000333 0.002015 0.005487 0.022526 0.032609 0.026860 0.007999 0.000096 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 -0.000105 -0.001136 -0.001862 -0.000211 -0.000110 0.000142 -0.000107 0.000765 0.001730 0.005228 0.003133 0.000361 0.000003 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000001 -0.000000 -0.000000 0.000000 -0.000000 0.000001 0.000002 0.000005 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000003 0.000043 0.000081 0.000034 0.000006 -0.000034 -0.000020 -0.000001 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000036 0.000689 0.003527 0.006626 0.004948 0.001744 0.000793 -0.001115 -0.001622 -0.000748 -0.000254 -0.000015 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000409 0.005059 0.015420 0.023333 0.020407 0.011370 0.005494 0.003529 0.000087 -0.002663 -0.004059 -0.004663 -0.001995 -0.000161 -0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000002 -0.000432 0.004053 0.027271 0.029229 0.018451 0.011242 0.006618 0.005681 0.003612 0.002766 0.002075 0.000441 -0.004907 -0.007443 -0.002628 -0.000282 -0.000002 0.000000 0.000000 0.000000 -0.000000 -0.000515 -0.012090 -0.014182 0.015482 0.007117 -0.033564 -0.079375 -0.042164 0.008044 0.028912 0.023614 0.000519 0.000987 0.003361 -0.000443 -0.007429 -0.005402 -0.000429 -0.000000 0.000000 0.000000 -0.000068 -0.007665 -0.041156 -0.032027 -0.195959 -0.851247 -1.112069 -0.598348 0.279827 0.075321 -0.405285 -0.819551 -1.472302 -1.416528 -0.513564 -0.040398 -0.006553 -0.015975 -0.004276 -0.000087 0.000000 0.000000 -0.001767 -0.032874 -0.047881 -0.359961 -2.214652 -1.313847 1.766396 2.122848 1.577526 0.134149 -1.173014 -2.324110 -5.085905 -7.981863 -6.518966 -2.179853 -0.166668 -0.012947 -0.014360 -0.001412 -0.000000 0.000000 -0.007616 -0.059266 -0.217202 -1.097950 -0.584448 2.836109 2.471772 0.512650 0.158341 -0.017736 -0.097398 -0.524744 -2.358989 -6.812238 -12.818349 -11.473523 -3.163400 -0.117644 -0.020429 -0.006263 -0.000046 0.000000 -0.006308 -0.105952 -3.063278 -2.681763 1.597880 -9.526690 -12.336441 -10.056984 -7.353563 -4.631383 0.226786 -1.824058 -6.168291 -7.871545 -7.476843 -16.206606 -11.902899 -1.262473 -0.021020 -0.016033 -0.000502 0.000000 -0.000728 -0.817796 -9.016939 -1.930068 -0.329361 -15.930734 -8.143202 -15.491320 -13.273321 -13.336745 -4.227992 -1.553651 -8.156377 -16.685144 -4.975661 -10.278577 -17.329199 -2.939271 0.016392 -0.017010 -0.000876 0.000000 -0.000044 -2.418265 -12.203445 1.062380 1.955045 -2.511285 1.410565 -3.162460 0.661388 -9.538872 -12.185811 -4.624979 -1.845587 -10.541282 -3.546652 -5.344147 -15.686123 -2.081331 0.255451 -0.002552 -0.000168 0.000000 -0.001484 -3.681856 -13.332393 0.458514 2.153662 0.603237 0.047573 0.004520 0.225284 -2.181836 -2.291779 -2.904620 3.100203 2.468009 0.025794 -3.492959 -14.300711 -0.861536 0.574455 -0.001095 -0.000113 0.000000 -0.007282 -4.061594 -14.176543 -1.205942 1.650395 1.042973 0.151773 -0.019210 -0.519829 -0.554868 0.678746 -0.169265 1.258374 1.323598 0.797017 -3.280379 -13.619501 -0.175232 0.600192 -0.021823 -0.001300 0.000000 -0.009728 -3.020430 -15.893497 -7.743051 -0.007421 1.195392 1.412601 0.172457 0.232715 3.394546 3.465900 0.964158 0.601102 0.495990 0.345556 -4.721974 -10.093707 2.276557 0.334477 -0.039079 -0.001459 0.000000 -0.005947 -1.194841 -12.546828 -15.753263 -4.122195 0.054848 1.315420 0.584254 1.699820 6.899059 7.833571 2.232154 1.051314 0.423406 -0.561117 -6.705528 -3.724758 2.838653 0.038145 -0.026564 -0.000324 0.000000 -0.001461 -0.184327 -4.329864 -12.087469 -8.593975 -2.150718 -0.215849 0.011882 0.308500 1.766992 1.827027 0.466834 0.091756 -0.604338 0.712830 -0.176841 0.367664 0.698469 -0.051039 -0.008404 -0.000014 0.000000 -0.000081 -0.011252 -0.410671 -2.598206 -4.316554 -2.995143 -1.262208 0.404381 2.085291 -0.223220 -2.616312 -1.122932 0.714567 2.326031 5.106137 3.648194 0.325408 -0.032246 -0.022050 -0.000849 -0.000000 0.000000 -0.000000 -0.000691 -0.026815 -0.418931 -0.916378 -0.586389 -0.310194 0.144248 0.693736 0.121536 -0.659212 -0.355030 0.321044 0.842560 0.936245 0.846171 0.118736 -0.045293 -0.001878 -0.000010 0.000000 0.000000 0.000000 -0.000007 -0.006494 -0.427054 -1.022571 -0.374025 -0.051008 -0.000232 0.012669 0.010288 -0.028241 -0.042630 -0.017129 0.059901 0.411181 1.349291 0.550463 -0.005072 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000290 -0.036795 -0.143718 -0.177253 -0.096961 -0.003635 0.004751 0.005742 -0.002224 0.010825 0.048166 0.210222 0.302150 0.243667 0.070442 0.000836 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000007 -0.001032 -0.011259 -0.019286 -0.003000 0.001115 0.001149 -0.001122 0.003954 0.015127 0.048539 0.029036 0.003309 0.000032 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000002 -0.000015 -0.000004 0.000003 0.000002 -0.000002 0.000006 0.000020 0.000045 0.000007 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000006 0.000082 0.000167 0.000066 0.000020 -0.000045 -0.000024 -0.000002 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000069 0.001261 0.006213 0.011476 0.009004 0.003178 0.001592 -0.000897 -0.002556 -0.001688 -0.000484 -0.000026 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000808 0.010070 0.029157 0.040246 0.033821 0.018894 0.008980 0.006122 0.001225 -0.005168 -0.008557 -0.008827 -0.003589 -0.000281 -0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000799 0.007862 0.054139 0.056830 0.030780 0.015460 0.009743 0.008938 0.007863 0.005385 0.003089 0.001125 -0.009227 -0.013714 -0.005323 -0.000499 -0.000003 0.000000 0.000000 0.000000 -0.000000 -0.000903 -0.021223 -0.024517 0.029581 0.008128 -0.071871 -0.119235 -0.089976 0.005346 0.075470 0.138090 0.083106 0.021503 0.006692 -0.003182 -0.012453 -0.007889 -0.000713 -0.000000 0.000000 0.000000 -0.000125 -0.013966 -0.073444 -0.059341 -0.391246 -1.836210 -2.371024 -0.905837 -0.040876 0.023303 -0.067090 -0.051952 -0.394448 -0.391554 -0.191461 -0.024649 -0.006530 -0.025509 -0.007903 -0.000161 0.000000 0.000000 -0.003185 -0.061578 -0.092295 -0.791590 -4.135993 -2.586125 2.527783 3.661327 1.942017 0.132845 -1.079860 -1.589816 -4.085500 -6.815025 -5.868133 -2.154530 -0.136395 -0.021911 -0.026337 -0.002663 -0.000001 0.000000 -0.013583 -0.106540 -0.387734 -2.379690 -1.132630 6.494289 7.255776 2.160196 0.414476 -0.014293 -0.250579 2.047288 -0.016633 -8.347779 -15.378068 -12.713038 -3.212819 -0.117156 -0.040882 -0.013095 -0.000095 0.000000 -0.011872 -0.196914 -5.295661 -4.351614 4.933254 -5.657521 -10.677583 -9.570638 -7.073804 -4.124534 -1.281549 -0.543013 -2.620771 -7.608030 -8.727970 -19.454124 -13.409581 -0.966061 -0.032992 -0.031037 -0.000872 0.000000 -0.001653 -1.478612 -14.601527 -0.376297 3.817670 -14.254874 -10.451223 -20.392141 -15.064163 -13.302627 -9.303597 -2.465040 -8.872855 -22.784382 -9.988811 -12.789372 -20.794378 -1.481307 0.206970 -0.029609 -0.001517 0.000000 -0.000422 -4.370195 -18.327883 5.992226 4.001530 -2.686056 1.119547 -5.458707 1.749866 -10.259461 -19.936352 -5.718936 -2.983740 -22.394094 -13.545824 -7.532695 -22.147814 -0.383770 1.005524 -0.004358 -0.000333 0.000000 -0.005737 -6.899036 -19.142782 6.933812 4.654514 0.334340 0.054882 0.009932 0.591423 -3.291014 -6.156606 -5.743652 2.698920 0.819500 -2.006903 -3.930529 -21.934067 -0.309039 1.774899 -0.002710 -0.000337 0.000000 -0.013245 -7.633206 -20.937290 3.619574 4.307522 1.107026 0.109572 -0.030031 -0.867571 -1.131251 1.587601 -0.634760 1.223266 3.653928 1.953332 -3.712679 -21.163298 1.103037 2.051054 -0.048677 -0.003287 0.000000 -0.014129 -5.653492 -22.263144 -3.354109 2.077286 1.854364 1.090642 0.217917 -1.064790 1.283584 1.310584 0.579376 0.010904 0.090111 0.523438 -6.009040 -17.148504 4.221685 1.206682 -0.079630 -0.003460 0.000000 -0.008454 -2.338154 -18.939054 -15.496433 -1.879258 1.018048 1.430438 1.365935 2.757015 9.753010 9.553032 5.193135 1.492641 0.765700 -0.737502 -9.682403 -7.080474 6.293609 0.285055 -0.051642 -0.000728 0.000000 -0.002394 -0.391540 -7.808372 -16.722708 -7.954739 -0.445096 0.315924 -0.064412 0.351935 6.418612 6.161689 2.996682 0.110303 -1.623372 -1.554033 -1.831549 1.138863 2.017989 -0.071674 -0.016574 -0.000031 0.000000 -0.000149 -0.021179 -0.902170 -4.916854 -6.644434 -3.937411 -1.726032 0.607397 3.328853 0.820657 -2.706008 -1.273967 0.359968 2.582070 7.246342 6.587198 0.963395 -0.001711 -0.040866 -0.001654 -0.000000 0.000000 -0.000001 -0.001024 -0.047104 -0.818158 -1.899977 -1.270904 -0.675406 0.413906 1.538095 0.242883 -1.258069 -0.735246 0.464038 1.588027 2.007787 1.691465 0.191944 -0.081973 -0.003206 -0.000017 0.000000 0.000000 0.000000 -0.000010 -0.010245 -0.743073 -1.909529 -0.768114 -0.132455 0.003218 0.022258 0.008926 -0.024087 -0.062025 -0.023530 0.084339 0.679639 2.255047 0.897138 -0.010791 -0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000437 -0.060253 -0.259924 -0.356840 -0.206213 -0.011465 0.010571 0.000023 0.002523 0.014702 0.080282 0.359527 0.523358 0.412455 0.114877 0.001343 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000011 -0.001882 -0.021164 -0.037771 -0.006842 0.003636 -0.000681 -0.000379 0.005096 0.025993 0.083623 0.049753 0.005716 0.000053 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000028 -0.000010 0.000010 -0.000000 -0.000003 0.000007 0.000038 0.000078 0.000013 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000006 0.000080 0.000172 0.000073 0.000022 -0.000048 -0.000024 -0.000002 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000066 0.001075 0.005622 0.010959 0.009132 0.003362 0.001518 -0.000846 -0.002133 -0.001636 -0.000452 -0.000026 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000770 0.009792 0.026808 0.035272 0.032618 0.019504 0.009593 0.006392 0.002403 -0.003105 -0.008136 -0.008332 -0.003099 -0.000272 -0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000773 0.007046 0.052111 0.054957 0.028825 0.016390 0.011032 0.009639 0.010005 0.006863 0.005194 0.002068 -0.008526 -0.012441 -0.005905 -0.000598 -0.000002 0.000000 0.000000 0.000000 -0.000000 -0.000823 -0.019348 -0.022947 0.028562 0.006719 -0.058983 -0.093560 -0.166827 -0.039447 0.051907 0.180046 0.170443 0.046676 0.007827 -0.005039 -0.014877 -0.006690 -0.000564 -0.000000 0.000000 0.000000 -0.000120 -0.012877 -0.066644 -0.054154 -0.414955 -2.335202 -2.827208 -0.735467 -0.634049 -0.292162 -0.184753 0.408029 0.890884 0.270848 0.085905 0.029440 -0.002907 -0.017540 -0.006116 -0.000135 0.000000 0.000000 -0.003034 -0.058662 -0.088491 -0.859880 -3.859525 -4.061653 0.486482 3.707288 1.866899 0.020670 -1.414173 -2.427667 -3.394942 -5.279736 -2.744211 -0.275453 0.132859 -0.010277 -0.021722 -0.002444 -0.000001 0.000000 -0.012947 -0.102406 -0.414713 -2.636722 0.308347 7.439934 5.394847 2.211638 0.646522 0.044113 -0.492235 1.468040 1.271615 -6.950087 -11.388300 -7.423272 -0.218964 0.116561 -0.036801 -0.012380 -0.000091 0.000000 -0.011728 -0.222645 -5.651361 -4.320050 6.652699 2.091135 -0.784057 -1.358874 -1.271102 -0.649027 -1.445808 1.386251 4.994064 -2.441939 -7.069456 -18.133192 -8.775498 0.027535 -0.014272 -0.029571 -0.000815 0.000000 -0.001647 -1.694111 -14.971084 1.563671 6.598542 -1.350555 -1.418984 -4.293414 -2.718226 -3.389793 -9.077879 -2.216396 -3.554694 -15.826493 -8.954682 -11.738169 -18.886074 -0.472989 0.441852 -0.027902 -0.001405 0.000000 -0.001426 -4.978715 -16.994047 9.460588 4.099248 -0.402947 0.124897 -1.336309 0.811313 -5.965880 -21.681738 -6.671319 -4.408761 -24.790726 -16.612000 -5.728615 -22.126913 -1.729616 1.547357 -0.001755 -0.000285 0.000000 -0.010276 -7.818167 -17.228231 8.689899 2.534433 -0.520880 -0.012732 0.025571 0.168533 -3.499910 -9.907629 -8.049515 0.402639 -3.055557 -3.284667 -0.236601 -22.207743 -5.788843 2.157543 0.001401 -0.000382 0.000000 -0.015556 -8.386016 -19.453472 5.528413 4.338294 -0.765030 -0.352504 -0.040208 -0.610063 -0.990687 2.368398 -0.801167 1.093346 4.695928 1.521081 -1.134484 -20.773996 -2.631429 2.946871 -0.044818 -0.003551 0.000000 -0.014058 -6.662627 -21.118296 2.293283 6.164742 0.789741 -1.147498 -0.473182 -1.544606 1.328898 2.765371 0.586226 0.278976 1.182103 -0.033282 -4.011997 -18.935644 2.419829 2.348406 -0.078510 -0.003713 0.000000 -0.007892 -3.038522 -19.537115 -8.817132 2.593972 1.957000 1.315836 0.197284 2.273348 11.717926 10.540721 3.947757 1.377264 2.820337 0.062763 -7.706174 -10.926433 6.570261 0.798068 -0.052414 -0.000756 0.000000 -0.002346 -0.579383 -9.519675 -15.104700 -3.585306 1.422485 1.828685 0.082864 0.412461 10.704837 9.366757 3.753037 0.790808 -0.660220 -3.020601 -3.738324 0.276800 3.118339 0.013454 -0.016657 -0.000030 0.000000 -0.000153 -0.029662 -1.367551 -6.350284 -7.115363 -3.715624 -1.430019 0.334291 2.741798 2.329203 -1.393896 -0.972767 0.025416 1.638242 6.261055 7.429716 1.713625 0.129980 -0.039171 -0.001643 -0.000000 0.000000 -0.000001 -0.000850 -0.050539 -0.970234 -2.372989 -1.803328 -0.909371 0.657588 2.129949 0.351094 -1.703108 -1.088366 0.486747 2.037543 2.978676 2.297894 0.236798 -0.087884 -0.003329 -0.000017 0.000000 0.000000 0.000000 -0.000009 -0.008777 -0.691484 -1.823734 -0.809036 -0.186795 0.030650 0.040994 -0.011022 -0.036059 -0.056174 -0.004935 0.094716 0.666882 2.186468 0.862617 -0.012206 -0.000011 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000364 -0.052195 -0.237972 -0.371413 -0.235847 -0.017426 0.009749 0.008996 0.000817 0.016526 0.077606 0.348210 0.523848 0.401875 0.110026 0.001297 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000009 -0.001848 -0.022258 -0.039738 -0.007591 0.003985 0.004194 -0.000577 0.005191 0.025814 0.081418 0.049094 0.005719 0.000050 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000027 -0.000010 0.000013 0.000012 -0.000004 0.000008 0.000040 0.000078 0.000012 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000006 0.000080 0.000181 0.000073 0.000009 -0.000063 -0.000033 -0.000003 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000062 0.001076 0.005465 0.010630 0.009318 0.003407 0.001291 -0.001425 -0.002730 -0.001692 -0.000439 -0.000023 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000715 0.009013 0.025910 0.034642 0.030490 0.019529 0.009752 0.007347 0.004857 -0.002905 -0.008272 -0.007043 -0.002332 -0.000287 -0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000715 0.007438 0.049595 0.052905 0.028618 0.014112 0.009794 0.009643 0.011541 0.011805 0.007254 0.002626 -0.005042 -0.011619 -0.006572 -0.000618 -0.000001 0.000000 0.000000 0.000000 -0.000000 -0.000786 -0.018440 -0.020943 0.029338 0.010525 -0.037634 -0.056685 -0.161178 -0.070043 0.026837 0.095968 0.158222 0.068044 0.009849 -0.005663 -0.016387 -0.006619 -0.000519 -0.000000 0.000000 0.000000 -0.000113 -0.012218 -0.064191 -0.054503 -0.432448 -2.312049 -2.702485 -0.537468 -0.518323 -0.479203 -0.472093 -0.073822 1.341269 0.932376 0.107517 0.025969 -0.004051 -0.018600 -0.006368 -0.000137 0.000000 0.000000 -0.002785 -0.054707 -0.085178 -0.842156 -3.791084 -4.795440 -0.452822 3.515208 2.268014 0.048605 -1.861143 -3.042944 -3.673775 -4.730012 -3.189794 -0.821082 0.049649 -0.013028 -0.021389 -0.002187 -0.000001 0.000000 -0.011870 -0.093635 -0.415828 -2.360867 1.733444 7.469761 4.478870 2.132088 0.794815 0.085934 -0.465653 -0.822940 -2.103367 -6.910929 -11.608685 -9.142010 -0.807917 0.144804 -0.030332 -0.011047 -0.000086 0.000000 -0.011113 -0.228905 -5.941845 -4.411407 7.149467 2.412071 0.327223 0.040435 0.024661 0.014780 -0.175322 0.636727 2.673692 -0.750325 -5.840021 -18.804857 -10.018825 -0.004044 -0.000372 -0.028739 -0.000848 0.000000 -0.001726 -1.792845 -15.908051 0.429481 5.348279 -0.692076 -0.008532 -0.018713 0.037485 -0.587159 -2.812967 -1.538686 -1.028990 -5.027911 -2.113870 -7.698640 -17.868238 -1.394501 0.553981 -0.030218 -0.001605 0.000000 -0.002054 -5.208784 -15.967645 8.736792 -1.895616 -2.973627 -0.136519 0.009185 0.033708 -4.994686 -17.181581 -10.495964 -6.185798 -10.876489 -6.041030 -1.558338 -19.228996 -4.294866 1.945657 0.000747 -0.000382 0.000000 -0.013173 -8.007956 -15.119355 3.833799 -12.130549 -7.645195 -0.915603 -0.000773 -0.011942 -4.184453 -7.902502 -4.671445 -0.914430 -1.985048 -1.886065 1.082203 -19.302505 -9.611271 2.782749 0.021723 -0.000437 0.000000 -0.022907 -8.684352 -15.921797 2.020570 -15.661517 -12.834053 -4.250802 -0.541450 -0.495230 -1.070402 4.526091 1.424058 0.777572 -0.569577 -4.609350 2.942662 -18.473375 -7.347750 3.671864 -0.019881 -0.003592 0.000000 -0.019458 -7.446005 -19.777178 0.076335 -9.251631 -12.274594 -9.526390 -3.781179 -2.234354 3.073990 9.385862 1.431733 2.090003 -1.195022 -11.293948 -2.997363 -18.856663 -0.917702 3.645574 -0.070726 -0.003856 0.000000 -0.009579 -3.837064 -20.817852 -6.972490 -2.862167 -7.353252 -4.479005 -3.561502 0.719057 11.522085 12.172010 -0.967854 -1.611762 2.520338 -3.213790 -5.562078 -14.388668 5.138382 1.660317 -0.050674 -0.000787 0.000000 -0.002502 -0.875584 -11.423840 -14.114176 -2.473767 0.058904 2.320970 3.068632 1.635246 9.948197 9.980051 2.620161 -0.136995 1.222552 -3.081866 -4.309720 -1.907413 3.919619 0.227954 -0.015611 -0.000031 0.000000 -0.000156 -0.053219 -2.011325 -7.847363 -7.660527 -3.596690 -0.754323 0.834668 2.276859 2.364547 -1.009277 -0.311440 0.559455 0.971313 4.687057 8.156442 2.566886 0.332457 -0.030772 -0.001580 -0.000000 0.000000 -0.000001 -0.000904 -0.067696 -1.257731 -3.108709 -2.398345 -1.108135 0.850798 2.688618 0.460001 -2.369070 -1.493963 0.565802 2.623709 4.204348 3.140612 0.262715 -0.100596 -0.003476 -0.000016 0.000000 0.000000 0.000000 -0.000009 -0.007559 -0.637150 -1.707450 -0.780052 -0.200461 0.047715 0.086263 -0.024103 -0.088742 -0.084131 0.024101 0.199362 0.717411 2.010557 0.752427 -0.015818 -0.000020 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000298 -0.043482 -0.210064 -0.371981 -0.272962 -0.026149 -0.007026 -0.001206 -0.004625 0.016909 0.070988 0.371141 0.526776 0.374154 0.101022 0.001209 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000009 -0.001796 -0.023845 -0.045920 -0.010142 -0.002750 0.000039 -0.002149 0.005645 0.024524 0.085918 0.048936 0.005499 0.000047 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000003 -0.000026 -0.000013 0.000003 0.000003 -0.000006 0.000009 0.000041 0.000082 0.000012 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000007 0.000092 0.000199 0.000052 -0.000002 -0.000053 -0.000035 -0.000003 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000069 0.001197 0.006033 0.012142 0.009918 0.002738 0.001257 -0.001054 -0.003755 -0.002286 -0.000563 -0.000030 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000770 0.009495 0.027990 0.037029 0.033534 0.018272 0.007551 0.007402 0.005014 -0.005966 -0.011780 -0.009360 -0.003233 -0.000348 -0.000003 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000755 0.008648 0.052913 0.054954 0.028241 0.014534 0.008666 0.007557 0.009973 0.011895 0.006535 -0.000920 -0.009818 -0.015912 -0.007290 -0.000619 -0.000002 0.000000 0.000000 0.000000 -0.000000 -0.000903 -0.020751 -0.021905 0.031555 0.014637 -0.016078 -0.038034 -0.105806 -0.039468 0.047830 0.078590 0.128416 0.059114 0.006749 -0.006092 -0.017443 -0.008767 -0.000655 -0.000000 0.000000 0.000000 -0.000126 -0.014043 -0.074569 -0.061716 -0.342335 -1.766550 -2.076287 -0.334827 -0.460100 -0.317559 -0.182926 0.034149 1.505946 1.103283 -0.107287 -0.029264 -0.009831 -0.026893 -0.008220 -0.000166 0.000000 0.000000 -0.003037 -0.061599 -0.097099 -0.848738 -3.728116 -3.787974 -0.257108 3.359937 1.953915 0.157890 -1.384437 -2.623134 -2.960674 -4.872118 -6.388019 -2.979743 -0.354952 -0.028061 -0.028315 -0.002760 -0.000001 0.000000 -0.012813 -0.102713 -0.480935 -2.462901 1.524342 6.216361 3.957192 2.135392 0.806808 0.125477 -0.285313 -1.060908 -2.936868 -7.629561 -13.251549 -14.790535 -5.147513 -0.277309 -0.041904 -0.012862 -0.000088 0.000000 -0.012235 -0.230734 -6.912576 -9.155500 3.212853 -1.012296 0.201188 0.075601 0.036052 0.099540 0.427924 0.126211 -0.142463 -1.987156 -3.763288 -16.704845 -15.502948 -1.717332 -0.013777 -0.032054 -0.001035 0.000000 -0.002407 -1.822142 -18.170603 -7.712887 -1.884015 -5.097494 0.156084 0.064521 0.026601 -0.019929 -0.044168 -0.686866 -0.421919 -2.795196 -3.464602 -4.412816 -15.876425 -3.238131 0.601316 -0.037780 -0.002248 0.000000 -0.002588 -5.285451 -16.260336 4.225967 -10.319097 -9.227826 -0.548912 0.076176 0.007260 -1.634478 -5.122472 -3.715961 -1.494742 -4.134866 -7.685569 -1.887777 -12.271722 -6.464684 2.176343 0.007380 -0.000615 0.000000 -0.017462 -8.146956 -13.111868 1.906934 -17.550505 -14.024590 -3.312135 -0.176662 -0.017281 -1.708325 -1.634883 0.482172 -0.745161 -3.448161 -6.957163 -5.069051 -13.676422 -12.108741 3.254351 0.071241 -0.000515 0.000000 -0.038956 -9.377433 -14.035764 0.654901 -24.117332 -16.876043 -8.882224 -2.470193 -0.752863 -1.231119 3.790954 2.438493 0.170205 -1.405442 -5.195828 -2.389453 -15.558855 -11.069710 4.216878 0.041027 -0.004254 0.000000 -0.032687 -8.364916 -17.724274 1.861606 -20.680483 -14.448950 -10.412667 -7.202578 -4.204630 -0.781614 0.024673 -1.867460 3.577260 -2.809999 -8.742967 -0.868882 -17.131012 -4.917282 4.983096 -0.036963 -0.004569 0.000000 -0.013804 -4.893337 -21.361511 -3.639119 -7.239965 -11.114491 -5.404105 -7.120397 -3.970208 4.505157 -1.176715 -15.150580 -8.206413 -7.374511 -4.695329 -2.425444 -16.242754 2.176703 2.960804 -0.043957 -0.000913 0.000000 -0.003124 -1.423711 -14.086723 -13.021113 -1.853955 -1.665454 1.338735 3.911564 0.545065 7.574326 8.475110 -2.562964 -4.104297 -0.792037 -3.588165 -4.555965 -4.692537 4.257241 0.684791 -0.015562 -0.000035 0.000000 -0.000185 -0.116258 -3.122539 -9.622436 -8.015872 -3.361185 0.070622 1.963699 1.416391 2.642381 0.261823 0.077076 1.228445 0.749154 2.008105 7.784650 3.356977 0.666385 -0.005404 -0.001596 -0.000000 0.000000 -0.000001 -0.001458 -0.121882 -1.818393 -4.349784 -3.221993 -1.405877 0.976944 3.130207 0.778733 -2.919440 -2.014204 0.600301 3.227429 5.393653 4.476542 0.472408 -0.110896 -0.004021 -0.000016 0.000000 0.000000 0.000000 -0.000011 -0.006977 -0.613160 -1.724759 -0.865528 -0.262467 0.092247 0.178756 0.036038 -0.149838 -0.181783 0.067753 0.435005 0.937486 2.013458 0.685107 -0.018720 -0.000027 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000270 -0.035980 -0.190703 -0.379506 -0.320861 -0.056248 -0.034641 -0.019293 0.023898 0.031394 0.113877 0.470149 0.575497 0.363699 0.095924 0.001175 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000008 -0.001799 -0.025269 -0.057924 -0.019784 -0.010852 -0.007772 0.007229 0.011438 0.038342 0.107787 0.054062 0.005554 0.000046 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000035 -0.000024 -0.000007 -0.000013 0.000012 0.000021 0.000060 0.000099 0.000013 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000006 0.000093 0.000216 0.000062 0.000006 -0.000029 -0.000021 -0.000002 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000070 0.001264 0.006137 0.011710 0.009995 0.002988 0.001274 -0.000194 -0.002585 -0.002297 -0.000534 -0.000027 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000795 0.009690 0.028967 0.038384 0.032841 0.018568 0.007999 0.006244 0.004701 -0.004088 -0.011480 -0.008366 -0.003153 -0.000396 -0.000004 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000005 -0.000847 0.008164 0.052784 0.053896 0.025633 0.014020 0.011295 0.007806 0.008028 0.009632 0.006325 -0.000280 -0.007161 -0.016342 -0.008467 -0.000626 -0.000003 0.000000 0.000000 0.000000 -0.000000 -0.000915 -0.022072 -0.025812 0.030794 0.015252 -0.006311 -0.032817 -0.091822 -0.024784 0.055637 0.048780 0.078496 0.035286 0.008584 -0.006469 -0.017783 -0.008081 -0.000631 -0.000000 0.000000 0.000000 -0.000131 -0.015543 -0.080370 -0.067454 -0.276119 -1.198552 -1.488035 -0.348156 -0.807697 -0.224793 0.226454 0.055334 1.168580 0.356753 -0.294927 -0.025806 -0.007587 -0.024901 -0.008135 -0.000174 0.000000 0.000000 -0.003218 -0.068524 -0.109894 -0.640908 -3.581960 -3.462804 -0.964046 2.337808 1.257671 0.708526 -0.325798 -2.190018 -2.742287 -5.748264 -4.892301 -2.122309 -0.405197 -0.034107 -0.030186 -0.003116 -0.000001 0.000000 -0.013677 -0.110325 -0.622992 -2.409493 0.440180 0.003599 -0.298819 1.189306 0.625633 0.918805 1.952886 -0.867118 -3.965115 -8.773149 -5.358680 -10.779285 -7.806172 -0.802439 -0.052505 -0.015901 -0.000121 0.000000 -0.013961 -0.232280 -7.795226 -15.625690 -0.665573 -6.994668 -1.623828 0.498968 -0.003523 1.191963 5.463413 1.284419 -1.994364 -9.156667 -6.011736 -12.529432 -18.783127 -3.616870 -0.000463 -0.041127 -0.001476 0.000000 -0.003188 -1.834543 -20.322548 -14.512803 -1.323843 -8.689082 -0.299097 0.945888 0.097851 0.764392 7.189702 3.718458 -1.575205 -9.168918 -7.362669 -7.805820 -14.692643 -3.422580 0.881172 -0.047931 -0.003082 0.000000 -0.003566 -5.522710 -18.963781 1.846407 -3.497475 -10.013839 -2.352766 0.759594 0.084583 0.107381 4.839363 4.391622 -1.530195 -7.369493 -6.315249 -5.471144 -7.823615 -7.693068 2.135791 0.025286 -0.000770 0.000000 -0.028943 -8.732452 -13.606607 2.309941 -9.371624 -10.186688 -7.006518 -1.220121 -0.330786 -0.129149 1.854868 1.797087 0.659769 -1.380017 -5.844958 -7.782465 -7.317527 -14.286776 3.101005 0.152975 -0.000503 0.000000 -0.072531 -10.563496 -13.697681 -0.010611 -15.273920 -7.857361 -9.428201 -5.522534 -3.095549 -1.928152 2.466268 0.374128 0.763194 0.650064 -7.823584 -11.841721 -12.722942 -14.921201 3.911724 0.154107 -0.004531 0.000000 -0.063051 -9.715234 -16.393372 0.449062 -18.265785 -6.464990 -4.678957 -5.888053 -7.291476 -4.528619 -8.798194 -5.493970 1.914014 -0.672632 -7.169862 -6.605443 -14.654922 -9.761897 5.957237 0.092553 -0.004843 0.000000 -0.023688 -6.424609 -21.613560 -2.700674 -8.224202 -5.964995 -1.918673 -6.438837 -5.031779 0.778916 -13.678192 -22.022243 -7.865684 -4.254919 -2.952193 -1.931315 -15.828216 -2.555710 4.657751 0.014626 -0.000919 0.000000 -0.004137 -2.360538 -17.597820 -11.941126 -1.140502 -0.412271 1.645330 3.715372 -0.026389 6.430762 2.613708 -11.142045 -5.348428 1.695620 -1.868630 -4.651039 -7.275315 3.872532 1.632407 -0.009552 -0.000034 0.000000 -0.000208 -0.257014 -4.944066 -11.430318 -7.933126 -2.523604 1.628919 4.915186 1.980347 3.272564 0.882338 -1.644911 1.332048 0.886824 -0.067920 5.970536 3.886156 1.230279 0.102630 -0.001225 -0.000000 0.000000 -0.000001 -0.003043 -0.258393 -2.635673 -5.864656 -3.941566 -1.405636 1.157903 3.472119 0.807174 -3.117962 -2.103250 0.388900 3.202111 6.216919 5.834474 1.049654 -0.066394 -0.004058 -0.000011 0.000000 0.000000 0.000000 -0.000012 -0.006274 -0.563216 -1.776988 -1.021879 -0.349054 0.129321 0.356572 0.087033 -0.281875 -0.252451 0.066406 0.631243 1.216034 1.872333 0.608868 -0.012195 -0.000026 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000253 -0.029497 -0.172845 -0.385699 -0.338466 -0.056971 -0.017216 -0.007566 0.024974 0.023066 0.097799 0.415800 0.554257 0.346716 0.092021 0.001209 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000008 -0.001786 -0.026032 -0.059555 -0.019080 -0.005033 -0.003909 0.007350 0.008220 0.032130 0.094021 0.051878 0.005562 0.000045 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000036 -0.000025 -0.000001 -0.000006 0.000012 0.000014 0.000047 0.000085 0.000012 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000008 0.000107 0.000246 0.000078 0.000011 -0.000060 -0.000034 -0.000002 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000080 0.001444 0.007213 0.013631 0.011581 0.003365 0.001012 -0.001600 -0.002423 -0.002004 -0.000519 -0.000023 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000892 0.011055 0.033004 0.045329 0.039363 0.021963 0.009177 0.005495 0.003092 -0.002117 -0.010101 -0.007575 -0.003225 -0.000381 -0.000003 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000006 -0.000970 0.009804 0.060558 0.061080 0.029251 0.015229 0.011296 0.010270 0.009533 0.009987 0.006686 0.000299 -0.006750 -0.016598 -0.008707 -0.000717 -0.000003 0.000000 0.000000 0.000000 -0.000000 -0.001074 -0.026081 -0.029598 0.036148 0.015591 -0.004092 -0.009321 -0.038764 0.009263 0.066211 0.022399 0.035509 0.017692 0.007703 -0.008192 -0.019131 -0.008428 -0.000659 -0.000000 0.000000 0.000000 -0.000132 -0.017991 -0.094880 -0.097728 -0.424719 -0.976935 -1.027201 -0.225085 -0.429437 0.118450 0.476139 0.010867 0.515292 -0.237465 -0.246230 -0.030684 -0.008684 -0.024791 -0.008812 -0.000223 -0.000000 0.000000 -0.003285 -0.073868 -0.142470 -0.799416 -3.427987 -2.171492 -1.388820 -0.287518 0.190422 1.291934 0.267782 -1.367977 -2.693299 -4.290394 -1.810159 -2.436401 -0.955027 -0.080628 -0.037708 -0.004572 -0.000004 0.000000 -0.014879 -0.121438 -1.334961 -5.629467 -1.006352 1.042446 -2.246612 -3.241386 -2.558730 1.339428 2.638490 -0.645855 -5.972305 -10.858704 -5.026903 -13.724361 -12.595323 -1.877121 -0.080150 -0.025283 -0.000260 0.000000 -0.016852 -0.288939 -9.400713 -19.463665 1.747447 -2.707038 -4.533554 -1.194823 -0.829349 1.033982 4.395025 0.816755 -5.233187 -17.340118 -13.014802 -14.508710 -19.365419 -3.987780 0.157898 -0.062379 -0.002444 0.000000 -0.004264 -1.890973 -19.839203 -12.311432 4.193564 -5.017435 -5.620960 -0.098368 0.732310 0.539485 4.318565 2.262486 -3.397480 -12.207751 -4.495410 -9.472651 -11.687546 -0.659753 1.547096 -0.061583 -0.004363 0.000000 -0.005370 -5.683754 -19.451267 -1.246385 -1.222795 -5.140121 -7.488831 -2.174711 -0.342317 0.052580 4.861290 4.833447 -2.965575 -7.571254 -1.460568 -9.019078 -9.798233 -7.260225 2.632628 0.066675 -0.001018 0.000000 -0.047571 -9.373498 -14.337951 -3.709792 -10.411879 -3.860055 -8.570647 -6.993825 -4.500045 -1.374083 3.415357 5.048303 4.177951 0.652461 -3.645043 -8.695265 -5.692380 -14.305495 2.929538 0.270761 -0.000524 0.000000 -0.112946 -11.179820 -10.149822 -1.444678 -15.466125 -2.607957 -5.163282 -7.569060 -10.490537 -5.917852 -0.483303 -3.918004 3.745703 1.412357 -7.940419 -11.771567 -6.788159 -17.352720 2.690535 0.328264 -0.004657 0.000000 -0.113961 -10.911822 -12.496114 0.920894 -18.813496 -4.233010 -1.030900 -3.194712 -9.890394 -6.264706 -10.536593 -9.337057 -0.206537 -0.764003 -10.677517 -8.424994 -10.426052 -14.686462 5.827637 0.366354 -0.005061 0.000000 -0.053429 -8.509320 -20.645262 -0.576067 -15.432287 -8.999381 -1.282788 -5.318681 -4.281959 1.914642 -15.490913 -22.225805 -5.824452 -2.203882 -6.358514 1.756267 -12.682023 -9.060649 5.707407 0.191486 -0.001024 0.000000 -0.008649 -3.838889 -20.882170 -9.342091 -4.984087 -8.851227 -2.270414 -1.156364 -1.188921 7.902775 0.670244 -17.402922 -6.795852 3.358476 -0.134594 -2.730520 -8.809609 1.351224 2.966112 0.020312 -0.000043 0.000000 -0.000312 -0.551645 -7.566095 -13.204758 -6.960577 -3.540683 0.575758 5.611701 1.897505 2.713962 1.109390 -3.441448 0.243063 1.483698 -0.818329 3.005365 3.701812 1.859340 0.392343 0.000219 -0.000000 0.000000 -0.000001 -0.009557 -0.584735 -3.914771 -6.851916 -3.613796 -0.801556 1.099174 2.777318 -0.006990 -2.778232 -1.903107 -0.269937 1.396533 5.616933 6.827271 2.108027 0.054595 -0.003016 -0.000005 0.000000 0.000000 0.000000 -0.000015 -0.007211 -0.516071 -1.751437 -1.017647 -0.325630 0.054072 0.454763 0.099732 -0.154760 -0.078586 -0.020026 0.421246 1.408652 1.852938 0.607150 -0.003916 -0.000015 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000250 -0.026695 -0.165109 -0.384126 -0.346588 -0.059789 -0.006691 0.014579 0.020132 0.001155 0.095341 0.413242 0.546365 0.347384 0.095649 0.001366 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000008 -0.001795 -0.026596 -0.059487 -0.015837 -0.001864 0.003619 0.005877 0.000874 0.032183 0.098278 0.053027 0.005815 0.000045 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000034 -0.000017 0.000005 0.000007 0.000008 0.000000 0.000050 0.000095 0.000013 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000046 0.000374 0.000569 0.000155 0.000017 -0.000133 -0.000104 -0.000014 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000238 0.004114 0.018047 0.031146 0.022751 0.005836 0.001246 -0.004760 -0.009274 -0.006713 -0.001554 -0.000066 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.001502 0.021116 0.069352 0.094508 0.075833 0.036676 0.012100 0.005581 -0.000885 -0.016577 -0.031767 -0.021303 -0.007057 -0.000699 -0.000005 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000008 -0.001490 0.015505 0.100786 0.108325 0.051595 0.022091 0.012370 0.010466 0.009421 0.010488 0.006311 -0.007360 -0.022938 -0.034971 -0.015299 -0.001361 -0.000007 0.000000 0.000000 0.000000 -0.000000 -0.001708 -0.041000 -0.046674 0.054058 0.024756 0.002346 0.006948 0.002308 0.013380 0.021026 0.012878 0.017412 0.013336 0.007228 -0.019853 -0.038819 -0.017694 -0.001324 -0.000002 0.000000 0.000000 -0.000216 -0.028632 -0.154212 -0.156153 -0.522720 -1.098336 -0.785750 0.019896 0.062086 0.013891 0.028610 0.008868 0.069524 -0.400324 -0.246485 -0.048146 -0.026134 -0.057359 -0.020286 -0.000624 -0.000000 0.000000 -0.005396 -0.120620 -0.232532 -0.755069 -2.586649 -2.021094 -0.753672 -0.392672 -1.169550 0.089139 -0.205750 -0.942624 -2.331373 -3.912322 -3.609373 -3.398204 -1.312559 -0.160350 -0.092503 -0.012331 -0.000017 0.000000 -0.023720 -0.206250 -1.924592 -3.360827 2.166612 3.039562 2.015376 -5.580306 -11.109156 -1.486865 0.167063 -0.964824 -6.193798 -11.127841 -9.775258 -12.869164 -12.782275 -2.813424 -0.191012 -0.058334 -0.000638 0.000000 -0.027163 -0.581080 -10.887233 -10.491919 4.571912 2.014655 -0.994319 -7.486533 -7.332724 -0.665598 0.192901 -0.170535 -7.257889 -18.351334 -12.360156 -12.396392 -18.463804 -5.485000 0.219286 -0.111774 -0.004258 0.000000 -0.007809 -2.557889 -17.429827 0.966590 7.405147 0.205020 -4.005313 -8.391686 -2.261931 0.179385 0.101056 0.032642 -4.828094 -12.594605 -3.327514 -10.509925 -14.037907 -1.664643 2.334102 -0.080431 -0.006619 0.000000 -0.011233 -6.330040 -15.407471 5.400536 0.702361 -0.256364 -4.623801 -11.383760 -6.425145 -0.051626 0.944980 0.593260 -4.698306 -7.979490 -0.064688 -8.371709 -10.682787 -6.835749 3.616691 0.142610 -0.001484 0.000000 -0.078459 -10.062530 -14.111408 -6.128097 -8.820270 -0.411414 -3.093898 -12.450037 -13.890027 -1.983730 3.327040 4.303919 1.807374 -1.775615 -0.876785 -7.308544 -7.257319 -12.039502 2.907813 0.436329 -0.001017 0.000000 -0.187651 -12.074699 -10.075183 -3.719436 -12.318154 -0.684187 -0.848189 -6.953420 -18.049505 -7.649537 0.803549 -1.367173 5.061604 0.755473 -3.916305 -7.657759 -0.866689 -15.199359 0.842026 0.540103 -0.008437 0.000000 -0.234891 -12.813149 -10.571862 0.702174 -14.517614 -2.204298 -0.065659 -2.425526 -12.858544 -6.787960 -7.357895 -9.652681 -0.260483 -0.236822 -8.213862 -8.288078 -3.353008 -17.526178 3.499635 0.763899 -0.008222 0.000000 -0.144622 -11.358032 -18.374134 2.017423 -12.291004 -7.088778 -1.184380 -4.715178 -3.774053 3.546436 -10.482693 -17.454699 -4.371333 -0.983798 -6.632934 1.049150 -7.514687 -15.682151 4.856638 0.593145 -0.001262 0.000000 -0.029468 -6.009696 -22.596771 -5.847987 -4.015842 -9.249870 -4.155611 -5.295664 -1.692270 11.090436 3.395726 -15.496402 -7.179286 4.339398 0.523914 -1.542220 -8.787197 -3.365137 4.060819 0.153931 0.000011 0.000000 -0.001186 -1.127881 -10.613442 -13.576204 -5.011088 -3.472857 0.585520 6.803470 1.460606 4.297227 3.416760 -3.690773 -1.043496 3.693584 0.584302 0.184511 2.804539 2.445369 0.971691 0.012043 0.000001 0.000000 -0.000002 -0.032470 -1.189880 -5.625341 -7.119407 -2.622104 -0.065794 1.464136 1.439034 -0.630648 -2.234814 -1.954613 -0.064188 1.013463 4.108931 7.484771 3.850874 0.369262 0.006001 0.000033 0.000000 0.000000 0.000000 -0.000025 -0.014007 -0.562454 -1.662666 -0.803512 -0.319405 -0.054630 0.195768 0.048544 -0.025889 -0.325652 0.163825 0.792490 1.415318 2.278155 0.808809 0.001345 0.000004 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000262 -0.026183 -0.165698 -0.409743 -0.413216 -0.082298 0.018863 0.000563 0.012378 0.022091 0.158185 0.561549 0.635054 0.375608 0.107040 0.001573 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000009 -0.001850 -0.028381 -0.072432 -0.023730 0.003939 0.000793 0.004208 0.009360 0.051063 0.126887 0.061787 0.006301 0.000050 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000046 -0.000032 0.000005 0.000002 0.000003 0.000015 0.000076 0.000117 0.000014 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000002 0.000285 0.002156 0.002859 0.000609 -0.000099 -0.000703 -0.000559 -0.000095 -0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000002 0.001305 0.021838 0.090404 0.152252 0.102111 0.019100 -0.002171 -0.028254 -0.053749 -0.040616 -0.008710 -0.000353 -0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000004 0.006260 0.094889 0.328224 0.434742 0.329833 0.141144 0.027112 0.002269 -0.034868 -0.118378 -0.178824 -0.108692 -0.030868 -0.002824 -0.000019 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000027 -0.006020 0.058195 0.405417 0.454054 0.206138 0.063724 0.018955 0.009292 0.008158 0.005731 -0.011447 -0.066146 -0.131891 -0.154087 -0.065435 -0.006221 -0.000029 0.000000 0.000000 0.000000 -0.000000 -0.006518 -0.157033 -0.197010 0.183757 0.090211 0.014555 0.009666 0.005698 -0.015029 -0.006646 0.012752 0.011686 0.008667 -0.013189 -0.111838 -0.197513 -0.087022 -0.006205 -0.000010 0.000000 0.000000 -0.000884 -0.112830 -0.606754 -0.445736 -0.289878 -0.714589 -0.613052 0.018863 0.102709 -0.617685 -0.275610 0.235882 0.071370 -0.174424 -0.083004 -0.029738 -0.142878 -0.279869 -0.097242 -0.003069 -0.000000 0.000000 -0.022130 -0.490122 -0.833510 -0.993105 -2.748711 -2.734547 -1.058120 1.812389 1.336137 2.534059 3.560561 -0.839162 -2.309118 -2.570353 -2.709063 -2.377783 -0.740958 -0.380632 -0.421568 -0.056115 -0.000080 0.000000 -0.094084 -0.786124 -1.422596 -0.289832 -0.148767 0.744451 3.070802 -1.868330 -9.243674 0.958080 3.472166 -1.922879 -6.625914 -6.970370 -9.888264 -13.512105 -8.482581 -1.958124 -0.720762 -0.248151 -0.002844 0.000000 -0.104675 -1.172660 -8.582118 -1.409625 -3.112652 -0.060371 1.508403 -8.152708 -10.401909 -0.851784 0.201478 -0.675070 -10.023065 -17.934464 -13.857731 -14.008825 -15.269633 -5.993881 -0.489697 -0.452610 -0.017193 0.000000 -0.031569 -3.648464 -15.554351 1.729226 -2.790890 -0.529302 -1.037143 -10.636785 -4.407514 0.527843 0.044316 -0.189141 -7.649863 -13.279802 -4.916509 -7.496576 -11.685242 -5.330615 1.795730 -0.336643 -0.025111 0.000000 -0.030614 -7.652185 -12.962044 2.638881 -2.597867 0.164757 -1.478271 -14.281156 -10.615866 1.710640 0.855692 -0.064195 -6.205070 -6.109888 -0.061036 -7.038680 -10.865075 -9.207273 3.453826 0.238201 -0.005266 0.000000 -0.150280 -11.243745 -12.213461 -6.926773 -7.641407 -0.027348 -0.818187 -13.215363 -17.137999 1.238265 3.533879 4.278327 0.646009 -1.207065 -0.077416 -7.498629 -7.182191 -13.166882 1.558806 0.726919 -0.005092 0.000000 -0.351872 -13.591543 -7.951205 -5.830534 -10.400536 -0.258221 -0.157913 -7.524660 -19.793623 -5.411008 3.096069 0.471608 3.999097 0.372787 -0.972053 -7.962325 1.144325 -14.601486 -1.922708 0.717124 -0.038877 0.000000 -0.514378 -15.594731 -7.896770 -2.172519 -13.556490 -1.404680 0.032800 -3.367327 -14.778198 -6.037383 -6.245860 -10.093796 -0.351445 0.090626 -3.221010 -7.884914 1.645801 -18.047709 -0.387506 1.172687 -0.031815 0.000000 -0.416335 -15.846600 -15.525298 2.422294 -12.574530 -4.893093 -0.513214 -3.845366 -4.354056 2.005513 -11.109440 -16.558405 -3.748694 -0.879027 -5.507691 -2.176056 -2.503263 -18.974224 2.829944 1.422428 -0.002189 0.000000 -0.120742 -9.750545 -23.092762 -1.627493 -3.999063 -6.155373 -0.485602 -2.003220 1.993034 10.933777 1.786784 -16.775732 -10.455056 0.965596 0.332481 0.058056 -6.958123 -8.229977 4.635156 0.620263 0.000444 0.000000 -0.007805 -2.330695 -14.590787 -12.996533 -3.881883 -1.814501 5.598462 10.038110 3.519305 6.172113 4.972857 -4.775181 -4.486525 5.281556 3.243940 -2.070384 1.442028 2.286990 1.749945 0.079697 0.000010 0.000000 -0.000021 -0.102481 -2.348547 -8.058500 -7.667012 -0.680673 2.406766 2.772991 1.252674 -0.649022 -2.436376 -1.862466 0.412513 3.312011 3.255933 6.368232 5.663627 0.951583 0.028391 0.000488 0.000000 0.000000 0.000000 -0.000113 -0.040734 -0.837032 -1.956519 -1.226999 -0.694862 0.285613 0.455757 -0.080464 -0.926800 -1.093020 0.603820 2.274508 1.989788 2.836571 1.181056 0.013900 0.000064 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000344 -0.031713 -0.227363 -0.720035 -0.860167 -0.166043 0.034952 -0.010925 -0.013781 -0.018663 0.316507 1.052482 1.016327 0.515396 0.132828 0.001918 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000013 -0.002570 -0.046710 -0.131260 -0.045034 0.003794 -0.002518 0.004156 0.005608 0.085479 0.212746 0.097002 0.009554 0.000078 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000007 -0.000076 -0.000061 -0.000001 -0.000002 0.000005 0.000007 0.000103 0.000170 0.000021 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000150 0.001142 0.001544 0.000342 -0.000039 -0.000367 -0.000291 -0.000049 -0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000710 0.011844 0.048808 0.082402 0.056509 0.011283 -0.000124 -0.014151 -0.027648 -0.021083 -0.004542 -0.000181 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000002 0.003466 0.052299 0.180562 0.238017 0.181207 0.081162 0.017851 0.004790 -0.014881 -0.059512 -0.092288 -0.056144 -0.016386 -0.001539 -0.000010 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000015 -0.003304 0.032786 0.226319 0.254253 0.117257 0.038815 0.015260 0.008571 0.007943 0.007128 -0.002897 -0.031929 -0.067866 -0.082638 -0.035464 -0.003408 -0.000016 0.000000 0.000000 0.000000 -0.000000 -0.003586 -0.086262 -0.106427 0.105628 0.055700 0.013778 0.010364 0.007853 -0.009643 -0.002905 0.011047 0.008272 0.006530 -0.005742 -0.059233 -0.108328 -0.047662 -0.003366 -0.000005 0.000000 0.000000 -0.000488 -0.061640 -0.331177 -0.230972 -0.057900 -0.237330 -0.454162 -0.302332 -0.097375 -0.402718 0.095189 0.355800 0.059357 -0.022796 0.001928 -0.003973 -0.075273 -0.150046 -0.052322 -0.001620 -0.000000 0.000000 -0.012346 -0.269404 -0.456056 -0.653008 -1.700239 -2.359075 -2.298533 0.525471 1.334072 1.509508 2.228048 -0.596435 -1.792251 -0.610025 -0.341095 -0.485453 -0.135695 -0.185268 -0.223985 -0.029583 -0.000043 0.000000 -0.052477 -0.432479 -0.541804 -1.894853 -2.286923 1.365406 3.257944 1.984614 -3.773378 0.551702 0.917003 -3.772625 -5.960337 0.746852 -0.702729 -6.402250 -3.820237 -0.717565 -0.383940 -0.134372 -0.001586 0.000000 -0.057170 -0.755861 -3.836507 0.204084 -4.432751 3.244470 4.109282 -7.103904 -12.295362 -1.042427 0.276206 -2.470604 -12.188313 -10.758476 -7.048865 -13.405485 -14.635472 -5.967273 -0.630151 -0.253535 -0.009830 0.000000 -0.019753 -3.718228 -12.086295 -0.723232 -9.697319 -0.269635 -0.202184 -10.511464 -5.807690 0.943636 0.094088 -1.520852 -12.171258 -11.826189 -7.564260 -8.857384 -10.189986 -12.009410 -0.568234 -0.175010 -0.014260 0.000000 -0.074533 -8.863132 -10.302481 1.658621 -6.089735 -0.087721 -1.251918 -13.782725 -7.580659 3.815348 0.531580 0.095838 -6.790159 -3.592706 -1.564197 -6.819847 -3.378594 -13.283683 0.469486 0.318828 -0.002932 0.000000 -0.308377 -12.704253 -6.450362 -1.965749 -6.866965 -0.000240 -0.878773 -13.796540 -15.277154 0.863407 1.689733 5.208456 2.642846 -0.309665 -0.581692 -7.030571 -1.651337 -13.802909 -1.365061 0.998888 -0.003087 0.000000 -0.611995 -14.989653 -3.959914 -2.869826 -8.784911 -0.206230 -0.259543 -9.153281 -20.556978 -4.490385 3.585890 -2.956349 1.846055 0.277176 -0.826719 -8.409028 1.077948 -14.284780 -5.120593 1.319367 -0.022897 0.000000 -0.866223 -17.597532 -5.283823 -3.379762 -14.566699 -1.552059 0.000470 -4.746353 -16.559011 -5.448358 -6.496668 -12.122027 -0.746717 0.150620 -2.498824 -9.923519 2.598069 -17.792538 -5.131530 1.853737 -0.018437 0.000000 -0.784630 -18.437695 -10.294807 1.389990 -16.467175 -5.985586 -0.627355 -4.681452 -5.977582 0.256047 -12.552648 -14.593740 -2.498356 -0.338143 -4.194740 -4.368052 0.922808 -20.188524 -3.450359 2.001607 -0.000753 0.000000 -0.304099 -12.425218 -18.728868 1.351036 -8.012556 -11.530203 -3.203698 -4.405900 -0.042443 6.867720 -1.582857 -20.844458 -13.076844 -0.201189 1.091977 2.643654 -4.006873 -12.115973 2.312172 1.355887 0.000613 0.000000 -0.028103 -3.418044 -15.087439 -10.146993 -2.594116 -2.450723 2.815912 7.477930 2.652770 5.500769 4.102374 -9.025338 -8.664281 4.069777 1.709259 -2.938509 0.119166 2.247436 2.671830 0.290304 0.000034 0.000000 -0.000126 -0.195464 -3.113407 -8.581581 -6.768499 -0.465468 2.318904 4.229460 1.786932 -0.352772 -2.764473 -2.456942 0.032492 5.435589 2.534162 3.879267 7.080104 2.226633 0.158940 0.003499 0.000000 0.000000 0.000000 -0.000347 -0.068386 -0.940151 -1.855039 -1.747597 -1.259156 1.142425 1.305824 -0.377088 -2.259616 -2.223550 1.103500 4.000154 2.360373 2.713551 1.504755 0.060175 0.000285 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000295 -0.024718 -0.149941 -0.482399 -0.670530 -0.140177 0.033157 -0.021893 -0.081501 -0.085034 0.327223 0.759813 0.661095 0.417871 0.127575 0.001868 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000010 -0.001565 -0.028759 -0.091637 -0.036050 0.000201 -0.003608 0.001048 0.007686 0.078480 0.142277 0.061339 0.006269 0.000057 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000005 -0.000050 -0.000039 -0.000000 -0.000005 0.000002 0.000013 0.000107 0.000124 0.000014 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000007 0.000079 0.000165 0.000067 0.000016 -0.000046 -0.000032 -0.000003 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000070 0.001247 0.005315 0.009537 0.008231 0.003330 0.001932 -0.000997 -0.002613 -0.001490 -0.000387 -0.000018 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000642 0.008433 0.025849 0.033732 0.027446 0.017699 0.009154 0.007439 0.002962 -0.002729 -0.007331 -0.006610 -0.002577 -0.000241 -0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000003 -0.000673 0.006876 0.044765 0.046795 0.023690 0.012833 0.010817 0.008906 0.007265 0.007150 0.005769 -0.000125 -0.008178 -0.012485 -0.005544 -0.000503 -0.000003 0.000000 0.000000 0.000000 -0.000000 -0.000736 -0.017401 -0.019180 0.026853 0.017559 0.009533 0.008641 0.008887 0.009393 0.007268 0.007053 0.006231 0.004809 0.002344 -0.005890 -0.014236 -0.006621 -0.000488 -0.000000 0.000000 0.000000 -0.000091 -0.010636 -0.058427 -0.037563 0.001261 -0.039476 -0.150431 -0.240896 -0.152740 0.071503 0.286332 0.167773 0.032184 0.005204 0.004979 0.005626 -0.004884 -0.017232 -0.005706 -0.000135 -0.000000 0.000000 -0.002251 -0.041693 -0.065937 -0.154707 -0.614549 -1.513077 -2.498038 -2.047899 -1.251526 0.218098 1.287717 0.236883 -0.560197 -0.041018 0.024306 -0.014372 -0.000063 -0.016104 -0.021900 -0.002470 -0.000003 0.000000 -0.009782 -0.069368 -0.206578 -2.278402 -2.807124 0.431344 1.220223 2.523612 -1.480044 -0.792195 -1.458761 -4.160167 -2.364325 2.680035 1.242263 -0.995681 -0.902022 -0.144633 -0.044622 -0.016574 -0.000244 0.000000 -0.008730 -0.197096 -0.988690 -1.328312 -0.250349 8.636356 7.010618 -3.703078 -13.207872 -1.366627 -0.905477 -6.090451 -8.188572 -2.087246 2.622674 -4.436845 -8.847066 -3.504312 -0.388525 -0.050054 -0.002273 0.000000 -0.009650 -2.577270 -5.073910 2.557987 -7.054661 1.548219 1.352820 -10.461905 -9.941569 1.180779 -1.013751 -5.444550 -10.744613 -8.734962 -3.454885 -9.356501 -15.370591 -14.789915 -3.699898 -0.123305 -0.003380 0.000000 -0.161245 -9.503947 -8.258733 0.442718 -6.943405 -0.613303 -0.826934 -12.651318 -7.441411 2.402994 -1.877108 -1.249190 -1.873600 -1.183461 -3.605509 -10.641760 -8.088477 -21.478704 -9.694309 -0.342934 -0.000683 0.000000 -0.437790 -13.220445 -8.055099 -3.255792 -5.190348 0.160586 -0.751949 -13.079153 -13.955591 -0.669618 -3.047097 -1.731551 2.999683 0.265093 -1.502761 -9.830893 -2.252849 -13.503530 -6.166864 0.199826 -0.000726 0.000000 -0.499767 -11.503379 -8.141950 -3.692273 -8.428592 -1.185936 -0.328681 -10.106899 -18.857515 -2.705741 -0.354207 -13.261909 -1.238492 0.114963 -1.980624 -7.592717 -0.352250 -9.146749 -1.189654 0.798978 -0.005057 0.000000 -0.656073 -12.335086 -6.450290 -2.321135 -10.167704 -1.748700 -0.103367 -6.241861 -17.512726 -4.287271 -5.737560 -15.193329 -1.757752 0.068693 -3.925760 -6.545208 0.773216 -12.197578 -2.225133 0.829880 -0.004673 0.000000 -0.964888 -16.840845 -6.893143 0.537905 -16.292414 -8.144258 -0.991384 -5.178514 -7.956264 -0.902929 -12.722616 -14.074268 -1.503648 -0.205057 -3.790611 -2.917727 -1.194224 -18.542038 -9.350036 0.537618 0.000787 0.000000 -0.551768 -13.913264 -16.948275 -1.218551 -13.661954 -20.087631 -5.707179 -5.390482 -2.038037 4.080605 -4.470193 -22.594849 -11.402930 -0.442463 1.250958 5.991630 -1.051718 -14.668460 -4.268018 1.540682 0.002004 0.000000 -0.056409 -4.111730 -15.373097 -9.765611 -0.453274 -3.063516 -0.357359 6.465640 1.883593 5.147377 4.168368 -10.733711 -8.163508 3.845582 2.201136 -0.430853 0.553755 2.558917 2.529023 0.628034 0.000249 0.000000 -0.000272 -0.296395 -3.837572 -8.790206 -5.114991 -0.427275 -0.588040 4.484713 2.695313 0.826260 -2.001206 -3.102612 -0.073267 7.255733 2.574092 2.781374 7.858399 4.079210 0.423698 0.013484 0.000000 0.000000 0.000000 -0.001141 -0.110353 -1.057771 -1.848731 -1.977751 -1.958949 1.605537 1.885862 -0.471603 -2.950660 -2.888629 1.268366 5.403325 2.510037 2.746994 1.840861 0.140890 0.002000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000259 -0.018224 -0.076166 -0.218099 -0.429812 -0.099231 0.063928 -0.031751 -0.137982 -0.106307 0.276028 0.427745 0.340739 0.353070 0.131140 0.001901 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000006 -0.000751 -0.012380 -0.051115 -0.028877 0.001892 -0.002782 0.000332 0.013324 0.064911 0.072107 0.029718 0.003448 0.000036 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000003 -0.000027 -0.000025 -0.000000 -0.000005 0.000001 0.000021 0.000105 0.000084 0.000008 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000007 0.000094 0.000195 0.000074 0.000006 -0.000079 -0.000040 -0.000003 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000079 0.001420 0.006763 0.012914 0.010241 0.003805 0.001627 -0.002575 -0.003540 -0.002045 -0.000600 -0.000030 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000837 0.011092 0.032407 0.043037 0.037806 0.020934 0.009518 0.006706 0.000574 -0.004953 -0.011723 -0.010820 -0.003655 -0.000331 -0.000003 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000005 -0.000841 0.008214 0.058259 0.060721 0.029754 0.015244 0.010555 0.007888 0.004763 0.005779 0.003990 -0.003646 -0.014464 -0.017239 -0.007679 -0.000737 -0.000004 0.000000 0.000000 0.000000 -0.000000 -0.001029 -0.023400 -0.026574 0.032493 0.020645 0.009502 0.008252 0.009520 0.010467 0.005999 0.005552 0.003988 0.002937 0.001538 -0.008715 -0.021068 -0.010333 -0.000712 -0.000000 0.000000 0.000000 -0.000135 -0.014761 -0.079926 -0.051798 0.006295 0.005928 -0.008792 -0.035714 -0.036569 0.029210 0.086502 0.040624 0.009047 0.004591 0.004877 0.005357 -0.009986 -0.027099 -0.008380 -0.000179 0.000000 0.000000 -0.003077 -0.054750 -0.081292 -0.022121 -0.078332 -0.293806 -0.832549 -1.347989 -1.513990 0.249385 1.617115 0.621192 -0.076717 -0.000406 0.007009 0.006368 0.005267 -0.024262 -0.030448 -0.003026 -0.000001 0.000000 -0.012205 -0.081323 -0.101114 -1.066293 -2.023967 -1.344452 -1.818372 0.538117 -1.605243 -0.275343 0.006260 -2.696820 -0.710775 1.096514 0.320742 -0.108146 -0.106491 -0.023892 -0.051437 -0.017408 -0.000203 0.000000 -0.009681 -0.069262 -0.705342 -4.273922 -4.686628 1.760402 2.351337 0.922238 -6.465844 -0.412647 -4.507231 -7.757852 -0.269472 3.475896 4.076615 -2.472666 -3.188910 -0.656275 -0.178335 -0.056558 -0.002598 0.000000 -0.023176 -1.212471 0.497673 1.999243 -9.696503 0.037874 2.763703 -7.302460 -9.543289 1.630069 -7.229260 -8.909075 -2.467738 -3.245731 -1.484787 -9.813437 -9.980090 -8.066668 -4.140754 -0.246833 -0.004321 0.000000 -0.305774 -9.452046 -7.150202 -1.734249 -14.088861 -2.256931 0.004257 -11.037883 -10.535144 0.303063 -10.221927 -9.251862 0.275472 -2.127831 -8.823812 -13.006681 -11.000064 -20.408445 -13.430375 -0.867627 -0.000864 0.000000 -0.359634 -10.014196 -16.751213 -13.103344 -8.344353 -1.342214 -0.479744 -11.766497 -13.905252 -0.707225 -7.484629 -12.696603 -0.621349 -0.081780 -3.798794 -8.631685 -4.652262 -3.330999 -2.294898 -0.252195 -0.000609 0.000000 -0.092043 -3.175541 -14.362771 -15.681354 0.567282 -3.362991 -0.361007 -10.066483 -14.065104 3.380931 0.093395 -18.007027 -3.427443 -0.261419 -5.552452 -1.341507 -0.830929 1.413238 2.783263 0.079809 -0.004726 0.000000 -0.102891 -2.285601 -9.996107 -7.251641 19.492807 -0.383182 -0.220227 -7.249651 -15.350474 1.346511 3.552358 -15.475491 -4.435876 -0.270491 -6.610789 10.281685 11.269858 -0.960693 2.223579 0.000768 -0.004995 0.000000 -0.417584 -7.988565 -3.583355 -0.210923 -17.218948 -12.622428 -1.240072 -5.141312 -10.527019 -2.203238 -8.654588 -13.826309 -1.924138 -0.467093 -7.121746 -5.839735 -8.119252 -10.093386 -3.629461 -0.111634 -0.000169 0.000000 -0.434307 -12.829620 -22.790688 -7.106836 -16.601231 -24.103439 -4.373100 -2.798862 -1.635822 4.634278 -4.854161 -21.329618 -10.076551 -1.373648 -0.910466 3.106424 -3.448281 -16.247145 -5.255099 1.270117 0.001810 0.000000 -0.059657 -4.451821 -19.371042 -12.970800 1.460890 -3.696505 2.228229 7.617273 2.377586 6.529313 5.638590 -8.880054 -7.914076 2.334292 2.268332 0.367574 2.518063 0.378066 0.740810 0.769319 0.000313 0.000000 -0.000299 -0.360711 -4.659034 -9.253685 -5.809246 -1.452687 0.205452 4.878290 2.811901 1.130946 -0.395130 -2.833134 -0.208693 6.050709 1.666262 2.445730 8.443842 5.430118 0.461016 0.022009 0.000000 0.000000 0.000000 -0.002245 -0.145882 -1.156018 -2.051538 -2.288622 -2.318321 2.080081 2.294255 -0.480739 -2.621406 -2.768549 1.552990 4.905386 2.353748 2.823164 1.966660 0.193853 0.005281 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000267 -0.018009 -0.076762 -0.228997 -0.454636 -0.059122 0.085764 -0.038913 -0.121773 -0.110496 0.312493 0.518344 0.429229 0.394105 0.141625 0.002056 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000006 -0.000828 -0.012857 -0.051136 -0.033694 -0.003133 -0.004511 0.004531 0.010762 0.071431 0.088413 0.036173 0.003987 0.000041 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000003 -0.000031 -0.000039 -0.000006 -0.000005 0.000007 0.000017 0.000110 0.000093 0.000009 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000011 0.000145 0.000321 0.000103 0.000003 -0.000119 -0.000061 -0.000004 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000115 0.002019 0.009235 0.018259 0.015083 0.004161 0.001095 -0.004413 -0.005616 -0.002996 -0.000802 -0.000042 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.001267 0.015975 0.046361 0.058458 0.050323 0.026609 0.008287 0.004563 -0.003024 -0.010861 -0.016771 -0.014916 -0.005122 -0.000442 -0.000004 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000007 -0.001308 0.011799 0.084863 0.085084 0.038370 0.017080 0.010202 0.006153 0.005027 0.004691 0.001413 -0.006723 -0.020689 -0.023781 -0.011280 -0.001130 -0.000006 0.000000 0.000000 0.000000 -0.000000 -0.001481 -0.034397 -0.042456 0.044244 0.024491 0.007452 0.007060 0.009197 0.008917 0.006119 0.004293 0.003578 0.002778 0.000842 -0.014158 -0.031607 -0.014418 -0.001017 -0.000001 0.000000 0.000000 -0.000194 -0.021545 -0.117409 -0.080621 0.003934 0.006757 0.004272 0.005725 0.006749 0.011484 0.011918 0.006623 0.005235 0.004147 0.006041 0.005436 -0.016285 -0.041760 -0.013418 -0.000252 0.000000 0.000000 -0.004304 -0.079347 -0.121152 -0.017422 0.005119 -0.015919 -0.083897 -0.241344 -0.500981 0.155565 0.673585 0.234548 0.004039 0.003845 0.006160 0.007524 0.002829 -0.041236 -0.044135 -0.004167 -0.000002 0.000000 -0.015581 -0.109105 -0.064369 -0.169102 -0.667816 -1.538818 -2.192142 -1.458866 -2.702227 -0.457442 1.414930 -0.901035 -0.719761 0.062266 0.026005 -0.005283 -0.000182 -0.017592 -0.072838 -0.023279 -0.000211 0.000000 -0.009925 -0.056034 -0.492156 -2.856900 -4.244072 -2.718282 -1.034254 0.059607 -3.257380 -0.890361 -5.548746 -10.136423 -2.807632 1.410123 0.725154 -1.466069 -0.236335 0.150561 -0.087943 -0.066977 -0.002788 0.000000 -0.039714 -0.738869 -0.274374 -0.897399 -3.344069 6.316727 7.246184 -4.771036 -8.538791 2.517446 -9.650458 -16.515574 -5.226391 1.701967 -2.474923 -9.151800 -2.413101 -2.288704 -2.450873 -0.239171 -0.004785 0.000000 -0.548969 -9.506032 -8.350452 -0.549737 -13.540809 -3.776332 1.685410 -10.439413 -12.573891 3.081991 -8.774112 -15.507188 -3.083623 -1.579822 -7.262278 -12.176525 -10.738228 -14.363190 -8.164477 -0.620319 -0.000993 0.000000 -0.486795 -8.328898 -16.716810 -14.635098 -10.193447 -5.085664 -0.552013 -11.149863 -14.567781 1.927752 -1.711389 -14.441083 -1.894017 -0.892938 -5.951023 -5.153631 -1.397827 0.686808 2.428367 0.093266 -0.000774 0.000000 -0.029767 -0.744416 -11.368952 -17.459240 25.167316 1.828127 -0.311724 -9.784938 -15.921274 8.823297 2.638461 -19.756264 -3.843705 -1.055841 -10.642915 5.202568 7.290926 3.541431 1.777527 -0.020248 -0.005989 0.000000 -0.020876 -0.158684 -9.301548 -4.473375 58.612053 4.359829 -0.325670 -8.088372 -19.796120 4.187118 6.987244 -16.704611 -5.356394 -1.132092 -8.970532 29.048550 23.775852 0.926786 1.641591 -0.069150 -0.005885 0.000000 -0.138534 -4.125969 -2.976039 4.794196 -17.638437 -17.618990 -1.060386 -4.640569 -10.050092 -1.806413 -6.270487 -14.451237 -2.551743 -1.387865 -10.066395 -8.419364 -15.151335 -6.538087 -0.893248 0.182760 0.003673 0.000000 -0.268468 -11.626227 -26.217745 -3.318234 -5.939578 -16.264679 -2.179828 -0.891907 1.731111 7.549829 -0.674126 -21.905003 -11.812719 -1.662689 0.196804 -0.067451 -7.481157 -16.593702 -4.749265 1.246409 0.004697 0.000000 -0.054030 -4.622265 -20.657593 -11.929667 2.610591 -2.012393 3.467104 7.847846 3.655952 8.596263 6.982236 -8.608910 -9.540375 2.522707 3.302924 -0.067734 1.864230 -1.235773 -0.655761 0.679790 0.000455 0.000000 -0.000303 -0.368206 -4.573200 -8.743187 -6.890186 -2.947467 0.562744 5.309017 2.403240 0.490458 0.449342 -2.143074 -0.412740 3.830502 1.378989 3.576197 7.758409 5.271810 0.373022 0.017663 0.000000 0.000000 0.000000 -0.002220 -0.132107 -1.075337 -1.968135 -2.316113 -2.310124 1.612493 1.905761 -0.593356 -1.312974 -1.941776 1.588058 3.392683 1.919795 2.830312 1.762368 0.155269 0.005173 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000269 -0.019789 -0.096007 -0.310028 -0.575076 -0.107378 0.084611 -0.018019 -0.060962 -0.088069 0.313812 0.682603 0.599445 0.414704 0.134881 0.002013 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000007 -0.000988 -0.016090 -0.061937 -0.034436 0.000979 0.001458 0.002513 0.004396 0.067948 0.123755 0.052780 0.005226 0.000048 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000003 -0.000034 -0.000037 0.000001 0.000005 0.000003 0.000006 0.000089 0.000105 0.000012 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000008 0.000110 0.000247 0.000074 0.000012 -0.000064 -0.000038 -0.000003 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000087 0.001459 0.006491 0.013175 0.011507 0.003248 0.001226 -0.002197 -0.003752 -0.002121 -0.000556 -0.000029 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000942 0.011961 0.034679 0.041680 0.035832 0.020658 0.007809 0.004490 -0.001098 -0.007882 -0.011910 -0.010472 -0.003766 -0.000307 -0.000003 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000005 -0.001016 0.009640 0.063940 0.063435 0.027900 0.012357 0.008700 0.007208 0.005991 0.003678 0.001290 -0.004200 -0.013643 -0.015991 -0.007808 -0.000865 -0.000005 0.000000 0.000000 0.000000 -0.000000 -0.001108 -0.026352 -0.031546 0.035951 0.018856 0.006278 0.005546 0.007424 0.007795 0.006080 0.004248 0.003718 0.003469 0.002073 -0.008697 -0.024212 -0.011778 -0.000749 -0.000001 0.000000 0.000000 -0.000144 -0.016491 -0.089942 -0.060449 0.005244 0.006797 0.004319 0.005155 0.006892 0.006536 0.005110 0.004282 0.005559 0.004932 0.005351 0.003822 -0.012667 -0.029639 -0.009253 -0.000192 0.000000 0.000000 -0.003133 -0.059081 -0.092396 -0.012542 0.007260 0.004577 -0.000280 -0.015313 -0.066318 -0.002419 0.083726 0.035770 0.007874 0.005670 0.005802 0.005578 0.004684 -0.025928 -0.032784 -0.003207 -0.000001 0.000000 -0.010750 -0.076054 -0.038489 -0.000081 -0.058460 -0.273107 -0.595846 -0.974570 -1.859306 -0.161690 1.644824 0.334076 -0.167460 -0.036060 0.004976 0.005578 0.007958 -0.009091 -0.053559 -0.016991 -0.000126 0.000000 -0.005320 -0.026355 -0.087515 -0.556545 -1.132244 -0.792506 -2.244032 -2.403537 -3.839121 0.245434 0.446289 -4.987799 -3.326081 -1.611140 -0.929188 -0.357887 0.094699 0.040742 -0.053240 -0.042565 -0.001553 0.000000 -0.031058 -0.403059 -0.539273 -1.210726 -2.078543 3.904486 3.371704 -1.883728 -4.591549 4.035966 -2.640935 -15.842628 -7.393592 -4.555700 -6.617470 -3.033712 0.435199 -0.527536 -0.899011 -0.133235 -0.002826 0.000000 -0.782013 -7.785911 -4.247461 4.340378 -5.395049 -5.607614 0.818858 -8.391488 -12.445860 6.316924 1.883328 -16.019802 -5.179324 -4.749294 -6.092209 -4.399625 -5.765899 -9.917624 -5.913732 -0.742896 -0.002047 0.000000 -1.106990 -10.368345 -12.594232 -4.960522 -12.231855 -9.071115 -1.076742 -11.244857 -17.060898 1.536070 -0.366723 -14.353097 -2.432540 -4.109872 -8.729162 -4.338533 -7.598146 -10.124027 -1.018054 -0.557967 -0.014090 0.000000 -0.217368 -2.926959 -17.257130 -26.248472 -13.612751 -9.454470 0.359446 -8.975382 -16.941175 5.896127 -2.585370 -17.927345 -2.542934 -3.177980 -15.388957 2.783272 -2.309978 -5.025687 2.650528 -0.353447 -0.034752 0.000000 -0.193037 -1.801320 -12.394902 -18.239355 13.725853 -12.005365 -1.015658 -8.176813 -18.654402 3.855790 -0.405001 -18.911917 -3.880944 -2.908648 -17.638304 25.656612 21.421116 -6.280303 2.078600 0.200396 0.040202 0.000000 -0.617192 -8.106540 -3.660427 2.299585 -18.153833 -19.809107 -2.510608 -5.120930 -8.040627 -0.054508 -6.535924 -19.259842 -5.330414 -3.038130 -9.317337 1.734862 -2.072799 -11.416433 -2.696887 3.025367 0.195921 0.000000 -0.523848 -14.102015 -23.834274 2.255807 4.703605 -7.952152 -0.370744 1.111332 1.800901 9.839647 3.902303 -20.356163 -12.300837 -1.949479 1.768200 -1.053453 -2.796186 -12.007698 -3.915344 3.323973 0.081079 0.000000 -0.068067 -4.771807 -17.365602 -7.360835 4.322897 2.258994 4.349650 6.358669 3.224485 10.111780 7.846879 -5.626500 -6.248682 3.510983 1.702556 -1.106049 3.054272 2.562430 -0.391164 0.535474 0.002815 0.000000 -0.000317 -0.303935 -3.382387 -7.097916 -6.079620 -2.205702 0.008097 3.228114 1.328302 0.794616 0.955581 -0.916589 -0.202607 2.623814 2.228974 6.003297 6.359091 3.729391 0.351485 0.005707 0.000000 0.000000 0.000000 -0.001054 -0.074164 -0.766712 -1.368309 -1.427122 -1.499593 0.632272 0.805661 -0.337712 -0.121501 -0.622933 0.820990 1.592744 1.242791 2.824571 1.374759 0.065537 0.001700 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000269 -0.020378 -0.112165 -0.348020 -0.499616 -0.093616 0.049626 -0.000010 0.009671 -0.028036 0.175635 0.580498 0.602793 0.385086 0.119192 0.001807 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000007 -0.001126 -0.019426 -0.063828 -0.023331 0.005799 0.002817 0.004133 -0.001965 0.043183 0.121044 0.057454 0.005709 0.000047 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000003 -0.000035 -0.000025 0.000005 0.000005 0.000003 -0.000007 0.000053 0.000105 0.000013 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000006 0.000090 0.000200 0.000054 0.000007 -0.000038 -0.000030 -0.000003 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000069 0.001131 0.005483 0.010887 0.009240 0.002412 0.000880 -0.001474 -0.003240 -0.001712 -0.000408 -0.000022 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000783 0.009658 0.027582 0.034181 0.029771 0.016239 0.006399 0.003844 -0.000760 -0.006812 -0.008774 -0.007278 -0.003039 -0.000301 -0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000807 0.008314 0.052515 0.051767 0.022870 0.010865 0.006946 0.006231 0.004699 0.002375 0.001297 -0.001501 -0.009250 -0.014099 -0.005855 -0.000607 -0.000004 0.000000 0.000000 0.000000 -0.000000 -0.000892 -0.021455 -0.024340 0.030791 0.016871 0.005851 0.004498 0.005763 0.005822 0.004225 0.002908 0.003936 0.004166 0.002152 -0.006612 -0.017776 -0.009472 -0.000591 -0.000000 0.000000 0.000000 -0.000116 -0.013284 -0.072733 -0.049350 0.004760 0.006702 0.004777 0.003936 0.005405 0.005321 0.004111 0.003562 0.005177 0.005835 0.005557 0.003711 -0.010157 -0.023846 -0.007793 -0.000175 0.000000 0.000000 -0.002591 -0.048868 -0.075108 -0.009899 0.007619 0.006859 0.004836 0.004390 0.002283 0.004771 0.007556 0.005779 0.006025 0.006328 0.006640 0.005991 0.003973 -0.023117 -0.029042 -0.002855 -0.000001 0.000000 -0.009166 -0.065300 -0.032608 0.006908 0.005842 -0.005122 -0.051693 -0.159002 -0.359100 0.222835 0.656339 0.200385 0.039046 0.004908 0.007364 0.006787 0.007292 -0.007516 -0.044139 -0.014048 -0.000092 0.000000 -0.004463 -0.019793 -0.005290 -0.048157 -0.282058 -0.931851 -1.928351 -1.712959 -1.986913 1.671542 3.165066 -0.021674 0.040409 -0.477404 -0.298197 0.021228 0.035083 0.007187 -0.045150 -0.033106 -0.001016 0.000000 -0.007587 -0.073923 -0.225837 -1.165089 -2.642443 -3.365036 -2.011935 0.977918 -0.030967 3.993790 2.627620 -7.764141 -3.801662 -2.995263 -2.222035 0.632571 0.784313 0.168208 -0.122810 -0.055372 -0.002033 0.000000 -0.475472 -2.924744 0.259818 2.105466 2.090349 -0.001269 -1.732765 -3.229014 -8.088886 4.871786 6.041487 -11.098333 -6.655210 -4.320959 -3.875708 -2.243362 -1.219295 -3.519844 -3.972644 -0.858597 -0.004511 0.000000 -1.458491 -7.666026 0.367222 5.557261 0.957849 -4.914664 -6.060272 -10.882491 -17.727533 -0.161338 -1.156690 -11.014524 -4.381505 -5.912910 -4.877159 -4.686388 -5.502431 -11.881479 -12.350725 -3.785681 -0.071299 0.000000 -1.532410 -8.439904 -6.541959 -0.817615 -4.429694 -11.418231 -1.999430 -8.858995 -17.025808 5.448756 -3.307491 -18.088726 -3.806309 -8.022111 -8.789608 2.132454 2.815628 -10.432590 -12.315763 -5.502008 -0.200964 0.000000 -2.061145 -12.112046 -5.343407 8.221372 11.651610 -14.472595 -3.749081 -9.212508 -15.631208 5.799757 0.688509 -21.163956 -5.726954 -6.975798 -11.884830 18.048151 25.151751 -10.065563 -15.862930 -3.357100 0.167028 0.000000 -2.770515 -23.018545 -9.403024 6.826183 -0.398920 -15.027747 -8.051941 -5.209569 -6.560703 2.581149 -1.712808 -20.995134 -9.241560 -1.600111 -2.124490 6.397590 7.505457 -10.171129 -13.158017 4.153696 0.565915 0.000000 -1.150975 -19.788855 -25.478157 5.958390 8.959245 -2.319815 -2.277219 5.520442 3.994164 8.961635 4.607013 -14.335286 -6.673472 2.954261 1.704825 -3.035800 -3.840172 -4.347048 -3.702161 3.191081 0.150589 0.000000 -0.085455 -4.805636 -16.249979 -8.264651 1.405134 2.211643 2.171567 3.786694 2.076323 7.248565 5.092340 -1.583738 -0.053572 2.852787 0.421991 1.265756 6.171807 7.113579 0.951805 0.218374 0.002788 0.000000 -0.000251 -0.164976 -1.892449 -5.316228 -6.104975 -2.230305 -0.661207 0.696461 -0.207689 0.279220 1.034272 0.094936 0.418732 1.909932 4.129509 6.082077 3.994854 1.642467 0.182970 0.000700 0.000000 0.000000 0.000000 -0.000183 -0.022952 -0.503629 -1.205469 -0.747617 -0.411866 0.090331 0.041475 -0.112584 0.176847 -0.071620 0.164898 0.405695 1.039048 2.278528 0.915404 0.009924 0.000147 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000265 -0.021291 -0.132730 -0.343691 -0.346751 -0.057546 0.009257 -0.001366 0.040879 -0.003845 0.084399 0.427650 0.521625 0.352742 0.105965 0.001552 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000007 -0.001455 -0.022127 -0.059868 -0.019888 0.002840 0.000425 0.010476 -0.001647 0.027376 0.101725 0.052626 0.005569 0.000045 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000043 -0.000034 0.000006 0.000003 0.000012 -0.000006 0.000040 0.000096 0.000013 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000003 0.000036 0.000081 0.000026 0.000001 -0.000020 -0.000014 -0.000001 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000027 0.000477 0.002453 0.004630 0.003809 0.001203 0.000314 -0.000695 -0.001311 -0.000752 -0.000183 -0.000009 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000339 0.003977 0.011196 0.014950 0.012858 0.006793 0.002989 0.001685 -0.000101 -0.002513 -0.003922 -0.003052 -0.001235 -0.000113 -0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000002 -0.000341 0.003552 0.022422 0.021500 0.009589 0.004437 0.002896 0.002545 0.001949 0.001377 0.000819 -0.000445 -0.003445 -0.005165 -0.002182 -0.000277 -0.000002 0.000000 0.000000 0.000000 -0.000000 -0.000367 -0.009121 -0.010367 0.013004 0.007293 0.002416 0.001767 0.002290 0.002329 0.001718 0.001514 0.001630 0.001435 0.000685 -0.002356 -0.007434 -0.003858 -0.000233 -0.000000 0.000000 0.000000 -0.000048 -0.005385 -0.030024 -0.021071 0.001693 0.002818 0.001921 0.001517 0.001656 0.002049 0.001744 0.001640 0.001711 0.001962 0.001756 0.001247 -0.004247 -0.009863 -0.003298 -0.000075 0.000000 0.000000 -0.001105 -0.020216 -0.030766 -0.003797 0.003372 0.003453 0.002045 0.001754 0.001117 0.001868 0.002044 0.002191 0.002523 0.002119 0.002085 0.002773 0.001732 -0.010475 -0.012281 -0.001210 -0.000000 0.000000 -0.003933 -0.027223 -0.012563 0.003684 0.003010 0.003556 0.001423 -0.004722 -0.014733 0.027700 0.058511 0.018571 0.006467 0.003740 0.003408 0.002795 0.003472 -0.003245 -0.018786 -0.005938 -0.000038 0.000000 -0.001855 -0.008035 0.000315 0.000523 -0.029949 -0.176546 -0.405488 -0.474059 -0.459720 0.172216 0.816112 0.335157 0.279385 0.098898 0.018194 0.010982 0.005647 0.001782 -0.020556 -0.014563 -0.000419 0.000000 -0.000550 -0.011391 -0.067371 -0.317853 -0.939177 -1.348409 -0.937178 -0.260140 -0.223360 0.337825 0.468970 -1.725228 -0.713883 -0.061686 0.200992 0.436558 0.176415 0.047989 -0.006242 -0.016529 -0.000861 0.000000 -0.087119 -0.561238 -0.305252 -0.271700 0.515938 1.246573 -0.979245 -1.315998 -2.753235 0.652476 0.364993 -4.527643 -3.968266 -2.755360 -1.705578 -0.517460 0.086601 -0.129792 -0.423038 -0.144566 -0.001345 0.000000 -0.696271 -3.129676 1.407004 2.803733 2.746283 -0.825515 -4.754142 -5.557524 -8.177989 -0.960079 -2.679724 -4.004813 -3.134236 -5.308018 -2.445292 -2.578752 -2.257370 -3.320166 -3.980402 -1.280180 -0.028521 0.000000 -1.716549 -7.803995 0.886610 6.191083 3.894143 -5.129673 -3.752018 -4.629589 -8.618211 2.480559 -3.389318 -9.789497 -2.725237 -6.868302 -2.071920 2.211718 2.094867 -5.468721 -8.600200 -2.349468 -0.063477 0.000000 -2.382173 -13.710564 -2.290957 13.571347 11.840096 -4.207357 -4.889450 -5.412734 -7.513553 3.573602 0.686404 -10.780961 -3.167701 -4.614436 -2.327654 10.676297 13.741268 -3.896926 -10.757886 -0.823163 0.136776 0.000000 -2.082578 -17.233612 -9.351544 4.368808 3.395102 -2.938856 -4.931214 -3.917229 -4.157233 2.377048 1.024605 -9.291064 -4.659127 1.672943 0.845725 3.126927 5.503785 -1.875571 -4.759000 1.574187 0.196975 0.000000 -0.552911 -8.445257 -10.663756 0.542405 1.391388 -0.908473 -1.363480 2.755912 2.396029 2.778400 0.274334 -5.708061 -0.965847 2.595315 0.578950 -0.219237 1.161214 0.790245 -0.836727 0.504175 0.031771 0.000000 -0.025340 -1.353827 -5.140883 -3.944243 -1.650198 -1.367733 -0.349902 1.319901 0.837784 2.335448 1.404237 0.022558 1.544237 1.764450 1.749773 3.150844 4.215977 2.722144 0.354465 0.014951 0.000279 0.000000 -0.000042 -0.025369 -0.390347 -1.527196 -2.447306 -1.876401 -1.185730 -0.164417 -0.313402 -0.009750 0.526004 0.394099 0.931585 1.838506 2.695720 2.454077 1.036803 0.226637 0.017025 0.000034 0.000000 0.000000 0.000000 -0.000009 -0.003893 -0.192340 -0.537959 -0.342471 -0.112756 -0.016116 -0.036039 -0.010592 0.046988 0.005317 0.070975 0.186940 0.446571 0.910750 0.363974 -0.000746 0.000008 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000124 -0.010389 -0.062829 -0.145980 -0.133261 -0.025658 0.002316 0.005253 0.011912 -0.001881 0.014202 0.149052 0.219552 0.157469 0.046265 0.000657 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000003 -0.000720 -0.010060 -0.026557 -0.010136 0.001263 0.001959 0.003230 -0.000689 0.005785 0.036704 0.022017 0.002511 0.000020 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000002 -0.000021 -0.000018 0.000004 0.000005 0.000004 -0.000002 0.000012 0.000036 0.000006 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000002 0.000004 0.000001 -0.000000 -0.000001 -0.000001 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000023 0.000121 0.000223 0.000176 0.000064 0.000006 -0.000042 -0.000054 -0.000037 -0.000009 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000017 0.000192 0.000520 0.000729 0.000627 0.000320 0.000148 0.000064 0.000013 -0.000074 -0.000194 -0.000149 -0.000064 -0.000005 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000016 0.000181 0.001114 0.001024 0.000431 0.000190 0.000149 0.000124 0.000084 0.000090 0.000069 -0.000014 -0.000162 -0.000238 -0.000101 -0.000015 -0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000018 -0.000450 -0.000484 0.000653 0.000355 0.000107 0.000097 0.000139 0.000126 0.000090 0.000107 0.000086 0.000054 0.000033 -0.000091 -0.000380 -0.000193 -0.000011 -0.000000 0.000000 0.000000 -0.000002 -0.000255 -0.001461 -0.001040 0.000087 0.000154 0.000111 0.000102 0.000066 0.000089 0.000096 0.000104 0.000068 0.000065 0.000056 0.000045 -0.000210 -0.000480 -0.000163 -0.000004 0.000000 0.000000 -0.000052 -0.000958 -0.001498 -0.000170 0.000180 0.000201 0.000102 0.000083 0.000041 0.000085 0.000087 0.000110 0.000110 0.000069 0.000055 0.000143 0.000117 -0.000503 -0.000595 -0.000060 -0.000000 0.000000 -0.000184 -0.001229 -0.000485 0.000266 0.000167 0.000227 0.000160 0.000095 0.000008 0.000122 0.000432 0.000291 0.000148 0.000230 0.000225 0.000156 0.000232 -0.000093 -0.000934 -0.000299 -0.000002 0.000000 -0.000072 -0.000280 0.000116 0.000145 -0.000173 -0.001948 -0.008104 -0.017618 -0.018733 -0.007350 0.023014 0.022306 0.013597 0.004886 0.001125 0.000251 0.000303 0.000143 -0.001055 -0.000728 -0.000020 0.000000 -0.000000 -0.000155 -0.002044 -0.010422 -0.034258 -0.033574 -0.018178 -0.022656 -0.019312 -0.028230 -0.022749 -0.057400 -0.014509 0.005594 0.014950 0.016281 0.006081 0.001192 -0.000644 -0.000823 -0.000042 0.000000 -0.002147 -0.028053 -0.048311 -0.045077 0.005399 0.111215 0.009815 -0.045317 -0.124460 -0.030510 -0.096309 -0.258925 -0.228926 -0.221191 -0.128855 -0.028183 0.023099 0.018659 0.009445 0.000165 -0.000019 0.000000 -0.041993 -0.261406 -0.047895 0.129552 0.181588 0.056569 -0.183935 -0.306583 -0.458436 -0.102859 -0.280560 -0.184099 -0.181972 -0.441492 -0.247510 -0.177290 -0.131342 -0.112898 -0.005451 0.009348 -0.000043 0.000000 -0.151706 -0.772099 -0.125384 0.387389 0.182457 -0.264332 -0.223754 -0.281047 -0.536588 0.090400 -0.327965 -0.593135 -0.169160 -0.520591 -0.223057 0.135221 0.095029 -0.366650 -0.218088 0.085173 0.003849 0.000000 -0.207638 -1.294069 -0.442889 0.852718 0.557971 -0.251043 -0.442478 -0.371867 -0.464445 0.237032 0.005840 -0.655954 -0.159355 -0.221798 -0.143423 0.751882 0.864743 -0.259523 -0.319476 0.199377 0.011071 0.000000 -0.133497 -1.188824 -0.788532 0.203884 0.214142 -0.068788 -0.371019 -0.330396 -0.336003 0.160864 0.084378 -0.504305 -0.239145 0.333987 0.118750 0.242417 0.451812 0.000326 0.013128 0.144345 0.004897 0.000000 -0.021664 -0.339845 -0.501326 -0.137933 -0.013437 -0.046504 -0.103712 0.088427 0.083113 0.084771 -0.067560 -0.337999 -0.002693 0.166388 0.050778 0.067653 0.268798 0.147696 0.011721 0.015261 0.000287 0.000000 -0.000449 -0.029092 -0.157300 -0.222543 -0.170374 -0.121218 -0.065391 0.043379 0.033582 0.112687 0.038162 -0.031695 0.125313 0.136691 0.191889 0.282441 0.274722 0.104046 0.006295 0.000017 0.000000 0.000000 -0.000000 -0.000252 -0.007829 -0.051485 -0.112683 -0.121161 -0.101904 -0.024863 -0.022486 -0.021028 0.023025 0.040714 0.103582 0.155538 0.174874 0.129575 0.038744 0.002760 0.000029 -0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000163 -0.010066 -0.027140 -0.019461 -0.009989 -0.001665 -0.002823 -0.002894 0.000487 0.003367 0.011691 0.012080 0.021787 0.050282 0.021004 -0.000086 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000007 -0.000626 -0.003536 -0.007553 -0.006762 -0.001399 0.000297 0.000788 0.000375 0.000004 0.000088 0.006820 0.012015 0.008835 0.002551 0.000036 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000040 -0.000527 -0.001449 -0.000592 0.000132 0.000277 0.000084 -0.000012 0.000092 0.001689 0.001185 0.000143 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000001 -0.000001 0.000000 0.000001 0.000000 -0.000000 0.000000 0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000002 0.000025 0.000028 0.000003 0.000002 0.000024 0.000019 0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000009 0.000176 0.000889 0.001939 0.001184 0.000014 0.000018 0.000947 0.001273 0.000515 0.000097 0.000006 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000051 0.000775 0.002703 0.004163 0.003904 0.001347 -0.000365 -0.000276 0.001056 0.002158 0.001945 0.001365 0.000445 0.000035 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000048 0.000359 0.003127 0.003522 0.001556 0.000078 -0.000438 -0.000496 -0.000360 -0.000269 -0.000089 0.000457 0.001598 0.001624 0.000452 0.000030 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000048 -0.001166 -0.001717 0.000929 -0.000472 -0.011396 -0.036240 -0.056204 -0.054127 -0.014798 0.010878 0.016141 0.004201 0.000123 0.000565 0.000907 0.000449 0.000025 0.000000 0.000000 0.000000 -0.000006 -0.000675 -0.003868 -0.003684 -0.028055 -0.152450 -0.226605 0.041862 0.450719 0.712197 0.920226 0.981715 0.971845 0.641009 0.155183 0.007130 0.000545 0.000987 0.000175 0.000002 0.000000 0.000000 -0.000117 -0.002356 -0.004270 -0.043283 -0.261541 0.027657 0.828664 1.427372 1.683864 1.728745 1.864400 2.101983 2.543144 2.630039 1.390676 0.313158 0.019576 0.000641 0.000567 0.000048 0.000000 0.000000 -0.000380 -0.003295 -0.021424 -0.128678 -0.009029 0.908520 1.321477 0.642846 0.360541 0.396233 0.781605 0.820186 1.058829 1.582314 2.080766 1.495264 0.305935 0.006578 0.000483 0.000092 0.000000 0.000000 -0.000233 -0.006737 -0.249208 -0.245426 0.199232 0.175168 2.132366 0.920585 0.968781 0.816445 2.181876 2.230852 2.090906 1.087700 0.850934 1.585040 0.914851 0.091302 -0.000053 0.000109 0.000006 0.000000 -0.000067 -0.040488 -0.528481 -0.191311 0.122638 1.060960 2.705246 1.110743 1.824754 0.855479 1.260714 1.144718 1.448412 1.187700 0.202654 0.650645 1.057452 0.216711 0.000089 0.000125 0.000011 0.000000 -0.000020 -0.068752 -0.377934 0.014270 0.090804 0.655062 1.049206 0.812655 1.330939 1.291589 2.353114 1.986067 1.181808 0.597108 0.038050 0.162983 0.480949 0.111583 -0.001601 -0.000233 -0.000005 0.000000 -0.000096 -0.044151 -0.168911 -0.017795 -0.110262 -0.034958 0.016307 0.047042 0.083719 0.270673 0.796761 1.687840 1.729638 0.523604 -0.024770 0.034647 0.114839 0.020163 -0.002243 -0.000712 -0.000030 0.000000 0.000046 0.005605 0.039559 0.026154 0.001023 -0.062499 -0.032332 -0.007274 -0.103565 0.039149 0.129848 0.131842 0.214899 -0.068373 -0.069415 -0.021848 -0.048513 -0.002913 -0.001153 -0.001236 -0.000059 0.000000 0.000294 0.049999 0.373528 0.343566 0.040928 -0.175586 -0.157903 -0.032728 -0.286061 -0.567865 -0.691648 -0.057916 -0.095650 -0.026602 0.005342 -0.152687 -0.129822 0.087956 0.001104 -0.001251 -0.000031 0.000000 0.000235 0.039301 0.587326 1.278044 0.688614 0.102211 -0.047148 -0.064556 -0.168075 -0.628911 -0.876911 -0.196171 -0.116369 -0.055384 -0.081792 -0.339325 0.008936 0.138671 -0.001741 -0.001056 -0.000007 0.000000 0.000071 0.009086 0.320175 1.579947 2.331685 1.562362 0.700119 0.322461 0.134065 0.645156 1.240103 0.583282 0.117604 0.044216 0.306088 0.245045 0.088946 0.034821 -0.002939 -0.000383 -0.000000 0.000000 0.000004 0.000780 0.039950 0.449410 1.432088 2.048569 1.990430 1.839427 1.628096 1.797412 2.366502 2.026957 1.670308 1.558808 1.309775 0.537701 0.031506 -0.003797 -0.001394 -0.000040 -0.000000 0.000000 0.000000 0.000050 0.001603 -0.022772 -0.029940 0.284064 0.476296 0.523780 0.421767 0.290900 0.422845 0.627714 0.646365 0.477818 0.239629 0.106469 0.011700 -0.003990 -0.000177 -0.000000 0.000000 0.000000 0.000000 0.000001 0.000117 -0.015632 0.008687 0.125793 0.032225 -0.001111 -0.001779 0.013990 0.018617 0.000317 -0.012579 0.006360 0.092108 0.163751 0.041440 -0.000694 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000005 0.002826 0.032941 0.064299 0.042024 0.005769 0.004449 0.025090 0.038309 0.029053 0.017850 0.054676 0.069373 0.043981 0.007503 0.000041 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000206 0.002717 0.006043 -0.000994 -0.002010 0.004637 0.010004 0.007639 0.003418 0.010048 0.005430 0.000506 0.000005 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000005 -0.000002 -0.000004 0.000008 0.000019 0.000014 0.000005 0.000008 0.000001 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000024 0.000249 0.000284 0.000033 0.000027 0.000270 0.000209 0.000017 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000092 0.001813 0.009007 0.018899 0.011570 0.000468 0.000459 0.010372 0.013488 0.005491 0.001071 0.000061 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000532 0.007943 0.028035 0.042816 0.038618 0.013932 -0.002210 -0.001794 0.012239 0.024033 0.021884 0.014729 0.004582 0.000344 0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000003 -0.000473 0.003971 0.033093 0.036908 0.016101 0.002331 -0.002448 -0.003868 -0.003428 -0.002381 0.000426 0.005980 0.016532 0.016336 0.004718 0.000298 0.000001 0.000000 0.000000 0.000000 -0.000000 -0.000475 -0.011502 -0.016074 0.010815 -0.009793 -0.140244 -0.457221 -0.802373 -0.891507 -0.624842 -0.242201 0.020762 0.014907 0.000090 0.005348 0.008364 0.003745 0.000225 0.000000 0.000000 0.000000 -0.000056 -0.006423 -0.037762 -0.038328 -0.325561 -1.741410 -2.825458 -1.356542 1.284508 3.073527 4.075865 5.092721 5.665591 3.747885 1.041490 0.068114 0.004108 0.008776 0.001914 0.000022 0.000000 0.000000 -0.001082 -0.022495 -0.041338 -0.490521 -2.959878 -0.878525 6.168744 11.413188 13.592269 14.209538 14.646764 16.033390 18.494387 18.597752 11.033946 2.847511 0.179498 0.005603 0.005076 0.000378 0.000000 0.000000 -0.003720 -0.031467 -0.196372 -1.409322 -0.535034 7.398693 9.434914 5.126222 3.116459 2.915485 4.430013 4.342112 7.415325 12.913298 17.358234 12.241953 2.720836 0.081367 0.004486 0.000925 0.000004 0.000000 -0.002235 -0.062312 -2.279947 -2.188375 2.150398 0.775910 14.331537 6.431481 7.934645 4.626954 12.457868 13.945103 14.015552 8.662406 7.273564 13.041177 7.743386 0.683707 0.000069 0.001381 0.000045 0.000000 -0.000362 -0.373851 -4.683965 -1.341744 1.386555 7.048184 20.670099 8.609478 15.187311 4.795880 7.736963 9.838627 12.239566 10.998853 2.611932 5.309107 7.528644 1.173763 -0.010693 0.000958 0.000084 0.000000 -0.000136 -0.644534 -3.291758 0.083362 0.506157 5.569790 9.289035 8.126019 12.086302 8.247061 15.333769 12.731344 5.432539 3.563675 -0.107649 0.977859 3.562042 0.572261 -0.042482 -0.001549 -0.000021 0.000000 -0.000875 -0.412937 -1.356084 0.078716 -0.492949 -0.118957 0.212426 0.699666 0.964919 1.701703 5.725142 13.955617 13.386705 4.772470 -0.099534 0.288023 1.109124 0.099086 -0.049015 -0.005514 -0.000231 0.000000 0.000555 0.029692 0.223089 0.030174 -0.606336 -0.557536 -0.191383 -0.051292 -0.701688 0.448046 1.475441 2.416358 3.584489 0.478166 -0.333651 -0.135916 -0.344313 0.062624 -0.004781 -0.011400 -0.000541 0.000000 0.002472 0.451385 2.784564 1.971849 0.087174 -1.328482 -1.750175 -0.554684 -2.113825 -3.793999 -4.007782 -0.761349 -0.936480 -0.155231 0.111070 -1.202166 -1.062104 1.056352 0.043135 -0.013962 -0.000376 0.000000 0.001840 0.368831 4.754485 9.083756 4.455541 0.175177 -1.428089 -1.307103 -2.480226 -7.286844 -7.888304 -2.230945 -1.258428 -0.540336 -0.849572 -2.991030 -0.003835 1.471385 0.003728 -0.010651 -0.000090 0.000000 0.000592 0.088716 2.848052 12.613854 16.448811 8.977736 2.717902 -0.176086 -0.762051 2.821279 7.358000 2.293706 -1.239381 -1.918058 0.549182 1.311097 0.957364 0.415791 -0.031291 -0.004055 -0.000003 0.000000 0.000040 0.007448 0.399861 4.113739 11.935325 15.902630 15.012955 13.590354 13.212342 15.740519 19.384705 15.177180 12.166630 11.881773 10.968204 4.932865 0.358922 -0.031271 -0.015293 -0.000509 -0.000000 0.000000 0.000000 0.000451 0.015953 -0.136145 0.047687 2.996538 4.788364 5.262280 4.325266 3.114393 4.337863 6.033972 6.194903 5.028197 2.599251 1.069782 0.113628 -0.038914 -0.001691 -0.000004 0.000000 0.000000 0.000000 0.000006 0.001179 -0.083765 0.307244 1.342317 0.575919 0.272671 0.174158 0.213943 0.374281 0.431876 0.345239 0.346248 0.772050 1.444510 0.387530 -0.006742 -0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000050 0.028924 0.318245 0.622914 0.412369 0.048995 0.034062 0.248658 0.356863 0.276230 0.189408 0.517722 0.621406 0.392137 0.068489 0.000369 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000009 0.001976 0.026153 0.059161 -0.009927 -0.017355 0.054239 0.095650 0.068605 0.033446 0.095885 0.050359 0.004655 0.000044 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000006 0.000049 -0.000017 -0.000030 0.000093 0.000176 0.000124 0.000044 0.000073 0.000011 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000042 0.000450 0.000531 0.000056 0.000052 0.000519 0.000397 0.000031 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000168 0.003266 0.016232 0.034037 0.021110 0.000728 0.000962 0.018691 0.024267 0.010542 0.002131 0.000115 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 0.001021 0.015150 0.051879 0.077816 0.071013 0.026651 -0.003655 -0.003082 0.020133 0.043374 0.044401 0.028274 0.008399 0.000612 0.000004 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000868 0.007613 0.063952 0.070604 0.030219 0.007213 -0.002060 -0.006584 -0.007204 -0.005949 0.000024 0.013270 0.030190 0.029159 0.008582 0.000524 0.000002 0.000000 0.000000 0.000000 -0.000000 -0.000845 -0.020531 -0.028517 0.021560 -0.024353 -0.264929 -0.992190 -1.861840 -1.756527 -1.559893 -1.015138 -0.292978 -0.042590 -0.002238 0.010579 0.014119 0.005826 0.000389 0.000000 0.000000 0.000000 -0.000097 -0.011578 -0.068348 -0.074784 -0.651147 -3.615222 -5.820771 -5.255847 -3.461943 1.614334 2.185691 2.144578 2.564543 1.632680 0.633353 0.056126 0.004091 0.013106 0.003251 0.000037 0.000000 0.000000 -0.001900 -0.040563 -0.075491 -1.087194 -5.695336 -2.562068 8.342375 16.789551 19.437510 21.843468 22.011101 20.360085 20.111401 19.297419 11.249513 2.848606 0.143794 0.005899 0.007762 0.000610 0.000000 0.000000 -0.006668 -0.056136 -0.348427 -3.062597 -1.224183 12.632011 11.960506 7.496669 4.929106 3.964931 3.832336 2.032051 7.404892 17.983290 22.322083 13.984162 2.880302 0.078919 0.008000 0.001912 0.000008 0.000000 -0.004500 -0.116356 -3.994188 -3.842433 4.365724 1.153791 10.303983 5.085012 9.292148 2.913059 4.764986 8.869644 10.886167 9.055735 9.977615 17.415039 8.849259 0.402158 -0.001336 0.003190 0.000069 0.000000 -0.000819 -0.686630 -7.697710 -1.191001 2.825325 4.316684 17.326693 7.789696 17.838161 2.576032 0.531691 13.405724 20.031946 18.846367 7.308063 8.339231 8.574142 0.703287 -0.050801 0.002158 0.000156 0.000000 -0.000571 -1.228870 -5.060807 1.103183 0.556587 5.434291 9.712077 11.165966 15.031479 5.260305 9.808667 8.771891 0.979248 4.292377 1.928548 2.257275 5.263280 0.266675 -0.226947 -0.001089 0.000040 0.000000 -0.001932 -0.907367 -2.228521 -0.542050 -0.951285 0.013325 0.323317 1.313082 1.467760 0.797445 5.728318 18.198997 16.299307 6.758914 -0.673468 0.461773 1.946436 -0.198176 -0.218538 -0.007474 -0.000339 0.000000 -0.000147 0.023547 0.132942 -0.411036 -1.557426 -0.734822 -0.111978 -0.080933 -0.953161 0.763379 3.342472 7.030360 11.523208 5.235408 -0.156349 -0.176173 -0.399650 0.115111 -0.014772 -0.021156 -0.001072 0.000000 0.003352 0.874860 3.604953 0.624686 -1.196826 -1.778407 -2.076654 -1.377659 -2.825085 -3.009363 -2.220730 -1.121011 -1.153647 -0.634549 -0.404312 -1.551351 -1.634866 2.132470 0.154971 -0.028107 -0.000822 0.000000 0.002516 0.697511 6.789613 8.271722 1.894067 -1.504863 -3.216180 -4.129146 -5.256813 -11.315932 -11.946608 -5.926146 -2.732007 -1.149690 -1.534989 -4.620692 -0.342158 3.402173 0.101801 -0.020382 -0.000195 0.000000 0.000863 0.179143 4.928742 16.826899 15.350801 4.306099 -0.613063 -5.909789 -7.221676 -2.568828 3.258513 -1.769917 -4.349388 -7.112833 -3.860571 -0.024115 1.814708 1.098866 -0.050836 -0.007947 -0.000007 0.000000 0.000070 0.013860 0.877237 7.659632 18.533739 22.055494 20.107346 15.849503 16.619038 22.591373 26.054073 19.764208 15.948402 14.588161 16.395601 9.135592 0.982150 -0.023297 -0.029926 -0.001079 -0.000000 0.000000 0.000000 0.000706 0.030925 -0.000351 1.111961 6.211261 8.474996 8.920892 7.704130 6.071208 7.619912 9.737807 10.066466 9.461605 6.316182 2.271737 0.175449 -0.070385 -0.002919 -0.000009 0.000000 0.000000 0.000000 0.000008 0.001830 -0.015164 1.022152 2.761766 1.350371 0.759294 0.737963 0.782270 0.987296 0.840311 0.683247 1.009141 1.443805 2.121135 0.589093 -0.012675 -0.000008 0.000000 0.000000 0.000000 0.000000 0.000000 0.000082 0.055252 0.565904 1.125850 0.757929 0.095734 0.068402 0.477460 0.615394 0.462897 0.336757 0.901220 1.038251 0.621553 0.107948 0.000586 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000014 0.003531 0.047638 0.108410 -0.011821 -0.024126 0.118655 0.167420 0.114892 0.062337 0.167555 0.087191 0.008095 0.000074 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000011 0.000088 -0.000022 -0.000039 0.000212 0.000307 0.000207 0.000084 0.000128 0.000018 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000037 0.000432 0.000538 0.000056 0.000054 0.000499 0.000404 0.000032 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000161 0.002949 0.014735 0.031927 0.020479 0.000667 0.000758 0.017099 0.022569 0.009626 0.001875 0.000101 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 0.000957 0.014437 0.048470 0.071093 0.066163 0.025160 -0.004086 -0.004635 0.016118 0.038079 0.038586 0.023990 0.007100 0.000566 0.000003 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000815 0.006765 0.058898 0.065158 0.026988 0.005705 -0.002506 -0.006956 -0.008997 -0.006580 -0.003105 0.007157 0.022460 0.025801 0.008593 0.000576 0.000002 0.000000 0.000000 0.000000 -0.000000 -0.000776 -0.019010 -0.027473 0.018784 -0.018849 -0.212891 -1.010065 -2.022605 -1.595125 -1.549186 -1.114078 -0.503791 -0.122049 -0.007049 0.011870 0.014918 0.005024 0.000288 0.000000 0.000000 0.000000 -0.000091 -0.010535 -0.062094 -0.074312 -0.718319 -3.964119 -5.791582 -7.103628 -7.082057 0.956430 1.605038 0.349950 -1.349556 -1.213254 0.023165 -0.005620 -0.000141 0.007600 0.002069 0.000025 0.000000 0.000000 -0.001813 -0.037917 -0.070529 -1.276006 -5.885847 -3.890866 7.723949 15.450937 17.753782 21.401079 22.404339 20.404943 17.624792 14.728521 7.314164 0.710693 -0.152991 -0.003338 0.004396 0.000408 0.000000 0.000000 -0.006410 -0.053883 -0.372612 -3.440705 -0.043954 14.691751 12.885670 7.939735 5.027410 3.914816 3.915406 1.628487 5.986566 17.181171 19.197500 8.850508 0.189858 -0.111552 0.003305 0.001040 0.000006 0.000000 -0.004420 -0.133031 -4.287699 -4.074125 4.772267 2.615947 1.419677 0.462734 1.803004 0.304566 -1.209316 -2.274116 -1.074152 4.024784 8.938228 17.520939 5.636670 -0.352422 -0.009728 0.002479 0.000074 0.000000 -0.000530 -0.801209 -8.049473 -1.004186 2.559888 0.052696 1.573502 0.559803 3.406685 -0.509599 -4.165771 8.883379 15.916700 16.343197 6.209800 8.824671 8.817667 0.916776 -0.086299 0.003112 0.000178 0.000000 -0.000959 -1.479663 -4.997485 2.015217 0.585548 0.735514 1.344891 2.506284 3.161902 -0.440390 2.004549 8.139035 3.101376 7.816278 3.850305 2.940984 6.198703 0.666534 -0.398286 -0.000183 0.000053 0.000000 -0.002521 -1.134665 -2.262655 -0.415847 -0.773036 0.225309 0.072484 0.330120 0.268133 -0.135901 7.617568 17.310537 12.668107 6.138755 -0.322323 0.538119 2.295597 0.216969 -0.267641 -0.005622 -0.000302 0.000000 -0.000838 0.038765 0.052833 -2.105848 -2.794185 0.163321 0.315145 -0.033709 -0.710593 0.355848 3.001952 7.846322 14.274820 7.452133 -0.321309 0.102075 -0.248457 0.208112 0.047808 -0.020944 -0.001157 0.000000 0.002831 1.007042 3.182707 -1.504387 -4.250013 -1.035824 1.012074 -0.201226 -1.922753 -1.120743 -1.178960 -0.713695 0.029238 -0.532968 -1.401063 -0.834696 -2.187338 1.684046 0.295988 -0.028016 -0.000899 0.000000 0.002008 0.867503 6.665634 4.416318 -1.737324 -1.368566 -1.290797 -2.468220 -4.993808 -7.009184 -6.411030 -5.719362 -2.829423 0.420807 -0.976872 -3.885683 -1.555288 4.157149 0.299884 -0.020041 -0.000200 0.000000 0.000777 0.254731 5.713089 14.451209 7.666549 -0.804006 -3.606014 -6.447956 -9.741318 -6.984012 -1.184706 -3.796745 -4.592677 -7.749731 -6.941140 -2.642365 1.517820 1.804974 -0.010947 -0.007900 -0.000006 0.000000 0.000067 0.019144 1.299136 9.544479 19.290760 19.350285 15.874272 12.731790 12.221085 18.708569 21.302294 16.144943 11.932228 9.003490 14.118158 10.705697 1.748820 0.063201 -0.028701 -0.001079 -0.000000 0.000000 0.000000 0.000594 0.038938 0.242729 2.356449 7.734627 9.978429 10.456886 8.535032 6.222206 7.906436 10.648022 11.123086 10.344309 9.090714 3.721694 0.185732 -0.077962 -0.002866 -0.000009 0.000000 0.000000 0.000000 0.000007 0.000701 -0.048107 1.151567 2.791401 0.750276 0.056010 0.471452 0.803711 0.626930 -0.081156 -0.341478 0.400052 1.695131 1.922812 0.443680 -0.015361 -0.000014 0.000000 0.000000 0.000000 0.000000 0.000000 0.000049 0.051500 0.545089 1.110464 0.748807 0.069424 0.054148 0.462364 0.559249 0.364899 0.225674 0.810885 1.009495 0.567502 0.093127 0.000513 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000013 0.003459 0.048980 0.112585 -0.003702 -0.021973 0.113209 0.153607 0.100027 0.048801 0.155976 0.086058 0.008069 0.000070 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000011 0.000093 -0.000011 -0.000045 0.000198 0.000278 0.000179 0.000062 0.000112 0.000018 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000035 0.000439 0.000547 0.000070 0.000062 0.000463 0.000387 0.000031 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000161 0.003043 0.013868 0.029957 0.020533 0.001196 0.000761 0.015665 0.022325 0.009600 0.001733 0.000094 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000874 0.013324 0.047064 0.068807 0.060852 0.025416 -0.002269 -0.005673 0.013339 0.038355 0.037216 0.021781 0.006350 0.000600 0.000004 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000766 0.006594 0.053726 0.058099 0.024455 0.003896 -0.004442 -0.006317 -0.008634 -0.007157 -0.003042 0.003818 0.016942 0.025031 0.009669 0.000608 0.000001 0.000000 0.000000 0.000000 -0.000000 -0.000710 -0.017472 -0.024759 0.016264 -0.016194 -0.165725 -0.815039 -1.892696 -1.627096 -1.427294 -1.100878 -0.461055 -0.138889 -0.012543 0.011888 0.016769 0.004516 0.000222 0.000000 0.000000 0.000000 -0.000085 -0.009865 -0.055699 -0.070971 -0.816603 -3.991175 -5.460490 -6.779666 -8.048296 -1.056646 0.448313 -0.689636 -1.266515 -2.279783 -0.176841 0.009421 0.001874 0.007911 0.002100 0.000024 0.000000 0.000000 -0.001703 -0.035753 -0.065283 -1.357622 -6.523723 -5.586180 7.057662 15.058543 17.629068 21.495522 22.676600 22.077330 19.819042 13.534120 8.206342 1.684082 -0.037651 -0.001899 0.004671 0.000355 0.000000 0.000000 -0.006202 -0.052252 -0.377873 -3.386103 1.596386 15.455010 13.463977 8.603987 5.643276 4.532367 4.904423 5.646681 9.646791 17.603605 21.066767 11.649881 0.788930 -0.141940 0.001889 0.000564 0.000005 0.000000 -0.004558 -0.141775 -4.513861 -3.984690 6.893849 3.723926 0.606036 0.015781 -0.036841 -0.044708 -0.192487 -2.269042 -2.763049 1.764154 7.644547 17.954103 6.429139 -0.444856 -0.020190 0.001874 0.000064 0.000000 -0.000567 -0.863708 -8.879752 -1.966393 3.385211 0.313846 -0.012326 -0.057226 -0.057566 -0.600087 0.700560 4.071499 2.387978 5.208319 0.736149 6.856173 10.285082 1.436557 -0.102422 0.001634 0.000096 0.000000 -0.001019 -1.583244 -5.519896 0.530722 1.534922 1.085410 0.055643 0.003298 -0.016217 -1.637577 4.277052 13.082205 4.122927 4.858601 0.248092 2.281006 8.079125 2.015732 -0.435122 -0.002204 -0.000047 0.000000 -0.002612 -1.103769 -2.001178 -0.243042 2.798064 3.323246 0.517807 -0.001476 -0.047984 0.187754 10.932671 15.337217 9.099879 3.389987 -3.750640 -0.110604 3.487589 1.282801 -0.204636 -0.006607 -0.000341 0.000000 -0.000792 -0.033365 0.003867 -0.268558 3.257802 7.230304 3.868331 0.792045 -0.304698 -0.621269 -0.360998 3.439744 6.509211 2.690953 -2.542040 0.568923 0.309096 0.471416 0.145701 -0.020481 -0.001208 0.000000 0.002550 0.888684 2.956284 -0.057043 1.723823 9.823494 12.157243 6.113454 0.219350 0.690203 -3.634082 -1.301717 3.284651 3.188251 0.751650 1.705524 -2.483047 0.744526 0.447680 -0.027398 -0.000934 0.000000 0.002542 1.035922 6.628100 3.354650 3.074302 12.511836 12.218411 4.842052 -3.834256 -1.004732 -4.228710 -5.078363 3.406265 7.425529 0.998407 -2.333671 -3.233993 3.421491 0.517549 -0.019802 -0.000212 0.000000 0.000928 0.360916 6.438574 13.023058 5.729748 2.005514 -0.051875 -3.876439 -9.628922 -9.060297 -5.581090 -4.572040 -0.845706 -2.294967 -6.763170 -3.926054 0.425923 2.311651 0.074755 -0.007587 -0.000007 0.000000 0.000067 0.032215 1.845318 11.343290 19.557205 15.535522 9.692485 8.626494 8.945125 15.672187 18.283278 12.587649 6.466231 5.009264 10.474300 11.876935 2.745695 0.197502 -0.024016 -0.001028 -0.000000 0.000000 0.000001 0.000644 0.064497 0.739413 4.049673 9.998899 13.009770 13.460949 11.126062 8.262547 10.506539 14.232392 14.571792 12.707111 10.778288 5.718786 0.380077 -0.090477 -0.002950 -0.000008 0.000000 0.000000 0.000000 0.000006 -0.000010 -0.048786 1.251309 2.265348 0.135914 -0.509645 -0.358398 -0.069404 -0.214980 -0.438024 -0.470833 -0.206978 1.267446 1.911788 0.329167 -0.018955 -0.000022 0.000000 0.000000 0.000000 0.000000 0.000000 0.000018 0.044213 0.499644 1.045501 0.771060 0.047218 0.005788 0.367205 0.475098 0.312727 0.190756 0.794933 0.968548 0.511076 0.075846 0.000419 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000011 0.003288 0.051088 0.125064 0.000408 -0.019419 0.099288 0.145767 0.098647 0.049957 0.164780 0.086695 0.007817 0.000066 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000011 0.000091 -0.000017 -0.000045 0.000172 0.000267 0.000178 0.000056 0.000115 0.000018 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000042 0.000497 0.000595 0.000056 0.000042 0.000449 0.000382 0.000031 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000178 0.003322 0.015588 0.034322 0.023020 0.000681 -0.000201 0.015996 0.023699 0.010632 0.002116 0.000113 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000969 0.014745 0.051895 0.076208 0.069871 0.028812 -0.003139 -0.005611 0.015781 0.043032 0.044284 0.028340 0.008010 0.000683 0.000005 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000849 0.007241 0.059703 0.064806 0.026893 0.003355 -0.005645 -0.006307 -0.005898 -0.007693 -0.000126 0.010643 0.028227 0.029997 0.010623 0.000680 0.000002 0.000000 0.000000 0.000000 -0.000000 -0.000780 -0.019231 -0.028088 0.016462 -0.011539 -0.144584 -0.730284 -1.558008 -1.529568 -1.321627 -0.929674 -0.402757 -0.111826 -0.008498 0.012694 0.020494 0.006710 0.000322 0.000000 0.000000 0.000000 -0.000099 -0.011161 -0.061679 -0.073009 -0.764645 -3.711880 -5.192923 -7.505895 -8.761989 -3.128923 -1.630719 -1.624606 -1.974499 -2.172727 0.237536 0.087721 0.008082 0.013608 0.003033 0.000031 0.000000 0.000000 -0.001844 -0.040573 -0.073623 -1.365862 -6.595655 -5.728265 6.822581 14.387998 16.722551 21.192282 21.712391 21.205854 18.663750 14.901629 13.705291 4.772799 0.439090 0.010741 0.008246 0.000687 0.000000 0.000000 -0.006464 -0.055281 -0.421527 -3.540961 2.152884 15.466787 13.778258 9.626555 6.668400 5.604736 5.720559 7.337556 11.449268 18.740778 24.251541 19.698488 5.529479 0.221312 0.010637 0.002351 0.000009 0.000000 -0.004827 -0.140007 -5.098173 -5.859725 10.190269 4.696476 0.642727 0.055424 -0.022436 -0.130252 -0.345984 -0.170230 0.046123 0.702044 2.888792 18.912348 13.558049 0.990235 -0.014413 0.004733 0.000121 0.000000 -0.000868 -0.891687 -10.142651 -3.242081 8.236934 1.618132 -0.009506 -0.033951 -0.047181 -0.266615 -0.065921 0.643549 -0.396181 -0.548856 -2.393715 6.776269 12.621758 1.736669 -0.180644 0.004316 0.000257 0.000000 -0.001300 -1.625860 -5.704117 2.182266 5.212242 2.905287 0.217427 -0.043195 -0.044417 -0.769311 0.525841 3.629678 0.148455 -0.979883 -2.171617 2.287743 9.870200 2.501020 -0.534432 -0.003436 -0.000025 0.000000 -0.002762 -1.086976 -1.846182 1.170238 6.253873 6.379158 2.004388 0.200399 0.000049 -0.362126 2.446011 3.474939 0.675839 -1.325838 -2.730676 2.839341 7.040889 2.435303 -0.163000 -0.009075 -0.000443 0.000000 -0.001727 -0.160217 -0.297988 1.929133 9.425887 10.106194 8.230620 4.011147 1.614734 -0.041300 -0.892244 1.218371 0.902664 -0.385687 -2.869972 3.868597 2.652458 0.839593 0.214603 -0.020801 -0.001442 0.000000 0.002019 0.672091 1.809053 0.271920 8.105854 10.633082 14.376450 14.596473 6.416340 2.200407 -0.179970 1.752179 7.098897 0.889598 -1.390384 3.663205 -1.636133 0.013261 0.567837 -0.024087 -0.001014 0.000000 0.003404 1.173940 5.914593 1.296414 5.331867 15.336273 15.639291 9.583613 -0.757918 -2.552467 -3.113504 1.267079 9.021726 1.889743 1.443345 -0.258406 -3.962326 2.260009 0.766922 -0.018895 -0.000227 0.000000 0.001260 0.550181 7.458776 11.549915 4.207062 6.109117 8.288603 1.456182 -8.503709 -11.601584 -8.771459 -2.052364 7.874929 1.349371 -5.667514 -5.046984 -0.903368 2.848835 0.265106 -0.007510 -0.000007 0.000000 0.000082 0.068256 2.773477 13.290992 18.920395 13.768648 7.616503 5.147351 5.108811 11.546158 14.078765 7.939306 3.808564 2.340108 5.189035 10.967114 3.734969 0.458721 -0.010758 -0.001031 -0.000000 0.000000 0.000001 0.001115 0.134031 1.710956 6.809943 13.162086 15.931493 16.244068 14.622237 11.910964 13.582211 16.503653 16.978434 15.994157 12.471958 7.456438 0.736738 -0.102344 -0.003479 -0.000008 0.000000 0.000000 0.000000 0.000008 -0.000171 0.041608 1.453133 2.046820 0.445750 0.012952 -0.316784 -0.819194 -0.610324 0.017857 0.320543 0.413002 0.880798 1.635352 0.260443 -0.022188 -0.000030 0.000000 0.000000 0.000000 0.000000 0.000000 0.000003 0.038826 0.452216 1.004162 0.838651 0.069942 -0.010584 0.306572 0.383206 0.301329 0.262580 0.962040 1.002777 0.464092 0.065255 0.000363 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000011 0.003282 0.053595 0.143516 0.008729 -0.015828 0.096208 0.126272 0.098947 0.076118 0.205069 0.096294 0.008021 0.000065 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000011 0.000093 -0.000015 -0.000040 0.000163 0.000225 0.000168 0.000097 0.000153 0.000019 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000044 0.000523 0.000645 0.000060 0.000045 0.000472 0.000388 0.000031 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000174 0.003268 0.016142 0.035669 0.024674 0.001081 0.000165 0.015635 0.022878 0.010431 0.002061 0.000105 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 0.000984 0.014902 0.051662 0.076686 0.070792 0.030191 -0.002310 -0.004013 0.014602 0.040335 0.043883 0.026944 0.007835 0.000701 0.000006 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000005 -0.000963 0.006342 0.059313 0.067165 0.026920 0.002302 -0.003936 -0.005516 -0.006105 -0.006762 -0.000545 0.011965 0.028739 0.031715 0.011716 0.000691 0.000003 0.000000 0.000000 0.000000 -0.000000 -0.000810 -0.020616 -0.031930 0.015881 -0.004959 -0.108587 -0.528930 -1.007982 -0.986445 -0.879908 -0.702830 -0.329662 -0.071156 -0.003699 0.014392 0.019439 0.006496 0.000363 0.000000 0.000000 0.000000 -0.000100 -0.012694 -0.068449 -0.076831 -0.612644 -3.059910 -4.549656 -6.342250 -7.602660 -3.718052 -2.552419 -3.371943 -3.115623 -0.243751 0.901917 0.073311 0.007318 0.015664 0.003720 0.000039 0.000000 0.000000 -0.001899 -0.045118 -0.084498 -0.900872 -4.791575 -3.707640 5.931175 14.650203 16.767626 19.262585 19.327206 19.151781 17.098885 18.899466 12.723811 3.585461 0.489566 0.020336 0.010121 0.000858 0.000000 0.000000 -0.006723 -0.056408 -0.523227 -2.325972 4.280594 12.592338 11.362988 10.186279 8.430026 6.158895 5.521672 8.860756 11.819817 12.406171 7.989668 13.435346 7.721602 0.625266 0.015615 0.003935 0.000022 0.000000 -0.005145 -0.134835 -5.612751 -10.389957 8.052111 3.467554 0.197922 0.252010 0.068404 -0.805242 -3.197079 -0.693397 0.131641 -0.847038 -1.082377 12.848046 17.264824 2.647773 -0.013377 0.007604 0.000220 0.000000 -0.001015 -0.908471 -11.294034 -6.238128 7.454525 1.292062 -0.009077 0.037027 -0.009461 -0.574592 -3.627555 -1.526084 -0.027812 -0.376624 -0.998058 5.172929 13.557281 1.930056 -0.400453 0.006086 0.000405 0.000000 -0.001714 -1.757903 -6.686909 4.011915 5.838898 2.765139 0.688933 -0.132961 -0.032652 -0.088680 -1.088827 -0.656998 -0.257773 -1.297157 -0.714901 2.104455 10.057835 2.520292 -0.669359 -0.003983 0.000061 0.000000 -0.005171 -1.252525 -1.706722 4.376537 5.149642 4.599450 3.885390 1.393200 0.759537 -0.135282 -0.574652 0.282201 1.887138 0.416556 -1.877124 -0.416179 7.112805 3.283159 0.068997 -0.008747 -0.000408 0.000000 -0.005270 -0.454251 -0.420346 3.887206 7.178352 4.787704 8.541644 9.219926 8.168434 1.795321 -2.623897 -0.064831 1.769859 0.666585 -1.755874 2.187117 4.065467 1.346367 0.252459 -0.019948 -0.001511 0.000000 0.004273 0.634812 0.979354 1.775153 8.437392 3.907715 6.338274 12.076282 11.169617 4.738270 -0.244100 3.778914 4.946348 -0.230250 -0.951790 4.005494 0.315752 -0.311088 0.593051 -0.014073 -0.001011 0.000000 0.005132 1.358389 5.326036 1.001059 3.184409 5.608045 5.292754 0.484161 -1.417607 -1.039530 0.938819 10.101439 6.601236 -0.444479 1.677810 1.003973 -3.516465 0.931456 1.017255 -0.010906 -0.000214 0.000000 0.001499 0.879252 8.906069 9.707057 1.031156 2.582846 9.504993 3.120627 -6.345439 -9.116588 -5.045985 5.900517 10.531944 4.649174 -2.812370 -5.417712 -2.384425 3.284985 0.677543 -0.005494 -0.000007 0.000000 0.000094 0.151656 4.307619 15.209915 16.884111 9.889032 5.876710 4.421554 2.353145 7.199155 12.923206 7.481606 3.614669 -0.312192 -0.117655 8.343800 4.553785 0.925943 0.050509 -0.000745 -0.000000 0.000000 0.000001 0.002559 0.300800 3.170564 10.028641 14.838602 15.046893 15.435183 16.215916 15.044260 15.686372 13.893278 11.985986 13.670505 13.536665 9.021532 1.351743 -0.066095 -0.003608 -0.000006 0.000000 0.000000 0.000000 0.000010 -0.000434 0.053339 1.532224 2.156342 0.694512 0.339022 0.108357 -0.714962 -0.639809 -0.188497 -0.082801 0.486348 0.882692 0.909095 0.070688 -0.018858 -0.000028 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000010 0.030549 0.405121 0.961819 0.834649 0.070797 -0.046399 0.244863 0.385282 0.336311 0.247999 0.863478 0.922584 0.399432 0.052749 0.000330 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000010 0.003202 0.053357 0.144893 0.008113 -0.024499 0.080492 0.128269 0.104051 0.063179 0.182481 0.092042 0.007903 0.000064 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000011 0.000096 -0.000021 -0.000067 0.000122 0.000217 0.000170 0.000075 0.000133 0.000019 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000052 0.000610 0.000754 0.000077 0.000063 0.000614 0.000497 0.000038 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000193 0.003793 0.018651 0.040024 0.027375 0.001245 0.000570 0.020411 0.028002 0.011956 0.002278 0.000116 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 0.001105 0.016950 0.060094 0.089765 0.078257 0.030995 -0.003683 -0.004144 0.019623 0.047360 0.048743 0.028316 0.008688 0.000766 0.000005 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000005 -0.001087 0.008320 0.069639 0.080906 0.034443 0.003316 -0.006044 -0.008331 -0.006714 -0.007957 -0.003095 0.011509 0.028771 0.035066 0.012927 0.000783 0.000003 0.000000 0.000000 0.000000 -0.000000 -0.000971 -0.024745 -0.034637 0.024060 -0.006145 -0.074847 -0.256459 -0.553147 -0.751836 -0.697664 -0.535363 -0.247115 -0.042676 -0.001025 0.018402 0.021991 0.006358 0.000361 0.000000 0.000000 0.000000 -0.000094 -0.014672 -0.083661 -0.125390 -0.969157 -3.276290 -4.017345 -3.740152 -5.772873 -5.643795 -5.487976 -5.855793 -3.461465 2.023053 1.443281 0.117393 0.009513 0.014869 0.003835 0.000055 0.000000 0.000000 -0.001947 -0.048270 -0.113769 -1.037646 -3.596611 0.516509 4.357543 8.702471 13.794426 16.478580 15.282827 15.575546 15.511972 18.276041 10.602695 4.881756 1.178622 0.060882 0.012998 0.001564 0.000001 0.000000 -0.007358 -0.062570 -1.028338 -4.792745 3.907618 15.363176 11.374525 6.978059 7.838291 8.145318 7.717988 11.035257 9.171528 0.576379 3.531671 16.300573 11.615383 1.374526 0.029483 0.007628 0.000048 0.000000 -0.006353 -0.154863 -6.058598 -13.811396 3.879828 3.547840 0.115413 0.164413 0.093766 -0.256950 -1.798957 -0.324290 0.075160 1.213211 7.129719 12.278446 14.803987 2.900220 -0.065019 0.011959 0.000340 0.000000 -0.001178 -0.902030 -10.321795 -6.508562 4.275865 0.467676 -0.569626 -0.139921 0.197493 -0.269871 -2.223380 -1.056512 0.210385 0.969022 1.867894 2.973394 7.133117 0.583463 -0.646357 0.009352 0.000573 0.000000 -0.002125 -1.873943 -6.565357 4.459209 4.157139 1.187788 1.305722 0.507295 0.247047 -0.313780 -2.521904 -1.294161 -0.470519 -0.831707 -0.159290 -1.617680 5.940536 2.715759 -0.394520 -0.002250 0.000145 0.000000 -0.010331 -1.666426 -2.636798 4.535111 3.949072 1.547619 4.022263 5.028211 4.346477 0.229868 -2.513717 1.353572 7.452492 1.981530 -1.535488 -4.993540 3.323937 4.141720 0.499008 -0.008593 -0.000320 0.000000 -0.009945 -0.786292 -0.944740 4.123471 6.112179 1.380894 4.374129 10.310527 13.831529 3.667709 -5.416265 -4.540621 6.132881 1.567325 -3.792342 -4.201542 3.337671 2.319016 0.287020 -0.027153 -0.001306 0.000000 0.006229 0.660187 0.932774 3.239181 10.389861 2.498928 1.273272 4.382323 6.687351 4.338288 -0.957868 -0.113022 1.196659 -0.538455 -4.341828 3.284853 2.603512 -0.075729 0.455335 -0.010018 -0.001103 0.000000 0.009659 1.648733 4.751433 1.521948 9.230616 6.953013 1.595444 -2.937066 -2.964099 -1.011475 3.131120 11.994989 4.574390 -0.819543 -1.545764 3.667472 -1.808121 -0.520698 1.024321 0.004254 -0.000313 0.000000 0.002496 1.325058 9.860154 7.257657 3.403740 9.500168 10.385694 2.517441 -4.759849 -8.310424 -2.195893 12.042020 11.444757 7.012156 0.988507 -3.728086 -3.715026 2.799113 1.241759 0.000805 -0.000019 0.000000 0.000131 0.315441 6.413677 17.141176 14.004285 9.209049 9.610546 5.845594 0.344642 5.878790 15.597863 13.275752 7.245556 -0.676377 -2.708852 4.721876 4.661128 1.495527 0.217565 0.000021 -0.000000 0.000000 0.000001 0.008290 0.697274 5.485022 12.518270 12.842256 9.716791 9.501343 12.191014 16.860798 19.612623 17.010836 8.973818 5.471635 12.064494 11.566596 2.752020 0.051209 -0.002813 -0.000001 0.000000 0.000000 0.000000 0.000013 0.001423 0.055478 1.607741 2.201868 0.333480 -0.177160 -0.089695 -0.394415 -0.367427 0.725026 0.801843 0.007957 1.010216 0.730664 -0.048015 -0.014295 -0.000017 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000019 0.025728 0.393521 0.993072 0.866195 0.109315 -0.046604 0.233077 0.427867 0.380705 0.317603 0.909598 0.913931 0.368141 0.045243 0.000346 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000011 0.003267 0.054596 0.148367 0.017732 -0.024899 0.078442 0.137459 0.108107 0.073343 0.194229 0.093489 0.008158 0.000065 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000012 0.000112 0.000006 -0.000072 0.000114 0.000229 0.000178 0.000090 0.000151 0.000020 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000002 0.000211 0.001777 0.001875 0.000193 0.000103 0.001069 0.000948 0.000100 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000422 0.009289 0.045931 0.093041 0.059101 0.004580 0.002158 0.038085 0.056636 0.027044 0.005072 0.000244 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 0.001837 0.030049 0.118766 0.195297 0.174557 0.070567 0.001011 -0.002227 0.042565 0.101756 0.104537 0.058859 0.016088 0.001284 0.000008 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000008 -0.001598 0.014663 0.119602 0.145500 0.075168 0.018996 -0.002630 -0.007126 -0.007493 -0.007634 0.003627 0.030454 0.060199 0.061901 0.021369 0.001409 0.000006 0.000000 0.000000 0.000000 -0.000000 -0.001465 -0.037712 -0.050832 0.043648 0.000067 -0.052667 -0.127182 -0.308946 -0.376798 -0.399661 -0.322259 -0.143154 -0.023470 0.003163 0.033101 0.042373 0.013177 0.000684 0.000001 0.000000 0.000000 -0.000152 -0.022461 -0.129720 -0.196133 -1.240269 -3.437057 -3.018635 -2.525203 -4.732863 -4.183627 -5.381864 -6.006353 -3.241720 2.267676 1.436273 0.168346 0.022775 0.031009 0.009187 0.000247 0.000000 0.000000 -0.003184 -0.077607 -0.181750 -1.048105 -2.435344 2.045861 7.882412 6.786955 9.784811 16.534697 15.033334 13.285333 13.744949 20.157127 16.517982 7.728981 1.788326 0.123608 0.040202 0.004997 0.000003 0.000000 -0.011316 -0.104108 -1.501653 -2.593685 7.421919 17.365864 19.178429 11.707017 7.126791 10.949520 12.413116 13.983063 9.162395 6.068769 22.109844 21.963024 13.629115 2.399908 0.081919 0.017552 0.000113 0.000000 -0.009293 -0.287682 -6.607237 -7.859197 3.283080 4.788433 3.227743 -0.146994 -1.177841 -0.028653 0.166171 0.299716 -0.346274 3.035481 13.223260 11.434707 13.965128 4.495007 -0.023480 0.023054 0.000701 0.000000 -0.001668 -1.058569 -8.518128 -1.674993 3.793324 0.387903 -0.749126 -1.905496 -0.348575 0.010882 -0.073858 -0.047199 0.474993 1.519196 2.405592 2.846891 5.099048 1.286390 -0.656363 0.016454 0.001336 0.000000 -0.004056 -1.919222 -4.817562 4.114678 2.500914 0.054161 0.350125 0.871534 0.515410 -1.315087 -1.652928 -0.268810 -1.239074 -1.007168 0.358013 -0.264089 4.049381 3.214876 -0.231999 -0.006026 0.000463 0.000000 -0.016526 -1.885520 -2.487124 3.471785 2.264590 0.121502 1.189620 4.975022 5.391797 -2.834124 -5.972916 2.279150 5.381024 -0.304211 -0.572465 -1.965322 4.331970 4.768244 0.477440 -0.025505 -0.000401 0.000000 -0.017246 -0.915499 -0.991217 2.889176 3.179018 0.158369 0.648452 4.736135 9.666878 1.678797 -6.832355 -3.381146 7.485153 0.862240 -2.442356 -4.109608 4.780073 3.789866 0.256881 -0.069314 -0.001950 0.000000 0.005344 0.370253 0.439936 1.452071 3.644918 0.743766 0.036635 0.627014 2.456103 1.460379 -0.895216 0.071432 1.032657 -0.212618 -3.751826 0.726768 4.733952 0.998907 0.167697 -0.044568 -0.001929 0.000000 0.021522 1.859312 3.578829 0.468792 5.960966 5.352157 1.032980 -2.724761 -3.947714 -4.311569 1.876841 9.797469 4.096650 -0.552632 -3.106927 2.792876 0.349215 -1.309211 0.729516 0.029931 -0.000396 0.000000 0.007453 1.910776 9.816854 4.743074 3.611026 12.395920 12.390554 0.216440 -5.788364 -13.598552 -5.154587 13.090046 11.629383 6.314520 1.778525 -2.602309 -4.288793 1.616779 1.721949 0.029617 0.000006 0.000000 0.000404 0.628964 8.825763 18.156958 13.429373 15.468987 20.022942 10.718596 1.550927 5.479670 10.842278 10.698826 8.009423 1.798949 -2.312124 0.955431 4.033533 2.347894 0.555803 0.004315 0.000000 0.000000 0.000001 0.028370 1.445719 8.641651 14.553126 14.666264 15.576221 13.383124 11.140508 19.098690 22.781044 19.193520 11.361120 4.433051 7.688603 12.979767 5.191237 0.389652 0.003869 0.000019 0.000000 0.000000 0.000000 0.000023 0.011802 0.190820 1.627002 2.609177 2.298142 1.895044 0.750666 0.370807 1.065811 4.668535 5.981128 2.418120 0.523255 0.899332 0.080445 -0.008519 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000022 0.024242 0.400781 1.070650 1.046392 0.219427 -0.024295 0.330653 0.516573 0.499730 0.552742 1.191766 1.018541 0.373740 0.046552 0.000398 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000012 0.003347 0.057488 0.181292 0.050570 -0.022682 0.104875 0.167343 0.134141 0.121213 0.251345 0.106498 0.008817 0.000070 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000012 0.000143 0.000062 -0.000060 0.000156 0.000287 0.000230 0.000160 0.000199 0.000021 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000011 0.001237 0.009950 0.010032 0.000962 0.000436 0.004288 0.004059 0.000545 0.000009 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000003 0.002020 0.046956 0.232146 0.467819 0.292194 0.024457 0.013612 0.159395 0.254278 0.137810 0.025747 0.001149 0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000006 0.007557 0.129630 0.545235 0.937739 0.849995 0.356051 0.023167 0.011291 0.205589 0.484683 0.523457 0.282294 0.069353 0.005194 0.000032 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000024 -0.006239 0.056019 0.491697 0.634588 0.357308 0.116172 0.018776 -0.005196 -0.007689 0.005963 0.059531 0.178450 0.297248 0.265969 0.089453 0.006437 0.000025 0.000000 0.000000 0.000000 -0.000000 -0.005446 -0.139030 -0.191608 0.181428 0.083483 -0.020248 -0.074810 -0.182725 -0.203959 -0.163263 -0.102864 -0.043960 -0.008326 0.032252 0.156231 0.207130 0.067024 0.003292 0.000004 0.000000 0.000000 -0.000623 -0.086852 -0.492721 -0.421485 -0.782642 -2.381548 -2.371027 -2.728984 -4.960387 -5.495468 -4.168318 -3.463502 -1.957235 0.957659 0.483811 0.072094 0.111624 0.165078 0.047777 0.001321 0.000000 0.000000 -0.012861 -0.309669 -0.598277 -1.520707 -4.736006 -3.932591 4.145424 8.075786 10.129844 9.787247 10.394891 12.029078 12.935895 15.469253 10.445538 5.186220 1.071082 0.219223 0.194610 0.023149 0.000013 0.000000 -0.044104 -0.378764 -1.069699 -0.107004 4.027554 13.242232 22.623653 20.354622 13.298422 12.641624 14.051638 17.865477 12.855885 5.424465 20.113049 24.342438 11.188553 1.891946 0.284169 0.074708 0.000544 0.000000 -0.034988 -0.568401 -5.784816 -0.036211 -0.311170 4.979749 7.748243 3.423831 -0.045039 0.273292 0.632954 0.918029 -1.751799 0.611638 13.497002 19.220724 17.136608 5.356616 0.205068 0.102826 0.003419 0.000000 -0.006320 -1.532082 -7.977879 -0.013242 -0.895742 -0.197990 -0.150328 -2.355036 -0.801564 -0.040164 -0.037495 0.008474 0.813930 2.563359 4.509376 5.569859 7.149463 2.776355 -0.579384 0.076751 0.006441 0.000000 -0.010160 -2.129606 -3.902497 1.964614 1.071865 -0.053018 -0.150781 0.372553 -0.656774 -3.141152 -0.904052 0.087864 -1.538154 -0.322542 0.645125 0.724937 2.956165 2.229443 -1.097752 -0.054159 0.002188 0.000000 -0.030600 -1.934031 -2.305104 1.409559 1.085601 -0.073204 0.096392 2.696109 3.399882 -3.398330 -3.039645 4.682657 3.431045 -0.540718 0.026726 -1.285514 2.331031 3.661723 -0.710244 -0.189534 -0.001961 0.000000 -0.039151 -1.322197 -1.019947 3.057606 2.446516 -0.001644 0.040471 2.336413 6.263894 0.215777 -4.923131 1.191693 5.870045 0.225310 -0.653844 -2.668392 3.906343 4.470062 -0.483989 -0.298615 -0.008172 0.000000 0.006822 0.151519 -0.131368 2.295305 3.572104 0.378180 0.012110 0.485539 2.613056 0.774818 -0.615802 1.868347 1.035058 -0.100153 -2.059653 -2.091435 5.232819 2.698350 -0.144352 -0.185273 -0.005732 0.000000 0.054557 2.136077 1.987372 0.124136 4.711583 3.048360 0.560236 -2.177808 -2.418948 -2.478614 1.169275 8.080873 3.708622 -1.035667 -4.357502 -0.627980 1.706372 -1.013277 0.496517 0.081616 -0.000008 0.000000 0.028038 2.885854 9.627506 2.288105 2.950772 9.456316 8.936007 -1.680157 -3.237894 -10.771647 -2.685828 14.295487 11.010190 2.247287 -0.027858 -1.371335 -3.903914 0.136886 2.063919 0.136649 0.000248 0.000000 0.002679 1.306984 12.220503 18.559608 13.231759 14.852354 14.729369 6.931899 3.028509 3.415825 4.972824 5.118113 7.211202 4.993869 -0.801441 -2.921944 2.659774 2.788716 1.010037 0.030375 0.000004 0.000000 0.000012 0.091843 2.890456 13.208794 17.212376 14.735863 14.683037 13.863488 11.900079 19.081690 22.213139 14.626876 10.538667 9.635719 5.250680 10.480411 7.833274 1.061551 0.019144 0.000267 0.000000 0.000000 0.000000 0.000122 0.051228 0.667988 2.253560 4.657322 6.528081 6.273208 2.908797 1.465725 5.105611 11.272578 13.772326 9.237275 1.631201 0.770036 0.411759 0.006265 0.000052 0.000000 0.000000 0.000000 0.000000 0.000000 0.000020 0.031082 0.521323 1.654630 2.039507 0.614384 -0.080631 0.360188 0.709700 1.025461 1.477886 2.179037 1.503182 0.518638 0.068158 0.000607 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000018 0.004750 0.089323 0.330845 0.140764 -0.048135 0.115247 0.201762 0.175873 0.241302 0.415013 0.156760 0.012826 0.000106 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000017 0.000254 0.000180 -0.000100 0.000171 0.000345 0.000293 0.000268 0.000305 0.000030 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000006 0.000656 0.005280 0.005330 0.000504 0.000239 0.002349 0.002197 0.000289 0.000005 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000002 0.001107 0.025540 0.125297 0.251243 0.156410 0.012477 0.006847 0.085925 0.136157 0.073483 0.013689 0.000606 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000003 0.004204 0.071607 0.299334 0.509590 0.457132 0.190468 0.010012 0.002814 0.108375 0.257430 0.278620 0.149200 0.037267 0.002864 0.000017 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000014 -0.003484 0.030911 0.272050 0.348226 0.193430 0.060016 0.008150 -0.005261 -0.007899 0.000023 0.028064 0.092247 0.155612 0.144459 0.049029 0.003524 0.000014 0.000000 0.000000 0.000000 -0.000000 -0.003015 -0.076832 -0.106670 0.099088 0.044472 -0.006351 -0.020365 -0.048759 -0.069105 -0.048213 -0.020870 -0.012355 -0.006509 0.015472 0.084367 0.113235 0.036939 0.001811 0.000002 0.000000 0.000000 -0.000347 -0.047770 -0.270750 -0.210978 -0.231983 -0.995819 -1.598320 -2.250575 -3.942944 -5.443700 -4.306556 -2.481287 -0.695794 0.164338 0.031784 0.006861 0.058157 0.089843 0.025630 0.000682 0.000000 0.000000 -0.007185 -0.171530 -0.335851 -1.106651 -4.482503 -7.943667 -5.051016 -0.228761 3.447369 3.276108 3.669149 5.239641 9.374461 5.196424 1.620280 1.118559 0.212908 0.094985 0.101006 0.012006 0.000007 0.000000 -0.024791 -0.210459 -0.481665 -2.845385 -0.714932 10.220174 19.731306 20.658689 18.175476 21.630013 22.331097 21.672323 14.237628 -5.705527 1.171324 11.781735 5.857376 0.785525 0.148184 0.040356 0.000310 0.000000 -0.019441 -0.437731 -2.924470 2.400123 4.496713 16.048525 16.571648 9.943014 3.193688 2.476999 2.993446 2.484255 -5.369709 -7.554636 3.331461 17.453579 20.063910 5.990866 0.349580 0.059092 0.002000 0.000000 -0.005151 -1.922307 -7.451153 0.605507 -3.857845 1.868660 1.399032 -1.954443 -2.421380 -0.691250 -0.044535 0.010134 0.708851 4.016835 7.314301 6.248482 12.449841 8.953633 0.730223 0.042246 0.003729 0.000000 -0.025133 -2.853370 -4.166634 0.827800 -0.752681 -0.104647 -0.178633 -0.599087 -2.635615 -2.141374 -0.145805 1.085440 -0.466755 0.125560 1.204961 1.704356 3.117409 5.796158 0.187705 -0.093104 0.001269 0.000000 -0.061031 -2.112134 -1.113045 1.126914 0.772430 -0.169026 -0.010560 1.844144 3.048156 -0.027238 -2.670364 5.175004 4.752594 -0.118649 0.039025 0.264519 1.882826 3.960167 -0.322877 -0.285887 -0.001078 0.000000 -0.061957 -1.263181 -0.260155 1.933638 1.398820 -0.086051 0.018886 2.220293 5.598336 -0.619402 -6.965183 0.395099 3.392587 0.022498 -0.422923 -3.099875 0.763232 3.317903 0.028002 -0.289935 -0.004560 0.000000 -0.010871 -0.239322 0.068182 3.190022 4.239766 0.547931 0.023282 0.933838 3.892883 1.008011 -0.368748 3.457577 1.041364 -0.094964 -1.577717 -5.507735 2.143185 2.637346 0.196037 -0.153686 -0.003022 0.000000 0.052977 1.458636 0.917888 1.407465 7.710236 4.267129 0.624490 -1.917090 -0.621206 0.572640 0.506714 5.675804 3.143064 -0.439726 -2.721228 -1.801316 1.998766 0.150734 0.475942 0.097195 0.000086 0.000000 0.056108 3.215453 7.600710 0.514590 4.888288 13.974749 11.590655 0.084760 -1.066809 -5.709270 1.530698 18.038015 11.783248 1.909101 -0.222093 0.134293 -3.168552 -0.872167 2.394029 0.296927 0.000184 0.000000 0.010315 1.905337 13.145315 16.200142 8.575520 11.428239 14.306471 4.040713 -0.422524 -1.236689 1.807304 4.891045 7.127174 4.607660 -3.079105 -6.864558 0.709319 3.544412 1.938301 0.112380 0.000011 0.000000 0.000089 0.181176 4.092281 15.585127 17.058449 12.524237 12.233292 9.444195 8.041085 15.864759 19.550913 10.305941 6.561223 10.101851 2.926528 4.715234 10.173097 2.632871 0.138348 0.002312 0.000000 0.000000 0.000000 0.000431 0.103638 1.114364 2.749355 7.137598 12.751110 12.518215 6.308797 3.939806 10.415325 17.001999 19.280352 14.807691 2.740318 -0.719555 0.619350 0.068155 0.000315 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000009 0.021469 0.362547 1.220529 1.825741 0.822212 0.064037 0.438588 1.103777 2.005048 2.275163 1.874570 0.961411 0.328814 0.048757 0.000461 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000013 0.003021 0.056579 0.223536 0.083584 -0.041319 0.131418 0.233088 0.275838 0.265527 0.274759 0.097209 0.008338 0.000077 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000011 0.000166 0.000096 -0.000096 0.000182 0.000384 0.000463 0.000345 0.000215 0.000020 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000044 0.000462 0.000531 0.000052 0.000035 0.000379 0.000305 0.000026 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000146 0.002928 0.013511 0.028695 0.019247 0.000961 0.000260 0.012970 0.017908 0.008313 0.001645 0.000083 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000814 0.012267 0.043581 0.063960 0.054702 0.024093 -0.001663 -0.004282 0.012649 0.030352 0.033371 0.020994 0.006176 0.000501 0.000003 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000003 -0.000754 0.006274 0.051652 0.057315 0.024280 0.001955 -0.002998 -0.005444 -0.007974 -0.006544 -0.003522 0.007348 0.021439 0.023248 0.007994 0.000513 0.000002 0.000000 0.000000 0.000000 -0.000000 -0.000672 -0.016650 -0.023835 0.017331 0.003239 -0.007220 -0.007379 -0.006241 -0.008300 -0.007575 -0.007490 -0.007645 -0.006025 -0.001533 0.010676 0.014240 0.004925 0.000272 0.000000 0.000000 0.000000 -0.000073 -0.008678 -0.051984 -0.043011 -0.030294 -0.168918 -0.451100 -0.843558 -1.644667 -2.855776 -2.657683 -1.187834 -0.157848 0.003642 -0.005233 -0.004055 0.001385 0.009016 0.002328 0.000037 0.000000 0.000000 -0.001438 -0.028320 -0.055023 -0.309187 -1.956536 -5.279400 -7.058903 -6.852646 -5.473199 -6.627978 -6.342555 -1.335841 3.754327 0.870129 0.006888 0.044518 0.003564 0.003618 0.006462 0.000658 0.000001 0.000000 -0.005064 -0.038040 -0.285642 -3.648420 -4.942254 1.286137 6.814235 9.998652 15.416220 24.760571 23.648439 19.363247 9.493853 -6.285079 -1.960799 2.334219 1.589670 0.198412 0.013126 0.004205 0.000054 0.000000 -0.003445 -0.150544 -0.951347 -0.137525 8.839161 25.356190 24.061283 17.003700 8.864000 9.880126 9.968573 5.163211 -8.217047 -13.136683 -5.238470 9.335643 14.268247 4.274353 0.337781 0.012014 0.000459 0.000000 -0.005831 -1.710515 -3.001069 6.546587 0.886126 7.410147 5.548695 0.656834 -3.711907 -1.015008 -0.165132 -0.346840 0.826036 5.995411 5.009282 10.761503 21.669630 14.767965 3.084792 0.061776 0.000939 0.000000 -0.059444 -3.924084 -3.629921 1.532831 -2.411077 -0.305563 -0.037362 -1.464661 -2.234309 -0.195720 -0.491523 2.026171 1.836077 1.755280 3.336083 4.375445 8.156278 14.141364 5.319179 0.160427 0.000345 0.000000 -0.067471 -1.245613 1.327149 -0.226722 1.496036 0.237441 -0.048496 0.763684 1.464973 -0.357008 -4.516991 1.787040 4.008424 0.168152 0.023987 -0.836224 -0.849052 6.284544 4.558939 0.125521 -0.000177 0.000000 -0.026142 0.301097 1.441943 -1.666726 1.054277 0.294235 -0.008299 1.570531 3.077664 -1.932616 -6.718377 -0.746440 1.103328 -0.031907 -1.285575 -8.525873 -7.676068 -0.019206 2.900494 0.119839 -0.000858 0.000000 -0.061010 -1.197222 0.476703 1.230700 1.626871 0.601458 -0.025989 1.285572 3.947107 1.268436 1.486868 5.058949 1.411588 -0.091448 -2.150164 -9.974700 -3.101696 1.308068 0.581144 -0.047916 -0.000705 0.000000 -0.137372 -2.490691 0.867238 4.450177 8.724647 6.220679 0.841521 -1.430348 -0.347117 0.811637 0.429558 4.059672 2.742038 -0.159362 -1.992556 -0.427192 5.016369 6.498319 2.798966 0.159772 -0.000256 0.000000 0.020698 1.810109 5.492864 0.908568 7.567659 21.597092 13.526738 0.338038 -2.912819 -5.722631 1.611753 17.231773 11.767198 3.204519 0.344139 0.740371 -0.446943 1.854061 3.633289 0.519505 0.000073 0.000000 0.020709 2.184893 12.714950 14.842302 4.789624 11.632456 15.285569 2.187788 -3.898483 -5.587544 -0.472030 5.245871 7.570544 4.491857 -1.253376 -5.522398 0.467447 4.477234 2.867931 0.298227 0.000069 0.000000 0.000197 0.254860 5.115805 17.854580 17.936052 13.915440 14.547398 8.825105 8.022511 12.786213 16.160118 7.100291 3.966223 8.212072 1.142216 1.136216 12.497950 5.003969 0.407850 0.011127 0.000000 0.000000 0.000000 0.001369 0.191210 1.682043 3.978529 9.819774 17.449974 17.382811 10.605616 7.558537 13.866982 18.842651 21.507202 16.832298 2.858256 -1.939173 0.811762 0.195857 0.002287 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000037 0.014051 0.238944 0.815590 1.592741 1.135444 0.282386 0.487070 1.442953 2.719630 2.659012 1.461007 0.512248 0.204033 0.034733 0.000300 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000008 0.001571 0.026244 0.120308 0.035880 -0.043203 0.111772 0.257290 0.386600 0.261680 0.146346 0.048198 0.004664 0.000051 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000006 0.000084 0.000008 -0.000102 0.000145 0.000429 0.000678 0.000409 0.000147 0.000012 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000048 0.000570 0.000681 0.000067 0.000056 0.000563 0.000448 0.000034 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000186 0.003670 0.017575 0.038747 0.026722 0.001804 0.001302 0.019938 0.025900 0.011254 0.002299 0.000122 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 0.001067 0.016341 0.057202 0.085952 0.077763 0.035157 0.000127 -0.001435 0.022464 0.045872 0.048973 0.031556 0.008796 0.000673 0.000004 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000005 -0.000943 0.007546 0.068148 0.078103 0.035250 0.006653 -0.001764 -0.005499 -0.005755 -0.004178 0.000627 0.016135 0.034088 0.033182 0.011388 0.000789 0.000003 0.000000 0.000000 0.000000 -0.000000 -0.000922 -0.022034 -0.031767 0.022090 0.007891 -0.005882 -0.007245 -0.005242 -0.006256 -0.005834 -0.006440 -0.006868 -0.006108 -0.000754 0.017428 0.023893 0.007821 0.000356 0.000000 0.000000 0.000000 -0.000108 -0.011879 -0.068259 -0.056351 -0.011279 -0.012498 -0.041055 -0.131968 -0.347877 -0.715502 -0.643333 -0.217154 -0.020299 -0.004923 -0.004207 -0.001331 0.007233 0.014180 0.003584 0.000049 0.000000 0.000000 -0.002011 -0.036590 -0.061102 -0.047378 -0.324544 -1.268901 -2.968741 -5.198971 -7.261617 -10.206042 -8.514879 -2.653679 0.663024 0.090286 -0.003657 -0.004645 -0.005387 0.008318 0.010066 0.000744 0.000000 0.000000 -0.005917 -0.042008 -0.127149 -1.828967 -4.445979 -4.548212 -5.962627 -3.141148 3.113526 11.304223 11.436117 10.193630 4.999478 -2.036333 -0.430127 0.337248 0.211392 0.021263 0.012539 0.003801 0.000041 0.000000 -0.003095 -0.042324 -1.033198 -5.936794 -3.166066 10.234795 11.639007 17.332966 16.038021 22.200098 20.599815 10.499353 -3.496995 -11.642820 -7.552817 7.483581 6.136020 0.847383 0.143196 0.013292 0.000526 0.000000 -0.018400 -0.821152 2.640871 8.735241 2.188112 9.751139 9.944640 7.302813 1.314026 2.315101 -0.267098 -0.871429 2.113766 0.613279 -6.063395 18.306463 20.132879 9.977142 3.688528 0.135733 0.001127 0.000000 -0.135336 -3.541436 5.320290 8.681863 -4.058305 -0.049679 1.003240 -1.204651 -2.159513 0.100421 -0.964605 0.474075 2.166268 3.344392 4.609950 9.842628 14.314231 16.070808 7.707730 0.374991 0.000336 0.000000 -0.038426 1.282187 11.396520 8.475444 1.590054 0.286977 -0.061987 0.073748 -0.266753 -1.837748 -3.487452 0.268103 0.777533 0.095268 0.256691 1.983673 4.745036 9.155076 5.177269 0.199682 -0.000214 0.000000 0.012581 1.232084 5.247834 -10.429796 -13.634105 -0.543459 -0.013183 0.540144 -2.501651 -8.067624 -7.065378 2.160051 1.134424 -0.076713 -4.505601 -26.211128 -14.411227 2.934903 2.412930 0.069558 -0.000834 0.000000 -0.029521 -0.484360 1.292344 -7.635759 -6.614027 0.496594 0.008190 1.141667 2.089983 1.370932 3.096600 7.738510 2.954388 -0.070631 -8.111526 -46.938232 -23.137911 -0.552216 -0.069938 -0.008898 -0.000850 0.000000 -0.209628 -4.743886 4.716565 12.625859 12.894302 8.858825 1.349849 -0.582267 0.548320 2.676324 2.709759 2.621396 2.734632 -0.299866 -5.510342 -6.273157 17.038681 12.228317 4.710458 0.396358 -0.000457 0.000000 -0.106095 -2.445449 4.336632 1.993942 10.889466 27.140343 14.760108 1.136392 -3.254028 -8.746190 -1.143369 12.419336 9.827121 1.501428 1.201115 6.253980 10.148710 9.939268 7.021863 0.625685 -0.000125 0.000000 0.012231 1.876273 13.433464 16.514624 7.052985 10.395136 13.376917 3.431728 -3.676499 -8.096304 -4.946483 2.984961 7.518032 3.254223 0.540677 -2.193812 0.920728 2.378880 2.725098 0.404618 0.000054 0.000000 0.000216 0.276789 5.832218 19.858519 19.534830 12.441520 11.478583 6.999225 7.788020 12.631873 12.352690 5.597033 5.810896 8.287827 0.106469 1.384760 14.531609 6.213869 0.444866 0.019909 0.000000 0.000000 0.000000 0.002566 0.272850 2.093601 4.855027 11.102724 18.196756 18.378899 12.505363 10.503284 15.386084 18.967823 21.674053 16.100542 2.428027 -1.987839 1.037125 0.301746 0.005860 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000036 0.014722 0.254667 0.902119 1.873763 1.548102 0.485200 0.658370 1.622116 2.785517 2.661495 1.551551 0.627880 0.257755 0.039120 0.000317 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000009 0.001670 0.027493 0.129911 0.062169 -0.036742 0.113974 0.278069 0.406321 0.276775 0.170513 0.057068 0.005363 0.000057 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000007 0.000095 0.000041 -0.000103 0.000130 0.000459 0.000721 0.000427 0.000161 0.000013 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000065 0.000768 0.000940 0.000093 0.000079 0.000800 0.000641 0.000050 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000273 0.005284 0.024693 0.053072 0.036524 0.002689 0.002154 0.028327 0.037687 0.016527 0.003246 0.000177 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 0.001591 0.023702 0.083758 0.122205 0.108703 0.047318 0.001077 0.000193 0.033590 0.069071 0.070146 0.044313 0.012538 0.000898 0.000006 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000007 -0.001403 0.011501 0.100657 0.115419 0.053067 0.012414 -0.000662 -0.004000 -0.004235 -0.002631 0.005480 0.024631 0.048885 0.045014 0.015996 0.001205 0.000005 0.000000 0.000000 0.000000 -0.000000 -0.001328 -0.031614 -0.045488 0.035445 0.015614 -0.004378 -0.007061 -0.005417 -0.004952 -0.004758 -0.004791 -0.004971 -0.005235 0.001608 0.025031 0.035560 0.011236 0.000525 0.000000 0.000000 0.000000 -0.000151 -0.017371 -0.099045 -0.079358 -0.011772 -0.006560 -0.006771 -0.011213 -0.026662 -0.058282 -0.048759 -0.013959 -0.004647 -0.006129 -0.003816 0.000703 0.014094 0.023526 0.006121 0.000068 0.000000 0.000000 -0.002760 -0.052189 -0.089000 -0.025864 -0.018609 -0.084428 -0.336921 -1.130642 -2.800916 -4.426485 -3.201662 -0.885524 0.023524 -0.001248 -0.004689 -0.003996 -0.002366 0.017423 0.015301 0.001060 0.000000 0.000000 -0.007867 -0.057055 -0.048906 -0.322257 -1.309384 -2.973003 -5.417867 -5.896301 -7.148444 -5.110744 -1.305946 1.884284 3.018903 0.097503 -0.024116 0.023090 0.008099 0.002385 0.017616 0.005016 0.000036 0.000000 -0.003714 -0.035154 -0.877427 -4.907481 -6.398064 -2.699052 -1.468701 6.504697 13.751897 24.167719 24.882318 13.618332 8.292701 -1.068978 -0.333545 3.675862 0.489536 -0.338499 0.019143 0.014433 0.000536 0.000000 -0.041729 -0.216513 2.522191 3.807170 6.907587 19.007938 16.747692 11.270401 8.011881 9.785947 7.642416 3.143841 7.794310 -1.459861 4.116329 18.502047 6.231831 2.347842 2.130241 0.143806 0.001191 0.000000 -0.377506 -3.614862 12.272902 18.901205 2.002350 3.759652 4.705232 0.812474 -2.029853 -1.878638 -2.750331 -1.248904 4.676606 3.326279 7.627973 17.561119 14.638117 11.141724 6.451399 0.437362 0.000345 0.000000 -0.145213 1.075099 17.578205 20.355104 -4.912094 -3.692738 -0.158844 0.202765 -0.480517 -3.781776 -4.828176 -0.271036 0.312498 0.527611 0.817024 4.436521 9.551889 10.974565 4.625383 0.174703 -0.000263 0.000000 0.012965 0.778880 4.939833 -27.125107 -50.068600 -6.684509 -0.026333 0.251043 -3.816818 -14.783360 -7.313019 4.138052 1.480418 -0.014104 -5.303447 -36.472679 -16.885054 4.872464 1.317491 0.002622 -0.001128 0.000000 -0.000183 0.053228 1.233698 -9.590643 -11.006863 -0.970222 0.004532 0.998217 2.783557 2.549093 3.074831 8.545453 3.555134 -0.174069 -12.979426 -73.428871 -39.054596 -2.143376 -0.737279 -0.115888 -0.001871 0.000000 -0.099518 -3.560571 6.840855 27.338823 26.264114 9.356692 1.688254 0.081514 1.816406 3.804295 2.834590 2.481411 3.051207 -0.606059 -8.216912 -10.226165 24.499456 12.081019 2.148088 -0.119472 -0.003280 0.000000 -0.122012 -4.471002 2.731887 6.124639 9.042587 18.630100 14.810975 1.221332 -1.951213 -8.152818 -1.918619 10.989649 10.873342 2.458815 2.726656 8.252235 13.951464 11.845004 6.640230 0.347500 -0.001304 0.000000 0.001739 1.514252 13.618913 17.200024 6.462656 6.305654 10.002392 -0.901590 -2.455498 -4.226335 -4.904541 1.656376 9.059313 6.826007 1.292893 -2.355853 -0.244689 1.202046 1.892879 0.330047 0.000008 0.000000 0.000219 0.285096 5.941816 19.213175 18.526384 12.788558 10.984008 5.634319 8.484181 15.649301 11.392542 7.188475 8.154776 9.052208 0.971506 5.206729 14.808739 6.255828 0.373926 0.016470 0.000000 0.000000 0.000000 0.002635 0.258599 1.860047 4.161051 10.266361 17.395140 17.901451 13.079913 12.939199 15.599754 17.919237 19.052217 12.517072 1.166984 -1.143304 1.025688 0.257044 0.005740 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000039 0.017036 0.284101 1.002517 1.980844 1.501025 0.498193 0.836355 1.477807 2.135349 2.120929 1.586946 0.842175 0.316249 0.041944 0.000384 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000009 0.001907 0.033358 0.155291 0.071393 -0.039753 0.120897 0.239575 0.299831 0.241796 0.226383 0.080759 0.007057 0.000068 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000008 0.000110 0.000046 -0.000105 0.000137 0.000374 0.000515 0.000338 0.000182 0.000016 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000049 0.000569 0.000693 0.000073 0.000065 0.000616 0.000490 0.000039 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000201 0.003844 0.017736 0.038510 0.026869 0.002085 0.001724 0.022048 0.028903 0.012168 0.002360 0.000131 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.001167 0.017647 0.062547 0.088370 0.077569 0.034633 0.000577 -0.000191 0.025844 0.051610 0.050183 0.032062 0.009411 0.000646 0.000005 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000005 -0.001097 0.009152 0.074414 0.085336 0.037961 0.007253 -0.001814 -0.002908 -0.003510 -0.002880 0.002201 0.015712 0.034981 0.031879 0.011002 0.000892 0.000004 0.000000 0.000000 0.000000 -0.000000 -0.000966 -0.024201 -0.034999 0.025976 0.009366 -0.005815 -0.007773 -0.005916 -0.003620 -0.003573 -0.003988 -0.004621 -0.005380 -0.000661 0.015371 0.025749 0.009481 0.000398 0.000000 0.000000 0.000000 -0.000114 -0.013002 -0.073806 -0.060504 -0.009911 -0.006159 -0.007280 -0.007438 -0.006591 -0.005116 -0.005578 -0.004165 -0.003345 -0.004520 -0.003493 0.000013 0.011330 0.016858 0.003832 0.000055 0.000000 0.000000 -0.002016 -0.039475 -0.067953 -0.019072 -0.006386 -0.007382 -0.015860 -0.082506 -0.380142 -0.706067 -0.455430 -0.113519 -0.009737 -0.004907 -0.003645 -0.002990 -0.003412 0.010340 0.011896 0.000935 0.000000 0.000000 -0.005689 -0.042466 -0.030646 -0.020862 -0.138520 -0.639352 -1.666059 -3.173836 -6.056933 -8.372531 -5.184132 -1.459876 0.574782 0.151477 0.000123 -0.003839 -0.005605 0.000513 0.015049 0.004023 0.000018 0.000000 -0.002906 -0.021019 -0.233563 -1.300959 -2.890337 -3.416780 -6.135210 -6.247411 1.011084 6.304893 10.799601 6.518021 8.803281 5.915220 2.948942 0.838201 -0.399007 -0.170382 0.000539 0.008164 0.000244 0.000000 -0.038379 -0.090524 -0.342955 -2.951329 0.041446 11.100086 11.114396 8.743201 14.119937 16.707523 20.938076 13.022349 15.857590 15.499472 18.811630 7.805184 -3.295206 -1.844717 0.395048 0.085078 0.000626 0.000000 -0.713206 -4.761803 5.499553 13.864908 9.845998 6.729020 8.394412 6.962294 2.760679 -3.776114 -4.025825 -0.516366 9.234394 9.549134 16.342482 19.201614 12.153792 6.878877 4.987054 0.612719 0.000184 0.000000 -0.501831 -0.746026 11.646637 12.094856 -2.780313 -4.329786 0.573851 2.459181 2.000557 -1.686766 -3.179322 -2.393124 1.420863 3.318769 5.636270 8.984660 9.431407 7.711787 6.404165 0.661507 0.000972 0.000000 0.090266 1.988334 4.582129 -26.350767 -41.350586 -5.430743 0.558486 0.441144 -1.525000 -11.300747 -4.270136 1.031220 0.510671 1.027469 -0.051966 -27.556061 -19.159674 -1.415984 2.187086 0.208271 0.000458 0.000000 -0.108291 -0.888152 0.178680 -12.561666 -15.306566 -1.107407 0.409050 0.278792 1.339664 2.951032 2.899668 5.059304 1.671354 -0.328697 -8.746875 -45.588329 -24.375475 -1.040026 -1.802687 -0.677997 -0.010510 0.000000 -0.324323 -6.361548 0.898446 15.123376 12.739972 5.934270 3.240183 0.582359 0.848430 0.781714 1.626174 4.425085 2.605762 -0.676308 -2.167732 1.267531 12.710459 9.119009 -0.274428 -0.807456 0.009648 0.000000 -0.111416 -3.108911 2.259062 1.579008 0.410229 8.958970 14.857253 3.068630 -2.728384 -10.334306 -5.872681 7.130419 12.187060 4.294811 3.198431 0.887259 2.207947 3.858833 3.678131 1.007297 0.013842 0.000000 0.014301 2.321622 16.464193 20.022276 6.488754 3.843081 8.133636 -0.498625 -2.357230 -3.773608 -4.523650 1.546504 10.515497 7.999593 -0.535388 -1.634664 5.274180 5.136900 0.843447 0.302252 0.000648 0.000000 0.000243 0.279862 5.258067 16.646208 16.023460 11.783322 13.438822 10.483361 8.499434 13.974351 11.447227 10.635377 11.120977 9.661072 5.771464 11.177825 13.221065 5.434979 0.384552 0.005355 0.000000 0.000000 0.000000 0.001398 0.146240 1.019119 2.036670 5.921238 12.160080 13.572267 9.642015 10.462929 11.361263 12.418839 12.086329 5.649554 -0.207813 0.107301 0.607314 0.104580 0.002003 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000038 0.018613 0.299468 0.951558 1.472068 0.819997 0.205099 0.649224 0.949526 1.059128 0.994967 1.223150 0.898817 0.333718 0.042030 0.000371 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000009 0.002095 0.038525 0.156160 0.050243 -0.046653 0.104222 0.178899 0.167434 0.137667 0.231500 0.094577 0.007889 0.000067 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000008 0.000115 0.000044 -0.000104 0.000132 0.000278 0.000270 0.000179 0.000180 0.000018 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000039 0.000462 0.000567 0.000060 0.000048 0.000486 0.000390 0.000031 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000165 0.003040 0.014536 0.032031 0.022560 0.001887 0.000945 0.017151 0.023305 0.010090 0.001956 0.000105 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 0.000982 0.014761 0.050946 0.072138 0.065579 0.029709 0.000524 -0.001423 0.019731 0.042261 0.042131 0.025882 0.007882 0.000604 0.000004 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000005 -0.000876 0.007871 0.062147 0.070324 0.030601 0.006372 -0.002039 -0.003200 -0.003650 -0.003081 0.000903 0.013470 0.029223 0.028910 0.008908 0.000612 0.000004 0.000000 0.000000 0.000000 -0.000000 -0.000771 -0.019739 -0.026992 0.022457 0.006878 -0.005042 -0.006418 -0.005211 -0.003327 -0.003592 -0.004217 -0.004247 -0.003110 0.000816 0.013028 0.018568 0.007368 0.000307 0.000000 0.000000 0.000000 -0.000089 -0.010413 -0.059274 -0.047735 -0.007669 -0.005695 -0.005726 -0.005323 -0.004658 -0.004279 -0.004333 -0.004324 -0.004419 -0.003723 -0.003369 -0.002089 0.008061 0.013360 0.003211 0.000054 0.000000 0.000000 -0.001670 -0.032499 -0.056444 -0.016063 -0.005775 -0.006465 -0.006363 -0.005597 -0.013914 -0.031751 -0.023804 -0.007247 -0.004421 -0.003947 -0.003783 -0.005038 -0.003666 0.009348 0.011386 0.000912 0.000000 0.000000 -0.004907 -0.037712 -0.028748 -0.009039 -0.010167 -0.037909 -0.169935 -0.584170 -1.483891 -2.727937 -2.131646 -0.738940 -0.131411 0.001493 -0.003972 -0.004954 -0.005928 0.001426 0.014955 0.003543 0.000008 0.000000 -0.002521 -0.015049 -0.033700 -0.179564 -0.705513 -2.113730 -4.621425 -5.753257 -5.465185 -6.750195 -3.749027 -2.178072 -0.912700 1.643078 0.881738 -0.056045 -0.117908 -0.032185 0.004890 0.004526 0.000092 0.000000 -0.009943 -0.112276 -1.368209 -4.608913 -5.275002 -3.856609 -0.469090 5.933291 13.018621 14.109041 19.331657 14.310615 9.406538 12.438508 7.468391 -1.638067 -3.518876 -1.834373 -0.207948 0.019210 0.000336 0.000000 -0.465799 -2.737988 -0.273216 2.675863 9.024462 10.605217 9.399673 13.744794 11.227164 3.560205 4.569571 8.317631 13.448738 16.581217 16.898903 11.321045 5.422674 1.658965 1.717136 0.439121 0.000696 0.000000 -0.869424 -2.182139 8.170843 12.823569 10.015109 1.930701 -0.563983 4.799334 3.435974 -4.137870 -7.016452 -3.667924 3.582800 6.215260 9.505138 16.012201 18.708038 12.976691 6.711424 1.188556 0.008712 0.000000 -0.345731 -0.640361 0.199061 -18.136831 -20.317890 -4.695531 -0.294479 0.649058 -0.766506 -11.966855 -8.955832 -1.973135 0.648764 1.783258 -0.881919 -17.267714 -7.950092 1.647413 3.189594 0.657873 0.009960 0.000000 -0.593974 -4.385050 -3.153573 -17.515867 -16.684057 -0.685047 0.676486 -0.440803 0.389878 5.275436 2.993115 4.345827 0.900848 -1.054984 -6.533031 -33.563656 -15.648858 0.406673 0.334928 -0.092653 0.018147 0.000000 -0.272968 -4.981812 -4.227815 -0.940611 0.701134 5.447233 10.565440 7.095887 3.472751 0.200894 -0.728897 6.045718 3.377202 1.722806 1.065872 -1.136868 1.012554 4.025204 3.063636 2.019546 0.132240 0.000000 0.165339 3.503951 11.156458 -0.885274 -7.485807 1.520461 17.137814 15.302236 3.987849 -9.556540 -7.298151 4.127248 13.959863 7.982165 1.200973 -4.364191 -3.326482 0.923790 1.882400 1.917838 0.056976 0.000000 0.036151 3.889796 25.189013 32.116035 15.427722 9.128091 11.312563 8.147300 7.068831 5.470216 4.328237 8.582377 9.794958 3.800109 1.172505 5.819365 14.837786 10.690672 1.204201 0.162267 0.001171 0.000000 0.000229 0.211860 3.606721 12.453580 16.321859 13.870063 14.920322 14.738122 14.229506 19.803453 17.101549 15.687357 10.102750 8.305688 12.119279 12.905740 8.424517 2.770948 0.209768 0.000487 0.000000 0.000000 0.000000 0.000281 0.036102 0.261454 1.176212 2.400878 3.858232 4.836324 3.418360 4.751634 4.708622 4.290442 2.905923 0.617086 0.603514 0.679691 0.118090 0.006903 0.000188 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000027 0.022466 0.335141 0.889120 0.951290 0.255023 -0.027630 0.386942 0.520493 0.444920 0.371709 0.929327 0.861436 0.352437 0.044638 0.000335 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000009 0.002614 0.044463 0.153875 0.041662 -0.037858 0.096176 0.147658 0.119018 0.091448 0.205612 0.090807 0.007589 0.000063 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000010 0.000131 0.000060 -0.000100 0.000116 0.000234 0.000185 0.000118 0.000164 0.000019 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000016 0.000187 0.000233 0.000028 0.000019 0.000197 0.000162 0.000013 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000068 0.001276 0.006253 0.013496 0.009393 0.000916 0.000368 0.006756 0.009500 0.004360 0.000848 0.000046 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000424 0.006123 0.020936 0.030814 0.028571 0.012605 0.000232 -0.000541 0.007630 0.017130 0.018423 0.011472 0.003427 0.000242 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000002 -0.000364 0.003560 0.026802 0.028810 0.012682 0.003412 -0.000766 -0.001502 -0.001188 -0.000992 0.000446 0.006326 0.013411 0.011662 0.003521 0.000283 0.000001 0.000000 0.000000 0.000000 -0.000000 -0.000319 -0.008336 -0.010832 0.010505 0.002906 -0.002948 -0.002847 -0.001981 -0.001550 -0.001579 -0.001593 -0.001398 -0.000935 0.000886 0.005125 0.008125 0.003026 0.000112 0.000000 0.000000 0.000000 -0.000037 -0.004242 -0.024750 -0.019996 -0.002858 -0.002178 -0.002650 -0.002412 -0.001754 -0.001761 -0.001793 -0.001851 -0.001765 -0.001757 -0.001565 -0.001320 0.003366 0.005276 0.001327 0.000024 0.000000 0.000000 -0.000721 -0.013478 -0.023524 -0.007035 -0.002336 -0.003033 -0.002735 -0.002236 -0.001619 -0.001403 -0.001696 -0.001162 -0.001563 -0.002053 -0.002531 -0.003117 -0.001404 0.004167 0.004698 0.000366 0.000000 0.000000 -0.002117 -0.015776 -0.011295 -0.003807 -0.003381 -0.004398 -0.007492 -0.031888 -0.117229 -0.247175 -0.212595 -0.080509 -0.018491 -0.002974 -0.002493 -0.003268 -0.003302 0.000219 0.005911 0.001432 0.000004 0.000000 -0.001247 -0.007001 -0.004746 -0.008698 -0.063249 -0.387390 -1.108095 -1.780297 -2.682541 -3.717106 -2.546719 -1.549039 -1.105749 -0.274677 -0.024391 -0.021087 -0.007575 -0.002862 0.002482 0.002054 0.000042 0.000000 -0.001608 -0.055380 -0.412319 -1.195345 -2.071495 -2.538636 -1.664339 0.540562 3.430036 4.913888 7.754818 5.623010 1.638196 1.857570 0.327445 -0.984424 -0.668317 -0.285175 -0.045777 0.002043 0.000163 0.000000 -0.098858 -1.111428 -2.127458 -1.620593 1.444335 5.257226 4.895461 7.440902 7.684593 5.965526 7.801114 7.574395 6.988527 9.084363 7.137154 2.719630 0.254655 -0.337509 0.051560 0.073110 0.000403 0.000000 -0.613474 -3.384557 2.133789 7.684256 7.616872 3.174201 -1.296085 2.458441 2.124701 -2.791431 -3.500269 -0.948344 2.433084 5.192274 6.345890 9.193210 9.687799 6.727189 2.512417 0.414217 0.004099 0.000000 -0.798434 -4.759787 -1.357299 -2.665525 -4.903943 -2.878413 -1.450700 0.559238 -0.299373 -6.730465 -6.176454 -1.261895 0.629510 1.395907 -1.127387 -6.287254 -0.243115 4.895565 2.452255 0.103911 -0.001075 0.000000 -0.300075 -2.194566 -1.387406 -4.693440 -6.126544 -1.612188 -0.382768 -0.365180 0.048268 2.526846 0.840695 2.084854 0.170132 -1.359236 -3.184973 -14.209897 -6.620117 1.118389 0.590568 -0.024906 0.010841 0.000000 0.382427 4.357419 4.826686 1.676890 0.621799 1.113732 4.633593 4.558170 2.595820 1.790028 -0.571204 2.787098 0.854548 0.552255 0.591659 0.307010 0.182926 -0.068394 0.915176 1.046385 0.051547 0.000000 0.215786 4.687251 10.435211 3.775157 -0.231719 1.023338 5.982892 9.104300 3.233316 -2.624729 -1.925194 2.844572 7.465001 3.687989 0.240918 -0.076996 1.860031 1.679235 0.243119 0.396766 0.014444 0.000000 0.014247 1.370760 8.803739 12.432019 8.731492 7.630046 8.665536 8.594970 7.857216 6.733153 6.407022 8.579062 7.711887 4.262302 5.020752 7.360191 8.087408 3.939612 0.420173 0.014072 0.000161 0.000000 0.000042 0.039742 0.760500 3.122010 5.895311 8.042569 10.039631 10.837152 11.683922 13.100333 12.112271 11.448610 8.418695 7.738377 7.974129 5.324301 2.010103 0.398382 0.021558 0.000027 0.000000 0.000000 0.000000 0.000012 0.001472 0.004407 0.595174 1.147162 0.776045 0.868274 0.883523 1.329852 1.285987 0.984099 0.712395 0.775769 0.858388 0.512444 0.048702 -0.003972 0.000006 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000012 0.012103 0.163792 0.395383 0.375623 0.071880 -0.007077 0.163852 0.208227 0.173332 0.132850 0.376677 0.394202 0.179899 0.023815 0.000161 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000004 0.001300 0.020899 0.068218 0.017209 -0.013064 0.043288 0.062139 0.048098 0.029436 0.077089 0.038109 0.003376 0.000029 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000005 0.000062 0.000027 -0.000041 0.000047 0.000095 0.000072 0.000034 0.000060 0.000008 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000009 0.000011 0.000002 0.000001 0.000009 0.000008 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000003 0.000060 0.000299 0.000653 0.000466 0.000052 0.000013 0.000297 0.000442 0.000216 0.000043 0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000021 0.000294 0.000968 0.001452 0.001398 0.000634 0.000019 -0.000025 0.000306 0.000763 0.000918 0.000600 0.000185 0.000012 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000017 0.000191 0.001353 0.001362 0.000558 0.000162 -0.000052 -0.000086 -0.000042 -0.000046 0.000014 0.000313 0.000728 0.000589 0.000171 0.000016 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000015 -0.000404 -0.000484 0.000570 0.000141 -0.000224 -0.000191 -0.000113 -0.000106 -0.000085 -0.000082 -0.000053 -0.000066 0.000034 0.000234 0.000429 0.000146 0.000004 0.000000 0.000000 0.000000 -0.000002 -0.000194 -0.001172 -0.000944 -0.000102 -0.000099 -0.000175 -0.000160 -0.000088 -0.000091 -0.000085 -0.000103 -0.000078 -0.000117 -0.000099 -0.000114 0.000137 0.000226 0.000063 0.000001 0.000000 0.000000 -0.000035 -0.000639 -0.001120 -0.000338 -0.000096 -0.000181 -0.000132 -0.000135 -0.000088 -0.000060 -0.000068 -0.000043 -0.000043 -0.000113 -0.000181 -0.000226 -0.000078 0.000203 0.000210 0.000014 0.000000 0.000000 -0.000100 -0.000740 -0.000542 -0.000232 -0.000191 -0.000257 -0.000125 -0.000211 -0.001214 -0.003124 -0.002757 -0.001021 -0.000147 -0.000063 -0.000152 -0.000222 -0.000187 -0.000010 0.000227 0.000062 0.000000 0.000000 -0.000059 -0.000350 -0.000224 -0.000157 -0.000730 -0.006564 -0.031409 -0.077331 -0.134051 -0.185080 -0.129020 -0.090507 -0.053875 -0.012629 -0.001691 -0.000317 -0.000189 -0.000120 0.000094 0.000102 0.000002 0.000000 -0.000050 -0.001307 -0.010873 -0.036281 -0.081325 -0.088987 -0.068780 -0.044847 0.095087 0.247632 0.456736 0.260708 0.030189 0.062902 0.006484 -0.033563 -0.019903 -0.005324 -0.000609 0.000113 0.000009 0.000000 -0.003059 -0.061342 -0.172210 -0.172459 0.001458 0.325271 0.367789 0.451699 0.489193 0.477038 0.673395 0.555437 0.416966 0.580421 0.422764 0.108247 -0.060658 -0.072381 -0.028335 -0.000800 0.000008 0.000000 -0.040962 -0.305789 0.016504 0.426359 0.479780 0.288509 -0.008354 0.165046 0.158246 -0.080747 -0.042388 0.016210 0.162510 0.439346 0.486187 0.568250 0.501749 0.228107 -0.012266 -0.008185 -0.000024 0.000000 -0.074713 -0.468207 -0.076639 0.089998 -0.112483 -0.123723 -0.080655 0.053414 -0.018453 -0.401629 -0.356334 -0.067169 0.048983 0.146550 0.002374 -0.280391 0.095736 0.372699 0.061857 -0.047934 -0.001001 0.000000 -0.004190 -0.050995 -0.023464 -0.007904 -0.200398 -0.138610 -0.039938 -0.023338 -0.008356 0.140939 0.054435 0.134404 0.008619 -0.075890 -0.132794 -0.597853 -0.284111 0.146095 0.010497 -0.041276 -0.000799 0.000000 0.043979 0.562571 0.688972 0.284837 0.066012 -0.015490 0.219387 0.256626 0.144906 0.229716 0.027453 0.155313 -0.029938 -0.035654 0.048713 0.204974 0.120956 0.079596 0.113584 0.040859 0.000625 0.000000 0.012803 0.293015 0.644834 0.346351 0.097940 0.070279 0.262613 0.516506 0.168117 -0.065341 0.017045 0.246959 0.409173 0.152464 0.046742 0.155759 0.342470 0.183070 0.029666 0.008864 0.000104 0.000000 0.000351 0.033238 0.238613 0.450503 0.468271 0.477934 0.631913 0.659302 0.567083 0.494110 0.520426 0.687487 0.633419 0.458075 0.536762 0.607256 0.462638 0.138626 0.007420 0.000029 0.000000 0.000000 0.000000 0.000362 0.012722 0.077196 0.237632 0.482398 0.730520 0.797115 0.830222 0.841155 0.818945 0.812469 0.736513 0.656449 0.500489 0.254071 0.061756 0.005215 0.000051 -0.000000 0.000000 0.000000 0.000000 0.000000 -0.000046 -0.001124 0.033965 0.078266 0.056143 0.049783 0.060067 0.067830 0.067440 0.062540 0.074396 0.073314 0.052201 0.032974 0.004522 -0.000205 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 0.000767 0.009595 0.022034 0.019946 0.003257 0.001163 0.010633 0.012902 0.011121 0.007760 0.019801 0.022663 0.010964 0.001478 0.000009 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000074 0.001142 0.003541 0.000691 -0.000497 0.002616 0.003542 0.002654 0.001262 0.003712 0.002056 0.000190 0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000003 0.000001 -0.000002 0.000003 0.000005 0.000004 0.000001 0.000003 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000002 -0.000008 -0.000004 -0.000000 0.000002 -0.000002 -0.000011 -0.000013 -0.000004 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000002 -0.000051 -0.000263 -0.000404 -0.000132 0.000046 0.000106 -0.000076 -0.000543 -0.000919 -0.000563 -0.000113 -0.000006 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000004 -0.000080 -0.000426 -0.000743 -0.000663 -0.000146 0.000219 0.000306 -0.000057 -0.000884 -0.002133 -0.002510 -0.001524 -0.000389 -0.000024 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000005 0.000011 -0.000143 -0.000187 0.000165 0.000153 0.000048 0.000227 0.000304 0.000150 -0.000048 -0.000447 -0.001343 -0.002616 -0.002194 -0.000553 -0.000025 -0.000000 0.000000 0.000000 -0.000000 0.000001 0.000054 0.000229 0.000175 0.000191 0.000844 0.002107 0.004748 0.010933 0.005611 0.000743 0.000086 0.000264 0.000171 -0.000670 -0.002418 -0.002148 -0.000416 -0.000008 0.000000 0.000000 0.000001 0.000061 0.000233 0.000406 0.000897 0.002707 0.008255 0.004297 -0.016166 0.022255 -0.003063 -0.016579 -0.027392 -0.019449 -0.003582 0.000167 -0.000572 -0.002520 -0.001660 -0.000142 -0.000000 0.000000 0.000025 0.000562 0.000867 0.001041 0.005855 -0.002730 -0.026076 -0.050641 -0.091772 -0.067144 -0.063272 -0.045952 -0.074947 -0.067286 -0.016485 -0.000269 0.000279 -0.001175 -0.002611 -0.000695 -0.000009 0.000000 0.000069 0.000969 0.001117 0.000787 -0.001228 -0.012584 -0.087153 -0.047847 -0.023429 -0.038777 -0.077137 -0.034754 -0.014463 0.023368 0.021949 0.014290 0.010844 0.000431 -0.002042 -0.001188 -0.000034 0.000000 0.000035 0.000442 -0.001494 -0.002203 0.039620 0.271325 -0.196379 -0.223807 -0.095493 0.113725 -0.316382 -0.209180 -0.002680 0.132111 0.039562 0.062150 0.071833 0.010797 -0.000613 -0.000781 -0.000035 0.000000 0.000067 -0.001503 -0.016854 0.024556 0.124249 0.203713 -0.201757 -0.380282 -0.188922 0.867630 0.159073 -0.108659 0.127665 0.595610 0.237587 0.073088 0.157543 0.038564 -0.000019 -0.000226 -0.000015 0.000000 0.000054 -0.009272 -0.042444 0.010754 0.084056 -0.024479 -0.101570 -0.205502 -0.135206 0.523346 0.266297 -0.212288 -0.067566 0.403338 0.147067 0.047194 0.164014 0.036651 -0.000565 0.000051 -0.000001 0.000000 0.000022 -0.010481 -0.031815 0.046985 0.254355 0.082358 -0.002457 -0.011308 -0.005373 0.074243 0.068488 0.020551 -0.304436 -0.099408 0.040532 0.039129 0.172674 0.042127 -0.001504 -0.000016 -0.000005 0.000000 0.000063 -0.005190 0.008756 0.069657 0.206745 0.107921 0.014913 0.002367 0.037433 0.070432 0.210292 0.918109 0.456733 0.119006 0.064373 0.055415 0.224094 0.046568 -0.003032 -0.000206 -0.000014 0.000000 0.000037 -0.008702 -0.042644 -0.023243 0.018864 0.174357 0.079028 0.017145 0.300386 0.406335 0.414617 0.316123 0.244485 0.017824 -0.006539 0.084606 0.151645 -0.020753 -0.003185 -0.000491 -0.000025 0.000000 0.000003 -0.005506 -0.065631 -0.113667 -0.044151 0.041187 -0.000353 0.089732 0.678106 0.610323 0.504011 0.112071 0.116329 0.047753 0.015700 0.121746 0.051235 -0.038001 -0.001664 -0.000511 -0.000012 0.000000 -0.000001 -0.001031 -0.029216 -0.113640 -0.136411 -0.067640 -0.002494 0.124659 0.403889 0.036961 -0.009218 0.005545 -0.024858 0.034790 0.004090 0.002061 -0.016784 -0.011441 -0.000610 -0.000140 -0.000001 0.000000 -0.000001 -0.000005 -0.002511 -0.026975 -0.079564 -0.110043 -0.069457 -0.025832 -0.035799 -0.213605 -0.231546 -0.159059 -0.187439 -0.132592 -0.124416 -0.066379 -0.005398 -0.000610 -0.000191 -0.000010 -0.000000 0.000000 0.000000 0.000006 0.000130 -0.000241 -0.006306 -0.017406 -0.023492 -0.024989 -0.019426 -0.017272 -0.023173 -0.040728 -0.059220 -0.048839 -0.026697 -0.005535 -0.000237 -0.000171 -0.000018 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000005 -0.000245 -0.000059 0.004472 -0.000245 0.001276 0.001820 0.002468 0.007266 0.009604 0.005517 0.002918 -0.001228 -0.000665 -0.000152 -0.000008 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000013 0.000414 0.001530 -0.000356 0.000280 0.002411 0.001231 0.001177 0.000883 0.001288 0.001778 0.001187 0.000310 -0.000005 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000007 0.000038 -0.000020 0.000024 0.000766 0.000490 0.000272 0.000068 0.000236 0.000344 0.000101 0.000013 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000001 0.000001 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000011 -0.000041 -0.000023 -0.000003 0.000007 -0.000016 -0.000061 -0.000070 -0.000022 -0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000010 -0.000270 -0.001428 -0.002210 -0.000697 0.000101 0.000431 -0.000544 -0.002908 -0.004844 -0.002986 -0.000605 -0.000034 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000019 -0.000445 -0.002424 -0.004040 -0.003683 -0.000836 0.000612 0.001167 -0.000585 -0.005112 -0.011390 -0.013272 -0.008085 -0.002052 -0.000130 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000029 0.000105 -0.000739 -0.001634 0.000856 0.000802 0.000121 0.000967 0.001579 0.000863 -0.000851 -0.002521 -0.006881 -0.013630 -0.011550 -0.002939 -0.000135 -0.000000 0.000000 0.000000 -0.000000 0.000008 0.000354 0.001354 0.000854 0.000896 0.008895 0.023909 0.049870 0.098175 0.056264 0.017364 0.003185 0.001961 0.001369 -0.003438 -0.012924 -0.011389 -0.002199 -0.000044 0.000000 0.000000 0.000005 0.000346 0.001320 0.002295 0.008174 0.024854 0.129750 0.094270 -0.144211 -0.017903 -0.049005 0.057176 -0.067558 -0.088004 -0.021562 -0.000119 -0.003274 -0.013148 -0.008666 -0.000744 -0.000001 0.000000 0.000112 0.002659 0.004071 0.009948 0.082451 0.019768 -0.206826 -0.505999 -0.971340 -1.087515 -0.706075 -0.090131 -0.380009 -0.460155 -0.162290 -0.010882 0.001693 -0.006187 -0.013737 -0.003674 -0.000048 0.000000 0.000289 0.004114 0.003187 0.002441 -0.018869 -0.214275 -0.953704 -0.508124 -0.275089 -0.358470 -0.387166 0.099474 -0.028692 0.000292 0.106411 0.152425 0.122501 0.006359 -0.011294 -0.006425 -0.000184 0.000000 -0.000026 -0.000496 -0.045953 -0.087662 0.235762 2.998640 -2.056103 -2.880007 -1.724543 0.370661 -2.714791 -1.915446 -0.453287 0.512147 0.115836 0.568499 0.718185 0.079128 -0.004195 -0.004371 -0.000191 0.000000 0.000191 -0.024635 -0.212750 0.085040 0.754510 4.142094 -0.496659 -4.205101 -3.138939 6.855853 1.060979 -2.019833 -0.010578 3.427191 1.152342 0.436744 1.195640 0.186671 -0.004542 -0.001214 -0.000079 0.000000 0.000217 -0.115662 -0.464302 0.226826 0.594916 0.391778 -0.161737 -1.921010 -1.486681 5.339230 3.152231 -1.699295 -0.089958 3.571919 1.401415 0.317659 1.381212 0.160919 -0.030460 0.000240 -0.000014 0.000000 -0.000144 -0.197735 -0.554876 0.022654 0.972259 0.353460 -0.025431 -0.137224 -0.067454 0.799783 0.408409 -2.051021 -4.538812 -1.938978 0.117493 0.320447 1.723974 0.127436 -0.078206 -0.000456 -0.000046 0.000000 -0.000270 -0.244916 -0.516587 0.211274 0.780401 0.466768 0.085553 0.015360 0.417938 1.129516 1.068290 3.267268 0.673362 0.010932 0.255177 0.495355 2.067670 0.101765 -0.088582 -0.001334 -0.000089 0.000000 -0.000285 -0.169020 -0.680347 -0.241162 -0.103367 0.786557 0.443995 0.024178 1.642061 3.073207 2.460260 1.430241 1.136697 0.121392 0.003195 0.778839 1.378796 -0.493414 -0.066359 -0.002884 -0.000146 0.000000 -0.000051 -0.072784 -0.743874 -1.134477 -0.473335 0.201367 -0.189318 -0.035313 2.216740 2.291884 1.853896 0.446809 0.750556 0.238099 0.181208 1.220336 0.338269 -0.612303 -0.026776 -0.002737 -0.000066 0.000000 -0.000005 -0.012663 -0.359922 -1.319435 -1.315523 -0.378931 -0.054130 0.473195 1.300158 -0.544043 -0.707716 0.075464 0.403203 0.654249 0.211043 0.088963 -0.257405 -0.173263 -0.004648 -0.000767 -0.000004 0.000000 -0.000002 -0.000423 -0.042071 -0.386028 -0.972827 -1.238146 -1.244981 -1.048517 -0.898485 -1.644750 -1.835650 -1.189025 -1.134003 -1.230910 -1.496134 -0.859954 -0.088433 -0.007543 -0.001118 -0.000058 -0.000000 0.000000 0.000000 0.000025 0.000292 -0.012391 -0.108802 -0.289453 -0.445562 -0.513589 -0.333965 -0.213866 -0.301728 -0.462119 -0.593600 -0.588006 -0.347432 -0.088558 -0.007222 -0.001187 -0.000095 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000025 -0.001772 -0.019234 -0.024039 -0.015905 0.004085 0.021321 0.017412 0.032199 0.046585 0.042280 0.031435 -0.004297 -0.018921 -0.005186 -0.000148 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 -0.000000 0.000059 -0.000369 -0.012667 -0.013471 0.005723 0.007526 0.006687 0.000886 0.005102 0.008215 0.003140 -0.000922 -0.000416 -0.000002 0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000023 0.000029 -0.001586 -0.003402 0.001637 0.002618 0.001282 -0.001205 0.000334 0.001418 0.000333 0.000034 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 -0.000004 0.000003 0.000007 0.000002 -0.000004 -0.000002 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000005 -0.000017 -0.000007 -0.000000 -0.000001 -0.000010 -0.000023 -0.000023 -0.000007 -0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000003 -0.000081 -0.000512 -0.000901 -0.000285 -0.000146 -0.000120 -0.000448 -0.001038 -0.001551 -0.000898 -0.000193 -0.000012 -0.000000 0.000000 0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000005 -0.000166 -0.000891 -0.001148 -0.001036 -0.000146 -0.000450 -0.000305 -0.000457 -0.001974 -0.003588 -0.003608 -0.002280 -0.000575 -0.000037 -0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000009 0.000092 0.000184 -0.000614 0.001111 0.000967 0.000387 0.000297 0.000969 0.000871 -0.000775 -0.000885 -0.000946 -0.002680 -0.002915 -0.000843 -0.000039 -0.000000 0.000000 0.000000 -0.000000 0.000006 0.000100 0.000292 0.000713 0.002977 0.018816 0.036198 0.060259 0.082378 0.065175 0.072969 0.022426 0.002043 0.000885 0.000805 -0.003185 -0.003266 -0.000631 -0.000012 0.000000 0.000000 0.000000 0.000071 0.000250 0.000983 0.024342 0.249052 0.494900 0.179480 -0.132740 -0.327472 -0.127561 0.348489 0.147651 0.001551 -0.008578 -0.000916 -0.000668 -0.003271 -0.002284 -0.000199 -0.000000 0.000000 -0.000003 -0.000024 0.000387 0.018183 0.159195 0.282547 -0.099568 -0.895308 -1.224391 -1.572826 -0.977374 -0.135605 -0.224523 -0.281839 -0.133464 -0.032996 -0.002256 -0.001366 -0.003890 -0.001099 -0.000013 0.000000 0.000050 -0.000141 -0.005957 -0.004372 -0.132400 -0.437446 -1.028703 -0.692288 -0.385214 -0.344577 0.019724 0.518870 0.075013 -0.033399 0.134790 0.135201 0.119396 0.005393 -0.004318 -0.002097 -0.000057 0.000000 -0.000082 -0.005032 -0.128162 -0.079307 0.163436 3.178423 -3.412495 -3.354543 -2.863145 -0.117623 -0.714761 -1.501292 -1.198790 -0.267170 0.245374 0.901587 0.828762 0.020899 -0.002794 -0.001418 -0.000064 0.000000 0.000054 -0.054586 -0.435682 -0.009681 0.784202 9.738048 5.084347 1.481015 -0.520909 6.497286 5.481081 -3.957286 -3.715250 -0.310975 -0.568897 -0.128522 1.442693 0.093857 -0.020356 -0.000250 -0.000032 0.000000 0.000032 -0.228494 -0.775852 0.452086 0.635765 2.850054 3.538846 3.617173 3.175481 6.770648 7.124166 -0.851195 0.335141 2.965624 0.504303 -0.590925 2.060244 -0.124473 -0.166085 -0.000222 -0.000038 0.000000 -0.000764 -0.503857 -1.097574 0.701646 0.679129 0.158941 0.044137 0.196358 0.268769 1.090998 0.762311 -3.162685 -5.654525 -2.729783 0.255138 0.253282 2.540438 -0.575394 -0.371174 -0.000521 -0.000052 0.000000 -0.001665 -0.642738 -1.544744 0.061939 0.573412 0.346851 0.051446 0.000360 0.331454 1.367989 -0.145245 -0.571349 -2.736207 -1.563236 -0.075877 0.575984 2.907003 -0.583738 -0.396366 -0.000633 -0.000052 0.000000 -0.001023 -0.388066 -1.242268 -0.213397 -0.259638 0.139758 0.564224 0.025930 -0.190973 1.246327 0.685577 0.369433 0.435493 0.257977 0.052550 1.040841 2.188468 -1.180851 -0.216243 -0.001307 -0.000059 0.000000 -0.000104 -0.152735 -1.249866 -1.316463 -0.685322 -0.191338 0.651109 -0.021812 -1.360083 -1.491950 -0.183748 0.165997 0.318065 0.021639 0.304650 1.988191 0.540864 -1.658780 -0.095816 -0.000659 -0.000020 0.000000 -0.000033 -0.030435 -0.758604 -2.283986 -1.635842 0.106347 0.446531 0.993891 0.341680 -0.360546 0.065798 0.653052 1.359128 1.572175 0.976526 0.544318 -0.485144 -0.477781 -0.009002 -0.000163 -0.000001 0.000000 -0.000003 -0.001559 -0.121109 -0.948133 -2.060844 -2.387044 -2.552567 -1.793394 -1.883093 -2.247883 -2.141382 -1.722661 -1.300820 -1.699075 -2.688183 -1.833837 -0.269293 -0.022750 -0.000415 -0.000013 0.000000 0.000000 0.000001 0.000014 -0.001121 -0.045987 -0.270605 -0.733930 -1.192361 -1.300149 -0.980831 -0.627278 -0.776753 -1.259353 -1.484771 -1.404344 -0.927038 -0.273155 -0.021977 -0.000298 -0.000040 -0.000000 0.000000 0.000000 0.000000 0.000002 -0.000001 0.002193 0.019962 0.004913 -0.020920 -0.022222 0.015941 0.012204 0.010285 0.011435 0.015170 0.004841 -0.044037 -0.053613 -0.012695 -0.000086 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000429 0.001617 -0.003194 -0.008699 -0.012596 0.003751 0.002224 0.004021 0.003577 -0.001137 0.001791 -0.004158 -0.004087 -0.000863 -0.000005 0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 -0.000006 -0.000024 -0.000921 -0.002396 0.001099 0.000292 0.000861 0.000808 -0.000986 0.000171 0.000001 -0.000019 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000001 0.000001 0.000001 0.000002 0.000001 -0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000005 0.000020 0.000015 0.000004 0.000002 0.000012 0.000032 0.000035 0.000011 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000006 0.000163 0.000868 0.001251 0.000471 0.000028 -0.000028 0.000498 0.001836 0.002641 0.001682 0.000340 0.000017 0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000014 0.000301 0.001474 0.003282 0.002692 0.000618 -0.000510 -0.001007 0.000322 0.003510 0.006709 0.008173 0.004699 0.001148 0.000076 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000011 0.000000 0.001216 0.001843 0.001997 0.001450 -0.000059 -0.000736 -0.000938 -0.000206 0.000963 0.002070 0.005531 0.008669 0.006989 0.001791 0.000083 0.000000 -0.000000 0.000000 -0.000000 -0.000002 -0.000078 -0.000391 0.000627 0.003158 0.013466 0.029471 0.075479 0.037679 0.025812 0.066864 0.030291 0.002078 0.000538 0.003927 0.008562 0.006825 0.001325 0.000026 -0.000000 0.000000 0.000000 0.000018 0.000134 0.000201 0.020562 0.240718 0.405775 0.128655 0.294212 0.104817 -0.056754 0.196329 0.190815 0.026034 -0.007837 -0.003809 0.001891 0.007858 0.005189 0.000458 0.000001 0.000000 -0.000013 -0.000084 0.000199 0.016880 0.089151 0.179333 -0.148023 -0.797300 -0.564852 -0.260589 -0.499839 -0.133464 0.270932 0.097330 0.040497 -0.001676 -0.010019 0.003238 0.007848 0.002130 0.000029 0.000000 -0.000076 -0.000588 -0.004534 0.026574 -0.021248 -0.413341 -0.498053 -0.401873 -0.220752 -0.071149 0.115959 1.464223 1.081924 0.242703 0.604546 0.421552 -0.008577 -0.011353 0.005971 0.003616 0.000106 0.000000 -0.000081 -0.004625 -0.096706 -0.031219 0.143737 0.507461 -0.627190 -0.215950 -0.733753 -0.145289 1.049832 1.931836 1.183154 -0.585408 0.513751 1.067079 0.166300 -0.112579 0.000858 0.002555 0.000107 0.000000 -0.000005 -0.046884 -0.296875 0.157780 0.215511 2.814222 2.702307 4.490922 2.458507 1.226069 3.821454 -3.993181 -5.902229 -6.584562 -1.954355 -0.428794 0.766538 0.110124 -0.032200 0.000496 0.000026 0.000000 -0.000229 -0.168458 -0.448415 -0.056723 -0.152727 1.178847 1.750785 3.924052 3.387371 1.504164 2.448409 -1.393966 -2.926973 -7.694614 -2.978856 -0.919280 1.746103 -0.002648 -0.235548 -0.000077 -0.000024 0.000000 -0.000736 -0.300002 -0.480146 0.369875 -0.103494 0.358373 0.060535 0.208079 0.220882 0.070886 0.329857 5.060002 5.421911 0.166464 -0.585031 0.003841 2.340225 -0.067865 -0.407387 -0.000288 -0.000022 0.000000 -0.001037 -0.276891 -0.495399 0.119743 -2.644830 -0.125656 0.326372 0.036127 0.212220 0.002279 -0.846000 0.851772 1.817496 1.248029 -0.167632 -0.129639 2.661202 -0.453535 -0.604698 -0.000521 0.000016 0.000000 -0.000719 -0.316464 -0.861501 -0.743143 -7.265113 -4.391304 1.495634 0.656666 0.409420 -1.394306 -1.327472 -0.225049 0.231688 1.261671 0.818476 0.442915 2.498008 -0.969999 -0.405104 0.001018 0.000068 0.000000 -0.000212 -0.182909 -1.217760 -0.971675 -3.720473 -6.169981 0.571658 1.253106 0.571256 -0.268299 0.283922 -0.256858 -1.194112 -0.550186 0.574917 1.672983 1.181615 -2.077204 -0.207064 0.001852 0.000039 0.000000 -0.000018 -0.043432 -0.876529 -1.965801 -1.164236 -1.255330 -0.575869 1.143588 1.861613 2.021069 0.923161 0.043579 -0.045977 0.861076 1.351616 1.117769 -0.281707 -0.792028 -0.025999 0.000531 0.000003 0.000000 0.000002 -0.002365 -0.184065 -1.213261 -2.380134 -2.615651 -2.535826 -1.439512 -1.450701 -2.138424 -2.339267 -2.203656 -1.495709 -1.127242 -2.387049 -2.095156 -0.476708 -0.053096 0.000376 0.000037 0.000000 0.000000 0.000001 0.000003 -0.003765 -0.099574 -0.523494 -1.180661 -1.733175 -1.850306 -1.618921 -1.141303 -1.331693 -1.968456 -2.237015 -2.083805 -1.452427 -0.472051 -0.037435 0.000413 0.000041 0.000000 0.000000 0.000000 0.000000 0.000002 -0.000046 -0.006139 -0.009299 0.020188 -0.028795 -0.038292 -0.017934 -0.025947 -0.070303 -0.093123 -0.104647 -0.090434 -0.068354 -0.053485 -0.012281 -0.000069 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 -0.000267 0.000972 0.007382 0.004956 0.004234 0.000847 0.000351 -0.004362 -0.010534 -0.001173 -0.000495 -0.003221 -0.003904 -0.000937 -0.000007 0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000004 0.000048 0.000533 0.001293 -0.000006 0.000420 -0.000613 -0.002842 0.000425 0.000326 -0.000014 -0.000007 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000001 0.000002 -0.000001 -0.000000 -0.000002 -0.000006 0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000004 -0.000017 -0.000007 0.000007 0.000003 -0.000006 -0.000023 -0.000026 -0.000008 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000004 -0.000097 -0.000490 -0.000829 -0.000230 0.000280 -0.000108 -0.000279 -0.001076 -0.001839 -0.001093 -0.000227 -0.000014 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000010 -0.000168 -0.001015 -0.001469 -0.001394 -0.000528 -0.000253 -0.001347 -0.001356 -0.001498 -0.004441 -0.005051 -0.003178 -0.000799 -0.000049 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 0.000022 0.000060 -0.000336 -0.000621 0.000114 0.000020 -0.000411 -0.000964 -0.001443 -0.001653 -0.000020 -0.001161 -0.002546 -0.005360 -0.004304 -0.001080 -0.000051 -0.000000 -0.000000 0.000000 -0.000000 0.000008 0.000367 0.001105 0.000004 0.001176 0.009279 0.021215 0.113917 0.120531 0.030898 0.012563 0.010843 0.003374 0.000889 -0.001158 -0.004893 -0.004417 -0.000848 -0.000018 -0.000000 0.000000 0.000000 -0.000009 0.000393 0.000731 0.009089 0.110122 0.246104 0.060327 0.495839 0.609465 -0.061797 -0.056132 0.112708 0.060787 -0.003790 -0.003281 -0.002617 -0.006163 -0.003603 -0.000317 -0.000000 0.000000 0.000032 0.000240 -0.000410 -0.017743 -0.013261 0.141937 -0.105258 -0.816194 -0.792226 -0.425553 -0.755669 -0.345048 0.010994 -0.010149 -0.021907 -0.014887 -0.009768 -0.004983 -0.006037 -0.001448 -0.000018 0.000000 0.000184 0.001816 0.003403 -0.283777 -0.687316 -0.228743 -0.343217 -0.389020 -0.295375 -0.182838 -0.144607 0.515933 0.503055 0.008149 0.203996 0.315938 0.025418 -0.016611 -0.003683 -0.002392 -0.000070 0.000000 0.000152 0.001458 0.018304 -0.502761 -0.511986 0.179921 -0.004265 0.007348 -0.013778 -0.009215 0.134554 1.695329 1.989180 -0.142601 0.104311 0.988161 0.124585 -0.134719 -0.004435 -0.001869 -0.000080 0.000000 0.000034 -0.010641 -0.038677 -0.920550 0.407423 0.837912 0.051843 0.181966 0.113804 0.151414 -1.306946 -3.280385 -1.504834 -4.367549 -1.244649 -0.352966 -0.670019 0.105222 -0.028747 -0.001369 -0.000056 0.000000 -0.000184 -0.058331 -0.110314 -2.005770 0.856055 2.104167 0.117195 0.128886 0.117495 0.883511 0.938684 -0.790910 1.526901 -8.445780 -2.109156 -0.081393 -0.343587 0.282278 -0.192922 -0.000631 -0.000028 0.000000 -0.000293 -0.078591 -0.114677 -5.400051 -3.148712 4.204696 0.625694 0.013446 0.005375 0.752946 4.690268 11.405011 14.910517 1.704067 1.099155 0.687209 0.617262 0.864188 -0.199011 -0.000829 -0.000023 0.000000 -0.000270 -0.058506 -0.031550 -4.684559 -7.279905 5.679326 3.507884 0.609339 0.113941 0.011094 0.572193 2.353080 4.609488 2.976157 3.196961 -0.050068 1.756754 0.352973 -0.565893 -0.003737 -0.000047 0.000000 -0.001018 -0.237043 -0.665427 -2.387485 -13.536360 -3.512270 8.956763 5.165773 0.726075 -1.107599 -0.498005 -0.665596 1.998639 4.120838 -0.587646 -2.038170 2.549433 -0.335258 -0.620644 -0.003998 -0.000071 0.000000 -0.000704 -0.225680 -1.290956 -1.072810 -7.802504 -13.196600 1.681078 5.786306 0.344258 -1.806194 -0.979425 -4.435802 -6.508667 -4.545925 -2.362045 0.472726 2.119156 -1.633725 -0.348691 -0.001354 -0.000027 0.000000 -0.000080 -0.070343 -1.076652 -1.782140 -1.478403 -4.902365 -4.225922 -0.408634 0.947745 0.961408 -0.373909 -2.039696 -5.992652 -3.722650 0.609917 1.356062 0.300034 -0.984192 -0.072385 -0.000280 -0.000002 0.000000 -0.000001 -0.005805 -0.274924 -1.421896 -2.401352 -2.591815 -2.186481 -1.374093 -1.217171 -2.180993 -2.555989 -2.068000 -1.507463 -0.816471 -1.749145 -2.316567 -0.702258 -0.101505 -0.002153 -0.000020 -0.000000 0.000000 0.000000 -0.000074 -0.009048 -0.165938 -0.767419 -1.628698 -2.258298 -2.431441 -2.246082 -1.720723 -1.879799 -2.647568 -2.985040 -2.832267 -2.106834 -0.827350 -0.093842 -0.000610 -0.000028 -0.000000 0.000000 0.000000 0.000000 0.000000 -0.000041 -0.000225 0.009551 -0.001712 -0.072331 -0.116273 -0.096380 -0.046734 -0.069689 -0.160605 -0.226942 -0.188718 -0.099355 -0.053308 -0.012402 -0.000185 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000356 0.003684 0.008164 0.008904 0.002492 -0.007682 -0.017232 -0.007131 -0.000002 -0.003475 -0.001118 0.001350 -0.002265 -0.000730 -0.000005 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000009 0.000261 0.000971 0.000546 -0.001991 -0.005843 -0.002885 0.000457 -0.000243 -0.000114 0.000499 0.000053 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000002 -0.000011 -0.000007 0.000002 0.000001 -0.000001 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000006 -0.000022 -0.000008 0.000004 -0.000003 -0.000009 -0.000031 -0.000034 -0.000010 -0.000000 0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000005 -0.000129 -0.000680 -0.001118 -0.000301 0.000170 -0.000212 -0.000272 -0.001469 -0.002497 -0.001505 -0.000303 -0.000018 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000016 -0.000214 -0.001104 -0.002417 -0.002304 -0.000721 -0.000403 -0.000987 -0.000739 -0.002441 -0.006384 -0.007173 -0.004119 -0.001027 -0.000067 -0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000024 0.000145 -0.000166 0.000019 -0.001200 -0.001382 -0.000135 -0.000268 -0.000795 -0.000220 -0.000110 -0.001639 -0.004062 -0.006770 -0.005805 -0.001490 -0.000067 -0.000000 0.000000 0.000000 0.000000 0.000003 0.000257 0.001639 0.001444 0.001926 0.006215 0.032191 0.159833 0.232681 0.109399 0.031476 0.024062 0.008294 0.000350 -0.002476 -0.007332 -0.005995 -0.001168 -0.000024 0.000000 0.000000 0.000001 0.000071 0.000184 0.000339 0.006984 0.100047 0.213885 0.150167 0.900423 1.119567 0.226227 -0.019031 0.256227 0.159390 0.002978 -0.002082 -0.003343 -0.007674 -0.004745 -0.000408 -0.000001 0.000000 0.000004 0.000022 -0.000433 -0.010784 0.084982 0.321856 -0.150557 -1.244683 -1.353433 -1.445644 -1.517844 -1.077972 -0.488647 -0.192279 -0.113472 -0.004783 -0.000467 -0.004522 -0.007422 -0.001904 -0.000025 0.000000 0.000032 0.000253 -0.004950 -0.615954 -0.602310 1.427812 0.004179 -0.645430 -0.623467 -0.600365 -0.495720 -0.388431 -0.442936 -0.953517 -0.544168 0.254814 0.028397 0.005019 -0.005131 -0.003267 -0.000095 0.000000 0.000011 0.001942 -0.005465 -1.999472 0.460843 3.917395 0.250371 -0.025614 -0.003337 -0.067734 -0.111891 0.086229 0.018278 -2.016571 -1.653550 0.417818 -0.722194 -0.055799 -0.006233 -0.002500 -0.000101 0.000000 -0.000024 0.001089 -0.115449 -3.411902 3.183975 5.124695 -0.075150 -0.041896 -0.003588 0.026410 -0.246926 -0.382479 0.214091 -2.901735 -3.735754 -1.551837 -3.674943 -0.308987 -0.040163 -0.001140 -0.000048 0.000000 -0.000197 -0.042425 -0.337384 -4.439080 2.756618 6.798573 0.460262 -0.049385 -0.001046 1.132692 4.856099 1.512320 1.155505 -3.819757 -2.799332 0.975096 -5.001605 -0.424529 -0.169984 -0.001101 -0.000020 0.000000 -0.000462 -0.065662 0.128730 -3.293743 -0.036515 9.096493 2.660110 0.182671 0.020825 1.325592 6.892455 4.130056 2.370322 -2.096514 -0.187914 -2.947093 -4.432365 0.695043 -0.072870 -0.001778 -0.000017 0.000000 -0.002031 -0.154640 0.401747 -1.813199 -4.024387 9.307814 8.173243 3.160393 1.493069 0.799849 1.166962 1.611957 0.747744 1.447602 3.591886 -6.604799 -1.706362 0.746844 -0.544429 -0.010137 -0.000043 0.000000 -0.002239 -0.290596 -0.379835 -0.506221 -3.894546 3.249247 11.016184 11.586901 7.338048 4.376111 -0.090068 -0.293454 4.604359 3.065391 -1.935073 -5.301883 1.773780 0.316960 -0.893055 -0.014172 -0.000084 0.000000 -0.000982 -0.317458 -1.398223 -0.443078 -3.166368 -6.284559 1.012132 9.088381 4.491159 1.990427 -1.248262 -10.634696 -6.460293 -6.289659 -7.412576 -1.223253 2.819723 -0.889109 -0.569207 -0.003853 -0.000036 0.000000 -0.000138 -0.130230 -1.427123 -1.646075 -1.578750 -6.309255 -5.527339 0.854784 1.611533 1.158806 0.401433 -4.671242 -8.415401 -6.359960 -1.352350 1.276278 0.989967 -1.167635 -0.186530 -0.000483 -0.000002 0.000000 -0.000003 -0.013727 -0.444344 -1.751845 -2.644242 -3.302241 -2.823693 -1.233189 -0.624009 -2.288429 -2.608387 -1.970604 -1.595909 -0.631027 -0.672215 -2.344150 -0.988831 -0.200544 -0.009810 -0.000031 0.000000 0.000000 0.000001 -0.000112 -0.020462 -0.295388 -1.162563 -2.231190 -2.893215 -2.991413 -2.918805 -2.663307 -2.756589 -3.338356 -3.694173 -3.652832 -2.789516 -1.391622 -0.213851 -0.002685 -0.000043 0.000000 0.000000 0.000000 0.000000 0.000002 -0.000082 -0.005351 -0.015347 -0.079355 -0.229171 -0.279076 -0.230305 -0.162737 -0.201743 -0.367346 -0.483144 -0.415029 -0.209181 -0.077373 -0.013648 -0.000028 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000002 0.000033 0.002907 0.009085 0.014743 0.015843 0.003868 -0.006835 -0.006295 0.007006 0.001944 0.000585 -0.000391 -0.002545 -0.000754 -0.000002 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000009 0.000409 0.002397 0.003802 0.002107 -0.000030 -0.000502 0.004329 0.002125 0.000767 0.000254 0.000024 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000003 0.000004 0.000002 0.000001 0.000010 0.000004 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000002 -0.000007 0.000000 -0.000001 -0.000003 -0.000007 -0.000014 -0.000016 -0.000005 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 -0.000002 -0.000047 -0.000277 -0.000481 -0.000198 -0.000027 0.000053 -0.000117 -0.000551 -0.001117 -0.000737 -0.000142 -0.000008 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000014 -0.000174 -0.000260 -0.000694 -0.001484 -0.000461 0.000078 -0.000020 -0.000189 -0.000737 -0.002383 -0.003162 -0.001799 -0.000497 -0.000037 -0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 -0.000015 -0.000164 -0.000873 -0.000346 0.000015 -0.000871 0.000008 -0.000304 -0.001296 0.000173 -0.000092 0.000165 -0.000784 -0.002811 -0.002991 -0.000758 -0.000029 0.000000 0.000000 0.000000 -0.000000 0.000003 -0.000192 -0.000578 0.000226 0.000109 0.002254 0.044641 0.182962 0.190672 0.102375 0.039295 0.021052 0.006594 0.001176 -0.001189 -0.003753 -0.002858 -0.000622 -0.000012 0.000000 0.000000 -0.000000 -0.000089 -0.000988 -0.006843 -0.069784 -0.094470 0.056911 0.282633 1.617467 1.427023 0.367108 -0.002140 0.292907 0.295404 0.068965 0.002359 -0.000766 -0.003200 -0.002370 -0.000195 -0.000000 0.000000 -0.000022 -0.000480 -0.002588 -0.137954 -0.611403 0.439543 0.860790 -1.081172 -1.226535 -1.281737 -2.000210 -1.831270 -0.463309 0.276923 -0.042198 0.333277 0.103836 0.001811 -0.003204 -0.000907 -0.000012 0.000000 -0.000251 -0.002160 -0.067440 -0.838024 0.609861 7.128364 4.846394 0.121385 -0.912430 -0.901947 -0.871274 -0.812735 -1.364179 -5.050043 -4.149297 1.374609 1.388235 0.146002 -0.002721 -0.001691 -0.000047 0.000000 -0.000530 -0.003387 -0.259972 -2.946615 1.809736 11.016210 3.049153 -0.433994 -0.101712 -0.240853 -0.343907 -0.027296 -1.175352 -7.646537 -3.846600 0.454392 -0.083579 0.291364 -0.006600 -0.000891 -0.000044 0.000000 -0.000219 0.007715 -0.083957 -3.381876 2.638806 9.735936 1.063575 -0.921190 -0.108157 -0.140032 -0.435380 -0.142976 -0.682436 -5.906352 -0.283491 2.279060 -5.139561 -0.705453 -0.063950 -0.000189 -0.000020 0.000000 -0.000311 -0.050277 -0.236558 -4.233992 -0.107388 9.418773 3.136409 -0.495188 -0.065813 0.024066 0.008288 -0.071224 -0.744631 -4.695415 0.281896 0.098262 -7.144182 -0.905758 -0.114723 -0.001129 -0.000000 0.000000 -0.001852 -0.222423 -0.329697 -2.921215 -1.888223 8.382087 7.337530 1.785705 0.505793 0.225254 0.306461 -0.573340 -1.097859 -1.555456 2.066296 -3.630718 -5.756015 0.931155 0.061423 -0.001756 0.000013 0.000000 -0.006461 -0.566162 -0.446221 -0.610593 -2.912761 4.874397 10.231234 8.372265 5.870800 1.835174 0.206631 -0.544870 -0.659930 0.631420 0.050894 -10.368121 -4.604626 1.157267 -0.517824 -0.022613 -0.000021 0.000000 -0.005946 -0.601283 -0.655257 0.473622 -1.553214 1.051916 5.870450 10.501691 10.480989 3.239163 -1.937065 1.069147 2.931088 0.536253 -3.855770 -9.915214 -0.383668 0.873140 -1.287495 -0.044679 -0.000045 0.000000 -0.001668 -0.457678 -1.495187 0.090604 -0.194599 -0.947768 -0.148437 4.255181 3.824962 1.405726 -1.237800 -6.197168 -3.203439 -4.850225 -7.177477 -3.226471 2.828215 0.039378 -0.920355 -0.013973 -0.000017 0.000000 -0.000184 -0.243965 -2.032832 -1.471866 -0.048423 -2.821563 -4.554495 0.542042 2.824863 1.665643 1.320209 -3.398577 -5.982440 -7.962325 -3.257517 1.216224 1.748187 -1.376899 -0.460904 -0.000947 -0.000001 0.000000 -0.000000 -0.035806 -0.822604 -2.307045 -2.530292 -3.047860 -3.200063 -1.051616 0.277554 -1.395142 -2.503551 -1.210820 -0.543394 -0.279339 0.167686 -1.863859 -1.311280 -0.405792 -0.041289 -0.000024 0.000000 0.000000 0.000002 -0.000389 -0.053589 -0.530945 -1.643694 -2.645739 -2.885141 -3.060691 -3.394918 -3.437192 -3.541717 -2.909064 -2.518793 -3.387535 -3.466932 -2.244668 -0.484069 -0.012948 -0.000055 0.000000 0.000000 0.000000 0.000000 0.000006 -0.000172 -0.010570 -0.080807 -0.215235 -0.337209 -0.452031 -0.439220 -0.288268 -0.329478 -0.390754 -0.444591 -0.632465 -0.512593 -0.197220 -0.026161 -0.000080 0.000003 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 -0.000032 0.000708 0.003454 -0.004891 -0.010072 -0.002162 0.007121 0.009138 -0.011029 -0.015630 -0.008895 -0.011004 -0.007678 -0.001547 -0.000004 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000018 -0.000002 -0.001426 -0.001570 0.000719 0.003378 0.005422 -0.000211 -0.001464 0.000653 -0.000030 -0.000003 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000001 -0.000001 0.000001 0.000005 0.000010 0.000000 -0.000002 0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000008 -0.000029 -0.000011 -0.000004 -0.000012 -0.000024 -0.000051 -0.000058 -0.000019 -0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000010 -0.000242 -0.001227 -0.001613 -0.000379 -0.000280 -0.000587 -0.000810 -0.002510 -0.004353 -0.002780 -0.000576 -0.000033 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 -0.000030 -0.000505 -0.002492 -0.004244 -0.003263 -0.000051 0.000006 -0.001730 -0.001589 -0.003880 -0.010187 -0.012319 -0.007530 -0.001854 -0.000112 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 -0.000010 -0.000539 -0.002868 -0.003881 -0.001748 -0.001169 0.000290 0.000709 -0.001669 -0.001023 -0.000644 -0.002065 -0.007164 -0.012683 -0.010369 -0.002717 -0.000121 0.000000 0.000000 0.000000 -0.000000 0.000004 -0.000016 -0.001325 -0.002747 -0.002988 -0.002264 0.021696 0.103869 0.127430 0.062475 0.019070 0.009834 0.001907 -0.001593 -0.004779 -0.012835 -0.011253 -0.002342 -0.000044 0.000000 0.000000 0.000003 0.000139 -0.000023 -0.013718 -0.163384 -0.275227 -0.193118 0.079192 1.185970 1.282616 0.233207 -0.039138 0.282713 0.305686 0.084641 -0.000407 -0.003180 -0.012953 -0.008319 -0.000701 -0.000001 0.000000 0.000059 0.001068 -0.005908 -0.377495 -1.312095 0.386581 1.215636 0.304400 -0.512146 -1.318980 -2.176281 -1.870382 -0.010124 0.317076 -0.664218 0.380311 0.185340 0.001909 -0.012307 -0.003458 -0.000044 0.000000 0.000193 0.000686 -0.328396 -2.227495 -1.188475 4.440034 6.398844 3.891140 0.888215 -0.323744 -0.531931 -1.036545 -1.301098 -5.383444 -4.517175 3.590667 3.090935 0.396507 -0.011485 -0.006657 -0.000186 0.000000 0.000140 -0.025113 -1.388897 -3.638442 -0.614924 5.723356 6.822925 0.995046 -0.271109 0.351597 0.491229 0.038078 -1.224945 -5.256121 -1.244613 1.931746 2.974784 0.745657 -0.061294 -0.004678 -0.000204 0.000000 0.000063 -0.089659 -1.177175 -2.437322 -0.846764 6.271636 7.627508 0.573265 -0.894061 0.057013 0.467907 0.156368 -0.533651 -2.385639 1.240963 1.580302 -1.234148 -0.730545 -0.274336 -0.002395 -0.000129 0.000000 -0.000447 -0.134931 -0.447531 -4.352320 -3.369022 5.362381 9.170855 3.125714 0.127705 0.046973 0.956240 0.552128 -0.477229 -1.296170 2.123249 4.557173 -2.296998 -0.456107 -0.094514 -0.001259 -0.000016 0.000000 -0.003751 -0.353660 -0.611821 -4.285137 -4.230661 3.117575 9.643977 8.204155 3.045166 0.101786 0.232728 -0.404404 -0.543825 -0.037130 2.370607 3.873063 -2.052298 1.319527 0.235038 -0.003039 0.000013 0.000000 -0.007739 -0.599229 -0.828462 -1.626779 -2.946774 0.841763 5.975466 10.160933 7.174285 1.219351 -0.661698 -4.173018 -1.331307 0.184943 2.207211 -1.447461 -3.648730 1.426456 -0.391987 -0.048089 -0.000091 0.000000 -0.008410 -0.690723 -0.819632 -0.004855 -1.662550 -0.094682 1.313033 4.038444 4.130391 0.567278 0.108339 -1.177661 -0.289490 0.095418 -0.463051 -10.073967 -3.136447 1.369844 -1.614805 -0.118500 -0.000176 0.000000 -0.004589 -0.726052 -1.786390 0.058642 -0.287103 -0.057477 0.184540 1.095468 0.680777 -0.146834 0.180917 -1.822821 -0.982105 -1.486507 -4.800234 -4.860393 1.789140 1.421997 -1.198173 -0.054538 -0.000067 0.000000 -0.000600 -0.436301 -2.692366 -1.613401 0.142674 -0.117005 -0.352680 1.027426 1.477101 0.336111 0.879927 -1.373241 -2.794241 -4.331940 -4.611965 0.590117 2.400708 -0.997516 -0.875378 -0.007976 -0.000005 0.000000 0.000028 -0.082008 -1.360343 -3.004199 -2.296755 -1.475218 -1.705083 -0.774532 0.296756 -2.396784 -2.881080 -1.206568 -0.532731 0.512183 0.778479 -0.914633 -1.390129 -0.662794 -0.137277 -0.000420 0.000000 0.000000 0.000013 -0.001548 -0.130482 -0.914400 -2.042370 -2.218690 -1.629108 -1.595153 -2.714187 -4.043985 -3.711850 -2.362737 -0.881750 -1.268443 -3.164632 -3.035356 -0.955698 -0.053124 -0.000583 0.000004 0.000000 0.000000 0.000002 0.000038 -0.000261 -0.022313 -0.145554 -0.196496 -0.132809 -0.221728 -0.460445 -0.482589 -0.295863 -0.183235 -0.292727 -0.514506 -0.729889 -0.367802 -0.047583 -0.000344 0.000025 0.000001 0.000000 0.000000 0.000000 0.000003 0.000016 -0.000080 -0.001816 0.000124 0.003487 -0.001367 -0.004152 -0.008330 -0.014716 -0.015704 -0.026691 -0.032664 -0.026547 -0.012546 -0.002313 0.000010 0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000002 0.000010 0.000239 0.000249 -0.000120 0.000011 -0.000348 -0.000548 -0.000548 -0.002407 -0.001856 -0.000618 -0.000029 0.000004 0.000001 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000001 0.000001 0.000001 0.000001 -0.000002 -0.000002 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000026 -0.000168 -0.000124 -0.000009 -0.000012 -0.000067 -0.000209 -0.000213 -0.000054 -0.000001 -0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000015 -0.000459 -0.002871 -0.005930 -0.002937 -0.000420 -0.000792 -0.002304 -0.008204 -0.012823 -0.007526 -0.001592 -0.000090 -0.000000 -0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000030 -0.000662 -0.003694 -0.008723 -0.009044 -0.003093 -0.000538 -0.001992 -0.003713 -0.013077 -0.029049 -0.034492 -0.022124 -0.005583 -0.000320 -0.000001 0.000000 0.000000 0.000000 -0.000000 -0.000002 0.000039 -0.000279 -0.002778 -0.004488 -0.003083 -0.001625 -0.000554 0.000197 -0.000469 -0.001619 -0.003031 -0.006886 -0.020867 -0.038894 -0.029514 -0.007371 -0.000358 -0.000000 0.000000 0.000000 -0.000000 0.000024 0.000900 0.001315 -0.001552 -0.000172 0.001872 0.006332 0.038394 0.055583 0.019663 0.010923 0.015103 0.001872 -0.003541 -0.013958 -0.034472 -0.028819 -0.005550 -0.000113 0.000000 0.000000 0.000001 0.000364 0.002729 0.013380 0.168553 0.625520 0.370420 0.070486 0.699416 0.836253 0.115908 0.200176 0.602499 -0.098022 -0.115407 -0.020371 -0.011761 -0.033545 -0.021914 -0.001936 -0.000003 0.000000 -0.000010 -0.000018 -0.002099 0.043842 0.972389 1.845266 -0.393631 -0.590858 0.278731 -0.892135 -1.855843 -2.025373 -1.243094 -1.966689 -1.991177 -0.992579 -0.219280 -0.027688 -0.034196 -0.008669 -0.000102 0.000000 -0.000142 -0.003329 -0.220360 -1.215678 -1.044789 -1.896256 -2.569407 0.502069 2.077810 -0.513170 -1.198978 -1.901020 -1.432643 -1.567947 -4.217552 -1.960229 -0.763518 -0.108456 -0.029755 -0.016900 -0.000595 0.000000 -0.000079 -0.070251 -1.381395 -0.681810 -0.163589 -1.676164 1.446231 2.559539 1.080047 0.109353 0.051384 -0.075783 -0.714130 -2.604711 -3.122839 1.010791 1.141493 -0.178835 -0.102775 -0.015531 -0.000840 0.000000 -0.000058 -0.337086 -1.915296 0.919231 0.269083 0.539932 4.397253 4.328013 0.053478 -0.101779 0.058124 0.016452 -0.711288 -1.601294 -0.147423 2.306919 2.577194 -0.768701 -0.486090 -0.007922 -0.000370 0.000000 -0.001394 -0.510664 -0.482841 -0.778735 -2.501184 0.492748 4.717620 6.414245 1.279133 -0.208023 0.544073 0.281423 -0.687298 -0.831455 0.577205 1.928774 -0.077605 0.163917 -0.177742 -0.009037 -0.000036 0.000000 -0.006811 -0.581024 -0.483953 -2.935020 -3.104789 0.172686 3.175514 7.013366 3.203685 -0.457740 1.456715 1.085626 -0.002309 -0.244629 1.014540 1.896949 -3.045804 1.915423 0.398292 -0.024092 -0.000087 0.000000 -0.017508 -0.686448 -0.707602 -2.300013 -2.246071 -0.028960 0.969517 3.274976 1.282466 -0.692638 0.439699 -0.306036 0.475606 0.094635 1.869622 0.458715 -6.083794 1.786696 -0.138995 -0.117454 -0.000781 0.000000 -0.025912 -0.960675 -0.539042 0.497222 -0.781031 -0.093940 0.075949 0.217955 -1.213956 -0.985517 0.336816 -0.718988 -0.161953 0.067249 0.701306 -7.847390 -6.414742 1.710917 -1.613811 -0.270355 -0.001202 0.000000 -0.015943 -1.109347 -1.675640 0.838236 -0.088245 -0.228537 0.235411 0.340267 0.470481 0.666016 0.897797 -0.677749 -0.296860 -0.534776 -3.340620 -5.750414 0.053768 2.694601 -1.220242 -0.167142 -0.000930 0.000000 -0.002793 -0.740701 -2.980663 -0.974268 0.311375 0.600480 2.104200 1.496737 1.038955 0.158503 0.492534 0.563410 -0.571928 -3.096323 -6.369394 -0.853792 2.422372 -0.030049 -1.262052 -0.051212 -0.000469 0.000000 0.000557 -0.165746 -1.903621 -3.045057 -1.417863 -0.800531 -0.267067 0.276703 -0.013336 -2.529659 -2.670163 0.006029 -0.769929 -1.616874 -1.341362 -0.200902 -1.257664 -1.046381 -0.348234 -0.008595 -0.000151 0.000000 0.000242 -0.002360 -0.257515 -1.382728 -1.990893 -1.469487 -1.393856 -0.980755 -1.420547 -3.114694 -3.099636 -2.756996 -1.882129 -1.132190 -2.131494 -3.335458 -1.643109 -0.174595 -0.004429 -0.000455 -0.000018 0.000000 0.000036 0.000693 0.000716 -0.053961 -0.136907 0.002940 -0.075502 -0.190013 -0.289104 -0.362394 -0.248405 -0.905153 -1.312079 -0.936273 -0.598130 -0.482002 -0.085847 0.000849 0.000651 0.000028 -0.000000 0.000000 -0.000002 0.000007 0.000225 0.000167 0.000146 0.003307 -0.006277 -0.010824 -0.004528 -0.013635 -0.023451 -0.027018 -0.035267 -0.029223 -0.015376 -0.007791 -0.000763 0.000337 -0.000007 -0.000014 -0.000000 0.000000 -0.000001 -0.000006 -0.000004 0.000016 0.000070 0.000098 -0.000183 -0.000378 0.000315 -0.002815 -0.003608 -0.000073 -0.000265 -0.000647 -0.000074 0.000110 0.000040 -0.000003 -0.000011 -0.000002 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000001 0.000001 -0.000001 -0.000007 -0.000007 -0.000001 -0.000001 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000030 -0.000268 -0.000213 -0.000004 -0.000023 -0.000155 -0.000486 -0.000435 -0.000088 -0.000002 -0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000001 -0.000002 -0.000158 -0.003235 -0.010584 -0.005578 0.000008 -0.001050 -0.005209 -0.016864 -0.022492 -0.010990 -0.002196 -0.000116 -0.000002 -0.000000 -0.000000 0.000000 0.000000 -0.000000 0.000001 0.000003 -0.000029 -0.000250 0.000045 -0.007913 -0.016197 -0.006058 0.000697 -0.001262 -0.007316 -0.023826 -0.046224 -0.052498 -0.034606 -0.009266 -0.000583 -0.000003 -0.000000 -0.000000 0.000000 -0.000000 -0.000002 -0.000002 -0.000498 -0.001838 -0.000708 -0.000728 -0.000546 0.000060 0.001298 0.001457 -0.001743 -0.003504 -0.009498 -0.033874 -0.067534 -0.048814 -0.010754 -0.000495 -0.000001 -0.000000 0.000000 0.000002 0.000050 0.001005 -0.000494 -0.001847 -0.000111 0.002601 0.007723 0.033634 0.036614 0.013949 0.008280 0.006412 0.001152 -0.003468 -0.023444 -0.051610 -0.038670 -0.007380 -0.000170 -0.000000 0.000000 0.000000 -0.000450 0.001789 0.019895 0.238295 0.856508 0.843001 0.428668 1.091226 1.283223 0.628529 0.575085 0.437518 -0.202492 -0.096451 -0.015017 -0.016598 -0.047552 -0.031360 -0.002318 -0.000002 0.000000 -0.000207 -0.005582 0.000954 0.494929 2.030817 2.251177 0.203088 -1.354958 -0.941198 -0.761989 -1.435935 -2.078622 -3.269101 -3.540841 -2.386861 -1.451590 -0.302381 -0.037106 -0.045160 -0.009264 -0.000067 0.000000 -0.000271 -0.002622 0.105093 -0.349164 -2.671171 -5.551242 -6.780863 -5.816668 -3.367043 -2.633378 -2.634164 -3.733040 -4.127307 -0.648060 -4.523059 -7.144889 -2.940420 -0.392984 -0.041620 -0.021219 -0.000710 0.000000 0.000363 -0.001982 0.395586 -1.993795 -6.330825 -4.465230 -2.680263 -1.394856 -0.569045 -0.401821 -0.208457 -0.369802 -1.501606 -1.976407 -3.759890 -5.378847 -2.917073 -0.942591 -0.079029 -0.023968 -0.001252 0.000000 -0.000113 -0.272273 -0.391507 -0.701768 -4.221751 -0.896619 0.153542 1.122625 0.390736 -0.092143 -0.008428 -0.071783 -1.910334 -2.781485 -1.620195 -2.627767 0.257827 -0.302091 -0.401337 -0.018029 -0.000654 0.000000 -0.004495 -0.757833 -0.340177 0.042009 -2.823133 -0.161491 0.323559 1.003480 -0.372803 -0.347164 0.135808 0.007609 -1.714770 -1.158648 0.157379 -0.457663 0.187257 1.044502 -0.635675 -0.060363 -0.000080 0.000000 -0.018197 -0.905135 -0.154387 -2.038855 -2.682675 -0.038557 0.139733 0.376843 -0.531707 0.221072 0.773965 1.656754 0.392380 -0.297599 0.242905 1.241919 0.032875 2.996419 -0.391786 -0.178186 -0.000190 0.000000 -0.039523 -1.107786 -0.360664 -1.574275 -2.038175 -0.034905 0.003998 -0.451861 -1.877934 -0.679265 -0.125155 1.019868 1.465747 0.051975 0.346015 -0.478083 -3.998745 1.986185 -0.720745 -0.376074 -0.001762 0.000000 -0.051643 -1.369618 -0.439905 0.354362 -1.296005 -0.112790 0.024522 -0.366793 -1.762684 -0.452295 0.345904 -0.423806 -0.079845 0.029615 0.488284 -4.215324 -4.760516 1.946967 -1.863698 -0.622037 -0.003429 0.000000 -0.041431 -1.650568 -1.310488 1.068641 -0.784779 -0.112871 0.186062 0.046457 0.406945 1.641922 1.390467 -0.234168 -0.284992 0.003733 -1.227052 -4.697869 -0.743771 3.677163 -1.389601 -0.483936 -0.003201 0.000000 -0.002716 -1.195550 -3.167179 -0.241814 0.490578 1.215818 2.379975 2.328846 2.045546 1.363294 0.006537 -1.236521 -1.595054 -4.426181 -7.509726 -1.779725 1.956615 1.455222 -1.611491 -0.207567 -0.001674 0.000000 0.014335 -0.201013 -2.344711 -2.540070 -0.781188 -0.497278 0.360936 1.089253 1.365137 -1.199381 -1.813110 -0.397502 -1.285818 -5.126138 -5.598703 0.151643 -0.713298 -0.999353 -0.620266 -0.037135 -0.000475 0.000000 0.005923 0.069682 -0.241457 -1.542850 -1.821284 -2.174509 -3.253929 -2.484977 -0.949231 -1.782215 -2.698383 -2.021872 -1.940174 -2.102368 -1.638301 -2.731161 -2.129971 -0.241293 0.021582 0.001568 -0.000023 0.000000 0.000944 0.017496 0.064660 0.026813 0.017235 -0.193462 -1.047317 -1.150700 -0.450630 -0.073810 -0.706330 -1.891350 -2.414509 -1.659603 -0.561428 -0.388457 -0.026420 0.076033 0.017216 0.001174 0.000007 0.000000 0.000036 0.001076 0.006656 0.016618 0.028072 0.026056 -0.024557 -0.064419 -0.029266 -0.001214 -0.011912 -0.072834 -0.103981 -0.048847 0.012232 0.031129 0.025400 0.009670 0.001353 0.000024 -0.000001 0.000000 -0.000002 -0.000011 0.000107 0.000460 0.001123 0.002343 -0.001426 -0.010398 -0.005843 0.000745 0.003502 0.002583 -0.000689 -0.000112 0.003165 0.002299 0.000973 0.000190 -0.000024 -0.000009 -0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000001 0.000001 -0.000009 -0.000007 0.000001 0.000008 0.000006 0.000002 0.000003 0.000002 0.000001 0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000002 0.000111 0.000517 0.000344 0.000036 0.000004 0.000162 0.000487 0.000568 0.000180 0.000005 -0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000081 0.002469 0.012992 0.020726 0.009799 0.001157 0.000091 0.006076 0.024178 0.040736 0.026613 0.005683 0.000326 0.000001 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000003 0.000133 0.003304 0.020283 0.042254 0.034022 0.012044 0.001901 0.000103 0.007236 0.040093 0.098003 0.121120 0.074032 0.017838 0.001019 0.000004 0.000000 0.000000 0.000000 0.000000 0.000005 -0.000150 0.000242 0.009605 0.017810 0.013436 0.004952 0.001001 0.000556 0.000036 -0.001516 0.003512 0.021864 0.067656 0.121438 0.097977 0.026158 0.001290 0.000002 0.000000 0.000000 0.000003 -0.000075 -0.002308 -0.004896 0.002452 0.002315 0.000643 0.001242 0.009145 0.014282 0.008490 0.002825 -0.000170 -0.000127 0.003457 0.038619 0.120310 0.107634 0.020691 0.000405 0.000000 0.000000 -0.000009 -0.001995 -0.008872 -0.001251 0.080333 0.421784 0.753309 0.677337 0.804584 1.330939 1.305026 0.774589 0.158367 -0.057280 -0.010778 0.002051 0.040527 0.125669 0.080948 0.007667 0.000014 0.000000 -0.000374 -0.008613 -0.004393 0.456549 2.017494 3.732409 3.493616 1.523586 -0.843460 -1.359178 -0.911984 -1.243962 -3.265118 -1.497549 -0.419071 -0.409266 -0.070769 0.063391 0.130284 0.036282 0.000507 0.000000 -0.000776 -0.005467 0.117879 0.992136 -0.909612 -5.184000 -7.406929 -6.855771 -6.346684 -7.086286 -6.929171 -6.930120 -5.619049 4.060781 1.888656 -3.790030 -2.025930 -0.198490 0.099517 0.062062 0.002105 0.000000 -0.000127 0.076627 0.721640 -3.194241 -8.990636 -10.458493 -7.800816 -4.654047 -2.411864 -1.255752 -1.078995 -1.881029 -2.447549 0.979468 2.381763 -2.167768 -5.167513 -1.428401 -0.009659 0.046597 0.002534 0.000000 -0.000435 0.186403 1.387335 -2.442183 -3.843648 -2.078223 -0.714871 0.735823 -0.041852 -0.330977 -0.033340 -0.949501 -5.362271 -5.252260 -2.086004 1.318543 -0.606894 -0.728219 -0.164806 0.008044 0.001054 0.000000 -0.009749 -0.455203 0.332732 -1.994187 -3.330018 -0.166928 0.135669 0.847738 -0.123240 0.210196 0.114684 0.433205 -2.742872 -1.314155 -0.102207 -0.894705 0.163572 2.297776 -0.208003 -0.078443 0.000117 0.000000 -0.033793 -0.899649 0.751932 -2.648348 -3.866923 -0.097730 0.067797 0.025934 -0.225895 0.638409 -0.976541 3.217433 2.393527 -0.121583 0.023739 -1.649374 -0.650044 4.165926 -0.075125 -0.257487 0.000153 0.000000 -0.032088 -0.058042 1.198501 -0.850463 -1.470794 -0.038393 0.000969 -0.608092 -1.889270 -1.099004 -3.324096 -0.694008 1.410548 0.020877 0.071885 -0.116512 -1.891643 1.607401 0.445403 -0.318613 0.001191 0.000000 -0.031175 0.185855 0.736376 -0.222948 -0.668109 -0.100265 0.007927 -0.463235 -1.806033 -0.745376 -0.046161 -0.400141 -0.191046 0.011834 0.039338 -0.305293 -2.814152 -0.528241 -0.113006 -0.382869 0.001135 0.000000 -0.066121 -1.320296 -0.442273 0.743519 -0.966064 -0.139126 0.160036 0.064719 -0.297928 0.082886 0.626258 -0.376152 -0.420190 -0.052246 -1.926233 -3.712284 -0.443952 2.437868 -0.119476 -0.421249 -0.000103 0.000000 -0.035618 -1.685502 -2.772724 0.272858 0.174883 1.668471 3.538264 2.536822 0.331163 0.082888 -0.413008 -2.582301 -1.559023 -2.655650 -6.338984 -3.777290 1.492306 2.732718 -1.327205 -0.401586 -0.000300 0.000000 0.010274 -0.398890 -2.530541 -2.023418 -0.678910 1.814478 5.169657 3.151524 0.855789 -1.136440 -0.357936 -0.281419 -0.863781 -2.986842 -4.291292 -0.102712 -0.130243 -0.963930 -0.994411 -0.095041 -0.000010 0.000000 0.006019 0.051751 -0.400201 -1.486544 -1.546543 -1.522706 -2.157506 -1.661980 -1.019558 -2.442242 -2.466753 -1.658558 -2.268003 -1.741484 -0.869993 -1.308725 -2.080572 -0.622675 -0.017842 0.002460 0.000038 0.000000 0.000972 0.017875 0.059997 -0.003039 -0.095280 -0.507022 -1.570799 -1.631990 -0.896430 -0.711699 -1.289589 -2.354638 -3.045609 -1.903750 -0.681425 -0.285022 -0.006706 0.073159 0.017621 0.001266 0.000010 0.000000 0.000050 0.001235 0.006968 0.016795 0.023599 0.011858 -0.029935 -0.055366 -0.032313 -0.009924 -0.045196 -0.133652 -0.163546 -0.086463 -0.011003 0.019012 0.024779 0.010061 0.001605 0.000081 0.000000 0.000000 -0.000000 0.000010 0.000142 0.000483 0.001102 0.002102 0.000503 -0.004068 -0.004140 0.001903 0.001700 0.000099 -0.000206 -0.001042 0.002283 0.002178 0.001000 0.000232 0.000011 -0.000002 -0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000001 0.000001 -0.000004 -0.000003 0.000005 0.000004 0.000001 0.000001 0.000000 0.000002 0.000001 0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000001 0.000003 0.000007 -0.000000 -0.000005 -0.000001 -0.000010 -0.000011 -0.000003 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000003 -0.000044 -0.000269 -0.000531 -0.000035 0.000213 0.000092 0.000156 -0.000443 -0.000798 -0.000347 -0.000056 -0.000003 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000010 -0.000115 -0.000313 -0.000739 -0.001615 -0.000215 0.001114 0.000585 0.000135 -0.000861 -0.002002 -0.001627 -0.001048 -0.000312 -0.000028 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000003 -0.000179 -0.000366 0.000274 -0.000348 -0.000935 -0.000001 0.000237 0.000286 -0.000720 -0.001049 -0.000902 -0.001767 -0.002223 -0.001888 -0.000489 -0.000018 -0.000000 -0.000000 0.000000 0.000000 -0.000007 -0.000013 -0.000021 -0.000209 0.000542 0.000289 0.000635 0.001219 0.002047 0.001597 0.000744 0.000403 0.000549 -0.000725 -0.001364 -0.002224 -0.001658 -0.000296 -0.000005 -0.000000 0.000000 -0.000001 -0.000349 -0.001367 0.000174 0.010279 0.080351 0.232870 0.395550 0.524684 0.949966 1.017160 0.422108 0.053202 -0.002040 0.000332 0.000153 -0.001472 -0.002293 -0.001231 -0.000074 -0.000000 0.000000 -0.000046 -0.001394 -0.000287 0.145457 0.934016 2.600730 3.919927 4.237124 2.720106 2.471735 2.984802 0.616388 -1.464682 -0.269676 0.016509 -0.018723 -0.004177 -0.001483 -0.001995 -0.000419 -0.000005 0.000000 -0.000150 -0.001489 0.123312 1.747775 1.828035 -1.146274 -2.444448 -2.993951 -5.478592 -9.769768 -9.151976 -8.385841 -4.157163 3.557293 1.284808 -0.854121 -0.654103 -0.072388 -0.002062 -0.000690 -0.000001 0.000000 -0.000055 0.044732 0.354564 -0.374270 -6.907071 -14.108701 -11.262941 -7.567580 -4.278642 -4.708162 -4.916180 -6.233369 -1.919307 3.881762 1.137130 -3.353019 -5.342493 -1.252025 -0.054901 -0.000660 -0.000006 0.000000 -0.001110 0.303450 0.682747 -3.161406 -3.222029 -4.677885 -2.409158 -0.014861 -0.247411 -0.695331 -1.091734 -4.749538 -6.979928 -4.859475 -6.154181 -6.309931 -6.399675 -2.206334 0.033962 0.012931 -0.000023 0.000000 -0.022293 -0.244320 1.125110 -0.009814 -2.436630 -0.518205 0.099209 1.712665 1.449713 0.365644 -1.217129 0.163382 -0.370076 -0.630595 -2.805186 -3.220149 -0.277178 1.813553 1.642930 0.078410 0.000016 0.000000 -0.013142 0.969872 4.252460 -0.908526 -2.987985 -0.142796 0.100866 0.954683 1.030798 0.058055 -2.545091 2.392010 3.316757 0.169797 -0.327702 -0.050667 1.453397 5.152627 3.982337 0.133577 0.000005 0.000000 0.078156 4.725776 8.624575 -1.106687 3.356252 1.308506 0.021957 -0.050634 -0.888445 -1.549832 -2.913080 -0.395896 0.634395 -0.001003 -0.792814 -3.619202 -5.910218 -0.868978 5.521106 0.403171 -0.000023 0.000000 0.149752 5.771354 6.072118 -2.410902 3.331184 0.910842 -0.028622 -0.459517 -1.856303 -1.558332 0.094212 1.076926 -0.009420 -0.015928 -1.872279 -9.896897 -13.987917 -10.361601 3.289400 0.491624 -0.000054 0.000000 0.123395 3.549220 0.820861 -1.902713 1.739743 0.227678 0.079188 0.039887 -0.650493 -0.860259 0.444215 0.522048 -0.383795 -0.128704 -2.735429 -5.177686 -7.023278 -10.120065 -1.690664 -0.069679 -0.000108 0.000000 0.004119 0.164453 -0.413168 -1.026033 -2.637946 -0.200227 2.555335 2.359079 0.521716 0.003086 -0.183524 -1.314156 -1.037350 -2.021751 -5.981925 -3.945625 -0.538130 -1.448563 -1.977309 -0.449392 -0.000211 0.000000 -0.003182 -0.241404 -1.402941 -2.196760 -2.646249 0.139787 3.836999 3.478991 1.199976 -0.174111 0.519808 0.697333 0.331066 -1.399163 -2.954638 -0.404306 -0.239088 -1.411450 -1.034502 -0.125238 -0.000031 0.000000 0.000249 -0.023574 -0.558852 -1.501354 -0.998327 0.120915 0.229893 -0.521059 -0.962858 -1.546408 -1.051507 -0.498954 -0.696943 0.097095 -0.058768 -0.520315 -1.815473 -1.068885 -0.108318 -0.002154 0.000003 0.000000 0.000043 0.000585 -0.015305 -0.121504 -0.169837 -0.347009 -1.075355 -1.456679 -0.941349 -0.705719 -0.722769 -0.919805 -1.116488 -0.631000 -0.374587 -0.314622 -0.190021 -0.027423 0.000333 0.000057 0.000000 0.000000 0.000002 0.000056 0.000303 0.000561 0.002629 -0.006342 -0.058698 -0.073799 -0.024733 -0.015572 -0.036868 -0.056011 -0.061489 -0.043056 -0.019625 -0.011439 -0.001553 0.000434 0.000074 0.000004 0.000000 0.000000 0.000000 0.000001 0.000007 0.000021 0.000064 0.000204 -0.000064 0.000444 0.001198 -0.000563 -0.002367 -0.001300 -0.001094 -0.000353 0.000101 0.000121 0.000044 0.000011 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000001 0.000003 -0.000002 -0.000005 -0.000004 -0.000002 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000001 -0.000028 -0.000110 -0.000067 -0.000010 -0.000006 -0.000049 -0.000154 -0.000171 -0.000052 -0.000001 0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000024 -0.000707 -0.004013 -0.006316 -0.002701 -0.000504 -0.000169 -0.001765 -0.007431 -0.012218 -0.007417 -0.001522 -0.000088 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000058 -0.001126 -0.006092 -0.013670 -0.012271 -0.003978 -0.000614 0.000282 -0.001986 -0.012194 -0.029509 -0.034323 -0.020963 -0.005224 -0.000324 -0.000001 0.000000 0.000000 0.000000 -0.000000 0.000000 0.000058 -0.000249 -0.003476 -0.005194 -0.004522 -0.002155 -0.000628 -0.000662 0.000446 0.000265 -0.001501 -0.007127 -0.020425 -0.036329 -0.029288 -0.007614 -0.000358 -0.000000 0.000000 0.000000 0.000000 0.000020 0.000728 0.001728 -0.000632 -0.000485 -0.000232 0.000079 0.000051 0.000314 0.000132 0.000150 0.000916 0.000047 -0.001965 -0.011939 -0.034455 -0.030448 -0.005884 -0.000116 0.000000 0.000000 0.000002 0.000028 0.000875 0.001272 -0.000022 0.002942 0.018651 0.066047 0.147940 0.297818 0.295240 0.095693 0.008647 0.000922 0.000285 -0.000195 -0.011822 -0.037653 -0.023284 -0.001999 -0.000003 0.000000 0.000020 -0.000513 -0.001669 0.014507 0.160433 0.680280 1.585943 2.755173 3.518782 4.517578 4.129662 1.317214 -0.299450 -0.035063 0.000179 0.001009 -0.000991 -0.019706 -0.036623 -0.009538 -0.000125 0.000000 -0.000075 -0.001130 0.049777 0.935878 2.557430 3.388844 3.791604 2.176846 -0.983822 -5.480223 -5.393807 -5.416571 -2.476263 1.224800 0.243075 -0.151984 -0.096232 -0.013136 -0.029444 -0.016483 -0.000471 0.000000 -0.000301 0.009431 0.495144 2.917143 1.585225 -4.100780 -5.296731 -8.169821 -8.440849 -11.942769 -11.683656 -8.792726 -0.453976 6.651864 4.198773 -3.899138 -2.794545 -0.225021 -0.026875 -0.012167 -0.000568 0.000000 -0.002772 0.021719 -1.089754 -4.798908 -4.993508 -6.758460 -5.440173 -3.424810 -2.107305 -2.514883 -3.026074 -3.626104 -3.788606 -0.209496 3.402826 -10.849889 -7.558864 -0.914362 0.268871 0.026874 -0.000324 0.000000 -0.042036 -0.417587 -0.713269 -2.474754 -1.328216 -0.679768 -0.494137 1.131753 1.370824 -0.218939 -3.096120 -1.340086 0.367660 -2.174023 -3.550909 -6.984911 -4.552832 -1.163099 1.649366 0.166875 -0.000041 0.000000 -0.018460 1.268292 7.518572 7.393468 3.587749 1.316114 0.125008 0.985748 0.918262 -0.724604 -3.145331 -1.066989 0.754952 -0.114554 -2.080202 -4.815679 -3.431340 0.792671 2.358534 0.138611 -0.000050 0.000000 0.027306 2.231827 10.892961 13.034341 13.856280 4.717644 0.105102 0.320503 -2.164139 -5.608120 -3.210116 0.028845 0.218402 -0.115104 -3.819386 -15.820107 -20.370516 -0.929824 3.148923 0.148661 -0.000305 0.000000 0.050561 1.884683 4.950062 0.347656 1.868252 1.950039 -0.020622 -0.330203 -3.367795 -6.421610 -1.493864 1.764438 0.418325 -0.113009 -4.794698 -22.174643 -26.240059 -4.630536 2.373888 0.141792 -0.000540 0.000000 0.161363 3.498527 -2.663816 -5.877717 4.530249 1.243272 0.018566 -0.168898 -1.079147 -1.434981 0.609127 1.433996 -0.121282 -0.241056 -3.913416 -8.754393 -15.495324 -10.298993 -2.097908 -0.152270 -0.000105 0.000000 0.100567 2.553302 0.702419 -5.542159 -2.109344 1.256489 3.243722 1.499218 -0.871309 -0.821498 0.075047 -0.831105 -1.175978 -2.646113 -5.564998 -1.579136 -3.412317 -5.797514 -2.533704 -0.101419 0.000125 0.000000 0.004156 0.125699 -0.185752 -1.533261 -1.124910 1.656565 4.549613 3.286089 -0.377237 -0.568831 -0.533001 -1.304206 -2.004969 -3.667987 -3.706345 -0.214701 -0.313439 -0.800715 -0.339331 -0.007772 0.000008 0.000000 -0.000001 -0.005954 -0.164933 -0.198464 0.219857 0.063320 -0.046559 -0.315376 -0.539556 -0.971822 -0.295701 0.410025 1.047875 1.065757 0.105402 0.189115 -0.170586 -0.381910 -0.035451 -0.000559 -0.000000 0.000000 -0.000001 -0.000155 -0.004868 0.008175 0.030454 -0.102001 -0.468835 -0.705954 -0.428112 -0.475495 0.040550 0.777318 1.427816 1.100528 0.289082 0.060034 0.007023 -0.011117 -0.000418 -0.000003 -0.000000 0.000000 -0.000000 -0.000004 -0.000025 0.000501 0.001859 -0.008361 -0.041999 -0.044454 -0.017817 -0.022045 0.008352 0.038402 0.059330 0.045112 0.014222 0.005335 0.000311 -0.000043 -0.000006 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000001 -0.000004 -0.000011 -0.000321 -0.001300 0.000064 -0.000173 -0.004089 -0.001721 -0.003069 -0.001253 0.000853 0.000397 0.000028 -0.000006 -0.000002 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000001 0.000001 -0.000003 -0.000002 -0.000005 -0.000002 0.000001 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000001 -0.000008 -0.000010 -0.000005 -0.000000 0.000002 0.000001 -0.000004 -0.000003 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 -0.000061 -0.000438 -0.000669 -0.000513 -0.000498 -0.000101 -0.000002 -0.000021 -0.000450 -0.000289 -0.000041 -0.000006 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 -0.000000 0.000005 0.000077 -0.000196 -0.001510 -0.001884 -0.001127 -0.000936 0.000090 -0.000072 -0.000133 -0.001194 -0.000762 -0.000309 -0.000003 -0.000001 -0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 -0.000004 0.000049 0.000400 0.000267 -0.000527 -0.000588 0.000111 -0.000069 0.000344 0.000173 -0.000142 -0.000359 -0.000477 -0.000562 0.000081 -0.000079 -0.000002 -0.000000 -0.000000 0.000000 0.000000 -0.000003 -0.000001 0.000005 -0.000348 -0.000044 0.000193 -0.000553 -0.000548 -0.000361 -0.000618 -0.000392 -0.000446 -0.000271 -0.000231 0.000098 0.001102 0.000215 -0.000067 -0.000007 -0.000000 0.000000 0.000000 -0.000128 -0.000408 0.000032 -0.000083 0.000588 0.000751 0.000280 0.007881 0.024065 0.021116 0.004314 0.000067 0.000770 0.000604 0.000436 0.000379 -0.001281 -0.001015 -0.000101 -0.000000 0.000000 0.000040 0.000047 -0.001043 0.000309 0.007683 0.045789 0.175761 0.580429 1.407514 2.138590 1.622608 0.456686 -0.013133 -0.000761 0.000526 0.000722 0.000089 -0.001638 -0.001156 -0.000206 -0.000004 0.000000 0.000280 0.001930 0.006558 0.180658 0.841020 1.802966 3.026740 3.296374 3.873044 2.052594 0.361905 -1.160869 -1.622844 -0.048920 0.009836 -0.014944 -0.006549 -0.000242 -0.000260 -0.000375 -0.000021 0.000000 0.000189 0.009172 0.432060 2.697338 3.717596 1.131845 1.060862 -2.770318 -7.193785 -14.007633 -13.879057 -7.585787 -5.771179 -0.203358 0.306134 -1.838172 -0.284344 0.156543 0.006918 -0.000629 -0.000054 0.000000 0.000349 -0.025886 -0.490623 -1.605150 -4.462279 -12.315600 -8.615550 -5.794617 -6.108810 -7.887523 -3.847580 0.026234 -8.021016 -4.957109 -3.770605 -8.388258 -2.034790 0.411049 0.212288 0.018005 -0.000066 0.000000 -0.019554 -0.085133 -3.070325 -6.024789 2.967187 -0.367607 -2.340495 -1.463009 -1.453254 -2.800535 0.849896 3.226947 -3.121476 -6.377883 -8.888848 -6.620177 -4.817375 -2.256436 0.028079 0.052349 0.000041 0.000000 -0.043493 -0.225664 -0.189321 -0.798413 4.185418 3.973888 0.171345 0.126801 -0.015045 -1.598263 -1.134272 0.963364 -0.027091 -1.212742 -6.157934 -4.570925 0.371128 -1.074850 -1.330701 -0.072139 0.000022 0.000000 -0.006600 -0.056466 -0.512093 -4.863825 -1.279964 1.685955 0.073089 0.409278 -0.171052 -2.620290 -0.901085 -0.303012 -0.106108 -0.367269 -5.792455 -3.500771 8.582527 0.569611 -0.797983 -0.037553 -0.000044 0.000000 -0.001361 -0.024455 -0.533402 -8.254787 -5.535962 0.932570 -0.019568 -0.033117 -0.670020 0.011783 1.815390 -0.979512 -0.119587 -0.344293 -6.931356 -7.333101 10.654191 0.429529 -1.664619 -0.165174 -0.001366 0.000000 0.000718 -0.044016 -1.753332 -4.168587 3.500235 2.368978 -0.344319 -0.322924 -1.013037 -0.736287 0.928043 0.353008 0.318141 -0.749125 -6.861981 -3.216561 9.624388 1.048993 -1.612947 -0.408430 -0.004789 0.000000 0.002292 -0.023817 -1.938452 -5.938379 2.714053 4.817579 3.402143 1.348712 -1.557078 -1.457747 1.223718 0.211402 -0.888522 -2.795290 -5.895831 -2.028659 0.036990 0.255313 0.133364 -0.156546 -0.002214 0.000000 0.000277 -0.024258 -0.093252 -0.084037 1.054745 2.541110 4.700537 2.588476 -0.428969 0.411649 0.429486 -0.995071 -1.433134 -3.395922 -4.166262 -2.279730 -1.077918 -0.102757 0.024224 -0.005403 -0.000097 0.000000 0.000026 0.005074 0.273222 1.171411 1.316468 1.057130 1.113492 0.938956 0.449479 0.088156 0.591366 2.031347 2.217381 0.918696 0.203924 1.243561 1.732586 0.539160 0.016265 -0.000110 -0.000003 0.000000 -0.000005 0.000028 0.016100 0.138064 0.248086 0.617875 1.475817 1.512848 0.564570 0.082513 0.877327 2.414844 3.069652 1.925161 0.778723 0.414472 0.213920 0.024684 0.000081 -0.000027 -0.000000 0.000000 -0.000001 -0.000020 -0.000113 -0.000253 0.000780 0.019111 0.077483 0.088953 0.029192 0.013069 0.055105 0.133516 0.165735 0.080469 0.027273 0.014060 0.002022 -0.000160 -0.000034 -0.000003 -0.000000 0.000000 -0.000000 -0.000001 -0.000004 -0.000013 -0.000021 0.000054 0.000764 0.001551 0.000835 0.001531 0.001861 -0.001231 0.000551 -0.000903 -0.000276 -0.000065 -0.000020 -0.000007 -0.000001 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000001 0.000001 0.000001 0.000002 0.000001 -0.000003 0.000001 -0.000001 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000022 0.000083 0.000042 0.000002 0.000007 0.000047 0.000133 0.000139 0.000041 0.000001 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000022 0.000542 0.002936 0.004487 0.001539 -0.000058 0.000324 0.001714 0.006407 0.009886 0.006074 0.001265 0.000069 0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 0.000056 0.001034 0.005208 0.009943 0.007858 0.001800 -0.000474 0.000377 0.002026 0.010361 0.023406 0.028569 0.017815 0.004521 0.000268 0.000001 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000036 0.000413 0.003675 0.005351 0.003270 0.000976 0.000151 -0.000489 -0.000398 0.000018 0.000795 0.004965 0.016792 0.030929 0.025142 0.006359 0.000304 0.000000 -0.000000 0.000000 0.000000 -0.000015 -0.000472 -0.000500 0.001687 0.001452 0.000601 0.000257 -0.000118 -0.000306 -0.000411 0.000342 0.000143 0.000464 0.001486 0.010779 0.031252 0.026089 0.004916 0.000092 -0.000000 0.000000 -0.000002 -0.000162 -0.000706 -0.000337 0.000658 0.000855 0.000995 0.000013 -0.000124 -0.000113 0.000190 0.000180 -0.000146 0.000500 0.000773 0.001587 0.011053 0.030228 0.018540 0.001592 0.000003 0.000000 -0.000018 -0.000189 0.000063 0.000837 0.000732 0.001292 0.006211 0.041270 0.198858 0.346544 0.224028 0.057810 0.002945 0.000726 0.000715 0.000600 0.001233 0.014913 0.029406 0.007822 0.000101 0.000000 0.000059 0.000066 0.000028 0.007601 0.070977 0.361699 0.979885 1.801410 3.327213 4.277043 2.602849 0.830341 -0.287636 -0.082734 -0.002472 -0.000150 0.000135 0.004159 0.024361 0.013503 0.000375 0.000000 0.000195 0.003328 0.110227 0.698336 1.598133 2.182385 4.127473 3.819511 -0.598121 -4.454487 -6.448802 -2.474275 -4.261897 -3.045227 -1.502425 -0.435898 0.164727 0.062687 0.014532 0.009255 0.000403 0.000000 0.007091 0.073596 0.570440 1.720165 0.846768 -4.807250 -5.134608 -5.811247 -9.578506 -13.121896 -12.472639 -3.799170 -7.242121 -8.454859 -10.327506 -3.714622 1.622419 1.044704 0.152644 0.000307 0.000202 0.000000 0.141811 1.161240 -1.238492 -5.553215 -1.687879 1.144999 -4.314400 -6.684767 -3.765967 -3.240205 -0.054262 3.506168 -5.533102 -7.503879 -10.029719 -7.841303 -3.592107 0.665181 0.087586 -0.070613 0.000303 0.000000 -0.071781 -2.123105 -7.798538 -7.812271 1.929412 4.813795 -0.477347 -0.727499 0.081987 -0.704064 0.997563 3.023518 -1.542423 -5.044614 -7.117980 -5.183318 0.582239 2.850399 -1.157836 -0.154692 0.000819 0.000000 -0.280103 -3.535222 -13.427979 -19.047865 4.033190 3.739824 -1.190034 0.338266 0.775565 -1.555193 -0.934948 -0.155869 -0.353732 -2.717813 -7.277293 5.415008 24.021080 6.092006 -3.269747 -0.358682 -0.001444 0.000000 -0.381083 -2.971650 -5.347907 -8.513877 9.622332 8.695637 0.086549 -0.127764 0.206636 0.024961 -1.366645 -2.496988 -0.344714 -1.736655 -5.959891 7.816548 31.402901 10.829469 -4.102165 -1.380532 -0.027458 0.000000 -0.579715 -7.405854 -1.114349 7.460748 12.029656 11.791763 1.267558 -1.047705 -1.587102 -1.982346 -0.449912 0.447367 0.393527 -2.949233 -6.944905 4.228493 17.631689 14.087245 2.607858 -1.550475 -0.048149 0.000000 -0.227220 -5.999367 -10.771445 -5.238609 -1.166072 8.789182 6.542229 0.906684 -1.638123 -2.342392 0.881567 1.508394 -1.361743 -5.468214 -4.914892 -1.723506 -6.136242 0.370056 3.419224 0.017380 -0.008873 0.000000 -0.009740 -0.644499 -1.682387 -0.529802 -1.133021 0.881283 4.692424 2.175560 -0.146000 -0.142730 0.490995 0.099667 -0.104325 -0.458255 -2.470706 -3.846420 -2.211612 0.428626 0.240667 0.026852 -0.000011 0.000000 0.000013 0.026853 0.765881 2.481668 2.103688 1.245549 2.387962 2.706558 1.290316 1.022965 1.174074 2.530176 2.920674 2.178902 1.415578 3.371888 3.499166 1.303994 0.070896 -0.000186 -0.000003 0.000000 -0.000006 0.000097 0.022276 0.180642 0.227301 0.583323 1.935770 2.461421 1.400584 1.040341 1.491933 2.474409 2.897690 1.599687 0.592709 0.585530 0.251239 0.026637 0.000179 -0.000024 -0.000000 0.000000 -0.000001 -0.000015 -0.000078 -0.000539 -0.003035 0.002263 0.048793 0.084571 0.034863 0.009774 0.036886 0.103144 0.117559 0.042428 0.004623 0.004714 0.001175 -0.000093 -0.000022 -0.000002 -0.000000 0.000000 -0.000000 -0.000000 -0.000002 -0.000007 -0.000032 -0.000245 -0.000848 -0.000791 -0.002450 -0.005952 -0.004531 0.000554 0.001100 -0.000510 -0.000766 -0.000098 -0.000011 -0.000003 -0.000001 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000001 -0.000001 -0.000005 -0.000005 0.000001 0.000002 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000001 0.000004 0.000001 0.000000 0.000001 -0.000000 0.000006 0.000007 0.000002 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000003 0.000057 0.000297 0.000340 0.000042 0.000015 -0.000017 -0.000109 0.000317 0.000509 0.000318 0.000054 0.000004 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000001 0.000010 0.000448 0.001298 0.000904 -0.000057 -0.000352 -0.000543 -0.000788 0.000239 0.001050 0.001772 0.001377 0.000374 0.000004 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000006 -0.000005 -0.000134 0.000083 0.000468 0.000305 -0.000568 -0.001046 -0.001097 -0.000296 0.000088 0.000227 0.001109 0.002401 0.001330 0.000358 0.000026 -0.000000 -0.000000 0.000000 0.000000 -0.000001 -0.000166 -0.000122 0.000223 0.000492 0.000323 -0.000208 -0.000719 -0.000539 -0.001056 0.000287 0.000857 0.000609 0.000280 0.000487 0.001853 0.001883 0.000321 0.000006 -0.000000 0.000000 -0.000000 0.000127 0.000224 -0.000050 0.000054 0.000576 0.000747 -0.000115 -0.000212 0.000020 -0.000422 -0.000576 -0.000544 -0.000305 0.000206 0.000330 0.001396 0.001910 0.001103 0.000102 0.000000 0.000000 -0.000032 -0.000092 0.000660 -0.000016 -0.000619 0.000206 0.000155 -0.000137 0.005334 0.015024 0.009621 0.001379 -0.000737 -0.000562 0.000124 0.000193 0.000279 0.000865 0.001853 0.000562 0.000003 0.000000 -0.000236 -0.002375 -0.001118 -0.000219 0.001101 0.019680 0.093506 0.329934 0.875282 1.617016 1.212113 0.421684 0.072338 -0.002591 0.000138 -0.000186 0.000041 0.000150 0.001492 0.000891 0.000012 0.000000 -0.000238 -0.002031 0.009958 0.093270 0.417308 1.156179 2.485096 3.222739 3.271981 3.792461 1.665481 1.387318 0.733601 -0.745782 -0.426496 0.025941 0.052525 0.011757 0.001238 0.000654 0.000023 0.000000 0.003628 0.088427 0.807659 2.471716 3.210592 2.949940 0.775011 -3.412349 -7.137603 -8.689211 -11.673376 -5.788201 -2.862428 -4.791212 -3.172578 0.933822 1.762782 0.921504 0.153281 -0.001303 0.000031 0.000000 0.191843 1.532884 1.519077 -0.509635 -3.612775 -2.454872 -4.762926 -8.681158 -6.229201 -1.897938 -3.233565 -2.745923 -7.518631 -7.769023 -6.140835 -4.743370 -2.157466 0.388632 0.222407 -0.089932 0.000167 0.000000 0.198514 -0.309664 -4.304257 -6.442860 -3.920429 -0.619537 -1.576256 -2.754358 -1.811849 1.920353 2.328624 0.592915 -4.530633 -8.703921 -5.386148 -7.891469 -9.952830 -6.426580 -2.452150 -0.257370 -0.000836 0.000000 -0.812731 -4.929363 -3.902237 0.352942 10.430737 4.151063 -2.690606 -0.730085 -0.855318 -1.272170 0.416209 -0.200428 -1.666107 -8.047635 -6.208522 0.741385 3.154966 0.500253 -5.276854 -0.592543 0.013986 0.000000 -2.166398 -11.366352 0.878689 6.533797 15.412325 9.030900 -1.383530 -0.613127 -1.148996 -2.853338 -1.738981 -0.663892 -1.061212 -6.872891 -3.908813 7.936512 8.152493 10.586600 2.424624 1.094188 0.097800 0.000000 -1.603879 -12.638786 1.447986 4.858364 4.646397 11.671051 4.879290 -1.905961 -3.793937 -5.168481 -2.465907 -0.225742 -2.343488 -7.979020 -3.342561 2.898225 -1.752343 7.440402 12.504594 3.984373 0.134991 0.000000 -0.192401 -1.673151 6.665497 12.458344 2.730432 7.374197 9.428884 -1.699881 -2.868641 -2.886889 -0.933319 0.108240 -0.485315 -4.435323 -2.971891 -1.068998 -4.291528 -2.012980 4.470757 1.915947 0.033680 0.000000 0.003250 0.791068 7.845245 15.695007 10.826212 5.185012 5.733994 2.023024 1.531310 1.054935 1.029027 2.243585 2.142922 0.340262 0.216050 3.042429 7.433523 5.126313 0.752260 0.098099 0.000605 0.000000 -0.000048 0.061203 1.182235 4.117837 5.765759 4.396278 3.718805 3.478347 2.901731 2.985661 2.627688 3.069516 2.410364 3.372945 5.799273 6.212174 4.001460 1.237066 0.081515 -0.000223 -0.000005 0.000000 -0.000015 -0.000192 0.009306 0.110310 0.245125 0.300410 0.832040 1.289265 0.938976 0.972975 1.049745 1.134887 1.167821 0.863429 0.854227 0.598260 0.119870 0.005337 -0.000255 -0.000035 -0.000000 0.000000 -0.000001 -0.000020 -0.000101 -0.000291 0.003555 0.017129 0.041801 0.042955 0.021642 0.033214 0.034837 0.044509 0.049935 0.039277 0.019095 0.012860 0.002157 -0.000097 -0.000024 -0.000002 -0.000000 0.000000 -0.000000 -0.000000 -0.000002 -0.000006 -0.000008 0.000483 0.002861 0.002208 -0.000200 0.002509 0.001786 0.003770 0.004510 0.003602 0.000309 -0.000052 -0.000009 -0.000002 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000002 0.000002 0.000003 0.000006 0.000007 0.000003 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000006 0.000021 0.000010 0.000001 0.000000 0.000009 0.000027 0.000032 0.000010 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000005 0.000139 0.000799 0.001129 0.000326 -0.000017 -0.000130 0.000191 0.001302 0.002288 0.001407 0.000277 0.000016 0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 0.000009 0.000207 0.001207 0.002700 0.002098 0.000241 -0.000381 -0.000724 -0.000342 0.001851 0.005448 0.006521 0.004035 0.001027 0.000057 0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000000 -0.000012 -0.000029 0.000387 0.000977 0.000726 0.000176 -0.000453 -0.000697 -0.000809 -0.000532 -0.000191 0.001143 0.003526 0.006922 0.005480 0.001469 0.000071 0.000000 -0.000000 0.000000 0.000000 -0.000002 -0.000189 -0.000416 -0.000182 -0.000091 -0.000279 -0.000497 -0.000687 -0.000507 -0.000948 -0.000306 -0.000221 -0.000436 -0.000179 0.001718 0.006363 0.005970 0.001116 0.000022 -0.000000 0.000000 0.000001 0.000116 0.000220 -0.000150 -0.000333 -0.000123 -0.000217 -0.000585 -0.000401 -0.000380 -0.000870 -0.000622 -0.000663 -0.000728 -0.000388 -0.000266 0.002042 0.006817 0.004509 0.000408 0.000001 0.000000 -0.000004 0.000482 0.001136 -0.000202 -0.000725 -0.000463 -0.000440 -0.000684 -0.000221 -0.000258 -0.000681 -0.000783 -0.000771 -0.000646 -0.000245 -0.000395 -0.000504 0.002996 0.007110 0.001974 0.000025 0.000000 -0.000067 -0.000657 -0.000217 -0.000976 -0.001313 -0.000772 0.001878 0.016318 0.070770 0.149764 0.119138 0.042602 0.008282 0.000182 -0.000288 -0.000850 -0.000768 0.000409 0.005740 0.003353 0.000090 0.000000 0.000147 -0.000259 -0.000999 0.001830 0.030875 0.205027 0.606706 0.978665 1.574872 2.286674 1.356471 0.770659 0.591726 0.151469 0.013290 0.008432 0.001074 0.000606 0.003114 0.002472 0.000098 0.000000 0.000603 0.030954 0.225357 0.625442 1.132177 1.546718 1.083761 -0.207779 -1.345377 -1.335052 -3.160460 -2.245762 -0.352797 -0.590431 -0.062412 0.527955 0.360725 0.159324 0.029018 0.001072 0.000050 0.000000 0.065307 0.850013 1.557568 1.030810 -0.421626 -2.267243 -3.007550 -4.262460 -4.268571 -2.566029 -3.730771 -3.156033 -3.117304 -4.044187 -3.223619 -1.315774 -0.195639 0.102841 0.028314 -0.029248 -0.000079 0.000000 0.498530 3.706829 0.995839 -3.470186 -3.610452 -2.085303 -0.514963 -1.967010 -2.254361 0.741716 0.155572 -1.298417 -2.236905 -3.467123 -3.183189 -5.330917 -7.140481 -7.452495 -3.092273 -0.235656 -0.001477 0.000000 0.362277 4.516721 5.438187 0.598530 0.513917 0.300849 -0.436710 -0.810102 -0.888432 0.837230 1.606864 -0.187121 -1.372893 -3.229852 -0.639297 -0.329903 -2.652492 -9.065746 -8.143867 -0.102417 0.031962 0.000000 -0.513831 -0.324574 4.484810 -1.210617 0.345149 -0.431597 -1.650797 -0.271567 -0.773788 -1.317948 -0.193758 -0.045583 -0.926197 -2.797453 0.533384 1.975954 -1.481680 -6.024725 -7.192143 1.542391 0.143707 0.000000 -0.008238 3.616469 9.329690 -1.479336 -1.401488 0.806490 0.037911 -0.716812 -1.599619 -3.231452 -2.233862 -1.096723 -3.912324 -6.016262 -0.440778 -1.091811 -6.507047 -5.710771 -1.059786 2.561090 0.126274 0.000000 0.154042 5.736710 18.630930 12.370942 2.293859 1.255341 1.309057 -1.745128 -0.900618 -2.302725 -2.106072 -2.303981 -1.908426 -2.162279 -0.659602 -1.105095 -1.205662 -0.951298 0.048881 0.617753 0.018232 0.000000 0.010626 1.144691 7.648122 11.813021 7.103797 2.983182 1.622356 0.845509 1.475850 0.472374 0.367144 0.318077 1.008324 0.554357 1.107942 3.045494 4.710497 2.479076 0.257806 0.015989 0.000127 0.000000 -0.000011 0.019734 0.413400 1.750331 2.940368 2.602651 1.737074 1.721504 2.090199 1.846208 1.072810 1.141149 1.252292 2.108230 3.102353 2.605692 1.247225 0.262025 0.013057 -0.000058 -0.000001 0.000000 -0.000004 -0.000078 0.000697 0.018414 0.101981 0.149381 0.047711 0.105827 0.165281 0.122624 0.052859 0.010983 0.207194 0.405979 0.383386 0.200106 0.032430 0.000353 -0.000089 -0.000010 -0.000000 0.000000 -0.000000 -0.000006 -0.000028 -0.000059 0.002807 0.014459 0.028099 0.014301 0.006829 0.019458 0.020775 0.012213 0.024975 0.013314 0.001670 0.006993 0.001549 -0.000024 -0.000007 -0.000001 -0.000000 0.000000 -0.000000 -0.000000 -0.000001 -0.000002 0.000012 0.000567 0.002829 0.001025 -0.000143 0.004028 0.004380 0.001565 0.003872 0.000920 -0.000592 -0.000090 -0.000003 -0.000001 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 0.000000 -0.000001 -0.000003 0.000004 0.000006 0.000002 0.000003 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000001 -0.000001 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000000 -0.000004 -0.000018 -0.000034 -0.000026 -0.000008 -0.000017 -0.000028 -0.000055 -0.000067 -0.000042 -0.000010 -0.000001 -0.000000 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000001 -0.000009 -0.000039 -0.000071 -0.000069 -0.000056 -0.000045 -0.000071 -0.000088 -0.000109 -0.000160 -0.000209 -0.000133 -0.000030 -0.000002 -0.000000 -0.000000 -0.000000 0.000000 -0.000000 -0.000000 -0.000000 -0.000010 -0.000051 -0.000052 -0.000054 -0.000036 -0.000047 -0.000056 -0.000068 -0.000059 -0.000055 -0.000056 -0.000167 -0.000232 -0.000181 -0.000046 -0.000002 -0.000000 0.000000 0.000000 0.000000 0.000000 -0.000010 -0.000032 -0.000059 -0.000059 -0.000065 -0.000051 -0.000050 -0.000047 -0.000079 -0.000046 -0.000056 -0.000085 -0.000074 -0.000123 -0.000242 -0.000186 -0.000037 -0.000001 0.000000 0.000000 0.000000 0.000010 0.000015 -0.000022 -0.000035 -0.000043 -0.000064 -0.000059 -0.000020 -0.000063 -0.000089 -0.000058 -0.000079 -0.000107 -0.000067 -0.000069 -0.000137 -0.000259 -0.000133 -0.000010 -0.000000 0.000000 0.000002 0.000059 0.000086 -0.000027 -0.000051 -0.000065 -0.000071 -0.000073 -0.000025 -0.000054 -0.000068 -0.000064 -0.000084 -0.000080 -0.000050 -0.000072 -0.000113 -0.000198 -0.000226 -0.000048 -0.000001 0.000000 -0.000003 -0.000021 -0.000029 -0.000112 -0.000123 -0.000127 -0.000118 -0.000039 0.000587 0.001758 0.001326 0.000373 -0.000031 -0.000066 -0.000064 -0.000108 -0.000106 -0.000122 -0.000203 -0.000088 -0.000002 0.000000 0.000013 -0.000001 -0.000109 -0.000168 0.000146 0.003749 0.018742 0.044056 0.073799 0.115273 0.076888 0.043659 0.027965 0.006594 0.000819 -0.000036 -0.000141 -0.000031 -0.000074 -0.000070 -0.000003 0.000000 0.000013 0.000646 0.006140 0.019417 0.045762 0.061641 0.058422 0.044568 -0.003183 0.003064 -0.112243 -0.088481 -0.008008 -0.039036 -0.003076 0.020113 0.012013 0.003318 0.000327 -0.000059 -0.000002 0.000000 0.002653 0.050640 0.121315 0.110784 0.036455 -0.121362 -0.178376 -0.232898 -0.273806 -0.220521 -0.298965 -0.236677 -0.216200 -0.326601 -0.244296 -0.057348 0.027201 0.037106 0.021739 0.001057 -0.000003 0.000000 0.041709 0.340249 0.134737 -0.174292 -0.197332 -0.136394 -0.021341 -0.124708 -0.191953 -0.067589 -0.141405 -0.179361 -0.181620 -0.207464 -0.267147 -0.370487 -0.463866 -0.455228 -0.102392 0.013212 0.000136 0.000000 0.084658 0.593636 0.306275 -0.075318 -0.044549 -0.035005 -0.031263 -0.066389 -0.074880 0.028185 0.043222 -0.045427 -0.113476 -0.124646 -0.006000 -0.054120 -0.262363 -0.891934 -0.628257 0.068003 0.003765 0.000000 0.067554 0.522255 0.265726 -0.376725 -0.188987 -0.229671 -0.163744 -0.016918 -0.059876 -0.083189 -0.003581 0.009733 -0.060265 -0.059168 0.099430 0.076138 -0.163354 -0.758259 -0.861765 0.122725 0.009854 0.000000 0.058748 0.739464 0.798554 -0.347767 -0.239969 -0.224421 -0.230517 -0.043086 -0.074657 -0.181350 -0.183152 -0.083478 -0.382599 -0.409975 0.022724 -0.153622 -0.573959 -0.568305 -0.369106 0.086200 0.004719 0.000000 0.013584 0.367976 0.895869 0.381147 0.037520 -0.007095 -0.071876 -0.114372 -0.077058 -0.280419 -0.333684 -0.249615 -0.267759 -0.240396 -0.016198 -0.055792 -0.102799 -0.052307 -0.032117 0.010334 0.000306 0.000000 0.000403 0.037058 0.236803 0.336848 0.162826 0.061818 0.033101 0.029292 0.062432 -0.030932 -0.049361 -0.044752 0.048731 0.049479 0.084632 0.150325 0.167895 0.065867 0.004181 0.000046 0.000000 0.000000 0.000000 0.000293 0.008699 0.040807 0.064698 0.063447 0.057191 0.082317 0.116791 0.089121 0.007910 0.019930 0.073364 0.108497 0.122311 0.086448 0.031747 0.003853 0.000069 0.000000 0.000000 0.000000 0.000000 0.000001 0.000009 0.000092 0.001470 0.003640 -0.002106 0.000241 0.004495 -0.009434 -0.017760 -0.014185 0.008170 0.018116 0.012041 0.007134 0.001624 0.000037 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000006 0.000018 0.000506 0.001518 0.000527 -0.000002 0.000549 0.001119 0.000540 0.001566 0.000273 -0.000392 0.000346 0.000105 0.000001 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000001 0.000042 0.000181 -0.000048 -0.000112 0.000169 0.000324 0.000084 0.000283 0.000002 -0.000064 -0.000007 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/xf-tps-1.txt000066400000000000000000000003621321604176500261260ustar00rootroot00000000000000PLASTIMATCH_TPS_XFORM img_origin = -25 -25 -25 img_spacing = 1.31579 1.31579 1.31579 img_dim = 38 38 38 -11.8658 0.173951 -0.65788 -1.88375 0.524197 -0.65788 49.941 -0.307638 -11.6469 -0.65788 10.1122 -11.9971 -0.65788 52.1286 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/Data/xf-translation-1.txt000077500000000000000000000002041321604176500276540ustar00rootroot00000000000000#Insight Transform File V1.0 # Transform 0 Transform: TranslationTransform_double_3_3 Parameters: 10.00 0.00 0.00 FixedParameters: plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/PlmCheckInterval.cmake000077500000000000000000000014271321604176500273400ustar00rootroot00000000000000## This script compares a value in a text file against lower and ## upper thresholds message (STATUS "INFILE is ${INFILE}") message (STATUS "REGEX is ${REGEX}") message (STATUS "LOWER_THRESH is ${LOWER_THRESH}") message (STATUS "UPPER_THRESH is ${UPPER_THRESH}") file (STRINGS ${INFILE} TEST_OUTPUT REGEX "${REGEX}") message (STATUS "PARSED VALUE=|${TEST_OUTPUT}|") string (REGEX MATCH "${REGEX}" TEST_OUTPUT ${TEST_OUTPUT}) set (TEST_OUTPUT ${CMAKE_MATCH_1}) message (STATUS "PARSED_VALUE=|${TEST_OUTPUT}|") string (LENGTH "${CMAKE_MATCH_1}" MATCH_LENGTH) if (MATCH_LENGTH GREATER 0 AND NOT CMAKE_MATCH_1 LESS ${LOWER_THRESH} AND NOT CMAKE_MATCH_1 GREATER ${UPPER_THRESH}) message ("Not an error") else () message (SEND_ERROR "An error") endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/PlmCheckString.cmake000077500000000000000000000014351321604176500270210ustar00rootroot00000000000000## This script finds a regex in a file and compares the first match ## with an input string message (STATUS "INFILE is ${INFILE}") message (STATUS "REGEX is ${REGEX}") message (STATUS "MATCH_STRING is ${MATCH_STRING}") file (STRINGS ${INFILE} test_output REGEX "${REGEX}") message (STATUS "PARSED VALUE=|${test_output}|") string (REGEX MATCH "${REGEX}" test_output ${test_output}) set (test_output ${CMAKE_MATCH_1}) message (STATUS "PARSED_VALUE=|${test_output}|") string (LENGTH "${test_output}" match_length) message (STATUS "LENGTH=${match_length}") message (STATUS "|${test_output}|${MATCH_STRING}|") if ("${match_length}" GREATER 0 AND "${test_output}" STREQUAL "${MATCH_STRING}") message("Not an error") else () message (SEND_ERROR "An error") endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/PlmSpeedTest.cmake000077500000000000000000000010501321604176500265060ustar00rootroot00000000000000## This script runs the speed tests execute_process ( COMMAND "${PLM_PLASTIMATCH_PATH}/plastimatch" # OUTPUT_FILE ${PLM_BUILD_TESTING_DIR}/hello.txt OUTPUT_VARIABLE STDOUT ERROR_VARIABLE STDOUT ) message (STATUS "${PLM_PLASTIMATCH_PATH}/plastimatch") message (STATUS "${STDOUT}") file (WRITE "${PLM_BUILD_TESTING_DIR}/hello.txt" "${PLM_PLASTIMATCH_PATH}/plastimatch\n") file (APPEND "${PLM_BUILD_TESTING_DIR}/hello.txt" "STDOUT = ${STDOUT}\n") file (APPEND "${PLM_BUILD_TESTING_DIR}/hello.txt" "STDERR = ${STDERR}\n") plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/Testing/PlmTestDebug.cmake000077500000000000000000000005241321604176500265010ustar00rootroot00000000000000## This script that spits out the contents of two files, and then fails. ## It is used to debug debian build failures. message (STATUS ">>${STDOUT_FILE}") file (READ ${STDOUT_FILE} VAL) message (STATUS "${VAL}") message (STATUS ">>${STDERR_FILE}") file (READ ${STDERR_FILE} VAL) message (STATUS "${VAL}") message (SEND_ERROR "An error") plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/000077500000000000000000000000001321604176500225775ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/CheckCharSign.cmake000077500000000000000000000006541321604176500262450ustar00rootroot00000000000000##--------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##--------------------------------------------------------------------------- macro (check_char_sign _out_var) try_run (RUN_RESULT_VAR COMPILE_RESULT_VAR ${PLM_BINARY_DIR} ${PLM_SOURCE_DIR}/cmake/char_is_signed.cxx RUN_OUTPUT_VARIABLE ${_out_var}) endmacro () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/CheckEpsilon.cmake000077500000000000000000000006441321604176500261570ustar00rootroot00000000000000##--------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##--------------------------------------------------------------------------- macro (check_epsilon _out_var) try_run (RUN_RESULT_VAR COMPILE_RESULT_VAR ${PLM_BINARY_DIR} ${PLM_SOURCE_DIR}/cmake/test_eps.cxx RUN_OUTPUT_VARIABLE ${_out_var}) endmacro () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/CheckQt.cmake000066400000000000000000000013561321604176500251300ustar00rootroot00000000000000##--------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##--------------------------------------------------------------------------- include (CheckCXXSourceCompiles) macro (CHECK_QT QT_TEST_COMPILE_SUCCEEDED) # It took forever to get the quoting correct on this. # Thanks to sakra @ http://stackoverflow.com/questions/25726853 try_compile (COMPILE_RESULT_VAR ${CMAKE_BINARY_DIR}/helpme ${CMAKE_SOURCE_DIR}/cmake/test_qt.cxx CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${QT_INCLUDES}" "-DLINK_LIBRARIES:STRING=${QT_QTCORE_LIBRARIES}" OUTPUT_VARIABLE OUT_VAR ) set (${QT_TEST_COMPILE_SUCCEEDED} ${COMPILE_RESULT_VAR}) endmacro () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/ExternalITKPatch.cmake000077500000000000000000000013521321604176500267170ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## Patch stock ITK 3.20.0 to make it work on gcc 4.6 ##----------------------------------------------------------------------------- execute_process ( COMMAND "${CMAKE_COMMAND}" -E copy "${PLM_SOURCE_DIR}/libs/itk-3.20.0/metaUtils.cxx" "${PLM_TARGET_DIR}/${proj_itk}/Utilities/MetaIO/metaUtils.cxx" ) execute_process ( COMMAND "${CMAKE_COMMAND}" -E copy "${PLM_SOURCE_DIR}/libs/itk-3.20.0/itkImageIORegion.h" "${PLM_TARGET_DIR}/${proj_itk}/Code/IO/itkImageIORegion.h" ) execute_process ( COMMAND "${CMAKE_COMMAND}" -E copy "${PLM_SOURCE_DIR}/libs/itk-3.20.0/itkImageIOBase.h" "${PLM_TARGET_DIR}/${proj_itk}/Code/IO/itkImageIOBase.h" ) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindAdvantech.cmake000077500000000000000000000027461321604176500263130ustar00rootroot00000000000000# Detect development libraries for Advantech I/O card. # These variables are set: # # ADVANTECH_FOUND # ADVANTECH_INCLUDE_DIR # ADVANTECH_LIBRARIES # # Only works on Windows if (ADVANTECH_INCLUDE_DIR) # Already in cache, be silent set (Advantech_FIND_QUIETLY TRUE) endif () FIND_PATH (ADVANTECH_INCLUDE_DIR "Driver.h" "C:/Program Files/Advantech/Adsapi/Include" DOC "Path to ADVANTECH include files.") FIND_PATH (ADVANTECH_LIBRARY_PATH "ADSDEV.lib" "C:/Program Files/Advantech/Adsapi/Lib" DOC "Path to ADVANTECH libraries.") FIND_LIBRARY(ADVANTECH_ADS841_LIB ADS841 ${ADVANTECH_LIBRARY_PATH}) FIND_LIBRARY(ADVANTECH_Adsapi32_LIB Adsapi32 ${ADVANTECH_LIBRARY_PATH}) FIND_LIBRARY(ADVANTECH_Adsapi32bcb_LIB Adsapi32bcb ${ADVANTECH_LIBRARY_PATH}) FIND_LIBRARY(ADVANTECH_Adscomm_LIB Adscomm ${ADVANTECH_LIBRARY_PATH}) FIND_LIBRARY(ADVANTECH_ADSDEV_LIB ADSDEV ${ADVANTECH_LIBRARY_PATH}) FIND_LIBRARY(ADVANTECH_adsdnet_LIB adsdnet ${ADVANTECH_LIBRARY_PATH}) if (ADVANTECH_Adscomm_LIB AND ADVANTECH_Adsapi32_LIB) set (ADVANTECH_LIBRARIES ${ADVANTECH_Adscomm_LIB} ${ADVANTECH_Adsapi32_LIB}) else () set (ADVANTECH_LIBRARIES) endif () INCLUDE (FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS (Advantech DEFAULT_MSG ADVANTECH_LIBRARIES ADVANTECH_INCLUDE_DIR) MARK_AS_ADVANCED ( ADVANTECH_ADS841_LIB ADVANTECH_Adsapi32_LIB ADVANTECH_Adsapi32bcb_LIB ADVANTECH_Adscomm_LIB ADVANTECH_ADSDEV_LIB ADVANTECH_adsdnet_LIB) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindBitflow.cmake000077500000000000000000000024001321604176500260070ustar00rootroot00000000000000# Bitflow lib and include path # These variables are set: # # BITFLOW_FOUND # BITFLOW_INCLUDE_DIR # BITFLOW_LIBRARIES # # Only works on Windows if (BITFLOW_INCLUDE_DIR) # Already in cache, be silent set (Bitflow_FIND_QUIETLY TRUE) endif () FIND_PATH (BITFLOW_SDK_DIR "include/BFApi.h" "C:/BitFlow SDK 4.00" DOC "Path to Bitflow SDK") FIND_PATH (BITFLOW_INCLUDE_DIR "BFApi.h" "${BITFLOW_SDK_DIR}/include" "C:/BitFlow SDK 4.00/include" DOC "Path to Bitflow include files") FIND_PATH (BITFLOW_LIBRARY_PATH "BFD.lib" "${BITFLOW_SDK_DIR}/lib" "C:/BitFlow SDK 4.00/lib" DOC "Path to Bitflow libraries.") FIND_LIBRARY (BITFLOW_BFD_LIB BFD ${BITFLOW_LIBRARY_PATH}) FIND_LIBRARY (BITFLOW_R2D_LIB R2d ${BITFLOW_LIBRARY_PATH}) FIND_LIBRARY (BITFLOW_DISPSURF_LIB DispSurf ${BITFLOW_LIBRARY_PATH}) if (BITFLOW_BFD_LIB AND BITFLOW_R2D_LIB AND BITFLOW_DISPSURF_LIB) set (BITFLOW_LIBRARIES ${BITFLOW_BFD_LIB} ${BITFLOW_R2D_LIB} ${BITFLOW_DISPSURF_LIB}) else () set (BITFLOW_LIBRARIES) endif () INCLUDE (FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS (Bitflow DEFAULT_MSG BITFLOW_LIBRARIES BITFLOW_INCLUDE_DIR) MARK_AS_ADVANCED ( BITFLOW_INCLUDE_DIR BITFLOW_LIBRARY_PATH BITFLOW_BFD_LIB BITFLOW_R2D_LIB BITFLOW_DISPSURF_LIB) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindCUDA_wrap.cmake000077500000000000000000000121041321604176500261500ustar00rootroot00000000000000# - Wrapper around FindCUDA if (MINGW) # Cuda doesn't work with mingw at all set (CUDA_FOUND FALSE) elseif (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.8) # FindCuda is included with CMake 2.8 set (CUDA_FOUND FALSE) else () # GCS 2011.03.16 # Make nvcc less whiny if (CMAKE_COMPILER_IS_GNUCC) set (CUDA_PROPAGATE_HOST_FLAGS OFF) endif () # GCS 2012-05-11: We need to propagate cxx flags to nvcc, but # the flag -ftest-coverage causes nvcc to barf, so exclude that one if (CMAKE_COMPILER_IS_GNUCC) string (REPLACE "-ftest-coverage" "" TMP "${CMAKE_CXX_FLAGS}") string (REPLACE " " "," TMP "${TMP}") set (CUDA_CXX_FLAGS ${CUDA_CXX_FLAGS} ${TMP}) endif () # GCS 2012-05-07: Workaround for poor, troubled FindCUDA set (CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE FALSE) find_package (CUDA QUIET) # GCS 2016-12-23: Tell FindCUDA to tell nvcc to use the c++ compiler, # which it doesn't do even if CUDA_HOST_COMPILATION_CPP is true. # This has to be done after calling FindCUDA, because FindCUDA overwrites # the variable. PS: Merry Christmas! if (NOT MSVC) set (CUDA_HOST_COMPILER "${CMAKE_CXX_COMPILER}") endif () endif () # 14-5-2016 PAOLO: WORKAROUND GCC 6.1 AND CUDA 7.5 INCOMPATIBILITY if (CMAKE_COMPILER_IS_GNUCC AND (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)) set (CUDA_CXX_FLAGS "${CUDA_CXX_FLAGS},-std=c++98") endif () # ITK headers cannot be processed by nvcc, so we define # PLM_CUDA_COMPILE for the purpose of guarding # (see base/plmbase.h) if (CUDA_CXX_FLAGS) set (CUDA_CXX_FLAGS "${CUDA_CXX_FLAGS},-DPLM_CUDA_COMPILE=1") else () set (CUDA_CXX_FLAGS "-DPLM_CUDA_COMPILE=1") endif () # GCS 2012-09-25 - Seems this is needed too if ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") set (CUDA_CXX_FLAGS "${CUDA_CXX_FLAGS},-fPIC") endif () if (CUDA_CXX_FLAGS) list (APPEND CUDA_NVCC_FLAGS --compiler-options ${CUDA_CXX_FLAGS}) endif () set (CUDA_FOUND ${CUDA_FOUND} CACHE BOOL "Did we find cuda?") if (CUDA_FOUND) cuda_include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ) endif () # GCS 2012-05-22 -- viscous fluid registration requires CUDA SDK. if (NOT CUDA_SDK_ROOT_DIR) # Try some obvious paths not searched by stock FindCUDA find_path(CUDA_SDK_ROOT_DIR common/inc/cutil.h "$ENV{HOME}/NVIDIA_GPU_Computing_SDK/C" "/usr/local/NVIDIA_GPU_Computing_SDK/C" ) endif () if (CUDA_SDK_ROOT_DIR) find_path (CUDA_CUT_INCLUDE_DIR cutil.h PATHS ${CUDA_SDK_SEARCH_PATH} PATH_SUFFIXES "common/inc" "C/common/inc" DOC "Location of cutil.h" NO_DEFAULT_PATH ) if (CUDA_CUT_INCLUDE_DIR) cuda_include_directories ( ${CUDA_CUT_INCLUDE_DIR} ) endif () endif () # JAS 08.25.2010 # Check to make sure nvcc has gcc-4.3 for compiling. # This script will modify CUDA_NVCC_FLAGS if system default is not gcc-4.3 include (nvcc-check) # GCS 2017-10-24: Let CUDA work with gcc 6 and CUDA 8 if (CUDA_VERSION_MAJOR EQUAL "8" AND CMAKE_COMPILER_IS_GNUCC AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) list (APPEND CUDA_NVCC_FLAGS --compiler-options -D__GNUC__=5) endif () # JAS 2010.12.09 # Build code for all known compute capabilities by default. # When developing, it is sometimes nice to turn this off in order # to speed up the build processes (since you only have 1 GPU in your machine). set (PLM_CUDA_ALL_DEVICES ON CACHE BOOL "Generate GPU code for all compute capabilities?") if (PLM_CUDA_ALL_DEVICES) message (STATUS "CUDA Build Level: ALL Compute Capabilities") if (CUDA_VERSION_MAJOR LESS "7") message (STATUS " >> Generation 1: [X]") set (CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -gencode arch=compute_11,code=sm_11 -gencode arch=compute_12,code=sm_12 -gencode arch=compute_13,code=sm_13 ) if (CUDA_VERSION_MAJOR EQUAL "6") set (CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} --Wno-deprecated-gpu-targets) if (CUDA_VERSION_MINOR LESS "5") set (CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -gencode arch=compute_10,code=sm_10) endif () else () set (CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -gencode arch=compute_10,code=sm_10) endif () else() message (STATUS " >> Generation 1: [ ]") endif() if (CUDA_VERSION_MAJOR GREATER "2") message (STATUS " >> Generation 2: [X]") set (CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -gencode arch=compute_20,code=sm_20 ) else() message (STATUS " >> Generation 2: [ ]") endif() if (CUDA_VERSION_MAJOR GREATER "4") message (STATUS " >> Generation 3: [X]") set (CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -gencode arch=compute_30,code=sm_30 ) else() message (STATUS " >> Generation 3: [ ]") endif() if (CUDA_VERSION_MAJOR GREATER "5") message (STATUS " >> Generation 5: [X]") set (CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -gencode arch=compute_50,code=sm_50 -gencode arch=compute_50,code=compute_50 ) else() message (STATUS " >> Generation 5: [ ]") endif() #MESSAGE(STATUS "<<-->>: CUDA_NVCC_FLAGS set to \"${CUDA_NVCC_FLAGS}\"") else () message (STATUS "CUDA Build Level: Build system Compute Capability ONLY!") endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindDCMTK_legacy.cmake000077500000000000000000000131301321604176500265710ustar00rootroot00000000000000# - find DCMTK libraries # # DCMTK_INCLUDE_DIR - Directories to include to use DCMTK # DCMTK_LIBRARIES - Files to link against to use DCMTK # DCMTK_FOUND - If false, don't try to use DCMTK # DCMTK_DIR - (optional) Source directory for DCMTK # # DCMTK_VERSION_STRING - Like "3.5.4" or "3.6.0" # # DCMTK_DIR can be used to make it simpler to find the various include # directories and compiled libraries if you've just compiled it in the # source tree. Just set it to the root of the tree where you extracted # the source. # # Written for VXL by Amitha Perera. # # On debian, require the following packages: # libdcmtk1-dev # libpng12-dev # libtiff4-dev # libwrap0-dev include(CheckLibraryExists) include(FindThreads) set (DCMTK_DIR "" CACHE PATH "Root of DCMTK install tree (optional).") find_package (ZLIB) if (ZLIB_FOUND) message (STATUS "Looking for ZLIB - found") else () message (STATUS "Looking for ZLIB - not found") endif () find_package (PNG) if (PNG_FOUND) message (STATUS "Looking for PNG - found") else () message (STATUS "Looking for PNG - not found") endif () find_package (TIFF) if (TIFF_FOUND) message (STATUS "Looking for TIFF - found") else () message (STATUS "Looking for TIFF - not found") endif () find_library (SSL_LIBRARY ssl) if (SSL_LIBRARY) message (STATUS "Looking for SSL - found: ${SSL_LIBRARY}") else () message (STATUS "Looking for SSL - not found") endif () find_path (DCMTK_INCLUDE_DIR NAMES dcmtk/config/osconfig.h HINTS ${DCMTK_DIR}/include /usr/local/dicom/include ) if (UNIX) find_file (DCMTK_HAVE_CFUNIX_H dcmtk/config/cfunix.h ${DCMTK_DIR}/include /usr/local/dicom/include ) else () set (DCMTK_HAVE_CFUNIX_H FALSE) endif () find_library (DCMTK_dcmimgle_LIBRARY NAMES dcmimgle HINTS ${DCMTK_DIR}/dcmimgle/libsrc ${DCMTK_DIR}/dcmimgle/libsrc/Release ${DCMTK_DIR}/dcmimgle/libsrc/Debug ${DCMTK_DIR}/dcmimgle/Release ${DCMTK_DIR}/dcmimgle/Debug ${DCMTK_DIR}/lib /usr/lib/dcmtk /usr/local/dicom/lib ) # This is gone in 3.6 find_library (DCMTK_imagedb_LIBRARY NAMES imagedb dcmimage HINTS ${DCMTK_DIR}/imagectn/libsrc/Release ${DCMTK_DIR}/imagectn/libsrc/ ${DCMTK_DIR}/imagectn/libsrc/Debug ${DCMTK_DIR}/lib/ /usr/lib/dcmtk /usr/local/dicom/lib ) find_library (DCMTK_dcmtls_LIBRARY NAMES dcmtls HINTS ${DCMTK_DIR}/dcmnet/libsrc/Release ${DCMTK_DIR}/dcmnet/libsrc/Debug ${DCMTK_DIR}/dcmnet/libsrc ${DCMTK_DIR}/dcmtls/libsrc/Release ${DCMTK_DIR}/dcmtls/libsrc/Debug ${DCMTK_DIR}/dcmtls/libsrc ${DCMTK_DIR}/lib /usr/lib/dcmtk /usr/local/dicom/lib ) find_library (DCMTK_dcmnet_LIBRARY NAMES dcmnet HINTS ${DCMTK_DIR}/dcmnet/libsrc/Release ${DCMTK_DIR}/dcmnet/libsrc/Debug ${DCMTK_DIR}/dcmnet/libsrc/ ${DCMTK_DIR}/lib/ /usr/lib/dcmtk /usr/local/dicom/lib ) find_library (DCMTK_dcmdata_LIBRARY NAMES dcmdata HINTS ${DCMTK_DIR}/dcmdata/libsrc ${DCMTK_DIR}/dcmdata/libsrc/Release ${DCMTK_DIR}/dcmdata/libsrc/Debug ${DCMTK_DIR}/dcmdata/Release ${DCMTK_DIR}/dcmdata/Debug ${DCMTK_DIR}/lib /usr/lib/dcmtk /usr/local/dicom/lib ) # Quick hack: dcmtk 3.6.0 find_library (DCMTK_oflog_LIBRARY NAMES oflog HINTS ${DCMTK_DIR}/lib /usr/lib/dcmtk /usr/local/dicom/lib ) find_library (DCMTK_ofstd_LIBRARY NAMES ofstd HINTS ${DCMTK_DIR}/ofstd/libsrc ${DCMTK_DIR}/ofstd/libsrc/Release ${DCMTK_DIR}/ofstd/libsrc/Debug ${DCMTK_DIR}/ofstd/Release ${DCMTK_DIR}/ofstd/Debug ${DCMTK_DIR}/lib /usr/lib/dcmtk /usr/local/dicom/lib ) if (DCMTK_INCLUDE_DIR AND DCMTK_dcmnet_LIBRARY AND DCMTK_ofstd_LIBRARY AND DCMTK_dcmdata_LIBRARY AND DCMTK_dcmimgle_LIBRARY) set (DCMTK_FOUND "YES") set (DCMTK_LIBRARIES "") ## The libraries dcmtls, dcmnet, dcmimgle are not used by plastimatch. ## Including them increases the number of required dependencies ## for debian. set (DCMTK_LIBRARIES ${DCMTK_LIBRARIES} # ${DCMTK_dcmtls_LIBRARY} # ${DCMTK_dcmnet_LIBRARY} # ${DCMTK_dcmimgle_LIBRARY} ${DCMTK_dcmdata_LIBRARY} ) if (DCMTK_oflog_LIBRARY) set (DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${DCMTK_oflog_LIBRARY} ) endif () set (DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${DCMTK_ofstd_LIBRARY} ) if (SSL_LIBRARY) set (DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${SSL_LIBRARY} ) endif () if (PNG_FOUND) set (DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${PNG_LIBRARIES}) endif () if (TIFF_FOUND) set (DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${TIFF_LIBRARIES}) endif () if (ZLIB_FOUND) set (DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${ZLIB_LIBRARIES}) endif () if (CMAKE_THREAD_LIBS_INIT) set (DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) endif () # Dcmtk must be linked with libwrap if the original package was # built with libwrap support. set (NEED_LIBWRAP_CHECK TRUE) if (EXISTS "${DCMTK_INCLUDE_DIR}/dcmtk/config/osconfig.h") file (STRINGS "${DCMTK_INCLUDE_DIR}/dcmtk/config/osconfig.h" DCMTK_UNDEF_TCPWRAPPER REGEX "#undef WITH_TCPWRAPPER") if (NOT ${DCMTK_UNDEF_TCPWRAPPER} STREQUAL "") message (STATUS "DCMTK was built without libwrap") set (NEED_LIBWRAP_CHECK FALSE) else () message (STATUS "DCMTK may have been built with libwrap") endif () endif () if (NEED_LIBWRAP_CHECK) find_library (LIBWRAP_LIBRARY NAMES wrap libwrap PATHS /lib) if (LIBWRAP_LIBRARY) set (DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${LIBWRAP_LIBRARY}) endif () endif () if (WIN32) set (DCMTK_LIBRARIES ${DCMTK_LIBRARIES} netapi32 ws2_32) endif () endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindDCMTK_wrap.cmake000066400000000000000000000034151321604176500263000ustar00rootroot00000000000000# - Wrapper around FindDCMTK ## If it is a modern version of DCMTK, such as found in Slicer build, ## it will have a working version of DCMTKConfig.cmake. ## Otherwise we use the old hacked version of FindDCMTK.cmake. if (DCMTK_DIR) if (EXISTS "${DCMTK_DIR}/DCMTKConfig.cmake") find_package (DCMTK NO_MODULE) endif () endif () if (NOT DCMTK_FOUND) find_package (DCMTK) endif () ## Get the version string (?) if (DCMTK_FOUND) # Basic version information if (DCMTK_VERSION_MAJOR) set (DCMTK_VERSION_STRING "${DCMTK_VERSION_MAJOR}.${DCMTK_VERSION_MINOR}.${DCMTK_VERSION_PATCH}") endif () if (NOT DCMTK_VERSION_STRING) if (EXISTS "${DCMTK_INCLUDE_DIR}/dcmtk/dcmdata/dcuid.h") file (STRINGS "${DCMTK_INCLUDE_DIR}/dcmtk/dcmdata/dcuid.h" DCMTK_VERSION_STRING REGEX "^#define OFFIS_DCMTK_VERSION_STRING *\"([^\"]*)\"") endif () endif () if (NOT DCMTK_VERSION_STRING) if (EXISTS "${DCMTK_INCLUDE_DIR}/dcmtk/config/osconfig.h") file (STRINGS "${DCMTK_INCLUDE_DIR}/dcmtk/config/osconfig.h" DCMTK_VERSION_STRING REGEX "^#define PACKAGE_VERSION *\"([^\"]*)\"") endif () endif () if (NOT DCMTK_VERSION_STRING) if (EXISTS "${DCMTK_INCLUDE_DIR}/dcmtk/config/cfunix.h") file (STRINGS "${DCMTK_INCLUDE_DIR}/dcmtk/config/cfunix.h" DCMTK_VERSION_STRING REGEX "^#define PACKAGE_VERSION *\"([^\"]*)\"") endif () endif () if (DCMTK_VERSION_STRING) # GCS: The below doesn't seem to work on Mac CMake 2.6.4. # SET (DCMTK_VERSION_STRING "${CMAKE_MATCH_1}") string (REGEX REPLACE "[^\"]*\"([^\"]*)\".*" "\\1" DCMTK_VERSION_STRING "${DCMTK_VERSION_STRING}") endif () endif () if (DCMTK_FOUND) message (STATUS "DCMTK version ${DCMTK_VERSION_STRING}") else () message (STATUS "DCMTK not found") endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindDlib.cmake000077500000000000000000000026011321604176500252560ustar00rootroot00000000000000# - Find Dlib # Find the native Dlib includes and library # # DLIB_INCLUDE_DIR - where to find zlib.h, etc. # DLIB_LIBRARIES - List of libraries when using zlib. # DLIB_FOUND - True if zlib found. if (NOT DLIB_DIR) find_path (DLIB_DIR DLIBconfig.cmake $ENV{DLIB_DIR} DOC "The build directory, containing Dlibconfig.cmake") endif (NOT DLIB_DIR) if (DLIB_DIR) if (EXISTS (${DLIB_DIR}/Dlibconfig.cmake)) include (${DLIB_DIR}/Dlibconfig.cmake) endif () endif (DLIB_DIR) if (DLIB_INCLUDE_DIR) # Already in cache, be silent set (Dlib_FIND_QUIETLY TRUE) endif (DLIB_INCLUDE_DIR) find_path (DLIB_INCLUDE_DIR "dlib/algs.h" PATHS "${DLIB_DIR}") set (DLIB_NAMES dlib) find_library (DLIB_LIBRARY NAMES ${DLIB_NAMES}) # handle the QUIETLY and REQUIRED arguments and set DLIB_FOUND to TRUE if # all listed variables are TRUE include (FindPackageHandleStandardArgs) find_package_handle_standard_args (DLIB DEFAULT_MSG DLIB_LIBRARY DLIB_INCLUDE_DIR) # Dlib on debian is linked against lapack and blas if (DLIB_LIBRARY) find_package (BLAS) if (BLAS_FOUND) find_package (LAPACK) endif () if (LAPACK_FOUND) list (APPEND DLIB_LIBRARY ${LAPACK_LIBRARIES}) else () set (DLIB_FOUND FALSE) endif () endif () if (DLIB_FOUND) set (DLIB_LIBRARIES ${DLIB_LIBRARY}) else (DLIB_FOUND) set (DLIB_LIBRARIES) endif (DLIB_FOUND) mark_as_advanced (DLIB_LIBRARY) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindEtags.cmake000066400000000000000000000006311321604176500254450ustar00rootroot00000000000000## From Jan Woetzel, CMAKE email list ## http://www.cmake.org/pipermail/cmake/2006-January/007883.html IF (UNIX) ADD_CUSTOM_TARGET(tags etags --members --declarations `find ${CMAKE_SOURCE_DIR} -name *.cc -or -name *.cxx -or -name *.hxx -or -name *.hh -or -name *.cpp -or -name *.h -or -name *.c -or -name *.f`) ADD_CUSTOM_TARGET(etags DEPENDS tags) MESSAGE (STATUS "Etags targets added.") ENDIF (UNIX) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindFFTW.cmake000077500000000000000000000037301321604176500251560ustar00rootroot00000000000000###################################################### ## RULES FOR FINDING FFTW ## FFTW_INCLUDE_DIR - where to find fftw3.h, etc. ## FFTW_LIBRARIES - List of libraries when using fftw ## FFTW_FOUND - True if fftw found. ###################################################### IF (FFTW_INCLUDE_DIR) # Already in cache, be silent SET (FFTW_FIND_QUIETLY TRUE) ENDIF (FFTW_INCLUDE_DIR) IF (NOT FFTW_DIR) # I think this only applies to windows FIND_PATH(FFTW_DIR fftw3.h PATH $ENV{FFTWDIR} $ENV{FFTW_DIR} "${FFTWDIR}" DOC "Root directory of fftw.") ENDIF (NOT FFTW_DIR) # Convert from old name (without underscore) to new name (with underscore) IF (FFTWDIR AND FFTW_DIR) UNSET (FFTWDIR CACHE) ENDIF (FFTWDIR AND FFTW_DIR) FIND_PATH (FFTW_INCLUDE_DIR fftw3.h ${FFTW_DIR} /usr/local/include /usr/include ) FIND_LIBRARY(FFTW_LIBRARY_FLOAT NAMES fftw3f libfftw3f-3 PATHS /usr/lib /usr/local/lib ${FFTW_DIR} ) FIND_LIBRARY(FFTW_LIBRARY_DOUBLE NAMES fftw3 libfftw3-3 PATHS /usr/lib /usr/local/lib ${FFTW_DIR} ) FIND_LIBRARY(FFTW_LIBRARY_LONG_DOUBLE NAMES fftw3l libfftw3l-3 PATHS /usr/lib /usr/local/lib ${FFTW_DIR} ) # NOTE: OpenSUSE doesn't provide long double implementation IF (FFTW_INCLUDE_DIR AND FFTW_LIBRARY_FLOAT AND FFTW_LIBRARY_DOUBLE) SET (FFTW_FOUND TRUE) SET (FFTW_LIBRARIES ${FFTW_LIBRARY_FLOAT} ${FFTW_LIBRARY_DOUBLE}) ELSE (FFTW_INCLUDE_DIR AND FFTW_LIBRARY_FLOAT AND FFTW_LIBRARY_DOUBLE) SET (FFTW_FOUND FALSE) SET (FFTW_LIBRARIES) ENDIF (FFTW_INCLUDE_DIR AND FFTW_LIBRARY_FLOAT AND FFTW_LIBRARY_DOUBLE) # IF (FFTW_FOUND) # IF (NOT FFTW_FIND_QUIETLY) # MESSAGE(STATUS "Found FFTW: ${FFTW_LIBRARY}") # ENDIF (NOT FFTW_FIND_QUIETLY) # ELSE (FFTW_FOUND) # IF (FFTW_FIND_REQUIRED) # MESSAGE(STATUS "Looked for FFTW libraries named ${FFTW_NAMES}.") # MESSAGE(FATAL_ERROR "Could NOT find FFTW library") # ENDIF (FFTW_FIND_REQUIRED) # ENDIF (FFTW_FOUND) MARK_AS_ADVANCED( FFTW_LIBRARY FFTW_INCLUDE_DIR ) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindFann.cmake000077500000000000000000000014751321604176500252760ustar00rootroot00000000000000# - Find Fann # Find the native Fann includes and library # # FANN_INCLUDE_DIR - where to find zlib.h, etc. # FANN_LIBRARIES - List of libraries when using zlib. # FANN_FOUND - True if zlib found. IF (FANN_INCLUDE_DIR) # Already in cache, be silent SET (fann_FIND_QUIETLY TRUE) ENDIF (FANN_INCLUDE_DIR) FIND_PATH(FANN_INCLUDE_DIR fann.h) SET (FANN_NAMES fann) FIND_LIBRARY (FANN_LIBRARY NAMES ${FANN_NAMES}) # handle the QUIETLY and REQUIRED arguments and set FANN_FOUND to TRUE if # all listed variables are TRUE INCLUDE (FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS (FANN DEFAULT_MSG FANN_LIBRARY FANN_INCLUDE_DIR) IF(FANN_FOUND) SET (FANN_LIBRARIES ${FANN_LIBRARY}) ELSE (FANN_FOUND) SET (FANN_LIBRARIES) ENDIF (FANN_FOUND) MARK_AS_ADVANCED (FANN_LIBRARY FANN_INCLUDE_DIR) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindKaze.cmake000066400000000000000000000015531321604176500253000ustar00rootroot00000000000000# - Find libkaze # KAZE_INCLUDE_DIR - where to find kaze.h, etc. # KAZE_LIBRARIES - List of libraries when using kaze. # KAZE_FOUND - True if kaze found. set (KAZE_DIR "" CACHE PATH "Root of libkaze install tree (optional).") if (KAZE_INCLUDE_DIR) # Already in cache, be silent set (Kaze_FIND_QUIETLY TRUE) endif () find_path (KAZE_INCLUDE_DIR kimage.h ${KAZE_DIR}/include) set (KAZE_NAMES kaze) find_library (KAZE_LIBRARY NAMES ${KAZE_NAMES} PATHS ${KAZE_DIR}/lib) # handle the QUIETLY and REQUIRED arguments and set KAZE_FOUND to TRUE if # all listed variables are TRUE include (FindPackageHandleStandardArgs) find_package_handle_standard_args (Kaze DEFAULT_MSG KAZE_LIBRARY KAZE_INCLUDE_DIR) if (KAZE_FOUND) set (KAZE_LIBRARIES ${KAZE_LIBRARY}) else () set (KAZE_LIBRARIES) endif () mark_as_advanced (KAZE_LIBRARY KAZE_INCLUDE_DIR) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindLibYAML.cmake000077500000000000000000000007631321604176500256040ustar00rootroot00000000000000# CMake module to search for the libyaml library # (library for parsing YAML files) # # If it's found it sets LIBYAML_FOUND to TRUE # and following variables are set: # LIBYAML_INCLUDE_DIR # LIBYAML_LIBRARY find_path (LIBYAML_INCLUDE_DIR NAMES yaml.h) find_library (LIBYAML_LIBRARIES NAMES yaml libyaml) include (FindPackageHandleStandardArgs) find_package_handle_standard_args (LIBYAML DEFAULT_MSG LIBYAML_LIBRARIES LIBYAML_INCLUDE_DIR) mark_as_advanced (LIBYAML_INCLUDE_DIR LIBYAML_LIBRARIES) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindLiblbfgs.cmake000077500000000000000000000016401321604176500261320ustar00rootroot00000000000000# - Find Liblbfgs # Find the native Liblbfgs includes and library # # LIBLBFGS_INCLUDE_DIR - where to find zlib.h, etc. # LIBLBFGS_LIBRARIES - List of libraries when using zlib. # LIBLBFGS_FOUND - True if zlib found. IF (LIBLBFGS_INCLUDE_DIR) # Already in cache, be silent SET (liblbfgs_FIND_QUIETLY TRUE) ENDIF (LIBLBFGS_INCLUDE_DIR) FIND_PATH(LIBLBFGS_INCLUDE_DIR lbfgs.h) SET (LIBLBFGS_NAMES lbfgs) FIND_LIBRARY (LIBLBFGS_LIBRARY NAMES ${LIBLBFGS_NAMES}) # handle the QUIETLY and REQUIRED arguments and set LIBLBFGS_FOUND to TRUE if # all listed variables are TRUE INCLUDE (FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS (LIBLBFGS DEFAULT_MSG LIBLBFGS_LIBRARY LIBLBFGS_INCLUDE_DIR) IF (LIBLBFGS_FOUND) SET (LIBLBFGS_LIBRARIES ${LIBLBFGS_LIBRARY}) ELSE (LIBLBFGS_FOUND) SET (LIBLBFGS_LIBRARIES) ENDIF (LIBLBFGS_FOUND) MARK_AS_ADVANCED (LIBLBFGS_LIBRARY LIBLBFGS_INCLUDE_DIR) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindMIL.cmake000077500000000000000000000023261321604176500250310ustar00rootroot00000000000000# MIL = Matrox Imaging Library # Sets the following variables # # MIL_FOUND # MIL_INCLUDE_DIR # MIL_LIBRARIES # # Only works on Windows if (MIL_INCLUDE_DIR) # Already in cache, be silent set (MIL_FIND_QUIETLY TRUE) endif () FIND_PATH (MIL_SDK_DIR "include/mil.h" "C:/Program Files/Matrox Imaging/mil" DOC "Path to MIL SDK") FIND_PATH (MIL_INCLUDE_DIR "mil.h" "${MIL_SDK_DIR}/include" "C:/Program Files/Matrox Imaging/mil/include" DOC "Path to MIL include files") FIND_PATH (MIL_LIBRARY_PATH "BFD.lib" "${MIL_SDK_DIR}/library/winnt/msc/dll" "C:/Program Files/Matrox Imaging/mil/library/winnt/msc/dll" DOC "Path to MIL libraries") FIND_LIBRARY(MIL_MIL_LIB mil ${MIL_LIBRARY_PATH}) FIND_LIBRARY(MIL_MILVGA_LIB milvga ${MIL_LIBRARY_PATH}) FIND_LIBRARY(MIL_MILMET2D_LIB milmet2d ${MIL_LIBRARY_PATH}) if (MIL_MIL_LIB AND MIL_MILVGA_LIB AND MIL_MILMET2D_LIB) set (MIL_LIBRARIES ${MIL_MIL_LIB} ${MIL_MILVGA_LIB} ${MIL_MILMET2D_LIB}) else () set (MIL_LIBRARIES) endif () INCLUDE (FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS (MIL DEFAULT_MSG MIL_LIBRARIES MIL_INCLUDE_DIR) MARK_AS_ADVANCED ( MIL_INCLUDE_DIR MIL_LIBRARY_PATH MIL_MIL_LIB MIL_MILVGA_LIB MIL_MILMET2D_LIB) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindMatlab.cmake000066400000000000000000000063431321604176500256100ustar00rootroot00000000000000SET (MATLAB_FOUND 0) FIND_PROGRAM (MATLAB_EXE matlab ) IF (MATLAB_EXE) MESSAGE (STATUS "Probing matlab capabilities") FILE (WRITE "${CMAKE_BINARY_DIR}/probe_matlab.c" " #include \"mex.h\" void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { mxArray *v = mxCreateDoubleMatrix (1, 1, mxREAL); double *data = mxGetPr (v); *data = 1.23456789; plhs[0] = v; } " ) FILE (WRITE "${CMAKE_BINARY_DIR}/probe_matlab_2.m" " disp(sprintf('mexext=%s',mexext)); disp(sprintf('matlabroot=%s',matlabroot)); %cpp_config = mex.getCompilerConfigurations('C++'); %disp(sprintf('cxxflags=%s',cpp_config.Details.CompilerFlags)); mex -v probe_matlab.c; exit; " ) EXECUTE_PROCESS (COMMAND "${MATLAB_EXE}" -nosplash -nodisplay -r "probe_matlab_2" TIMEOUT 20 RESULT_VARIABLE MATLAB_RESULT OUTPUT_VARIABLE MATLAB_STDOUT ERROR_VARIABLE MATLAB_STDERR ) IF (MATLAB_STDOUT) STRING (REGEX MATCH "mexext *=[ ]*([^\n]*)" JUNK ${MATLAB_STDOUT}) SET (MATLAB_MEXEXT "${CMAKE_MATCH_1}") STRING (REGEX MATCH "matlabroot *=[ \n]*([^\n]*)" JUNK ${MATLAB_STDOUT}) SET (MATLAB_ROOT "${CMAKE_MATCH_1}") STRING (REGEX MATCH "cxxflags *=[ \n]*([^\n]*)" JUNK ${MATLAB_STDOUT}) SET (MATLAB_CXXFLAGS "${CMAKE_MATCH_1}") STRING (REGEX MATCH "CXXFLAGS *= *([^\n]*)" JUNK ${MATLAB_STDOUT}) SET (MATLAB_CXXFLAGS "${CMAKE_MATCH_1}") STRING (REGEX MATCH "CXXLIBS *= *([^\n]*)" JUNK ${MATLAB_STDOUT}) SET (MATLAB_CXXLIBS "${CMAKE_MATCH_1}") STRING (REGEX MATCH "LD *= *([^\n]*)" JUNK ${MATLAB_STDOUT}) SET (MATLAB_LD "${CMAKE_MATCH_1}") STRING (REGEX MATCH "LDFLAGS *= *([^\n]*)" JUNK ${MATLAB_STDOUT}) SET (MATLAB_LDFLAGS "${CMAKE_MATCH_1}") ENDIF (MATLAB_STDOUT) #MESSAGE (STATUS "Matlab stdout = ${MATLAB_STDOUT}") MESSAGE (STATUS "Matlab root = ${MATLAB_ROOT}") MESSAGE (STATUS "MEX extension = ${MATLAB_MEXEXT}") MESSAGE (STATUS "MEX cxxflags = ${MATLAB_CXXFLAGS}") MESSAGE (STATUS "MEX cxxlibs = ${MATLAB_CXXLIBS}") MESSAGE (STATUS "MEX ld = ${MATLAB_LD}") MESSAGE (STATUS "MEX ldflags = ${MATLAB_LDFLAGS}") IF (MATLAB_MEXEXT) SET (MATLAB_FOUND 1) SET (MATLAB_INCLUDE_DIRS "${MATLAB_ROOT}/extern/include") ENDIF (MATLAB_MEXEXT) ENDIF (MATLAB_EXE) ####################################################################### ## Macro for compiling mex files ####################################################################### MACRO (MEX_TARGET TARGET_NAME TARGET_SRC TARGET_LIBS TARGET_LDFLAGS) # GCS: This mostly works, except that "-framework OpenCL" # gives a link error when combined with # "-Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk" # It seems to work ok if I don't use ${MATLAB_LDFLAGS} SET (MEX_COMPILE_TGT "${CMAKE_BINARY_DIR}/${TARGET_NAME}${MATLAB_LDEXTENSION}") SET (MEX_COMPILE_SRC "${CMAKE_SOURCE_DIR}/${TARGET_SRC}") ADD_LIBRARY (${TARGET_NAME} MODULE ${TARGET_SRC}) TARGET_LINK_LIBRARIES (${TARGET_NAME} ${TARGET_LIBS} ${MATLAB_CXXLIBS}) IF (NOT ${TARGET_LDFLAGS} STREQUAL "") SET_TARGET_PROPERTIES (${TARGET_NAME} PROPERTIES LINK_FLAGS "${TARGET_LDFLAGS}") ENDIF (NOT ${TARGET_LDFLAGS} STREQUAL "") SET_TARGET_PROPERTIES (${TARGET_NAME} PROPERTIES PREFIX "" SUFFIX ".${MATLAB_MEXEXT}") ENDMACRO (MEX_TARGET) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindNLopt.cmake000077500000000000000000000017061321604176500254450ustar00rootroot00000000000000# - Find NLopt # Find the native NLopt includes and library # # NLOPT_INCLUDE_DIR - where to find zlib.h, etc. # NLOPT_LIBRARIES - List of libraries when using zlib. # NLOPT_FOUND - True if zlib found. set (NLOPT_DIR "" CACHE PATH "Root of NLopt install tree (optional).") if (NLOPT_INCLUDE_DIR) # Already in cache, be silent set (nlopt_FIND_QUIETLY TRUE) endif (NLOPT_INCLUDE_DIR) find_path (NLOPT_INCLUDE_DIR nlopt.h ${NLOPT_DIR}/include) set (NLOPT_NAMES nlopt nlopt_cxx) find_library (NLOPT_LIBRARY NAMES ${NLOPT_NAMES} PATHS ${NLOPT_DIR}/lib) # handle the QUIETLY and REQUIRED arguments and set NLOPT_FOUND to TRUE if # all listed variables are TRUE include (FindPackageHandleStandardArgs) find_package_handle_standard_args (NLOPT DEFAULT_MSG NLOPT_LIBRARY NLOPT_INCLUDE_DIR) if (NLOPT_FOUND) set (NLOPT_LIBRARIES ${NLOPT_LIBRARY}) else () set (NLOPT_LIBRARIES) endif () mark_as_advanced (NLOPT_LIBRARY NLOPT_INCLUDE_DIR) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindOctave.cmake000077500000000000000000000033071321604176500256310ustar00rootroot00000000000000# - Find Octave # Find the Octave includes, libraries, and executables # # OCTAVE_INCLUDE_DIR # OCTAVE_LIBRARIES # OCTAVE_MKOCTFILE # OCTAVE_FOUND IF (OCTAVE_INCLUDE_DIR) # Already in cache, be silent SET (Octave_FIND_QUIETLY TRUE) ENDIF (OCTAVE_INCLUDE_DIR) # Find some hints for directories using octave-config FIND_PROGRAM (OCTAVE_CONFIG octave-config ) IF (OCTAVE_CONFIG) EXECUTE_PROCESS ( COMMAND ${OCTAVE_CONFIG} -p OCTLIBDIR RESULT_VARIABLE RESULT OUTPUT_VARIABLE OUTPUT ERROR_VARIABLE ERROR ) IF (${RESULT} EQUAL 0) STRING (STRIP ${OUTPUT} OCTLIBDIR) ENDIF (${RESULT} EQUAL 0) EXECUTE_PROCESS ( COMMAND ${OCTAVE_CONFIG} -p OCTINCLUDEDIR RESULT_VARIABLE RESULT OUTPUT_VARIABLE OUTPUT ERROR_VARIABLE ERROR ) IF (${RESULT} EQUAL 0) STRING (STRIP ${OUTPUT} OCTINCLUDEDIR) ENDIF (${RESULT} EQUAL 0) ENDIF (OCTAVE_CONFIG) # Find include dir FIND_PATH (OCTAVE_INCLUDE_DIR octave/oct.h PATHS ${OCTINCLUDEDIR} ${OCTAVE_DIR} /usr/local/include /usr/include ) #MESSAGE (STATUS "OCTAVE_INCLUDE_DIR = ${OCTAVE_INCLUDE_DIR}") # Find libraries FIND_LIBRARY (OCTAVE_LIBRARIES octave PATHS ${OCTLIBDIR} /usr/lib /usr/local/lib ${OCTAVE_DIR} ) #MESSAGE (STATUS "OCTAVE_LIBRARIES = ${OCTAVE_LIBRARIES}") # Find mkoctfile FIND_PROGRAM (OCTAVE_MKOCTFILE mkoctfile PATHS /usr/local/bin ${OCTAVE_DIR} ) #MESSAGE (STATUS "OCTAVE_MKOCTFILE = ${OCTAVE_MKOCTFILE}") # Set OCTAVE_FOUND IF (OCTAVE_INCLUDE_DIR AND OCTAVE_LIBRARIES AND OCTAVE_MKOCTFILE) SET (OCTAVE_FOUND TRUE) ELSE (OCTAVE_INCLUDE_DIR AND OCTAVE_LIBRARIES AND OCTAVE_MKOCTFILE) SET (OCTAVE_FOUND FALSE) ENDIF (OCTAVE_INCLUDE_DIR AND OCTAVE_LIBRARIES AND OCTAVE_MKOCTFILE) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindOpenCL.cmake000066400000000000000000000061351321604176500255270ustar00rootroot00000000000000# Retrieved from: # http://gitorious.org/findopencl ############################################################################# # - Try to find OpenCL # This module tries to find an OpenCL implementation on your system. It supports # AMD / ATI, Apple and NVIDIA implementations, but should work, too. # # To set manually the paths, define these environment variables: # OpenCL_INCPATH - Include path (e.g. OpenCL_INCPATH=/opt/cuda/4.0/cuda/include) # OpenCL_LIBPATH - Library path (e.h. OpenCL_LIBPATH=/usr/lib64/nvidia) # # Once done this will define # OPENCL_FOUND - system has OpenCL # OPENCL_INCLUDE_DIRS - the OpenCL include directory # OPENCL_LIBRARIES - link these to use OpenCL # # WIN32 should work, but is untested FIND_PACKAGE(PackageHandleStandardArgs) SET (OPENCL_VERSION_STRING "0.1.0") SET (OPENCL_VERSION_MAJOR 0) SET (OPENCL_VERSION_MINOR 1) SET (OPENCL_VERSION_PATCH 0) IF (APPLE) FIND_LIBRARY(OPENCL_LIBRARIES OpenCL DOC "OpenCL lib for OSX") FIND_PATH(OPENCL_INCLUDE_DIRS OpenCL/cl.h DOC "Include for OpenCL on OSX") FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS OpenCL/cl.hpp DOC "Include for OpenCL CPP bindings on OSX") ELSE (APPLE) IF (WIN32) FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h) FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp) # The AMD SDK currently installs both x86 and x86_64 libraries # This is only a hack to find out architecture IF( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64" ) SET(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86_64") ELSE (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64") SET(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86") ENDIF( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64" ) FIND_LIBRARY(OPENCL_LIBRARIES OpenCL.lib PATHS ${OPENCL_LIB_DIR} ENV OpenCL_LIBPATH) GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE) # On Win32 search relative to the library FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS "${_OPENCL_INC_CAND}" ENV OpenCL_INCPATH) FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS "${_OPENCL_INC_CAND}" ENV OpenCL_INCPATH) ELSE (WIN32) # Unix style platforms FIND_LIBRARY(OPENCL_LIBRARIES OpenCL PATHS ENV LD_LIBRARY_PATH ENV OpenCL_LIBPATH ) GET_FILENAME_COMPONENT(OPENCL_LIB_DIR ${OPENCL_LIBRARIES} PATH) GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE) # The AMD SDK currently does not place its headers # in /usr/include, therefore also search relative # to the library FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS ${_OPENCL_INC_CAND} "/usr/local/cuda/include" "/opt/AMDAPP/include" ENV OpenCL_INCPATH) FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS ${_OPENCL_INC_CAND} "/usr/local/cuda/include" "/opt/AMDAPP/include" ENV OpenCL_INCPATH) ENDIF (WIN32) ENDIF (APPLE) FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenCL DEFAULT_MSG OPENCL_LIBRARIES OPENCL_INCLUDE_DIRS) IF(_OPENCL_CPP_INCLUDE_DIRS) SET( OPENCL_HAS_CPP_BINDINGS TRUE ) LIST( APPEND OPENCL_INCLUDE_DIRS ${_OPENCL_CPP_INCLUDE_DIRS} ) # This is often the same, so clean up LIST( REMOVE_DUPLICATES OPENCL_INCLUDE_DIRS ) ENDIF(_OPENCL_CPP_INCLUDE_DIRS) MARK_AS_ADVANCED( OPENCL_INCLUDE_DIRS ) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindOpenCL.cmake.old000077500000000000000000000046771321604176500263200ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## As posted on NVidia forum ## http://forums.nvidia.com/index.php?showtopic=97795 ## Version: Oct 5, 2009 ## Downloaded: Nov 14, 2009 ## Modified by GCS ## Modified by JAS (Feb 15, 2012) ##----------------------------------------------------------------------------- if (APPLE) # JAS 2012.02.15 # First, let's deal with OS X # # ...but not now, perhaps later. OS X provides OpenCL # as a Framework, which is great if you can compile your # program at the command prompt with a gcc one-liner, I guess. # # Some time will have to go into making this CMake Find # file play nice, so for now we just prevent any build # errors by doing nothing here. else (APPLE) # Second, let's handle the Win32 / Linux cases ## Check for AMD/ATI set(ENV_ATISTREAMSDKROOT $ENV{ATISTREAMSDKROOT}) ## ATI if(ENV_ATISTREAMSDKROOT) find_path( OPENCL_INCLUDE_DIR NAMES CL/cl.h OpenCL/cl.h PATHS $ENV{ATISTREAMSDKROOT}/include NO_DEFAULT_PATH ) ## Both windows and linux follow this directory structure. if(CMAKE_SIZEOF_VOID_P EQUAL 4) set( OPENCL_LIB_SEARCH_PATH ${OPENCL_LIB_SEARCH_PATH} $ENV{ATISTREAMSDKROOT}/lib/x86 ) else(CMAKE_SIZEOF_VOID_P EQUAL 4) set( OPENCL_LIB_SEARCH_PATH ${OPENCL_LIB_SEARCH_PATH} $ENV{ATISTREAMSDKROOT}/lib/x86_64 ) endif(CMAKE_SIZEOF_VOID_P EQUAL 4) find_library( OPENCL_LIBRARY NAMES OpenCL PATHS ${OPENCL_LIB_SEARCH_PATH} NO_DEFAULT_PATH ) ## NVIDIA else(ENV_ATISTREAMSDKROOT) find_path( OPENCL_INCLUDE_DIR PATHS $ENV{CUDA_INC_PATH} NAMES CL/cl.h OpenCL/cl.h ) find_library( OPENCL_LIBRARY PATHS $ENV{CUDA_LIB_PATH} NAMES OpenCL ) endif(ENV_ATISTREAMSDKROOT) endif (APPLE) include(FindPackageHandleStandardArgs) find_package_handle_standard_args( OPENCL DEFAULT_MSG OPENCL_LIBRARY OPENCL_INCLUDE_DIR ) # JAS 2010.12.09 # Edit to allow OpenCL to be delay loaded IF (OPENCL_FOUND) SET (OPENCL_LIBRARIES ${OPENCL_LIBRARY}) ELSE (OPENCL_FOUND) SET (OPENCL_LIBRARIES) ENDIF (OPENCL_FOUND) if(MINGW) set(OPENCL_FOUND FALSE) endif(MINGW) mark_as_advanced( OPENCL_INCLUDE_DIR OPENCL_LIBRARY ) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindOpenMP.cmake000077500000000000000000000055661321604176500255570ustar00rootroot00000000000000###################################################### ## OpenMP ###################################################### include (CheckFunctionExists) include (CheckCXXSourceCompiles) message (STATUS "Check for compiler OpenMP support...") set (OPENMP_FLAGS) set (OPENMP_LIBRARIES) set (OPENMP_FOUND FALSE) # sample openmp source code to test set(OpenMP_C_TEST_SOURCE " #include int main() { #ifdef _OPENMP return 0; #else breaks_on_purpose #endif } ") # Key: CFLAGS##LDFLAGS#LIBRARIES # Neither CFLAGS nor LDFLAGS can be empty. Use NONE instead. set( OPENMP_FLAGS_AND_LIBRARIES # gcc "-fopenmp##-fopenmp#" "-fopenmp##-fopenmp#gomp" "-fopenmp##-fopenmp#gomp pthread" # MSVC "/openmp##NONE#" # clang (??) "-fopenmp=libomp##NONE#gomp" # icc "-openmp##-openmp#" "-openmp -parallel##-openmp -parallel#" # SGI & PGI "-mp##-mp#" # Sun "-xopenmp##-xopenmp#" # Tru64 "-omp##-omp#" # AIX "-qsmp=omp##-qsmp=omp#" ) # Massive hack to workaround CMake limitations list (LENGTH OPENMP_FLAGS_AND_LIBRARIES NUM_FLAGS) math (EXPR NUM_FLAGS "${NUM_FLAGS} - 1") foreach (I RANGE 0 ${NUM_FLAGS}) if (NOT OPENMP_FOUND) list (GET OPENMP_FLAGS_AND_LIBRARIES ${I} TMP) string (REGEX MATCH "([^#]*)" OPENMP_FLAGS ${TMP}) string (REGEX REPLACE "[^#]*##" "" TMP ${TMP}) string (REGEX MATCH "([^#]*)" OPENMP_LDFLAGS ${TMP}) string (REGEX REPLACE "[^#]*#" "" OPENMP_LIBRARIES ${TMP}) # message (STATUS "OPENMP_FLAGS=${OPENMP_FLAGS}") # message (STATUS "OPENMP_LDFLAGS = ${OPENMP_LDFLAGS}") # message (STATUS "OPENMP_LIBRARIES = ${OPENMP_LIBRARIES}") # message (STATUS "-------") if (OPENMP_LDFLAGS MATCHES "NONE") set (OPENMP_LDFLAGS "") endif () if (OPENMP_LIBRARIES MATCHES " ") string (REPLACE " " ";" OPENMP_LIBRARIES ${OPENMP_LIBRARIES}) endif () # 2017-12-07. If you overwrite CMAKE_REQUIRED_FLAGS, FindCUDA # does not work correctly. It gives the wrong set of libraries. # Therefore, we must save and restore the original values. push_vars ("CMAKE_REQUIRED_QUIET" "CMAKE_REQUIRED_FLAGS" "CMAKE_REQUIRED_LIBRARIES") set (CMAKE_REQUIRED_QUIET TRUE) set (CMAKE_REQUIRED_FLAGS ${OPENMP_FLAGS}) set (CMAKE_REQUIRED_LIBRARIES ${OPENMP_LIBRARIES}) # CMake caches results from test compilations. We need to unset the # cache value, or else cached test results gets used after first # iteration unset (OPENMP_COMPILES CACHE) check_cxx_source_compiles ("${OpenMP_C_TEST_SOURCE}" OPENMP_COMPILES) pop_vars ("CMAKE_REQUIRED_QUIET" "CMAKE_REQUIRED_FLAGS" "CMAKE_REQUIRED_LIBRARIES") if (OPENMP_COMPILES) set (OPENMP_FOUND TRUE) endif () endif () endforeach () if (OPENMP_FOUND) message (STATUS "OpenMP flags \"${OPENMP_FLAGS}\", OpenMP libraries \"${OPENMP_LIBRARIES}\"") else () message (STATUS "Given compiler does not support OpenMP.") endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindPantheios.cmake000077500000000000000000000011341321604176500263360ustar00rootroot00000000000000# - find PANTHEIOS libraries # # STLSOFT_INCLUDE_DIR - Include directories for STLSOFT # PANTHEIOS_INCLUDE_DIR - Include directories for PANTHEIOS # PANTHEIOS_FOUND - If false, don't try to use PANTHEIOS FIND_PATH(PANTHEIOS_INCLUDE_DIR pantheios/pantheios.h $ENV{FASTFORMAT_ROOT}/include ) FIND_PATH(STLSOFT_INCLUDE_DIR stlsoft/algorithms.hpp $ENV{STLSOFT}/include ) IF(PANTHEIOS_INCLUDE_DIR AND STLSOFT_INCLUDE_DIR) SET(PANTHEIOS_FOUND TRUE) ELSE(PANTHEIOS_INCLUDE_DIR AND STLSOFT_INCLUDE_DIR) SET(PANTHEIOS_FOUND FALSE) ENDIF(PANTHEIOS_INCLUDE_DIR AND STLSOFT_INCLUDE_DIR) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindPaxscan.cmake000077500000000000000000000011311321604176500257760ustar00rootroot00000000000000# Varian Paxscan # These variables are set: # # PAXSCAN_FOUND # PAXSCAN_INCLUDE_DIR # PAXSCAN_LIBRARIES # # Only works on Windows if (PAXSCAN_INCLUDE_DIR) # Already in cache, be silent set (Paxscan_FIND_QUIETLY TRUE) endif () FIND_PATH (PAXSCAN_INCLUDE_DIR "HcpFuncDefs.h" "C:/Program Files/Varian/PaxscanL04/DeveloperFiles/Includes" ) FIND_LIBRARY (PAXSCAN_LIBRARIES "VirtCp.lib" "C:/Program Files/Varian/PaxscanL04/DeveloperFiles/VirtCpRel") INCLUDE (FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS (Paxscan DEFAULT_MSG PAXSCAN_LIBRARIES PAXSCAN_INCLUDE_DIR) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindRTK.cmake000077500000000000000000000030531321604176500250460ustar00rootroot00000000000000# - Find RTK # Find the RTK includes and library # # RTK_SOURCE_DIR - where to find RTK source directory # JAS 2010.11.24 # I've grown tired for getting my build log filled with # errors from RTK when I check for Windows compile sanity... # Give an option to turn this off without excluding ITK. SET (PLM_BUILD_RTK ON CACHE BOOL "Build RTK") IF (NOT RTK_SOURCE_DIR) FIND_PATH (RTK_SOURCE_DIR RTKconfig.cmake.in "${CMAKE_SOURCE_DIR}/libs/RTK.git" "${CMAKE_SOURCE_DIR}/libs/RTK" "${CMAKE_SOURCE_DIR}/libs/RTK.svn" $ENV{RTK_SOURCE_DIR} DOC "directory containing RTK source files") ENDIF (NOT RTK_SOURCE_DIR) #IF (NOT RTK_SOURCE_DIR) # MESSAGE (ERROR "Sorry, I couldn't find the RTK directory") #ENDIF (NOT RTK_SOURCE_DIR) # JAS 2010.11.23 # Make life easier for people who only # want to build plastimatch components # that don't depend on ITK. FIND_PACKAGE (ITK) IF (PLM_BUILD_RTK) IF (NOT ITK_FOUND) MESSAGE (STATUS "NOT building RTK, could not find ITK") ELSE(NOT ITK_FOUND) MESSAGE (STATUS "Building RTK") ## GCS (Dec 2, 2010) - Don't do this. RTK/github is unstable. ##ADD_SUBDIRECTORY (${RTK_SOURCE_DIR}) ENDIF (NOT ITK_FOUND) ELSE (PLM_BUILD_RTK) MESSAGE (STATUS "NOT Building RTK") ENDIF (PLM_BUILD_RTK) IF (NOT RTK_DIR) FIND_PATH (RTK_DIR RTKconfig.cmake $ENV{RTK_DIR} DOC "directory containing RTK build files") ENDIF (NOT RTK_DIR) IF (RTK_DIR AND ITK_FOUND AND PLM_BUILD_RTK) SET (RTK_FOUND 1) INCLUDE (${RTK_DIR}/RTKconfig.cmake) ENDIF (RTK_DIR AND ITK_FOUND AND PLM_BUILD_RTK) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindReadline.cmake000066400000000000000000000024071321604176500261300ustar00rootroot00000000000000# from http://websvn.kde.org/trunk/KDE/kdeedu/cmake/modules/FindReadline.cmake # http://websvn.kde.org/trunk/KDE/kdeedu/cmake/modules/COPYING-CMAKE-SCRIPTS # --> BSD licensed # # GNU Readline library finder if(READLINE_INCLUDE_DIR AND READLINE_LIBRARY AND NCURSES_LIBRARY) set(READLINE_FOUND TRUE) else(READLINE_INCLUDE_DIR AND READLINE_LIBRARY AND NCURSES_LIBRARY) FIND_PATH(READLINE_INCLUDE_DIR readline/readline.h /usr/include/readline ) # 2008-04-22 The next clause used to read like this: # # FIND_LIBRARY(READLINE_LIBRARY NAMES readline) # FIND_LIBRARY(NCURSES_LIBRARY NAMES ncurses ) # include(FindPackageHandleStandardArgs) # FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG NCURSES_LIBRARY READLINE_INCLUDE_DIR READLINE_LIBRARY ) # # I was advised to modify it such that it will find an ncurses library if # required, but not if one was explicitly given, that is, it allows the # default to be overridden. PH FIND_LIBRARY(READLINE_LIBRARY NAMES readline) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG READLINE_INCLUDE_DIR READLINE_LIBRARY ) MARK_AS_ADVANCED(READLINE_INCLUDE_DIR READLINE_LIBRARY) endif(READLINE_INCLUDE_DIR AND READLINE_LIBRARY AND NCURSES_LIBRARY) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindSQLite.cmake000066400000000000000000000015631321604176500255500ustar00rootroot00000000000000# - Find Sqlite # Find the native Sqlite includes and library # # SQLITE_INCLUDE_DIR - where to find zlib.h, etc. # SQLITE_LIBRARIES - List of libraries when using zlib. # SQLITE_FOUND - True if zlib found. IF (SQLITE_INCLUDE_DIR) # Already in cache, be silent SET (Sqlite_FIND_QUIETLY TRUE) ENDIF (SQLITE_INCLUDE_DIR) FIND_PATH(SQLITE_INCLUDE_DIR sqlite3.h) SET (SQLITE_NAMES sqlite3) FIND_LIBRARY (SQLITE_LIBRARY NAMES ${SQLITE_NAMES}) # handle the QUIETLY and REQUIRED arguments and set SQLITE_FOUND to TRUE if # all listed variables are TRUE INCLUDE (FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS (SQLITE DEFAULT_MSG SQLITE_LIBRARY SQLITE_INCLUDE_DIR) IF(SQLITE_FOUND) SET (SQLITE_LIBRARIES ${SQLITE_LIBRARY}) ELSE (SQLITE_FOUND) SET (SQLITE_LIBRARIES) ENDIF (SQLITE_FOUND) MARK_AS_ADVANCED (SQLITE_LIBRARY SQLITE_INCLUDE_DIR) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindSSE.cmake000066400000000000000000000035751321604176500250460ustar00rootroot00000000000000# JAS 08.19.2010 # I have tested this working under Linux using gcc-4.4 # The OSX/Darwin case is untested, but should work in theory. # LINUX: We check for SSE extensions using a RegEx on /proc/cpuinfo IF(CMAKE_SYSTEM_NAME MATCHES "Linux") # Store /proc/cpuinfo output into CPUINFO EXEC_PROGRAM (cat ARGS "/proc/cpuinfo" OUTPUT_VARIABLE CPUINFO) # Check for SSE2 STRING (REGEX REPLACE "^.*(sse2).*$" "\\1" SSE_THERE ${CPUINFO}) STRING (COMPARE EQUAL "sse2" "${SSE_THERE}" SSE2_TRUE) IF (SSE2_TRUE) SET (SSE2_FOUND true CACHE BOOL "SSE2 Available?") SET (SSE2_FLAGS "-msse2 -mfpmath=sse") ELSE (SSE2_TRUE) SET (SSE2_FOUND false CACHE BOOL "SSE2 Available?") ENDIF (SSE2_TRUE) # OSX/DARWIN: We check for SSE extensions using a RegEx on sysctl output ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Darwin") EXEC_PROGRAM ("/usr/sbin/sysctl -n machdep.cpu.features" OUTPUT_VARIABLE CPUINFO) # Check for SSE2 STRING (REGEX REPLACE "^.*(SSE2).*$" "\\1" SSE_THERE ${CPUINFO}) STRING (COMPARE EQUAL "SSE2" "${SSE_THERE}" SSE2_TRUE) IF (SSE2_TRUE) SET (SSE2_FOUND true CACHE BOOL "SSE2 Available?") SET (SSE2_FLAGS "-msse2 -mfpmath=sse") # Darwin uses gcc, right? ELSE (SSE2_TRUE) SET (SSE2_FOUND false CACHE BOOL "SSE2 Available?") ENDIF (SSE2_TRUE) # WINDOWS: Currently, no SSE detection method. Disabled. ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Windows") set (SSE2_FOUND false CACHE BOOL "SSE2 Available?") # Something else... BSD or BeOS, perhaps? Disabled. ELSE (CMAKE_SYSTEM_NAME MATCHES "Linux") set (SSE2_FOUND false CACHE BOOL "SSE2 Available?") ENDIF (CMAKE_SYSTEM_NAME MATCHES "Linux") # Report SSE2 compiler flags or failure. IF (SSE2_FOUND) MESSAGE (STATUS "SSE2_FLAGS \"${SSE2_FLAGS}\"") ELSE (SSE2_FOUND) MESSAGE (STATUS "CPU does not support SSE2.") ENDIF (SSE2_FOUND) # Put this in the advanced toggles mark_as_advanced (SSE2_FOUND) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindSubversion.cmake000077500000000000000000000150361321604176500265510ustar00rootroot00000000000000# - Extract information from a subversion working copy # The module defines the following variables: # Subversion_SVN_EXECUTABLE - path to svn command line client # Subversion_VERSION_SVN - version of svn command line client # Subversion_FOUND - true if the command line client was found # If the command line client executable is found the macro # Subversion_WC_INFO( ) # is defined to extract information of a subversion working copy at # a given location. The macro defines the following variables: # _WC_URL - url of the repository (at ) # _WC_ROOT - root url of the repository # _WC_REVISION - current revision # _WC_LAST_CHANGED_AUTHOR - author of last commit # _WC_LAST_CHANGED_DATE - date of last commit # _WC_LAST_CHANGED_REV - revision of last commit # _WC_LAST_CHANGED_LOG - last log of base revision # _WC_INFO - output of command `svn info ' # Example usage: # FIND_PACKAGE(Subversion) # IF(Subversion_FOUND) # Subversion_WC_INFO(${PROJECT_SOURCE_DIR} Project) # MESSAGE("Current revision is ${Project_WC_REVISION}") # Subversion_WC_LOG(${PROJECT_SOURCE_DIR} Project) # MESSAGE("Last changed log is ${Project_LAST_CHANGED_LOG}") # ENDIF(Subversion_FOUND) # Copyright (c) 2006, Tristan Carel # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the University of California, Berkeley nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # $Id: FindSubversion.cmake,v 1.2.2.3 2008-05-23 20:09:34 hoffman Exp $ SET(Subversion_FOUND FALSE) SET(Subversion_SVN_FOUND FALSE) FIND_PROGRAM(Subversion_SVN_EXECUTABLE NAMES svn C:/cygwin/bin/svn DOC "subversion command line client") FIND_PROGRAM(Subversion_SVNVERSION_EXECUTABLE NAMES svnversion C:/cygwin/bin/svnversion DOC "subversion svnversion program") MARK_AS_ADVANCED(Subversion_SVN_EXECUTABLE) MARK_AS_ADVANCED(Subversion_SVNVERSION_EXECUTABLE) IF(Subversion_SVN_EXECUTABLE) SET(Subversion_SVN_FOUND TRUE) SET(Subversion_FOUND TRUE) MACRO(Subversion_WC_INFO dir prefix) # the subversion commands should be executed with the C locale, otherwise # the message (which are parsed) may be translated, Alex SET(_Subversion_SAVED_LC_ALL "$ENV{LC_ALL}") SET(ENV{LC_ALL} C) EXECUTE_PROCESS(COMMAND ${Subversion_SVN_EXECUTABLE} --version WORKING_DIRECTORY ${dir} OUTPUT_VARIABLE Subversion_VERSION_SVN OUTPUT_STRIP_TRAILING_WHITESPACE) EXECUTE_PROCESS(COMMAND ${Subversion_SVN_EXECUTABLE} info ${dir} OUTPUT_VARIABLE ${prefix}_WC_INFO ERROR_VARIABLE Subversion_svn_info_error RESULT_VARIABLE Subversion_svn_info_result OUTPUT_STRIP_TRAILING_WHITESPACE) IF(NOT ${Subversion_svn_info_result} EQUAL 0) MESSAGE(SEND_ERROR "Command \"${Subversion_SVN_EXECUTABLE} info ${dir}\" failed with output:\n${Subversion_svn_info_error}") ELSE(NOT ${Subversion_svn_info_result} EQUAL 0) STRING(REGEX REPLACE "^(.*\n)?svn, version ([.0-9]+).*" "\\2" Subversion_VERSION_SVN "${Subversion_VERSION_SVN}") STRING(REGEX REPLACE "^(.*\n)?URL: ([^\n]+).*" "\\2" ${prefix}_WC_URL "${${prefix}_WC_INFO}") STRING(REGEX REPLACE "^(.*\n)?Revision: ([^\n]+).*" "\\2" ${prefix}_WC_REVISION "${${prefix}_WC_INFO}") STRING(REGEX REPLACE "^(.*\n)?Last Changed Author: ([^\n]+).*" "\\2" ${prefix}_WC_LAST_CHANGED_AUTHOR "${${prefix}_WC_INFO}") STRING(REGEX REPLACE "^(.*\n)?Last Changed Rev: ([^\n]+).*" "\\2" ${prefix}_WC_LAST_CHANGED_REV "${${prefix}_WC_INFO}") STRING(REGEX REPLACE "^(.*\n)?Last Changed Date: ([^\n]+).*" "\\2" ${prefix}_WC_LAST_CHANGED_DATE "${${prefix}_WC_INFO}") ENDIF(NOT ${Subversion_svn_info_result} EQUAL 0) # restore the previous LC_ALL SET(ENV{LC_ALL} ${_Subversion_SAVED_LC_ALL}) ENDMACRO(Subversion_WC_INFO) MACRO(Subversion_WC_LOG dir prefix) # This macro can block if the certificate is not signed: # svn ask you to accept the certificate and wait for your answer # This macro requires a svn server network access (Internet most of the time) # and can also be slow since it access the svn server EXECUTE_PROCESS(COMMAND ${Subversion_SVN_EXECUTABLE} log -r BASE ${dir} OUTPUT_VARIABLE ${prefix}_LAST_CHANGED_LOG ERROR_VARIABLE Subversion_svn_log_error RESULT_VARIABLE Subversion_svn_log_result OUTPUT_STRIP_TRAILING_WHITESPACE) IF(NOT ${Subversion_svn_log_result} EQUAL 0) MESSAGE(SEND_ERROR "Command \"${Subversion_SVN_EXECUTABLE} log -r BASE ${dir}\" failed with output:\n${Subversion_svn_log_error}") ENDIF(NOT ${Subversion_svn_log_result} EQUAL 0) ENDMACRO(Subversion_WC_LOG) ENDIF(Subversion_SVN_EXECUTABLE) IF(NOT Subversion_FOUND) IF(NOT Subversion_FIND_QUIETLY) MESSAGE(STATUS "Subversion was not found.") ELSE(NOT Subversion_FIND_QUIETLY) IF(Subversion_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Subversion was not found.") ENDIF(Subversion_FIND_REQUIRED) ENDIF(NOT Subversion_FIND_QUIETLY) ENDIF(NOT Subversion_FOUND) # FindSubversion.cmake ends here. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindTR1.cmake000066400000000000000000000035471321604176500250210ustar00rootroot00000000000000# ########################################################################## # This file is from the SeqAn project, www.seqan.de # Distributed under 3-clause BSD license # ########################################################################## # Check availability of C++ TR1 contents. # # Sets the following variables: # # TR1_SHARED_PTR_FOUND -- std::tr1::shared_ptr1 available # TR1_SHARED_PTR_USE_TR1_MEMORY -- #include # TR1_SHARED_PTR_USE_MEMORY -- #include # We need to have at least this version to support the VERSION_LESS argument to 'if' (2.6.2) and unset (2.6.3) cmake_policy(PUSH) cmake_minimum_required(VERSION 2.6.3) cmake_policy(POP) include (CheckCXXSourceCompiles) # --------------------------------------------------------------------------- # std::tr1::shared_ptr # --------------------------------------------------------------------------- check_cxx_source_compiles( " #include int main() { std::shared_ptr ptr; return 0; } " SHARED_PTR_USE_MEMORY) check_cxx_source_compiles( " #include int main() { std::tr1::shared_ptr ptr; return 0; } " TR1_SHARED_PTR_USE_TR1_MEMORY) check_cxx_source_compiles( " #include int main() { std::tr1::shared_ptr ptr; return 0; } " TR1_SHARED_PTR_USE_MEMORY) set (SHARED_PTR -NOTFOUND) if (SHARED_PTR_USE_MEMORY) set (SHARED_PTR_FOUND TRUE) endif () if (TR1_SHARED_PTR_USE_TR1_MEMORY) set (SHARED_PTR_FOUND TRUE) endif () if (TR1_SHARED_PTR_USE_MEMORY) set (SHARED_PTR_FOUND TRUE) endif () mark_as_advanced (SHARED_PTR_FOUND) mark_as_advanced (SHARED_PTR_USE_MEMORY) mark_as_advanced (TR1_SHARED_PTR_USE_TR1_MEMORY) mark_as_advanced (TR1_SHARED_PTR_USE_MEMORY) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindThrust.cmake000066400000000000000000000016031321604176500256730ustar00rootroot00000000000000# - Find Thrust # Find the native Thrust includes and library # # THRUST_INCLUDE_DIR - where to find zlib.h, etc. # THRUST_FOUND - True if zlib found. if (NOT THRUST_DIR) find_path (THRUST_DIR THRUSTconfig.cmake $ENV{THRUST_DIR} DOC "The build directory, containing Thrustconfig.cmake") endif (NOT THRUST_DIR) if (THRUST_DIR) if (EXISTS (${THRUST_DIR}/Thrustconfig.cmake)) include (${THRUST_DIR}/Thrustconfig.cmake) endif () endif (THRUST_DIR) if (THRUST_INCLUDE_DIR) # Already in cache, be silent set (Thrust_FIND_QUIETLY TRUE) endif (THRUST_INCLUDE_DIR) find_path (THRUST_INCLUDE_DIR "thrust/uninitialized_fill.h" PATHS "${THRUST_DIR}") # handle the QUIETLY and REQUIRED arguments and set THRUST_FOUND to TRUE if # all listed variables are TRUE include (FindPackageHandleStandardArgs) find_package_handle_standard_args (THRUST DEFAULT_MSG THRUST_INCLUDE_DIR) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindYamlCpp.cmake000077500000000000000000000027461321604176500257630ustar00rootroot00000000000000# Locate yaml-cpp # # This module defines # YAMLCPP_FOUND, if false, do not try to link to yaml-cpp # YAMLCPP_LIBRARY, where to find yaml-cpp # YAMLCPP_INCLUDE_DIR, where to find yaml.h # # By default, the dynamic libraries of yaml-cpp will be found. To find the static ones instead, # you must set the YAMLCPP_STATIC_LIBRARY variable to TRUE before calling find_package(YamlCpp ...). # # If yaml-cpp is not installed in a standard path, you can use the YAMLCPP_DIR CMake variable # to tell CMake where yaml-cpp is. # attempt to find static library first if this is set if(YAMLCPP_STATIC_LIBRARY) set(YAMLCPP_STATIC libyaml-cpp.a) endif() # find the yaml-cpp include directory find_path(YAMLCPP_INCLUDE_DIR yaml-cpp/yaml.h PATH_SUFFIXES include PATHS ~/Library/Frameworks/yaml-cpp/include/ /Library/Frameworks/yaml-cpp/include/ /usr/local/include/ /usr/include/ /sw/yaml-cpp/ # Fink /opt/local/yaml-cpp/ # DarwinPorts /opt/csw/yaml-cpp/ # Blastwave /opt/yaml-cpp/ ${YAMLCPP_DIR}/include/) # find the yaml-cpp library find_library(YAMLCPP_LIBRARY NAMES ${YAMLCPP_STATIC} yaml-cpp PATH_SUFFIXES lib64 lib PATHS ~/Library/Frameworks /Library/Frameworks /usr/local /usr /sw /opt/local /opt/csw /opt ${YAMLCPP_DIR}/lib) # handle the QUIETLY and REQUIRED arguments and set YAMLCPP_FOUND to TRUE if all listed variables are TRUE include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(YAMLCPP DEFAULT_MSG YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY) mark_as_advanced(YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/FindZLIB.cmake000077500000000000000000000072641321604176500251560ustar00rootroot00000000000000# - Find zlib # Find the native ZLIB includes and library. # Once done this will define # # ZLIB_INCLUDE_DIRS - where to find zlib.h, etc. # ZLIB_LIBRARIES - List of libraries when using zlib. # ZLIB_FOUND - True if zlib found. # # ZLIB_VERSION_STRING - The version of zlib found (x.y.z) # ZLIB_VERSION_MAJOR - The major version of zlib # ZLIB_VERSION_MINOR - The minor version of zlib # ZLIB_VERSION_PATCH - The patch version of zlib # ZLIB_VERSION_TWEAK - The tweak version of zlib # # The following variable are provided for backward compatibility # # ZLIB_MAJOR_VERSION - The major version of zlib # ZLIB_MINOR_VERSION - The minor version of zlib # ZLIB_PATCH_VERSION - The patch version of zlib #============================================================================= # Copyright 2001-2009 Kitware, Inc. # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distributed this file outside of CMake, substitute the full # License text for the above reference.) FIND_PATH(ZLIB_INCLUDE_DIR zlib.h "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Zlib;InstallPath]/include" ) SET(ZLIB_NAMES z zlib zdll) FIND_LIBRARY(ZLIB_LIBRARY NAMES ${ZLIB_NAMES} PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Zlib;InstallPath]/lib" ) MARK_AS_ADVANCED(ZLIB_LIBRARY ZLIB_INCLUDE_DIR) IF(ZLIB_INCLUDE_DIR AND EXISTS "${ZLIB_INCLUDE_DIR}/zlib.h") FILE(STRINGS "${ZLIB_INCLUDE_DIR}/zlib.h" ZLIB_H REGEX "^#define ZLIB_VERSION \"[^\"]*\"$") string(REGEX REPLACE "^.*ZLIB_VERSION \"([0-9]+).*$" "\\1" ZLIB_VERSION_MAJOR "${ZLIB_H}") string(REGEX REPLACE "^.*ZLIB_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" ZLIB_VERSION_MINOR "${ZLIB_H}") string(REGEX REPLACE "^.*ZLIB_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" ZLIB_VERSION_PATCH "${ZLIB_H}") string(REGEX REPLACE "^.*ZLIB_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" ZLIB_VERSION_TWEAK "${ZLIB_H}") set(ZLIB_VERSION_STRING "${ZLIB_VERSION_MAJOR}.${ZLIB_VERSION_MINOR}.${ZLIB_VERSION_PATCH}.${ZLIB_VERSION_TWEAK}") set(ZLIB_MAJOR_VERSION "${ZLIB_VERSION_MAJOR}") set(ZLIB_MINOR_VERSION "${ZLIB_VERSION_MINOR}") set(ZLIB_PATCH_VERSION "${ZLIB_VERSION_PATCH}") ENDIF() # handle the QUIETLY and REQUIRED arguments and set ZLIB_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZLIB DEFAULT_MSG ZLIB_LIBRARY ZLIB_INCLUDE_DIR) # handle the VERSION provided in find_package() command if(ZLIB_FIND_VERSION) if(ZLIB_FIND_VERSION_EXACT AND NOT ${ZLIB_VERSION_STRING} VERSION_EQUAL ${ZLIB_FIND_VERSION}) message(FATAL_ERROR "ZLIB version found (${ZLIB_VERSION_STRING}) does not match the required one (${ZLIB_FIND_VERSION}), aborting.") elseif(${ZLIB_VERSION_STRING} VERSION_LESS ${ZLIB_FIND_VERSION}) if(ZLIB_FIND_REQUIRED) message(FATAL_ERROR "ZLIB version found (${ZLIB_VERSION_STRING}) is less then the minimum required (${ZLIB_FIND_VERSION}), aborting.") else(ZLIB_FIND_REQUIRED) message("ZLIB version found (${ZLIB_VERSION_STRING}) is less then the minimum required (${ZLIB_FIND_VERSION}), continue without ZLIB support.") set(ZLIB_FOUND FALSE) endif(ZLIB_FIND_REQUIRED) endif() endif(ZLIB_FIND_VERSION) IF(ZLIB_FOUND) SET(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR}) SET(ZLIB_LIBRARIES ${ZLIB_LIBRARY}) ENDIF() plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/HandleITK.cmake000066400000000000000000000033621321604176500253500ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## HandleITK.cmake ## Check ITK version and optional components ## Include use file (for registering IO factories) ##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- # GCS 2016-10-20 # The GDCM USE file spews out copious extraneous warnings on Debian. # If we are not using GDCM, this might be avoided by setting # ITK_USE_SYSTEM_GDCM to FALSE. However, this has the undesirable # effect of removing gdcm includes from include list and gdcm libraries # from library list. #if (DCMTK_FOUND) # set (ITK_USE_SYSTEM_GDCM FALSE) #endif () # GCS 2017-12-14 On older ITK version, the use file sets variables such # as DCMTK_FOUND, DCMTK_DIR. Needs more investigation. include (${ITK_USE_FILE}) if (NOT ITK_VERSION) set (ITK_VERSION "${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}.${ITK_VERSION_PATCH}") endif () if (${ITK_VERSION} VERSION_LESS "3.16.0") message (FATAL_ERROR "Fatal Error. ITK must be version 3.16.0 or higher") endif () if (${ITK_VERSION_MAJOR} VERSION_EQUAL "3") if (NOT ITK_USE_REVIEW) message (FATAL_ERROR "Fatal Error. ITK must be compiled with ITK_USE_REVIEW set to ON") endif () set (ITK_LIBRARIES ${ITK_LIBRARIES} ITKIOReview) elseif (${ITK_VERSION_MAJOR} VERSION_EQUAL "4") if (${ITK_VERSION} VERSION_LESS "4.1") message (FATAL_ERROR "Fatal Error. ITK 4 must be 4.1 or greater") endif () else () message (FATAL_ERROR "Fatal Error. ITK version should be either 3.X or 4.X") endif () message (STATUS "ITK_VERSION = ${ITK_VERSION} found") InstallRequiredSystemLibrariesPatched.cmake000077500000000000000000000404441321604176500331750ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake# By including this file, all library files listed in the variable # CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS will be installed with # install(PROGRAMS ...) into bin for WIN32 and lib # for non-WIN32. If CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP is set to TRUE # before including this file, then the INSTALL command is not called. # The user can use the variable CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS to use a # custom install command and install them however they want. # If it is the MSVC compiler, then the microsoft run # time libraries will be found and automatically added to the # CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS, and installed. # If CMAKE_INSTALL_DEBUG_LIBRARIES is set and it is the MSVC # compiler, then the debug libraries are installed when available. # If CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY is set then only the debug # libraries are installed when both debug and release are available. # If CMAKE_INSTALL_MFC_LIBRARIES is set then the MFC run time # libraries are installed as well as the CRT run time libraries. # If CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION is set then the libraries are # installed to that directory rather than the default. # If CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS is NOT set, then this file # warns about required files that do not exist. You can set this variable to # ON before including this file to avoid the warning. For example, the Visual # Studio Express editions do not include the redistributable files, so if you # include this file on a machine with only VS Express installed, you'll get # the warning. #============================================================================= # Copyright 2006-2009 Kitware, Inc. # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) if(MSVC) file(TO_CMAKE_PATH "$ENV{SYSTEMROOT}" SYSTEMROOT) if(CMAKE_CL_64) if(MSVC_VERSION GREATER 1599) # VS 10 and later: set(CMAKE_MSVC_ARCH x64) else() # VS 9 and earlier: set(CMAKE_MSVC_ARCH amd64) endif() else() set(CMAKE_MSVC_ARCH x86) endif() get_filename_component(devenv_dir "${CMAKE_MAKE_PROGRAM}" PATH) get_filename_component(base_dir "${devenv_dir}/../.." ABSOLUTE) if(MSVC70) set(__install__libs "${SYSTEMROOT}/system32/msvcp70.dll" "${SYSTEMROOT}/system32/msvcr70.dll" ) endif() if(MSVC71) set(__install__libs "${SYSTEMROOT}/system32/msvcp71.dll" "${SYSTEMROOT}/system32/msvcr71.dll" ) endif() if(MSVC80) # Find the runtime library redistribution directory. get_filename_component(msvc_install_dir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]" ABSOLUTE) find_path(MSVC80_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC80.CRT/Microsoft.VC80.CRT.manifest PATHS "${msvc_install_dir}/../../VC/redist" "${base_dir}/VC/redist" ) mark_as_advanced(MSVC80_REDIST_DIR) set(MSVC80_CRT_DIR "${MSVC80_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.CRT") # Install the manifest that allows DLLs to be loaded from the # directory containing the executable. if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) set(__install__libs "${MSVC80_CRT_DIR}/Microsoft.VC80.CRT.manifest" "${MSVC80_CRT_DIR}/msvcm80.dll" "${MSVC80_CRT_DIR}/msvcp80.dll" "${MSVC80_CRT_DIR}/msvcr80.dll" ) endif() if(CMAKE_INSTALL_DEBUG_LIBRARIES) set(MSVC80_CRT_DIR "${MSVC80_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC80.DebugCRT") set(__install__libs ${__install__libs} "${MSVC80_CRT_DIR}/Microsoft.VC80.DebugCRT.manifest" "${MSVC80_CRT_DIR}/msvcm80d.dll" "${MSVC80_CRT_DIR}/msvcp80d.dll" "${MSVC80_CRT_DIR}/msvcr80d.dll" ) endif() endif() if(MSVC90) # Find the runtime library redistribution directory. get_filename_component(msvc_install_dir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]" ABSOLUTE) get_filename_component(msvc_express_install_dir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\9.0;InstallDir]" ABSOLUTE) find_path(MSVC90_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest PATHS "${msvc_install_dir}/../../VC/redist" "${msvc_express_install_dir}/../../VC/redist" "${base_dir}/VC/redist" ) mark_as_advanced(MSVC90_REDIST_DIR) set(MSVC90_CRT_DIR "${MSVC90_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.CRT") # Install the manifest that allows DLLs to be loaded from the # directory containing the executable. if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) set(__install__libs "${MSVC90_CRT_DIR}/Microsoft.VC90.CRT.manifest" "${MSVC90_CRT_DIR}/msvcm90.dll" "${MSVC90_CRT_DIR}/msvcp90.dll" "${MSVC90_CRT_DIR}/msvcr90.dll" ) endif() if(CMAKE_INSTALL_DEBUG_LIBRARIES) set(MSVC90_CRT_DIR "${MSVC90_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC90.DebugCRT") set(__install__libs ${__install__libs} "${MSVC90_CRT_DIR}/Microsoft.VC90.DebugCRT.manifest" "${MSVC90_CRT_DIR}/msvcm90d.dll" "${MSVC90_CRT_DIR}/msvcp90d.dll" "${MSVC90_CRT_DIR}/msvcr90d.dll" ) endif() endif() macro(MSVCRT_FILES_FOR_VERSION version) set(v "${version}") set(ProgramFilesX86 "ProgramFiles(x86)") # Find the runtime library redistribution directory. get_filename_component(msvc_install_dir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\${v}.0;InstallDir]" ABSOLUTE) find_path(MSVC${v}_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC${v}0.CRT PATHS "${msvc_install_dir}/../../VC/redist" "${base_dir}/VC/redist" "$ENV{ProgramFiles}/Microsoft Visual Studio ${v}.0/VC/redist" "$ENV{${ProgramFilesX86}}/Microsoft Visual Studio ${v}.0/VC/redist" ) mark_as_advanced(MSVC${v}_REDIST_DIR) set(MSVC${v}_CRT_DIR "${MSVC${v}_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC${v}0.CRT") if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) set(__install__libs "${MSVC${v}_CRT_DIR}/msvcp${v}0.dll" "${MSVC${v}_CRT_DIR}/msvcr${v}0.dll" ) endif() if(CMAKE_INSTALL_DEBUG_LIBRARIES) set(MSVC${v}_CRT_DIR "${MSVC${v}_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC${v}0.DebugCRT") set(__install__libs ${__install__libs} "${MSVC${v}_CRT_DIR}/msvcp${v}0d.dll" "${MSVC${v}_CRT_DIR}/msvcr${v}0d.dll" ) endif() endmacro() if(MSVC10) MSVCRT_FILES_FOR_VERSION(10) endif() if(MSVC11) MSVCRT_FILES_FOR_VERSION(11) endif() if(MSVC12) MSVCRT_FILES_FOR_VERSION(12) endif() if(CMAKE_INSTALL_MFC_LIBRARIES) if(MSVC70) set(__install__libs ${__install__libs} "${SYSTEMROOT}/system32/mfc70.dll" ) endif() if(MSVC71) set(__install__libs ${__install__libs} "${SYSTEMROOT}/system32/mfc71.dll" ) endif() if(MSVC80) if(CMAKE_INSTALL_DEBUG_LIBRARIES) set(MSVC80_MFC_DIR "${MSVC80_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC80.DebugMFC") set(__install__libs ${__install__libs} "${MSVC80_MFC_DIR}/Microsoft.VC80.DebugMFC.manifest" "${MSVC80_MFC_DIR}/mfc80d.dll" "${MSVC80_MFC_DIR}/mfc80ud.dll" "${MSVC80_MFC_DIR}/mfcm80d.dll" "${MSVC80_MFC_DIR}/mfcm80ud.dll" ) endif() set(MSVC80_MFC_DIR "${MSVC80_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.MFC") # Install the manifest that allows DLLs to be loaded from the # directory containing the executable. if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) set(__install__libs ${__install__libs} "${MSVC80_MFC_DIR}/Microsoft.VC80.MFC.manifest" "${MSVC80_MFC_DIR}/mfc80.dll" "${MSVC80_MFC_DIR}/mfc80u.dll" "${MSVC80_MFC_DIR}/mfcm80.dll" "${MSVC80_MFC_DIR}/mfcm80u.dll" ) endif() # include the language dll's for vs8 as well as the actuall dll's set(MSVC80_MFCLOC_DIR "${MSVC80_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.MFCLOC") # Install the manifest that allows DLLs to be loaded from the # directory containing the executable. set(__install__libs ${__install__libs} "${MSVC80_MFCLOC_DIR}/Microsoft.VC80.MFCLOC.manifest" "${MSVC80_MFCLOC_DIR}/mfc80chs.dll" "${MSVC80_MFCLOC_DIR}/mfc80cht.dll" "${MSVC80_MFCLOC_DIR}/mfc80enu.dll" "${MSVC80_MFCLOC_DIR}/mfc80esp.dll" "${MSVC80_MFCLOC_DIR}/mfc80deu.dll" "${MSVC80_MFCLOC_DIR}/mfc80fra.dll" "${MSVC80_MFCLOC_DIR}/mfc80ita.dll" "${MSVC80_MFCLOC_DIR}/mfc80jpn.dll" "${MSVC80_MFCLOC_DIR}/mfc80kor.dll" ) endif() if(MSVC90) if(CMAKE_INSTALL_DEBUG_LIBRARIES) set(MSVC90_MFC_DIR "${MSVC90_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC90.DebugMFC") set(__install__libs ${__install__libs} "${MSVC90_MFC_DIR}/Microsoft.VC90.DebugMFC.manifest" "${MSVC90_MFC_DIR}/mfc90d.dll" "${MSVC90_MFC_DIR}/mfc90ud.dll" "${MSVC90_MFC_DIR}/mfcm90d.dll" "${MSVC90_MFC_DIR}/mfcm90ud.dll" ) endif() set(MSVC90_MFC_DIR "${MSVC90_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.MFC") # Install the manifest that allows DLLs to be loaded from the # directory containing the executable. if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) set(__install__libs ${__install__libs} "${MSVC90_MFC_DIR}/Microsoft.VC90.MFC.manifest" "${MSVC90_MFC_DIR}/mfc90.dll" "${MSVC90_MFC_DIR}/mfc90u.dll" "${MSVC90_MFC_DIR}/mfcm90.dll" "${MSVC90_MFC_DIR}/mfcm90u.dll" ) endif() # include the language dll's for vs9 as well as the actuall dll's set(MSVC90_MFCLOC_DIR "${MSVC90_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.MFCLOC") # Install the manifest that allows DLLs to be loaded from the # directory containing the executable. set(__install__libs ${__install__libs} "${MSVC90_MFCLOC_DIR}/Microsoft.VC90.MFCLOC.manifest" "${MSVC90_MFCLOC_DIR}/mfc90chs.dll" "${MSVC90_MFCLOC_DIR}/mfc90cht.dll" "${MSVC90_MFCLOC_DIR}/mfc90enu.dll" "${MSVC90_MFCLOC_DIR}/mfc90esp.dll" "${MSVC90_MFCLOC_DIR}/mfc90deu.dll" "${MSVC90_MFCLOC_DIR}/mfc90fra.dll" "${MSVC90_MFCLOC_DIR}/mfc90ita.dll" "${MSVC90_MFCLOC_DIR}/mfc90jpn.dll" "${MSVC90_MFCLOC_DIR}/mfc90kor.dll" ) endif() macro(MFC_FILES_FOR_VERSION version) set(v "${version}") if(CMAKE_INSTALL_DEBUG_LIBRARIES) set(MSVC${v}_MFC_DIR "${MSVC${v}_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC${v}0.DebugMFC") set(__install__libs ${__install__libs} "${MSVC${v}_MFC_DIR}/mfc${v}0d.dll" "${MSVC${v}_MFC_DIR}/mfc${v}0ud.dll" "${MSVC${v}_MFC_DIR}/mfcm${v}0d.dll" "${MSVC${v}_MFC_DIR}/mfcm${v}0ud.dll" ) endif() set(MSVC${v}_MFC_DIR "${MSVC${v}_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC${v}0.MFC") if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) set(__install__libs ${__install__libs} "${MSVC${v}_MFC_DIR}/mfc${v}0.dll" "${MSVC${v}_MFC_DIR}/mfc${v}0u.dll" "${MSVC${v}_MFC_DIR}/mfcm${v}0.dll" "${MSVC${v}_MFC_DIR}/mfcm${v}0u.dll" ) endif() # include the language dll's as well as the actuall dll's set(MSVC${v}_MFCLOC_DIR "${MSVC${v}_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC${v}0.MFCLOC") set(__install__libs ${__install__libs} "${MSVC${v}_MFCLOC_DIR}/mfc${v}0chs.dll" "${MSVC${v}_MFCLOC_DIR}/mfc${v}0cht.dll" "${MSVC${v}_MFCLOC_DIR}/mfc${v}0deu.dll" "${MSVC${v}_MFCLOC_DIR}/mfc${v}0enu.dll" "${MSVC${v}_MFCLOC_DIR}/mfc${v}0esn.dll" "${MSVC${v}_MFCLOC_DIR}/mfc${v}0fra.dll" "${MSVC${v}_MFCLOC_DIR}/mfc${v}0ita.dll" "${MSVC${v}_MFCLOC_DIR}/mfc${v}0jpn.dll" "${MSVC${v}_MFCLOC_DIR}/mfc${v}0kor.dll" "${MSVC${v}_MFCLOC_DIR}/mfc${v}0rus.dll" ) endmacro() if(MSVC10) MFC_FILES_FOR_VERSION(10) endif() if(MSVC11) MFC_FILES_FOR_VERSION(11) endif() if(MSVC12) MFC_FILES_FOR_VERSION(12) endif() endif() # MSVC 8 was the first version with OpenMP # Furthermore, there is no debug version of this if(CMAKE_INSTALL_OPENMP_LIBRARIES) macro(OPENMP_FILES_FOR_VERSION version_a version_b) set(va "${version_a}") set(vb "${version_b}") set(MSVC${va}_OPENMP_DIR "${MSVC${va}_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC${vb}.OPENMP") if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) set(__install__libs ${__install__libs} "${MSVC${va}_OPENMP_DIR}/vcomp${vb}.dll") endif() endmacro() if(MSVC80) OPENMP_FILES_FOR_VERSION(80 80) endif() if(MSVC90) OPENMP_FILES_FOR_VERSION(90 90) endif() if(MSVC10) OPENMP_FILES_FOR_VERSION(10 100) endif() if(MSVC11) OPENMP_FILES_FOR_VERSION(11 110) endif() if(MSVC12) OPENMP_FILES_FOR_VERSION(12 120) endif() endif() foreach(lib ${__install__libs} ) if(EXISTS ${lib}) set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${lib}) message (STATUS ">> ${lib}") else() if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS) message(WARNING "system runtime library file does not exist: '${lib}'") # This warning indicates an incomplete Visual Studio installation # or a bug somewhere above here in this file. # If you would like to avoid this warning, fix the real problem, or # set CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS before including # this file. endif() endif() endforeach() endif() if(WATCOM) get_filename_component( CompilerPath ${CMAKE_C_COMPILER} PATH ) if(WATCOM17) set( __install__libs ${CompilerPath}/clbr17.dll ${CompilerPath}/mt7r17.dll ${CompilerPath}/plbr17.dll ) endif() if(WATCOM18) set( __install__libs ${CompilerPath}/clbr18.dll ${CompilerPath}/mt7r18.dll ${CompilerPath}/plbr18.dll ) endif() if(WATCOM19) set( __install__libs ${CompilerPath}/clbr19.dll ${CompilerPath}/mt7r19.dll ${CompilerPath}/plbr19.dll ) endif() foreach(lib ${__install__libs} ) if(EXISTS ${lib}) set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${lib}) else() if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS) message(WARNING "system runtime library file does not exist: '${lib}'") # This warning indicates an incomplete Watcom installation # or a bug somewhere above here in this file. # If you would like to avoid this warning, fix the real problem, or # set CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS before including # this file. endif() endif() endforeach() endif() # Include system runtime libraries in the installation if any are # specified by CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS. if(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS) if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP) if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION) if(WIN32) set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION bin) else() set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION lib) endif() endif() install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ${CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION}) endif() endif() plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/PlmMacros.cmake000066400000000000000000000215601321604176500255020ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- ##----------------------------------------------------------------------------- ## A few constants used to control build & install ##----------------------------------------------------------------------------- set (INSTALL_NEVER 0) set (INSTALL_ALWAYS 1) if (PLM_CONFIG_DEBIAN_BUILD) set (INSTALL_IF_NOT_DEBIAN 0) else () set (INSTALL_IF_NOT_DEBIAN 1) endif () set (BUILD_NEVER 0) set (BUILD_ALWAYS 1) set (BUILD_IF_NOT_SLICER_EXT 1) ##----------------------------------------------------------------------------- ## Create enum options ##----------------------------------------------------------------------------- macro (option_enum option_name option_descr option_value ) set (${option_name} ${option_value} CACHE STRING ${option_descr}) set_property (CACHE ${option_name} PROPERTY STRINGS ${ARGN}) endmacro () ##----------------------------------------------------------------------------- ## Save and restore variables ##----------------------------------------------------------------------------- macro (push_var _var) set (${_var}_BACKUP ${${_var}}) endmacro () macro (push_vars) foreach (_var IN ITEMS ${ARGN}) push_var (${_var}) endforeach () endmacro () macro (pop_var _var) set (${_var} ${${_var}_BACKUP}) endmacro () macro (pop_vars) foreach (_var IN ITEMS ${ARGN}) pop_var (${_var}) endforeach () endmacro () ##----------------------------------------------------------------------------- ## Macros for creating targets ##----------------------------------------------------------------------------- macro (PLM_ADD_LIBRARY TARGET_NAME TARGET_SRC TARGET_LIBS TARGET_LDFLAGS TARGET_INCLUDE_DIRECTORIES TARGET_INCLUDE_FILES ) add_library (${TARGET_NAME} ${TARGET_SRC}) set_target_properties (${TARGET_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}" LIBRARY_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}" RUNTIME_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}" PUBLIC_HEADER "${TARGET_INCLUDE_FILES}") if (PLM_CONFIG_INSTALL_LIBRARIES) if (NOT PLM_PACKAGE_LEGACY_CMAKE_CONFIG) target_include_directories(${TARGET_NAME} INTERFACE ${TARGET_INCLUDE_DIRECTORIES}) endif () install (TARGETS ${TARGET_NAME} EXPORT PlastimatchLibraryDepends RUNTIME DESTINATION "${PLM_INSTALL_BIN_DIR}" LIBRARY DESTINATION "${PLM_INSTALL_LIB_DIR}" ARCHIVE DESTINATION "${PLM_INSTALL_LIB_DIR}" PUBLIC_HEADER DESTINATION "${PLM_INSTALL_INCLUDE_DIR}" ) endif () target_link_libraries (${TARGET_NAME} ${TARGET_LIBS}) if (NOT ${TARGET_LDFLAGS} STREQUAL "") set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS ${TARGET_LDFLAGS}) endif () # Decorate .so on unix set_target_properties(${TARGET_NAME} PROPERTIES SOVERSION "${PLM_VERSION_MAJOR}.${PLM_VERSION_MINOR}") endmacro () # Static libraries used when they aren't properly decorated for windows macro (PLM_ADD_STATIC_LIBRARY TARGET_NAME TARGET_SRC TARGET_LIBS TARGET_LDFLAGS TARGET_INCLUDES) add_library (${TARGET_NAME} STATIC ${TARGET_SRC}) set_target_properties (${TARGET_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}" LIBRARY_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}" RUNTIME_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}" PUBLIC_HEADER "${TARGET_INCLUDES}") if (PLM_CONFIG_INSTALL_LIBRARIES) install (TARGETS ${TARGET_NAME} EXPORT PlastimatchLibraryDepends RUNTIME DESTINATION "${PLM_INSTALL_BIN_DIR}" LIBRARY DESTINATION "${PLM_INSTALL_LIB_DIR}" ARCHIVE DESTINATION "${PLM_INSTALL_LIB_DIR}" PUBLIC_HEADER DESTINATION "${PLM_INSTALL_INCLUDE_DIR}" ) endif () target_link_libraries (${TARGET_NAME} ${TARGET_LIBS}) if (NOT ${TARGET_LDFLAGS} STREQUAL "") set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS ${TARGET_LDFLAGS}) endif () endmacro () macro (PLM_ADD_GPU_PLUGIN_LIBRARY TARGET_NAME TARGET_SRC) # Add library target cuda_add_library (${TARGET_NAME} SHARED ${TARGET_SRC}) # Set output directory. No PUBLIC_HEADER directory is needed, # because they don't have a public API. set_target_properties (${TARGET_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}" LIBRARY_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}" RUNTIME_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}") # Set installation diretory and export definition. No PUBLIC_HEADER needed. if (PLM_CONFIG_INSTALL_LIBRARIES) install (TARGETS ${TARGET_NAME} EXPORT PlastimatchLibraryDepends RUNTIME DESTINATION "${PLM_INSTALL_BIN_DIR}" LIBRARY DESTINATION "${PLM_INSTALL_LIB_DIR}" ARCHIVE DESTINATION "${PLM_INSTALL_LIB_DIR}" ) endif () # Decorate .so on unix set_target_properties(${TARGET_NAME} PROPERTIES SOVERSION "${PLM_VERSION_MAJOR}.${PLM_VERSION_MINOR}") endmacro () ## Legacy version, designed before target_include_directories was ## implemented in cmake 2.8.12 macro (PLM_ADD_EXECUTABLE TARGET_NAME TARGET_SRC TARGET_LIBS TARGET_LDFLAGS TARGET_BUILD TARGET_INSTALL) if (${TARGET_BUILD}) add_executable (${TARGET_NAME} ${TARGET_SRC}) target_link_libraries (${TARGET_NAME} ${TARGET_LIBS}) set_target_properties (${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}") if (NOT ${TARGET_LDFLAGS} STREQUAL "") set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS ${TARGET_LDFLAGS}) endif () # CXX linkage required for nlopt set_target_properties (${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX) if (${TARGET_INSTALL}) install (TARGETS ${TARGET_NAME} DESTINATION "${PLM_INSTALL_BIN_DIR}") endif () endif () endmacro () ## New version, uses target_include_directories macro (plm_add_executable_v2 TARGET_NAME TARGET_SRC TARGET_INCLUDES TARGET_LIBS TARGET_LDFLAGS TARGET_BUILD TARGET_INSTALL) if (${TARGET_BUILD}) add_executable (${TARGET_NAME} ${TARGET_SRC}) target_link_libraries (${TARGET_NAME} ${TARGET_LIBS}) target_include_directories (${TARGET_NAME} PRIVATE ${TARGET_INCLUDES}) set_target_properties (${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PLM_BINARY_DIR}") if (NOT ${TARGET_LDFLAGS} STREQUAL "") set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS ${TARGET_LDFLAGS}) endif () # CXX linkage required for nlopt set_target_properties (${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX) if (${TARGET_INSTALL}) install (TARGETS ${TARGET_NAME} DESTINATION "${PLM_INSTALL_BIN_DIR}") endif () endif () endmacro () macro (PLM_ADD_OPENCL_FILE SRCS CL_FILE) # I don't yet know how to bundle the .cl file within the executable. # Therefore, copy the .cl into binary directory. set (${SRCS} ${${SRCS}} "${PLM_BINARY_DIR}/${CL_FILE}") add_custom_command ( OUTPUT "${PLM_BINARY_DIR}/${CL_FILE}" COMMAND ${CMAKE_COMMAND} "-E" "copy" "${CMAKE_CURRENT_SOURCE_DIR}/${CL_FILE}" "${PLM_BINARY_DIR}/${CL_FILE}" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${CL_FILE}") # Need in the testing directory too :( set (${SRCS} ${${SRCS}} "${PLM_BUILD_TESTING_DIR}/${CL_FILE}") add_custom_command ( OUTPUT "${PLM_BUILD_TESTING_DIR}/${CL_FILE}" COMMAND ${CMAKE_COMMAND} "-E" "copy" "${CMAKE_CURRENT_SOURCE_DIR}/${CL_FILE}" "${PLM_BUILD_TESTING_DIR}/${CL_FILE}" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${CL_FILE}") endmacro () macro (PLM_ADD_TARGET_COPY TARGET SRC DEST DEPENDENCY) add_custom_target (${TARGET} ALL DEPENDS "${DEST}") add_custom_command ( OUTPUT "${DEST}" COMMAND ${CMAKE_COMMAND} "-E" "copy" "${SRC}" "${DEST}" DEPENDS ${DEPENDENCY} ) endmacro () macro (PLM_SET_SSE2_FLAGS) foreach (SRC ${ARGN}) # JAS 08.19.2010 - Unfortunately, this doesn't work. # SET_PROPERTY( # SOURCE bspline.c # APPEND PROPERTY COMPILE_DEFINITIONS ${SSE2_FLAGS} # ) # So, we ask CMake more forcefully to add additional compile flags get_source_file_property (FILE_FLAGS ${SRC} COMPILE_FLAGS) if (FILE_FLAGS AND NOT FILE_FLAGS MATCHES "NONE") set (FILE_FLAGS "${FILE_FLAGS} -msse2") else () set (FILE_FLAGS "-msse2") endif () set_source_files_properties ( ${SRC} PROPERTIES COMPILE_FLAGS "${FILE_FLAGS}") endforeach () endmacro () macro (PLM_SET_PIC_FLAGS) if (CMAKE_VERSION VERSION_LESS "2.8.9") if ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fPIC") set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fPIC") set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC") set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fPIC") endif () else () set (CMAKE_POSITION_INDEPENDENT_CODE TRUE) endif () endmacro () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/PreventInSourceBuilds.cmake000066400000000000000000000007551321604176500300460ustar00rootroot00000000000000# This function will prevent in-source builds. Copied from ITK. function(AssureOutOfSourceBuilds) # make sure the user doesn't play dirty with symlinks get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) # disallow in-source builds if("${srcdir}" STREQUAL "${bindir}") message(FATAL_ERROR "Error: Plastimatch should not be built in its source directory") endif() endfunction() AssureOutOfSourceBuilds() plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/RUN_CTEST.cmake000077500000000000000000000042411321604176500252130ustar00rootroot00000000000000## Some good info on using CTest: ## http://www.cmake.org/pipermail/cmake/2007-April/013797.html ## Apparently this is how to make the CMake script return status ## http://www.cmake.org/Wiki/CMake/C_Plugins_for_Loadable_Commands set (ENV{PATH} "$ENV{PATH};${ITK_LIBRARY_PATH};${PLM_PLASTIMATCH_PATH};${PLM_FFTW_PATH}") message ("PLM_TEST_COMMAND is ${PLM_TEST_COMMAND}") message ("PARMS is ${PARMS}") message ("EXPECTED_ERRNO is ${EXPECTED_ERRNO}") # CMake doesn't allow "=" to be passed in a -D parameter. So we substitute # with replacement string when calling ADD_TEST(), but need to back-substitute # here. string (REPLACE "&equal&" "=" PARMS "${PARMS}") if (WORKING_DIR) set (WORKING_DIR WORKING_DIRECTORY ${WORKING_DIR}) endif () execute_process ( COMMAND ${PLM_TEST_COMMAND} ${PARMS} ${WORKING_DIR} RESULT_VARIABLE RESULT OUTPUT_VARIABLE STDOUT ERROR_VARIABLE STDERR ) message ("RETVAL: ${RESULT}") message ("STDOUT: ${STDOUT}") message ("STDERR: ${STDERR}") # For CMake version 2.8 and higher, we can set execute permission # http://www.mail-archive.com/cmake@cmake.org/msg26920.html set (CMD_FN "${PLM_BUILD_TESTING_DIR}/${PLM_TEST_NAME}.cmd") if (NOT ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 2.8) set (CMD_FN "${PLM_BUILD_TESTING_DIR}/tmp/${PLM_TEST_NAME}.cmd") endif () file (WRITE ${CMD_FN} ${PLM_TEST_COMMAND}) foreach (PARM ${PARMS}) file (APPEND ${CMD_FN} " \"" ${PARM} "\"") endforeach () file (APPEND ${CMD_FN} "\n") if (NOT ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 2.8) file (COPY "${CMD_FN}" DESTINATION "${PLM_BUILD_TESTING_DIR}" FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) endif () set (STDOUT_FN "${PLM_BUILD_TESTING_DIR}/${PLM_TEST_NAME}.stdout.txt") file (WRITE ${STDOUT_FN} ${STDOUT}) set (STDERR_FN "${PLM_BUILD_TESTING_DIR}/${PLM_TEST_NAME}.stderr.txt") file (WRITE ${STDERR_FN} ${STDERR}) if (NOT DEFINED EXPECTED_ERRNO) set (EXPECTED_ERRNO 0) endif () if (${RESULT} EQUAL ${EXPECTED_ERRNO}) message ("Not an error") else () message (SEND_ERROR "An error") endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/SuperbuildOptions.cmake000066400000000000000000000026431321604176500273000ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- ## These macros are used to forward variables defined in the outer build ## to the inner build. The variable values cannot be a list; these ## don't expand properly. ##----------------------------------------------------------------------------- # macro: sb_variable # Add a variable to the list of superbuild variables that are passed to the # inner build macro (sb_variable _var) list (APPEND sb_cmake_vars ${_var}) endmacro () # macro: sb_set # Set a variable and add it to the list of superbuild variables # that are passed to the inner build macro (sb_set _var) set (${_var} ${ARGN}) list (APPEND sb_cmake_vars ${_var}) endmacro () # macro: sb_option # Create an option in the cmake-gui, and mark the variable as a superbuild # variable to be passed to the inner build macro (sb_option _var _desc _defval) option (${_var} ${_desc} ${_defval}) list (APPEND sb_cmake_vars ${_var}) endmacro () # macro: sb_option_enum # Create an enum option in the cmake-gui, and mark the variable as a # superbuild variable to be passed to the inner build macro (sb_option_enum _var _desc _defval) option_enum (${_var} ${_desc} ${_defval} ${ARGN}) list (APPEND sb_cmake_vars ${_var}) endmacro () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/char_is_signed.cxx000077500000000000000000000002511321604176500262650ustar00rootroot00000000000000#include int main (void) { char c = 255; if (c > 128) { printf ("char is unsigned"); } else { printf ("char is signed"); } return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/cmake_uninstall.cmake000066400000000000000000000017371321604176500267620ustar00rootroot00000000000000IF (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") FOREACH (file ${files}) MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") IF (EXISTS "$ENV{DESTDIR}${file}") EXECUTE_PROCESS( COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" OUTPUT_VARIABLE rm_out RESULT_VARIABLE rm_retval ) IF(NOT ${rm_retval} EQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") ENDIF (NOT ${rm_retval} EQUAL 0) ELSE (EXISTS "$ENV{DESTDIR}${file}") MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") ENDIF (EXISTS "$ENV{DESTDIR}${file}") ENDFOREACH(file) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/nvcc-check.cmake000077500000000000000000000150351321604176500256140ustar00rootroot00000000000000# James Shackleford # Date: 2010.08.24 # File: nvcc-check.cmake # # 2012.11.21 # -- Complete rewrite to make checking different gcc # versions easier for the increasing number of nvcc versions ###################################################################### #: FUNCTION: get_nvcc_version () #: RETURNS: CUDA_VERSION_MAJOR = #: CUDA_VERSION_MINOR = # ---------------------------------------------------------------------------- function (get_nvcc_version) # We have to get NVCC version ourselves. FindCUDA.cmake version checks are # skipped for non-initial CMake configuration runs exec_program(${CUDA_NVCC_EXECUTABLE} ARGS "--version" OUTPUT_VARIABLE NVCC_OUT) string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\1" NVCC_VERSION_MAJOR ${NVCC_OUT}) string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\2" NVCC_VERSION_MINOR ${NVCC_OUT}) set (CUDA_VERSION_MAJOR ${NVCC_VERSION_MAJOR} PARENT_SCOPE) set (CUDA_VERSION_MINOR ${NVCC_VERSION_MINOR} PARENT_SCOPE) set (CUDA_VERSION_STRING "${NVCC_VERSION_MAJOR}.${NVCC_VERSION_MINOR}" PARENT_SCOPE) endfunction () #: FUNCTION: find_gcc_version (major_version minor_version) #: RETURNS: NVC_GCC_STATUS = 0 [FAILURE] #: = 1 [USE DEFAULT GCC] #: = 2 [USE SELECT GCC] #: NVC_SELECT_GCC = # ---------------------------------------------------------------------------- function (find_gcc_version major minor) set (NVC_GCC_STATUS "0" PARENT_SCOPE) exec_program (gcc ARGS "-dumpversion" OUTPUT_VARIABLE GCCVER) string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*" "\\1" GCCVER_MAJOR "${GCCVER}") string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*" "\\2" GCCVER_MINOR "${GCCVER}") if (GCCVER_MAJOR MATCHES "${major}" AND GCCVER_MINOR MATCHES "${minor}") set (NVC_GCC_STATUS "1" PARENT_SCOPE) else () exec_program (which ARGS "gcc-${major}.${minor}" OUTPUT_VARIABLE GCC_XX RETURN_VALUE GCC_XX_EXIST) if (GCC_XX_EXIST EQUAL 0) set (NVC_GCC_STATUS "2" PARENT_SCOPE) set (NVC_SELECT_GCC ${GCC_XX} PARENT_SCOPE) endif () endif () endfunction () #: FUNCTION: error_request_gcc_version (major_version minor_version) # ---------------------------------------------------------------------------- function (error_request_gcc_version major minor) message (FATAL_ERROR "nvcc-check: Please install gcc-${major}.${minor}, it is needed by nvcc \(CUDA\).\nNote that gcc-${major}.${minor} can be installed side-by-side with your current version of gcc.\nYou need not replace your current version of gcc; just make gcc-${major}.${minor} available as well so that nvcc can use it.\nDebian/Ubuntu users with root privilages may simply enter the following at a terminal prompt:\n sudo apt-get install gcc-${major}.${minor} g++-${major}.${minor}\n") endfunction () #: Only perform the gcc version check if it is necessary # ---------------------------------------------------------------------------- if (CUDA_FOUND AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND CMAKE_COMPILER_IS_GNUCC) get_nvcc_version () message(STATUS "nvcc-check: NVCC Version is ${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR}") #: CUDA 2.X: UNSUPPORTED # ---------------------------------------------------------------- if (CUDA_VERSION_MAJOR MATCHES "2") message (FATAL_ERROR "nvcc-check: Plastimatch only supports CUDA 3.0+\n") endif () #: CUDA 3.X+: gcc-4.3 # ---------------------------------------------------------------- if (CUDA_VERSION_MAJOR MATCHES "3") find_gcc_version (4 3) # JAS 08.06.2012: default behavior in CUDA 4.1+ list (APPEND CUDA_NVCC_FLAGS --host-compilation C++) endif () #: CUDA 4.0, 4.1: gcc-4.4 or gcc-4.3 # ---------------------------------------------------------------- if ((NVC_GCC_STATUS STREQUAL "0") AND (CUDA_VERSION_STRING VERSION_LESS "4.2")) find_gcc_version (4 4) if (NVC_GCC_STATUS MATCHES "0") find_gcc_version (4 3) endif () endif () #: CUDA 4.2+, CUDA 5.X+: gcc-4.6, gcc-4.4 or gcc-4.3 # ---------------------------------------------------------------- if ((NVC_GCC_STATUS STREQUAL "0") AND (CUDA_VERSION_STRING VERSION_GREATER "4.1")) find_gcc_version (4 6) if (NVC_GCC_STATUS MATCHES "0") find_gcc_version (4 4) endif () if (NVC_GCC_STATUS MATCHES "0") find_gcc_version (4 3) endif () endif () #: Set CUDA_NVCC_FLAGS and give the user a little feedback # ---------------------------------------------------------------- #: CASE 0: NO COMPATIBLE VERSION OF GCC WAS FOUND! if (NVC_GCC_STATUS MATCHES "0") if (CUDA_VERSION_MAJOR MATCHES "3") error_request_gcc_version (4 3) endif() if (CUDA_VERSION_MAJOR MATCHES "4") error_request_gcc_version (4 4) endif() if (CUDA_VERSION_MAJOR MATCHES "5") error_request_gcc_version (4 6) endif() endif () #: CASE 1: SYSTEM DEFAULT GCC IS COMPATIBLE if (NVC_GCC_STATUS MATCHES "1") message (STATUS "nvcc-check: Using system default gcc for CUDA compilation.") endif () #: CASE 2: COMPATIBLE VERSION OF GCC WAS FOUND (NOT SYSTEM DEFAULT) if (NVC_GCC_STATUS MATCHES "2") message (STATUS "nvcc-check: Using \"${NVC_SELECT_GCC}\" for CUDA compilation.") list (APPEND CUDA_NVCC_FLAGS --compiler-bindir ${NVC_SELECT_GCC}) endif () endif () #: Exceptions for specific quirks in certain CUDA versions # ---------------------------------------------------------------- if (CUDA_FOUND AND CMAKE_COMPILER_IS_GNUCC) if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "APPLE") # For CUDA 3.2: surface_functions.h does some non-compliant things, # so we tell g++ to ignore them when called via nvcc by passing the # -fpermissive flag through the nvcc build trajectory. Unfortunately, # nvcc will also blindly pass this flag to gcc, even though it is # not valid; thus, resulting in TONS of warnings. So, we 1st check # the nvcc version number if (CUDA_VERSION_MAJOR MATCHES "3" AND CUDA_VERSION_MINOR MATCHES "2") list (APPEND CUDA_NVCC_FLAGS --compiler-options -fpermissive) message (STATUS "nvcc-check: CUDA 3.2 exception (-fpermissive enabled)") endif () endif () endif () if (verbose) message(STATUS "nvcc-check: CUDA_NVCC_FLAGS=\"${CUDA_NVCC_FLAGS}\"") endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/test_eps.cxx000077500000000000000000000015671321604176500251650ustar00rootroot00000000000000#include #include typedef union { long long i64; double d64; } dbl_64; double machine_eps (double value) { dbl_64 s; s.d64 = value; s.i64++; return (s.i64 < 0 ? value - s.d64 : s.d64 - value); } int main (int argc, char* argv[]) { double machEps = 1.0f; do { #if defined (commentout) printf( "%G\t%.20f\n", machEps, (1.0f + machEps) ); #endif machEps /= 2.0f; // If next epsilon yields 1, then break, because current // epsilon is the machine epsilon. } while ((double)(1.0 + (machEps/2.0)) != 1.0); #if defined (commentout) printf ("DBL_EPSILON = %G\n", DBL_EPSILON); printf ("Machine epsilon (alg 1) = %G\n", machine_eps((double)1.0)); printf ("Machine epsilon (alg 2) = %G\n", machEps); #endif printf ("%G %G %G", DBL_EPSILON, machine_eps((double)1.0), machEps); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/cmake/test_qt.cxx000066400000000000000000000004431321604176500250070ustar00rootroot00000000000000#include QString foo () { return QString ("a") + QString ("b"); } int main (int argc, char* argv[]) { QString q1 ("Hello world"); /* The below test fails on VS 2013 when attempting to link against QT built with VS 2008 */ QString q2; q2 = foo (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/000077500000000000000000000000001321604176500222645ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/NOTES.TXT000077500000000000000000001422571321604176500235730ustar00rootroot00000000000000****************************************************************************** Superbuild test configurations Standard build: local ITK, local DCMTK Standard build: system ITK, system DCMTK Superbuild: system ITK, system DCMTK Superbuild: download ITK, download DCMTK ****************************************************************************** Good ideas from Elastix A good set of random sampling options Schedule of grid spacing allows multiple sub-stages Parameter file overwrites Rigidity penalty ****************************************************************************** Groupwise registration Current form: fixed=foo.mha moving=foo.mha Future form: group=dir/ [GROUP] iterations=3 convergence=XX (or) group=dir/ group_iterations=3 group_convergence=XX ****************************************************************************** Beam model, spot map rt_beam_model: TBD. rt_depth_dose: This contains a single depth-dose curve. Currently only generated by analytic model. rt_mebs: This contain a grid of beamlet weights as a function of energy and position. rt_spot_map: This contains a list of spots, each spot containing spot position, energy, sigma, weight. rt_dij: This contains a sparse dose grid. Ideally it should use the same data structure as pcmd_warp_dij. However, that structure uses ushort. Need to consider how to mitigate truncation and overflow. Active scanning: A beam contains a dij. A beam contains a spot map. A beam contains a mebs. There is a map from mebs to spots. There is a dij for each meb. There is a dij for each spot. The pre-optimizer calculates dij for each spot. For each beamlet: Calculate dij Increment involved spots by dij An optimizer will take a set of dij, and will create spot weights. The final calculations sums the weighted dij. Passive scattering: A beam contains a mebs. The ****************************************************************************** Calc methodology 1. manual beamlet map compute_beam_data_from_beamlet_map mebs()->clear_depth_dose mebs()->load_beamlet_map update_aperture_and_range_compensator (not implemented) 2. manual spot map 3. manual peaks compute_beam_data_from_manual_peaks mebs()->generate_part_num_from_weight compute_beam_modifiers_active_scanning compute_beam_modifiers_passive_scattering 4. dose prescription mebs()->set_target_depths compute_beam_data_from_prescription 5. target compute_beam_data_from_target if passive compute_beam_modifiers compute_beam_data_from_prescription if active compute_beam_modifiers_active_scanning compute_particle_number_matrix_from_target_active 6. 100 MeV sample beam compute_default_beam mebs()->add_peak compute_beam_data_from_manual_peaks ****************************************************************************** Dose calculation LUTs rpl_volume.cxx -------------- compute_density_from_HU "From Schneider paper" (Not clear how.) compute_PrSTPR_Schneider_weq_from_HU "From Schneider paper" (Not clear how.) compute_PrSTRP_XiO_MGH_weq_from_HU Not used (?) compute_PrWER_from_HU Stopping power / density rpl_lut.cxx ----------- get_proton_stop energy -> ?? get_proton_range energy -> ?? compute_X0_from_HU HU -> radiation length (Where does this come from?) ****************************************************************************** Global vs stage vs shared There are only a few small differences. Review of global options - No registration is run - Allows process stage before first registration stage - Global outputs are written after final stage -- Written at original resolution, potentially with different options - Logfile is global -- I suppose you could switch logfile per stage if you wanted Review of stage options - Resume stage / finalize stage ****************************************************************************** Alternate syntax [METRIC] id=0 metric=mse fixed=x1 moving=y1 lambda=0.1 [METRIC] id=1 metric=dmap fixed=x2 moving=y2 lambda=1.0 histogram_bins=30 [STAGE] metric=mse,dmap Note that this is not more powerful. Instead we could do this: fixed[0]=x1 moving[0]=y1 metric[0]=mse fixed[1]=x2 moving[1]=y2 metric[1]=mi histogram_bins[1]=30 Also, with the first syntax, you might want some way to specify warped images (warped y1 and y2). ****************************************************************************** Registration similarity parms/data (cont.) On the use of std::map. There are three places where it gets used. - Shared_parms -- Individual maps for filenames fixed, moving, etc - Stage_parms -- To be added, individual maps for parameters smetric, smetric_lambda - Registration_data -- Map of Registration_similarity_data's (containing Plm_image's) After this, the map gets dissolved into a vector of Stage_similarity_data - Filenames go raw into map for Shared_parms, images get loaded into Registration_data. - Smetric gets cooked and split going into vector for Stage_parms. - The Registration_similarity_data (and then Stage_similarity_data) seem to need the parameters. The main question seems to be that parms and images are considered separate. What kind of remedies are there for this? - Keep separate, parallel maps -- Registration_similarity_data stays as-is -- Individual maps (or Similarity_parms map) remain in Stage_parms -- Copy into unified vector of Stage_similarity_data - Single unified parameter map, duplicated parms -- Upgrade smetric, smetric_lambda to shared parms -- Copy parms into unified Registration_similarity_data at same time as image load for each stage - Unify Registration_parms and Registration_data -- Upgrade smetric, smetric_lambda to shared parms -- Create pairs --- Or scoreboard that maps filename -> Plm_image -- At filename load, the pairs are interpreted The first option seems easiest, and we could eventually upgrade to third option later. The second option is largely similar to the first, and does not appear to have significant advantages, with the exception of a unified map. The third option seems elegant, but may have some fragile points. - What to do about process section? Possible solutions: -- Update scoreboard entries with process results -- Augment scoreboard to include variable -- In any case, this is not super-well supported anyway - What to do about avoiding repeat loads -- Images in scoreboard, filenames get passed to stages -- Pointers copied from stage to stage Similarity_data , , smetric, smetric_lambda Registration_parms list Stage_parms map Final decision: "first option" ****************************************************************************** Registration similarity parms/data (cont.) ROIs are different from similarity? Here are ways they are different. - Probably ROIs should affect multiple similarity metrics - Probably ROIs should affect regularization -- This one is not currently implemented -- Ideally should be allowed independent of similarity roi -- Ideally should be allowed on a per-regularization basis Current decision. Make ROI affect multiple similiary metrics. ****************************************************************************** Registration similarity parms/data (cont.) Proposed change option 1 Registration_parms list Shared_parms map <- new Similarity_parms fixed_fn moving_fn What should happen with un-specified parameters? Example: fixed[0] = a.mha moving[0] = b.mha metric[0] = mi // A) should this propagate to [1]? impl = plastimatch // B) should this propagate to [1]? fixed[1] = c.mha // C) if moving[1] not specified should anything happen? histeq[1] = true // D) should this propagate to [0]? Answers: A) No. B) No. C) No. D) No. ****************************************************************************** Registration similarity parms/data (cont.) Current status 2016-12-28 Registration_parms list Shared_parms map fixed_fn, moving_fn, etc Registration_data map list Stage_parms auto_parms Bspline_stage Bspline_optimize <- check_grad, bspline_score only depends on this Bspline_parms Bspline_state <- needs parms & bxf to initialize Stage_similarity_data <- newly created bxf depends on master image Bspline_score Bspline_xform <- might be loaded from disc, might rely on fixed image size to set # of control points 1a) Load image 1b) Fixate image 2a) Load xform 2b) Fixate xform N.b. also Bspline_options Bspline_parms ****************************************************************************** Registration similarity parms/data There are three main types of similarity data: - parms - original images - derived images In 2016-12-22 design (so far), - parms - Read into Stage_parms during parameter file parsing. - For each stage, copied into Bspline_parms. - original images - Filenames are read into Shared_parms (but update each stage not implemented) during parameter file parsing. - Images loaded during load_stage_input(), placed in Registration_data (Type Similarity_data). - They are not reloaded each stage because file_names are not copied when new stages are created. - derived images - Images subsampled and grad calculated into Bspline_stage, then copied into Bspline_parms. Next iteration of design. - parms - Read into Stage_parms during parameter file parsing. - For each stage, copied into Bspline_parms. - original images - Filenames are read into Shared_parms (but update each stage not implemented) during parameter file parsing. - Images loaded during load_stage_input(), placed in Registration_data (type Registration_data::similarity_images). - They are not reloaded each stage because file_names are not copied when new stages are created. - derived images - Images subsampled and grad calculated into Bspline_stage, then copied into Bspline_parms, type Bspline_data::similarity_images. ****************************************************************************** register_gui 2016-10-31 A) Multiple jobs, each with one fixed and one moving job1/fix.mha job1/mov.mha job2/fix.mha job2/mov.mha *) Choose job1/fix.mha as fixed *) Choose job1/mov.mha as moving *) Click on "repeat for peer directories" B) Multiple jobs, each with one fixed and many moving job1/fix.mha job1/mov1.mha job1/mov2.mha job2/fix.mha job2/mov1.mha job2/mov2.mha *) Choose job1/fix.mha as fixed *) Choose job1 as moving *) Click on "repeat for peer directories" C) Multiple jobs, all-to-all job1/img1.mha job1/img2.mha job1/img3.mha job2/img1.mha job2/img2.mha job2/img3.mha *) Choose job1 as fixed *) Click on "repeat for peer directories" D) All-to-all with different directories dir/p1/img.mha dir/p2/img.mha dir/p3/img.mha *) Choose dir as fixed *) Click "recurse" *) Unclick "repeat for peer directories" ****************************************************************************** DICOM export entry points 2016-10-19 Rt_study::save_dcmtk Dcmtk_rt_study::save Rt_study::save_gdcm Segmentation::save_gdcm_rtss ****************************************************************************** Slice_list 2016-10-05 Used in: base/dcmtk_rtss.cxx base/rtss.cxx base/rtss.h base/rt_study_metadata.cxx Slice_list is encapsulated inside rt_study_metadata.cxx. - The get/set image_header function is based on Slice_list - slice_list_apply -- What does it mean? --- called on rtss -- When is it called - slice_list_complete -- What does it mean? --- set_image_header() and set_slice_list_complete() both were called -- When is it called ****************************************************************************** register_gui 2016-09-01 Use cases for register_gui A) Multiple jobs, each with one fixed and one moving job1/fix.mha job1/mov.mha job2/fix.mha job2/mov.mha B) Multiple jobs, each with one fixed and many moving job1/fix.mha job1/mov1.mha job1/mov2.mha job2/fix.mha job2/mov1.mha job2/mov2.mha C) Multiple jobs, all-to-all job1/img1.mha job1/img2.mha job1/img3.mha job2/img1.mha job2/img2.mha job2/img3.mha ****************************************************************************** cmake upgrade 2016-05-16 The cmake infrastructure will benefit from using the new tools for creating packages. New tools are available with CMake 2.8.11, available since May 2013. Here is my understanding of how this stuff is supposed to work. 1) Create target add_library (libr src.cxx) 2) Assign property to library target target_include_directories (libr INTERFACE $) I think you can also set target_link_libraries, which would track library dependencies. 3) Install target with EXPORT option install (TARGETS libr EXPORT LibrTargets ) It seems step 2 can be omitted by using the INCLUDES DESTINATION option in install(TARGETS). 4) Install export set install (EXPORT LibrTargets DESTINATION "${PLM_INSTALL_CMAKE_DIR}" ) Do I need to specify the DESTINATION? Will it do the right thing regardless? 5) Using the library No need to do anything. By creating an executable which depends on a library target, the include directories are set appropriately. ****************************************************************************** xvi archive 2016-04-13 1) Handle multiple Rx (done) 2) Handle HFP/FFS/FFP (done) 3) Handle rotations (done) 4) Some form of series description and study description (done) 5) Correct dates (done) 6) Mark as CBCT (done) 7) Some form of window/level (done, supported by MIM 6.6) ****************************************************************************** WED 2016-03-09 Temporarily (?) removed functionality - Computing aperture and range compensator (mode 2) - Looping through angles (mode 3) ****************************************************************************** Proj_volume coordinates 2016-02-08 The main issue with the proj volume is that its coordinates are both difficult to understand and poorly documented. What makes it difficult? - ires vs image_dim vs dim -- use image_dim - is first index row or column? -- dim[0] = cols, dim[1] = rows -- loop (j=0;j No ray tracing performed -> WTF ? compute_rpl_ct_density -> rpl_ray_trace_callback_ct_density -> Schneider density, not accumulated compute_rpl_HU -> rpl_ray_trace_callback_ct_HU -> HU, not accumulated compute_rpl_PrSTRP_no_rgc -> rpl_ray_trace_callback_PrSTPR -> Schneider stopping power, not accumulated compute_rpl_range_length_rgc -> rpl_ray_trace_callback_range_length -> Schneider stopping power, accumulated rpl_ray_trace_callback_PrSTPR_XiO_MGH (not called) Answer. There are limitations in the ray tracing design which limit reusability. -> May accumulate or not -> No real world coordinates / li_values ****************************************************************************** ITK Origin and Index 2015-08-18 It seems that ITK allows images for which the first pixel is a non-zero (but non-negative) index. When using such images, care must be used. Either, use the region and the (ITK) origin: const typename ImageType::PointType& og = input->GetOrigin(); const typename ImageType::SpacingType& sp = input->GetSpacing(); Or, use the dimension and the (plastimatch) origin: ****************************************************************************** Image orientation 2015-08-13 DICOM is simple. Coordinate system is always LPS. a) (0020,0032) Image Position Patient: the world coordinate location of the center of the first voxel in the file. b) (0020,0037) Image Orientation Patient: the real world direction cosines, mapping an increment in voxel index to an increment in real-world location. c) (0018,5100) Patient Position: does not affect mapping from voxel index to world coordinate. But it can be used to display correct orientation on the screen (e.g. putting patient left on screen right for HFS). ITK is simple. However, not yet clear to me if coordinate system is always LPS. a) Offset: the world coordinate location of the center of the first voxel in the file. b) TransformMatrix: the real world direction cosines, mapping an increment in voxel index to an increment in real-world location. c) AnatomicOrientation: does not affect mapping from voxel index to world coordinate. ****************************************************************************** Bspline_parms 2015-06-10 1. Historically, it is not possible to include ITK include files by the nvcc compiler. 2. Also historically, the itk include file is in plm_config.h 3. As a result, bspline_parms is needed, instead of accessing stage_parms. ****************************************************************************** Proj_volume, Proj_image, Rpl_volume, and dose calculation 2015-05-06, 2016-03-16 :: Proj_volume Volume *vol; Proj_matrix *pmat; double ic[2]; double matrix[12]; double sad; double sid; double cam[3]; double nrm[3]; double extrinsic[16]; double intrinsic[12]; int num_steps; double step_length; int image_dim[2]; double image_spacing[2]; double clipping_dist[2]; double nrm[3]; double src[3]; double iso[3]; double ul_room[3]; double incr_r[3]; double incr_c[3]; * Proj_volume is defined in documentation with a projective geometry. But it seems to be implemented as a spherical geometry. * It is used by rpl_volume, dose * It is not used by drr, fdk * Regarding Proj_matrix: - Can be used by Siddon approach, does not depend on uniform steps - Has no knowledge of projection plane dimension, spacing :: Proj_image int dim[2]; /* dim[0] = cols, dim[1] = rows */ double xy_offset[2]; /* Offset of center pixel */ Proj_matrix *pmat; double ic[2]; double matrix[12]; double sad; double sid; double cam[3]; double nrm[3]; double extrinsic[16]; double intrinsic[12]; float* img; /* Pixel data */ * Note use of raw pixel data * Spacing gets encoded in pmat * Proj_image could be a 1D Proj_vol :: Aperture Private: Plm_image::Pointer aperture_image; Plm_image::Pointer range_compensator_image; double distance; int dim[2]; double center[2]; double spacing[2]; Public: double vup[3]; /* orientation */ double ic_room[3]; /* loc of center (room coords) */ double ul_room[3]; /* loc of upper left corder (room coords) */ double incr_r[3]; /* row increment vector */ double incr_c[3]; /* col increment vector */ double nrm[3]; /* unit vec: normal */ double pdn[3]; /* unit vec: down */ double prt[3]; /* unit vec: right */ double tmp[3]; * Projection plane geometry and proton hardware * Maybe two separate distances would be helpful * Reimplements concepts of Proj_matrix * Why not two separate Proj_image with same Proj_matrix? * Why pdn instead of pup? :: Projection Canonical double src[3]; double iso[3]; double sid; int image_dim[2]; // [0] = columns, [1] = rows double image_center[2]; // in pixels double image_spacing[2]; // spacing on detector double vup[3]; Optional double clipping_dist[2]; Derivative double matrix[12]; double extrinsic[16]; double intrinsic[12]; double sad; // || src - iso || double nrm[3]; // src - iso / || src - iso || double plt[3]; // nrm x vup / || nrm x vup || double pup[3]; // plt x nrm double ic_room[3]; // src - sad * nrm double incr_c[3]; // ic_room - image_center[0] * isp[0] * pup double incr_r[3]; // ic_room + image_center[1] * isp[1] * plt double ul_room[3]; // ic_room - ic[0] * incr_c - ic[1] * incr_r * Replaces Proj_matrix and Aperture :: IEC double gantry_angle; double couch_angle; double detector_angle; double I_f; // SAD (?) double I_r; // detector distance double I_p[3]; // patient offset double Rx, Ry; // image center N.b. IEC does not describe image resolution or spacing :: DICOM RT Image General Image (C.7.6.1) Image Pixel (C.7.6.3) Rows Columns RT Image (C.8.8.2) X-Ray Image Receptor Translation // IEC X-Ray Image Receptor Angle // IEC RT Image Plane, RT Image Orientation // out-of-plane rotations Image Plane Pixel Spacing RT Image Position // 2D coords of first pixel Radiation Machine SAD RT Image SID Source to Reference ObjectDistance Gantry Angle Gantry Pitch Angle Patient Support Angle Table Top Eccentric AxisDistance Table Top Eccentric Angle Table Top Pitch Angle Table Top Roll Angle Table Top Vertical Position Table Top LongitudinalPosition Table Top Lateral Position Isocenter Position Patient Position * Strangely, no Image Plane module seems required (or even allowed?), which would define Image Position Patient, Image Orientation Patient :: Other thoughts * The Aperture class demonstrates that you may have multiple proj_image with same proj_matrix. A few mild assumptions are used: image pixels are matched and clipping plane is same. Backprojection will map voxels correctly in both proj_image. Alternative implementation as master-slave, using Proj_image for aperture_image and Volume for range_compensator_image could also be considered. ****************************************************************************** Older stuff ***** Metadata hookup ***** Current status: Rt_study_metadata constructor hooks up internally created metadata Segmentation allows external hookup of parent in constructor. DCMTK loading puts items into Rt_study_metadata. It puts the info directly into the right section. Ditto for GDCM1. Synthetic_mha creates images and inserts images into an Rt_study. XiO loader (Rt_study::load_xio) inserts items directly into Rt_study_metadata. Metadata within Plm_image is never actually used. You must have an Rt_study to have metadata. The Rt_study_metadata is passed into Plm_image::save() ***** Metadata ownership ***** Current ownership organization Rt_study -> Rt_study_metadata Rt_study_metadata -> shared metadata Rt_study_metadata -> image metadata Rt_study_metadata -> dose metadata Rt_study_metadata -> rtss metadata Plm_image -> image metadata Plm_image -> dose metadata Segmentation -> rtss metadata image metadata -> shared metadata rtss metadata -> shared metadata dose metadata -> shared metadata ***** Bspline methods ***** Method mi-i Tile loop to create histogram (hist_add omp_v2) Condense loop to create gradient Method mi-h Serial loop to create histogram Condense loop to create gradient Method mi-g == method mi-h Method mi-f Tile loop to create histogram (hist_add omp_crit) Condense loop to create gradient Method mi-e Tile loop to create histogram (hist_add omp_v1) Condense loop to create gradient Method d == method h Method mi-c Serial loop to create histogram Serial loop to create gradient Method mse-i Parallel tile Method mse-h Serial tile Method mse-g == mse-i Method mse-c Serial voxel Method k Serial loop Method l Serial tile loop, condense with sets ***** Overlap fraction ***** The overlap fraction should (?) be tied to score at initial iteration. This requires stashing the initial score somewhere. But this needs to be done in a general way for various optimizers. Furthermore, the "best score" concept is probably not implemented for the non-Nocedal optimizers. This is a TODO. ***** Programmability redux ***** Option 1) Internal programmability, with lua Effort: medium Pro: Convenient Con: Lua not popular Option 2) Internal programmability, with internal language Effort: medium-high Pro: Convenient for existing users, not so difficult to implement Con: Custom languages are lame Option 3) External wrapping, a la VTK Effort: medium Pro: Python popular Con: Option 4) External wrapping with Swig Effort: medium Pro: Python popular, other languages supported Con: ***** Restartable registration (second try) ***** After a lot of effort, I learned that you can't simply code up something like suggested on the ITK web site to create a semaphore from a condition variable [1]. Doing so does not work, because the condition variable does not guarantee that the signalee gets the resource before the signaller can re-grab. N.b. that the DLIB implementation has the same problem. Therefore instead, let's try a producer-consumer style solution, with two locks. master_grab: mutex.lock slave_waits = true master_waits = true while master_waits == true master_sema.wait // wait for slave to finish mutex.unlock master_release: mutex.lock slave_waits = false slave_sema.signal // wake up slave mutex.unlock slave_grab: mutex.lock while slave_waits == true slave_sema.wait // slave waits to get woken up mutex.unlock slave_release: mutex.lock master_waits = false; master_sema.wait // slave waits to get woken up mutex.unlock http://itk.org/migrationv4/index.php?action=artikel&cat=3&id=108&artlang=en ***** Restartable registration ***** Here is how it looks using ITK methodology reg_func: halt_sem.Down(); // do registration halt_sem.Up (); start_registration: halt_sem.Initialize (1); id = spawn thread(reg_func); return; halt_registration: halt_sem.Down(); return; wait_for_complete: threader.TerminateThread (id) ***** ITK and plastimatch direction cosines ***** There are two ways to have a rotated volume. The direction cosines of the volume might be inherently rotated, or there might be a rigid transform associated with it. ITK direction cosines are stored in the columns of the array. In other words, if the (DICOM) orientations are A, B, and C for the i (fastest), j, and k (slowest) indices, then ITK stores them like this: itk_dc[0][0] = A[0]; itk_dc[0][1] = B[0]; itk_dc[0][2] = C[0]; itk_dc[1][0] = A[1]; itk_dc[1][1] = B[1]; itk_dc[1][2] = C[1]; itk_dc[2][0] = A[2]; itk_dc[2][1] = B[2]; itk_dc[2][2] = C[2]; The plastimatch direction cosines are stored in a one-dimensional array, also by columns. dc[0] = A[0]; dc[1] = B[0]; dc[2] = C[0]; dc[3] = A[1]; dc[4] = B[1]; dc[5] = C[1]; dc[6] = A[2]; dc[7] = B[2]; dc[8] = C[2]; These are then converted into the "step" and "proj" matrices. step[0] <- spacing[0] * dc[0] == spacing[0] * itk_dc[0][0] step[1] <- spacing[1] * dc[1] == spacing[1] * itk_dc[0][1] step[2] <- spacing[2] * dc[2] == spacing[2] * itk_dc[0][2] step[3] <- spacing[0] * dc[3] == spacing[0] * itk_dc[1][0] ... step[8] <- spacing[2] * dc[8] == spacing[0] * itk_dc[2][2] To convert an index into a position, you do this: pos[0] = origin[0] + idx[0]*step[0] + idx[1]*step[1] + idx[2]*step[2] pos[1] = origin[1] + idx[0]*step[3] + idx[1]*step[4] + idx[2]*step[5] pos[2] = origin[2] + idx[0]*step[6] + idx[1]*step[7] + idx[2]*step[8] ***** How to delete items from conquest ***** ./dgate --deletepatient:patid Note: supports wildcards, such as: ./dgate --deletepatient:0522* ***** Subsampling framework ***** legacy vox subsampling Voxel binning, new voxel center at bin center new vox subsampling Convert into standard resampling, allow fraction mm resampling Choose by mm pct resample Choose by pct of original voxels dim resample Choose by number of voxels res,res_vox,ss res_mm res_pct res_dim ***** When is itk vs native resample used? ***** native: xform.cxx resample gpuit vfs demons,bspline,transl registration subsampling itk: everywhere else ***** How to detect a "Null" smart pointer ***** Just like a regular pointer. Plm_image::Pointer p; if (p) { /* Will not be executed because p is null */ } You can return a null pointer like this: if (error) { return Plm_image::Pointer(); } ***** Plastimatch 2.0 ***** Proposal #1, extend existing language. The below is an example, but many improvements could be made. [GLOBAL] fixed[0]=image_1a.mha // support for multi-planar registration fixed[1]=image_1b.mha moving[0]=image_2a.mha moving[1]=image_2b.mha $aux=image_1a_mask.mha // load image into a variable img_out[0]=warped_1a.mha [FILTER] action=dmap // could be lua script here... input_1=$fixed[0] // set input from variable input_2=$aux // set input from variable input_3=image_1c.mha // load image into a variable $f1=$fixed[0] // save a copy of the old fixed[0] fixed[0]=$output // overwrite fixed[0] with filter output [STAGE] xform=translation optim=rsg max_its=30 res=4 4 2 [RESUME_STAGE] // continue existing stage (yuck) max_its=50 [STAGE] fixed[0]=$f1 // replace fixed image for this stage xform=bspline Proposal #2, extend lua scripting. Something like this: -- Global (inputs) r = Registration() r:fixed[0] = Image.load("image_1a.mha") r:fixed[1] = Image.load("image_1b.mha") r:moving[0] = Image.load("image_2a.mha") r:moving[1] = Image.load("image_2b.mha") aux = Image.load("image_1a_mask.mha") -- Filter f1 = fixed[0] r:fixed[0] = Dmap:get_output (r:fixed[0], aux, Image.load("Image_1c.mha")) -- Stage s = r:Stage () s:xform = 'translation' s:optim = 'rsg' s:max_its = 30 s:res = '4 4 2' s:run() -- Stage (continuation) s:max_its = 30 s:run() -- Stage s = r:Stage(s) s:fixed[0] = f1 s:xform = 'bspline' s:run() -- Global (outputs) r:get_output():save("warped_1a.mha") ***** What to do about const smart pointers ***** (Your answer here) ***** A trick for forward declaration of nested classes ***** http://stackoverflow.com/questions/2600385/c-nested-class-forward-declaration-issue (Not the first answer that was accepted though. The second one is the one you want.) ***** Rt_study API example ***** /* Example #1, simple save using images */ itk::Image::Pointer itk_image; itk::Image::Pointer itk_dose; itk::Image::Pointer itk_structure_1; itk::Image::Pointer itk_structure_2; Rt_study rt_study; rt_study.set_image (itk_image); rt_study.set_dose (itk_dose); rt_study.add_structure (itk_structure_1, "Body", "255\\0\\0"); rt_study.add_structure (itk_structure_2, "Tumor", "0\\255\\0"); rt_study.save ("output_directory"); /* Example #2, save structure set that references existing CT image */ Rt_study rt_study; rt_study.add_structure (itk_structure_1, "Body", "255\\0\\0"); rt_study.add_structure (itk_structure_2, "Tumor", "0\\255\\0"); const char *study_uid, *ct_series_uid, *for_uid; Rt_study_metadata::Pointer = rt_study.get_study_metadata(); rt_study_metadata.set_study_uid (study_uid); rt_study_metadata.set_ct_series_uid (ct_series_uid); rt_study_metadata.set_frame_of_reference_uid (for_uid); rt_study_metadata.set_study_metadata (0x0010, 0x0010, "PATIENT^NAME"); rt_study_metadata.set_study_metadata (0x0010, 0x0020, "PATIENT^ID"); itk::Image::Pointer itk_image; rt_study_metadata.set_image_header (itk_reference_image); for (int slice = 0; slice < num_slices; slice++) { rt_study_metadata.set_slice_uid (slice, uid_string[slice]); } rt_study.save ("output_directory"); ***** Which metadata goes where? ***** PatientPosition ? StudyID ? ***** Rtss, rtss_structure_set, ... ***** These names are lousy. Let's get some new names. DICOM officially refers to the set of all structures as a "RT Structure Set". The image associated with the structures is called a "Contour Image Sequence". A single structure is called an "ROI". A single polyline is called an "ROI Contour". Proposed names (polyline types) - Rtss_contour replaces Rtss_polyline - Rtss_roi replaces Rtss_structure - Rtss replaces Rtss_structure_set Proposed names (image & polymorphic types) - Segmentation replaces Rtss - Segmentation_image replaces Ss_img ***** Smart pointers part 3 ***** Things to fix - Plm_image::steal_volume () should be removed - Rtds::load_dcmtk (const char *dicom_path) - need to be fixed ***** Smart pointers redux ***** Prefer to have "internal" smart pointers Dlib has 3 kinds #include "smart_pointers/scoped_ptr.h" #include "smart_pointers/shared_ptr.h" #include "smart_pointers/weak_ptr.h" - shared_ptr is a standard smart pointer - weak_ptr is a shared_ptr that can go away; you make a special call to see if it's still there - scoped_ptr doesn't have reference counting ***** DICOM re-org 2013-03-24 ***** Future plan: Dicom_rt_study -> Various metadata -> Dcmtk_rt_study -> Backpointer to Dicom_rt_study -> More metadata -> Dcmtk_series (dose) // currently in dcmtk_loader -> Dcmtk_series (rtss) // currently in dcmtk_loader -> Dcmtk_series (img) //?? -> cxt // currently in dcmtk_loader -> dose // currently in dcmtk_loader -> img // currently in dcmtk_loader ***** MABS re-org ***** Prep/training steps: (1) convert file format (2) do registrations, compute dice, possibly optimize registration (3) warp structures and get distance maps (4) optimize voting parameters (rho, sigma, thresh) Workflow -- optimizing registrations ------------------------------------ convert file format for each image pair for each registration parameter register warp structures compute distance maps compute dice tabulate results choose best registration parameter Workflow -- optimizing voting parameters ---------------------------------------- convert file format for each image pair register warp structures compute distance maps for each structure for each voting parameter for each image pair load dmap vote save weights for each thresh threshold image compute dice save results Workflow -- standard usage -------------------------- for each image pair register warp structures for each structure compute distance maps vote threshold image Other thoughts: (1) Make dmap, dice faster ***** Geometry chooser ***** Two use cases. Use case one: - Manual overrides - Fixed image - Input image Use case two: - Manual overrides - Fixed image - Reference image - Compare image ***** DICOM re-org ***** Need patient, study, series hierarchy. ------ Plm_patient ---- Plm_study -- Plm_series This should be allowed to be created via dicom. It might therefore be required to move rtss/rtds code into base. These files would move: Idea (1). Plm_series has a "type" field, which tells us if the item is an image, rtss, etc. Idea (2). Plm_series is a base type, subclassed by image, rtss, etc. ***** Viscous ***** It seems that only certain versions of thrust work with certain versions of cuda. Thrust 1.6.0 does not work with CUDA 3.0 Thrust 1.4.0 does work with CUDA 3.0 ***** Metadata Mark II ***** Do we need separate metadata items for image, dose, and rtstruct? Not sure. Here are the considerations: - ITK dicom write (image) requires setting metadata into itk image - CXT, xio formats need somewhere to store the metadata - RDD has its own metadata Where does RTSS metadata get used (version 1.5.9) - cxt_io.cxx - name, id, sex (rtss meta) - study id, ct study id, ct series id, ct for id (rdd) - gdcm1_rtss.cxx - name, id, sex, series description - study id, ct study id, ct series id, ct for, ct slice ids (rdd) Where RDD metadata get used (version 1.5.9) - rtds.cxx - name, id, sex, patient position - (xio ct transform -- this should be part of metadata??) - gdcm1_rdd.cxx - name, id, sex, patient position Options: (a) All in rtds. PRO: simple, heterogenous data structure makes sense CON: registration code (and other code which doesn't use rtds) still needs somewhere to store metadata (b) Separate metadata for each item PRO: more similar to dicom, works well with registration code CON: difficult to synchronize Final choice: - Separate metadata for image, struct, dose - Special structure for ct uids, etc. These go in rtds instead of image (as they are now), because we might have a referenced dicom dir, without an actual image. ***** Debian notes ***** In order to install ITK 3.20, you need to use unstable repository. Here is what you need: sudo apt-get -V install -t unstable \ libgdcm2-dev libinsighttoolkit3-dev libvtk5-dev It seems that Debian ITK was built with GDCM 2.X instead of GDCM 1.X. Too bad. ***** Organization of learning code ***** Use cases: image: can be 2d (slice) or 3d (vol) pos: can be 1d (slice loc), 2d (in-plane), or 3d (position) binary (in/out, male/female) tri-state (above, near, below) continuous tri-state (above (+1), near (-1 to +1), below (-1)) conditional position (inside (with position), outside (without position)) - T-spine slice -> slice loc slice -> in-plane - Lung apex slice -> continuous tri-state - T-spine slice + continuous tri-state -> slice loc Finding training data: T-spine: Choose only slice or vol centered at fiducial T-spine: Interpolate fiducials, use all slices Lung apex: Choose only slice at apex Lung apex: Choose all slices, compute distance to apex Lung volume: Choose all slices intersecting mask Transition plan: Use hard-coded training routines for different use cases plastimatch autolabel-train \ --task t-spine-v1 \ --input dir \ --output net The data needs a hierarchy, to allow for cross-validation on a patient-by-patient basis. Call the data for a single patient an Autolabel_data_item Autolabel_data_item { dlib::matrix inputs; dlib::matrix outputs; } Autolabel_data { std::list choose_subset () } Autolabel_trainer { Autolabel_data ad; train (parameter_range) { for (num_trials) { dlib::matrix training_data = ad.choose_subset(); } } } ***** Organization for irregular volume (transition plan) ***** (1) Use native, not ITK (2) Only support volumes with irregular slice spacing. No support for things like changing pixel size or direction cosines (3) Add irregular volume as a member of Volume class Volume { /* Regular volume stuff */ int npix; void *data; /* Irregular volume stuff */ float *irr_spacing; void **irr_data; }; ***** Writing a Slicer4 loadable module ***** (1) Use the wizard to make a template export SD=$HOME/build/slicer-4/Slicer4 python ${SD}/Scripts/ModuleWizard.py \ --template ${SD}/QTModules/ModuleTemplate \ --target MY_MODULE_NAME \ MY_MODULE_NAME (2) Modify CMakeLists.txt find_package (Slicer QUIET) if (SLICER_FOUND) include ("${Slicer_USE_FILE}") if (SLICER_IS_SLICER4) add_subdirectory (QTModules/MY_MODULE_NAME) endif () endif () (3) Copy over TestingMacros.h cp ${SD}/TestingMacros.h MY_MODULE_NAME At this point you can compile, and it runs. But it builds directly into the slicer directory. This can be (partly) defeated using the following strategy, but it is a moot point because you can't yet set the module search path. Here is the strategy: (4) Defeat Slicer overwriting CMAKE_* variables if (Slicer_USE_FILE) set (OLD_CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set (OLD_CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) set (OLD_CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) include ("${Slicer_USE_FILE}") set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OLD_CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OLD_CMAKE_LIBRARY_OUTPUT_DIRECTORY}) set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OLD_CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) endif () (5) Edit CMakeLists.txt files generated by the python script. There are two files to edit: MY_MODULE_NAME/CMakeLists.txt, and MY_MODULE_NAME/Logic/CMakeLists.txt. (5a) For MY_MODULE_NAME/CMakeLists.txt, do the following: set (lib_name qSlicer${qt_module_name}Module) set_target_properties (${lib_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_BIN_DIR}" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_LIB_DIR}" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_LIB_DIR}" ) (5b) For MY_MODULE_NAME/Logic/CMakeLists.txt, do the following: SlicerMacroBuildModuleLogic( NAME ${module_logic_name} DISABLE_WRAP_PYTHON EXPORT_DIRECTIVE ${module_logic_export_directive} INCLUDE_DIRECTORIES ${module_logic_include_directories} SRCS ${module_logic_SRCS} TARGET_LIBRARIES ${module_logic_target_libraries} ) set_target_properties (${module_logic_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_BIN_DIR}" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_LIB_DIR}" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${Slicer_INSTALL_QTLOADABLEMODULES_LIB_DIR}" ) ***** Proton dose ideas ***** Stage 1(a): Compute pencil beam in standard grid (z direction is pdd in water) (x-y direction is scatter in water, or just 1-d with distance) Stage 1(b): Compute RPL in interpolated coordinate system (z axis is beam axis) (x-y perpendicular to beam, arbitrary v-up vector) Stage 2: For each voxel a) Look up primary in RPL grid b) Convolve to find scatter within x-y axis of primary grid (ignoring tilt) ***** File browser design ***** http://www.xvsxp.com/files/file_browsing.php http://rixstep.com/4/0/xfile/ss.shtml http://www.ragesw.com/products/explorer/screenshots/1/ ***** Writing to stdout in Qt ***** QTextStream(stdout) << QString("foo") << "\n"; ***** dgate quite ref (for wormwood) ***** cd ~/build/conquest-1.4.15 ./dgate & ***** dcmtk quick ref ***** Run the dicom server like this: $ dcmqrscp It will read a file "dcmqrscp.cfg" in the current directory, which is used to set user/group, port, AET, storage directory. NOTE: Be very careful about extra spaces in the list of remote AETs. Here the file I used for these tests: --- begin here --- NetworkType = "tcp" NetworkTCPPort = 9885 MaxPDUSize = 16384 MaxAssociations = 16 Display = "no" UserName = "gsharp" GroupName = "gsharp" HostTable BEGIN entry1 = (MOVESCU, localhost, 19530) entry2 = (STORESCP, localhost, 19335) HostTable END VendorTable BEGIN VendorTable END AETable BEGIN READWRITE /home/gsharp/projects/dicom-test/junk RW (10, 1024mb) ANY AETable END --- end here --- Send files to database like this: $ storescu -aec READWRITE localhost 9885 *.dcm Query the database like this: $ findscu -P -k 0010,0010 -k 0008,0052=PATIENT -aec READWRITE localhost 9885 Retrieve from the database like this: $ movescu -v --patient -aet MOVESCU -aem MOVESCU -aec READWRITE --port 19530 -k 0008,0052=PATIENT -k 0010,0020=PL811332912032439 localhost 9885 Or like this: $ storescp 19335 & $ movescu -v --patient -aet MOVESCU -aem STORESCP -aec READWRITE -k 0008,0052=PATIENT -k 0010,0020=PL811332912032439 localhost 9885 ***** Proposed engineering changes: Aug 1, 2009 ***** 1) Reduce number of executables Old: plastimatch [options] dicom_to_mha [options] warp_mha [options] New: plastimatch register [options] plastimatch convert [options] plastimatch warp [options] "Simple" executables such as bspline.exe, drr_c.exe etc. will not be merged. 2) Add threading options to plastimatch Old: implementation=gpuit_cpu New: implementation=plastimatch threading=openmp max_threads=2 3) Remove gpuit sub-library, merge into plastimatch1.lib 4) Move source code to src/ subdirectory ***** How to compile libf2c ***** Edit libf2c/makefile.vc, and change: CFLAGS = -DUSE_CLOCK -DMSDOS -DNO_ONEXIT -Ot1 To: CFLAGS = -DUSE_CLOCK -DMSDOS -DNO_ONEXIT -Ot1 -MD Edit libf2c/fio.h, and comment out: extern int isatty(int); ***** How to compile the .br into .cpp ***** The default compile is simply: brcc -o outfile.cpp infile.br The FDK code doesn't work for PS20 & ARB targets. We can use -p flag to set the platform. brcc -o outfile.cpp ***** How to compile brook on cygwin/g++ ***** 1) The config/DetectOS thing always gets Windows_NT because the $OS environment variable is standard in Windows. 2) Need to create a new *.mk file (To be done) 3) It seems to build OK, but doesn't completely solve the problem. fxc still requires windows style paths, maybe cgc does too. ***** Threads vs OpenMP ***** http://www.intel.com/cd/ids/developer/asmo-na/eng/technologies/threading/hyperthreading/53797.htm https://computing.llnl.gov/tutorials/openMP/ On GCC: gcc -fopenmp openmp_test.c Visual studio 2005 supports OpenMP 2.0 cl /openmp Express version does not support OpenMP (except as described below) http://blog.codekills.net/archives/25-OpenMP-and-Visual-C++-the-free-way-sorta.html MinGW gcc OpenMP is still not fully supported http://www.nabble.com/OpenMP-and-shared-libgcc-td17516165.html ***** What is the deal with ITK's oriented images? ***** http://www.itk.org/pipermail/insight-users/2008-August/027102.html Now, ITK 3.10.2 has two flags (earlier version are similar). The use of these flags are not well described. ITK_USE_ORIENTED_IMAGE_DIRECTION ITK_IMAGE_BEHAVES_AS_ORIENTED_IMAGE ***** Logging ***** For "C" logging, I found 2 projects: - log4c (LGPL license) - pantheios (BSD license) ***** Timing ***** Options: 1) clock() 2) time() 3) gettimeofday() 4) QueryPerformanceCounter // windows only 5) OpenMP timer 6a) clock_gettime(CLOCK_MONOTONIC) 6b) clock_gettime(CLOCK_REALTIME) 6c) clock_gettime(CLOCK_HIGHRES) // solaris only? http://en.wikipedia.org/wiki/Real-time_clock http://en.wikipedia.org/wiki/High_Precision_Event_Timer http://cboard.cprogramming.com/c-programming/106025-clock-vs-gettimeofday.html http://fixunix.com/linux/6645-negative-response-time-gettimeofday.html http://code.google.com/p/high-resolution-timer/source/browse/trunk/highrestimer/c%2B%2B_library/wraper_and_library/timer_library.c ***** SVN eol-goop ***** Put the following in your ~/.subversion/config CMakeLists.txt = svn:eol-style=native;svn:mime-type=text/plain Makefile = svn:eol-style=native;svn:mime-type=text/plain README* = svn:mime-type=text/plain;svn:eol-style=native readme* = svn:mime-type=text/plain;svn:eol-style=native *.tga = svn:mime-type=image/tga *.bat = svn:mime-type=text/plain;svn:eol-style=CRLF *.br = svn:eol-style=native;svn:mime-type=text/plain *.c = svn:eol-style=native;svn:mime-type=text/plain *.cmake = svn:mime-type=text/plain;svn:eol-style=native *.cmd = svn:mime-type=text/plain;svn:eol-style=CRLF *.cpp = svn:eol-style=native;svn:mime-type=text/plain *.cu = svn:eol-style=native;svn:mime-type=text/plain *.cxx = svn:eol-style=native;svn:mime-type=text/plain *.dsp = svn:eol-style=CRLF;svn:mime-type=text/plain *.dsw = svn:eol-style=CRLF;svn:mime-type=text/plain *.f = svn:eol-style=native;svn:mime-type=text/plain *.h = svn:eol-style=native;svn:mime-type=text/plain *.jpg = svn:mime-type=image/jpeg *.m = svn:eol-style=native;svn:mime-type=text/plain *.pl = svn:eol-style=native;svn:mime-type=text/plain;svn:executable *.png = svn:mime-type=image/png *.pm = svn:eol-style=native;svn:mime-type=text/plain *.sh = svn:mime-type=text/plain;svn:eol-style=LF;svn:executable *.txt = svn:mime-type=text/plain;svn:eol-style=native *.xml = svn:mime-type=text/xml;svn:eol-style=native plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/README.TXT000077500000000000000000000002621321604176500236250ustar00rootroot00000000000000To build the sphinx documentation, do this: sphinx-build -b html source_dir build_dir For example: sphinx-build -b html ~/work/plastimatch/doc/sphinx/ ~/work/web-plastimatch/ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/ROADMAP.TXT000066400000000000000000000031131321604176500237460ustar00rootroot000000000000002.0 Features * All registration parameters have auto defaults * Long option alias * Multi-planar registration * Multi-similarity registration * Overlap fraction penalty for native registration methods * Full support for irregular slice spacing * Superbuild * Non-aligned B-spline LUT Backward incompatible changes * Remove short options * DRR/FDK/dose calc use IEC coordinates * GDCM becomes deprecated * Standalone executables will no longer be available, instead they are merged into plastimatch executable: vf-invert, landmark-warp, drr, fdk, wed * Metric mi will default to Mattes for ITK methods (done) * Automatic tuning of regularization lambda as default (?) * xform=align_center -> xform=translation, optim=align_center Documentation * Registration tutorial based on NA-MIC case library * MABS tutorial Cleanup * Remove Pstring/bstring (done) * Remove unnecessary third party libraries (f2c, nocedal, sqlite?, lua?) * Evaluate if duplication between Stage_parms and Bspline_parms can be removed * Re-evaluate B-spline loop template * DICOM uses module system Wishlist * Autolabel (la,tsv1,tsv2) * Copy-free conversion between itk and native volumes * RTK wrapping * DRR/FDK dicom * Evaluate native vs itk jacobian * MSVC express multicore strategy (done, MSVC 2013 and higher) * Native rigid registration * Normalized MI * patient mask to support MRI * plastimatch gradient magnitude (done) * Proton/photon/electron dose calculation ** Add multi-beam to command file (done) ** Remove duplication of code for photons * RTPLAN support * Standalone GUI plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/STYLE_GUIDE_1.TXT000066400000000000000000000077721321604176500247370ustar00rootroot00000000000000Introduction ------------ This is part 1 of the style guide. It concerns how the C/C++ syntax should be formated within a file. Unified coding style is important because it eases software review and maintenance. This file specifies guidelines which can be broken for specific cases, but should be adhered to as closely as possible. Plastimatch can't be properly formatted automatically by GNU indent or astyle. Uncrustify will do a decent job; an uncrustify configuration file is included in the distribution. Files ----- Source code files should use Unix-style end-of-line characters. All source code should be written in 7-bit clean ASCII. Third-party code ---------------- Third-party code should be placed in separate files, and should be clearly identified, so that no mistake in licensing occurs. Indentation ----------- Indentation should be 4 spaces. Tabs are allowed, but you must set your tab stop to 8 spaces. Note that this is not the default for Microsoft Visual Studio compilers, so you should adjust your setting. Line breaking ------------- Code should be limited to 80 columns when possible. Use typedefs to assist in this process. Curly braces ------------ Use GNU curly brace style (curly on its own line) for function definitions, and K&R curly brace style (curly on same line as conditional) everywhere else. Always use curly braces for if/do/while/for statements, even if there is only one statement in the block. For a simple else clause, cozy it up with the previous right curly. For testing multiple cases, move the else keyword to a new line. Examples: int foo (int bar) { if (bar == 3) { return 1; } else { return 0; } } int foo (int bar) { if (bar == 3) { return 1; } else if (bar == 5) { return 2; } else { return 0; } } Switch statement ---------------- Case labels are not indented in the switch statement. A default label is required (even if there is no code). switch (x) { case a: code; case b: code; case c: default: code; } Function definitions -------------------- Declaritors and return values go on a separate line (GNU style): static int foo (int bar) { Use explicit "void" in the argument list if there are no arguments is optional: void foo (void) { Horizontal whitespace --------------------- Horizontal whitespace is used between operators and operands. Conditionals should be laid out like this: if (bar == 3 && baz > 4) { Function calls like this: foo (a, b); When there are no arguments, you may omit the space: foo(); Pointers and references ----------------------- As per linux kernel style, put the '*' adjacent to the data name or function name and not adjacent to the type name. char *foo; char *bar (char *baz, char **boo); The reason for this rule is it allows the declaration of multiple variables of the same type in a single statement. char *p, *q, *pv, *pq; However, references go together with the type rather than the name. char& linux_banner = s1; char& bar (char& baz, char*& boo); Vertical whitespace ------------------- A single empty line is used between functions or between two groups of code. Identifier naming ----------------- Prefer English words to abbreviations. Words are separated by underscores. Use lowercase for function names, variable names, and structure names. Use all upper case for constants. struct long_list { int list_length; void *list_items; } int my_function (struct long_list employee_list) { const int DESIRED_LENGTH = 3; employee_list->list_length = DESIRED_LENGTH; } Names for typedefs and C++ classes should capitalize only the first letter. Member names are lower case. class Volume_resizer { public: int foo; void bar (void); } void Volume_resizer::bar (void) { code; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/STYLE_GUIDE_2.TXT000066400000000000000000000160351321604176500247300ustar00rootroot00000000000000Introduction ------------ This is part 2 of the style guide. It concerns how variables and functions should be named to maintain a uniform look and feel. Include files ------------- Include files should be in the following order: 1) plm_config.h 2) Standard C++ include files (sorted alphabetically) 3) Standard C include files (sorted alphabetically) 4) Third party library include files (grouped, sorted alphabetically within each group if possible) 5) Plastimatch include files (sorted alphabetically) File names and function names ----------------------------- Generally, files will come in pairs, one h file and one cxx file. These pair of files will normally define a single public C++ class, and optionally will define a second private C++ class. The public class name will have the same name as the h and cxx file. For example, the class Plm_image is defined in plm_image.h. The private class will include the suffix "_private", and is defined in the cxx file. For example, class Plm_image_private is defined in plm_image.cxx. Layout of a public class definition ----------------------------------- The first entries of the class definition specify the API linkage, smart pointer support, and private class data. Next are the constructors and destructors. For example: class PLMBASE_API Plm_image { public: SMART_POINTER_SUPPORT (Plm_image); Plm_image_private *d_ptr; public: Plm_image (); The token PLMBASE_API is defined in plmbase_config.h, and is reqired for linking with the library on windows. The macro SMART_POINTER_SUPPORT specifies that this class allows the use of smart pointers, and is defined in smart_pointer.h. Native layer, itk layer, wrapper layer [Proposed, not implemented] ------------------------------------------------------------------ The following prefixes should be used for these three layers: itk_xxxx ## ITK layer, makes itk function calls. xxxx ## Native layer plm_xxxx ## Wrapper layer Alternatives: plc_xxx ## Native layer plm_core_xxx ## Native layer plw_xxx ## Wrapper layer For images, we currently use this following: itk_image, itk ## ITK layer volume ## Native layer plm_image, pli ## Wrapper layer For complex images (multiple irregular spacings), consider the following: itk_volume, itk ## ITK layer volume ## Native layer plm_volume, plv ## Wrapper layer plm_volset, plv ## Wrapper layer (wrapper layer sufficient?) The image header would become: itk_volume_header ## ITK layer volume_header ## Native layer plm_volume_header ## Wrapper layer plm_volset_header ## Wrapper layer (wrapper layer sufficient?) Command line args, Function options [Proposed, not implemented] --------------------------------------------------------------- Command line arguments are digested, and then placed in a structure called Xxx_args. Example: class Warp_args { ... }; Complicated functions which are controlled by a structure full of options will use a structure called Xxx_opts. Example: typedef struct bspline_opts Bspline_opts; struct bspline_opts { ... }; N.b. The old way is to use the term "parms" for both types of structures. N.b. Does this even make sense? Cxt_to_mha can use the same structure for both uses. Dim, dims, offset, origin, spacing ---------------------------------- To describe the position of an image in mm, use origin, not offset. The term offset is used to describe an ROI in voxels. To describe the resolution of an image in voxels, use dim, not dims. The order of parameters should be alphabetic: calling_a_function (dim, origin, spacing); Except that direction_cosines is last: calling_a_function (dim, origin, spacing, direction_cosines); For itk routines, it should follow the same semantic order, but it becomes non-alphabetic: calling_a_function (region, origin, spacing, direction_cosines); Direction_cosines, direction_matrix, Itk_direction -------------------------------------------------- A "direction matrix" is a raw matrix of nine numbers. The ITK version is called an Itk_direction. A Direction_cosine is a container that also holds the inverse. UChar, Char, ... ---------------- The ordering is: itk, then gpuit, integers, then float, then vectors, smaller, then larger, unsigned, then signed. get, set -------- The ordering is: get, then set Plm_image, ITK image, Volume ---------------------------- Overloaded functions which return specific types should specify them as follows: object.get_image (); // Returns Plm_image::Pointer object.get_image_itk () // Returns most appropriate itk type // (usually FloatImageType::Pointer) object.get_volume (); // Returns Volume::Pointer of most // appropriate type (usually float) object.get_vol (); // Returns Volume* When appropriate, the functions may be suffixed to specify the return type: object.get_image_itk_float (); object.get_volume_float (); Index convention in images and volumes -------------------------------------- The following convention is used for walking through images k, z = slowest moving index (usually IS) j, y = middle moving index (usually AP) i, x = fastest moving index (usually RL) Arrays which hold things like the dimensions are indexed as follows: dim[0] = dimensions of fastest moving index dim[1] = dimensions of middle moving index dim[2] = dimensions of slowest moving index Loops should be nested from slowest index to fastest index. Therefore, the correct nesting is: for (k = 0; k < fixed->dim[2]; k++) { for (j = 0; j < fixed->dim[1]; j++) { for (i = 0; i < fixed->dim[0]; i++) { ... } } } Embedded indices, such as (x,y,z) coordinates of the vector field at a voxel, should be in the order of x, then y, then z. When you pass indices into a function it should be in order x, then y, then z. For example: int volume_index (int* dims, int i, int j, int k); For 2D images, dim is preferred over ires. And (j,i) preferred over (r,c). But for legacy code, the following should be true: r, j, dim[1], ires[1] = slowest moving index (row) c, i, dim[0], ires[0] = fastest moving index (column) Variable naming for indexing [Proposed, not implemented] --------------------------------------------------------- idx index one dimensional index ijk coords three dimensional index xyz position three dimensional position Fixed image voxel fijk[3], fidx Fixed world coord fxyz[3] Moving image voxel mijk[3], midx < ditto > Moving world voxel mxyz[3] Tile p[3], pidx Offset within tile q[3], qidx Control point (c[3]), cidx Coefficient array ? Multiplier LUT qidx Index LUT pidx plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/man/000077500000000000000000000000001321604176500230375ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/man/README.TXT000066400000000000000000000003231321604176500243730ustar00rootroot00000000000000This directory includes the man pages for plastimatch, fdk, drr and landmark_warp. To enable these guides, as administrator, copy the files: plastimatch.1 fdk.1 drr.1 landmark_warp.1 into /usr/share/man/man1 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/man/drr.1000066400000000000000000000133731321604176500237170ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH "DRR" "1" "Dec 18, 2017" "Plastimatch 1.7.0" "Plastimatch" .SH NAME drr \- create a digitally reconstructed radiograph . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .sp \fBdrr [options] [infile]\fP .SH DESCRIPTION .sp A digitally reconstructed radiograph (DRR) is a synthetic radiograph which can be generated from a computed tomography (CT) scan. It is used as a reference image for verifying the correct setup position of a patient prior to radiation treatment. .SH DRR USAGE .sp The drr program that comes with plastimatch takes a CT image as input, and generates one or more output images. The input image is in MHA format, and the output images can be either pgm, pfm, or raw format. The command line usage is: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: drr [options] [infile] Options: \-A hardware Either "cpu" or "cuda" (default=cpu) \-a num Generate num equally spaced angles \-N angle Difference between neighboring angles (in degrees) \-nrm "x y z" Set the normal vector for the panel \-vup "x y z" Set the vup vector (toward top row) for the panel \-g "sad sid" Set the sad, sid (in mm) \-r "r c" Set output resolution (in pixels) \-s scale Scale the intensity of the output file \-e Do exponential mapping of output values \-c "r c" Set the image center (in pixels) \-z "s1 s2" Set the physical size of imager (in mm) \-w "r1 r2 c1 c2" Only produce image for pixes in window (in pix) \-t outformat Select output format: pgm, pfm or raw \-i algorithm Choose algorithm {exact,uniform} \-o "o1 o2 o3" Set isocenter position \-I infile Set the input file in mha format \-O outprefix Generate output files using the specified prefix .ft P .fi .UNINDENT .UNINDENT .sp The drr program can be used in either \fIsingle image mode\fP or \fIrotational mode\fP\&. In single image mode, you specify the complete geometry of the x\-ray source and imaging panel for a single image. In rotational mode, the imaging geometry is assumed to be .sp The command line options are described in more details as follows. .INDENT 0.0 .TP .B \-A hardware Choose the threading mode, which is either "cpu" or "cuda". The default value is "cpu". .sp When using CPU hardware, DRR generation uses OpenMP for multicore acceleration if your compiler supports this. Gcc and Microsoft Visual Studio Professional compilers support OpenMP, but Microsoft Visual Studio Express does not. .sp At the current time, cuda acceleration is not working. .UNINDENT .INDENT 0.0 .TP .B \-a num Generate num equally spaced angles .UNINDENT .INDENT 0.0 .TP .B \-r """r1 r2""" Set the resolution of the imaging panel (in pixels). Here, r1 refers to the number of rows, and r2 refers to the number of columns. .UNINDENT .SH SINGLE IMAGE MODE .sp The following example illustrates the use of single image mode: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C drr \-nrm "1 0 0" \e \-vup "0 0 1" \e \-g "1000 1500" \e \-r "1024 768" \e \-z "400 300" \e \-c "383.5 511.5" \e \-o "0 \-20 \-50" \e input_file.mha .ft P .fi .UNINDENT .UNINDENT .sp In the above example, the isocenter is chosen to be (0, \-20, \-50), the location marked on the CT image. The orientation of the projection image is controlled by the \fBnrm\fP and \fBvup\fP options. Using the default values of (1, 0, 0) and (0, 0, 1) yields the DRR shown on the right: [image] [image] .sp By changing the normal direction (\fBnrm\fP), we can choose different beam direction within an isocentric orbit. For example, an anterior\-posterior (AP) DRR is generated with a normal of (0, \-1, 0) as shown below: [image] .sp The rotation of the imaging panel is selected using the \fBvup\fP option. The default value of \fBvup\fP is (0, 0, 1), which means that the top of the panel is oriented toward the positive z direction in world coordinates. If we wanted to rotate the panel by 45 degrees counter\-clockwise on our AP view, we would set \fBvup\fP to the (1, 0, 1) direction, as shown in the image below. Note that \fBvup\fP doesn\(aqt have to be normalized. [image] .SH ROTATIONAL MODE .sp In rotional mode, multiple images are created. The source and imaging panel are assumed to rotate in a circular orbit around the isocenter. The circular orbit is performed around the Z axis, and the images are generated every \fB\-N ang\fP degrees of the orbit. This is illustrated using the following example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C drr \-N 20 \e \-a 18 \e \-g "1000 1500" \e \-r "1024 768" \e \-z "400 300" \e \-o "0 \-20 \-50" \e input_file.mha .ft P .fi .UNINDENT .UNINDENT .sp In the above example, 18 images are generated at a 20 degree interval, as follows: [image] .SH AUTHOR Plastimatch is a collaborative project. For additional documentation, please visit http://plastimatch.org. For questions, comments, and bug reports, please visit http://groups.google.com/group/plastimatch. .SH COPYRIGHT Plastimatch development team (C) 2010-2015. You are free to use, modify, and distribute plastimatch according to a BSD-style license. Please see LICENSE.TXT for details. .\" Generated by docutils manpage writer. . plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/man/fdk.1000066400000000000000000000107531321604176500236730ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH "FDK" "1" "Dec 18, 2017" "Plastimatch 1.7.0" "Plastimatch" .SH NAME fdk \- cone-beam reconstruction from projections using the FDK algorithm . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .sp The term FDK refers to the authors Feldkamp, Davis, and Kress who wrote the seminal paper "Practical cone\-beam algorithm" in 1984. Their paper describes a filtered back\-projection reconstruction algorithm for cone\-beam geometries. The fdk program in plastimatch is an implmenetation of the FDK algorithm. .SH FDK USAGE .sp The fdk program takes a directory of 2D projection images as input, and generates a single 3D volume as output. .sp The command line usage is: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: fdk [options] Options: \-A hardware Either "cpu" or "cuda" (default=cpu) \-a "num ((num) num)" Use this range of images \-r "r1 r2 r3" Set output resolution (in voxels) \-f filter Either "none" or "ramp" (default=ramp) \-s scale Scale the intensity of the output file \-z "s1 s2 s3" Physical size of the reconstruction (in mm) \-I indir The input directory \-O outfile The output file .ft P .fi .UNINDENT .UNINDENT .sp The usage of the fdk program is best understood by following along with the tutorials: fdk_tutorial_i and fdk_tutorial_ii\&. .SH INPUT FILES .sp Three different formats of input files are supported. These are: .INDENT 0.0 .IP \(bu 2 Pfm format image files with geometry txt files .IP \(bu 2 Raw format image files with geometry txt files .IP \(bu 2 Varian hnd files .UNINDENT .sp The pfm and raw files are similar, in that they store the image as an array of 4\-byte little\-endian floats. The only difference is that the pfm file has a header which stores the image size, and the raw file does not. .sp Each pfm or raw image file must have a geometry file in the same directory with the .txt extension. For example, if you want to use image_0000.pfm in a reconstruction, you should supply another file image_0000.txt which contains the geometry. A brief description of the geometry file format is given in proj_mat_file_format\&. .sp The sequence of files should be stored with the pattern: .INDENT 0.0 .INDENT 3.5 XXXXYYYY.ZZZ .UNINDENT .UNINDENT .sp where XXXX is a prefix, YYYY is a number, and .ZZZ is the extension of a known type (either .hnd, .pfm, or .raw). .sp For example the following would be a good directory layout for pfm files: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Files/image_00.pfm Files/image_00.txt Files/image_01.pfm Files/image_01.txt etc... .ft P .fi .UNINDENT .UNINDENT .sp The Varian hnd files should be stored in the original layout. For example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Files/ProjectionInfo.xml Files/Scan0/Proj_0000.hnd Files/Scan0/Proj_0001.hnd etc... .ft P .fi .UNINDENT .UNINDENT .sp No geometry txt files are needed to reconstruct from Varian hnd format. .SH IMAGE GEOMETRY .sp By default, when you generate a DRR, the image is oriented as if the virtual x\-ray source were a camera. That means that for a right lateral film, the columns of the image go from inf to sup, and the rows go from ant to post. The Varian OBI system produces HND files, which are oriented differently. For a right lateral film, the columns of the HND images go from ant to post, and the rows go from sup to inf. An illustration of this idea is shown in the figure below. .INDENT 0.0 .INDENT 2.5 [image] Geometry of Varian HND files.UNINDENT .UNINDENT .SH AUTHOR Plastimatch is a collaborative project. For additional documentation, please visit http://plastimatch.org. For questions, comments, and bug reports, please visit http://groups.google.com/group/plastimatch. .SH COPYRIGHT Plastimatch development team (C) 2010-2015. You are free to use, modify, and distribute plastimatch according to a BSD-style license. Please see LICENSE.TXT for details. .\" Generated by docutils manpage writer. . plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/man/landmark_warp.1000066400000000000000000000076461321604176500257600ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH "LANDMARK_WARP" "1" "Dec 18, 2017" "Plastimatch 1.7.0" "Plastimatch" .SH NAME landmark_warp \- warp an image using point landmarks . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .sp \fBlandmark_warp [options]\fP .SH DESCRIPTION .sp The landmark_warp executable performs registration by matching fiducials on reference and test images. The list of possible options can be seen by typing: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C landmark_warp \-\-help .ft P .fi .UNINDENT .UNINDENT .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: landmark_warp [options] Options: \-a, \-\-algorithm RBF warping algorithm {tps,gauss, wendland} \-d, \-\-default\-value Value to set for pixels with unknown value \-\-dim Size of output image in voxels "x [y z]" \-F, \-\-fixed Fixed image (match output size to this image) \-f, \-\-fixed\-landmarks Input fixed landmarks \-h, \-\-help Display this help message \-I, \-\-input\-image Input image to warp \-v, \-\-input\-vf Input vector field (applied prior to landmark warping) \-m, \-\-moving\-landmarks Output moving landmarks \-N, \-\-numclusters Number of clusters of landmarks \-\-origin Location of first image voxel in mm "x y z" \-O, \-\-output\-image Output warped image \-L, \-\-output\-landmarks Output warped landmarks \-V, \-\-output\-vf Output vector field \-r, \-\-radius Radius of radial basis function (in mm) \-\-spacing Voxel spacing in mm "x [y z]" \-Y, \-\-stiffness Young modulus (default = 0.0) .ft P .fi .UNINDENT .UNINDENT .sp Options "\-a", "\-r", "\-Y", "\-d" are set by default to: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C \-a=gauss Gaussian RBFs with infinite support \-r=50.0 Gaussian width 50 mm \-Y=0.0 No regularization of vector field \-d=\-1000 Air .ft P .fi .UNINDENT .UNINDENT .sp You may want to choose different algorithm: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C \-a=tps Thin\-plate splines (for global registration) \-a=wendland Wendland RBFs with compact support (for local registration) .ft P .fi .UNINDENT .UNINDENT .sp In the case of Wendland RBFs "\-r" option sets the radius of support. .sp Regularization of vector field is available for "gauss" and "wendland" algorithms. To regularize the output vector field increase "\-Y" to \(aq0.1\(aq and up with increment \(aq0.1\(aq. .SH AUTHOR Plastimatch is a collaborative project. For additional documentation, please visit http://plastimatch.org. For questions, comments, and bug reports, please visit http://groups.google.com/group/plastimatch. .SH COPYRIGHT Plastimatch development team (C) 2010-2015. You are free to use, modify, and distribute plastimatch according to a BSD-style license. Please see LICENSE.TXT for details. .\" Generated by docutils manpage writer. . plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/man/make_man.sh000077500000000000000000000001301321604176500251400ustar00rootroot00000000000000sphinx-build -d ~/work/web-plastimatch/.doctrees -b man ~/work/plastimatch/doc/sphinx . plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/doc/man/plastimatch.1000066400000000000000000001674051321604176500254470ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH "PLASTIMATCH" "1" "Dec 18, 2017" "Plastimatch 1.7.0" "Plastimatch" .SH NAME plastimatch \- register, convert, warp, or manipulate images . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .sp \fBplastimatch command [options]\fP .SH DESCRIPTION .sp The plastimatch executable is used for a variety of operations on either 2D or 3D images, including image registration, warping, resampling, and file format conversion. The form of the options depends upon the command given. The list of possible commands can be seen by simply typing "plastimatch" without any additional command line arguments: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ plastimatch plastimatch version 1.7.0 Usage: plastimatch command [options] Commands: add adjust average bbox boundary crop compare compose convert dice diff dmap dose dvh fill filter gamma header jacobian mabs mask maximum ml\-convert multiply probe register resample scale segment stats synth synth\-vf threshold thumbnail union vf\-invert warp xf\-convert For detailed usage of a specific command, type: plastimatch command .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH ADD .sp The \fIadd\fP command is used to add one or more images together and create an output image. The contributions of the input images can be weighted with a weight vector. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch add [options] input_file [input_file ...] Options: \-\-average produce an output file which is the average of the input files (if no weights are specified), or multiply the weights by 1/n \-\-output output image \-\-weight specify a vector of weights; the images are multiplied by the weight prior to adding their values .ft P .fi .UNINDENT .UNINDENT .SS Examples .sp To add together files 01.mha, 02.mha and 03.mha, and save the result in the file output.mha, you can run the following command: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch add \-\-output output.mha 01.mha 02.mha 03.mha .ft P .fi .UNINDENT .UNINDENT .sp If you wanted output.mha to be 2 * 01.mha + 0.5 * 02.mha + 0.1 * 03.mha, then you should do this: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch add \e \-\-output output.mha \e \-\-weight "2 0.5 0.1" \e 01.mha 02.mha 03.mha .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH ADJUST .sp The \fIadjust\fP command is used to adjust the intensity values within an image. The adjustment operations available are truncation and linear scaling. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch adjust [options] Required: \-\-input input directory or filename \-\-output output image Optional: \-\-pw\-linear a string that forms a piecewise linear map from input values to output values, of the form "in1,out1,in2,out2,..." .ft P .fi .UNINDENT .UNINDENT .sp The adjust command can be used to make a piecewise linear adjustment of the image intensities. The \-\-pw\-linear option is used to create the mapping from input intensities to output intensities. The input intensities in the curve must increase from left to right in the string, but output intensities are arbitrary. .sp Input intensities below the first pair or after the last pair are transformed by extrapolating the curve out to infinity with a slope of +1. A different slope may be specified out to positive or negative infinity by specifying the special input values of \-inf and +inf. In this case, the second number in the pair is the slope of the curve, not the output intensity. .SS Examples .sp The following command will add 100 to all voxels in the image: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch adjust \e \-\-input infile.nrrd \e \-\-output outfile.nrrd \e \-\-pw\-linear "0,100" .ft P .fi .UNINDENT .UNINDENT .sp The following command does the same thing, but with explicit specification of the slope in the extrapolation area: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch adjust \e \-\-input infile.nrrd \e \-\-output outfile.nrrd \e \-\-pw\-linear "\-inf,1,0,100,inf,1" .ft P .fi .UNINDENT .UNINDENT .sp The following command truncates the inputs to the range of [\-1000,+1000]: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch adjust \e \-\-input infile.nrrd \e \-\-output outfile.nrrd \e \-\-pw\-linear "\-inf,0,\-1000,\-1000,+1000,+1000,inf,0" .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH AVERAGE .sp The \fIaverage\fP command is used to compute the (weighted) average of multiple input images. It is the same as the plastimatch \fIadd\fP command, with the \-\-average option specified. Please refer to \fI\%plastimatch add\fP for the list of command line arguments. .SS Example .sp The following command will compute the average of three input images: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch average \e \-\-output outfile.nrrd \e 01.mha 02.mha 0.3.mha .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH AUTOLABEL .sp The \fIautolabel\fP command is an experimental program the uses machine learning to identify the thoracic vertibrae in a CT scan. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch autolabel [options] Options: \-h, \-\-help Display this help message \-\-input Input image filename (required) \-\-network Input trained network filename (required) \-\-output Output csv filename (required) .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH BOUNDARY .sp The \fIboundary\fP command takes a binary label image as input, and generates an image of the image boundary as the output. The boundary is defined as the voxels within the label which have neighboring voxels outside the label. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch boundary [options] input_file Required: \-\-output filename for output image .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH CROP .sp The \fIcrop\fP command crops out a rectangular portion of the input file, and saves that portion to an output file. The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch crop [options] Required: \-\-input=image_in \-\-output=image_out \-\-voxels="x\-min x\-max y\-min y\-max z\-min z\-max" (integers) .ft P .fi .UNINDENT .UNINDENT .sp The voxels are indexed starting at zero. In other words, if the size of the image is M \times N \times P, the x values should range between 0 and M-1\&. .SS Example .sp The following command selects the region of size 10 \times 10 \times 10, with the first voxel of the output image being at location (5,8,12) of the input image: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch crop \e \-\-input in.mha \e \-\-output out.mha \e \-\-voxels "5 14 8 17 12 21" .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH COMPARE .sp The \fIcompare\fP command compares two files by subtracting one file from the other, and reporting statistics of the difference image. The two input files must have the same geometry (origin, dimensions, and voxel spacing). The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch compare image_in_1 image_in_2 .ft P .fi .UNINDENT .UNINDENT .SS Example .sp The following command subtracts synth_2 from synth_1, and reports the statistics: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ plastimatch compare synth_1.mha synth_2.mha MIN \-558.201904 AVE 7.769664 MAX 558.680847 MAE 85.100204 MSE 18945.892578 DIF 54872 NUM 54872 .ft P .fi .UNINDENT .UNINDENT .sp The reported statistics are interpreted as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C MIN Minimum value of difference image AVE Average value of difference image MAX Maximum value of difference image MAE Mean average value of difference image MSE Mean squared difference between images DIF Number of pixels with different intensities NUM Total number of voxels in the difference image .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH COMPOSE .sp The \fIcompose\fP command is used to compose two transforms. The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch compose file_1 file_2 outfile Note: file_1 is applied first, and then file_2. outfile = file_2 o file_1 x \-> x + file_2(x + file_1(x)) .ft P .fi .UNINDENT .UNINDENT .sp The transforms can be of any type, including translation, rigid, affine, itk B\-spline, native B\-spline, or vector fields. The output file is always a vector field. .sp There is a further restriction that at least one of the input files must be either a native B\-spline or vector field. This restriction is required because that is how the resolution and voxel spacing of the output vector field is chosen. .SS Example .sp Suppose we want to compose a rigid transform (rigid.tfm) with a vector field (vf.mha), such that the output transform is equivalent to applying the rigid transform first, and the vector field second. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch compose rigid.tfm vf.mha composed_vf.mha .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH CONVERT .sp The \fIconvert\fP command is used to convert files from one format to another format. As part of the conversion process, it can also apply (linear or deformable) geometric transforms to the input images. In fact, \fIconvert\fP is just an alias for the \fIwarp\fP command. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch convert [options] Options: \-\-algorithm algorithm to use for warping, either "itk" or "native", default is native \-\-ctatts ct attributes file (used by dij warper) \-\-default\-value value to set for pixels with unknown value, default is 0 \-\-dicom\-with\-uids set to false to remove uids from created dicom filenames, default is true \-\-dif dif file (used by dij warper) \-\-dim size of output image in voxels "x [y z]" \-\-direction\-cosines oriention of x, y, and z axes; Specify either preset value, {identity,rotated\-{1,2,3},sheared}, or 9 digit matrix string "a b c d e f g h i" \-\-dose\-scale scale the dose by this value \-\-fixed fixed image (match output size to this image) \-\-input input directory or filename; can be an image, structure set file (cxt or dicom\-rt), dose file (dicom\-rt, monte\-carlo or xio), dicom directory, or xio directory \-\-input\-cxt input a cxt file \-\-input\-dose\-ast input an astroid dose volume \-\-input\-dose\-img input a dose volume \-\-input\-dose\-mc input an monte carlo volume \-\-input\-dose\-xio input an xio dose volume \-\-input\-prefix input a directory of structure set images (one image per file) \-\-input\-ss\-img input a structure set image file \-\-input\-ss\-list input a structure set list file containing names and colors \-\-interpolation interpolation to use when resampling, either "nn" for nearest neighbors or "linear" for tri\-linear, default is linear \-\-metadata patient metadata (you may use this option multiple times), option written as "XXXX,YYYY=string" \-\-modality modality metadata: such as {CT, MR, PT}, default is CT \-\-origin location of first image voxel in mm "x y z" \-\-output\-colormap create a colormap file that can be used with 3d slicer \-\-output\-cxt output a cxt\-format structure set file \-\-output\-dicom create a directory containing dicom and dicom\-rt files \-\-output\-dij create a dij matrix file \-\-output\-dose\-img create a dose image volume \-\-output\-img output image; can be mha, mhd, nii, nrrd, or other format supported by ITK \-\-output\-labelmap create a structure set image with each voxel labeled as a single structure \-\-output\-pointset create a pointset file that can be used with 3d slicer \-\-output\-prefix create a directory with a separate image for each structure \-\-output\-prefix\-fcsv create a directory with a separate fcsv pointset file for each structure \-\-output\-ss\-img create a structure set image which allows overlapping structures \-\-output\-ss\-list create a structure set list file containing names and colors \-\-output\-type type of output image, one of {uchar, short, float, ...} \-\-output\-vf create a vector field from the input xf \-\-output\-xio create a directory containing xio\-format files \-\-patient\-id patient id metadata: string \-\-patient\-name patient name metadata: string \-\-patient\-pos patient position metadata: one of {hfs,hfp,ffs,ffp} \-\-prefix\-format file format of rasterized structures, either "mha" or "nrrd" \-\-prune\-empty delete empty structures from output \-\-referenced\-ct dicom directory used to set UIDs and metadata \-\-series\-description series description metadata: string \-\-simplify\-perc delete percent of the vertices from output polylines \-\-spacing voxel spacing in mm "x [y z]" \-\-version display the program version \-\-xf input transform used to warp image(s) \-\-xor\-contours overlapping contours should be xor\(aqd instead of or\(aqd .ft P .fi .UNINDENT .UNINDENT .SS Examples .sp The first example demonstrates how to convert a DICOM volume to NRRD. The DICOM images that comprise the volume must be stored in a single directory, which for this example is called "dicom\-in\-dir". Because the \-\-output\-type option was not specified, the output type will be matched to the type of the input DICOM volume. The format of the output file (NRRD) is determined from the filename extension. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch convert \e \-\-input dicom\-in\-dir \e \-\-output\-img outfile.nrrd .ft P .fi .UNINDENT .UNINDENT .sp This example further converts the type of the image intensities to float. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch convert \e \-\-input dicom\-in\-dir \e \-\-output\-img outfile.nrrd \e \-\-output\-type float .ft P .fi .UNINDENT .UNINDENT .sp The next example shows how to resample the output image to a different geometry. The \-\-origin option sets the position of the (center of) the first voxel of the image, the \-\-dim option sets the number of voxels, and the \-\-spacing option sets the distance between voxels. The units for origin and spacing are assumed to be millimeters. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch convert \e \-\-input dicom\-in\-dir \e \-\-output\-img outfile.nrrd \e \-\-origin "\-200 \-200 \-165" \e \-\-dim "250 250 110" \e \-\-spacing "2 2 2.5" .ft P .fi .UNINDENT .UNINDENT .sp Generally speaking, it is tedious to manually specify the geometry of the output file. If you want to match the geometry of the output file with an existing file, you can do this using the \-\-fixed option. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch convert \e \-\-input dicom\-in\-dir \e \-\-output\-img outfile.nrrd \e \-\-fixed reference.nrrd .ft P .fi .UNINDENT .UNINDENT .sp This next example shows how to convert a DICOM RT structure set file into an image using the \-\-output\-ss\-img option. Because structures in DICOM RT are polylines, they are rasterized to create the image. The voxels of the output image are 32\-bit integers, where the i^th bit of each integer has value one if the voxel lies with in the corresponding structure, and value zero if the voxel lies outside the structure. The structure names are stored in separate file using the \-\-output\-ss\-list option. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch convert \e \-\-input structures.dcm \e \-\-output\-ss\-img outfile.nrrd \e \-\-output\-ss\-list outfile.txt .ft P .fi .UNINDENT .UNINDENT .sp In the previous example, the geometry of the output file wasn\(aqt specified. When the geometry of a DICOM RT structure set isn\(aqt specified, it is assumed to match the geometry of the DICOM (CT, MR, etc) image associated with the contours. If the associated DICOM image is in the same directory as the structure set file, it will be found automatically. Otherwise, we have to tell plastimatch where it is located with the \-\-referenced\-ct option. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch convert \e \-\-input structures.dcm \e \-\-output\-ss\-img outfile.nrrd \e \-\-output\-ss\-list outfile.txt \e \-\-referenced\-ct ../image\-directory .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH DICE .sp The plastimatch \fIdice\fP compares binary label images using Dice coefficient, Hausdorff distance, or contour mean distance. The input images are treated as boolean, where non\-zero values mean that voxel is inside of the structure and zero values mean that the voxel is outside of the structure. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch dice [options] reference\-image test\-image Options: \-\-all Compute Dice, Hausdorff, and contour mean distance (equivalent to \-\-dice \-\-hausdorff \-\-contour\-mean) \-\-contour\-mean Compute contour mean distance \-\-dice Compute Dice coefficient (default) \-\-hausdorff Compute Hausdorff distance and average Hausdorff distance .ft P .fi .UNINDENT .UNINDENT .SS Example .sp The following command computes all three statistics for mask1.mha and mask2.mha: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch dice \-\-all mask1.mha mask2.mha .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH DIFF .sp The plastimatch \fIdiff\fP command subtracts one image from another, and saves the output as a new image. The two input files must have the same geometry (origin, dimensions, and voxel spacing). .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch diff image_in_1 image_in_2 image_out .ft P .fi .UNINDENT .UNINDENT .SS Example .sp The following command computes file1.nrrd minus file2.nrrd, and saves the result in outfile.nrrd: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch diff file1.nrrd file2.nrrd outfile.nrrd .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH DMAP .sp The plastimatch \fIdmap\fP command takes a binary label image as input, and creates a distance map image as the output. The output image has the same image geometry (origin, dimensions, voxel spacing) as the input image. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch dmap [options] Required: \-\-input input directory or filename \-\-output output image Optional: \-\-algorithm a string that specifies the algorithm used for distance map calculation, either "maurer", "danielsson", or "itk\-danielsson" (default is "danielsson") \-\-inside\-positive voxels inside the structure should be positive (by default they are negative) \-\-maximum\-distance voxels with distances greater than this number will have the distance truncated to this number \-\-squared\-distance return the squared distance instead of distance .ft P .fi .UNINDENT .UNINDENT .SS Example .sp The following command computes a distance map file dmap.nrrd from a binary labelmap image label.nrrd.: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch dmap \-\-input label.nrrd \-\-output dmap.nrrd .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH DRR .sp This command is under construction. .SH PLASTIMATCH DVH .sp The \fIdvh\fP command creates a dose value histogram (DVH) from a given dose image and structure set image. The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch dvh [options] \-\-input\-ss\-img file \-\-input\-ss\-list file \-\-input\-dose file \-\-output\-csv file \-\-input\-units {gy,cgy} \-\-cumulative \-\-num\-bins \-\-bin\-width .ft P .fi .UNINDENT .UNINDENT .sp The required inputs are \-\-input\-dose, \-\-input\-ss\-img, \-\-input\-ss\-list, and \-\-output\-csv. The units of the input dose must be either Gy or cGy. DVH bin values will be generated for all structures found in the structure set files. The output will be generated as an ASCII csv\-format spreadsheet file, readable by OpenOffice.org or Microsoft Excel. .sp The default is a differential (standard) histogram, rather than the cumulative DVH which is most common in radiotherapy. To create a cumulative DVH, use the \-\-cumulative option. .sp The default is to create 256 bins, each with a width of 1 Gy. You can adjust these values using the \-\-num\-bins and \-\-bin\-width option. .SS Example .sp To generate a DVH for a single 2 Gy fraction, we might choose 250 bins each of width 1 cGy. If the input dose is already specified in cGy, you would use the following command: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch dvh \e \-\-input\-ss\-img structures.mha \e \-\-input\-ss\-list structures.txt \e \-\-input\-dose dose.mha \e \-\-output\-csv dvh.csv \e \-\-input\-units cgy \e \-\-num\-bins 250 \e \-\-bin\-width 1 .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH FILL .sp The \fIfill\fP command is used to fill an image region with a constant intensity. The region filled is defined by a mask file, with voxels with non\-zero intensity in the mask image being filled. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch fill [options] Options: \-\-input input directory or filename; can be an image or dicom directory \-\-mask input filename for mask image \-\-mask\-value value to set for pixels within mask (for "fill"), or outside of mask (for "mask" \-\-output output filename (for image file) or directory (for dicom) \-\-output\-format arg should be "dicom" for dicom output \-\-output\-type type of output image, one of {uchar, short, float, ...} .ft P .fi .UNINDENT .UNINDENT .SS Examples .sp Suppose we have a file prostate.nrrd which is zero outside of the prostate, and non\-zero inside of the prostate. We can fill the prostate with an intensity of 1000, while leaving non\-prostate areas with their original intensity, using the following command. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch fill \e \-\-input infile.nrrd \e \-\-output outfile.nrrd \e \-\-mask\-value 1000 \e \-\-mask prostate.nrrd .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH FILTER .sp The \fIfilter\fP command applies a filter to an input image, and creates a filtered image as its output. The filter can be either built\-in, or custom. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch filter [options] input_image Options: \-\-gabor\-k\-fib choose gabor direction at index i within fibonacci spiral of length n; specified as "i n" where i and n are integers, and i is between 0 and n\-1 \-\-gauss\-width the width (in mm) of a uniform Gaussian smoothing filter \-\-kernel kernel image filename \-\-output output image filename \-\-output\-kernel output kernel filename \-\-pattern filter type: {gabor, gauss, kernel}, default is gauss .ft P .fi .UNINDENT .UNINDENT .sp The built\-in filters supported are "gabor" and "gauss". For a Gaussian, the width of the Gaussian can be controlled using the \-\-gauss\-width option. The Gabor filter is currently limited to automatic selection of filter directions, which are spaced quasi\-uniformly on the unit sphere. Custom filters are specified by supplying a kernel file, which is convolved with the image. .SS Example .sp The following command will generate a filtered image from the first gabor filter within a bank of 10 filters.: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch filter \-\-pattern gabor Testing/rect\-1.mha \e \-\-gabor\-k\-fib "0 5" \-\-output g\-05.mha .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH GAMMA .sp The \fIgamma\fP command compares two images using the so\-called gamma criterion. The gamma criterion specifies that images are similar at a givel location within a reference image if there exists a voxel with similar intensity nearby in the comparison image. Both local gamma and global gamma can be performed using this command. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch gamma [options] image_1 image_2 Options: \-\-analysis\-threshold Analysis threshold for dose in float (for example, input 0.1 to apply 10% of the reference dose). The final threshold dose (Gy) is calculated by multiplying this value and a given reference dose (or maximum dose if not given). (default is 0.1) \-\-compute\-full\-region With this option, full gamma map will be generated over the entire image region (even for low\-dose region). It is recommended not to use this option to speed up the computation. It has no effect on gamma pass\-rate. \-\-dose\-tolerance The scaling coefficient for dose difference. (e.g. put 0.02 if you want to apply 2% dose difference criterion) (default is 0.03) \-\-dta\-tolerance The distance\-to\-agreement (DTA) scaling coefficient in mm (default is 3) \-\-gamma\-max The maximum value of gamma to compute; smaller values run faster (default is 2.0) \-\-inherent\-resample Spacing value in [mm]. The reference image itself will be resampled by this value (Note: resampling compare\-image to ref\-image is inherent already). If arg < 0, this option is disabled. (default is \-1.0) \-\-interp\-search With this option, smart interpolation search will be used in points near the reference point. This will eliminate the needs of fine resampling. However, it will take longer time to compute. \-\-local\-gamma With this option, dose difference is calculated based on local dose difference. Otherwise, a given reference dose will be used, which is called global\-gamma. \-\-output Output image \-\-output\-failmap File path for binary gamma evaluation result. \-\-output\-text Text file path for gamma evaluation result. \-\-reference\-dose The prescription dose (Gy) used to compute dose tolerance; if not specified, then maximum dose in reference volume is used \-\-resample\-nn With this option, Nearest Neighbor will be used instead of linear interpolation in resampling the compare\-image to the reference image. Not recommended for better results. .ft P .fi .UNINDENT .UNINDENT .SS Example .sp A gamma image is produced from two input images using the default parameters. This will be a global gamma, using maximum intensity of the reference image as the gamma normalization value.: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch gamma \-\-output gamma.mha \e reference\-image.mha compare\-image.mha .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH HEADER .sp The \fIheader\fP command is used to display simple properties about the volume, such as the image data type and image geometry. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch header [options] input_file [input_file ...] Options: \-h, \-\-help display this help message \-\-version display the program version .ft P .fi .UNINDENT .UNINDENT .SS Example .sp We can display the geometry of any supported file type, such as mha, nrrd, or dicom. We can run the command as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ plastimatch header input.mha Type = float Planes = 1 Origin = \-180 \-180 \-167.75 Size = 512 512 120 Spacing = 0.7031 0.7031 2.5 Direction = 1 0 0 0 1 0 0 0 1 .ft P .fi .UNINDENT .UNINDENT .sp From the header information, we see that the image has 120 slices, and each slice is 512 x 512 pixels. The slice spacing is 2.5 mm, and the in\-plane pixel spacing is 0.7031 mm. .SH PLASTIMATCH JACOBIAN .sp The \fIjacobian\fP command computes the Jacobian determinant of a vector field. Either a Jacobian determinant image, or its summary statistics, can be computed. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch jacobian [options] Options: \-\-input input directory or filename of image \-\-output\-img output image; can be mha, mhd, nii, nrrd, or other format supported by ITK \-\-output\-stats output stats file; .txt format .ft P .fi .UNINDENT .UNINDENT .SS Example .sp To create a Jacobian determinant image from a vector field file vf.mha, run the following: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch jacobian \e \-\-input vf.mha \-\-output\-img vf_jac.mha .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH MABS .sp The \fImabs\fP command performs a multi\-atlas based segmentation (MABS) operation. The command can operate in one of several training mode, or in segmentation mode. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch mabs [options] command_file Options: \-\-atlas\-selection run just atlas selection \-\-convert pre\-process atlas \-\-output output (non\-dicom) directory when doing a segmentation \-\-output\-dicom output dicom directory when doing a segmentation \-\-pre\-align pre\-process atlas \-\-segment use mabs to segment the specified image or directory \-\-train perform full training to find the best registration and segmentation parameters \-\-train\-atlas\-selection run just train atlas selection \-\-train\-registration perform limited training to find the best registration parameters only .ft P .fi .UNINDENT .UNINDENT .sp Prior to running the mabs command, you must create a configuration file, and you must arrange your training data into the proper directory format. For a complete description of the command file syntax and usage examples, please refer to the mabs_guidebook and the segmentation_command_file_reference\&. .SH PLASTIMATCH MASK .sp The \fImask\fP command is used to fill an image region with a constant intensity. The region filled is defined by a mask file, with voxels with zero intensity in the mask image being filled. Thus, it is the inverse of the \fIfill\fP command. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch mask [options] Options: \-\-input input directory or filename; can be an image or dicom directory \-\-mask input filename for mask image \-\-mask\-value value to set for pixels within mask (for "fill"), or outside of mask (for "mask" \-\-output output filename (for image file) or directory (for dicom) \-\-output\-format arg should be "dicom" for dicom output \-\-output\-type type of output image, one of {uchar, short, float, ...} .ft P .fi .UNINDENT .UNINDENT .SS Examples .sp Suppose we have a file called patient.nrrd, which is zero outside of the patient, and non\-zero inside the patient. If we want to fill in the area outside of the patient with value \-1000, we use the following command. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch mask \e \-\-input infile.nrrd \e \-\-output outfile.nrrd \e \-\-negate\-mask \e \-\-mask\-value \-1000 \e \-\-mask patient.nrrd .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH ML-CONVERT .sp To be written. .SH PLASTIMATCH PROBE .sp The plastimatch \fIprobe\fP command is used to examine the image intensity or vector field displacement at one or more positions within a volume. The probe positions can be specified in world coordinates (in mm), using the \-\-location option, or as image indices using the \-\-index option. The locations or indices are linearly interpolated if they lie between voxels. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch probe [options] file Options: \-i, \-\-index List of voxel indices, such as "i j k;i j k;..." \-l, \-\-location List of spatial locations, such as "i j k;i j k;..." .ft P .fi .UNINDENT .UNINDENT .sp The command will output one line for each probe requested. Each output line includes the following fields.: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C PROBE# The probe number, starting with zero INDEX The (fractional) position of the probe as a voxel index LOC The position of the probe in world coordinates VALUE The intensity (for volumes) or displacement (for vector fields) .ft P .fi .UNINDENT .UNINDENT .SS Example .sp We use the index option to see an image intensity at coordinate (2,3,4), and the location option to see image intensities at two different locations: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch probe \e \-\-index "2 3 4" \e \-\-location "0 0 0; 0.5 0.5 0.5" \e infile.nrrd .ft P .fi .UNINDENT .UNINDENT .sp The output will include three probe results. Each probe shows the probe index, voxel index, voxel location, and intensity. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C 0: 2.00, 3.00, 4.00; \-22.37, \-21.05, \-19.74; \-998.725891 1: 19.00, 19.00, 19.00; 0.00, 0.00, 0.00; \-0.000197 2: 19.38, 19.38, 19.38; 0.50, 0.50, 0.50; \-9.793450 .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH REGISTER .sp The plastimatch \fIregister\fP command is used to peform linear or deformable registration of two images. The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch register command_file .ft P .fi .UNINDENT .UNINDENT .sp The command file is an ordinary text file, which contains a single global section and one or more stages sections. The global section begins with a line containing only the string "[GLOBAL]", and each stage begins with a line containing the string "[STAGE]". .sp The global section is used to set input files, output files, and global parameters, while the each stage section defines a sequential stage of processing. For a complete description of the command file syntax, please refer to the registration_command_file_reference\&. .SS Examples .sp If you want to register image_2.mha to match image_1.mha using B\-spline registration, create a command file like this: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C # command_file.txt [GLOBAL] fixed=image_1.mha moving=image_2.mha img_out=warped_2.mha xform_out=bspline_coefficients.txt [STAGE] xform=bspline impl=plastimatch threading=openmp max_its=30 regularization_lambda=0.005 grid_spac=100 100 100 res=4 4 2 .ft P .fi .UNINDENT .UNINDENT .sp Then, run the registration like this: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch register command_file.txt .ft P .fi .UNINDENT .UNINDENT .sp The above example only performs a single registration stage. If you want to do multi\-stage registration, use multiple [STAGE] sections. Like this: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C # command_file.txt [GLOBAL] fixed=image_1.mha moving=image_2.mha img_out=warped_2.mha xform_out=bspline_coefficients.txt [STAGE] xform=bspline impl=plastimatch threading=openmp max_its=30 regularization_lambda=0.005 grid_spac=100 100 100 res=4 4 2 [STAGE] max_its=30 grid_spac=80 80 80 res=2 2 1 [STAGE] max_its=30 grid_spac=60 60 60 res=1 1 1 .ft P .fi .UNINDENT .UNINDENT .sp For more examples, please refer to the image_registration_guidebook\&. .SH PLASTIMATCH RESAMPLE .sp The \fIresample\fP command can be used to change the geometry of an image. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch resample [options] Options: \-\-default\-value value to set for pixels with unknown value, default is 0 \-\-dim size of output image in voxels "x [y z]" \-\-direction\-cosines oriention of x, y, and z axes; Specify either preset value, {identity,rotated\-{1,2,3},sheared}, or 9 digit matrix string "a b c d e f g h i" \-F, \-\-fixed fixed image (match output size to this image) \-h, \-\-help display this help message \-\-input input directory or filename; can be an image or vector field \-\-interpolation interpolation type, either "nn" or "linear", default is linear \-\-origin location of first image voxel in mm "x y z" \-\-output output image or vector field \-\-output\-type type of output image, one of {uchar, short, float, ...} \-\-spacing voxel spacing in mm "x [y z]" \-\-subsample bin voxels together at integer subsampling rate "x [y z]" \-\-version display the program version .ft P .fi .UNINDENT .UNINDENT .SS Example .sp We can use the \-\-subsample option to bin an integer number of voxels to a single voxel. So for example, if we want to bin a cube of size 3x3x1 voxels to a single voxel, we would do the following. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch resample \e \-\-input infile.nrrd \e \-\-output outfile.nrrd \e \-\-subsample "3 3 1" .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH SCALE .sp The \fIscale\fP command scales an image or vector field by multiplying each voxel by a constant value. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch scale [options] input_file Options: \-\-output filename for output image or vector field \-\-weight scale the input image or vector field by this value (float) .ft P .fi .UNINDENT .UNINDENT .SS Example .sp This command creates an output file with image intensity (or voxel length) twice as large as the input values: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch scale \-\-output output.mha \-\-weight 2.0 input.mha .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH SEGMENT .sp The \fIsegment\fP command does simple threshold\-based semgentation. The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch segment [options] Options: \-h, \-\-help Display this help message \-\-input Input image filename (required) \-\-lower\-threshold Lower threshold (include voxels above this value) \-\-output\-dicom Output dicom directory (for RTSTRUCT) \-\-output\-img Output image filename \-\-upper\-threshold Upper threshold (include voxels below this value) .ft P .fi .UNINDENT .UNINDENT .SS Example .sp Suppose we have a CT image of a water tank, and we wish to create an image which has ones where there is water, and zeros where there is air. Then we could do this: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch segment \e \-\-input water.mha \e \-\-output\-img water\-label.mha \e \-\-lower\-threshold \-500 .ft P .fi .UNINDENT .UNINDENT .sp If we wanted instead to create a DICOM\-RT structure set, we should specify a DICOM image as the input. This will allow plastimatch to create the DICOM\-RT with the correct patient name, patient id, and UIDs. The output file will be called "ss.dcm". .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch segment \e \-\-input water_dicom \e \-\-output\-dicom water_dicom \e \-\-lower\-threshold \-500 .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH STATS .sp The plastimatch stats command displays a few basic statistics about the image onto the screen. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch stats file [file ...] .ft P .fi .UNINDENT .UNINDENT .sp The input files can be either 2D projection images, 3D volumes, or 3D vector fields. .SS Example .sp The following command displays statistics for the 3D volume synth_1.mha. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ plastimatch stats synth_1.mha MIN \-999.915161 AVE \-878.686035 MAX 0.000000 NUM 54872 .ft P .fi .UNINDENT .UNINDENT .sp The reported statistics are interpreted as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C MIN Minimum intensity in image AVE Average intensity in image MAX Maximum intensity in image NUM Number of voxels in image .ft P .fi .UNINDENT .UNINDENT .SS Example .sp The following command displays statistics for the 3D vector field vf.mha: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ plastimatch stats vf.mha Min: 0.000 \-0.119 \-0.119 Mean: 13.200 0.593 0.593 Max: 21.250 1.488 1.488 Mean abs: 13.200 0.594 0.594 Energy: MINDIL \-6.79 MAXDIL 0.166 MAXSTRAIN 41.576 TOTSTRAIN 70849 Min dilation at: (29 19 19) Jacobian: MINJAC \-6.32835 MAXJAC 1.15443 MINABSJAC 0.360538 Min abs jacobian at: (28 36 36) Second derivatives: MINSECDER 0 MAXSECDER 388.82 TOTSECDER 669219 INTSECDER 1.524e+06 Max second derivative: (29 36 36) .ft P .fi .UNINDENT .UNINDENT .sp The rows corresponding to "Min, Mean, Max, and Mean abs" each have three numbers, which correspond to the x, y, and z coordinates. Therefore, they compute these statistics for each vector direction separately. .sp The remaining statistics are described as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C MINDIL Minimum dilation MAXDIL Maximum dilation MAXSTRAIN Maximum strain TOTSTRAIN Total strain MINJAC Minimum Jacobian MAXJAC Maximum Jacobian MINABSJAC Minimum absolute Jacobian MINSECDER Minimum second derivative MAXSECDER Maximum second derivative TOTSECDER Total second derivative INTSECDER Integral second derivative .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH SYNTH .sp The \fIsynth\fP command creates a synthetic image. The following kinds of images can be created, by specifying the appropriate \-\-pattern option. Each of these patterns come with a synthetic structure set and synthetic dose which can be used for testing. .INDENT 0.0 .IP \(bu 2 donut \-\- a donut shaped structure .IP \(bu 2 gauss \-\- a Gaussian blur .IP \(bu 2 grid \-\- a 3D grid .IP \(bu 2 lung \-\- a synthetic lung with a tumor .IP \(bu 2 rect \-\- a uniform rectangle within a uniform background .IP \(bu 2 sphere \-\- a uniform sphere within a uniform background .IP \(bu 2 xramp \-\- an image that linearly varies intensities in the x direction .IP \(bu 2 yramp \-\- an image that linearly varies intensities in the y direction .IP \(bu 2 zramp \-\- an image that linearly varies intensities in the z direction .UNINDENT .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch synth [options] Options: \-\-background intensity of background region \-\-cylinder\-center location of cylinder center in mm "x [y z]" \-\-cylinder\-radius size of cylinder in mm "x [y z]" \-\-dicom\-with\-uids set to false to remove uids from created dicom filenames, default is true \-\-dim size of output image in voxels "x [y z]" \-\-direction\-cosines oriention of x, y, and z axes; Specify either preset value, {identity,rotated\-{1,2,3},sheared}, or 9 digit matrix string "a b c d e f g h i" \-\-donut\-center location of donut center in mm "x [y z]" \-\-donut\-radius size of donut in mm "x [y z]" \-\-donut\-rings number of donut rings (2 rings for traditional donut) \-\-dose\-center location of dose center in mm "x y z" \-\-dose\-size dimensions of dose aperture in mm "x [y z]", or locations of rectangle corners in mm "x1 x2 y1 y2 z1 z2" \-\-fixed fixed image (match output size to this image) \-\-foreground intensity of foreground region \-\-gabor\-k\-fib choose gabor direction at index i within fibonacci spiral of length n; specified as "i n" where i and n are integers, and i is between 0 and n\-1 \-\-gauss\-center location of Gaussian center in mm "x [y z]" \-\-gauss\-std width of Gaussian in mm "x [y z]" \-\-grid\-pattern grid pattern spacing in voxels "x [y z]" \-\-input input image (add synthetic pattern onto existing image) \-\-lung\-tumor\-pos position of tumor in mm "z" or "x y z" \-\-metadata patient metadata (you may use this option multiple times) \-\-noise\-mean mean intensity of gaussian noise \-\-noise\-std standard deviation of gaussian noise \-\-origin location of first image voxel in mm "x y z" \-\-output output filename \-\-output\-dicom output dicom directory \-\-output\-dose\-img filename for output dose image \-\-output\-ss\-img filename for output structure set image \-\-output\-ss\-list filename for output file containing structure names \-\-output\-type data type for output image: {uchar, short, ushort, ulong, float}, default is float \-\-patient\-id patient id metadata: string \-\-patient\-name patient name metadata: string \-\-patient\-pos patient position metadata: one of {hfs,hfp,ffs,ffp} \-\-pattern synthetic pattern to create: {cylinder, donut, dose, gabor, gauss, grid, lung, noise, rect, sphere, xramp, yramp, zramp}, default is gauss \-\-penumbra width of dose penumbra in mm \-\-rect\-size width of rectangle in mm "x [y z]", or locations of rectangle corners in mm "x1 x2 y1 y2 z1 z2" \-\-spacing voxel spacing in mm "x [y z]" \-\-sphere\-center location of sphere center in mm "x y z" \-\-sphere\-radius radius of sphere in mm "x [y z]" \-\-volume\-size size of output image in mm "x [y z]" .ft P .fi .UNINDENT .UNINDENT .SS Examples .sp Create a cubic water phantom 30 x 30 x 40 cm with zero position at the center of the water surface: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch synth \e \-\-pattern rect \e \-\-output water_tank.mha \e \-\-rect\-size "\-150 150 0 400 \-150 150" \e \-\-origin "\-245.5 245.5 \-49.5 449.5 \-149.5 149.5" \e \-\-spacing "1 1 1" \e \-\-dim "500 500 300" .ft P .fi .UNINDENT .UNINDENT .sp Create lung phantoms with two different tumor positions, and output to dicom: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch synth \e \-\-pattern lung \e \-\-output\-dicom lung_inhale \e \-\-lung\-tumor\-pos "0 0 10" plastimatch synth \e \-\-pattern lung \e \-\-output\-dicom lung_exhale \e \-\-lung\-tumor\-pos "0 0 \-10" .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH SYNTH-VF .sp The \fIsynth\-vf\fP command creates a synthetic vector field. The following kinds of vector fields can be created, by specifying the appropriate option. .INDENT 0.0 .IP \(bu 2 gauss \-\- a gaussian warp .IP \(bu 2 radial \-\- a radial expansion or contraction .IP \(bu 2 translation \-\- a uniform translation .IP \(bu 2 zero \-\- a vector field that is zero everywhere .UNINDENT .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch synth\-vf [options] Options: \-\-dim size of output image in voxels "x [y z]" \-\-direction\-cosines oriention of x, y, and z axes; Specify either preset value, {identity, rotated\-{1,2,3}, sheared}, or 9 digit matrix string "a b c d e f g h i" \-\-fixed An input image used to set the size of the output \-\-gauss\-center location of center of gaussian warp "x [y z]" \-\-gauss\-mag displacment magnitude for gaussian warp in mm "x [y z]" \-\-gauss\-std width of gaussian std in mm "x [y z]" \-\-origin location of first image voxel in mm "x y z" \-\-output output filename \-\-radial\-center location of center of radial warp "x [y z]" \-\-radial\-mag displacement magnitude for radial warp in mm "x [y z]" \-\-spacing voxel spacing in mm "x [y z]" \-\-volume\-size size of output image in mm "x [y z]" \-\-xf\-gauss gaussian warp \-\-xf\-radial radial expansion (or contraction) \-\-xf\-trans uniform translation in mm "x y z" \-\-xf\-zero Null transform .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH THRESHOLD .sp The \fIthreshold\fP command creates a binary labelmap image from an input intensity image. .sp The command line usage is given as follows: .sp Usage: plastimatch threshold [options] Options: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .TP .BI \-\-above \ value above which output has value high .TP .BI \-\-below \ value below which output has value high .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B \-h\fP,\fB \-\-help display this help message \-\-input input directory or filename \-\-output output image \-\-range a string that forms a list of threshold ranges of the .INDENT 7.0 .INDENT 3.5 form "r1\-lo,r1\-hi,r2\-lo,r2\-hi,...", such that voxels with intensities within any of the ranges ([r1\-lo,r1\-hi], [r2\-lo,r2\-hi], ...) have output value high .UNINDENT .UNINDENT .INDENT 7.0 .TP .B \-\-version display the program version .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS Example .sp The following command creates a binary label image with value 1 when input intensities are between 100 and 200, and value 0 otherwise.: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch threshold \e \-\-input input_image.nrrd \e \-\-output output_labe.nrrd \e \-\-range "100,200" .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH THUMBNAIL .sp The \fIthumbnail\fP command generates a two\-dimensional thumbnail image of an axial slice of the input volume. The output image is not required to correspond exactly to an integer slice number. The location of the output image within the slice is always centered. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch thumbnail [options] input\-file Options: \-\-input file \-\-output file \-\-thumbnail\-dim size \-\-thumbnail\-spacing size \-\-slice\-loc location .ft P .fi .UNINDENT .UNINDENT .SS Example .sp We create a two\-dimensional image with resolution 10 x 10 pixels, at axial location 0, and of size 20 x 20 mm: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch thumbnail \e \-\-input in.mha \-\-output out.mha \e \-\-thumbnail\-dim 10 \e \-\-thumbnail\-spacing 2 \e \-\-slice\-loc 0 .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH UNION .sp The \fIunion\fP command creates a binary volume which is the logical union of two input images. Voxels in the output image have value one if the voxel is non\-zero in either input image, or value zero if the voxel is zero in both input images. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch union [options] input_1 input_2 Options: \-h, \-\-help display this help message \-\-output filename for output image \-\-version display the program version .ft P .fi .UNINDENT .UNINDENT .SS Example .sp The following command creates a volume that is the union of two input images: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch union \e \-\-output itv.mha \e phase_1.mha phase_2.mha .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH WARP .sp The \fIwarp\fP command is an alias for \fIconvert\fP\&. Please refer to \fI\%plastimatch convert\fP for the list of command line parameters. .SS Examples .sp To warp an image using the B\-spline coefficients generated by the plastimatch register command (saved in the file bspline.txt), do the following: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch warp \e \-\-input infile.nrrd \e \-\-output outfile.nrrd \e \-\-xf bspline.txt .ft P .fi .UNINDENT .UNINDENT .sp In the previous example, the output file geometry was determined by the geometry information in the bspline coefficient file. You can resample to a different geometry using \-\-fixed, or \-\-origin, \-\-dim, and \-\-spacing. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch warp \e \-\-input infile.nrrd \e \-\-output outfile.nrrd \e \-\-xf bspline.txt \e \-\-fixed reference.nrrd .ft P .fi .UNINDENT .UNINDENT .sp When warping a structure set image, where the integer bits correspond to structure membership, you need to use nearest neighbor interpolation rather than linear interpolation. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch warp \e \-\-input structures\-in.nrrd \e \-\-output structures\-out.nrrd \e \-\-xf bspline.txt \e \-\-interpolation nn .ft P .fi .UNINDENT .UNINDENT .sp Sometimes, voxels located outside of the geometry of the input image will be warped into the geometry of the output image. By default, these areas are "filled in" with an intensity of zero. You can choose a different value for these areas using the \-\-default\-value option. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch warp \e \-\-input infile.nrrd \e \-\-output outfile.nrrd \e \-\-xf bspline.txt \e \-\-default\-value \-1000 .ft P .fi .UNINDENT .UNINDENT .sp In addition to images and structures, landmarks exported from 3D Slicer can also be warped. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch warp \e \-\-input fixed_landmarks.fcsv \e \-\-output\-pointset warped_landmarks.fcsv \e \-\-xf bspline.txt .ft P .fi .UNINDENT .UNINDENT .sp Sometimes, it may be desirable to apply a transform explicitly defined by a vector field instead of using B\-spline coefficients. To allow this, the \-\-xf option also accepts vector field volumes. For example, the previous example would become. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch warp \e \-\-input fixed_landmarks.fcsv \e \-\-output\-pointset warped_landmarks.fcsv \e \-\-xf vf.mha .ft P .fi .UNINDENT .UNINDENT .SH PLASTIMATCH XF-CONVERT .sp The \fIxf\-convert\fP command converts between transform types. A transform can be either a B\-spline transform, or a vector field. There are two different kinds of B\-spline transform formats: the plastimatch native format, and the ITK format. In addition to converting the transform type, the \fIxf\-convert\fP command can also change the grid\-spacing of B\-spline transforms. .sp The command line usage is given as follows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Usage: plastimatch xf\-convert [options] Options: \-\-dim Size of output image in voxels "x [y z]" \-\-grid\-spacing B\-spline grid spacing in mm "x [y z]" \-\-input Input xform filename (required) \-\-nobulk Omit bulk transform for itk_bspline \-\-origin Location of first image voxel in mm "x y z" \-\-output Output xform filename (required) \-\-output\-type Type of xform to create (required), choose from {bspline, itk_bspline, vf} \-\-spacing Voxel spacing in mm "x [y z]" .ft P .fi .UNINDENT .UNINDENT .SS Example .sp We want to convert a B\-spline transform into a vector field. If the B\-spline transform is in native\-format, the vector field geometry is defined by the values found in the transform header.: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch xf\-convert \e \-\-input bspline.txt \e \-\-output vf.mha \e \-\-output\-type vf .ft P .fi .UNINDENT .UNINDENT .sp Likewise, if we want to convert a vector field into a set of B\-spline coefficients with a control\-point spacing of 30 mm in each direction. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C plastimatch xf\-convert \e \-\-input vf.mha \e \-\-output bspline.txt \e \-\-output\-type bspline \e \-\-grid\-spacing 30 .ft P .fi .UNINDENT .UNINDENT .SH AUTHOR Plastimatch is a collaborative project. For additional documentation, please visit http://plastimatch.org. For questions, comments, and bug reports, please visit http://groups.google.com/group/plastimatch. .SH COPYRIGHT Plastimatch development team (C) 2010-2015. You are free to use, modify, and distribute plastimatch according to a BSD-style license. Please see LICENSE.TXT for details. .\" Generated by docutils manpage writer. . plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/000077500000000000000000000000001321604176500224505ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/000077500000000000000000000000001321604176500263315ustar00rootroot00000000000000DiffeomorphicDemons/000077500000000000000000000000001321604176500321765ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insightitkDiffeomorphicDemonsRegistrationWithMaskFilter.h000066400000000000000000000242021321604176500442140ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/DiffeomorphicDemons/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkDiffeomorphicDemonsRegistrationWithMaskFilter.h,v $ Language: C++ Date: $Date: 2008-07-05 00:07:02 $ Version: $Revision: 1.1 $ 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. =========================================================================*/ #ifndef __itkDiffeomorphicDemonsRegistrationWithMaskFilter_h #define __itkDiffeomorphicDemonsRegistrationWithMaskFilter_h #include "itkPDEDeformableRegistrationWithMaskFilter.h" #include "itkESMDemonsRegistrationWithMaskFunction.h" #if ITK_VERSION_MAJOR >= 4 #include "itkMultiplyImageFilter.h" #include "itkExponentialDisplacementFieldImageFilter.h" #else #include "itkMultiplyByConstantImageFilter.h" #include "itkExponentialDeformationFieldImageFilter.h" #endif #include "itkWarpVectorImageFilter.h" #include "itkVectorLinearInterpolateNearestNeighborExtrapolateImageFunction.h" #include "itkAddImageFilter.h" #include "itkSpatialObject.h" namespace itk { /** * \class DiffeomorphicDemonsRegistrationWithMaskFilter * \brief Deformably register two images using a diffeomorphic demons algorithm. * * This class was contributed by Tom Vercauteren, INRIA & Mauna Kea * Technologies, based on a variation of the DemonsRegistrationFilter. The * basic modification is to use diffeomorphism exponentials. * * See T. Vercauteren, X. Pennec, A. Perchant and N. Ayache, "Non-parametric * Diffeomorphic Image Registration with the Demons Algorithm", * Proc. of MICCAI 2007. * * DiffeomorphicDemonsRegistrationWithMaskFilter implements the demons deformable algorithm that * register two images by computing the deformation field which will map a * moving image onto a fixed image. * * A deformation field is represented as a image whose pixel type is some * vector type with at least N elements, where N is the dimension of * the fixed image. The vector type must support element access via operator * []. It is assumed that the vector elements behave like floating point * scalars. * * This class is templated over the fixed image type, moving image type * and the deformation field type. * * The input fixed and moving images are set via methods SetFixedImage and * SetMovingImage respectively. An initial deformation field maybe set via * SetInitialDeformationField or SetInput. If no initial field is set, * a zero field is used as the initial condition. * * The output deformation field can be obtained via methods GetOutput * or GetDeformationField. * * This class make use of the finite difference solver hierarchy. Update * for each iteration is computed in DemonsRegistrationFunction. * * \author Tom Vercauteren, INRIA & Mauna Kea Technologies * * \warning This filter assumes that the fixed image type, moving image type * and deformation field type all have the same number of dimensions. * * This implementation was taken from the Insight Journal paper: * http://hdl.handle.net/1926/510 * * \sa DemonsRegistrationFilter * \sa DemonsRegistrationFunction * \ingroup DeformableImageRegistration MultiThreaded */ template class ITK_EXPORT DiffeomorphicDemonsRegistrationWithMaskFilter : public PDEDeformableRegistrationWithMaskFilter { public: /** Standard class typedefs. */ typedef DiffeomorphicDemonsRegistrationWithMaskFilter Self; typedef PDEDeformableRegistrationWithMaskFilter< TFixedImage, TMovingImage, TDeformationField> Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro( DiffeomorphicDemonsRegistrationWithMaskFilter, PDEDeformableRegistrationWithMaskFilter ); /** FixedImage image type. */ typedef typename Superclass::FixedImageType FixedImageType; typedef typename Superclass::FixedImagePointer FixedImagePointer; /** MovingImage image type. */ typedef typename Superclass::MovingImageType MovingImageType; typedef typename Superclass::MovingImagePointer MovingImagePointer; /** Deformation field type. */ typedef typename Superclass::DeformationFieldType DeformationFieldType; typedef typename Superclass::DeformationFieldPointer DeformationFieldPointer; /** FiniteDifferenceFunction type. */ typedef typename Superclass::FiniteDifferenceFunctionType FiniteDifferenceFunctionType; #if ITK_VERSION_MAJOR >= 4 typedef ExponentialDisplacementFieldImageFilter< DeformationFieldType, DeformationFieldType > FieldExponentiatorType; #else typedef ExponentialDeformationFieldImageFilter< DeformationFieldType, DeformationFieldType > FieldExponentiatorType; #endif /** Take timestep type from the FiniteDifferenceFunction. */ typedef typename FiniteDifferenceFunctionType::TimeStepType TimeStepType; /** DemonsRegistrationFilterFunction type. */ typedef ESMDemonsRegistrationWithMaskFunction< FixedImageType, MovingImageType, DeformationFieldType> DemonsRegistrationFunctionType; typedef typename DemonsRegistrationFunctionType::GradientType GradientType; /** Inherit some enums from the superclass. */ itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension); typedef itk::SpatialObject MaskType; /** Get the metric value. The metric value is the mean square difference * in intensity between the fixed image and transforming moving image * computed over the the overlapping region between the two images. * This value is calculated for the current iteration */ virtual double GetMetric() const; virtual const double & GetRMSChange() const; virtual void SetUseGradientType( GradientType gtype ); virtual GradientType GetUseGradientType() const; /** Use a first-order approximation of the exponential. * This amounts to using an update rule of the type * s <- s o (Id + u) instead of s <- s o exp(u) */ itkSetMacro( UseFirstOrderExp, bool ); itkGetMacro( UseFirstOrderExp, bool ); itkBooleanMacro( UseFirstOrderExp ); /** Set/Get the threshold below which the absolute difference of * intensity yields a match. When the intensities match between a * moving and fixed image pixel, the update vector (for that * iteration) will be the zero vector. Default is 0.001. */ virtual void SetIntensityDifferenceThreshold(double); virtual double GetIntensityDifferenceThreshold() const; /** Set/Get the maximum length in terms of pixels of * the vectors in the update buffer. */ virtual void SetMaximumUpdateStepLength(double); virtual double GetMaximumUpdateStepLength() const; virtual void SetMovingImageMask( MaskType *mask); virtual void SetFixedImageMask(MaskType *mask); virtual const MaskType * GetMovingImageMask() const; virtual const MaskType * GetFixedImageMask() const; protected: DiffeomorphicDemonsRegistrationWithMaskFilter(); ~DiffeomorphicDemonsRegistrationWithMaskFilter() {} void PrintSelf(std::ostream & os, Indent indent) const; /** Initialize the state of filter and equation before each iteration. */ virtual void InitializeIteration(); /** This method allocates storage in m_UpdateBuffer. It is called from * FiniteDifferenceFilter::GenerateData(). */ virtual void AllocateUpdateBuffer(); private: DiffeomorphicDemonsRegistrationWithMaskFilter(const Self &); // purposely not // implemented void operator=(const Self &); // purposely not // implemented /** Downcast the DifferenceFunction using a dynamic_cast to ensure that it is of the correct type. * this method will throw an exception if the function is not of the expected type. */ DemonsRegistrationFunctionType * DownCastDifferenceFunctionType(); const DemonsRegistrationFunctionType * DownCastDifferenceFunctionType() const; #if ITK_VERSION_MAJOR >= 4 /** Apply update. */ virtual void ApplyUpdate(const TimeStepType& dt); typedef MultiplyImageFilter< DeformationFieldType,itk::Image, DeformationFieldType> MultiplyByConstantType; #else /** Apply update. */ virtual void ApplyUpdate(TimeStepType dt); typedef MultiplyByConstantImageFilter< DeformationFieldType, TimeStepType, DeformationFieldType> MultiplyByConstantType; #endif typedef WarpVectorImageFilter< DeformationFieldType, DeformationFieldType, DeformationFieldType> VectorWarperType; typedef VectorLinearInterpolateNearestNeighborExtrapolateImageFunction< DeformationFieldType, double> FieldInterpolatorType; typedef AddImageFilter< DeformationFieldType, DeformationFieldType, DeformationFieldType> AdderType; typedef typename MultiplyByConstantType::Pointer MultiplyByConstantPointer; typedef typename FieldExponentiatorType::Pointer FieldExponentiatorPointer; typedef typename VectorWarperType::Pointer VectorWarperPointer; typedef typename FieldInterpolatorType::Pointer FieldInterpolatorPointer; typedef typename AdderType::Pointer AdderPointer; typedef typename FieldInterpolatorType::OutputType FieldInterpolatorOutputType; MultiplyByConstantPointer m_Multiplier; FieldExponentiatorPointer m_Exponentiator; VectorWarperPointer m_Warper; AdderPointer m_Adder; bool m_UseFirstOrderExp; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffeomorphicDemonsRegistrationWithMaskFilter.txx" #endif #endif itkDiffeomorphicDemonsRegistrationWithMaskFilter.txx000066400000000000000000000350771321604176500446240ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/DiffeomorphicDemons/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkDiffeomorphicDemonsRegistrationWithMaskFilter.txx,v $ Language: C++ Date: $Date: 2008-11-07 19:39:44 $ Version: $Revision: 1.7 $ 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. =========================================================================*/ #ifndef __itkDiffeomorphicDemonsRegistrationWithMaskFilter_txx #define __itkDiffeomorphicDemonsRegistrationWithMaskFilter_txx #include "itkDiffeomorphicDemonsRegistrationWithMaskFilter.h" #include "itkSmoothingRecursiveGaussianImageFilter.h" namespace itk { /** * Default constructor */ template DiffeomorphicDemonsRegistrationWithMaskFilter ::DiffeomorphicDemonsRegistrationWithMaskFilter() : m_UseFirstOrderExp(false) { typename DemonsRegistrationFunctionType::Pointer drfp; drfp = DemonsRegistrationFunctionType::New(); this->SetDifferenceFunction( static_cast( drfp.GetPointer() ) ); m_Multiplier = MultiplyByConstantType::New(); m_Multiplier->InPlaceOn(); m_Exponentiator = FieldExponentiatorType::New(); m_Warper = VectorWarperType::New(); FieldInterpolatorPointer VectorInterpolator = FieldInterpolatorType::New(); m_Warper->SetInterpolator(VectorInterpolator); m_Adder = AdderType::New(); m_Adder->InPlaceOn(); } /** * Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. * It throws and exception, if it is not. */ template typename DiffeomorphicDemonsRegistrationWithMaskFilter::DemonsRegistrationFunctionType * DiffeomorphicDemonsRegistrationWithMaskFilter ::DownCastDifferenceFunctionType() { DemonsRegistrationFunctionType *drfp = dynamic_cast ( this->GetDifferenceFunction().GetPointer() ); if ( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } /** * Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. * It throws and exception, if it is not. */ template const typename DiffeomorphicDemonsRegistrationWithMaskFilter::DemonsRegistrationFunctionType * DiffeomorphicDemonsRegistrationWithMaskFilter ::DownCastDifferenceFunctionType() const { const DemonsRegistrationFunctionType *drfp = dynamic_cast ( this->GetDifferenceFunction().GetPointer() ); if ( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } /** * Set the function state values before each iteration */ template void DiffeomorphicDemonsRegistrationWithMaskFilter ::InitializeIteration() { // update variables in the equation object DemonsRegistrationFunctionType *f = this->DownCastDifferenceFunctionType(); #if ITK_VERSION_MAJOR>=4 f->SetDisplacementField( this->GetDeformationField() ); #else f->SetDeformationField( this->GetDeformationField() ); #endif // call the superclass implementation ( initializes f ) Superclass::InitializeIteration(); } /* * Get the metric value from the difference function */ template double DiffeomorphicDemonsRegistrationWithMaskFilter ::GetMetric() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetMetric(); } /** * Get Intensity Difference Threshold */ template double DiffeomorphicDemonsRegistrationWithMaskFilter ::GetIntensityDifferenceThreshold() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetIntensityDifferenceThreshold(); } /** * Set Intensity Difference Threshold */ template void DiffeomorphicDemonsRegistrationWithMaskFilter ::SetIntensityDifferenceThreshold(double threshold) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetIntensityDifferenceThreshold(threshold); } /** * Get Maximum Update Step Length */ template double DiffeomorphicDemonsRegistrationWithMaskFilter ::GetMaximumUpdateStepLength() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetMaximumUpdateStepLength(); } /** * Set Maximum Update Step Length */ template void DiffeomorphicDemonsRegistrationWithMaskFilter ::SetMaximumUpdateStepLength(double threshold) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetMaximumUpdateStepLength(threshold); } /** * Get the metric value from the difference function */ template const double & DiffeomorphicDemonsRegistrationWithMaskFilter ::GetRMSChange() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetRMSChange(); } /** * */ template typename DiffeomorphicDemonsRegistrationWithMaskFilter ::GradientType DiffeomorphicDemonsRegistrationWithMaskFilter ::GetUseGradientType() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetUseGradientType(); } /** * */ template void DiffeomorphicDemonsRegistrationWithMaskFilter ::SetUseGradientType(GradientType gtype) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetUseGradientType(gtype); } template const typename DiffeomorphicDemonsRegistrationWithMaskFilter::MaskType * DiffeomorphicDemonsRegistrationWithMaskFilter ::GetMovingImageMask() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetMovingImageMask(); } template const typename DiffeomorphicDemonsRegistrationWithMaskFilter::MaskType * DiffeomorphicDemonsRegistrationWithMaskFilter ::GetFixedImageMask() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetFixedImageMask(); } /** * */ template void DiffeomorphicDemonsRegistrationWithMaskFilter ::SetMovingImageMask(MaskType *mask) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetMovingImageMask(mask); } /** * */ template void DiffeomorphicDemonsRegistrationWithMaskFilter ::SetFixedImageMask(MaskType *mask) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetFixedImageMask(mask); } /** * */ template void DiffeomorphicDemonsRegistrationWithMaskFilter ::AllocateUpdateBuffer() { // The update buffer looks just like the output. DeformationFieldPointer output = this->GetOutput(); DeformationFieldPointer upbuf = this->GetUpdateBuffer(); upbuf->SetLargestPossibleRegion( output->GetLargestPossibleRegion() ); upbuf->SetRequestedRegion( output->GetRequestedRegion() ); upbuf->SetBufferedRegion( output->GetBufferedRegion() ); upbuf->SetOrigin( output->GetOrigin() ); upbuf->SetSpacing( output->GetSpacing() ); upbuf->SetDirection( output->GetDirection() ); upbuf->Allocate(); } /** * Get the metric value from the difference function */ #if ITK_VERSION_MAJOR >= 4 template void DiffeomorphicDemonsRegistrationWithMaskFilter ::ApplyUpdate(const TimeStepType& dt) #else template void DiffeomorphicDemonsRegistrationWithMaskFilter ::ApplyUpdate(TimeStepType dt) #endif { // If we smooth the update buffer before applying it, then the are // approximating a viscuous problem as opposed to an elastic problem if ( this->GetSmoothUpdateField() ) { this->SmoothUpdateField(); } // Use time step if necessary. In many cases // the time step is one so this will be skipped if ( fabs(dt - 1.0) > 1.0e-4 ) { itkDebugMacro( "Using timestep: " << dt ); m_Multiplier->SetConstant( dt ); m_Multiplier->SetInput( this->GetUpdateBuffer() ); m_Multiplier->GraftOutput( this->GetUpdateBuffer() ); // in place update m_Multiplier->Update(); // graft output back to this->GetUpdateBuffer() this->GetUpdateBuffer()->Graft( m_Multiplier->GetOutput() ); } if ( this->m_UseFirstOrderExp ) { // use s <- s o (Id +u) // skip exponential and compose the vector fields m_Warper->SetOutputOrigin( this->GetUpdateBuffer()->GetOrigin() ); m_Warper->SetOutputSpacing( this->GetUpdateBuffer()->GetSpacing() ); m_Warper->SetOutputDirection( this->GetUpdateBuffer()->GetDirection() ); m_Warper->SetInput( this->GetOutput() ); #if ITK_VERSION_MAJOR>=4 m_Warper->SetDisplacementField( this->GetUpdateBuffer() ); #else m_Warper->SetDeformationField( this->GetUpdateBuffer() ); #endif m_Adder->SetInput1( m_Warper->GetOutput() ); m_Adder->SetInput2( this->GetUpdateBuffer() ); m_Adder->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); } else { // use s <- s o exp(u) // compute the exponential m_Exponentiator->SetInput( this->GetUpdateBuffer() ); const double imposedMaxUpStep = this->GetMaximumUpdateStepLength(); if ( imposedMaxUpStep > 0.0 ) { // max(norm(Phi))/2^N <= 0.25*pixelspacing const double numiterfloat = 2.0 + vcl_log(imposedMaxUpStep) / vnl_math::ln2; unsigned int numiter = 0; if ( numiterfloat > 0.0 ) { numiter = static_cast( vcl_ceil(numiterfloat) ); } m_Exponentiator->AutomaticNumberOfIterationsOff(); m_Exponentiator->SetMaximumNumberOfIterations( numiter ); } else { m_Exponentiator->AutomaticNumberOfIterationsOn(); // just set a high value so that automatic number of step // is not thresholded m_Exponentiator->SetMaximumNumberOfIterations( 2000u ); } m_Exponentiator->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); m_Exponentiator->Update(); // compose the vector fields m_Warper->SetOutputOrigin( this->GetUpdateBuffer()->GetOrigin() ); m_Warper->SetOutputSpacing( this->GetUpdateBuffer()->GetSpacing() ); m_Warper->SetOutputDirection( this->GetUpdateBuffer()->GetDirection() ); m_Warper->SetInput( this->GetOutput() ); #if ITK_VERSION_MAJOR>=4 m_Warper->SetDisplacementField( m_Exponentiator->GetOutput() ); #else m_Warper->SetDeformationField( m_Exponentiator->GetOutput() ); #endif m_Warper->Update(); m_Adder->SetInput1( m_Warper->GetOutput() ); m_Adder->SetInput2( m_Exponentiator->GetOutput() ); m_Adder->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); } // Triggers update m_Adder->Update(); // Region passing stuff this->GraftOutput( m_Adder->GetOutput() ); this->GetOutput()->Modified(); DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); this->SetRMSChange( drfp->GetRMSChange() ); /** * Smooth the deformation field */ if ( this->GetSmoothDeformationField() ) { this->SmoothDeformationField(); } } template void DiffeomorphicDemonsRegistrationWithMaskFilter ::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << "Intensity difference threshold: " << this->GetIntensityDifferenceThreshold() << std::endl; os << indent << "Use First Order exponential: " << this->m_UseFirstOrderExp << std::endl; } } // end namespace itk #endif readme.txt000066400000000000000000000001611321604176500341720ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/DiffeomorphicDemonsThis code is from an Insight Journal publication that can be downloaded here: http://hdl.handle.net/10380/3105 FastSymmetricForces/000077500000000000000000000000001321604176500322065ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insightitkFastSymmetricForcesDemonsRegistrationWithMaskFilter.h000066400000000000000000000203221321604176500454010ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/FastSymmetricForces/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: itkFastSymmetricForcesDemonsRegistrationWithMaskFilter.h Language: C++ Date: $Date$ Version: $Revision$ 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. =========================================================================*/ #ifndef __itkFastSymmetricForcesDemonsRegistrationWithMaskFilter_h #define __itkFastSymmetricForcesDemonsRegistrationWithMaskFilter_h #include "itkPDEDeformableRegistrationWithMaskFilter.h" #include "itkESMDemonsRegistrationWithMaskFunction.h" #if ITK_VERSION_MAJOR >= 4 #include "itkMultiplyImageFilter.h" #include "itkExponentialDisplacementFieldImageFilter.h" #else #include "itkMultiplyByConstantImageFilter.h" #include "itkExponentialDeformationFieldImageFilter.h" #endif #include "itkWarpVectorImageFilter.h" #include "itkVectorLinearInterpolateNearestNeighborExtrapolateImageFunction.h" #include "itkAddImageFilter.h" namespace itk { /** \class FastSymmetricForcesDemonsRegistrationWithMaskFilter * \brief Deformably register two images using a symmetric forces demons algorithm. * * This class was contributed by Tom Vercauteren, INRIA & Mauna Kea Technologies * based on a variation of the DemonsRegistrationFilter. * * FastSymmetricForcesDemonsRegistrationWithMaskFilter implements the demons deformable algorithm that * register two images by computing the deformation field which will map a * moving image onto a fixed image. * * A deformation field is represented as a image whose pixel type is some * vector type with at least N elements, where N is the dimension of * the fixed image. The vector type must support element access via operator * []. It is assumed that the vector elements behave like floating point * scalars. * * This class is templated over the fixed image type, moving image type * and the deformation field type. * * The input fixed and moving images are set via methods SetFixedImage * and SetMovingImage respectively. An initial deformation field maybe set via * SetInitialDeformationField or SetInput. If no initial field is set, * a zero field is used as the initial condition. * * The output deformation field can be obtained via methods GetOutput * or GetDeformationField. * * This class make use of the finite difference solver hierarchy. Update * for each iteration is computed in DemonsRegistrationFunction. * * \author Tom Vercauteren, INRIA & Mauna Kea Technologies * * This implementation was taken from the Insight Journal paper: * http://hdl.handle.net/1926/510 * * \warning This filter assumes that the fixed image type, moving image type * and deformation field type all have the same number of dimensions. * * \sa DemonsRegistrationFilter * \sa DemonsRegistrationFunction * \ingroup DeformableImageRegistration MultiThreaded */ template class ITK_EXPORT FastSymmetricForcesDemonsRegistrationWithMaskFilter : public PDEDeformableRegistrationWithMaskFilter< TFixedImage, TMovingImage, TDeformationField> { public: /** Standard class typedefs. */ typedef FastSymmetricForcesDemonsRegistrationWithMaskFilter Self; typedef PDEDeformableRegistrationWithMaskFilter< TFixedImage, TMovingImage,TDeformationField> Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro( FastSymmetricForcesDemonsRegistrationWithMaskFilter, PDEDeformableRegistrationWithMaskFilter ); /** FixedImage image type. */ typedef typename Superclass::FixedImageType FixedImageType; typedef typename Superclass::FixedImagePointer FixedImagePointer; /** MovingImage image type. */ typedef typename Superclass::MovingImageType MovingImageType; typedef typename Superclass::MovingImagePointer MovingImagePointer; /** Deformation field type. */ typedef typename Superclass::DeformationFieldType DeformationFieldType; typedef typename Superclass::DeformationFieldPointer DeformationFieldPointer; /** Get the metric value. The metric value is the mean square difference * in intensity between the fixed image and transforming moving image * computed over the the overlapping region between the two images. * This value is calculated for the current iteration */ virtual double GetMetric() const; virtual const double &GetRMSChange() const; /** DemonsRegistrationFilterFunction type. * * FIXME: Why is this the only permissible function ? * */ typedef ESMDemonsRegistrationWithMaskFunction< FixedImageType, MovingImageType, DeformationFieldType> DemonsRegistrationFunctionType; typedef typename DemonsRegistrationFunctionType::GradientType GradientType; virtual void SetUseGradientType( GradientType gtype ); virtual GradientType GetUseGradientType() const; /** Set/Get the threshold below which the absolute difference of * intensity yields a match. When the intensities match between a * moving and fixed image pixel, the update vector (for that * iteration) will be the zero vector. Default is 0.001. */ virtual void SetIntensityDifferenceThreshold(double); virtual double GetIntensityDifferenceThreshold() const; virtual void SetMaximumUpdateStepLength(double); virtual double GetMaximumUpdateStepLength() const; protected: FastSymmetricForcesDemonsRegistrationWithMaskFilter(); ~FastSymmetricForcesDemonsRegistrationWithMaskFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; /** Initialize the state of filter and equation before each iteration. */ virtual void InitializeIteration(); /** This method allocates storage in m_UpdateBuffer. It is called from * FiniteDifferenceFilter::GenerateData(). */ virtual void AllocateUpdateBuffer(); /** FiniteDifferenceFunction type. */ typedef typename Superclass::FiniteDifferenceFunctionType FiniteDifferenceFunctionType; /** Take timestep type from the FiniteDifferenceFunction. */ typedef typename FiniteDifferenceFunctionType::TimeStepType TimeStepType; #if ITK_VERSION_MAJOR >= 4 /** Apply update. */ virtual void ApplyUpdate(const TimeStepType& dt); typedef MultiplyImageFilter< DeformationFieldType,itk::Image, DeformationFieldType> MultiplyByConstantType; #else /** Apply update. */ virtual void ApplyUpdate(TimeStepType dt); typedef MultiplyByConstantImageFilter< DeformationFieldType, TimeStepType, DeformationFieldType> MultiplyByConstantType; #endif typedef AddImageFilter< DeformationFieldType, DeformationFieldType, DeformationFieldType> AdderType; typedef typename MultiplyByConstantType::Pointer MultiplyByConstantPointer; typedef typename AdderType::Pointer AdderPointer; private: FastSymmetricForcesDemonsRegistrationWithMaskFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented /** Downcast the DifferenceFunction using a dynamic_cast to ensure that it is of the correct type. * this method will throw an exception if the function is not of the expected type. */ DemonsRegistrationFunctionType * DownCastDifferenceFunctionType(); const DemonsRegistrationFunctionType * DownCastDifferenceFunctionType() const; MultiplyByConstantPointer m_Multiplier; AdderPointer m_Adder; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkFastSymmetricForcesDemonsRegistrationWithMaskFilter.txx" #endif #endif itkFastSymmetricForcesDemonsRegistrationWithMaskFilter.txx000066400000000000000000000233031321604176500457770ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/FastSymmetricForces/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: itkFastSymmetricForcesDemonsRegistrationWithMaskFilter.txx Language: C++ Date: $Date$ Version: $Revision$ 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. =========================================================================*/ #ifndef __itkFastSymmetricForcesDemonsRegistrationWithMaskFilter_txx #define __itkFastSymmetricForcesDemonsRegistrationWithMaskFilter_txx #include "itkFastSymmetricForcesDemonsRegistrationWithMaskFilter.h" namespace itk { /** * Default constructor */ template FastSymmetricForcesDemonsRegistrationWithMaskFilter ::FastSymmetricForcesDemonsRegistrationWithMaskFilter() { typename DemonsRegistrationFunctionType::Pointer drfp; drfp = DemonsRegistrationFunctionType::New(); this->SetDifferenceFunction( static_cast( drfp.GetPointer() ) ); m_Multiplier = MultiplyByConstantType::New(); m_Multiplier->InPlaceOn(); m_Adder = AdderType::New(); m_Adder->InPlaceOn(); } /* * Set the function state values before each iteration */ template void FastSymmetricForcesDemonsRegistrationWithMaskFilter ::InitializeIteration() { // update variables in the equation object DemonsRegistrationFunctionType *f = this->DownCastDifferenceFunctionType(); #if ITK_VERSION_MAJOR >= 4 f->SetDisplacementField( this->GetDeformationField() ); #else f->SetDeformationField( this->GetDeformationField() ); #endif // call the superclass implementation ( initializes f ) Superclass::InitializeIteration(); } /* * Get the metric value from the difference function */ template double FastSymmetricForcesDemonsRegistrationWithMaskFilter ::GetMetric() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetMetric(); } /** * Return intensity difference threshold */ template double FastSymmetricForcesDemonsRegistrationWithMaskFilter ::GetIntensityDifferenceThreshold() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetIntensityDifferenceThreshold(); } /** * Sets the intensity difference threshold */ template void FastSymmetricForcesDemonsRegistrationWithMaskFilter ::SetIntensityDifferenceThreshold(double threshold) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetIntensityDifferenceThreshold(threshold); } /** * Get the maximum update step length */ template double FastSymmetricForcesDemonsRegistrationWithMaskFilter ::GetMaximumUpdateStepLength() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetMaximumUpdateStepLength(); } /** * Set the maximum update step length */ template void FastSymmetricForcesDemonsRegistrationWithMaskFilter ::SetMaximumUpdateStepLength(double threshold) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetMaximumUpdateStepLength(threshold); } /** * Get the metric value from the difference function */ template const double & FastSymmetricForcesDemonsRegistrationWithMaskFilter ::GetRMSChange() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetRMSChange(); } /** * */ template typename FastSymmetricForcesDemonsRegistrationWithMaskFilter ::GradientType FastSymmetricForcesDemonsRegistrationWithMaskFilter ::GetUseGradientType() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetUseGradientType(); } /** * */ template void FastSymmetricForcesDemonsRegistrationWithMaskFilter ::SetUseGradientType(GradientType gtype) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetUseGradientType(gtype); } /** * Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. * It throws and exception, if it is not. */ template typename FastSymmetricForcesDemonsRegistrationWithMaskFilter::DemonsRegistrationFunctionType * FastSymmetricForcesDemonsRegistrationWithMaskFilter ::DownCastDifferenceFunctionType() { DemonsRegistrationFunctionType *drfp = dynamic_cast (this->GetDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } /** * Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. * It throws and exception, if it is not. */ template const typename FastSymmetricForcesDemonsRegistrationWithMaskFilter::DemonsRegistrationFunctionType * FastSymmetricForcesDemonsRegistrationWithMaskFilter ::DownCastDifferenceFunctionType() const { const DemonsRegistrationFunctionType *drfp = dynamic_cast (this->GetDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } template void FastSymmetricForcesDemonsRegistrationWithMaskFilter ::AllocateUpdateBuffer() { // The update buffer looks just like the output. DeformationFieldPointer output = this->GetOutput(); DeformationFieldPointer upbuf = this->GetUpdateBuffer(); upbuf->SetLargestPossibleRegion(output->GetLargestPossibleRegion()); upbuf->SetRequestedRegion(output->GetRequestedRegion()); upbuf->SetBufferedRegion(output->GetBufferedRegion()); upbuf->SetOrigin(output->GetOrigin()); upbuf->SetSpacing(output->GetSpacing()); upbuf->SetDirection(output->GetDirection()); upbuf->Allocate(); } /** * Get the metric value from the difference function */ /** * Get the metric value from the difference function */ #if ITK_VERSION_MAJOR >= 4 template void FastSymmetricForcesDemonsRegistrationWithMaskFilter ::ApplyUpdate(const TimeStepType& dt) #else template void FastSymmetricForcesDemonsRegistrationWithMaskFilter ::ApplyUpdate(TimeStepType dt) #endif { // If we smooth the update buffer before applying it, then the are // approximating a viscuous problem as opposed to an elastic problem if ( this->GetSmoothUpdateField() ) { this->SmoothUpdateField(); } // use time step if necessary if ( vcl_fabs(dt - 1.0)>1.0e-4 ) { itkDebugMacro( "Using timestep: " << dt ); m_Multiplier->SetConstant( dt ); m_Multiplier->SetInput( this->GetUpdateBuffer() ); m_Multiplier->GraftOutput( this->GetUpdateBuffer() ); // in place update m_Multiplier->Update(); // graft output back to this->GetUpdateBuffer() this->GetUpdateBuffer()->Graft( m_Multiplier->GetOutput() ); } m_Adder->SetInput1( this->GetOutput() ); m_Adder->SetInput2( this->GetUpdateBuffer() ); m_Adder->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); m_Adder->Update(); // Region passing stuff this->GraftOutput( m_Adder->GetOutput() ); DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); this->SetRMSChange( drfp->GetRMSChange() ); /* * Smooth the deformation field */ if ( this->GetSmoothDeformationField() ) { this->SmoothDeformationField(); } } template void FastSymmetricForcesDemonsRegistrationWithMaskFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << "Intensity difference threshold: " << this->GetIntensityDifferenceThreshold() << std::endl; } } // end namespace itk #endif readme.txt000066400000000000000000000002271321604176500342050ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/FastSymmetricForcesThis code is based on code, that adds mask functionality to diffeomorphic demons. This code can be downloaded here: http://hdl.handle.net/10380/3105 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/ITKCopyright.txt000077500000000000000000000047051321604176500314230ustar00rootroot00000000000000 Historical Note: The Insight Segmentation and Registration Toolkit (ITK) was initially developed under contract to the National Library of Medicine at the National Institutes of Health. ITK is partially derived from VTK and VXL, hence some code is copyrighted accordingly (see VTKCopyright.txt and VXLCopyright.txt). The copyright of most of the files in the "Utilities" subdirectory is held by third parties who allow to distribute this material under a license compatible with the one used by ITK. Please read the content of the subdirectories for specific details on those third-party licenses. You will also find details in the README.txt file under the "Copyright" subdirectory. Starting with its version ITK 3.6, The Insight Toolkit is distributed under the new and simplified BSD license approved by the Open Source Initiative (OSI) [http://www.opensource.org/licenses/bsd-license.php]. ITK Copyright Notice: Copyright (c) 1999-2003 Insight Software Consortium All rights reserved. License: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Insight Software Consortium nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons/000077500000000000000000000000001321604176500312505ustar00rootroot00000000000000copyright.txt000066400000000000000000000001641321604176500337430ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons The code that ships with the source package (the results of "make package_source" is released under a BSD licence)itkLogDomainDeformableRegistrationFilter.h000066400000000000000000000331311321604176500414460ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkLogDomainDeformableRegistrationFilter_h #define __itkLogDomainDeformableRegistrationFilter_h #include "itkDenseFiniteDifferenceImageFilter.h" #if ITK_VERSION_MAJOR >=4 #include "itkExponentialDisplacementFieldImageFilter.h" #else #include "itkExponentialDeformationFieldImageFilter.h" #endif #include "itkPDEDeformableRegistrationFunction.h" #include "itkPDEDeformableRegistrationWithMaskFilter.h" typedef enum { VELOCITYFIELD_IMAGE_CODE=0, FIXED_IMAGE_CODE=1, MOVING_IMAGE_CODE=2 } INPUT_OUTPUT_FILTER_CODES; namespace itk { /** * \class LogDomainDeformableRegistrationFilter * \brief Deformably register two images using a PDE-like algorithm * where the transformation is represented as the exponential of a velocity field. * * LogDomainDeformableRegistrationFilter is a base case for filter implementing * a PDE-like deformable algorithm that register two images by computing the * velocity field whose exponential will map a moving image onto a fixed image. * * See T. Vercauteren, X. Pennec, A. Perchant and N. Ayache, * "Symmetric Log-Domain Diffeomorphic Registration: A Demons-based Approach", * Proc. of MICCAI 2008. * * Velocity and deformation fields are represented as images whose pixel type are * some vector type with at least N elements, where N is the dimension of * the fixed image. The vector type must support element access via operator * []. It is assumed that the vector elements behave like floating point * scalars. * * This class is templated over the fixed image type, moving image type * and the velocity/deformation field type. * * The input fixed and moving images are set via methods SetFixedImage * and SetMovingImage respectively. An initial velocity field maybe set via * SetInitialVelocityField or SetInput. If no initial field is set, * a zero field is used as the initial condition. * * The output velocity field can be obtained via methods GetOutput * or GetVelocityField. * * The output deformation field can be obtained via method GetDeformationField. * * The PDE-like algorithm is run for a user defined number of iterations. * Typically the PDE-like algorithm requires period Gaussian smoothing of the * velocity field to enforce an elastic-like condition. The amount * of smoothing is governed by a set of user defined standard deviations * (one for each dimension). * * In terms of memory, this filter keeps two internal buffers: one for storing * the intermediate updates to the field and one for double-buffering when * smoothing the velocity field. Both buffers are the same type and size as the * output velocity field. * * This class make use of the finite difference solver hierarchy. Update * for each iteration is computed using a PDEDeformableRegistrationFunction. * * \warning This filter assumes that the fixed image type, moving image type * and velocity field type all have the same number of dimensions. * * \author Florence Dru, INRIA and Tom Vercauteren, MKT * * \sa PDEDeformableRegistrationFunction. * \ingroup DeformableImageRegistration */ template class ITK_EXPORT LogDomainDeformableRegistrationFilter : public PDEDeformableRegistrationWithMaskFilter { public: /** Standard class typedefs. */ typedef LogDomainDeformableRegistrationFilter Self; typedef DenseFiniteDifferenceImageFilter< TField, TField> Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods) */ itkTypeMacro( LogDomainDeformableRegistrationFilter, DenseFiniteDifferenceImageFilter ); /** FixedImage image type. */ typedef TFixedImage FixedImageType; typedef typename FixedImageType::Pointer FixedImagePointer; typedef typename FixedImageType::ConstPointer FixedImageConstPointer; /** MovingImage image type. */ typedef TMovingImage MovingImageType; typedef typename MovingImageType::Pointer MovingImagePointer; typedef typename MovingImageType::ConstPointer MovingImageConstPointer; /** Velocity field type. */ typedef TField VelocityFieldType; typedef typename VelocityFieldType::Pointer VelocityFieldPointer; /** Deformation field type. */ typedef TField DeformationFieldType; typedef typename DeformationFieldType::Pointer DeformationFieldPointer; /** Types inherithed from the superclass */ typedef typename Superclass::OutputImageType OutputImageType; /** The value type of a time step. Inherited from the superclass. */ typedef typename Superclass::TimeStepType TimeStepType; /** FiniteDifferenceFunction type. */ typedef typename Superclass::FiniteDifferenceFunctionType FiniteDifferenceFunctionType; /** PDEDeformableRegistrationFunction type. */ typedef PDEDeformableRegistrationFunction< FixedImageType, MovingImageType, DeformationFieldType> PDEDeformableRegistrationFunctionType; /** Inherit some enums and typedefs from the superclass. */ itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension); /** Set the fixed image. */ void SetFixedImage( const FixedImageType * ptr ); /** Get the fixed image. */ const FixedImageType * GetFixedImage(void) const; /** Set the moving image. */ void SetMovingImage( const MovingImageType * ptr ); /** Get the moving image. */ const MovingImageType * GetMovingImage(void) const; /** Set initial velocity field. */ void SetInitialVelocityField( VelocityFieldType * ptr ); /** Get output velocity field. */ //HACK: const VelocityFieldType * GetVelocityField(void) const; typename VelocityFieldType::Pointer GetVelocityField(void); /** Get output deformation field. */ DeformationFieldPointer GetDeformationField(); /** Get output inverse deformation field. */ DeformationFieldPointer GetInverseDisplacementField(); /** Get the number of valid inputs. For LogDomainDeformableRegistration, * this checks whether the fixed and moving images have been * set. While LogDomainDeformableRegistration can take a third input as an * initial velocity field, this input is not a required input. */ virtual std::vector >::size_type GetNumberOfValidRequiredInputs() const; /** Set/Get whether the velocity field is smoothed * (regularized). Smoothing the velocity yields a solution * elastic in nature. If SmoothVelocityField is on, then the * velocity field is smoothed with a Gaussian whose standard * deviations are specified with SetStandardDeviations() */ itkSetMacro( SmoothVelocityField, bool ); itkGetConstMacro( SmoothVelocityField, bool ); itkBooleanMacro( SmoothVelocityField ); /** Set the Gaussian smoothing standard deviations for the * velocity field. The values are set with respect to pixel * coordinates. */ itkSetVectorMacro( StandardDeviations, double, ImageDimension ); virtual void SetStandardDeviations( double value ); /** Get the Gaussian smoothing standard deviations use for smoothing * the velocity field. */ const double * GetStandardDeviations(void) const { return static_cast(m_StandardDeviations); } /** Set/Get whether the update field is smoothed * (regularized). Smoothing the update field yields a solution * viscous in nature. If SmoothUpdateField is on, then the * update field is smoothed with a Gaussian whose standard * deviations are specified with SetUpdateFieldStandardDeviations() */ itkSetMacro( SmoothUpdateField, bool ); itkGetConstMacro( SmoothUpdateField, bool ); itkBooleanMacro( SmoothUpdateField ); /** Set the Gaussian smoothing standard deviations for the update * field. The values are set with respect to pixel coordinates. */ itkSetVectorMacro( UpdateFieldStandardDeviations, double, ImageDimension ); virtual void SetUpdateFieldStandardDeviations( double value ); /** Get the Gaussian smoothing standard deviations used for * smoothing the update field. */ const double * GetUpdateFieldStandardDeviations(void) const { return static_cast(m_UpdateFieldStandardDeviations); } /** Stop the registration after the current iteration. */ virtual void StopRegistration() { m_StopRegistrationFlag = true; } /** Set/Get the desired maximum error of the Gaussian kernel approximate. * \sa GaussianOperator. */ itkSetMacro( MaximumError, double ); itkGetConstMacro( MaximumError, double ); /** Set/Get the desired limits of the Gaussian kernel width. * \sa GaussianOperator. */ itkSetMacro( MaximumKernelWidth, unsigned int ); itkGetConstMacro( MaximumKernelWidth, unsigned int ); /** Get the metric value. The metric value is the mean square difference * in intensity between the fixed image and transforming moving image * computed over the the overlapping region between the two images. * This value is calculated for the current iteration */ virtual double GetMetric() const { return 12345.6789; //A silly value for the metric. } protected: LogDomainDeformableRegistrationFilter(); ~LogDomainDeformableRegistrationFilter() { } void PrintSelf(std::ostream& os, Indent indent) const; /** Exponential type */ #if ITK_VERSION_MAJOR >=4 typedef ExponentialDisplacementFieldImageFilter< VelocityFieldType, DeformationFieldType> FieldExponentiatorType; #else typedef ExponentialDeformationFieldImageFilter< VelocityFieldType, DeformationFieldType> FieldExponentiatorType; #endif typedef typename FieldExponentiatorType::Pointer FieldExponentiatorPointer; itkSetObjectMacro( Exponentiator, FieldExponentiatorType ); itkGetObjectMacro( Exponentiator, FieldExponentiatorType ); /** Supplies the halting criteria for this class of filters. The * algorithm will stop after a user-specified number of iterations. */ virtual bool Halt() { if( m_StopRegistrationFlag ) { return true; } return this->Superclass::Halt(); } /** A simple method to copy the data from the input to the output. * If the input does not exist, a zero field is written to the output. */ virtual void CopyInputToOutput(); #if (ITK_VERSION_MAJOR < 4) virtual void ApplyUpdate(TimeStepType dt) { //By default just use the superclass. Superclass::ApplyUpdate(dt); }; #else /** This method applies changes from the m_UpdateBuffer to the output using * * the ThreadedApplyUpdate() method and a multithreading mechanism. "dt" is * * the time step to use for the update of each pixel. */ virtual void ApplyUpdate(const TimeStepType& dt) { //By default just use the superclass. Superclass::ApplyUpdate(dt); }; #endif /** Initialize the state of filter and equation before each iteration. * Progress feeback is implemented as part of this method. */ virtual void InitializeIteration(); /** Utility to smooth the velocity field (represented in the Output) * using a Gaussian operator. The amount of smoothing can be specified * by setting the StandardDeviations. */ virtual void SmoothVelocityField(); /** Utility to smooth the UpdateBuffer using a Gaussian operator. * The amount of smoothing can be specified by setting the * UpdateFieldStandardDeviations. */ virtual void SmoothUpdateField(); /** Utility to smooth a velocity field using a Gaussian operator. * The amount of smoothing can be specified by setting the * StandardDeviations. */ virtual void SmoothGivenField(VelocityFieldType * field, const double StandardDeviations[ImageDimension]); /** This method is called after the solution has been generated. In this case, * the filter release the memory of the internal buffers. */ virtual void PostProcessOutput(); /** This method is called before iterating the solution. */ virtual void Initialize(); /** By default the output velocity field has the same Spacing, Origin * and LargestPossibleRegion as the input/initial velocity field. If * the initial velocity field is not set, the output information is * copied from the fixed image. */ virtual void GenerateOutputInformation(); /** It is difficult to compute in advance the input moving image region * required to compute the requested output region. Thus the safest * thing to do is to request for the whole moving image. * For the fixed image and velocity field, the input requested region * set to be the same as that of the output requested region. */ virtual void GenerateInputRequestedRegion(); private: LogDomainDeformableRegistrationFilter(const Self &); // purposely not implemented void operator=(const Self &); // purposely not implemented /** Standard deviation for Gaussian smoothing */ double m_StandardDeviations[ImageDimension]; double m_UpdateFieldStandardDeviations[ImageDimension]; /** Modes to control smoothing of the update and velocity fields */ bool m_SmoothVelocityField; bool m_SmoothUpdateField; /** Temporary field used for smoothing the velocity field. */ VelocityFieldPointer m_TempField; /** Maximum error for Gaussian operator approximation. */ double m_MaximumError; /** Limits of Gaussian kernel width. */ unsigned int m_MaximumKernelWidth; /** Flag to indicate user stop registration request. */ bool m_StopRegistrationFlag; FieldExponentiatorPointer m_Exponentiator; FieldExponentiatorPointer m_InverseExponentiator; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkLogDomainDeformableRegistrationFilter.hxx" #endif #endif itkLogDomainDeformableRegistrationFilter.hxx000066400000000000000000000410301321604176500420230ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkLogDomainDeformableRegistrationFilter_txx #define __itkLogDomainDeformableRegistrationFilter_txx #include "itkLogDomainDeformableRegistrationFilter.h" #include "itkExceptionObject.h" #include "itkImageRegionIterator.h" #include "itkImageLinearIteratorWithIndex.h" #include "itkDataObject.h" #include "itkGaussianOperator.h" #include "itkVectorNeighborhoodOperatorImageFilter.h" #include "vnl/vnl_math.h" namespace itk { // Default constructor template LogDomainDeformableRegistrationFilter ::LogDomainDeformableRegistrationFilter() { #if (ITK_VERSION_MAJOR < 4) this->SetNumberOfRequiredInputs(2); #else //HACK: This really should define the names of the required inputs. this->SetNumberOfIndexedInputs(2); // Primary input is optional in this filter this->RemoveRequiredInputName( "Primary" ); #endif this->SetNumberOfIterations(10); unsigned int j; for( j = 0; j < ImageDimension; j++ ) { m_StandardDeviations[j] = 1.0; m_UpdateFieldStandardDeviations[j] = 1.0; } m_TempField = VelocityFieldType::New(); m_MaximumError = 0.1; m_MaximumKernelWidth = 30; m_StopRegistrationFlag = false; m_SmoothVelocityField = true; m_SmoothUpdateField = false; m_Exponentiator = FieldExponentiatorType::New(); m_Exponentiator->ComputeInverseOff(); m_InverseExponentiator = FieldExponentiatorType::New(); m_InverseExponentiator->ComputeInverseOn(); } template void LogDomainDeformableRegistrationFilter ::SetInitialVelocityField( VelocityFieldType * ptr ) { #if (ITK_VERSION_MAJOR < 4) this->SetNthInput( VELOCITYFIELD_IMAGE_CODE, ptr ); #else this->SetNthInput( VELOCITYFIELD_IMAGE_CODE, ptr ); #endif } // Set the fixed image. template void LogDomainDeformableRegistrationFilter ::SetFixedImage( const FixedImageType * ptr ) { #if (ITK_VERSION_MAJOR < 4) this->ProcessObject::SetNthInput( FIXED_IMAGE_CODE, const_cast( ptr ) ); #else this->ProcessObject::SetNthInput( FIXED_IMAGE_CODE, const_cast( ptr ) ); #endif } // Get the fixed image. template const typename LogDomainDeformableRegistrationFilter ::FixedImageType * LogDomainDeformableRegistrationFilter ::GetFixedImage() const { return dynamic_cast #if (ITK_VERSION_MAJOR < 4) ( this->ProcessObject::GetInput( FIXED_IMAGE_CODE ) ); #else ( this->ProcessObject::GetInput( FIXED_IMAGE_CODE ) ); #endif } template /*const HACK: This should be const */ typename LogDomainDeformableRegistrationFilter::VelocityFieldType::Pointer LogDomainDeformableRegistrationFilter ::GetVelocityField(void) /* const HACK I think this should be a const function */ { typename LogDomainDeformableRegistrationFilter::VelocityFieldType::Pointer tmpVelocityField=this->GetOutput(VELOCITYFIELD_IMAGE_CODE); return tmpVelocityField; } // Set the moving image. template void LogDomainDeformableRegistrationFilter ::SetMovingImage( const MovingImageType * ptr ) { #if (ITK_VERSION_MAJOR < 4) this->ProcessObject::SetNthInput( MOVING_IMAGE_CODE, const_cast( ptr ) ); #else this->ProcessObject::SetNthInput( MOVING_IMAGE_CODE, const_cast( ptr ) ); #endif } // Get the moving image. template const typename LogDomainDeformableRegistrationFilter ::MovingImageType * LogDomainDeformableRegistrationFilter ::GetMovingImage() const { return dynamic_cast #if (ITK_VERSION_MAJOR < 4) ( this->ProcessObject::GetInput( MOVING_IMAGE_CODE ) ); #else ( this->ProcessObject::GetInput( MOVING_IMAGE_CODE ) ); #endif } template std::vector >::size_type LogDomainDeformableRegistrationFilter ::GetNumberOfValidRequiredInputs() const { typename std::vector >::size_type num = 0; if( this->GetFixedImage() ) { num++; } if( this->GetMovingImage() ) { num++; } return num; } // Set the standard deviations. template void LogDomainDeformableRegistrationFilter ::SetStandardDeviations( double value ) { unsigned int j; for( j = 0; j < ImageDimension; j++ ) { if( value != m_StandardDeviations[j] ) { break; } } if( j < ImageDimension ) { this->Modified(); for( j = 0; j < ImageDimension; j++ ) { m_StandardDeviations[j] = value; } } } // Set the standard deviations. template void LogDomainDeformableRegistrationFilter ::SetUpdateFieldStandardDeviations( double value ) { unsigned int j; for( j = 0; j < ImageDimension; j++ ) { if( value != m_UpdateFieldStandardDeviations[j] ) { break; } } if( j < ImageDimension ) { this->Modified(); for( j = 0; j < ImageDimension; j++ ) { m_UpdateFieldStandardDeviations[j] = value; } } } // Standard PrintSelf method. template void LogDomainDeformableRegistrationFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Smooth velocity field: " << (m_SmoothVelocityField ? "on" : "off") << std::endl; os << indent << "Standard deviations: ["; unsigned int j; for( j = 0; j < ImageDimension - 1; j++ ) { os << m_StandardDeviations[j] << ", "; } os << m_StandardDeviations[j] << "]" << std::endl; os << indent << "Smooth update field: " << (m_SmoothUpdateField ? "on" : "off") << std::endl; os << indent << "Update field standard deviations: ["; for( j = 0; j < ImageDimension - 1; j++ ) { os << m_UpdateFieldStandardDeviations[j] << ", "; } os << m_UpdateFieldStandardDeviations[j] << "]" << std::endl; os << indent << "StopRegistrationFlag: "; os << m_StopRegistrationFlag << std::endl; os << indent << "MaximumError: "; os << m_MaximumError << std::endl; os << indent << "MaximumKernelWidth: "; os << m_MaximumKernelWidth << std::endl; os << indent << "Exponentiator: "; os << m_Exponentiator << std::endl; os << indent << "InverseExponentiator: "; os << m_InverseExponentiator << std::endl; } // Set the function state values before each iteration template void LogDomainDeformableRegistrationFilter ::InitializeIteration() { // std::cout<<"LogDomainDeformableRegistrationFilter::InitializeIteration"<GetMovingImage(); FixedImageConstPointer fixedPtr = this->GetFixedImage(); if( !movingPtr || !fixedPtr ) { itkExceptionMacro( << "Fixed and/or moving image not set" ); } // update variables in the equation object PDEDeformableRegistrationFunctionType *f = dynamic_cast (this->GetDifferenceFunction().GetPointer() ); if( !f ) { itkExceptionMacro(<< "FiniteDifferenceFunction not of type LogDomainDeformableRegistrationFilterFunction"); } f->SetFixedImage( fixedPtr ); f->SetMovingImage( movingPtr ); this->Superclass::InitializeIteration(); } /* Override the default implementation for the case when the * initial velocity is not set. * If the initial velocity is not set, the output is * fill with zero vectors.*/ template void LogDomainDeformableRegistrationFilter ::CopyInputToOutput() { #if (ITK_VERSION_MAJOR < 4) typename Superclass::InputImageType::ConstPointer inputPtr = this->GetInput(VELOCITYFIELD_IMAGE_CODE); #else typename Superclass::InputImageType::ConstPointer inputPtr = this->GetInput(VELOCITYFIELD_IMAGE_CODE); #endif if( inputPtr ) { this->Superclass::CopyInputToOutput(); } else { typename Superclass::PixelType zeros; for( unsigned int j = 0; j < ImageDimension; j++ ) { zeros[j] = 0; } typename OutputImageType::Pointer output = this->GetVelocityField(); ImageRegionIterator out(output, output->GetRequestedRegion() ); while( !out.IsAtEnd() ) { out.Value() = zeros; ++out; } } } template void LogDomainDeformableRegistrationFilter ::GenerateOutputInformation() { // std::cout<<"LogDomainDeformableRegistrationFilter::GenerateOutputInformation"<GetInput(VELOCITYFIELD_IMAGE_CODE) ) #else if( this->GetInput(VELOCITYFIELD_IMAGE_CODE) ) #endif { // Initial velocity field is set. // Copy information from initial field. this->Superclass::GenerateOutputInformation(); } else if( this->GetFixedImage() ) { // Initial deforamtion field is not set. // Copy information from the fixed image. for( unsigned int idx = 0; idx < this->GetNumberOfOutputs(); ++idx ) { output = this->GetOutput(idx); if( output ) { output->CopyInformation(this->GetFixedImage() ); } } } } template void LogDomainDeformableRegistrationFilter ::GenerateInputRequestedRegion() { // std::cout<<"LogDomainDeformableRegistrationFilter::GenerateInputRequestedRegion"<( this->GetMovingImage() ); if( movingPtr ) { movingPtr->SetRequestedRegionToLargestPossibleRegion(); } // just propagate up the output requested region for // the fixed image and initial velocity field. #if (ITK_VERSION_MAJOR < 4) VelocityFieldPointer inputPtr = const_cast( this->GetInput(VELOCITYFIELD_IMAGE_CODE) ); #else VelocityFieldPointer inputPtr = const_cast( this->GetInput(VELOCITYFIELD_IMAGE_CODE) ); #endif VelocityFieldPointer outputPtr = this->GetVelocityField(); FixedImagePointer fixedPtr = const_cast( this->GetFixedImage() ); if( inputPtr ) { inputPtr->SetRequestedRegion( outputPtr->GetRequestedRegion() ); } if( fixedPtr ) { fixedPtr->SetRequestedRegion( outputPtr->GetRequestedRegion() ); } } // Release memory of internal buffers template void LogDomainDeformableRegistrationFilter ::PostProcessOutput() { this->Superclass::PostProcessOutput(); m_TempField->Initialize(); } // Initialize flags template void LogDomainDeformableRegistrationFilter ::Initialize() { // std::cout<<"LogDomainDeformableRegistrationFilter::Initialize"<Superclass::Initialize(); m_StopRegistrationFlag = false; } // Smooth velocity using a separable Gaussian kernel template void LogDomainDeformableRegistrationFilter ::SmoothVelocityField() { // The output buffer will be overwritten with new data. this->SmoothGivenField(this->GetVelocityField(), this->m_StandardDeviations); } // Smooth update field using a separable Gaussian kernel template void LogDomainDeformableRegistrationFilter ::SmoothUpdateField() { // The update buffer will be overwritten with new data. this->SmoothGivenField(this->GetUpdateBuffer(), this->m_UpdateFieldStandardDeviations); } // Smooth velocity using a separable Gaussian kernel template void LogDomainDeformableRegistrationFilter ::SmoothGivenField(VelocityFieldType * field, const double StandardDeviations[ImageDimension]) { typedef typename VelocityFieldType::PixelType VectorType; typedef typename VectorType::ValueType ScalarType; // copy field to TempField m_TempField->SetOrigin( field->GetOrigin() ); m_TempField->SetSpacing( field->GetSpacing() ); m_TempField->SetDirection( field->GetDirection() ); m_TempField->SetLargestPossibleRegion( field->GetLargestPossibleRegion() ); m_TempField->SetRequestedRegion( field->GetRequestedRegion() ); m_TempField->SetBufferedRegion( field->GetBufferedRegion() ); m_TempField->Allocate(); { VectorType zeroVec; zeroVec.Fill( 0.0 ); m_TempField->FillBuffer( zeroVec ); } typedef GaussianOperator OperatorType; OperatorType * const oper = new OperatorType; typedef VectorNeighborhoodOperatorImageFilter< VelocityFieldType, VelocityFieldType> SmootherType; typename SmootherType::Pointer smoother = SmootherType::New(); typedef typename VelocityFieldType::PixelContainerPointer PixelContainerPointer; PixelContainerPointer swapPtr; // graft the output field onto the mini-pipeline smoother->GraftOutput( m_TempField ); for( unsigned int j = 0; j < ImageDimension; j++ ) { // smooth along this dimension oper->SetDirection( j ); double variance = vnl_math_sqr( StandardDeviations[j] ); oper->SetVariance( variance ); oper->SetMaximumError( m_MaximumError ); oper->SetMaximumKernelWidth( m_MaximumKernelWidth ); oper->CreateDirectional(); // todo: make sure we only smooth within the buffered region smoother->SetOperator( *oper ); smoother->SetInput( field ); smoother->Update(); if( j < ImageDimension - 1 ) { // swap the containers swapPtr = smoother->GetOutput()->GetPixelContainer(); smoother->GraftOutput( field ); field->SetPixelContainer( swapPtr ); smoother->Modified(); } } // graft the output back to field m_TempField->SetPixelContainer( field->GetPixelContainer() ); // field to contain the final smoothed data, do the equivalent of a graft field->SetPixelContainer( smoother->GetOutput()->GetPixelContainer() ); field->SetRequestedRegion( smoother->GetOutput()->GetRequestedRegion() ); field->SetBufferedRegion( smoother->GetOutput()->GetBufferedRegion() ); field->SetLargestPossibleRegion( smoother->GetOutput()->GetLargestPossibleRegion() ); field->CopyInformation( smoother->GetOutput() ); delete oper; } template typename LogDomainDeformableRegistrationFilter ::DeformationFieldPointer LogDomainDeformableRegistrationFilter ::GetDeformationField() { // std::cout<<"LogDomainDeformableRegistration::GetDeformationField"<SetInput( this->GetVelocityField() ); m_Exponentiator->GetOutput()->SetRequestedRegion( this->GetVelocityField()->GetRequestedRegion() ); m_Exponentiator->Update(); return m_Exponentiator->GetOutput(); } template typename LogDomainDeformableRegistrationFilter ::DeformationFieldPointer LogDomainDeformableRegistrationFilter ::GetInverseDisplacementField() { // std::cout<<"LogDomainDeformableRegistration::GetInverseDisplacementField"<SetInput( this->GetVelocityField() ); m_InverseExponentiator->GetOutput()->SetRequestedRegion( this->GetVelocityField()->GetRequestedRegion() ); m_InverseExponentiator->Update(); return m_InverseExponentiator->GetOutput(); } } // end namespace itk #endif itkLogDomainDemonsRegistrationFilterWithMaskExtension.h000066400000000000000000000202261321604176500442010ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkLogDomainDemonsRegistrationFilterWithMaskExtension_h #define __itkLogDomainDemonsRegistrationFilterWithMaskExtension_h #include "itkLogDomainDeformableRegistrationFilter.h" #include "itkESMDemonsRegistrationWithMaskFunction.h" #if ITK_VERSION_MAJOR >= 4 #include "itkMultiplyImageFilter.h" #else #include "itkMultiplyByConstantImageFilter.h" #endif #include "itkVelocityFieldBCHCompositionFilter.h" namespace itk { /** * \class LogDomainDemonsRegistrationFilterWithMaskExtension * \brief Deformably register two images using a diffeomorphic demons algorithm. * * See T. Vercauteren, X. Pennec, A. Perchant and N. Ayache, * "Symmetric Log-Domain Diffeomorphic Registration: A Demons-based Approach", * Proc. of MICCAI 2008. * * Velocity and deformation fields are represented as images whose pixel type are * some vector type with at least N elements, where N is the dimension of * the fixed image. The vector type must support element access via operator * []. It is assumed that the vector elements behave like floating point * scalars. * * This class is templated over the fixed image type, moving image type * and the velocity/deformation field type. * * The input fixed and moving images are set via methods SetFixedImage * and SetMovingImage respectively. An initial velocity field maybe set via * SetInitialVelocityField or SetInput. If no initial field is set, * a zero field is used as the initial condition. * * The output velocity field can be obtained via methods GetOutput * or GetVelocityField. * * The output deformation field can be obtained via method GetDeformationField. * * This class make use of the finite difference solver hierarchy. Update * for each iteration is computed using a PDEDeformableRegistrationFunction. * * \warning This filter assumes that the fixed image type, moving image type * and velocity field type all have the same number of dimensions. * * \sa DemonsRegistrationFilter * \sa DemonsRegistrationFunction * \ingroup DeformableImageRegistration MultiThreaded * \author Florence Dru, INRIA and Tom Vercauteren, MKT * * Extension (by Bene): -- Methods to set/get Masks * - using itk::ESMDemonsRegistrationWithMaskFunction */ template class ITK_EXPORT LogDomainDemonsRegistrationFilterWithMaskExtension : public LogDomainDeformableRegistrationFilter { public: /** Standard class typedefs. */ typedef LogDomainDemonsRegistrationFilterWithMaskExtension Self; typedef LogDomainDeformableRegistrationFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods) */ itkTypeMacro( LogDomainDemonsRegistrationFilterWithMaskExtension,LogDomainDeformableRegistrationFilter ); /** FixedImage image type. */ typedef typename Superclass::FixedImageType FixedImageType; typedef typename Superclass::FixedImagePointer FixedImagePointer; /** MovingImage image type. */ typedef typename Superclass::MovingImageType MovingImageType; typedef typename Superclass::MovingImagePointer MovingImagePointer; /** Velocity field type. */ typedef TField VelocityFieldType; typedef typename VelocityFieldType::Pointer VelocityFieldPointer; /** Deformation field type. */ typedef typename Superclass::DeformationFieldType DeformationFieldType; typedef typename Superclass::DeformationFieldPointer DeformationFieldPointer; /** Types inherithed from the superclass */ typedef typename Superclass::OutputImageType OutputImageType; /** FiniteDifferenceFunction type. */ typedef typename Superclass::FiniteDifferenceFunctionType FiniteDifferenceFunctionType; /** Take timestep type from the FiniteDifferenceFunction. */ typedef typename FiniteDifferenceFunctionType::TimeStepType TimeStepType; /** DemonsRegistrationFilterFunction type. */ typedef ESMDemonsRegistrationWithMaskFunction DemonsRegistrationFunctionType; typedef typename DemonsRegistrationFunctionType::Pointer DemonsRegistrationFunctionPointer; typedef typename DemonsRegistrationFunctionType::GradientType GradientType; /** Inherit some enums from the superclass. */ itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension); typedef itk::SpatialObject MaskType; /** Get the metric value. The metric value is the mean square difference * in intensity between the fixed image and transforming moving image * computed over the the overlapping region between the two images. * This value is calculated for the current iteration */ virtual double GetMetric() const; virtual const double &GetRMSChange() const; virtual void SetUseGradientType( GradientType gtype ); virtual GradientType GetUseGradientType() const; /** Set/Get the threshold below which the absolute difference of * intensity yields a match. When the intensities match between a * moving and fixed image pixel, the update vector (for that * iteration) will be the zero vector. Default is 0.001. */ virtual void SetIntensityDifferenceThreshold(double); virtual double GetIntensityDifferenceThreshold() const; /** Set/Get the maximum length in terms of pixels of * the vectors in the update buffer. */ virtual void SetMaximumUpdateStepLength(double); virtual double GetMaximumUpdateStepLength() const; /** Set/Get the number of terms used in the Baker-Campbell-Hausdorff approximation. */ virtual void SetNumberOfBCHApproximationTerms(unsigned int); virtual unsigned int GetNumberOfBCHApproximationTerms() const; /**Extension */ virtual void SetMovingImageMask( MaskType *mask); /**Extension */ virtual void SetFixedImageMask(MaskType *mask); /**Extension */ virtual const MaskType * GetMovingImageMask() const; /**Extension */ virtual const MaskType * GetFixedImageMask() const; protected: LogDomainDemonsRegistrationFilterWithMaskExtension(); ~LogDomainDemonsRegistrationFilterWithMaskExtension() {} void PrintSelf(std::ostream& os, Indent indent) const; /** Initialize the state of filter and equation before each iteration. */ virtual void InitializeIteration(); /** Apply update. */ #if (ITK_VERSION_MAJOR >= 4) virtual void ApplyUpdate(const TimeStepType& dt); #else virtual void ApplyUpdate(TimeStepType dt); #endif private: LogDomainDemonsRegistrationFilterWithMaskExtension(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented /** Downcast the DifferenceFunction using a dynamic_cast to ensure that it is of the correct type. * this method will throw an exception if the function is not of the expected type. */ DemonsRegistrationFunctionType * DownCastDifferenceFunctionType(); const DemonsRegistrationFunctionType * DownCastDifferenceFunctionType() const; /** Exp and composition typedefs */ #if ITK_VERSION_MAJOR >= 4 typedef MultiplyImageFilter< VelocityFieldType,itk::Image, VelocityFieldType> MultiplyByConstantType; #else typedef MultiplyByConstantImageFilter< VelocityFieldType, TimeStepType, VelocityFieldType> MultiplyByConstantType; #endif typedef VelocityFieldBCHCompositionFilter< VelocityFieldType, VelocityFieldType> BCHFilterType; typedef typename MultiplyByConstantType::Pointer MultiplyByConstantPointer; typedef typename BCHFilterType::Pointer BCHFilterPointer; MultiplyByConstantPointer m_Multiplier; BCHFilterPointer m_BCHFilter; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkLogDomainDemonsRegistrationFilterWithMaskExtension.txx" #endif #endif itkLogDomainDemonsRegistrationFilterWithMaskExtension.txx000066400000000000000000000244311321604176500445770ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkLogDomainDemonsRegistrationFilterWithMaskExtension_txx #define __itkLogDomainDemonsRegistrationFilterWithMaskExtension_txx #include "itkLogDomainDemonsRegistrationFilterWithMaskExtension.h" namespace itk { // Default constructor template LogDomainDemonsRegistrationFilterWithMaskExtension ::LogDomainDemonsRegistrationFilterWithMaskExtension() { DemonsRegistrationFunctionPointer drfp = DemonsRegistrationFunctionType::New(); this->SetDifferenceFunction( static_cast( drfp.GetPointer() ) ); m_Multiplier = MultiplyByConstantType::New(); m_Multiplier->InPlaceOn(); m_BCHFilter = BCHFilterType::New(); m_BCHFilter->InPlaceOn(); // Set number of terms in the BCH approximation to default value m_BCHFilter->SetNumberOfApproximationTerms( 2 ); } // Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. template typename LogDomainDemonsRegistrationFilterWithMaskExtension ::DemonsRegistrationFunctionType* LogDomainDemonsRegistrationFilterWithMaskExtension ::DownCastDifferenceFunctionType() { DemonsRegistrationFunctionType *drfp = dynamic_cast(this->GetDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } // Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. template const typename LogDomainDemonsRegistrationFilterWithMaskExtension ::DemonsRegistrationFunctionType* LogDomainDemonsRegistrationFilterWithMaskExtension ::DownCastDifferenceFunctionType() const { const DemonsRegistrationFunctionType *drfp = dynamic_cast(this->GetDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } // Set the function state values before each iteration template void LogDomainDemonsRegistrationFilterWithMaskExtension ::InitializeIteration() { //std::cout<<"LogDomainDemonsRegistrationFilter::InitializeIteration"<DownCastDifferenceFunctionType(); #if ITK_VERSION_MAJOR >= 4 f->SetDisplacementField( this->GetDeformationField() ); #else f->SetDeformationField( this->GetDeformationField() ); #endif // call the superclass implementation ( initializes f ) Superclass::InitializeIteration(); } // Get the metric value from the difference function template double LogDomainDemonsRegistrationFilterWithMaskExtension ::GetMetric() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetMetric(); } // Get Intensity Difference Threshold template double LogDomainDemonsRegistrationFilterWithMaskExtension ::GetIntensityDifferenceThreshold() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetIntensityDifferenceThreshold(); } // Set Intensity Difference Threshold template void LogDomainDemonsRegistrationFilterWithMaskExtension ::SetIntensityDifferenceThreshold(double threshold) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetIntensityDifferenceThreshold(threshold); } // Set Maximum Update Step Length template void LogDomainDemonsRegistrationFilterWithMaskExtension ::SetMaximumUpdateStepLength(double step) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetMaximumUpdateStepLength(step); } // Get Maximum Update Step Length template double LogDomainDemonsRegistrationFilterWithMaskExtension ::GetMaximumUpdateStepLength() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetMaximumUpdateStepLength(); } // Set number of terms used in the BCH approximation template void LogDomainDemonsRegistrationFilterWithMaskExtension ::SetNumberOfBCHApproximationTerms(unsigned int numterms) { this->m_BCHFilter->SetNumberOfApproximationTerms(numterms); } // Get number of terms used in the BCH approximation template unsigned int LogDomainDemonsRegistrationFilterWithMaskExtension ::GetNumberOfBCHApproximationTerms() const { return this->m_BCHFilter->GetNumberOfApproximationTerms(); } // Get the metric value from the difference function template const double & LogDomainDemonsRegistrationFilterWithMaskExtension ::GetRMSChange() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetRMSChange(); } // Get gradient type template typename LogDomainDemonsRegistrationFilterWithMaskExtension::GradientType LogDomainDemonsRegistrationFilterWithMaskExtension ::GetUseGradientType() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetUseGradientType(); } // Set gradient type template void LogDomainDemonsRegistrationFilterWithMaskExtension ::SetUseGradientType(GradientType gtype) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetUseGradientType(gtype); } template const typename LogDomainDemonsRegistrationFilterWithMaskExtension::MaskType * LogDomainDemonsRegistrationFilterWithMaskExtension ::GetMovingImageMask() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetMovingImageMask(); } template const typename LogDomainDemonsRegistrationFilterWithMaskExtension::MaskType * LogDomainDemonsRegistrationFilterWithMaskExtension ::GetFixedImageMask() const { const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetFixedImageMask(); } /** * */ template void LogDomainDemonsRegistrationFilterWithMaskExtension ::SetMovingImageMask(MaskType *mask) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetMovingImageMask(mask); } /** * */ template void LogDomainDemonsRegistrationFilterWithMaskExtension ::SetFixedImageMask(MaskType *mask) { DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetFixedImageMask(mask); } // Get the metric value from the difference function template void LogDomainDemonsRegistrationFilterWithMaskExtension #if ITK_VERSION_MAJOR >= 4 ::ApplyUpdate(const TimeStepType& dt) #else ::ApplyUpdate(TimeStepType dt) #endif { //std::cout<<"LogDomainDemonsRegistrationFilter::ApplyUpdate"<GetSmoothUpdateField() ) { this->SmoothUpdateField(); } // Use time step if necessary. In many cases // the time step is one so this will be skipped if ( fabs(dt - 1.0)>1.0e-4 ) { itkDebugMacro( "Using timestep: " << dt ); m_Multiplier->SetConstant( dt ); m_Multiplier->SetInput( this->GetUpdateBuffer() ); m_Multiplier->GraftOutput( this->GetUpdateBuffer() ); // in place update m_Multiplier->Update(); // graft output back to this->GetUpdateBuffer() this->GetUpdateBuffer()->Graft( m_Multiplier->GetOutput() ); } // Apply update by using BCH approximation m_BCHFilter->SetInput( 0, this->GetOutput() ); m_BCHFilter->SetInput( 1, this->GetUpdateBuffer() ); if ( m_BCHFilter->GetInPlace() ) { m_BCHFilter->GraftOutput( this->GetOutput() ); } else { // Work-around for http://www.itk.org/Bug/view.php?id=8672 m_BCHFilter->GraftOutput( DeformationFieldType::New() ); } m_BCHFilter->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); // Triggers in place update m_BCHFilter->Update(); // Region passing stuff this->GraftOutput( m_BCHFilter->GetOutput() ); //Smooth the velocity field if( this->GetSmoothVelocityField() ) { this->SmoothVelocityField(); } } template void LogDomainDemonsRegistrationFilterWithMaskExtension ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << "Multiplier: " << m_Multiplier << std::endl; os << indent << "BCHFilter: " << m_BCHFilter << std::endl; } } // end namespace itk #endif itkOppositeImageFilter.h000066400000000000000000000062631321604176500357740ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkOppositeImageFilter.h,v $ Language: C++ Date: $Date: 2009-02-19 21:18:10 $ Version: $Revision: 0.0 $ 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. =========================================================================*/ #ifndef __itkOppositeImageFilter_h #define __itkOppositeImageFilter_h #include "itkUnaryFunctorImageFilter.h" #include "itkNumericTraits.h" namespace itk { /** \class OppositeImageFilter * * \brief Take the opposite of the input pixels. * * This filter is templated over the input image type * and the output image type. * * \author Tom Vercauteren, INRIA & Mauna Kea Technologies * * \ingroup IntensityImageFilters Multithreaded * \sa UnaryFunctorImageFilter */ namespace Functor { template< class TInput, class TOutput> class Opposite { public: Opposite() {}; ~Opposite() {}; bool operator!=( const Opposite & other ) const { return false; } bool operator==( const Opposite & other ) const { return true; } inline TOutput operator()( const TInput & A ) const { // We don't check if the TOutput can be signed. // It's up to the user to decide whether this makes sense. return static_cast( - A ); } }; } template class ITK_EXPORT OppositeImageFilter : public UnaryFunctorImageFilter > { public: /** Standard class typedefs. */ typedef OppositeImageFilter Self; typedef UnaryFunctorImageFilter< TInputImage,TOutputImage, Functor::Opposite< typename TInputImage::PixelType, typename TOutputImage::PixelType> > Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(OppositeImageFilter, UnaryFunctorImageFilter); #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(InputConvertibleToOutputCheck, (Concept::Convertible)); /** End concept checking */ #endif protected: OppositeImageFilter() {}; virtual ~OppositeImageFilter() {}; void PrintSelf(std::ostream &os, Indent indent) const { Superclass::PrintSelf(os, indent); } private: OppositeImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented }; } // end namespace itk #endif itkSymmetricLogDomainDemonsRegistrationFilter.h000066400000000000000000000220571321604176500425350ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkSymmetricLogDomainDemonsRegistrationFilter_h #define __itkSymmetricLogDomainDemonsRegistrationFilter_h #include "itkLogDomainDeformableRegistrationFilter.h" #include "itkESMDemonsRegistrationFunction.h" #include "itkMultiplyByConstantImageFilter.h" namespace itk { /** * \class SymmetricLogDomainDemonsRegistrationFilter * \brief Deformably register two images using a diffeomorphic demons algorithm * and a symmetrized optimization scheme. * * See T. Vercauteren, X. Pennec, A. Perchant and N. Ayache, * "Symmetric Log-Domain Diffeomorphic Registration: A Demons-based Approach", * Proc. of MICCAI 2008. * * Velocity and deformation fields are represented as images whose pixel type are * some vector type with at least N elements, where N is the dimension of * the fixed image. The vector type must support element access via operator * []. It is assumed that the vector elements behave like floating point * scalars. * * This class is templated over the fixed image type, moving image type * and the velocity/deformation field type. * * The input fixed and moving images are set via methods SetFixedImage * and SetMovingImage respectively. An initial velocity field maybe set via * SetInitialVelocityField or SetInput. If no initial field is set, * a zero field is used as the initial condition. * * The output velocity field can be obtained via methods GetOutput * or GetVelocityField. * * The output deformation field can be obtained via method GetDeformationField. * * This class make use of the finite difference solver hierarchy. Update * for each iteration is computed using a PDEDeformableRegistrationFunction. * * \warning This filter assumes that the fixed image type, moving image type * and velocity field type all have the same number of dimensions. * * \sa DemonsRegistrationFilter * \sa DemonsRegistrationFunction * \ingroup DeformableImageRegistration MultiThreaded * \author Florence Dru, INRIA and Tom Vercauteren, MKT */ template class ITK_EXPORT SymmetricLogDomainDemonsRegistrationFilter : public LogDomainDeformableRegistrationFilter { public: /** Standard class typedefs. */ typedef SymmetricLogDomainDemonsRegistrationFilter Self; typedef LogDomainDeformableRegistrationFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods) */ itkTypeMacro( SymmetricLogDomainDemonsRegistrationFilter,LogDomainDeformableRegistrationFilter ); /** FixedImage image type. */ typedef typename Superclass::FixedImageType FixedImageType; typedef typename Superclass::FixedImagePointer FixedImagePointer; /** MovingImage image type. */ typedef typename Superclass::MovingImageType MovingImageType; typedef typename Superclass::MovingImagePointer MovingImagePointer; /** Velocity field type. */ typedef TField VelocityFieldType; typedef typename VelocityFieldType::Pointer VelocityFieldPointer; /** Deformation field type. */ typedef typename Superclass::DeformationFieldType DeformationFieldType; typedef typename Superclass::DeformationFieldPointer DeformationFieldPointer; /** Types inherithed from the superclass */ typedef typename Superclass::OutputImageType OutputImageType; /** FiniteDifferenceFunction type. */ typedef typename Superclass::FiniteDifferenceFunctionType FiniteDifferenceFunctionType; /** Take timestep type from the FiniteDifferenceFunction. */ typedef typename FiniteDifferenceFunctionType::TimeStepType TimeStepType; /** DemonsRegistrationFilterFunction type. */ typedef ESMDemonsRegistrationFunction DemonsRegistrationFunctionType; typedef typename DemonsRegistrationFunctionType::Pointer DemonsRegistrationFunctionPointer; typedef typename DemonsRegistrationFunctionType::GradientType GradientType; /** Get the metric value. The metric value is the mean square difference * in intensity between the fixed image and transforming moving image * computed over the the overlapping region between the two images. * This value is calculated for the current iteration */ virtual double GetMetric() const; virtual void SetUseGradientType( GradientType gtype ); virtual GradientType GetUseGradientType() const; /** Set/Get the threshold below which the absolute difference of * intensity yields a match. When the intensities match between a * moving and fixed image pixel, the update vector (for that * iteration) will be the zero vector. Default is 0.001. */ virtual void SetIntensityDifferenceThreshold(double); virtual double GetIntensityDifferenceThreshold() const; /** Set/Get the maximum length in terms of pixels of * the vectors in the update buffer. */ virtual void SetMaximumUpdateStepLength(double); virtual double GetMaximumUpdateStepLength() const; /** Set/Get the number of terms used in the Baker-Campbell-Hausdorff approximation. */ itkSetMacro( NumberOfBCHApproximationTerms, unsigned int ); itkGetConstMacro( NumberOfBCHApproximationTerms, unsigned int ); protected: SymmetricLogDomainDemonsRegistrationFilter(); ~SymmetricLogDomainDemonsRegistrationFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; /** Initialize the state of filter and equation before each iteration. */ virtual void InitializeIteration(); /** This method is called before iterating the solution. */ virtual void Initialize(); /** This method allocates storage in m_UpdateBuffer. It is called from * FiniteDifferenceFilter::GenerateData(). */ virtual void AllocateUpdateBuffer(); /** Method to allow subclasses to get direct access to the backward update * buffer */ virtual VelocityFieldType* GetBackwardUpdateBuffer() { return m_BackwardUpdateBuffer; } /** This method allocates storage in m_BackwardUpdateBuffer. */ virtual void AllocateBackwardUpdateBuffer(); /** Utility to smooth the BackwardUpdateBuffer using a Gaussian operator. * The amount of smoothing is specified by the UpdateFieldStandardDeviations. */ virtual void SmoothBackwardUpdateField(); typedef typename VelocityFieldType::RegionType ThreadRegionType; /** Does the actual work of calculating change over a region supplied by * the multithreading mechanism. */ virtual TimeStepType ThreadedCalculateChange( const ThreadRegionType ®ionToProcess, int threadId); /** Apply update. */ virtual void ApplyUpdate(TimeStepType dt); /** This method returns a pointer to a FiniteDifferenceFunction object that * will be used by the filter to calculate updates at image pixels. * \returns A FiniteDifferenceObject pointer. */ itkGetConstReferenceObjectMacro(BackwardDifferenceFunction, FiniteDifferenceFunctionType ); /** This method sets the pointer to a FiniteDifferenceFunction object that * will be used by the filter to calculate updates at image pixels. * \returns A FiniteDifferenceObject pointer. */ itkSetObjectMacro(BackwardDifferenceFunction, FiniteDifferenceFunctionType ); private: SymmetricLogDomainDemonsRegistrationFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented /** Downcast the DifferenceFunction using a dynamic_cast to ensure that it is of the correct type. * this method will throw an exception if the function is not of the expected type. */ DemonsRegistrationFunctionType * GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType * GetForwardRegistrationFunctionType() const; DemonsRegistrationFunctionType * GetBackwardRegistrationFunctionType(); const DemonsRegistrationFunctionType * GetBackwardRegistrationFunctionType() const; /** Exp and composition typedefs */ typedef MultiplyByConstantImageFilter< VelocityFieldType, TimeStepType, VelocityFieldType > MultiplyByConstantType; typedef AddImageFilter< VelocityFieldType, VelocityFieldType> AdderType; typedef typename MultiplyByConstantType::Pointer MultiplyByConstantPointer; typedef typename AdderType::Pointer AdderPointer; typename FiniteDifferenceFunctionType::Pointer m_BackwardDifferenceFunction; MultiplyByConstantPointer m_Multiplier; AdderPointer m_Adder; unsigned int m_NumberOfBCHApproximationTerms; /** The buffer that holds the updates for an iteration of the algorithm. */ VelocityFieldPointer m_BackwardUpdateBuffer; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkSymmetricLogDomainDemonsRegistrationFilter.txx" #endif #endif itkSymmetricLogDomainDemonsRegistrationFilter.txx000066400000000000000000000524361321604176500431350ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkSymmetricLogDomainDemonsRegistrationFilter_txx #define __itkSymmetricLogDomainDemonsRegistrationFilter_txx #include "itkSymmetricLogDomainDemonsRegistrationFilter.h" #include "itkOppositeImageFilter.h" #include "itkSubtractImageFilter.h" #include "itkVelocityFieldBCHCompositionFilter.h" namespace itk { // Default constructor template SymmetricLogDomainDemonsRegistrationFilter ::SymmetricLogDomainDemonsRegistrationFilter() { DemonsRegistrationFunctionPointer drfpf = DemonsRegistrationFunctionType::New(); this->SetDifferenceFunction( static_cast( drfpf.GetPointer() ) ); DemonsRegistrationFunctionPointer drfpb = DemonsRegistrationFunctionType::New(); this->SetBackwardDifferenceFunction( static_cast( drfpb.GetPointer() ) ); m_Multiplier = MultiplyByConstantType::New(); m_Multiplier->InPlaceOn(); m_Adder = AdderType::New(); m_Adder->InPlaceOn(); // Set number of terms in the BCH approximation to default value m_NumberOfBCHApproximationTerms = 2; m_BackwardUpdateBuffer = 0; } // Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. template typename SymmetricLogDomainDemonsRegistrationFilter ::DemonsRegistrationFunctionType* SymmetricLogDomainDemonsRegistrationFilter ::GetForwardRegistrationFunctionType() { DemonsRegistrationFunctionType *drfp = dynamic_cast(this->GetDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } // Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. template const typename SymmetricLogDomainDemonsRegistrationFilter ::DemonsRegistrationFunctionType* SymmetricLogDomainDemonsRegistrationFilter ::GetForwardRegistrationFunctionType() const { const DemonsRegistrationFunctionType *drfp = dynamic_cast(this->GetDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } // Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. template typename SymmetricLogDomainDemonsRegistrationFilter ::DemonsRegistrationFunctionType* SymmetricLogDomainDemonsRegistrationFilter ::GetBackwardRegistrationFunctionType() { DemonsRegistrationFunctionType *drfp = dynamic_cast(this->GetBackwardDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } // Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. template const typename SymmetricLogDomainDemonsRegistrationFilter ::DemonsRegistrationFunctionType* SymmetricLogDomainDemonsRegistrationFilter ::GetBackwardRegistrationFunctionType() const { const DemonsRegistrationFunctionType *drfp = dynamic_cast(this->GetBackwardDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } // Set the function state values before each iteration template void SymmetricLogDomainDemonsRegistrationFilter ::InitializeIteration() { // update variables in the equation object DemonsRegistrationFunctionType *f = this->GetForwardRegistrationFunctionType(); f->SetDeformationField( this->GetDeformationField() ); DemonsRegistrationFunctionType *b = this->GetBackwardRegistrationFunctionType(); b->SetFixedImage( this->GetMovingImage() ); b->SetMovingImage( this->GetFixedImage() ); b->SetDeformationField( this->GetInverseDisplacementField() ); b->InitializeIteration(); // call the superclass implementation ( initializes f ) Superclass::InitializeIteration(); } // Initialize flags template void SymmetricLogDomainDemonsRegistrationFilter ::Initialize() { //std::cout<<"SymmetricLogDomainDemonsRegistrationFilter::Initialize"<Superclass::Initialize(); const FixedImageType * fixim = this->GetFixedImage(); const MovingImageType * movim = this->GetMovingImage(); if ( fixim==0 || movim==0 ) { itkExceptionMacro( << "A fixed and a moving image are required" ); } if ( fixim->GetLargestPossibleRegion() != movim->GetLargestPossibleRegion() ) { itkExceptionMacro( << "Registering images that have diffent sizes is not supported yet." ); } if ( (fixim->GetSpacing() - movim->GetSpacing()).GetNorm() > 1e-10 ) { itkExceptionMacro( << "Registering images that have diffent spacing is not supported yet." ); } if ( (fixim->GetOrigin() - movim->GetOrigin()).GetNorm() > 1e-10 ) { itkExceptionMacro( << "Registering images that have diffent origins is not supported yet." ); } } // Get the metric value from the difference function template double SymmetricLogDomainDemonsRegistrationFilter ::GetMetric() const { const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); return 0.5*(drfpf->GetMetric() + drfpb->GetMetric()); } // Get Intensity Difference Threshold template double SymmetricLogDomainDemonsRegistrationFilter ::GetIntensityDifferenceThreshold() const { const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); if ( drfpf->GetIntensityDifferenceThreshold() != drfpb->GetIntensityDifferenceThreshold()) { itkExceptionMacro(<<"Forward and backward FiniteDifferenceFunctions not in sync"); } return drfpf->GetIntensityDifferenceThreshold(); } // Set Intensity Difference Threshold template void SymmetricLogDomainDemonsRegistrationFilter ::SetIntensityDifferenceThreshold(double threshold) { DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); drfpf->SetIntensityDifferenceThreshold(threshold); drfpb->SetIntensityDifferenceThreshold(threshold); } // Set Maximum Update Step Length template void SymmetricLogDomainDemonsRegistrationFilter ::SetMaximumUpdateStepLength(double step) { DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); drfpf->SetMaximumUpdateStepLength(step); drfpb->SetMaximumUpdateStepLength(step); } // Get Maximum Update Step Length template double SymmetricLogDomainDemonsRegistrationFilter ::GetMaximumUpdateStepLength() const { const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); if ( drfpf->GetMaximumUpdateStepLength() != drfpb->GetMaximumUpdateStepLength()) { itkExceptionMacro(<<"Forward and backward FiniteDifferenceFunctions not in sync"); } return drfpf->GetMaximumUpdateStepLength(); } // Get gradient type template typename SymmetricLogDomainDemonsRegistrationFilter::GradientType SymmetricLogDomainDemonsRegistrationFilter ::GetUseGradientType() const { const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); if ( drfpf->GetUseGradientType() != drfpb->GetUseGradientType()) { itkExceptionMacro(<<"Forward and backward FiniteDifferenceFunctions not in sync"); } return drfpf->GetUseGradientType(); } // Set gradient type template void SymmetricLogDomainDemonsRegistrationFilter ::SetUseGradientType(GradientType gtype) { DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); drfpf->SetUseGradientType(gtype); drfpb->SetUseGradientType(gtype); } // Allocate storage in m_UpdateBuffer template void SymmetricLogDomainDemonsRegistrationFilter ::AllocateUpdateBuffer() { Superclass::AllocateUpdateBuffer(); this->AllocateBackwardUpdateBuffer(); } // Allocates storage in m_BackwardUpdateBuffer template void SymmetricLogDomainDemonsRegistrationFilter ::AllocateBackwardUpdateBuffer() { if ( m_NumberOfBCHApproximationTerms < 3 ) { m_BackwardUpdateBuffer = 0; return; } // The backward update buffer looks just like the output. VelocityFieldPointer output = this->GetOutput(); if ( !m_BackwardUpdateBuffer ) m_BackwardUpdateBuffer = VelocityFieldType::New(); m_BackwardUpdateBuffer->SetOrigin(output->GetOrigin()); m_BackwardUpdateBuffer->SetSpacing(output->GetSpacing()); m_BackwardUpdateBuffer->SetDirection(output->GetDirection()); m_BackwardUpdateBuffer->SetLargestPossibleRegion(output->GetLargestPossibleRegion()); m_BackwardUpdateBuffer->SetRequestedRegion(output->GetRequestedRegion()); m_BackwardUpdateBuffer->SetBufferedRegion(output->GetBufferedRegion()); m_BackwardUpdateBuffer->Allocate(); } // Smooth the backward update field using a separable Gaussian kernel template void SymmetricLogDomainDemonsRegistrationFilter ::SmoothBackwardUpdateField() { // The update buffer will be overwritten with new data. this->SmoothGivenField(this->GetBackwardUpdateBuffer(), this->GetUpdateFieldStandardDeviations()); } template typename SymmetricLogDomainDemonsRegistrationFilter::TimeStepType SymmetricLogDomainDemonsRegistrationFilter ::ThreadedCalculateChange(const ThreadRegionType ®ionToProcess, int) { typedef typename VelocityFieldType::RegionType RegionType; typedef typename VelocityFieldType::SizeType SizeType; typedef typename VelocityFieldType::SizeValueType SizeValueType; typedef typename VelocityFieldType::IndexType IndexType; typedef typename VelocityFieldType::IndexValueType IndexValueType; typedef typename FiniteDifferenceFunctionType::NeighborhoodType NeighborhoodIteratorType; typedef ImageRegionIterator UpdateIteratorType; VelocityFieldPointer output = this->GetOutput(); // Get the FiniteDifferenceFunction to use in calculations. const typename FiniteDifferenceFunctionType::Pointer dff = this->GetDifferenceFunction(); const typename FiniteDifferenceFunctionType::Pointer dfb = this->GetBackwardDifferenceFunction(); if ( dff->GetRadius() != dfb->GetRadius()) { itkExceptionMacro(<<"Forward and backward FiniteDifferenceFunctions not in sync"); } const SizeType radius = dff->GetRadius(); // Break the input into a series of regions. The first region is free // of boundary conditions, the rest with boundary conditions. We operate // on the output region because input has been copied to output. typedef NeighborhoodAlgorithm::ImageBoundaryFacesCalculator FaceCalculatorType; typedef typename FaceCalculatorType::FaceListType FaceListType; FaceCalculatorType faceCalculator; FaceListType faceList = faceCalculator(output, regionToProcess, radius); typename FaceListType::iterator fIt = faceList.begin(); // Ask the function object for a pointer to a data structure it // will use to manage any global values it needs. We'll pass this // back to the function object at each calculation and then // again so that the function object can use it to determine a // time step for this iteration. void *globalDataf = dff->GetGlobalDataPointer(); void *globalDatab = dfb->GetGlobalDataPointer(); // Process the non-boundary region. NeighborhoodIteratorType nD(radius, output, *fIt); if ( m_NumberOfBCHApproximationTerms == 2 ) { UpdateIteratorType nU(this->GetUpdateBuffer(), *fIt); while( !nD.IsAtEnd() ) { nU.Value() = (dff->ComputeUpdate(nD, globalDataf)-dfb->ComputeUpdate(nD, globalDatab))*0.5; ++nD; ++nU; } // Process each of the boundary faces. NeighborhoodIteratorType bD; UpdateIteratorType bU; for (++fIt; fIt != faceList.end(); ++fIt) { bD = NeighborhoodIteratorType(radius, output, *fIt); bU = UpdateIteratorType (this->GetUpdateBuffer(), *fIt); while ( !bD.IsAtEnd() ) { bU.Value() = (dff->ComputeUpdate(bD, globalDataf)-dfb->ComputeUpdate(bD, globalDatab))*0.5; ++bD; ++bU; } } } else { UpdateIteratorType nUF(this->GetUpdateBuffer(), *fIt); UpdateIteratorType nUB(this->GetBackwardUpdateBuffer(), *fIt); while( !nD.IsAtEnd() ) { nUF.Value() = dff->ComputeUpdate(nD, globalDataf); nUB.Value() = dfb->ComputeUpdate(nD, globalDatab); ++nD; ++nUF; ++nUB; } // Process each of the boundary faces. NeighborhoodIteratorType bD; UpdateIteratorType bUF; UpdateIteratorType bUB; for (++fIt; fIt != faceList.end(); ++fIt) { bD = NeighborhoodIteratorType(radius, output, *fIt); bUF = UpdateIteratorType (this->GetUpdateBuffer(), *fIt); bUB = UpdateIteratorType (this->GetBackwardUpdateBuffer(), *fIt); while ( !bD.IsAtEnd() ) { bUF.Value() = dff->ComputeUpdate(bD, globalDataf); bUB.Value() = dfb->ComputeUpdate(bD, globalDatab); ++bD; ++bUF; ++bUB; } } } // Ask the finite difference function to compute the time step for // this iteration. We give it the global data pointer to use, then // ask it to free the global data memory. TimeStepType timeStep = 0.5*( dff->ComputeGlobalTimeStep(globalDataf) + dfb->ComputeGlobalTimeStep(globalDatab) ); dff->ReleaseGlobalDataPointer(globalDataf); dfb->ReleaseGlobalDataPointer(globalDatab); return timeStep; } // Get the metric value from the difference function template void SymmetricLogDomainDemonsRegistrationFilter ::ApplyUpdate(TimeStepType dt) { const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); this->SetRMSChange( 0.5*(drfpf->GetRMSChange() + drfpb->GetRMSChange()) ); if ( this->m_NumberOfBCHApproximationTerms < 3 ) { // If we smooth the update buffer before applying it, then the are // approximating a viscuous problem as opposed to an elastic problem if ( this->GetSmoothUpdateField() ) { this->SmoothUpdateField(); } // Use time step if necessary. In many cases // the time step is one so this will be skipped if ( fabs(dt - 1.0)>1.0e-4 ) { itkDebugMacro( "Using timestep: " << dt ); m_Multiplier->SetConstant( dt ); m_Multiplier->SetInput( this->GetUpdateBuffer() ); m_Multiplier->GraftOutput( this->GetUpdateBuffer() ); // in place update m_Multiplier->Update(); // graft output back to this->GetUpdateBuffer() this->GetUpdateBuffer()->Graft( m_Multiplier->GetOutput() ); } // Apply update m_Adder->SetInput( 0, this->GetOutput() ); m_Adder->SetInput( 1, this->GetUpdateBuffer() ); m_Adder->GraftOutput( this->GetOutput() ); m_Adder->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); // Triggers in place update m_Adder->Update(); // Region passing stuff this->GraftOutput( m_Adder->GetOutput() ); } else { // If we smooth the update buffer before applying it, then the are // approximating a viscuous problem as opposed to an elastic problem if ( this->GetSmoothUpdateField() ) { this->SmoothUpdateField(); this->SmoothBackwardUpdateField(); } // Use time step if necessary. In many cases // the time step is one so this will be skipped if ( fabs(dt - 1.0)>1.0e-4 ) { itkDebugMacro( "Using timestep: " << dt ); m_Multiplier->SetConstant( dt ); m_Multiplier->SetInput( this->GetUpdateBuffer() ); m_Multiplier->GraftOutput( this->GetUpdateBuffer() ); // in place update m_Multiplier->Update(); // graft output back to this->GetUpdateBuffer() this->GetUpdateBuffer()->Graft( m_Multiplier->GetOutput() ); m_Multiplier->SetInput( this->GetBackwardUpdateBuffer() ); m_Multiplier->GraftOutput( this->GetBackwardUpdateBuffer() ); // in place update m_Multiplier->Update(); // graft output back to this->GetUpdateBuffer() this->GetBackwardUpdateBuffer()->Graft( m_Multiplier->GetOutput() ); } // Apply update (declare the filters here as efficiency is not critical // with "high" order BCH approximations) typedef VelocityFieldBCHCompositionFilter< VelocityFieldType, VelocityFieldType> BCHFilterType; typename BCHFilterType::Pointer bchfilter = BCHFilterType::New(); bchfilter->SetNumberOfApproximationTerms( this->m_NumberOfBCHApproximationTerms ); // First get Z( v, K_fluid * u_forward ) bchfilter->SetInput( 0, this->GetOutput() ); bchfilter->SetInput( 1, this->GetUpdateBuffer() ); bchfilter->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); bchfilter->Update(); VelocityFieldPointer Zf = bchfilter->GetOutput(); Zf->DisconnectPipeline(); // Now get Z( -v, K_fluid * u_backward ) typedef OppositeImageFilter< VelocityFieldType, VelocityFieldType> OppositeFilterType; typename OppositeFilterType::Pointer oppositefilter = OppositeFilterType::New(); oppositefilter->SetInput( this->GetOutput() ); oppositefilter->InPlaceOn(); bchfilter->SetInput( 0, oppositefilter->GetOutput() ); bchfilter->SetInput( 1, this->GetBackwardUpdateBuffer() ); bchfilter->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); bchfilter->Update(); VelocityFieldPointer Zb = bchfilter->GetOutput(); Zb->DisconnectPipeline(); // Finally get 0.5*( Z( v, K_fluid * u_forward ) - Z( -v, K_fluid * u_backward ) ) typedef SubtractImageFilter< VelocityFieldType, VelocityFieldType, VelocityFieldType> SubtracterType; typename SubtracterType::Pointer subtracter = SubtracterType::New(); subtracter->SetInput( 0, Zf ); subtracter->SetInput( 1, Zb ); subtracter->GraftOutput( this->GetOutput() ); m_Multiplier->SetConstant( 0.5 ); m_Multiplier->SetInput( subtracter->GetOutput() ); m_Multiplier->GraftOutput( this->GetOutput() ); // Triggers in place update m_Multiplier->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); m_Multiplier->Update(); // Region passing stuff this->GraftOutput( m_Multiplier->GetOutput() ); } // Smooth the velocity field if( this->GetSmoothVelocityField() ) { this->SmoothVelocityField(); } } template void SymmetricLogDomainDemonsRegistrationFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << "Intensity difference threshold: " << this->GetIntensityDifferenceThreshold() << std::endl; os << indent << "Multiplier: " << m_Multiplier << std::endl; os << indent << "Adder: " << m_Adder << std::endl; os << indent << "NumberOfBCHApproximationTerms: " << m_NumberOfBCHApproximationTerms << std::endl; } } // end namespace itk #endif itkSymmetricLogDomainDemonsRegistrationFilterWithMaskExtension.h000066400000000000000000000244261321604176500461040ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkSymmetricLogDomainDemonsRegistrationFilterWithMaskExtension_h #define __itkSymmetricLogDomainDemonsRegistrationFilterWithMaskExtension_h #include "itkLogDomainDeformableRegistrationFilter.h" #include "itkESMDemonsRegistrationWithMaskFunction.h" #if ITK_VERSION_MAJOR >= 4 #include "itkMultiplyImageFilter.h" #else #include "itkMultiplyByConstantImageFilter.h" #endif namespace itk { /** * \class SymmetricLogDomainDemonsRegistrationFilter * \brief Deformably register two images using a diffeomorphic demons algorithm * and a symmetrized optimization scheme. * * See T. Vercauteren, X. Pennec, A. Perchant and N. Ayache, * "Symmetric Log-Domain Diffeomorphic Registration: A Demons-based Approach", * Proc. of MICCAI 2008. * * Velocity and deformation fields are represented as images whose pixel type are * some vector type with at least N elements, where N is the dimension of * the fixed image. The vector type must support element access via operator * []. It is assumed that the vector elements behave like floating point * scalars. * * This class is templated over the fixed image type, moving image type * and the velocity/deformation field type. * * The input fixed and moving images are set via methods SetFixedImage * and SetMovingImage respectively. An initial velocity field maybe set via * SetInitialVelocityField or SetInput. If no initial field is set, * a zero field is used as the initial condition. * * The output velocity field can be obtained via methods GetOutput * or GetVelocityField. * * The output deformation field can be obtained via method GetDeformationField. * * This class make use of the finite difference solver hierarchy. Update * for each iteration is computed using a PDEDeformableRegistrationFunction. * * \warning This filter assumes that the fixed image type, moving image type * and velocity field type all have the same number of dimensions. * * \sa DemonsRegistrationFilter * \sa DemonsRegistrationFunction * \ingroup DeformableImageRegistration MultiThreaded * \author Florence Dru, INRIA and Tom Vercauteren, MKT * * Extension (by Bene): -- Methods to set/get Masks * - using itk::ESMDemonsRegistrationWithMaskExtension */ template class ITK_EXPORT SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension : public LogDomainDeformableRegistrationFilter { public: /** Standard class typedefs. */ typedef SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension Self; typedef LogDomainDeformableRegistrationFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods) */ itkTypeMacro( SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension,LogDomainDeformableRegistrationFilter ); /** FixedImage image type. */ typedef typename Superclass::FixedImageType FixedImageType; typedef typename Superclass::FixedImagePointer FixedImagePointer; /** MovingImage image type. */ typedef typename Superclass::MovingImageType MovingImageType; typedef typename Superclass::MovingImagePointer MovingImagePointer; /** Velocity field type. */ typedef TField VelocityFieldType; typedef typename VelocityFieldType::Pointer VelocityFieldPointer; /** Deformation field type. */ typedef typename Superclass::DeformationFieldType DeformationFieldType; typedef typename Superclass::DeformationFieldPointer DeformationFieldPointer; /** Types inherithed from the superclass */ typedef typename Superclass::OutputImageType OutputImageType; /** FiniteDifferenceFunction type. */ typedef typename Superclass::FiniteDifferenceFunctionType FiniteDifferenceFunctionType; /** Take timestep type from the FiniteDifferenceFunction. */ typedef typename FiniteDifferenceFunctionType::TimeStepType TimeStepType; /** DemonsRegistrationFilterFunction type. */ typedef ESMDemonsRegistrationWithMaskFunction DemonsRegistrationFunctionType; typedef typename DemonsRegistrationFunctionType::Pointer DemonsRegistrationFunctionPointer; typedef typename DemonsRegistrationFunctionType::GradientType GradientType; /** Inherit some enums from the superclass. */ itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension); typedef itk::SpatialObject MaskType; /** Get the metric value. The metric value is the mean square difference * in intensity between the fixed image and transforming moving image * computed over the the overlapping region between the two images. * This value is calculated for the current iteration */ virtual double GetMetric() const; virtual void SetUseGradientType( GradientType gtype ); virtual GradientType GetUseGradientType() const; /** Set/Get the threshold below which the absolute difference of * intensity yields a match. When the intensities match between a * moving and fixed image pixel, the update vector (for that * iteration) will be the zero vector. Default is 0.001. */ virtual void SetIntensityDifferenceThreshold(double); virtual double GetIntensityDifferenceThreshold() const; /** Set/Get the maximum length in terms of pixels of * the vectors in the update buffer. */ virtual void SetMaximumUpdateStepLength(double); virtual double GetMaximumUpdateStepLength() const; /** Set/Get the number of terms used in the Baker-Campbell-Hausdorff approximation. */ itkSetMacro( NumberOfBCHApproximationTerms, unsigned int ); itkGetConstMacro( NumberOfBCHApproximationTerms, unsigned int ); /**Extension */ virtual void SetMovingImageMask( MaskType *mask); /**Extension */ virtual void SetFixedImageMask(MaskType *mask); /**Extension */ virtual const MaskType * GetMovingImageMask() const; /**Extension */ virtual const MaskType * GetFixedImageMask() const; protected: SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension(); ~SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension() {} void PrintSelf(std::ostream& os, Indent indent) const; /** Initialize the state of filter and equation before each iteration. */ virtual void InitializeIteration(); /** This method allocates storage in m_UpdateBuffer. It is called from * FiniteDifferenceFilter::GenerateData(). */ virtual void AllocateUpdateBuffer(); /** Method to allow subclasses to get direct access to the backward update * buffer */ virtual VelocityFieldType* GetBackwardUpdateBuffer() { return m_BackwardUpdateBuffer; } /** This method allocates storage in m_BackwardUpdateBuffer. */ virtual void AllocateBackwardUpdateBuffer(); /** Utility to smooth the BackwardUpdateBuffer using a Gaussian operator. * The amount of smoothing is specified by the UpdateFieldStandardDeviations. */ virtual void SmoothBackwardUpdateField(); typedef typename VelocityFieldType::RegionType ThreadRegionType; /** Does the actual work of calculating change over a region supplied by * the multithreading mechanism. */ #if ITK_VERSION_MAJOR >=4 virtual TimeStepType ThreadedCalculateChange( const ThreadRegionType ®ionToProcess, ThreadIdType threadId); #else virtual TimeStepType ThreadedCalculateChange( const ThreadRegionType ®ionToProcess, int threadId); #endif /** Apply update. */ #if (ITK_VERSION_MAJOR >= 4) virtual void ApplyUpdate(const TimeStepType& dt); #else virtual void ApplyUpdate(TimeStepType dt); #endif /** This method returns a pointer to a FiniteDifferenceFunction object that * will be used by the filter to calculate updates at image pixels. * \returns A FiniteDifferenceObject pointer. */ itkGetConstReferenceObjectMacro(BackwardDifferenceFunction, FiniteDifferenceFunctionType ); /** This method sets the pointer to a FiniteDifferenceFunction object that * will be used by the filter to calculate updates at image pixels. * \returns A FiniteDifferenceObject pointer. */ itkSetObjectMacro(BackwardDifferenceFunction, FiniteDifferenceFunctionType ); private: SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented /** Downcast the DifferenceFunction using a dynamic_cast to ensure that it is of the correct type. * this method will throw an exception if the function is not of the expected type. */ DemonsRegistrationFunctionType * GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType * GetForwardRegistrationFunctionType() const; DemonsRegistrationFunctionType * GetBackwardRegistrationFunctionType(); const DemonsRegistrationFunctionType * GetBackwardRegistrationFunctionType() const; /** Exp and composition typedefs */ #if ITK_VERSION_MAJOR >= 4 typedef MultiplyImageFilter< VelocityFieldType,itk::Image, VelocityFieldType> MultiplyByConstantType; #else typedef MultiplyByConstantImageFilter< VelocityFieldType, TimeStepType, VelocityFieldType> MultiplyByConstantType; #endif typedef AddImageFilter< VelocityFieldType, VelocityFieldType> AdderType; typedef typename MultiplyByConstantType::Pointer MultiplyByConstantPointer; typedef typename AdderType::Pointer AdderPointer; typename FiniteDifferenceFunctionType::Pointer m_BackwardDifferenceFunction; MultiplyByConstantPointer m_Multiplier; AdderPointer m_Adder; unsigned int m_NumberOfBCHApproximationTerms; /** The buffer that holds the updates for an iteration of the algorithm. */ VelocityFieldPointer m_BackwardUpdateBuffer; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkSymmetricLogDomainDemonsRegistrationFilterWithMaskExtension.txx" #endif #endif itkSymmetricLogDomainDemonsRegistrationFilterWithMaskExtension.txx000066400000000000000000000601371321604176500464770ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkSymmetricLogDomainDemonsRegistrationFilterWithMaskExtension_txx #define __itkSymmetricLogDomainDemonsRegistrationFilterWithMaskExtension_txx #include "itkSymmetricLogDomainDemonsRegistrationFilterWithMaskExtension.h" #include "itkOppositeImageFilter.h" #include "itkSubtractImageFilter.h" #include "itkVelocityFieldBCHCompositionFilter.h" namespace itk { // Default constructor template SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension() { DemonsRegistrationFunctionPointer drfpf = DemonsRegistrationFunctionType::New(); this->SetDifferenceFunction( static_cast( drfpf.GetPointer() ) ); DemonsRegistrationFunctionPointer drfpb = DemonsRegistrationFunctionType::New(); this->SetBackwardDifferenceFunction( static_cast( drfpb.GetPointer() ) ); m_Multiplier = MultiplyByConstantType::New(); m_Multiplier->InPlaceOn(); m_Adder = AdderType::New(); m_Adder->InPlaceOn(); // Set number of terms in the BCH approximation to default value m_NumberOfBCHApproximationTerms = 2; m_BackwardUpdateBuffer = 0; } // Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. template typename SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::DemonsRegistrationFunctionType* SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::GetForwardRegistrationFunctionType() { DemonsRegistrationFunctionType *drfp = dynamic_cast(this->GetDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } // Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. template const typename SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::DemonsRegistrationFunctionType* SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::GetForwardRegistrationFunctionType() const { const DemonsRegistrationFunctionType *drfp = dynamic_cast(this->GetDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } // Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. template typename SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::DemonsRegistrationFunctionType* SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::GetBackwardRegistrationFunctionType() { DemonsRegistrationFunctionType *drfp = dynamic_cast(this->GetBackwardDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } // Checks whether the DifferenceFunction is of type DemonsRegistrationFunction. template const typename SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::DemonsRegistrationFunctionType* SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::GetBackwardRegistrationFunctionType() const { const DemonsRegistrationFunctionType *drfp = dynamic_cast(this->GetBackwardDifferenceFunction().GetPointer()); if( !drfp ) { itkExceptionMacro( << "Could not cast difference function to SymmetricDemonsRegistrationFunction" ); } return drfp; } // Set the function state values before each iteration template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::InitializeIteration() { // update variables in the equation object DemonsRegistrationFunctionType *f = this->GetForwardRegistrationFunctionType(); #if ITK_VERSION_MAJOR >= 4 f->SetDisplacementField( this->GetDeformationField() ); #else f->SetDeformationField( this->GetDeformationField() ); #endif DemonsRegistrationFunctionType *b = this->GetBackwardRegistrationFunctionType(); b->SetFixedImage( this->GetMovingImage() ); b->SetMovingImage( this->GetFixedImage() ); #if ITK_VERSION_MAJOR >= 4 b->SetDisplacementField( this->GetInverseDisplacementField()); #else b->SetDeformationField( this->GetInverseDisplacementField()); #endif b->InitializeIteration(); // call the superclass implementation ( initializes f ) Superclass::InitializeIteration(); } // Get the metric value from the difference function template double SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::GetMetric() const { const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); return 0.5*(drfpf->GetMetric() + drfpb->GetMetric()); } // Get Intensity Difference Threshold template double SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::GetIntensityDifferenceThreshold() const { const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); if ( drfpf->GetIntensityDifferenceThreshold() != drfpb->GetIntensityDifferenceThreshold()) { itkExceptionMacro(<<"Forward and backward FiniteDifferenceFunctions not in sync"); } return drfpf->GetIntensityDifferenceThreshold(); } // Set Intensity Difference Threshold template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::SetIntensityDifferenceThreshold(double threshold) { DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); drfpf->SetIntensityDifferenceThreshold(threshold); drfpb->SetIntensityDifferenceThreshold(threshold); } // Set Maximum Update Step Length template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::SetMaximumUpdateStepLength(double step) { DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); drfpf->SetMaximumUpdateStepLength(step); drfpb->SetMaximumUpdateStepLength(step); } // Get Maximum Update Step Length template double SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::GetMaximumUpdateStepLength() const { const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); if ( drfpf->GetMaximumUpdateStepLength() != drfpb->GetMaximumUpdateStepLength()) { itkExceptionMacro(<<"Forward and backward FiniteDifferenceFunctions not in sync"); } return drfpf->GetMaximumUpdateStepLength(); } // Get gradient type template typename SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension::GradientType SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::GetUseGradientType() const { const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); if ( drfpf->GetUseGradientType() != drfpb->GetUseGradientType()) { itkExceptionMacro(<<"Forward and backward FiniteDifferenceFunctions not in sync"); } return drfpf->GetUseGradientType(); } // Set gradient type template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::SetUseGradientType(GradientType gtype) { DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); drfpf->SetUseGradientType(gtype); drfpb->SetUseGradientType(gtype); } template const typename SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension::MaskType * SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::GetMovingImageMask() const { /*const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetMovingImageMask(); */ const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); if ( drfpf->GetMaximumUpdateStepLength() != drfpb->GetMaximumUpdateStepLength()) { itkExceptionMacro(<<"Forward and backward FiniteDifferenceFunctions not in sync"); } return drfpf->GetMovingImageMask(); } template const typename SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension::MaskType * SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::GetFixedImageMask() const { /*const DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); return drfp->GetFixedImageMask(); */ const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); if ( drfpf->GetMaximumUpdateStepLength() != drfpb->GetMaximumUpdateStepLength()) { itkExceptionMacro(<<"Forward and backward FiniteDifferenceFunctions not in sync"); } return drfpf->GetFixedImageMask(); } /** * */ template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::SetMovingImageMask(MaskType *mask) { /*DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetMovingImageMask(mask); */ DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); drfpf->SetMovingImageMask(mask); drfpb->SetMovingImageMask(mask); } /** * */ template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::SetFixedImageMask(MaskType *mask) { /*DemonsRegistrationFunctionType *drfp = this->DownCastDifferenceFunctionType(); drfp->SetFixedImageMask(mask); */ DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); drfpf->SetFixedImageMask(mask); drfpb->SetFixedImageMask(mask); } // Allocate storage in m_UpdateBuffer template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::AllocateUpdateBuffer() { Superclass::AllocateUpdateBuffer(); this->AllocateBackwardUpdateBuffer(); } // Allocates storage in m_BackwardUpdateBuffer template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::AllocateBackwardUpdateBuffer() { if ( m_NumberOfBCHApproximationTerms < 3 ) { m_BackwardUpdateBuffer = 0; return; } // The backward update buffer looks just like the output. //VelocityFieldPointer output = this->GetOutput(); VelocityFieldPointer output = this->GetVelocityField(); if ( !m_BackwardUpdateBuffer ) m_BackwardUpdateBuffer = VelocityFieldType::New(); m_BackwardUpdateBuffer->SetOrigin(output->GetOrigin()); m_BackwardUpdateBuffer->SetSpacing(output->GetSpacing()); m_BackwardUpdateBuffer->SetDirection(output->GetDirection()); m_BackwardUpdateBuffer->SetLargestPossibleRegion(output->GetLargestPossibleRegion()); m_BackwardUpdateBuffer->SetRequestedRegion(output->GetRequestedRegion()); m_BackwardUpdateBuffer->SetBufferedRegion(output->GetBufferedRegion()); m_BackwardUpdateBuffer->Allocate(); } // Smooth the backward update field using a separable Gaussian kernel template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::SmoothBackwardUpdateField() { // The update buffer will be overwritten with new data. this->SmoothGivenField(this->GetBackwardUpdateBuffer(), this->GetUpdateFieldStandardDeviations()); } template typename SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension::TimeStepType SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension #if ITK_VERSION_MAJOR >= 4 ::ThreadedCalculateChange(const ThreadRegionType ®ionToProcess, ThreadIdType) #else ::ThreadedCalculateChange(const ThreadRegionType ®ionToProcess, int) #endif { typedef typename VelocityFieldType::RegionType RegionType; typedef typename VelocityFieldType::SizeType SizeType; typedef typename VelocityFieldType::SizeValueType SizeValueType; typedef typename VelocityFieldType::IndexType IndexType; typedef typename VelocityFieldType::IndexValueType IndexValueType; typedef typename FiniteDifferenceFunctionType::NeighborhoodType NeighborhoodIteratorType; typedef ImageRegionIterator UpdateIteratorType; VelocityFieldPointer output = this->GetVelocityField(); // Get the FiniteDifferenceFunction to use in calculations. const typename FiniteDifferenceFunctionType::Pointer dff = this->GetDifferenceFunction(); const typename FiniteDifferenceFunctionType::Pointer dfb = this->GetBackwardDifferenceFunction(); if ( dff->GetRadius() != dfb->GetRadius()) { itkExceptionMacro(<<"Forward and backward FiniteDifferenceFunctions not in sync"); } const SizeType radius = dff->GetRadius(); // Break the input into a series of regions. The first region is free // of boundary conditions, the rest with boundary conditions. We operate // on the output region because input has been copied to output. typedef NeighborhoodAlgorithm::ImageBoundaryFacesCalculator FaceCalculatorType; typedef typename FaceCalculatorType::FaceListType FaceListType; FaceCalculatorType faceCalculator; FaceListType faceList = faceCalculator(output, regionToProcess, radius); typename FaceListType::iterator fIt = faceList.begin(); // Ask the function object for a pointer to a data structure it // will use to manage any global values it needs. We'll pass this // back to the function object at each calculation and then // again so that the function object can use it to determine a // time step for this iteration. void *globalDataf = dff->GetGlobalDataPointer(); void *globalDatab = dfb->GetGlobalDataPointer(); // Process the non-boundary region. NeighborhoodIteratorType nD(radius, output, *fIt); if ( m_NumberOfBCHApproximationTerms == 2 ) { UpdateIteratorType nU(this->GetUpdateBuffer(), *fIt); while( !nD.IsAtEnd() ) { nU.Value() = (dff->ComputeUpdate(nD, globalDataf)-dfb->ComputeUpdate(nD, globalDatab))*0.5; ++nD; ++nU; } // Process each of the boundary faces. NeighborhoodIteratorType bD; UpdateIteratorType bU; for (++fIt; fIt != faceList.end(); ++fIt) { bD = NeighborhoodIteratorType(radius, output, *fIt); bU = UpdateIteratorType (this->GetUpdateBuffer(), *fIt); while ( !bD.IsAtEnd() ) { bU.Value() = (dff->ComputeUpdate(bD, globalDataf)-dfb->ComputeUpdate(bD, globalDatab))*0.5; ++bD; ++bU; } } } else { UpdateIteratorType nUF(this->GetUpdateBuffer(), *fIt); UpdateIteratorType nUB(this->GetBackwardUpdateBuffer(), *fIt); while( !nD.IsAtEnd() ) { nUF.Value() = dff->ComputeUpdate(nD, globalDataf); nUB.Value() = dfb->ComputeUpdate(nD, globalDatab); ++nD; ++nUF; ++nUB; } // Process each of the boundary faces. NeighborhoodIteratorType bD; UpdateIteratorType bUF; UpdateIteratorType bUB; for (++fIt; fIt != faceList.end(); ++fIt) { bD = NeighborhoodIteratorType(radius, output, *fIt); bUF = UpdateIteratorType (this->GetUpdateBuffer(), *fIt); bUB = UpdateIteratorType (this->GetBackwardUpdateBuffer(), *fIt); while ( !bD.IsAtEnd() ) { bUF.Value() = dff->ComputeUpdate(bD, globalDataf); bUB.Value() = dfb->ComputeUpdate(bD, globalDatab); ++bD; ++bUF; ++bUB; } } } // Ask the finite difference function to compute the time step for // this iteration. We give it the global data pointer to use, then // ask it to free the global data memory. TimeStepType timeStep = 0.5*( dff->ComputeGlobalTimeStep(globalDataf) + dfb->ComputeGlobalTimeStep(globalDatab) ); dff->ReleaseGlobalDataPointer(globalDataf); dfb->ReleaseGlobalDataPointer(globalDatab); return timeStep; } // Get the metric value from the difference function template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension #if ITK_VERSION_MAJOR >= 4 ::ApplyUpdate(const TimeStepType& dt) #else ::ApplyUpdate(TimeStepType dt) #endif { const DemonsRegistrationFunctionType *drfpf = this->GetForwardRegistrationFunctionType(); const DemonsRegistrationFunctionType *drfpb = this->GetBackwardRegistrationFunctionType(); this->SetRMSChange( 0.5*(drfpf->GetRMSChange() + drfpb->GetRMSChange()) ); if ( this->m_NumberOfBCHApproximationTerms < 3 ) { // If we smooth the update buffer before applying it, then the are // approximating a viscuous problem as opposed to an elastic problem if ( this->GetSmoothUpdateField() ) { this->SmoothUpdateField(); } // Use time step if necessary. In many cases // the time step is one so this will be skipped if ( fabs(dt - 1.0)>1.0e-4 ) { itkDebugMacro( "Using timestep: " << dt ); m_Multiplier->SetConstant( dt ); m_Multiplier->SetInput( this->GetUpdateBuffer() ); m_Multiplier->GraftOutput( this->GetUpdateBuffer() ); // in place update m_Multiplier->Update(); // graft output back to this->GetUpdateBuffer() this->GetUpdateBuffer()->Graft( m_Multiplier->GetOutput() ); } // Apply update m_Adder->SetInput( 0, this->GetOutput() ); m_Adder->SetInput( 1, this->GetUpdateBuffer() ); m_Adder->GraftOutput( this->GetOutput() ); m_Adder->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); // Triggers in place update m_Adder->Update(); // Region passing stuff this->GraftOutput( m_Adder->GetOutput() ); } else { // If we smooth the update buffer before applying it, then the are // approximating a viscuous problem as opposed to an elastic problem if ( this->GetSmoothUpdateField() ) { this->SmoothUpdateField(); this->SmoothBackwardUpdateField(); } // Use time step if necessary. In many cases // the time step is one so this will be skipped if ( fabs(dt - 1.0)>1.0e-4 ) { itkDebugMacro( "Using timestep: " << dt ); m_Multiplier->SetConstant( dt ); m_Multiplier->SetInput( this->GetUpdateBuffer() ); m_Multiplier->GraftOutput( this->GetUpdateBuffer() ); // in place update m_Multiplier->Update(); // graft output back to this->GetUpdateBuffer() this->GetUpdateBuffer()->Graft( m_Multiplier->GetOutput() ); m_Multiplier->SetInput( this->GetBackwardUpdateBuffer() ); m_Multiplier->GraftOutput( this->GetBackwardUpdateBuffer() ); // in place update m_Multiplier->Update(); // graft output back to this->GetUpdateBuffer() this->GetBackwardUpdateBuffer()->Graft( m_Multiplier->GetOutput() ); } // Apply update (declare the filters here as efficiency is not critical // with "high" order BCH approximations) typedef VelocityFieldBCHCompositionFilter< VelocityFieldType, VelocityFieldType> BCHFilterType; typename BCHFilterType::Pointer bchfilter = BCHFilterType::New(); bchfilter->SetNumberOfApproximationTerms( this->m_NumberOfBCHApproximationTerms ); // First get Z( v, K_fluid * u_forward ) bchfilter->SetInput( 0, this->GetOutput() ); bchfilter->SetInput( 1, this->GetUpdateBuffer() ); bchfilter->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); bchfilter->Update(); VelocityFieldPointer Zf = bchfilter->GetOutput(); Zf->DisconnectPipeline(); // Now get Z( -v, K_fluid * u_backward ) typedef OppositeImageFilter< VelocityFieldType, VelocityFieldType> OppositeFilterType; typename OppositeFilterType::Pointer oppositefilter = OppositeFilterType::New(); oppositefilter->SetInput( this->GetOutput() ); oppositefilter->InPlaceOn(); bchfilter->SetInput( 0, oppositefilter->GetOutput() ); bchfilter->SetInput( 1, this->GetBackwardUpdateBuffer() ); bchfilter->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); bchfilter->Update(); VelocityFieldPointer Zb = bchfilter->GetOutput(); Zb->DisconnectPipeline(); // Finally get 0.5*( Z( v, K_fluid * u_forward ) - Z( -v, K_fluid * u_backward ) ) typedef SubtractImageFilter< VelocityFieldType, VelocityFieldType, VelocityFieldType> SubtracterType; typename SubtracterType::Pointer subtracter = SubtracterType::New(); subtracter->SetInput( 0, Zf ); subtracter->SetInput( 1, Zb ); subtracter->GraftOutput( this->GetOutput() ); m_Multiplier->SetConstant( 0.5 ); m_Multiplier->SetInput( subtracter->GetOutput() ); m_Multiplier->GraftOutput( this->GetOutput() ); // Triggers in place update m_Multiplier->GetOutput()->SetRequestedRegion( this->GetOutput()->GetRequestedRegion() ); m_Multiplier->Update(); // Region passing stuff this->GraftOutput( m_Multiplier->GetOutput() ); } // Smooth the velocity field if( this->GetSmoothVelocityField() ) { this->SmoothVelocityField(); } } template void SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << "Intensity difference threshold: " << this->GetIntensityDifferenceThreshold() << std::endl; os << indent << "Multiplier: " << m_Multiplier << std::endl; os << indent << "Adder: " << m_Adder << std::endl; os << indent << "NumberOfBCHApproximationTerms: " << m_NumberOfBCHApproximationTerms << std::endl; } } // end namespace itk #endif itkVelocityFieldBCHCompositionFilter.h000066400000000000000000000130321321604176500405220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkVelocityFieldBCHCompositionFilter_h #define __itkVelocityFieldBCHCompositionFilter_h #include #include #include #if ITK_VERSION_MAJOR >= 4 #include #else #include #endif namespace itk { /** \class VelocityFieldBCHCompositionFilter * \brief Compute Baker-Campbell-Hausdorff formula on two vector fields. * * See M. Bossa, M. Hernandez and S.Olmos, "Contributions to 3D diffeomorphic atlas * estimation: Application to brain images", Proc. of MICCAI’07 * and * T. Vercauteren, X. Pennec, A. Perchant and N. Ayache, * "Symmetric Log-Domain Diffeomorphic Registration: A Demons-based Approach", * Proc. of MICCAI 2008. * * This class is templated over the input field type and the output * field type. * * Velocity fields are represented as images whose pixel type are vector type * with N elements, where N is the dimension of the image. * The vector type must support element access via operator[]. It is assumed * that the vector elements behave like floating point scalars. * * The number of approximation terms to used in the BCH approximation is set via * SetNumberOfApproximationTerms method. * * \warning This filter assumes that the input field type and velocity field type * both have the same number of dimensions. * * \author Florence Dru, INRIA and Tom Vercauteren, MKT */ template class ITK_EXPORT VelocityFieldBCHCompositionFilter : public InPlaceImageFilter { public: /** Standard class typedefs. */ typedef VelocityFieldBCHCompositionFilter Self; typedef InPlaceImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Some convenient typedefs. */ typedef TInputImage InputFieldType; typedef typename InputFieldType::PixelType InputFieldPixelType; typedef typename InputFieldType::Pointer InputFieldPointer; typedef typename InputFieldType::ConstPointer InputFieldConstPointer; typedef TOutputImage OutputFieldType; typedef typename OutputFieldType::PixelType OutputFieldPixelType; typedef typename OutputFieldType::Pointer OutputFieldPointer; typedef typename OutputFieldType::ConstPointer OutputFieldConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro( VelocityFieldBCHCompositionFilter, InPlaceImageFilter ); /** Set/Get the NumberOfApproximationTerms used in the BCH approximation. */ itkSetMacro( NumberOfApproximationTerms, unsigned int ); itkGetConstMacro( NumberOfApproximationTerms, unsigned int ); protected: VelocityFieldBCHCompositionFilter(); ~VelocityFieldBCHCompositionFilter() {}; void PrintSelf(std::ostream& os, Indent indent) const; /** * GenerateData() */ void GenerateData(); /** Adder type. */ typedef NaryAddImageFilter AdderType; typedef typename AdderType::Pointer AdderPointer; /** Lie bracket calculator type. */ typedef VelocityFieldLieBracketFilter LieBracketFilterType; typedef typename LieBracketFilterType::Pointer LieBracketFilterPointer; /** Multiplier type. */ #if ITK_VERSION_MAJOR>=4 typedef MultiplyImageFilter, InputFieldType> MultiplierType; #else typedef MultiplyByConstantImageFilter MultiplierType; #endif typedef typename MultiplierType::Pointer MultiplierPointer; /** Set/Get the adder. */ itkSetObjectMacro( Adder, AdderType ); itkGetObjectMacro( Adder, AdderType ); /** Set/Get the multipliers. */ itkSetObjectMacro( Multiplier, MultiplierType ); itkGetObjectMacro( Multiplier, MultiplierType ); itkSetObjectMacro( Multiplier2, MultiplierType ); itkGetObjectMacro( Multiplier2, MultiplierType ); /** Set/Get the Lie bracket filters. */ itkSetObjectMacro( LieBracketFilter, LieBracketFilterType ); itkGetObjectMacro( LieBracketFilter, LieBracketFilterType ); itkSetObjectMacro( LieBracketFilter2, LieBracketFilterType ); itkGetObjectMacro( LieBracketFilter2, LieBracketFilterType ); #if ( ITK_VERSION_MAJOR < 3 ) || ( ITK_VERSION_MAJOR == 3 && ITK_VERSION_MINOR < 13 ) virtual void SetInPlace(const bool b) { // Work-around for http://www.itk.org/Bug/view.php?id=8672 if (b) itkWarningMacro("A more recent version of ITK is required for this filter to run inplace"); this->Superclass::SetInPlace(false); } #endif private: VelocityFieldBCHCompositionFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented AdderPointer m_Adder; LieBracketFilterPointer m_LieBracketFilter; LieBracketFilterPointer m_LieBracketFilter2; MultiplierPointer m_Multiplier; MultiplierPointer m_Multiplier2; unsigned int m_NumberOfApproximationTerms; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkVelocityFieldBCHCompositionFilter.txx" #endif #endif itkVelocityFieldBCHCompositionFilter.txx000066400000000000000000000120021321604176500411120ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkVelocityFieldBCHCompositionFilter_txx #define __itkVelocityFieldBCHCompositionFilter_txx #include "itkVelocityFieldBCHCompositionFilter.h" #include namespace itk { /** * Default constructor. */ template VelocityFieldBCHCompositionFilter ::VelocityFieldBCHCompositionFilter() { // Setup the number of required inputs this->SetNumberOfRequiredInputs( 2 ); // By default we shouldn't be inplace this->InPlaceOff(); // Set number of apprximation terms to default value m_NumberOfApproximationTerms = 2; // Declare sub filters m_Adder = AdderType::New(); m_LieBracketFilter = LieBracketFilterType::New(); m_LieBracketFilter2 = LieBracketFilterType::New(); m_Multiplier = MultiplierType::New(); m_Multiplier2 = MultiplierType::New(); // Multipliers can always be inplace here m_Multiplier->InPlaceOn(); m_Multiplier2->InPlaceOn(); m_Multiplier->SetConstant( 0.5 ); m_Multiplier2->SetConstant( 1.0/12.0 ); } /** * Standard PrintSelf method. */ template void VelocityFieldBCHCompositionFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Adder: " << m_Adder << std::endl; os << indent << "LieBracketFilter: " << m_LieBracketFilter << std::endl; os << indent << "LieBracketFilter2: " << m_LieBracketFilter2 << std::endl; os << indent << "Multiplier: " << m_Multiplier << std::endl; os << indent << "Multiplier2: " << m_Multiplier2 << std::endl; os << indent << "NumberOfApproximationTerms: " << m_NumberOfApproximationTerms << std::endl; } /** * GenerateData() */ template void VelocityFieldBCHCompositionFilter ::GenerateData() { InputFieldConstPointer leftField = this->GetInput(0); InputFieldConstPointer rightField = this->GetInput(1); // Create a progress accumulator for tracking the progress of minipipeline ProgressAccumulator::Pointer progress = ProgressAccumulator::New(); progress->SetMiniPipelineFilter(this); switch ( m_NumberOfApproximationTerms ) { case 2: { // lf + rf progress->RegisterInternalFilter(m_Adder, 1.0); m_Adder->SetInput( 0, leftField ); m_Adder->SetInput( 1, rightField ); m_Adder->SetInPlace( this->GetInPlace() ); break; } case 3: { // lf + rf + 0.5*liebracket(lf,rf) progress->RegisterInternalFilter(m_LieBracketFilter, 0.5); progress->RegisterInternalFilter(m_Multiplier, 0.2); progress->RegisterInternalFilter(m_Adder, 0.3); m_LieBracketFilter->SetInput( 0, leftField ); m_LieBracketFilter->SetInput( 1, rightField ); m_Multiplier->SetInput( m_LieBracketFilter->GetOutput() ); // constant set to 0.5 in constructor m_Adder->SetInput( 0, m_Multiplier->GetOutput() ); m_Adder->SetInput( 1, leftField ); m_Adder->SetInput( 2, rightField ); #if ( ITK_VERSION_MAJOR < 3 ) || ( ITK_VERSION_MAJOR == 3 && ITK_VERSION_MINOR < 13 ) // Work-around for http://www.itk.org/Bug/view.php?id=8672 m_Adder->InPlaceOff(); #else // Adder can be inplace since the 0th input is a temp field m_Adder->InPlaceOn(); #endif break; } case 4: { // lf + rf + 0.5*liebracket(lf,rf) + (1/12)*liebracket(lf,*liebracket(lf,rf)) progress->RegisterInternalFilter(m_LieBracketFilter, 0.3); progress->RegisterInternalFilter(m_Multiplier, 0.15); progress->RegisterInternalFilter(m_LieBracketFilter2, 0.3); progress->RegisterInternalFilter(m_Multiplier2, 0.15); progress->RegisterInternalFilter(m_Adder, 0.1); m_LieBracketFilter->SetInput( 0, leftField ); m_LieBracketFilter->SetInput( 1, rightField ); m_LieBracketFilter2->SetInput( 0, leftField ); m_LieBracketFilter2->SetInput( 1, m_LieBracketFilter->GetOutput() ); m_Multiplier->SetInput( m_LieBracketFilter->GetOutput() ); // constant set to 0.5 in constructor m_Multiplier2->SetInput( m_LieBracketFilter2->GetOutput() ); // constant set to 1/12 in constructor m_Adder->SetInput( 0, m_Multiplier->GetOutput() ); m_Adder->SetInput( 1, leftField ); m_Adder->SetInput( 2, rightField ); m_Adder->SetInput( 3, m_Multiplier2->GetOutput() ); #if ( ITK_VERSION_MAJOR < 3 ) || ( ITK_VERSION_MAJOR == 3 && ITK_VERSION_MINOR < 13 ) // Work-around for http://www.itk.org/Bug/view.php?id=8672 m_Adder->InPlaceOff(); #else // Adder can be inplace since the 0th input is a temp field m_Adder->InPlaceOn(); #endif break; } default: { itkExceptionMacro(<< "NumberOfApproximationTerms (" << m_NumberOfApproximationTerms << ") not supported"); } } m_Adder->GraftOutput( this->GetOutput() ); m_Adder->Update(); this->GraftOutput( m_Adder->GetOutput() ); } } // end namespace itk #endif itkVelocityFieldExponentialComposedWithDisplacementFieldFilter.h000066400000000000000000000073661321604176500460300ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkVelocityFieldExponentialComposedWithDisplacementFieldFilter_h_ #define __itkVelocityFieldExponentialComposedWithDisplacementFieldFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorLinearInterpolateNearestNeighborExtrapolateImageFunction.h" // #include "itkVectorLinearInterpolateImageFunction.h" namespace itk { /** \class VelocityFieldExponentialComposedWithDisplacementFieldFilter \brief Computes the composition of a displacement field \phi with the exponential of a velocity field u: exp(u)o\phi This is an alternative to using an exponential and a composition filter. Using both implies at least two resamplings, one for each filter. This class only resamples the velocity field once, which increases the result accuracy. Moreover, a forward Euler method is used to compute the exponential, as it was shown to be more accurate than the scaling and squaring method. \author Pierre Fillard, INRIA Paris */ template< class TVelocityField, class TInputDisplacementField, class TOutputDisplacementField > class VelocityFieldExponentialComposedWithDisplacementFieldFilter: public ImageToImageFilter< TInputDisplacementField, TOutputDisplacementField > { public: typedef VelocityFieldExponentialComposedWithDisplacementFieldFilter Self; typedef ImageToImageFilter< TInputDisplacementField, TOutputDisplacementField > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; itkNewMacro (Self); itkTypeMacro (VelocityFieldExponentialComposedWithDisplacementFieldFilter, ImageToImageFilter); typedef TVelocityField VelocityFieldType; typedef typename VelocityFieldType::PixelType VelocityPixelType; typedef TInputDisplacementField InputImageType; typedef typename InputImageType::PixelType InputPixelType; typedef typename InputImageType::RegionType InputImageRegionType; typedef typename InputImageType::IndexType IndexType; typedef typename InputImageType::PointType PointType; typedef TOutputDisplacementField OutputImageType; typedef typename OutputImageType::PixelType OutputPixelType; typedef typename OutputImageType::RegionType OutputImageRegionType; //typedef VectorLinearInterpolateImageFunction // VelocityFieldInterpolatorType; typedef VectorLinearInterpolateNearestNeighborExtrapolateImageFunction< VelocityFieldType > VelocityFieldInterpolatorType; itkSetObjectMacro (VelocityField, VelocityFieldType); itkGetObjectMacro (VelocityField, VelocityFieldType); /** * Set/Get the number of integration steps to compute the exponential */ itkSetMacro (NumberOfIntegrationSteps, int); itkGetMacro (NumberOfIntegrationSteps, int); /** * If On, compute exp(-u)o\phi instead of exp(u)o\phi */ itkSetMacro (ComputeInverse, bool); itkGetConstMacro (ComputeInverse, bool); itkBooleanMacro (ComputeInverse); protected: VelocityFieldExponentialComposedWithDisplacementFieldFilter(); ~VelocityFieldExponentialComposedWithDisplacementFieldFilter(){} void BeforeThreadedGenerateData(void); void ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, int threadId); private: VelocityFieldExponentialComposedWithDisplacementFieldFilter (const Self &); void operator=(const Self &); typename VelocityFieldType::Pointer m_VelocityField; typename VelocityFieldInterpolatorType::Pointer m_VelocityFieldInterpolator; int m_NumberOfIntegrationSteps; bool m_ComputeInverse; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkVelocityFieldExponentialComposedWithDisplacementFieldFilter.txx" #endif #endif itkVelocityFieldExponentialComposedWithDisplacementFieldFilter.txx000066400000000000000000000060501321604176500464110ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkVelocityFieldExponentialComposedWithDisplacementFieldFilter_txx_ #define __itkVelocityFieldExponentialComposedWithDisplacementFieldFilter_txx_ #include "itkVelocityFieldExponentialComposedWithDisplacementFieldFilter.h" #include #include namespace itk { template< class TVelocityField, class TInputDisplacementField, class TOutputDisplacementField > VelocityFieldExponentialComposedWithDisplacementFieldFilter< TVelocityField, TInputDisplacementField, TOutputDisplacementField > ::VelocityFieldExponentialComposedWithDisplacementFieldFilter() { m_NumberOfIntegrationSteps = 10; m_VelocityField = 0; m_ComputeInverse = false; m_VelocityFieldInterpolator = VelocityFieldInterpolatorType::New(); } template< class TVelocityField, class TInputDisplacementField, class TOutputDisplacementField > void VelocityFieldExponentialComposedWithDisplacementFieldFilter< TVelocityField, TInputDisplacementField, TOutputDisplacementField > ::BeforeThreadedGenerateData() { if ( m_VelocityField.IsNull() ) { itkExceptionMacro (<< "Velocity field must be set"); } if ( m_NumberOfIntegrationSteps <= 0 ) { itkExceptionMacro (<< "Number of integration step cannot be null or negative"); } m_VelocityFieldInterpolator->SetInputImage (m_VelocityField); } template< class TVelocityField, class TInputDisplacementField, class TOutputDisplacementField > void VelocityFieldExponentialComposedWithDisplacementFieldFilter< TVelocityField, TInputDisplacementField, TOutputDisplacementField > ::ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, int threadId) { typename InputImageType::ConstPointer inputField = this->GetInput(); typename OutputImageType::Pointer outputField = this->GetOutput(); typedef ImageRegionConstIteratorWithIndex< InputImageType > InputImageIteratorType; typedef ImageRegionIteratorWithIndex< OutputImageType > OutputImageIteratorType; InputImageIteratorType itIn(inputField, outputRegionForThread); OutputImageIteratorType itOut(outputField, outputRegionForThread); double dt = 1.0 / static_cast< double >(m_NumberOfIntegrationSteps); while ( !itOut.IsAtEnd() ) { InputPixelType vecIn = itIn.Value(); IndexType indexIn = itOut.GetIndex(); PointType pointIn; inputField->TransformIndexToPhysicalPoint (indexIn, pointIn); pointIn = pointIn + vecIn; OutputPixelType vecOut(0.0); for ( int i = 0; i < m_NumberOfIntegrationSteps; i++ ) { PointType pointOut = pointIn + vecOut; OutputPixelType vec = m_VelocityFieldInterpolator->Evaluate (pointOut); if ( m_ComputeInverse ) { vecOut -= vec * dt; } else { vecOut += vec * dt; } } itOut.Set (vecIn + vecOut); ++itIn; ++itOut; } } } // end namespace itk #endif itkVelocityFieldLieBracketFilter.h000066400000000000000000000145101321604176500377110ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkVelocityFieldLieBracketFilter_h #define __itkVelocityFieldLieBracketFilter_h #include #include #include namespace itk { /** \class VelocityFieldLieBracketFilter * \brief Compute the Lie bracket of two vector fields * using the formula [v,u](p) = Jac(v)(p).u(p) − Jac(u)(p).v(p) (1) * * See M. Bossa, M. Hernandez and S.Olmos, "Contributions to 3D diffeomorphic atlas * estimation: Application to brain images", Proc. of MICCAI’07 * and * T. Vercauteren, X. Pennec, A. Perchant and N. Ayache, * "Symmetric Log-Domain Diffeomorphic Registration: A Demons-based Approach", * Proc. of MICCAI 2008. * * \note Most authors define the Lie bracket as the opposite of (1). Numerical simulations, * and personal communication with M. Bossa, showed the relevance of this definition. * Future research will aim at fully understanding the reason of this discrepancy. * * Velocity fields are represented as images whose pixel type are vector type * with N elements, where N is the dimension of the image. * The vector type must support element access via operator[]. It is assumed * that the vector elements behave like floating point scalars. * * This class is templated over the input field type and the output * field type. * * \warning This filter assumes that the input field type and velocity field type * both have the same number of dimensions. * * \author Florence Dru, INRIA and Tom Vercauteren, MKT */ template class ITK_EXPORT VelocityFieldLieBracketFilter : public ImageToImageFilter { public: /** Standard class typedefs. */ typedef VelocityFieldLieBracketFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Some convenient typedefs. */ typedef TInputImage InputFieldType; typedef typename InputFieldType::PixelType InputFieldPixelType; typedef typename InputFieldType::Pointer InputFieldPointer; typedef typename InputFieldType::ConstPointer InputFieldConstPointer; typedef typename InputFieldType::RegionType InputFieldRegionType; typedef TOutputImage OutputFieldType; typedef typename OutputFieldType::PixelType OutputFieldPixelType; typedef typename OutputFieldType::Pointer OutputFieldPointer; typedef typename OutputFieldType::ConstPointer OutputFieldConstPointer; typedef typename OutputFieldType::RegionType OutputFieldRegionType; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro( VelocityFieldLieBracketFilter, ImageToImageFilter ); /** Gradient calculator type. */ typedef itk::VectorCentralDifferenceImageFunction InputFieldGradientCalculatorType; /** Gradient type. */ typedef typename InputFieldGradientCalculatorType::OutputType InputFieldGradientType; /** VelocityFieldLieBracketFilter needs a larger input requested region than * the output requested region. As such, VelocityFieldLieBracketFilter needs * to provide an implementation for GenerateInputRequestedRegion() * in order to inform the pipeline execution model. * * \sa ImageToImageFilter::GenerateInputRequestedRegion() */ virtual void GenerateInputRequestedRegion() throw(InvalidRequestedRegionError); /** ImageDimension constants */ itkStaticConstMacro( InputFieldDimension, unsigned int, TInputImage::ImageDimension); itkStaticConstMacro( OutputFieldDimension, unsigned int, TOutputImage::ImageDimension); itkStaticConstMacro( InputFieldPixelDimension, unsigned int, InputFieldPixelType::Dimension ); itkStaticConstMacro( OutputFieldPixelDimension, unsigned int, OutputFieldPixelType::Dimension ); #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(SameDimensionCheck1, (Concept::SameDimension)); itkConceptMacro(SameDimensionCheck2, (Concept::SameDimension)); itkConceptMacro(SameDimensionCheck3, (Concept::SameDimension)); /** End concept checking */ #endif protected: VelocityFieldLieBracketFilter(); ~VelocityFieldLieBracketFilter() {}; void PrintSelf(std::ostream& os, Indent indent) const; /** VelocityFieldLieBracketFilter can be implemented as a multithreaded filter. * Therefore, this implementation provides a ThreadedGenerateData() routine * which is called for each processing thread. The output image data is * allocated automatically by the superclass prior to calling * ThreadedGenerateData(). ThreadedGenerateData can only write to the * portion of the output image specified by the parameter * "outputRegionForThread" * * \sa ImageToImageFilter::ThreadedGenerateData(), * ImageToImageFilter::GenerateData() */ void ThreadedGenerateData(const OutputFieldRegionType& outputRegionForThread, int threadId ); void BeforeThreadedGenerateData(); /** Set right and left gradient calculators. */ itkSetObjectMacro( RightGradientCalculator, InputFieldGradientCalculatorType ); itkSetObjectMacro( LeftGradientCalculator, InputFieldGradientCalculatorType ); /** Get right and left gradient calculators. */ itkGetObjectMacro( RightGradientCalculator, InputFieldGradientCalculatorType ); itkGetObjectMacro( LeftGradientCalculator, InputFieldGradientCalculatorType ); private: VelocityFieldLieBracketFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented typename InputFieldGradientCalculatorType::Pointer m_RightGradientCalculator; typename InputFieldGradientCalculatorType::Pointer m_LeftGradientCalculator; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkVelocityFieldLieBracketFilter.txx" #endif #endif itkVelocityFieldLieBracketFilter.txx000066400000000000000000000134761321604176500403170ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __itkVelocityFieldLieBracketFilter_txx #define __itkVelocityFieldLieBracketFilter_txx #include "itkVelocityFieldLieBracketFilter.h" #include #include namespace itk { /** * Default constructor. */ template VelocityFieldLieBracketFilter ::VelocityFieldLieBracketFilter() { // Setup the number of required inputs this->SetNumberOfRequiredInputs( 2 ); m_RightGradientCalculator = InputFieldGradientCalculatorType::New(); m_LeftGradientCalculator = InputFieldGradientCalculatorType::New(); } /** * Standard PrintSelf method. */ template void VelocityFieldLieBracketFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Right gradient calculator" << m_RightGradientCalculator << std::endl; os << indent << "Left gradient calculator" << m_LeftGradientCalculator << std::endl; } template void VelocityFieldLieBracketFilter ::GenerateInputRequestedRegion() throw (InvalidRequestedRegionError) { // call the superclass' implementation of this method Superclass::GenerateInputRequestedRegion(); // get pointers to the input and output InputFieldPointer inputPtr0 = const_cast< InputFieldType * >( this->GetInput(0) ); InputFieldPointer inputPtr1 = const_cast< InputFieldType * >( this->GetInput(1) ); OutputFieldPointer outputPtr = this->GetOutput(); if ( !inputPtr0 || !inputPtr1 || !outputPtr ) { return; } // The kernel size is one by default //\todo find a way to get the radius from the gradient calculator const unsigned long radius = 1; // get a copy of the input requested region (should equal the output // requested region) typename TInputImage::RegionType inputRequestedRegion0 = inputPtr0->GetRequestedRegion(); typename TInputImage::RegionType inputRequestedRegion1 = inputPtr1->GetRequestedRegion(); // pad the input requested region by the operator radius inputRequestedRegion0.PadByRadius( radius ); inputRequestedRegion1.PadByRadius( radius ); // crop the input requested region at the input's largest possible region if ( inputRequestedRegion0.Crop(inputPtr0->GetLargestPossibleRegion()) ) { inputPtr0->SetRequestedRegion( inputRequestedRegion0 ); } else { // Couldn't crop the region (requested region is outside the largest // possible region). Throw an exception. // store what we tried to request (prior to trying to crop) inputPtr0->SetRequestedRegion( inputRequestedRegion0 ); // build an exception InvalidRequestedRegionError e(__FILE__, __LINE__); e.SetLocation(ITK_LOCATION); e.SetDescription("Requested region is (at least partially) outside the largest possible region."); e.SetDataObject(inputPtr0); throw e; } if ( inputRequestedRegion1.Crop(inputPtr1->GetLargestPossibleRegion()) ) { inputPtr1->SetRequestedRegion( inputRequestedRegion1 ); } else { // Couldn't crop the region (requested region is outside the largest // possible region). Throw an exception. // store what we tried to request (prior to trying to crop) inputPtr1->SetRequestedRegion( inputRequestedRegion1 ); // build an exception InvalidRequestedRegionError e(__FILE__, __LINE__); e.SetLocation(ITK_LOCATION); e.SetDescription("Requested region is (at least partially) outside the largest possible region."); e.SetDataObject(inputPtr1); throw e; } } template void VelocityFieldLieBracketFilter ::BeforeThreadedGenerateData() { // Initialize gradient calculators m_LeftGradientCalculator->SetInputImage( this->GetInput(0) ); m_RightGradientCalculator->SetInputImage( this->GetInput(1) ); } /** * GenerateData() */ template void VelocityFieldLieBracketFilter ::ThreadedGenerateData( const OutputFieldRegionType &outputRegionForThread, int threadId) { // Get the input and output pointers InputFieldConstPointer leftField = this->GetInput(0); InputFieldConstPointer rightField = this->GetInput(1); OutputFieldPointer outputPtr = this->GetOutput(); // Progress tracking ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); // Input and output iterators/ typedef ImageRegionConstIterator InputFieldIteratorType; typedef ImageRegionIterator OutputFieldIteratorType; InputFieldIteratorType leftIter( leftField, outputRegionForThread ); InputFieldIteratorType rightIter( rightField, outputRegionForThread ); OutputFieldIteratorType outputIter( outputPtr, outputRegionForThread ); InputFieldGradientType leftgrad, rightgrad; while ( ! leftIter.IsAtEnd() ) { leftgrad = m_LeftGradientCalculator->EvaluateAtIndex(leftIter.GetIndex()); rightgrad = m_RightGradientCalculator->EvaluateAtIndex(rightIter.GetIndex()); const InputFieldPixelType & leftval = leftIter.Value(); const InputFieldPixelType & rightval = rightIter.Value(); OutputFieldPixelType & outVal = outputIter.Value(); for (unsigned int d=0; d #include /** * A set of non-obvious matrix functions. Includes the equivalent of * Matlab's logm and expm. * * \author Vincent Arsigny, INRIA, Olivier Commowick, INRIA, and Tom Vercauteren, MKT */ namespace sdtools { /** * Computation of the square root of a reasonnable matrix. * Essential part in the general computation of the matrix logarithm. * Based on a variant (product form) of the classical Denman-Beavers (DB) iteration. **/ template vnl_matrix GetSquareRoot(const vnl_matrix & m, const T precision, vnl_matrix & resultM); /** * Final part of the computation of the log. Estimates the log * with a Pade approximation for a matrix m such that \|m-Id\| <= 0.5. **/ template vnl_matrix GetPadeLogarithm(const vnl_matrix & m, const int numApprox); /** * Computation of the matrix logarithm. Algo: inverse scaling * and squaring, variant proposed by Cheng et al., SIAM Matrix Anal., 2001. **/ template vnl_matrix GetLogarithm(const vnl_matrix & m, const T square_root_precision=1e-11, const int numApprox=1); /** * Computation of the matrix exponential. Algo: classical scaling * and squaring, as in Matlab. See Higham, SIAM Matr. Anal., 2004. */ template vnl_matrix GetExponential(const vnl_matrix & m, const int numApprox=3); /** * Computation of the Log-Euclidean barycenter of matrices, ie the * exponential of the arithmetic mean of their logarithms. **/ template vnl_matrix GetLogEuclideanBarycenter(const std::vector< vnl_matrix > & matrices, const std::vector & weights); /** * Computation of the group barycenter of matrices, ie the left-, * right- and inverse-invariant barycenter. It is similar to the Log-Euclidean * barycenter. Its computation is iterative, whereas there is a closed * form for the LE barycenter. **/ template vnl_matrix GetGroupBarycenter(const std::vector< vnl_matrix > & matrices, const std::vector & weights, const T precision=0.000001); /** * Computation of the Arithmetic barycenter of matrices, ie the * arithmetic mean of the matrices! **/ template vnl_matrix GetArithmeticBarycenter(const std::vector< vnl_matrix > & matrices, const std::vector & weights); } // end namespace #include "vnl_sd_matrix_tools.txx" #endif vnl_sd_matrix_tools.txx000066400000000000000000000310611321604176500360300ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/LOGDomainDemons#ifndef __vnl_sd_matrix_tools_txx #define __vnl_sd_matrix_tools_txx #include "vnl_sd_matrix_tools.h" #include #include #include #include namespace sdtools { template vnl_matrix GetInverse(const vnl_matrix & m) { // Compute the matrix inverse. For dimensions less than 4, // this is basically a copy of the code in vn_inverse (explicit inversion) but avoids // some matrix copies. For arbitrary dimensions, we call vnl_matrix_inverse // which in turn use svd. const unsigned int n = m.rows(); switch (n) { case 1: { return vnl_matrix(n, n, static_cast(1.0)/m(0,0)); } case 2: { const T invdet = static_cast(1.0)/vnl_determinant(m[0], m[1]); vnl_matrix invmat(n, n); invmat(0,0) = m(1,1)*invdet; invmat(0,1) = -m(0,1)*invdet; invmat(1,0) = -m(1,0)*invdet; invmat(1,1) = m(0,0)*invdet; return invmat; } case 3: { const T invdet = static_cast(1.0)/vnl_determinant(m[0], m[1], m[2]); vnl_matrix invmat(n, n); invmat(0,0) = (m(1,1)*m(2,2)-m(1,2)*m(2,1))*invdet; invmat(0,1) = (m(2,1)*m(0,2)-m(2,2)*m(0,1))*invdet; invmat(0,2) = (m(0,1)*m(1,2)-m(0,2)*m(1,1))*invdet; invmat(1,0) = (m(1,2)*m(2,0)-m(1,0)*m(2,2))*invdet; invmat(1,1) = (m(0,0)*m(2,2)-m(0,2)*m(2,0))*invdet; invmat(1,2) = (m(1,0)*m(0,2)-m(1,2)*m(0,0))*invdet; invmat(2,0) = (m(1,0)*m(2,1)-m(1,1)*m(2,0))*invdet; invmat(2,1) = (m(0,1)*m(2,0)-m(0,0)*m(2,1))*invdet; invmat(2,2) = (m(0,0)*m(1,1)-m(0,1)*m(1,0))*invdet; return invmat; } case 4: { const T invdet = static_cast(1.0)/vnl_determinant(m[0], m[1], m[2], m[3]); vnl_matrix invmat(n, n); invmat(0,0) = ( m(1,1)*m(2,2)*m(3,3) - m(1,1)*m(2,3)*m(3,2) - m(2,1)*m(1,2)*m(3,3) +m(2,1)*m(1,3)*m(3,2) + m(3,1)*m(1,2)*m(2,3) - m(3,1)*m(1,3)*m(2,2))*invdet; invmat(0,1) = (-m(0,1)*m(2,2)*m(3,3) + m(0,1)*m(2,3)*m(3,2) + m(2,1)*m(0,2)*m(3,3) - m(2,1)*m(0,3)*m(3,2) - m(3,1)*m(0,2)*m(2,3) + m(3,1)*m(0,3)*m(2,2))*invdet; invmat(0,2) = ( m(0,1)*m(1,2)*m(3,3) - m(0,1)*m(1,3)*m(3,2) - m(1,1)*m(0,2)*m(3,3) +m(1,1)*m(0,3)*m(3,2) + m(3,1)*m(0,2)*m(1,3) - m(3,1)*m(0,3)*m(1,2))*invdet; invmat(0,3) = (-m(0,1)*m(1,2)*m(2,3) + m(0,1)*m(1,3)*m(2,2) + m(1,1)*m(0,2)*m(2,3) - m(1,1)*m(0,3)*m(2,2) - m(2,1)*m(0,2)*m(1,3) + m(2,1)*m(0,3)*m(1,2))*invdet; invmat(1,0) = (-m(1,0)*m(2,2)*m(3,3) + m(1,0)*m(2,3)*m(3,2) + m(2,0)*m(1,2)*m(3,3) - m(2,0)*m(1,3)*m(3,2) - m(3,0)*m(1,2)*m(2,3) + m(3,0)*m(1,3)*m(2,2))*invdet; invmat(1,1) = ( m(0,0)*m(2,2)*m(3,3) - m(0,0)*m(2,3)*m(3,2) - m(2,0)*m(0,2)*m(3,3) +m(2,0)*m(0,3)*m(3,2) + m(3,0)*m(0,2)*m(2,3) - m(3,0)*m(0,3)*m(2,2))*invdet; invmat(1,2) = (-m(0,0)*m(1,2)*m(3,3) + m(0,0)*m(1,3)*m(3,2) + m(1,0)*m(0,2)*m(3,3) - m(1,0)*m(0,3)*m(3,2) - m(3,0)*m(0,2)*m(1,3) + m(3,0)*m(0,3)*m(1,2))*invdet; invmat(1,3) = ( m(0,0)*m(1,2)*m(2,3) - m(0,0)*m(1,3)*m(2,2) - m(1,0)*m(0,2)*m(2,3) +m(1,0)*m(0,3)*m(2,2) + m(2,0)*m(0,2)*m(1,3) - m(2,0)*m(0,3)*m(1,2))*invdet; invmat(2,0) = ( m(1,0)*m(2,1)*m(3,3) - m(1,0)*m(2,3)*m(3,1) - m(2,0)*m(1,1)*m(3,3) +m(2,0)*m(1,3)*m(3,1) + m(3,0)*m(1,1)*m(2,3) - m(3,0)*m(1,3)*m(2,1))*invdet; invmat(2,1) = (-m(0,0)*m(2,1)*m(3,3) + m(0,0)*m(2,3)*m(3,1) + m(2,0)*m(0,1)*m(3,3) - m(2,0)*m(0,3)*m(3,1) - m(3,0)*m(0,1)*m(2,3) + m(3,0)*m(0,3)*m(2,1))*invdet; invmat(2,2) = ( m(0,0)*m(1,1)*m(3,3) - m(0,0)*m(1,3)*m(3,1) - m(1,0)*m(0,1)*m(3,3) +m(1,0)*m(0,3)*m(3,1) + m(3,0)*m(0,1)*m(1,3) - m(3,0)*m(0,3)*m(1,1))*invdet; invmat(2,3) = (-m(0,0)*m(1,1)*m(2,3) + m(0,0)*m(1,3)*m(2,1) + m(1,0)*m(0,1)*m(2,3) - m(1,0)*m(0,3)*m(2,1) - m(2,0)*m(0,1)*m(1,3) + m(2,0)*m(0,3)*m(1,1))*invdet; invmat(3,0) = (-m(1,0)*m(2,1)*m(3,2) + m(1,0)*m(2,2)*m(3,1) + m(2,0)*m(1,1)*m(3,2) - m(2,0)*m(1,2)*m(3,1) - m(3,0)*m(1,1)*m(2,2) + m(3,0)*m(1,2)*m(2,1))*invdet; invmat(3,1) = ( m(0,0)*m(2,1)*m(3,2) - m(0,0)*m(2,2)*m(3,1) - m(2,0)*m(0,1)*m(3,2) +m(2,0)*m(0,2)*m(3,1) + m(3,0)*m(0,1)*m(2,2) - m(3,0)*m(0,2)*m(2,1))*invdet; invmat(3,2) = (-m(0,0)*m(1,1)*m(3,2) + m(0,0)*m(1,2)*m(3,1) + m(1,0)*m(0,1)*m(3,2) - m(1,0)*m(0,2)*m(3,1) - m(3,0)*m(0,1)*m(1,2) + m(3,0)*m(0,2)*m(1,1))*invdet; invmat(3,3) = ( m(0,0)*m(1,1)*m(2,2) - m(0,0)*m(1,2)*m(2,1) - m(1,0)*m(0,1)*m(2,2) +m(1,0)*m(0,2)*m(2,1) + m(2,0)*m(0,1)*m(1,2) - m(2,0)*m(0,2)*m(1,1))*invdet; return invmat; } default: { // Fall-back to SVD-based inversion return vnl_matrix_inverse(m); } } } template vnl_matrix GetSquareRoot(const vnl_matrix & m, const T precision, vnl_matrix & resultM) { // Declarations vnl_matrix Mk1, Yk1, invMk; unsigned int niter = 1; const unsigned int niterMax = 100; // Initializations vnl_matrix Mk( m ); vnl_matrix Yk( m ); const vnl_matrix Id(m.rows(), m.columns(), vnl_matrix_identity); T energy = (Yk*Yk-m).frobenius_norm(); const double n = m.rows(); // loop while( (niter <= niterMax) && (energy > precision) ) { //std::cout << "niter=" << niter << ", energy=" << energy << "." << std::endl; const T gamma = vcl_pow(vcl_abs(vnl_determinant(Mk)), -1.0/(2.0*n)); const T gamma2 = gamma*gamma; invMk = GetInverse(Mk); Mk1 = ( Id + (Mk*gamma2 + invMk/gamma2)*0.5 )*0.5; Yk1 = Yk*(Id + invMk/gamma2)*(0.5*gamma); Yk = Yk1; Mk = Mk1; energy = (Yk*Yk-m).frobenius_norm(); ++niter; } if (niter > niterMax) { std::cout << std::endl << "Warning, max number of iteration reached in sqrt computation. Final energy is: " << energy << std::endl; } // std::cout << "niter=" << niter << std::endl; resultM = Mk; return Yk; } template vnl_matrix GetPadeLogarithm(const vnl_matrix & m, const int numApprox) { const vnl_matrix Id(m.rows(), m.columns(), vnl_matrix_identity); vnl_matrix interm2, interm3; const vnl_matrix diff = Id - m; const T energy = diff.frobenius_norm(); if (energy > 0.5) { std::cout <<"Warning, matrix is not close enough to Id to call Pade approximation. Frobenius Distance = " << energy <<". Returning original matrix." << std::endl; return m; } switch (numApprox) { case 1: { interm2 = -diff; interm3 = Id - diff*0.5; break; } case 2: { const vnl_matrix sqr = diff*diff; interm2 = sqr*0.5 - diff; interm3 = Id - diff + sqr; break; } case 3: { const vnl_matrix sqr = diff*diff; const vnl_matrix cube = sqr*diff; const double tmpcst = 11.0/60.0; interm2 = sqr + cube*tmpcst - diff; interm3 = Id - diff*1.5 + sqr*0.6 - cube*0.05; break; } default: { std::cerr << "Unsupported numApprox" << std::endl; throw 0; } } return interm2*GetInverse(interm3); } template vnl_matrix GetLogarithm(const vnl_matrix & m, const T square_root_precision, const int numApprox) { ///\todo Use Schur factorization prior to scaling and squaring // Note that this would imply using complex matrices T factor = 1.0; const vnl_matrix Id(m.rows(), m.columns(), vnl_matrix_identity); vnl_matrix resultM; const unsigned int niterMax = 100; unsigned int niter = 1; vnl_matrix Yi( m ); T energy = (Yi-Id).frobenius_norm(); vnl_matrix matrix_sum(m.rows(), m.columns(), 0.0); ///\todo initial version used 0.5 as threshold on the energy /// 0.005 seems better from unit tests -> check theory while ( (energy > 0.005) && (niter <= niterMax) ) { //std::cout << "niter=" << niter << ", energy=" << energy << "." << std::endl; Yi = GetSquareRoot(Yi,square_root_precision,resultM); matrix_sum += (Id-resultM)*factor; energy = (Yi-Id).frobenius_norm(); factor *= 2.0; ++niter; } if (niter > niterMax) { std::cout << std::endl << "Warning, max number of iteration reached in logarithm computation. Final energy is: " << energy << std::endl; } return GetPadeLogarithm(Yi,numApprox)*factor + matrix_sum; } template vnl_matrix GetExponential(const vnl_matrix & m, const int numApprox) { const vnl_matrix Id(m.rows(), m.columns(), vnl_matrix_identity); vnl_matrix interm2, interm3; const T norm = m.frobenius_norm(); int k; if(norm > 1) { k = 1 + static_cast( vcl_ceil( vcl_log(norm)/vnl_math::ln2 ) ); } else if(norm >0.5) { k = 1; } else { k = 0; } // std::cout << "The famous k=" << k << ". Norm=" << norm << std::endl; // Set factor to 2^k const T factor(1< interm = m/factor; switch(numApprox) { case 1: { interm2 = Id + interm*0.5; interm3 = Id - interm*0.5; break; } case 2: { const vnl_matrix sqr = interm*interm; const double tmpcst = 1.0/12.0; interm2 = Id +interm*0.5 + sqr*tmpcst; interm3 = Id -interm*0.5 + sqr*tmpcst; break; } case 3: { const vnl_matrix sqr = interm*interm; const vnl_matrix cube = sqr*interm; const double tmpcst = 1.0/120.0; interm2 = Id + interm*0.5 + sqr*0.1 + cube*tmpcst; interm3 = Id - interm*0.5 + sqr*0.1 - cube*tmpcst; break; } default: { std::cerr << "Unsupported numApprox" << std::endl; throw 0; } } interm = interm2*GetInverse(interm3); for(int i=1; i<=k; ++i) { interm *= interm; } return interm; } template vnl_matrix GetLogEuclideanBarycenter(const std::vector > & matrices, const std::vector & weights) { if ( matrices.empty() || (matrices.size() != weights.size()) ) { std::cerr << std::endl <<"Error: number of transfos =" << matrices.size() << " and is different from the number of weights =" << weights.size() << "." << std::endl; throw 0; } T sum = weights[0]; for(int i=1; i0.000000000001) { std::cerr << std::endl << "Error: sum of weights is not equal to 1 but to " << sum << std::endl; throw 0; } vnl_matrix bar = GetLogarithm(matrices[0])*weights[0]; for(int i=1; i vnl_matrix GetGroupBarycenter(const std::vector > & matrices, const std::vector & weights, const T precision) { const unsigned int niterMax = 60; vnl_matrix interm, invBar; // Initialization vnl_matrix bar = GetLogEuclideanBarycenter(matrices,weights); // Iterative procedure T energy = 1000000000; // anything higher than precision will do unsigned int niter = 1; while ((energy>precision) && (niter <= niterMax)) { invBar = GetInverse(bar); interm = GetLogarithm(invBar*matrices[0])*weights[0]; for(int i=1; i niterMax) { std::cout << std::endl << "Warning, max number of iteration reached in group baryscenter computation. Final energy is: " << energy << std::endl; } return bar; } template vnl_matrix GetArithmeticBarycenter(const std::vector > & matrices, const std::vector & weights) { if ( matrices.empty() || (matrices.size() != weights.size()) ) { std::cerr << std::endl << "Error: number of transfos = " << matrices.size() << " and is different from the number of weights = " << weights.size() << "." << std::endl; throw 0; } T sum = weights[0]; for(int i=1; i0.000000000001) { std::cerr << std::endl << "Error: sum of weights is not equal to 1 but to " << sum << std::endl; throw 0; } vnl_matrix bar = matrices[0]*weights[0]; for(int i=1; i::Max() as a special value. * * \author Tom Vercauteren, INRIA & Mauna Kea Technologies * * This implementation was taken from the Insight Journal paper: * http://hdl.handle.net/1926/510 * * \sa SymmetricForcesDemonsRegistrationFunction * \sa SymmetricForcesDemonsRegistrationFilter * \sa DemonsRegistrationFilter * \sa DemonsRegistrationFunction * \ingroup FiniteDifferenceFunctions * */ template class ITK_EXPORT ESMDemonsRegistrationWithMaskFunction : public PDEDeformableRegistrationFunction { public: /** Standard class typedefs. */ typedef ESMDemonsRegistrationWithMaskFunction Self; typedef PDEDeformableRegistrationFunction< TFixedImage, TMovingImage, TDeformationField> Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro( ESMDemonsRegistrationWithMaskFunction, PDEDeformableRegistrationFunction ); /** MovingImage image type. */ typedef typename Superclass::MovingImageType MovingImageType; typedef typename Superclass::MovingImagePointer MovingImagePointer; typedef typename MovingImageType::PixelType MovingPixelType; /** FixedImage image type. */ typedef typename Superclass::FixedImageType FixedImageType; typedef typename Superclass::FixedImagePointer FixedImagePointer; typedef typename FixedImageType::PixelType FixedPixelType; typedef typename FixedImageType::IndexType IndexType; typedef typename FixedImageType::SizeType SizeType; typedef typename FixedImageType::SpacingType SpacingType; typedef typename FixedImageType::DirectionType DirectionType; /** Deformation field type. */ #if ITK_VERSION_MAJOR>=4 typedef typename Superclass::DisplacementFieldType DeformationFieldType; #else typedef typename Superclass::DeformationFieldType DeformationFieldType; #endif typedef typename DeformationFieldType::Pointer DeformationFieldPointer; /** Inherit some enums from the superclass. */ itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension); typedef SpatialObject MaskType; typedef typename MaskType::Pointer MaskPointer; /** Inherit some enums from the superclass. */ typedef typename Superclass::PixelType PixelType; typedef typename Superclass::RadiusType RadiusType; typedef typename Superclass::NeighborhoodType NeighborhoodType; typedef typename Superclass::FloatOffsetType FloatOffsetType; typedef typename Superclass::TimeStepType TimeStepType; /** Interpolator type. */ typedef double CoordRepType; typedef InterpolateImageFunction< MovingImageType, CoordRepType> InterpolatorType; typedef typename InterpolatorType::Pointer InterpolatorPointer; typedef typename InterpolatorType::PointType PointType; typedef LinearInterpolateImageFunction< MovingImageType, CoordRepType> DefaultInterpolatorType; typedef Point MovingImagePointType; /** Warper type */ typedef WarpImageFilter< MovingImageType, MovingImageType, DeformationFieldType> WarperType; typedef typename WarperType::Pointer WarperPointer; /** Covariant vector type. */ typedef CovariantVector CovariantVectorType; /** Fixed image gradient calculator type. */ typedef CentralDifferenceImageFunction GradientCalculatorType; typedef typename GradientCalculatorType::Pointer GradientCalculatorPointer; /** Moving image gradient (unwarped) calculator type. */ typedef CentralDifferenceImageFunction MovingImageGradientCalculatorType; typedef typename MovingImageGradientCalculatorType::Pointer MovingImageGradientCalculatorPointer; /** Set the moving image interpolator. */ void SetMovingImageInterpolator( InterpolatorType *ptr ) { m_MovingImageInterpolator = ptr; m_MovingImageWarper->SetInterpolator( ptr ); } /** Get the moving image interpolator. */ InterpolatorType * GetMovingImageInterpolator(void) { return m_MovingImageInterpolator; } /** This class uses a constant timestep of 1. */ virtual TimeStepType ComputeGlobalTimeStep( void *itkNotUsed(GlobalData) ) const { return m_TimeStep; } /** Return a pointer to a global data structure that is passed to * this object from the solver at each calculation. */ virtual void * GetGlobalDataPointer() const { GlobalDataStruct *global = new GlobalDataStruct(); global->m_SumOfSquaredDifference = 0.0; global->m_NumberOfPixelsProcessed = 0L; global->m_SumOfSquaredChange = 0; return global; } /** Release memory for global data structure. */ virtual void ReleaseGlobalDataPointer( void *GlobalData ) const; /** Set the object's state before each iteration. */ virtual void InitializeIteration(); /** This method is called by a finite difference solver image filter at * each pixel that does not lie on a data set boundary */ virtual PixelType ComputeUpdate( const NeighborhoodType & neighborhood, void *globalData, const FloatOffsetType & offset = FloatOffsetType(0.0) ); /** Get the metric value. The metric value is the mean square difference * in intensity between the fixed image and transforming moving image * computed over the the overlapping region between the two images. */ virtual double GetMetric() const { return m_Metric; } /** Get the rms change in deformation field. */ virtual const double & GetRMSChange() const { return m_RMSChange; } /** Set/Get the threshold below which the absolute difference of * intensity yields a match. When the intensities match between a * moving and fixed image pixel, the update vector (for that * iteration) will be the zero vector. Default is 0.001. */ virtual void SetIntensityDifferenceThreshold(double); virtual double GetIntensityDifferenceThreshold() const; /** Set/Get the maximum update step length. In Thirion this is 0.5. * Setting it to 0 implies no restriction (beware of numerical * instability in this case. */ virtual void SetMaximumUpdateStepLength(double sm) { this->m_MaximumUpdateStepLength = sm; } virtual double GetMaximumUpdateStepLength() const { return this->m_MaximumUpdateStepLength; } /** Type of available image forces */ enum GradientType { Symmetric = 0, Fixed = 1, WarpedMoving = 2, MappedMoving = 3 }; /** Set/Get the type of used image forces */ virtual void SetUseGradientType( GradientType gtype ) { m_UseGradientType = gtype; } virtual GradientType GetUseGradientType() const { return m_UseGradientType; } virtual void SetMovingImageMask(MaskType *mask) { m_MovingMask = mask; } virtual const MaskType * GetMovingImageMask(void) const { return m_MovingMask; } virtual void SetFixedImageMask(MaskType *mask) { m_FixedMask = mask; } virtual const MaskType * GetFixedImageMask(void) const { return m_FixedMask; } protected: ESMDemonsRegistrationWithMaskFunction(); ~ESMDemonsRegistrationWithMaskFunction() {} void PrintSelf(std::ostream & os, Indent indent) const; /** FixedImage image neighborhood iterator type. */ typedef ConstNeighborhoodIterator FixedImageNeighborhoodIteratorType; /** A global data type for this class of equation. Used to store * iterators for the fixed image. */ struct GlobalDataStruct { double m_SumOfSquaredDifference; unsigned long m_NumberOfPixelsProcessed; double m_SumOfSquaredChange; }; private: ESMDemonsRegistrationWithMaskFunction(const Self &); // purposely not // implemented void operator=(const Self &); // purposely not // implemented /** Cache fixed image information. */ PointType m_FixedImageOrigin; SpacingType m_FixedImageSpacing; DirectionType m_FixedImageDirection; double m_Normalizer; /** Function to compute derivatives of the fixed image. */ GradientCalculatorPointer m_FixedImageGradientCalculator; /** Function to compute derivatives of the moving image (unwarped). */ MovingImageGradientCalculatorPointer m_MappedMovingImageGradientCalculator; GradientType m_UseGradientType; /** Function to interpolate the moving image. */ InterpolatorPointer m_MovingImageInterpolator; /** Filter to warp moving image for fast gradient computation. */ WarperPointer m_MovingImageWarper; /** The global timestep. */ TimeStepType m_TimeStep; /** Threshold below which the denominator term is considered zero. */ double m_DenominatorThreshold; /** Threshold below which two intensity value are assumed to match. */ double m_IntensityDifferenceThreshold; /** Maximum update step length in pixels (default is 0.5 as in Thirion). */ double m_MaximumUpdateStepLength; /** The metric value is the mean square difference in intensity between * the fixed image and transforming moving image computed over the * the overlapping region between the two images. */ mutable double m_Metric; mutable double m_SumOfSquaredDifference; mutable unsigned long m_NumberOfPixelsProcessed; mutable double m_RMSChange; mutable double m_SumOfSquaredChange; /** Mutex lock to protect modification to metric. */ mutable SimpleFastMutexLock m_MetricCalculationLock; MaskPointer m_MovingMask; MaskPointer m_FixedMask; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkESMDemonsRegistrationWithMaskFunction.txx" #endif #endif itkESMDemonsRegistrationWithMaskFunction.txx000066400000000000000000000441161321604176500371000ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkESMDemonsRegistrationWithMaskFunction.txx,v $ Language: C++ Date: $Date: 2008-11-10 12:44:44 $ Version: $Revision: 1.10 $ 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. =========================================================================*/ #ifndef __itkESMDemonsRegistrationWithMaskFunction_txx #define __itkESMDemonsRegistrationWithMaskFunction_txx #include "itkESMDemonsRegistrationWithMaskFunction.h" #include "itkExceptionObject.h" #include "vnl/vnl_math.h" #include "itkImageMaskSpatialObject.h" namespace itk { /** * Default constructor */ template ESMDemonsRegistrationWithMaskFunction ::ESMDemonsRegistrationWithMaskFunction() { RadiusType r; unsigned int j; for ( j = 0; j < ImageDimension; j++ ) { r[j] = 0; } this->SetRadius(r); m_TimeStep = 1.0; m_DenominatorThreshold = 1e-9; m_IntensityDifferenceThreshold = 0.001; m_MaximumUpdateStepLength = 0.5; this->SetMovingImage(NULL); this->SetFixedImage(NULL); this->SetMovingImageMask(NULL); this->SetFixedImageMask(NULL); m_FixedImageSpacing.Fill( 1.0 ); m_FixedImageOrigin.Fill( 0.0 ); m_FixedImageDirection.SetIdentity(); m_Normalizer = 0.0; m_FixedImageGradientCalculator = GradientCalculatorType::New(); // Gradient orientation will be taken care of explicitely m_FixedImageGradientCalculator->UseImageDirectionOff(); m_MappedMovingImageGradientCalculator = MovingImageGradientCalculatorType::New(); // Gradient orientation will be taken care of explicitely m_MappedMovingImageGradientCalculator->UseImageDirectionOff(); this->m_UseGradientType = Symmetric; typename DefaultInterpolatorType::Pointer interp = DefaultInterpolatorType::New(); m_MovingImageInterpolator = static_cast( interp.GetPointer() ); m_MovingImageWarper = WarperType::New(); m_MovingImageWarper->SetInterpolator( m_MovingImageInterpolator ); m_MovingImageWarper->SetEdgePaddingValue( NumericTraits::max() ); m_Metric = NumericTraits::max(); m_SumOfSquaredDifference = 0.0; m_NumberOfPixelsProcessed = 0L; m_RMSChange = NumericTraits::max(); m_SumOfSquaredChange = 0.0; } /* * Standard "PrintSelf" method. */ template void ESMDemonsRegistrationWithMaskFunction ::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "UseGradientType: "; os << m_UseGradientType << std::endl; os << indent << "MaximumUpdateStepLength: "; os << m_MaximumUpdateStepLength << std::endl; os << indent << "MovingImageIterpolator: "; os << m_MovingImageInterpolator.GetPointer() << std::endl; os << indent << "FixedImageGradientCalculator: "; os << m_FixedImageGradientCalculator.GetPointer() << std::endl; os << indent << "MappedMovingImageGradientCalculator: "; os << m_MappedMovingImageGradientCalculator.GetPointer() << std::endl; os << indent << "DenominatorThreshold: "; os << m_DenominatorThreshold << std::endl; os << indent << "IntensityDifferenceThreshold: "; os << m_IntensityDifferenceThreshold << std::endl; os << indent << "Metric: "; os << m_Metric << std::endl; os << indent << "SumOfSquaredDifference: "; os << m_SumOfSquaredDifference << std::endl; os << indent << "NumberOfPixelsProcessed: "; os << m_NumberOfPixelsProcessed << std::endl; os << indent << "RMSChange: "; os << m_RMSChange << std::endl; os << indent << "SumOfSquaredChange: "; os << m_SumOfSquaredChange << std::endl; } /** * */ template void ESMDemonsRegistrationWithMaskFunction ::SetIntensityDifferenceThreshold(double threshold) { m_IntensityDifferenceThreshold = threshold; } /** * */ template double ESMDemonsRegistrationWithMaskFunction ::GetIntensityDifferenceThreshold() const { return m_IntensityDifferenceThreshold; } /** * Set the function state values before each iteration */ template void ESMDemonsRegistrationWithMaskFunction ::InitializeIteration() { if ( !this->GetMovingImage() || !this->GetFixedImage() || !m_MovingImageInterpolator ) { itkExceptionMacro( << "MovingImage, FixedImage and/or Interpolator not set" ); } // cache fixed image information m_FixedImageOrigin = this->GetFixedImage()->GetOrigin(); m_FixedImageSpacing = this->GetFixedImage()->GetSpacing(); m_FixedImageDirection = this->GetFixedImage()->GetDirection(); // compute the normalizer if ( m_MaximumUpdateStepLength > 0.0 ) { m_Normalizer = 0.0; for ( unsigned int k = 0; k < ImageDimension; k++ ) { m_Normalizer += m_FixedImageSpacing[k] * m_FixedImageSpacing[k]; } m_Normalizer *= m_MaximumUpdateStepLength * m_MaximumUpdateStepLength / static_cast( ImageDimension ); } else { // set it to minus one to denote a special case // ( unrestricted update length ) m_Normalizer = -1.0; } // setup gradient calculator m_FixedImageGradientCalculator->SetInputImage( this->GetFixedImage() ); m_MappedMovingImageGradientCalculator->SetInputImage( this->GetMovingImage() ); // Compute warped moving image m_MovingImageWarper->SetOutputOrigin( this->m_FixedImageOrigin ); m_MovingImageWarper->SetOutputSpacing( this->m_FixedImageSpacing ); m_MovingImageWarper->SetOutputDirection( this->m_FixedImageDirection ); m_MovingImageWarper->SetInput( this->GetMovingImage() ); #if ITK_VERSION_MAJOR >= 4 m_MovingImageWarper->SetDisplacementField( this->GetDisplacementField() ); m_MovingImageWarper->GetOutput()->SetRequestedRegion( this->GetDisplacementField()->GetRequestedRegion() ); #else m_MovingImageWarper->SetDeformationField( this->GetDeformationField() ); m_MovingImageWarper->GetOutput()->SetRequestedRegion( this->GetDeformationField()->GetRequestedRegion() ); #endif m_MovingImageWarper->Update(); // setup moving image interpolator for further access m_MovingImageInterpolator->SetInputImage( this->GetMovingImage() ); // initialize metric computation variables m_SumOfSquaredDifference = 0.0; m_NumberOfPixelsProcessed = 0L; m_SumOfSquaredChange = 0.0; } /** * Compute update at a non boundary neighbourhood */ template typename ESMDemonsRegistrationWithMaskFunction ::PixelType ESMDemonsRegistrationWithMaskFunction ::ComputeUpdate( const NeighborhoodType & it, void *gd, const FloatOffsetType & itkNotUsed(offset) ) { GlobalDataStruct *globalData = (GlobalDataStruct *)gd; PixelType update; IndexType FirstIndex = this->GetFixedImage()->GetLargestPossibleRegion().GetIndex(); IndexType LastIndex = this->GetFixedImage()->GetLargestPossibleRegion().GetIndex() + this->GetFixedImage()-> GetLargestPossibleRegion().GetSize(); const IndexType index = it.GetIndex(); // Get fixed image related information // Note: no need to check if the index is within // fixed image buffer. This is done by the external filter. const double fixedValue = static_cast( this->GetFixedImage()->GetPixel( index ) ); // Get moving image related information // check if the point was mapped outside of the moving image using // the "special value" NumericTraits::max() MovingPixelType movingPixValue = m_MovingImageWarper->GetOutput()->GetPixel( index ); if ( movingPixValue == NumericTraits::max() ) { update.Fill( 0.0 ); return update; } // Determine if the current location falls within the deformed // moving image mask. If not, then set the update values to all // zeros and continue. if ( this->GetMovingImageMask() || this->GetFixedImageMask() ) { typename FixedImageType::PointType fixedPoint; this->GetFixedImage()->TransformIndexToPhysicalPoint(index, fixedPoint); if(this->GetMovingImageMask()) { MovingImagePointType mappedPoint; for( unsigned int j = 0; j < ImageDimension; j++ ) { mappedPoint[j] = fixedPoint[j] + it.GetCenterPixel()[j]; } if ( !this->GetMovingImageMask()->IsInside(mappedPoint) ) { update.Fill( 0.0 ); return update; } } if(this->GetFixedImageMask()) { if ( !this->GetFixedImageMask()->IsInside(fixedPoint) ) { update.Fill( 0.0 ); return update; } } } #if 0 if ( this->GetMovingImageMask() && this->GetFixedImageMask() ) { MovingImagePointType point; // IndexType maskIndex; this->m_MovingImageWarper->GetOutput()->TransformIndexToPhysicalPoint(index, point); // this->m_FixedMaskImage->TransformPhysicalPointToIndex(point, maskIndex); MovingPixelType movingMaskPixelValue = m_MaskImageWarper->GetOutput()->GetPixel(index); // FixedPixelType fixedMaskPixelValue = m_FixedMaskImage->GetPixel(maskIndex); // if ( ( !this->GetMovingImageMask()->IsInside(point) ) || ( !this->GetFixedImageMask()->IsInside(point)) ) if ( ( movingMaskPixelValue == 0 ) || ( !this->GetFixedImageMask()->IsInside(point)) ) { update.Fill( 0.0 ); return update; } } #endif const double movingValue = static_cast( movingPixValue ); // We compute the gradient more or less by hand. // We first start by ignoring the image orientation and introduce it // afterwards CovariantVectorType usedOrientFreeGradientTimes2; if ( ( this->m_UseGradientType == Symmetric ) || ( this->m_UseGradientType == WarpedMoving ) ) { // we don't use a CentralDifferenceImageFunction here to be able to // check for NumericTraits::max() CovariantVectorType warpedMovingGradient; IndexType tmpIndex = index; for ( unsigned int dim = 0; dim < ImageDimension; dim++ ) { // bounds checking if ( FirstIndex[dim] == LastIndex[dim] || index[dim] < FirstIndex[dim] || index[dim] >= LastIndex[dim] ) { warpedMovingGradient[dim] = 0.0; continue; } else if ( index[dim] == FirstIndex[dim] ) { // compute derivative tmpIndex[dim] += 1; movingPixValue = m_MovingImageWarper->GetOutput()->GetPixel( tmpIndex ); if ( movingPixValue == NumericTraits::max() ) { // weird crunched border case warpedMovingGradient[dim] = 0.0; } else { // forward difference warpedMovingGradient[dim] = static_cast( movingPixValue ) - movingValue; warpedMovingGradient[dim] /= m_FixedImageSpacing[dim]; } tmpIndex[dim] -= 1; continue; } else if ( index[dim] == ( LastIndex[dim] - 1 ) ) { // compute derivative tmpIndex[dim] -= 1; movingPixValue = m_MovingImageWarper->GetOutput()->GetPixel( tmpIndex ); if ( movingPixValue == NumericTraits::max() ) { // weird crunched border case warpedMovingGradient[dim] = 0.0; } else { // backward difference warpedMovingGradient[dim] = movingValue - static_cast( movingPixValue ); warpedMovingGradient[dim] /= m_FixedImageSpacing[dim]; } tmpIndex[dim] += 1; continue; } // compute derivative tmpIndex[dim] += 1; movingPixValue = m_MovingImageWarper->GetOutput()->GetPixel( tmpIndex ); if ( movingPixValue == NumericTraits ::max() ) { // backward difference warpedMovingGradient[dim] = movingValue; tmpIndex[dim] -= 2; movingPixValue = m_MovingImageWarper->GetOutput()->GetPixel( tmpIndex ); if ( movingPixValue == NumericTraits::max() ) { // weird crunched border case warpedMovingGradient[dim] = 0.0; } else { // backward difference warpedMovingGradient[dim] -= static_cast( m_MovingImageWarper->GetOutput()->GetPixel( tmpIndex ) ); warpedMovingGradient[dim] /= m_FixedImageSpacing[dim]; } } else { warpedMovingGradient[dim] = static_cast( movingPixValue ); tmpIndex[dim] -= 2; movingPixValue = m_MovingImageWarper->GetOutput()->GetPixel( tmpIndex ); if ( movingPixValue == NumericTraits::max() ) { // forward difference warpedMovingGradient[dim] -= movingValue; warpedMovingGradient[dim] /= m_FixedImageSpacing[dim]; } else { // normal case, central difference warpedMovingGradient[dim] -= static_cast( movingPixValue ); warpedMovingGradient[dim] *= 0.5 / m_FixedImageSpacing[dim]; } } tmpIndex[dim] += 1; } if ( this->m_UseGradientType == Symmetric ) { // Compute orientation-free gradient with calculator const CovariantVectorType fixedGradient = m_FixedImageGradientCalculator->EvaluateAtIndex( index ); usedOrientFreeGradientTimes2 = fixedGradient + warpedMovingGradient; } else if ( this->m_UseGradientType == WarpedMoving ) { usedOrientFreeGradientTimes2 = warpedMovingGradient + warpedMovingGradient; } else { itkExceptionMacro(<< "Unknown gradient type"); } } else if ( this->m_UseGradientType == Fixed ) { // Compute orientation-free gradient with calculator const CovariantVectorType fixedGradient = m_FixedImageGradientCalculator->EvaluateAtIndex( index ); usedOrientFreeGradientTimes2 = fixedGradient + fixedGradient; } else if ( this->m_UseGradientType == MappedMoving ) { PointType mappedPoint; this->GetFixedImage()->TransformIndexToPhysicalPoint(index, mappedPoint); for ( unsigned int j = 0; j < ImageDimension; j++ ) { mappedPoint[j] += it.GetCenterPixel()[j]; } const CovariantVectorType mappedMovingGradient = m_MappedMovingImageGradientCalculator->Evaluate( mappedPoint ); usedOrientFreeGradientTimes2 = mappedMovingGradient + mappedMovingGradient; } else { itkExceptionMacro(<< "Unknown gradient type"); } #ifdef ITK_USE_ORIENTED_IMAGE_DIRECTION CovariantVectorType usedGradientTimes2; this->GetFixedImage()->TransformLocalVectorToPhysicalVector( usedOrientFreeGradientTimes2, usedGradientTimes2); #else CovariantVectorType usedGradientTimes2 = usedOrientFreeGradientTimes2; #endif /** * Compute Update. * We avoid the mismatch in units between the two terms. * and avoid large step using a normalization term. */ const double usedGradientTimes2SquaredMagnitude = usedGradientTimes2.GetSquaredNorm(); const double speedValue = fixedValue - movingValue; if ( vnl_math_abs(speedValue) < m_IntensityDifferenceThreshold ) { update.Fill( 0.0 ); } else { double denom; if ( m_Normalizer > 0.0 ) { // "ITK-Thirion" normalization denom = usedGradientTimes2SquaredMagnitude + ( vnl_math_sqr(speedValue) / m_Normalizer ); } else { // least square solution of the system denom = usedGradientTimes2SquaredMagnitude; } if ( denom < m_DenominatorThreshold ) { update.Fill( 0.0 ); } else { const double factor = 2.0 * speedValue / denom; for ( unsigned int j = 0; j < ImageDimension; j++ ) { update[j] = factor * usedGradientTimes2[j]; } } } // WARNING!! We compute the global data without taking into account the // current update step. // There are several reasons for that: If an exponential, a smoothing or any // other operation // is applied on the update field, we cannot compute the newMappedCenterPoint // here; and even // if we could, this would be an often unnecessary time-consuming task. if ( globalData ) { globalData->m_SumOfSquaredDifference += vnl_math_sqr( speedValue ); globalData->m_NumberOfPixelsProcessed += 1; globalData->m_SumOfSquaredChange += update.GetSquaredNorm(); } return update; } /** * Update the metric and release the per-thread-global data. */ template void ESMDemonsRegistrationWithMaskFunction ::ReleaseGlobalDataPointer( void *gd ) const { GlobalDataStruct *globalData = (GlobalDataStruct *)gd; m_MetricCalculationLock.Lock(); m_SumOfSquaredDifference += globalData->m_SumOfSquaredDifference; m_NumberOfPixelsProcessed += globalData->m_NumberOfPixelsProcessed; m_SumOfSquaredChange += globalData->m_SumOfSquaredChange; if ( m_NumberOfPixelsProcessed ) { m_Metric = m_SumOfSquaredDifference / static_cast( m_NumberOfPixelsProcessed ); m_RMSChange = vcl_sqrt( m_SumOfSquaredChange / static_cast( m_NumberOfPixelsProcessed ) ); } m_MetricCalculationLock.Unlock(); delete globalData; } } // end namespace itk #endif itkPDEDeformableRegistrationWithMaskFilter.h000066400000000000000000000276561321604176500367550ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: itkPDEDeformableRegistrationWithMaskFilter.h Language: C++ Date: $Date$ Version: $Revision$ 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. =========================================================================*/ #ifndef __itkPDEDeformableRegistrationWithMaskFilter_h #define __itkPDEDeformableRegistrationWithMaskFilter_h #include "itkDenseFiniteDifferenceImageFilter.h" #include "itkPDEDeformableRegistrationFunction.h" #include "itkSpatialObject.h" //Used for mask extension namespace itk { /** * \class PDEDeformableRegistrationWithMaskFilter * \brief Deformably register two images using a PDE algorithm. * * PDEDeformableRegistrationWithMaskFilter is a base case for filter implementing * a PDE deformable algorithm that register two images by computing the * deformation field which will map a moving image onto a fixed image. * * A deformation field is represented as a image whose pixel type is some * vector type with at least N elements, where N is the dimension of * the fixed image. The vector type must support element access via operator * []. It is assumed that the vector elements behave like floating point * scalars. * * This class is templated over the fixed image type, moving image type * and the deformation Field type. * * The input fixed and moving images are set via methods SetFixedImage * and SetMovingImage respectively. An initial deformation field maybe set via * SetInitialDeformationField or SetInput. If no initial field is set, * a zero field is used as the initial condition. * * The output deformation field can be obtained via methods GetOutput * or GetDeformationField. * * The PDE algorithm is run for a user defined number of iterations. * Typically the PDE algorithm requires period Gaussin smoothing of the * deformation field to enforce an elastic-like condition. The amount * of smoothing is governed by a set of user defined standard deviations * (one for each dimension). * * In terms of memory, this filter keeps two internal buffers: one for storing * the intermediate updates to the field and one for double-buffering when * smoothing the deformation field. Both buffers are the same type and size as the * output deformation field. * * This class make use of the finite difference solver hierarchy. Update * for each iteration is computed using a PDEDeformableRegistrationFunction. * * \warning This filter assumes that the fixed image type, moving image type * and deformation field type all have the same number of dimensions. * * \sa PDEDeformableRegistrationFunction. * \ingroup DeformableImageRegistration */ template class ITK_EXPORT PDEDeformableRegistrationWithMaskFilter : public DenseFiniteDifferenceImageFilter { public: /** Standard class typedefs. */ typedef PDEDeformableRegistrationWithMaskFilter Self; typedef DenseFiniteDifferenceImageFilter< TDeformationField,TDeformationField> Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods) */ itkTypeMacro( PDEDeformableRegistrationWithMaskFilter, DenseFiniteDifferenceImageFilter ); /** FixedImage image type. */ typedef TFixedImage FixedImageType; typedef typename FixedImageType::Pointer FixedImagePointer; typedef typename FixedImageType::ConstPointer FixedImageConstPointer; /** MovingImage image type. */ typedef TMovingImage MovingImageType; typedef typename MovingImageType::Pointer MovingImagePointer; typedef typename MovingImageType::ConstPointer MovingImageConstPointer; /** Deformation field type. */ typedef TDeformationField DeformationFieldType; typedef typename DeformationFieldType::Pointer DeformationFieldPointer; /** Types inherithed from the superclass */ typedef typename Superclass::OutputImageType OutputImageType; /** FiniteDifferenceFunction type. */ typedef typename Superclass::FiniteDifferenceFunctionType FiniteDifferenceFunctionType; /** PDEDeformableRegistrationWithMaskFilterFunction type. */ typedef PDEDeformableRegistrationFunction PDEDeformableRegistrationFunctionType; /** Inherit some enums and typedefs from the superclass. */ itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension); /** Set the fixed image. */ void SetFixedImage( const FixedImageType * ptr ); /** Get the fixed image. */ const FixedImageType * GetFixedImage(void) const; /** Set the moving image. */ void SetMovingImage( const MovingImageType * ptr ); /** Get the moving image. */ const MovingImageType * GetMovingImage(void) const; /** Set initial deformation field. */ void SetInitialDeformationField( const DeformationFieldType * ptr ) { this->SetInput( ptr ); } /** Get output deformation field. */ DeformationFieldType * GetDeformationField() { return this->GetOutput(); } virtual double GetMetric() const {return 0;} /** Get the number of valid inputs. For PDEDeformableRegistration, * this checks whether the fixed and moving images have been * set. While PDEDeformableRegistration can take a third input as an * initial deformation field, this input is not a required input. */ virtual std::vector >::size_type GetNumberOfValidRequiredInputs() const; /** Set/Get whether the deformation field is smoothed * (regularized). Smoothing the deformation yields a solution * elastic in nature. If SmoothDeformationField is on, then the * deformation field is smoothed with a Gaussian whose standard * deviations are specified with SetStandardDeviations() */ itkSetMacro( SmoothDeformationField, bool ); itkGetConstMacro( SmoothDeformationField, bool ); itkBooleanMacro( SmoothDeformationField ); /** Set the Gaussian smoothing standard deviations for the * deformation field. The values are set with respect to pixel * coordinates. */ itkSetVectorMacro( StandardDeviations, double, ImageDimension ); virtual void SetStandardDeviations( double value ); /** Get the Gaussian smoothing standard deviations use for smoothing * the deformation field. */ const double * GetStandardDeviations(void) { return (double *) m_StandardDeviations; } /** Set/Get whether the update field is smoothed * (regularized). Smoothing the update field yields a solution * viscous in nature. If SmoothUpdateField is on, then the * update field is smoothed with a Gaussian whose standard * deviations are specified with SetUpdateFieldStandardDeviations() */ itkSetMacro( SmoothUpdateField, bool ); itkGetConstMacro( SmoothUpdateField, bool ); itkBooleanMacro( SmoothUpdateField ); /** Set the Gaussian smoothing standard deviations for the update * field. The values are set with respect to pixel coordinates. */ itkSetVectorMacro( UpdateFieldStandardDeviations, double, ImageDimension ); virtual void SetUpdateFieldStandardDeviations( double value ); /** Get the Gaussian smoothing standard deviations used for * smoothing the update field. */ const double * GetUpdateFieldStandardDeviations(void) { return (double *) m_UpdateFieldStandardDeviations; } /** Stop the registration after the current iteration. */ virtual void StopRegistration() { m_StopRegistrationFlag = true; } /** Set/Get the desired maximum error of the Guassian kernel approximate. * \sa GaussianOperator. */ itkSetMacro( MaximumError, double ); itkGetConstMacro( MaximumError, double ); /** Set/Get the desired limits of the Gaussian kernel width. * \sa GaussianOperator. */ itkSetMacro( MaximumKernelWidth, unsigned int ); itkGetConstMacro( MaximumKernelWidth, unsigned int ); /** PLM extension: Adding possibility to use masks with PDE * deformable registration filters. */ typedef itk::SpatialObject MaskType; virtual void SetMovingImageMask(MaskType *mask){}; virtual void SetFixedImageMask(MaskType *mask){}; protected: PDEDeformableRegistrationWithMaskFilter(); ~PDEDeformableRegistrationWithMaskFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; /** Supplies the halting criteria for this class of filters. The * algorithm will stop after a user-specified number of iterations. */ virtual bool Halt() { if ( m_StopRegistrationFlag ) { return true; } return this->Superclass::Halt(); } /** A simple method to copy the data from the input to the output. * If the input does not exist, a zero field is written to the output. */ virtual void CopyInputToOutput(); /** Initialize the state of filter and equation before each iteration. * Progress feeback is implemented as part of this method. */ virtual void InitializeIteration(); /** Utility to smooth the deformation field (represented in the Output) * using a Guassian operator. The amount of smoothing can be specified * by setting the StandardDeviations. */ virtual void SmoothDeformationField(); /** Utility to smooth the UpdateBuffer using a Gaussian operator. * The amount of smoothing can be specified by setting the * UpdateFieldStandardDeviations. */ virtual void SmoothUpdateField(); /** This method is called after the solution has been generated. In this case, * the filter release the memory of the internal buffers. */ virtual void PostProcessOutput(); /** This method is called before iterating the solution. */ virtual void Initialize(); /** By default the output deformation field has the same Spacing, Origin * and LargestPossibleRegion as the input/initial deformation field. If * the initial deformation field is not set, the output information is * copied from the fixed image. */ virtual void GenerateOutputInformation(); /** It is difficult to compute in advance the input moving image region * required to compute the requested output region. Thus the safest * thing to do is to request for the whole moving image. * * For the fixed image and deformation field, the input requested region * set to be the same as that of the output requested region. */ virtual void GenerateInputRequestedRegion(); private: PDEDeformableRegistrationWithMaskFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented /** Standard deviation for Gaussian smoothing */ double m_StandardDeviations[ImageDimension]; double m_UpdateFieldStandardDeviations[ImageDimension]; /** Modes to control smoothing of the update and deformation fields */ bool m_SmoothDeformationField; bool m_SmoothUpdateField; /** Temporary deformation field use for smoothing the * the deformation field. */ DeformationFieldPointer m_TempField; private: /** Maximum error for Gaussian operator approximation. */ double m_MaximumError; /** Limits of Guassian kernel width. */ unsigned int m_MaximumKernelWidth; /** Flag to indicate user stop registration request. */ bool m_StopRegistrationFlag; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkPDEDeformableRegistrationWithMaskFilter.hxx" #endif #endif itkPDEDeformableRegistrationWithMaskFilter.hxx000066400000000000000000000356221321604176500373250ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: itkPDEDeformableRegistrationWithMaskFilter.txx Language: C++ Date: $Date$ Version: $Revision$ 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. =========================================================================*/ #ifndef __itkPDEDeformableRegistrationWithMaskFilter_txx #define __itkPDEDeformableRegistrationWithMaskFilter_txx #include "itkPDEDeformableRegistrationWithMaskFilter.h" #include "itkExceptionObject.h" #include "itkImageRegionIterator.h" #include "itkImageLinearIteratorWithIndex.h" #include "itkDataObject.h" #include "itkGaussianOperator.h" #include "itkVectorNeighborhoodOperatorImageFilter.h" #include "vnl/vnl_math.h" namespace itk { /** * Default constructor */ template PDEDeformableRegistrationWithMaskFilter ::PDEDeformableRegistrationWithMaskFilter() { this->SetNumberOfRequiredInputs(2); #if ITK_VERSION_MAJOR >=4 this->RemoveRequiredInputName( "Primary"); #endif this->SetNumberOfIterations(10); unsigned int j; for( j = 0; j < ImageDimension; j++ ) { m_StandardDeviations[j] = 1.0; m_UpdateFieldStandardDeviations[j] = 1.0; } m_TempField = DeformationFieldType::New(); m_MaximumError = 0.1; m_MaximumKernelWidth = 30; m_StopRegistrationFlag = false; m_SmoothDeformationField = true; m_SmoothUpdateField = false; } /* * Set the fixed image. */ template void PDEDeformableRegistrationWithMaskFilter ::SetFixedImage( const FixedImageType * ptr ) { this->ProcessObject::SetNthInput( 1, const_cast< FixedImageType * >( ptr ) ); } /* * Get the fixed image. */ template const typename PDEDeformableRegistrationWithMaskFilter ::FixedImageType * PDEDeformableRegistrationWithMaskFilter ::GetFixedImage() const { return dynamic_cast< const FixedImageType * > ( this->ProcessObject::GetInput( 1 ) ); } /* * Set the moving image. */ template void PDEDeformableRegistrationWithMaskFilter ::SetMovingImage( const MovingImageType * ptr ) { this->ProcessObject::SetNthInput( 2, const_cast< MovingImageType * >( ptr ) ); } /* * Get the moving image. */ template const typename PDEDeformableRegistrationWithMaskFilter ::MovingImageType * PDEDeformableRegistrationWithMaskFilter ::GetMovingImage() const { return dynamic_cast< const MovingImageType * > ( this->ProcessObject::GetInput( 2 ) ); } /* * */ template std::vector >::size_type PDEDeformableRegistrationWithMaskFilter ::GetNumberOfValidRequiredInputs() const { typename std::vector >::size_type num = 0; if (this->GetFixedImage()) { num++; } if (this->GetMovingImage()) { num++; } return num; } /** * Set the standard deviations. */ template void PDEDeformableRegistrationWithMaskFilter ::SetStandardDeviations( double value ) { unsigned int j; for( j = 0; j < ImageDimension; j++ ) { if( value != m_StandardDeviations[j] ) { break; } } if( j < ImageDimension ) { this->Modified(); for( j = 0; j < ImageDimension; j++ ) { m_StandardDeviations[j] = value; } } } /* * Set the standard deviations. */ template void PDEDeformableRegistrationWithMaskFilter ::SetUpdateFieldStandardDeviations( double value ) { unsigned int j; for( j = 0; j < ImageDimension; j++ ) { if( value != m_UpdateFieldStandardDeviations[j] ) { break; } } if( j < ImageDimension ) { this->Modified(); for( j = 0; j < ImageDimension; j++ ) { m_UpdateFieldStandardDeviations[j] = value; } } } /* * Standard PrintSelf method. */ template void PDEDeformableRegistrationWithMaskFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Smooth deformation field: " << (m_SmoothDeformationField ? "on" : "off") << std::endl; os << indent << "Standard deviations: ["; unsigned int j; for( j = 0; j < ImageDimension - 1; j++ ) { os << m_StandardDeviations[j] << ", "; } os << m_StandardDeviations[j] << "]" << std::endl; os << indent << "Smooth update field: " << (m_SmoothUpdateField ? "on" : "off") << std::endl; os << indent << "Update field standard deviations: ["; for( j = 0; j < ImageDimension - 1; j++ ) { os << m_UpdateFieldStandardDeviations[j] << ", "; } os << m_UpdateFieldStandardDeviations[j] << "]" << std::endl; os << indent << "StopRegistrationFlag: "; os << m_StopRegistrationFlag << std::endl; os << indent << "MaximumError: "; os << m_MaximumError << std::endl; os << indent << "MaximumKernelWidth: "; os << m_MaximumKernelWidth << std::endl; } /* * Set the function state values before each iteration */ template void PDEDeformableRegistrationWithMaskFilter ::InitializeIteration() { MovingImageConstPointer movingPtr = this->GetMovingImage(); FixedImageConstPointer fixedPtr = this->GetFixedImage(); if( !movingPtr || !fixedPtr ) { itkExceptionMacro( << "Fixed and/or moving image not set" ); } // update variables in the equation object PDEDeformableRegistrationFunctionType *f = dynamic_cast (this->GetDifferenceFunction().GetPointer()); if ( !f ) { itkExceptionMacro(<<"FiniteDifferenceFunction not of type PDEDeformableRegistrationWithMaskFilterFunction"); } f->SetFixedImage( fixedPtr ); f->SetMovingImage( movingPtr ); this->Superclass::InitializeIteration(); } /* * Override the default implemenation for the case when the * initial deformation is not set. * If the initial deformation is not set, the output is * fill with zero vectors. */ template void PDEDeformableRegistrationWithMaskFilter ::CopyInputToOutput() { typename Superclass::InputImageType::ConstPointer inputPtr = this->GetInput(); if( inputPtr ) { this->Superclass::CopyInputToOutput(); } else { typename Superclass::PixelType zeros; for( unsigned int j = 0; j < ImageDimension; j++ ) { zeros[j] = 0; } typename OutputImageType::Pointer output = this->GetOutput(); ImageRegionIterator out(output, output->GetRequestedRegion()); while( ! out.IsAtEnd() ) { out.Value() = zeros; ++out; } } } template void PDEDeformableRegistrationWithMaskFilter ::GenerateOutputInformation() { typename DataObject::Pointer output; if( this->GetInput(0) ) { // Initial deformation field is set. // Copy information from initial field. this->Superclass::GenerateOutputInformation(); } else if( this->GetFixedImage() ) { // Initial deforamtion field is not set. // Copy information from the fixed image. for (unsigned int idx = 0; idx < this->GetNumberOfOutputs(); ++idx ) { output = this->GetOutput(idx); if (output) { output->CopyInformation(this->GetFixedImage()); } } } } template void PDEDeformableRegistrationWithMaskFilter ::GenerateInputRequestedRegion() { // call the superclass's implementation Superclass::GenerateInputRequestedRegion(); // request the largest possible region for the moving image MovingImagePointer movingPtr = const_cast< MovingImageType * >( this->GetMovingImage() ); if( movingPtr ) { movingPtr->SetRequestedRegionToLargestPossibleRegion(); } // just propagate up the output requested region for // the fixed image and initial deformation field. DeformationFieldPointer inputPtr = const_cast< DeformationFieldType * >( this->GetInput() ); DeformationFieldPointer outputPtr = this->GetOutput(); FixedImagePointer fixedPtr = const_cast< FixedImageType *>( this->GetFixedImage() ); if( inputPtr ) { inputPtr->SetRequestedRegion( outputPtr->GetRequestedRegion() ); } if( fixedPtr ) { fixedPtr->SetRequestedRegion( outputPtr->GetRequestedRegion() ); } } /* * Release memory of internal buffers */ template void PDEDeformableRegistrationWithMaskFilter ::PostProcessOutput() { this->Superclass::PostProcessOutput(); m_TempField->Initialize(); } /* * Initialize flags */ template void PDEDeformableRegistrationWithMaskFilter ::Initialize() { this->Superclass::Initialize(); m_StopRegistrationFlag = false; } /* * Smooth deformation using a separable Gaussian kernel */ template void PDEDeformableRegistrationWithMaskFilter ::SmoothDeformationField() { DeformationFieldPointer field = this->GetOutput(); // copy field to TempField m_TempField->SetOrigin( field->GetOrigin() ); m_TempField->SetSpacing( field->GetSpacing() ); m_TempField->SetDirection( field->GetDirection() ); m_TempField->SetLargestPossibleRegion( field->GetLargestPossibleRegion() ); m_TempField->SetRequestedRegion( field->GetRequestedRegion() ); m_TempField->SetBufferedRegion( field->GetBufferedRegion() ); m_TempField->Allocate(); typedef typename DeformationFieldType::PixelType VectorType; typedef typename VectorType::ValueType ScalarType; typedef GaussianOperator OperatorType; typedef VectorNeighborhoodOperatorImageFilter< DeformationFieldType, DeformationFieldType> SmootherType; OperatorType * oper = new OperatorType; typename SmootherType::Pointer smoother = SmootherType::New(); typedef typename DeformationFieldType::PixelContainerPointer PixelContainerPointer; PixelContainerPointer swapPtr; // graft the output field onto the mini-pipeline smoother->GraftOutput( m_TempField ); for( unsigned int j = 0; j < ImageDimension; j++ ) { // smooth along this dimension oper->SetDirection( j ); double variance = vnl_math_sqr( m_StandardDeviations[j] ); oper->SetVariance( variance ); oper->SetMaximumError( m_MaximumError ); oper->SetMaximumKernelWidth( m_MaximumKernelWidth ); oper->CreateDirectional(); // todo: make sure we only smooth within the buffered region smoother->SetOperator( *oper ); smoother->SetInput( field ); smoother->Update(); if ( j < ImageDimension - 1 ) { // swap the containers swapPtr = smoother->GetOutput()->GetPixelContainer(); smoother->GraftOutput( field ); field->SetPixelContainer( swapPtr ); smoother->Modified(); } } // graft the output back to this filter m_TempField->SetPixelContainer( field->GetPixelContainer() ); this->GraftOutput( smoother->GetOutput() ); delete oper; } /* * Smooth deformation using a separable Gaussian kernel */ template void PDEDeformableRegistrationWithMaskFilter ::SmoothUpdateField() { // The update buffer will be overwritten with new data. DeformationFieldPointer field = this->GetUpdateBuffer(); typedef typename DeformationFieldType::PixelType VectorType; typedef typename VectorType::ValueType ScalarType; typedef GaussianOperator OperatorType; typedef VectorNeighborhoodOperatorImageFilter< DeformationFieldType, DeformationFieldType> SmootherType; OperatorType opers[ImageDimension]; typename SmootherType::Pointer smoothers[ImageDimension]; for( unsigned int j = 0; j < ImageDimension; j++ ) { // smooth along this dimension opers[j].SetDirection( j ); double variance = vnl_math_sqr( this->GetUpdateFieldStandardDeviations()[j] ); //double variance = vnl_math_sqr( 1.0 ); opers[j].SetVariance( variance ); opers[j].SetMaximumError( this->GetMaximumError() ); opers[j].SetMaximumKernelWidth( this->GetMaximumKernelWidth() ); opers[j].CreateDirectional(); smoothers[j] = SmootherType::New(); smoothers[j]->SetOperator( opers[j] ); smoothers[j]->ReleaseDataFlagOn(); if (j > 0) { smoothers[j]->SetInput( smoothers[j-1]->GetOutput() ); } } smoothers[0]->SetInput( field ); smoothers[ImageDimension-1]->GetOutput() ->SetRequestedRegion( field->GetBufferedRegion() ); smoothers[ImageDimension-1]->Update(); // field to contain the final smoothed data, do the equivalent of a graft field->SetPixelContainer( smoothers[ImageDimension-1]->GetOutput() ->GetPixelContainer() ); field->SetRequestedRegion( smoothers[ImageDimension-1]->GetOutput() ->GetRequestedRegion() ); field->SetBufferedRegion( smoothers[ImageDimension-1]->GetOutput() ->GetBufferedRegion() ); field->SetLargestPossibleRegion( smoothers[ImageDimension-1]->GetOutput() ->GetLargestPossibleRegion() ); field->CopyInformation( smoothers[ImageDimension-1]->GetOutput() ); } } // end namespace itk #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/demons_itk_insight/readme.txt000066400000000000000000000003351321604176500303300ustar00rootroot00000000000000This folder contains adapted ITK classes and code from Insight Journal publications in order to integrate different demons variants into platimatch. For more information please also refer to readme files in sub-folders. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/devillard/000077500000000000000000000000001321604176500244165ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/devillard/CMakeLists.txt000077500000000000000000000001761321604176500271650ustar00rootroot00000000000000PROJECT (devillard) SET (LIBDEVILLARD_SRC wirth.cpp ) plm_add_static_library (devillard "${LIBDEVILLARD_SRC}" "" "" "") plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/devillard/README000077500000000000000000000001631321604176500253010ustar00rootroot00000000000000Downloaded from http://ndevilla.free.fr/ This code is written by Nicholas Devillard, and is in the public domain. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/devillard/quickselect.c000077500000000000000000000033321321604176500271020ustar00rootroot00000000000000/* * This Quickselect routine is based on the algorithm described in * "Numerical recipes in C", Second Edition, * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5 * This code by Nicolas Devillard - 1998. Public domain. */ #define ELEM_SWAP(a,b) { register elem_type t=(a);(a)=(b);(b)=t; } elem_type quick_select(elem_type arr[], int n) { int low, high ; int median; int middle, ll, hh; low = 0 ; high = n-1 ; median = (low + high) / 2; for (;;) { if (high <= low) /* One element only */ return arr[median] ; if (high == low + 1) { /* Two elements only */ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; return arr[median] ; } /* Find median of low, middle and high items; swap into position low */ middle = (low + high) / 2; if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; /* Swap low item (now in position middle) into position (low+1) */ ELEM_SWAP(arr[middle], arr[low+1]) ; /* Nibble from each end towards middle, swapping items when stuck */ ll = low + 1; hh = high; for (;;) { do ll++; while (arr[low] > arr[ll]) ; do hh--; while (arr[hh] > arr[low]) ; if (hh < ll) break; ELEM_SWAP(arr[ll], arr[hh]) ; } /* Swap middle item (in position low) back into correct position */ ELEM_SWAP(arr[low], arr[hh]) ; /* Re-set active partition */ if (hh <= median) low = ll; if (hh >= median) high = hh - 1; } } #undef ELEM_SWAP plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/devillard/wirth.cpp000077500000000000000000000027021321604176500262630ustar00rootroot00000000000000/* * Algorithm from N. Wirth's book, implementation by N. Devillard. * This code in public domain. */ typedef float elem_type ; #define ELEM_SWAP(a,b) { register elem_type t=(a);(a)=(b);(b)=t; } /*--------------------------------------------------------------------------- Function : kth_smallest() In : array of elements, # of elements in the array, rank k Out : one element Job : find the kth smallest element in the array Notice : use the median() macro defined below to get the median. Reference: Author: Wirth, Niklaus Title: Algorithms + data structures = programs Publisher: Englewood Cliffs: Prentice-Hall, 1976 Physical description: 366 p. Series: Prentice-Hall Series in Automatic Computation ---------------------------------------------------------------------------*/ elem_type kth_smallest(elem_type a[], int n, int k) { register int i,j,l,m ; register elem_type x ; l=0 ; m=n-1 ; while (l #include #include #include "ini.h" #include "INIReader.h" using std::string; INIReader::INIReader(string filename) { _error = ini_parse(filename.c_str(), ValueHandler, this); } int INIReader::ParseError() { return _error; } string INIReader::Get(string section, string name, string default_value) { string key = MakeKey(section, name); return _values.count(key) ? _values[key] : default_value; } long INIReader::GetInteger(string section, string name, long default_value) { string valstr = Get(section, name, ""); const char* value = valstr.c_str(); char* end; // This parses "1234" (decimal) and also "0x4D2" (hex) long n = strtol(value, &end, 0); return end > value ? n : default_value; } double INIReader::GetReal(string section, string name, double default_value) { string valstr = Get(section, name, ""); const char* value = valstr.c_str(); char* end; double n = strtod(value, &end); return end > value ? n : default_value; } bool INIReader::GetBoolean(string section, string name, bool default_value) { string valstr = Get(section, name, ""); // Convert to lower case to make string comparisons case-insensitive std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower); if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1") return true; else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0") return false; else return default_value; } string INIReader::MakeKey(string section, string name) { string key = section + "." + name; // Convert to lower case to make section/name lookups case-insensitive std::transform(key.begin(), key.end(), key.begin(), ::tolower); return key; } int INIReader::ValueHandler(void* user, const char* section, const char* name, const char* value) { INIReader* reader = (INIReader*)user; string key = MakeKey(section, name); if (reader->_values[key].size() > 0) reader->_values[key] += "\n"; reader->_values[key] += value; return 1; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/inih-r29/INIReader.h000066400000000000000000000041561321604176500257320ustar00rootroot00000000000000// Read an INI file into easy-to-access name/value pairs. // inih and INIReader are released under the New BSD license (see LICENSE.txt). // Go to the project home page for more info: // // http://code.google.com/p/inih/ #ifndef __INIREADER_H__ #define __INIREADER_H__ #include #include // Read an INI file into easy-to-access name/value pairs. (Note that I've gone // for simplicity here rather than speed, but it should be pretty decent.) class INIReader { public: // Construct INIReader and parse given filename. See ini.h for more info // about the parsing. INIReader(std::string filename); // Return the result of ini_parse(), i.e., 0 on success, line number of // first error on parse error, or -1 on file open error. int ParseError(); // Get a string value from INI file, returning default_value if not found. std::string Get(std::string section, std::string name, std::string default_value); // Get an integer (long) value from INI file, returning default_value if // not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2"). long GetInteger(std::string section, std::string name, long default_value); // Get a real (floating point double) value from INI file, returning // default_value if not found or not a valid floating point value // according to strtod(). double GetReal(std::string section, std::string name, double default_value); // Get a boolean value from INI file, returning default_value if not found or if // not a valid true/false value. Valid true values are "true", "yes", "on", "1", // and valid false values are "false", "no", "off", "0" (not case sensitive). bool GetBoolean(std::string section, std::string name, bool default_value); private: int _error; std::map _values; static std::string MakeKey(std::string section, std::string name); static int ValueHandler(void* user, const char* section, const char* name, const char* value); }; #endif // __INIREADER_H__ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/inih-r29/LICENSE.txt000066400000000000000000000030411321604176500256320ustar00rootroot00000000000000 The "inih" library is distributed under the New BSD license: Copyright (c) 2009, Brush Technology All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Brush Technology nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/inih-r29/README.txt000066400000000000000000000002671321604176500255140ustar00rootroot00000000000000 inih is a simple .INI file parser written in C, released under the New BSD license (see LICENSE.txt). Go to the project home page for more info: http://code.google.com/p/inih/ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/inih-r29/ini.c000066400000000000000000000117171321604176500247430ustar00rootroot00000000000000/* inih -- simple .INI file parser inih is released under the New BSD license (see LICENSE.txt). Go to the project home page for more info: http://code.google.com/p/inih/ */ #include #include #include #include "ini.h" #if !INI_USE_STACK #include #endif #define MAX_SECTION 50 #define MAX_NAME 50 /* Strip whitespace chars off end of given string, in place. Return s. */ static char* rstrip(char* s) { char* p = s + strlen(s); while (p > s && isspace((unsigned char)(*--p))) *p = '\0'; return s; } /* Return pointer to first non-whitespace char in given string. */ static char* lskip(const char* s) { while (*s && isspace((unsigned char)(*s))) s++; return (char*)s; } /* Return pointer to first char c or ';' comment in given string, or pointer to null at end of string if neither found. ';' must be prefixed by a whitespace character to register as a comment. */ static char* find_char_or_comment(const char* s, char c) { int was_whitespace = 0; while (*s && *s != c && !(was_whitespace && *s == ';')) { was_whitespace = isspace((unsigned char)(*s)); s++; } return (char*)s; } /* Version of strncpy that ensures dest (size bytes) is null-terminated. */ static char* strncpy0(char* dest, const char* src, size_t size) { strncpy(dest, src, size); dest[size - 1] = '\0'; return dest; } /* See documentation in header file. */ int ini_parse_file(FILE* file, int (*handler)(void*, const char*, const char*, const char*), void* user) { /* Uses a fair bit of stack (use heap instead if you need to) */ #if INI_USE_STACK char line[INI_MAX_LINE]; #else char* line; #endif char section[MAX_SECTION] = ""; char prev_name[MAX_NAME] = ""; char* start; char* end; char* name; char* value; int lineno = 0; int error = 0; #if !INI_USE_STACK line = (char*)malloc(INI_MAX_LINE); if (!line) { return -2; } #endif /* Scan through file line by line */ while (fgets(line, INI_MAX_LINE, file) != NULL) { lineno++; start = line; #if INI_ALLOW_BOM if (lineno == 1 && (unsigned char)start[0] == 0xEF && (unsigned char)start[1] == 0xBB && (unsigned char)start[2] == 0xBF) { start += 3; } #endif start = lskip(rstrip(start)); if (*start == ';' || *start == '#') { /* Per Python ConfigParser, allow '#' comments at start of line */ } #if INI_ALLOW_MULTILINE else if (*prev_name && *start && start > line) { /* Non-black line with leading whitespace, treat as continuation of previous name's value (as per Python ConfigParser). */ if (!handler(user, section, prev_name, start) && !error) error = lineno; } #endif else if (*start == '[') { /* A "[section]" line */ end = find_char_or_comment(start + 1, ']'); if (*end == ']') { *end = '\0'; strncpy0(section, start + 1, sizeof(section)); *prev_name = '\0'; } else if (!error) { /* No ']' found on section line */ error = lineno; } } else if (*start && *start != ';') { /* Not a comment, must be a name[=:]value pair */ end = find_char_or_comment(start, '='); if (*end != '=') { end = find_char_or_comment(start, ':'); } if (*end == '=' || *end == ':') { *end = '\0'; name = rstrip(start); value = lskip(end + 1); end = find_char_or_comment(value, '\0'); if (*end == ';') *end = '\0'; rstrip(value); /* Valid name[=:]value pair found, call handler */ strncpy0(prev_name, name, sizeof(prev_name)); if (!handler(user, section, name, value) && !error) error = lineno; } else if (!error) { /* No '=' or ':' found on name[=:]value line */ error = lineno; } } #if INI_STOP_ON_FIRST_ERROR if (error) break; #endif } #if !INI_USE_STACK free(line); #endif return error; } /* See documentation in header file. */ int ini_parse(const char* filename, int (*handler)(void*, const char*, const char*, const char*), void* user) { FILE* file; int error; file = fopen(filename, "r"); if (!file) return -1; error = ini_parse_file(file, handler, user); fclose(file); return error; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/inih-r29/ini.h000066400000000000000000000047501321604176500247470ustar00rootroot00000000000000/* inih -- simple .INI file parser inih is released under the New BSD license (see LICENSE.txt). Go to the project home page for more info: http://code.google.com/p/inih/ */ #ifndef __INI_H__ #define __INI_H__ /* Make this header file easier to include in C++ code */ #ifdef __cplusplus extern "C" { #endif #include /* Parse given INI-style file. May have [section]s, name=value pairs (whitespace stripped), and comments starting with ';' (semicolon). Section is "" if name=value pair parsed before any section heading. name:value pairs are also supported as a concession to Python's ConfigParser. For each name=value pair parsed, call handler function with given user pointer as well as section, name, and value (data only valid for duration of handler call). Handler should return nonzero on success, zero on error. Returns 0 on success, line number of first error on parse error (doesn't stop on first error), -1 on file open error, or -2 on memory allocation error (only when INI_USE_STACK is zero). */ int ini_parse(const char* filename, int (*handler)(void* user, const char* section, const char* name, const char* value), void* user); /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't close the file when it's finished -- the caller must do that. */ int ini_parse_file(FILE* file, int (*handler)(void* user, const char* section, const char* name, const char* value), void* user); /* Nonzero to allow multi-line value parsing, in the style of Python's ConfigParser. If allowed, ini_parse() will call the handler with the same name for each subsequent line parsed. */ #ifndef INI_ALLOW_MULTILINE #define INI_ALLOW_MULTILINE 1 #endif /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of the file. See http://code.google.com/p/inih/issues/detail?id=21 */ #ifndef INI_ALLOW_BOM #define INI_ALLOW_BOM 1 #endif /* Nonzero to use stack, zero to use heap (malloc/free). */ #ifndef INI_USE_STACK #define INI_USE_STACK 1 #endif /* Stop parsing on first error (default is to keep parsing). */ #ifndef INI_STOP_ON_FIRST_ERROR #define INI_STOP_ON_FIRST_ERROR 0 #endif /* Maximum line length for any line in INI file. */ #ifndef INI_MAX_LINE #define INI_MAX_LINE 200 #endif #ifdef __cplusplus } #endif #endif /* __INI_H__ */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/000077500000000000000000000000001321604176500237555ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/ITKCopyright.txt000077500000000000000000000047051321604176500270470ustar00rootroot00000000000000 Historical Note: The Insight Segmentation and Registration Toolkit (ITK) was initially developed under contract to the National Library of Medicine at the National Institutes of Health. ITK is partially derived from VTK and VXL, hence some code is copyrighted accordingly (see VTKCopyright.txt and VXLCopyright.txt). The copyright of most of the files in the "Utilities" subdirectory is held by third parties who allow to distribute this material under a license compatible with the one used by ITK. Please read the content of the subdirectories for specific details on those third-party licenses. You will also find details in the README.txt file under the "Copyright" subdirectory. Starting with its version ITK 3.6, The Insight Toolkit is distributed under the new and simplified BSD license approved by the Open Source Initiative (OSI) [http://www.opensource.org/licenses/bsd-license.php]. ITK Copyright Notice: Copyright (c) 1999-2003 Insight Software Consortium All rights reserved. License: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Insight Software Consortium nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/README000077500000000000000000000002661321604176500246440ustar00rootroot00000000000000This directory contains files which are modified versions of software from the InsightToolkit, Version 3.20.0. Please see ITKCopyright.txt for copyright and licensing information. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/itkImageIOBase.h000077500000000000000000000516231321604176500267150ustar00rootroot00000000000000/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkImageIOBase.h,v $ Language: C++ Date: $Date: 2009-11-29 15:51:11 $ Version: $Revision: 1.56 $ 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. =========================================================================*/ #ifndef __itkImageIOBase_h #define __itkImageIOBase_h #include #include "itkLightProcessObject.h" #include "itkObjectFactory.h" #include "itkIndent.h" #include "itkImageIORegion.h" #include "vnl/vnl_vector.h" #include namespace itk { /** \class ImageIOBase * \brief Abstract superclass defines image IO interface. * * ImageIOBase is a class that reads and/or writes image data * of a particular format (such as PNG or raw binary). The * ImageIOBase encapsulates both the reading and writing of data. The * ImageIOBase is used by the ImageFileReader class (to read data) * and the ImageFileWriter (to write data) into a single file. The * ImageSeriesReader and ImageSeriesWriter classes are used to read * and write data (in conjunction with ImageIOBase) when the data is * represented by a series of files. Normally the user does not directly * manipulate this class other than to instantiate it, set the FileName, * and assign it to a ImageFileReader/ImageFileWriter or * ImageSeriesReader/ImageSeriesWriter. * * A Pluggable factory pattern is used this allows different kinds of readers * to be registered (even at run time) without having to modify the * code in this class. * * \sa ImageFileWriter * \sa ImageFileReader * \sa ImageSeriesWriter * \sa ImageSeriesReader * * \ingroup IOFilters * */ class ITK_EXPORT ImageIOBase : public LightProcessObject { public: /** Standard class typedefs. */ typedef ImageIOBase Self; typedef LightProcessObject Superclass; typedef SmartPointer Pointer; /** Run-time type information (and related methods). */ itkTypeMacro(ImageIOBase, Superclass); /** Set/Get the name of the file to be read. */ itkSetStringMacro(FileName); itkGetStringMacro(FileName); /** Types for managing image size and image index components. */ typedef long IndexValueType; typedef unsigned long SizeValueType; /** * \class UnknownType * Used to return information when types are unknown. */ class UnknownType {}; /** Enums used to manipulate the pixel type. The pixel type provides * context for automatic data conversions (for instance, RGB to * SCALAR, VECTOR to SCALAR). */ typedef enum {UNKNOWNPIXELTYPE,SCALAR,RGB,RGBA,OFFSET,VECTOR, POINT,COVARIANTVECTOR,SYMMETRICSECONDRANKTENSOR, DIFFUSIONTENSOR3D,COMPLEX,FIXEDARRAY,MATRIX} IOPixelType; /** Enums used to manipulate the component type. The component type * refers to the actual storage class associated with either a * SCALAR pixel type or elements of a compound pixel. */ typedef enum {UNKNOWNCOMPONENTTYPE,UCHAR,CHAR,USHORT,SHORT,UINT,INT, ULONG,LONG, FLOAT,DOUBLE} IOComponentType; /** Set/Get the number of independent variables (dimensions) in the * image being read or written. Note this is not necessarily what * is written, rather the IORegion controls that. */ void SetNumberOfDimensions(unsigned int); itkGetConstMacro(NumberOfDimensions, unsigned int); /** Set/Get the image dimensions in the x, y, z, etc. directions. * GetDimensions() is typically used after reading the data; the * SetDimensions() is used prior to writing the data. */ virtual void SetDimensions(unsigned int i, unsigned int dim); virtual unsigned int GetDimensions(unsigned int i) const { return m_Dimensions[i]; } /** Set/Get the image origin on a axis-by-axis basis. The SetOrigin() method * is required when writing the image. */ virtual void SetOrigin(unsigned int i, double origin); virtual double GetOrigin(unsigned int i) const { return m_Origin[i]; } /** Set/Get the image spacing on an axis-by-axis basis. The * SetSpacing() method is required when writing the image. */ virtual void SetSpacing(unsigned int i, double spacing); virtual double GetSpacing(unsigned int i) const { return m_Spacing[i]; } /** Set/Get the image direction on an axis-by-axis basis. The * SetDirection() method is required when writing the image. */ virtual void SetDirection(unsigned int i, std::vector &direction); virtual void SetDirection(unsigned int i, vnl_vector &direction); virtual std::vector GetDirection(unsigned int i) const { return m_Direction[i]; } /** Return the directions to be assigned by default to recipient * images whose dimension is smaller than the image dimension in file. */ virtual std::vector GetDefaultDirection(unsigned int i) const; /** Specify the region of the image data to either read or * write. The IORegion specifies the part of the image to read or * write. Regions are defined with an index and a size vector. These * vectors define the start (lower-left corner) and length of the * region within the image. Make sure that the IORegion lies within * the image. */ itkSetMacro(IORegion, ImageIORegion); itkGetConstReferenceMacro(IORegion, ImageIORegion); /** Set/Get the type of the pixel. The PixelTypes provides context * to the IO mechanisms for data conversions. PixelTypes can be * SCALAR, RGB, RGBA, VECTOR, COVARIANTVECTOR, POINT, INDEX. If * the PIXELTYPE is SCALAR, then the NumberOfComponents should be 1. * Anyother of PIXELTYPE will have more than one component. */ itkSetEnumMacro(PixelType, IOPixelType); itkGetEnumMacro(PixelType, IOPixelType); /** SetPixelTypeInfo is used by writers to convert from an ITK * strongly typed pixel to a ImageIO (weaker) typed pixel. This * function sets these PixelType, ComponentType, and * NumberOfComponents based on RTTI type_info structure passed * in. The function returns false if the pixel type is not * supported. */ virtual bool SetPixelTypeInfo(const std::type_info& ptype); /** Set/Get the component type of the image. This is always a native * type. */ itkSetEnumMacro(ComponentType,IOComponentType); itkGetEnumMacro(ComponentType,IOComponentType); virtual const std::type_info& GetComponentTypeInfo() const; /** Set/Get the number of components per pixel in the image. This may * be set by the reading process. For SCALAR pixel types, * NumberOfComponents will be 1. For other pixel types, * NumberOfComponents will be greater than or equal to one. */ itkSetMacro(NumberOfComponents,unsigned int); itkGetConstReferenceMacro(NumberOfComponents,unsigned int); /** Set/Get a boolean to use the compression or not. */ itkSetMacro(UseCompression,bool); itkGetConstMacro(UseCompression,bool); itkBooleanMacro(UseCompression); /** Set/Get a boolean to use streaming while reading or not. */ itkSetMacro(UseStreamedReading,bool); itkGetConstMacro(UseStreamedReading,bool); itkBooleanMacro(UseStreamedReading); /** Set/Get a boolean to use streaming while writing or not. */ itkSetMacro(UseStreamedWriting,bool); itkGetConstMacro(UseStreamedWriting,bool); itkBooleanMacro(UseStreamedWriting); /** Convenience method returns the IOComponentType as a string. This can be * used for writing output files. */ std::string GetComponentTypeAsString(IOComponentType) const; /** Convenience method returns the IOPixelType as a string. This can be * used for writing output files. */ std::string GetPixelTypeAsString(IOPixelType) const; /** Enums used to specify write style: whether binary or ASCII. Some * subclasses use this, some ignore it. */ typedef enum {ASCII,Binary,TypeNotApplicable} FileType; /** Enums used to specify byte order; whether Big Endian or Little Endian. * Some subclasses use this, some ignore it. */ typedef enum {BigEndian,LittleEndian,OrderNotApplicable} ByteOrder; /** These methods control whether the file is written binary or ASCII. * Many file formats (i.e., subclasses) ignore this flag. */ itkSetEnumMacro(FileType,FileType); itkGetEnumMacro(FileType,FileType); void SetFileTypeToASCII() { this->SetFileType(ASCII); } void SetFileTypeToBinary() { this->SetFileType(Binary); } /** These methods indicate the byte ordering of the file you are * trying to read in. These methods will then either swap or not * swap the bytes depending on the byte ordering of the machine it * is being run on. For example, reading in a BigEndian file on a * BigEndian machine will result in no swapping. Trying to read the * same file on a LittleEndian machine will result in swapping. * Note: most UNIX machines are BigEndian while PC's and VAX's are * LittleEndian. So if the file you are reading in was generated on * a VAX or PC, SetByteOrderToLittleEndian() otherwise * SetByteOrderToBigEndian(). Some ImageIOBase subclasses * ignore these methods. */ itkSetEnumMacro(ByteOrder,ByteOrder); itkGetEnumMacro(ByteOrder,ByteOrder); void SetByteOrderToBigEndian() { this->SetByteOrder(BigEndian); } void SetByteOrderToLittleEndian() { this->SetByteOrder(LittleEndian); } /** Convenience method returns the FileType as a string. This can be * used for writing output files. */ std::string GetFileTypeAsString(FileType) const; /** Convenience method returns the ByteOrder as a string. This can be * used for writing output files. */ std::string GetByteOrderAsString(ByteOrder) const; /** Type for representing size of bytes, and or positions along a file */ typedef std::streamoff SizeType; /** Type for representing size of bytes, and or positions along a memory buffer */ typedef size_t BufferSizeType; /** Convenient method for accessing the number of bytes to get to * the next pixel. Returns m_Strides[1]; * * Please note that this methods depends the private methods * ComputeStrides being called, otherwise this is the incorrect value. */ virtual SizeType GetPixelStride () const; /** Return the number of pixels in the image. */ SizeType GetImageSizeInPixels() const; /** Return the number of bytes in the image. */ SizeType GetImageSizeInBytes() const; /** Return the number of pixels times the number * of components in the image. */ SizeType GetImageSizeInComponents() const; /** Compute the size (in bytes) of the components of a pixel. For * example, and RGB pixel of unsigned char would have a * component size of 1 byte. This method can be invoked only after * the component type is set. */ virtual unsigned int GetComponentSize() const; /*-------- This part of the interfaces deals with reading data ----- */ /** Determine the file type. Returns true if this ImageIO can read the * file specified. */ virtual bool CanReadFile(const char*) = 0; /** Determine if the ImageIO can stream reading from this file. Default is false. */ virtual bool CanStreamRead() { return false; } /** Read the spacing and dimentions of the image. * Assumes SetFileName has been called with a valid file name. */ virtual void ReadImageInformation() = 0; /** Reads the data from disk into the memory buffer provided. */ virtual void Read(void* buffer) = 0; /*-------- This part of the interfaces deals with writing data ----- */ /** Determine the file type. Returns true if this ImageIO can read the * file specified. */ virtual bool CanWriteFile(const char*) = 0; /** Determine if the ImageIO can stream writing to this file. Default is false. * * There are two types of non exclusive streaming: pasteing subregions, and iterative * If true then */ virtual bool CanStreamWrite() { return false; } /** Writes the spacing and dimentions of the image. * Assumes SetFileName has been called with a valid file name. */ virtual void WriteImageInformation() = 0; /** Writes the data to disk from the memory buffer provided. Make sure * that the IORegions has been set properly. The buffer is cast to a * pointer to the beginning of the image data. */ virtual void Write( const void* buffer) = 0; /* --- Support reading and writing data as a series of files. --- */ /** The different types of ImageIO's can support data of varying * dimensionality. For example, some file formats are strictly 2D * while others can support 2D, 3D, or even n-D. This method returns * true/false as to whether the ImageIO can support the dimension * indicated. */ virtual bool SupportsDimension(unsigned long dim) { return (dim == 2); } /** Method for supporting streaming. Given a requested region, determine what * could be the region that we can read from the file. This is called the * streamable region, which will be equal or smaller than the * LargestPossibleRegion (unless it was dimensionaly clipped) and * greater or equal to the RequestedRegion * * the resulting IORegion may be a greater dimensions the the * requested IORegion, if the the derived class is unable to read * the requested region. For example if the file has a size of [ 10, * 10, 10] but the requested region is [10, 10] the return may be 3 dimensions. */ virtual ImageIORegion GenerateStreamableReadRegionFromRequestedRegion( const ImageIORegion & requested ) const; /** Before this method is called all the configuration will be done, * that is Streaming/PasteRegion/Compression/Filename etc * If pasting is being used the number of requested splits is for that * region not the largest. The derived ImageIO class should verify that * the file is capable of being writen with this configuration. * If pasted is enabled and is not support or does not work with the file, * then an excepetion should be thrown. * * The default implementation depends on CanStreamWrite. * If false then 1 is returned (unless pasting is indicated), so that the whole file will be updated in one region. * If true then its assumed that any arbitrary region can be writen * to any file. So the users request will be respected. If a derived * class has more restictive conditions then they should be checked */ virtual unsigned int GetActualNumberOfSplitsForWriting(unsigned int numberOfRequestedSplits, const ImageIORegion &pasteRegion, const ImageIORegion &largestPossibleRegion); /** returns the ith IORegion * * numberOfActualSplits should be the value returned from GetActualNumberOfSplitsForWriting with the same parameters * * Derieved classes should overload this method to return a compatible region */ virtual ImageIORegion GetSplitRegionForWriting(unsigned int ithPiece, unsigned int numberOfActualSplits, const ImageIORegion &pasteRegion, const ImageIORegion &largestPossibleRegion); /** Type for the list of strings to be used for extensions. */ typedef std::vector< std::string > ArrayOfExtensionsType; /** This method returns an array with the list of filename extensions * supported for reading by this ImageIO class. This is intended to * facilitate GUI and application level integration. */ const ArrayOfExtensionsType & GetSupportedReadExtensions() const; /** This method returns an array with the list of filename extensions * supported for writing by this ImageIO class. This is intended to * facilitate GUI and application level integration. */ const ArrayOfExtensionsType & GetSupportedWriteExtensions() const; protected: ImageIOBase(); ~ImageIOBase(); void PrintSelf(std::ostream& os, Indent indent) const; /** Used internally to keep track of the type of the pixel. */ IOPixelType m_PixelType; /** Used internally to keep track of the type of the component. It is set * when ComputeStrides() is invoked. */ IOComponentType m_ComponentType; /** Big or Little Endian, and the type of the file. (May be ignored.) */ ByteOrder m_ByteOrder; FileType m_FileType; /** Does the ImageIOBase object have enough info to be of use? */ bool m_Initialized; /** Filename to read */ std::string m_FileName; /** Stores the number of components per pixel. This will be 1 for * grayscale images, 3 for RGBPixel images, and 4 for RGBPixelA images. */ unsigned int m_NumberOfComponents; /** The number of independent dimensions in the image. */ unsigned int m_NumberOfDimensions; /** Should we compress the data? */ bool m_UseCompression; /** Should we use streaming for reading */ bool m_UseStreamedReading; /** Should we use streaming for writing */ bool m_UseStreamedWriting; /** The region to read or write. The region contains information about the * data within the region to read or write. */ ImageIORegion m_IORegion; /** The array which stores the number of pixels in the x, y, z directions. */ std::vector< SizeValueType > m_Dimensions; /** The array which stores the spacing of pixels in the * x, y, z directions. */ std::vector m_Spacing; /** The array which stores the origin of the image. */ std::vector m_Origin; /** The arrays which store the direction cosines of the image. */ std::vector > m_Direction; /** Stores the number of bytes it takes to get to the next 'thing' * e.g. component, pixel, row, slice, etc. */ std::vector< SizeType > m_Strides; /** Return the object to an initialized state, ready to be used */ virtual void Reset(const bool freeDynamic = true); /** Resize the ImageIOBase object to new dimensions. */ void Resize(const unsigned int numDimensions, const unsigned int* dimensions); /** Compute the size (in bytes) of the pixel. For * example, and RGB pixel of unsigned char would have size 3 bytes. */ virtual unsigned int GetPixelSize() const; /** Calculates the different strides (distance from one thing to the next). * Upon return, * strides[0] = bytes to get to the next component of a pixel, * strides[1] = bytes to get to the next pixel in x direction, * strides[2] = bytes to get to the next row in y direction, * strides[3] = bytes to get to the next slice in z direction, etc. */ void ComputeStrides(); /** Convenient method for accessing number of bytes to get to the next pixel * component. Returns m_Strides[0]. */ SizeType GetComponentStride() const; /** Convenient method for accessing the number of bytes to get to the * next row. Returns m_Strides[2]. */ SizeType GetRowStride () const; /** Convenient method for accessing the number of bytes to get to the * next slice. Returns m_Strides[3]. */ SizeType GetSliceStride () const; /** Convenient method to write a buffer as ASCII text. */ void WriteBufferAsASCII(std::ostream& os, const void *buffer, IOComponentType ctype, SizeType numberOfBytesToWrite); /** Convenient method to read a buffer as ASCII text. */ void ReadBufferAsASCII(std::istream& os, void *buffer, IOComponentType ctype, SizeType numberOfBytesToBeRead); /** Convenient method to read a buffer as binary. Return true on success. */ bool ReadBufferAsBinary(std::istream& os, void *buffer, SizeType numberOfBytesToBeRead); /** Insert an extension to the list of supported extensions for reading. */ void AddSupportedReadExtension( const char * extension ); /** Insert an extension to the list of supported extensions for writing. */ void AddSupportedWriteExtension( const char * extension ); /** an implementation of ImageRegionSplitter:GetNumberOfSplits */ virtual unsigned int GetActualNumberOfSplitsForWritingCanStreamWrite(unsigned int numberOfRequestedSplits, const ImageIORegion &pasteRegion) const; /** an implementation of ImageRegionSplitter:GetSplit */ virtual ImageIORegion GetSplitRegionForWritingCanStreamWrite(unsigned int ithPiece, unsigned int numberOfActualSplits, const ImageIORegion &pasteRegion) const; private: ImageIOBase(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented ArrayOfExtensionsType m_SupportedReadExtensions; ArrayOfExtensionsType m_SupportedWriteExtensions; }; } // end namespace itk #endif // __itkImageIOBase_h plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/itkImageIORegion.h000077500000000000000000000232371321604176500272660ustar00rootroot00000000000000/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkImageIORegion.h,v $ Language: C++ Date: $Date: 2009-07-12 10:52:54 $ Version: $Revision: 1.25 $ 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. =========================================================================*/ #ifndef __itkImageIORegion_h #define __itkImageIORegion_h #include #include #include "itkRegion.h" #include "itkObjectFactory.h" #include "itkImageRegion.h" #include "itkIndex.h" #include "itkSize.h" namespace itk { /** \class ImageIORegion * \brief An ImageIORegion represents a structured region of data. * * ImageIORegion is an class that represents some structured portion or * piece of an Image. The ImageIORegion is represented with an index and * a size in each of the n-dimensions of the image. (The index is the * corner of the image, the size is the lengths of the image in each of * the topological directions.) ImageIORegion is not templated over * dimension, but uses dynamic arrays instead. * * The first pixel of an image always have a Zero index. Therefore the * index values of ImageIORegion may not directly correspond to those * of ImageRegion. When translation between the two is performed one * much consider the largest possible region who has a non-zero * starting index for the image. * * \sa Region * \sa ImageRegion * \sa Index * \sa Size * \sa MeshRegion */ class ITK_EXPORT ImageIORegion: public Region { public: /** Standard class typedefs. */ typedef ImageIORegion Self; typedef Region Superclass; /** these types correspond to those of itk::Size, itk::Offset and itk::Index */ typedef size_t SizeValueType; typedef ptrdiff_t IndexValueType; typedef ptrdiff_t OffsetValueType; /** Index typedef support. An index is used to access pixel values. */ typedef std::vector IndexType; /** Size typedef support. A size is used to define region bounds. */ typedef std::vector SizeType; /** Region type taken from the superclass */ typedef Superclass::RegionType RegionType; /** Standard part of all itk objects. */ itkTypeMacro(ImageIORegion, Region); /** Dimension of the image available at run time. */ unsigned int GetImageDimension() const; /** Dimension of the region to be written. This differs from the * the image dimension and is calculated at run-time by examining * the size of the image in each coordinate direction. */ unsigned int GetRegionDimension() const; /** Return the region type. Images are described with structured regions. */ virtual RegionType GetRegionType() const; /** Constructor. ImageIORegion is a lightweight object that is not reference * counted, so the constructor is public. */ ImageIORegion(unsigned int dimension); /** Constructor. ImageIORegion is a lightweight object that is not reference * counted, so the constructor is public. Default dimension is 2. */ ImageIORegion(); /** Destructor. ImageIORegion is a lightweight object that is not reference * counted, so the destructor is public. */ virtual ~ImageIORegion(); /** Copy constructor. ImageIORegion is a lightweight object that is not * reference counted, so the copy constructor is public. */ ImageIORegion(const Self& region); /** operator=. ImageIORegion is a lightweight object that is not reference * counted, so operator= is public. */ void operator=(const Self& region); /** Set the index defining the corner of the region. */ void SetIndex(const IndexType &index); /** Get index defining the corner of the region. */ const IndexType & GetIndex() const; /** Set the size of the region. This plus the index determines the * rectangular shape, or extent, of the region. */ void SetSize(const SizeType &size); /** Get the size of the region. */ const SizeType & GetSize() const; /** Convenience methods to get the size of the image in a particular * coordinate direction i. Do not try to access image sizes beyond the * the ImageDimension. */ SizeValueType GetSize(unsigned long i) const; IndexValueType GetIndex(unsigned long i) const; void SetSize(const unsigned long i, SizeValueType size); void SetIndex(const unsigned long i, IndexValueType idx); /** Compare two regions. */ bool operator==(const Self ®ion) const; /** Compare two regions. */ bool operator!=(const Self ®ion) const; /** Test if an index is inside */ bool IsInside(const IndexType &index) const; /** Test if a region (the argument) is completly inside of this region */ bool IsInside(const Self ®ion) const; /** Get the number of pixels contained in this region. This just * multiplies the size components. */ SizeValueType GetNumberOfPixels( void ) const; protected: /** Methods invoked by Print() to print information about the object * including superclasses. Typically not called by the user (use Print() * instead) but used in the hierarchical print process to combine the * output of several classes. */ virtual void PrintSelf(std::ostream& os, Indent indent) const; private: unsigned int m_ImageDimension; IndexType m_Index; SizeType m_Size; }; // Declare operator<< extern std::ostream & operator<<(std::ostream &os, const ImageIORegion ®ion); /** \class ImageIORegionAdaptor * \brief Helper class for converting ImageRegions into ImageIORegions and back. * **/ template< unsigned int VDimension > class ImageIORegionAdaptor { public: typedef ImageRegion ImageRegionType; typedef ImageIORegion ImageIORegionType; typedef typename ImageRegionType::SizeType ImageSizeType; typedef typename ImageRegionType::IndexType ImageIndexType; itkLegacyMacro(static void Convert( const ImageRegionType & outImageRegion, ImageIORegionType & inIORegion) ); static void Convert( const ImageRegionType & inImageRegion, ImageIORegionType & outIORegion, const ImageIndexType &largestRegionIndex) { // // The ImageRegion and ImageIORegion objects may have different dimensions. // Here we only copy the common dimensions between the two. If the ImageRegion // has more dimensions than the ImageIORegion, then the defaults of the ImageRegion // will take care of the remaining codimension. If the ImageRegion has less dimensions // than the ImageIORegion, then the remaining IO dimensions are simply ignored. // const unsigned int ioDimension = outIORegion.GetImageDimension(); const unsigned int imageDimension = VDimension; unsigned int minDimension = ( ioDimension > imageDimension ) ? imageDimension : ioDimension; ImageSizeType size = inImageRegion.GetSize(); ImageIndexType index = inImageRegion.GetIndex(); for( unsigned int i = 0; i < minDimension; i++ ) { outIORegion.SetSize( i, size[i] ); outIORegion.SetIndex( i, index[i] - largestRegionIndex[i]); } // // Fill in the remaining codimension (if any) with default values // for( unsigned int k = minDimension; k < ioDimension; k++ ) { outIORegion.SetSize( k, 1 ); // Note that default size in IO is 1 not 0 outIORegion.SetIndex( k, 0 ); } } itkLegacyMacro(static void Convert( const ImageIORegionType & inIORegion, ImageRegionType & outImageRegion) ); static void Convert( const ImageIORegionType & inIORegion, ImageRegionType & outImageRegion, const ImageIndexType &largestRegionIndex ) { ImageSizeType size; ImageIndexType index; size.Fill(1); // initialize with default values index.Fill(0); // // The ImageRegion and ImageIORegion objects may have different dimensions. // Here we only copy the common dimensions between the two. If the ImageRegion // has more dimensions than the ImageIORegion, then the defaults of the ImageRegion // will take care of the remaining codimension. If the ImageRegion has less dimensions // than the ImageIORegion, then the remaining IO dimensions are simply ignored. // const unsigned int ioDimension = inIORegion.GetImageDimension(); const unsigned int imageDimension = VDimension; unsigned int minDimension = ( ioDimension > imageDimension ) ? imageDimension : ioDimension; for(unsigned int i=0; i void ImageIORegionAdaptor::Convert( const ImageRegionType & inImageRegion, ImageIORegionType & outIORegion ) { itkGenericLegacyBodyMacro(ImageIORegionAdaptor::Convert, 4.0); // the index argument is required ImageIndexType index; index.Fill(0); ImageIORegionAdaptor::Convert(inImageRegion, outIORegion, index); } template< unsigned int VDimension > void ImageIORegionAdaptor::Convert( const ImageIORegionType & inIORegion, ImageRegionType & outImageRegion ) { itkGenericLegacyBodyMacro(ImageIORegionAdaptor::Convert, 4.0); // the index argument is required ImageIndexType index; index.Fill(0); ImageIORegionAdaptor::Convert(inIORegion, outImageRegion, index); } #endif } // end namespace itk #endif plm_DirectedHausdorffDistanceImageFilter.h000077500000000000000000000152561321604176500341040ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: plm_DirectedHausdorffDistanceImageFilter.h,v $ Language: C++ Date: $Date: 2009-04-25 12:27:21 $ Version: $Revision: 1.11 $ 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. =========================================================================*/ #ifndef __plm_DirectedHausdorffDistanceImageFilter_h #define __plm_DirectedHausdorffDistanceImageFilter_h #include "itkImageToImageFilter.h" #include "itkNumericTraits.h" #include "itkArray.h" #include "itkImage.h" namespace itk { /** \class plm_DirectedHausdorffDistanceImageFilter * \brief Computes the directed Hausdorff distance between the set of * non-zero pixels of two images. * * plm_DirectedHausdorffDistanceImageFilter computes the distance between the set * non-zero pixels of two images using the following formula: * \f[ h(A,B) = \max_{a \in A} \min_{b \in B} \| a - b\| \f] * where \f$A\f$ and \f$B\f$ are respectively the set of non-zero pixels * in the first and second input images. It identifies the point \f$ a \in A \f$ * that is farthest from any point of \f$B\f$ and measures the distance from \f$a\f$ * to the nearest neighbor in \f$B\f$. Note that this function is not * is not symmetric and hence is not a true distance. * * In particular, this filter uses the DanielssonDistanceMapImageFilter inside to * compute distance map from all non-zero pixels in the second image. It then * find the largest distance (in pixels) within the set of all non-zero pixels in the first * image. * * Use HausdorffDistanceImageFilter to compute the full Hausdorff distance. * * This filter requires the largest possible region of the first image * and the same corresponding region in the second image. * It behaves as filter with * two input and one output. Thus it can be inserted in a pipeline with * other filters. The filter passes the first input through unmodified. * * This filter is templated over the two input image type. It assume * both image have the same number of dimensions. * * \sa DanielssonDistanceMapImageFilter * \sa HausdorffDistanceImageFilter * * \ingroup MultiThreaded */ template class ITK_EXPORT plm_DirectedHausdorffDistanceImageFilter : public ImageToImageFilter { public: /** Standard Self typedef */ typedef plm_DirectedHausdorffDistanceImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Runtime information support. */ itkTypeMacro(plm_DirectedHausdorffDistanceImageFilter, ImageToImageFilter); /** Image related typedefs. */ typedef TInputImage1 InputImage1Type; typedef TInputImage2 InputImage2Type; typedef typename TInputImage1::Pointer InputImage1Pointer; typedef typename TInputImage2::Pointer InputImage2Pointer; typedef typename TInputImage1::ConstPointer InputImage1ConstPointer; typedef typename TInputImage2::ConstPointer InputImage2ConstPointer; typedef typename TInputImage1::RegionType RegionType; typedef typename TInputImage1::SizeType SizeType; typedef typename TInputImage1::IndexType IndexType; typedef typename TInputImage1::PixelType InputImage1PixelType; typedef typename TInputImage2::PixelType InputImage2PixelType; /** Image related typedefs. */ itkStaticConstMacro(ImageDimension, unsigned int, TInputImage1::ImageDimension); /** Type to use form computations. */ typedef typename NumericTraits::RealType RealType; /** Set the first input. */ void SetInput1( const InputImage1Type * image ) { this->SetInput( image ); } /** Set the second input. */ void SetInput2( const InputImage2Type * image ); /** Get the first input. */ const InputImage1Type * GetInput1(void) { return this->GetInput(); } /** Get the second input. */ const InputImage2Type * GetInput2(void); /** Return the computed directed Hausdorff distance. */ itkGetConstMacro(DirectedHausdorffDistance,RealType); itkGetConstMacro(AverageHausdorffDistance,RealType); /** Set if image spacing should be used in computing distances. */ itkSetMacro( UseImageSpacing, bool ); #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(InputHasNumericTraitsCheck, (Concept::HasNumericTraits)); /** End concept checking */ #endif protected: plm_DirectedHausdorffDistanceImageFilter(); ~plm_DirectedHausdorffDistanceImageFilter(){}; void PrintSelf(std::ostream& os, Indent indent) const; /** Pass the input through unmodified. Do this by Grafting in the * AllocateOutputs method. */ void AllocateOutputs(); /** Initialize some accumulators before the threads run. */ void BeforeThreadedGenerateData (); /** Do final mean and variance computation from data accumulated in threads. */ void AfterThreadedGenerateData (); /** Multi-thread version GenerateData. */ void ThreadedGenerateData (const RegionType& outputRegionForThread, int threadId); // Override since the filter needs all the data for the algorithm void GenerateInputRequestedRegion(); // Override since the filter produces all of its output void EnlargeOutputRequestedRegion(DataObject *data); private: plm_DirectedHausdorffDistanceImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented typedef Image DistanceMapType; typename DistanceMapType::Pointer m_DistanceMap; Array m_MaxDistance; Array m_PixelCount; Array m_Sum; RealType m_DirectedHausdorffDistance; RealType m_AverageHausdorffDistance; bool m_UseImageSpacing; }; // end of class } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "plm_DirectedHausdorffDistanceImageFilter.hxx" #endif #endif plm_DirectedHausdorffDistanceImageFilter.hxx000077500000000000000000000146371321604176500344660ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: plm_DirectedHausdorffDistanceImageFilter.txx,v $ Language: C++ Date: $Date: 2008-10-14 19:20:33 $ Version: $Revision: 1.14 $ 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. =========================================================================*/ #ifndef __plm_DirectedHausdorffDistanceImageFilter_hxx #define __plm_DirectedHausdorffDistanceImageFilter_hxx #include "plm_DirectedHausdorffDistanceImageFilter.h" #include "itkImageRegionIterator.h" #include "itkImageRegionConstIterator.h" #include "itkNumericTraits.h" #include "itkDanielssonDistanceMapImageFilter.h" #include "itkProgressReporter.h" #include "itkImageFileWriter.h" namespace itk { template plm_DirectedHausdorffDistanceImageFilter ::plm_DirectedHausdorffDistanceImageFilter(): m_MaxDistance(1) { // this filter requires two input images this->SetNumberOfRequiredInputs( 2 ); m_DistanceMap = NULL; m_DirectedHausdorffDistance = NumericTraits::Zero; m_AverageHausdorffDistance = NumericTraits::Zero; m_UseImageSpacing = false; } template void plm_DirectedHausdorffDistanceImageFilter ::SetInput2( const TInputImage2 * image ) { this->SetNthInput(1, const_cast( image ) ); } template const typename plm_DirectedHausdorffDistanceImageFilter ::InputImage2Type * plm_DirectedHausdorffDistanceImageFilter ::GetInput2() { return static_cast< const TInputImage2 * > (this->ProcessObject::GetInput(1)); } template void plm_DirectedHausdorffDistanceImageFilter ::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); // this filter requires: // - the largeset possible region of the first image // - the corresponding region of the second image if ( this->GetInput1() ) { InputImage1Pointer image1 = const_cast< InputImage1Type * >( this->GetInput1() ); image1->SetRequestedRegionToLargestPossibleRegion(); if ( this->GetInput2() ) { InputImage2Pointer image2 = const_cast< InputImage2Type * >( this->GetInput2() ); image2->SetRequestedRegion( this->GetInput1()->GetRequestedRegion() ); } } } template void plm_DirectedHausdorffDistanceImageFilter ::EnlargeOutputRequestedRegion(DataObject *data) { Superclass::EnlargeOutputRequestedRegion(data); data->SetRequestedRegionToLargestPossibleRegion(); } template void plm_DirectedHausdorffDistanceImageFilter ::AllocateOutputs() { // Pass the first input through as the output InputImage1Pointer image = const_cast< TInputImage1 * >( this->GetInput1() ); this->GraftOutput( image ); } template void plm_DirectedHausdorffDistanceImageFilter ::BeforeThreadedGenerateData() { int numberOfThreads = this->GetNumberOfThreads(); // Resize the thread temporaries m_MaxDistance.SetSize(numberOfThreads); m_PixelCount.SetSize(numberOfThreads); m_Sum.SetSize(numberOfThreads); // Initialize the temporaries m_MaxDistance.Fill(NumericTraits::Zero); m_PixelCount.Fill(0); m_Sum.Fill(NumericTraits::Zero); // Compute Danielsson distance from non-zero pixels in the second image typedef itk::DanielssonDistanceMapImageFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); filter->SetInput( this->GetInput2() ); filter->SetUseImageSpacing(m_UseImageSpacing); filter->Update(); m_DistanceMap = filter->GetOutput(); } template void plm_DirectedHausdorffDistanceImageFilter ::AfterThreadedGenerateData() { int i; int numberOfThreads = this->GetNumberOfThreads(); m_DirectedHausdorffDistance = NumericTraits::Zero; RealType sum = NumericTraits::Zero; unsigned int pixelcount = 0; // find max over all threads for( i = 0; i < numberOfThreads; i++) { if ( m_MaxDistance[i] > m_DirectedHausdorffDistance ) { m_DirectedHausdorffDistance = m_MaxDistance[i]; } pixelcount += m_PixelCount[i]; sum += m_Sum[i]; } m_AverageHausdorffDistance = sum / (RealType) pixelcount; // clean up m_DistanceMap = NULL; } template void plm_DirectedHausdorffDistanceImageFilter ::ThreadedGenerateData(const RegionType& regionForThread, int threadId) { ImageRegionConstIterator it1 (this->GetInput1(), regionForThread); ImageRegionConstIterator it2 (m_DistanceMap, regionForThread); // support progress methods/callbacks ProgressReporter progress(this, threadId, regionForThread.GetNumberOfPixels()); // do the work while (!it1.IsAtEnd()) { if( it1.Get() != NumericTraits::Zero ) { if ( it2.Get() > m_MaxDistance[threadId] ) { m_MaxDistance[threadId] = it2.Get(); } m_PixelCount[threadId]++; m_Sum[threadId] += it2.Get(); } ++it1; ++it2; progress.CompletedPixel(); } } template void plm_DirectedHausdorffDistanceImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); os << indent << "DirectedHausdorffDistance: " << m_DirectedHausdorffDistance << std::endl; os << indent << "AverageHausdorffDistance: " << m_AverageHausdorffDistance << std::endl; os << indent << "Use Image Spacing : " << m_UseImageSpacing << std::endl; } }// end namespace itk #endif plm_HausdorffDistanceImageFilter.h000077500000000000000000000123131321604176500324270ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/*========================================================================= Program: Plastimatch Module: $RCSfile: plmHausdorffDistanceImageFilter.h,v $ Language: C++ Date: $Date: 2011-05-01 $ Version: $Revision: 1.0 $ =========================================================================*/ #ifndef __plm_HausdorffDistanceImageFilter_h #define __plm_HausdorffDistanceImageFilter_h #include "itkImageToImageFilter.h" #include "itkNumericTraits.h" namespace itk { /** \class plm_HausdorffDistanceImageFilter * \brief Computes the Hausdorff distance between the set of * non-zero pixels of two images. * * * plm_HausdorffDistanceImageFilter computes the distance between the set * non-zero pixels of two images using the following formula: * \f[ H(A,B) = \max(h(A,B),h(B,A)) \f] * where * \f[ h(A,B) = \max_{a \in A} \min_{b \in B} \| a - b\| \f] is the directed * Hausdorff distance * and \f$A\f$ and \f$B\f$ are respectively the set of non-zero pixels * in the first and second input images. * * In particular, this filter uses the DirectedHausdorffImageFilter inside to * compute the two directed distances and then select the largest of the two. * * The Hausdorff distance measures the degree of mismatch between two sets and * behaves like a metric over the set of all closedm bounded sets - * with properties of identity, symmetry and triangle inequality. * * This filter requires the largest possible region of the first image * and the same corresponding region in the second image. * It behaves as filter with * two input and one output. Thus it can be inserted in a pipeline with * other filters. The filter passes the first input through unmodified. * * This filter is templated over the two input image type. It assume * both image have the same number of dimensions. * * \sa DirectedHausdorffDistanceImageFilter * * \ingroup MultiThreaded */ template class ITK_EXPORT plm_HausdorffDistanceImageFilter : public ImageToImageFilter { public: /** Standard Self typedef */ typedef plm_HausdorffDistanceImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Runtime information support. */ itkTypeMacro(plm_HausdorffDistanceImageFilter, ImageToImageFilter); /** Image related typedefs. */ typedef TInputImage1 InputImage1Type; typedef TInputImage2 InputImage2Type; typedef typename TInputImage1::Pointer InputImage1Pointer; typedef typename TInputImage2::Pointer InputImage2Pointer; typedef typename TInputImage1::ConstPointer InputImage1ConstPointer; typedef typename TInputImage2::ConstPointer InputImage2ConstPointer; typedef typename TInputImage1::RegionType RegionType; typedef typename TInputImage1::SizeType SizeType; typedef typename TInputImage1::IndexType IndexType; typedef typename TInputImage1::PixelType InputImage1PixelType; typedef typename TInputImage2::PixelType InputImage2PixelType; /** Image related typedefs. */ itkStaticConstMacro(ImageDimension, unsigned int, TInputImage1::ImageDimension); /** Type to use form computations. */ typedef typename NumericTraits::RealType RealType; /** Set the first input. */ void SetInput1( const InputImage1Type * image ) { this->SetInput( image ); } /** Set the second input. */ void SetInput2( const InputImage2Type * image ); /** Get the first input. */ const InputImage1Type * GetInput1(void) { return this->GetInput(); } /** Get the second input. */ const InputImage2Type * GetInput2(void); /** Return the computed Hausdorff distance. */ itkGetConstMacro(HausdorffDistance,RealType); itkGetConstMacro(AverageHausdorffDistance,RealType); /** Set if image spacing should be used in computing distances. */ itkSetMacro( UseImageSpacing, bool ); #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(Input1HasNumericTraitsCheck, (Concept::HasNumericTraits)); /** End concept checking */ #endif protected: plm_HausdorffDistanceImageFilter(); ~plm_HausdorffDistanceImageFilter(){}; void PrintSelf(std::ostream& os, Indent indent) const; /** GenerateData. */ void GenerateData(); // Override since the filter needs all the data for the algorithm void GenerateInputRequestedRegion(); // Override since the filter produces all of its output void EnlargeOutputRequestedRegion(DataObject *data); private: plm_HausdorffDistanceImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented RealType m_HausdorffDistance; RealType m_AverageHausdorffDistance; bool m_UseImageSpacing; }; // end of class } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "plm_HausdorffDistanceImageFilter.hxx" #endif #endif plm_HausdorffDistanceImageFilter.hxx000077500000000000000000000122541321604176500330130ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: plm_HausdorffDistanceImageFilter.txx,v $ Language: C++ Date: $Date: 2008-10-16 16:45:09 $ Version: $Revision: 1.13 $ 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. =========================================================================*/ #ifndef __plm_HausdorffDistanceImageFilter_hxx #define __plm_HausdorffDistanceImageFilter_hxx #include "plm_HausdorffDistanceImageFilter.h" #include "itkImageRegionIterator.h" #include "itkImageRegionConstIterator.h" #include "itkNumericTraits.h" #include "itkProgressAccumulator.h" #include "plm_DirectedHausdorffDistanceImageFilter.h" namespace itk { template plm_HausdorffDistanceImageFilter ::plm_HausdorffDistanceImageFilter() { // this filter requires two input images this->SetNumberOfRequiredInputs( 2 ); m_HausdorffDistance = NumericTraits::Zero; m_AverageHausdorffDistance = NumericTraits::Zero; m_UseImageSpacing = false; } template void plm_HausdorffDistanceImageFilter ::SetInput2( const TInputImage2 * image ) { this->SetNthInput(1, const_cast( image ) ); } template const typename plm_HausdorffDistanceImageFilter ::InputImage2Type * plm_HausdorffDistanceImageFilter ::GetInput2() { return static_cast< const TInputImage2 * > (this->ProcessObject::GetInput(1)); } template void plm_HausdorffDistanceImageFilter ::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); // this filter requires: // - the largeset possible region of the first image // - the corresponding region of the second image if ( this->GetInput1() ) { InputImage1Pointer image1 = const_cast< InputImage1Type * >( this->GetInput1() ); image1->SetRequestedRegionToLargestPossibleRegion(); if ( this->GetInput2() ) { InputImage2Pointer image2 = const_cast< InputImage2Type * >( this->GetInput2() ); image2->SetRequestedRegion( this->GetInput1()->GetRequestedRegion() ); } } } template void plm_HausdorffDistanceImageFilter ::EnlargeOutputRequestedRegion(DataObject *data) { Superclass::EnlargeOutputRequestedRegion(data); data->SetRequestedRegionToLargestPossibleRegion(); } template void plm_HausdorffDistanceImageFilter ::GenerateData() { // Pass the first input through as the output InputImage1Pointer image = const_cast< TInputImage1 * >( this->GetInput1() ); this->GraftOutput( image ); RealType distance12, distance21; // Create a process accumulator for tracking the progress of this minipipeline ProgressAccumulator::Pointer progress = ProgressAccumulator::New(); progress->SetMiniPipelineFilter(this); typedef plm_DirectedHausdorffDistanceImageFilter Filter12Type; typename Filter12Type::Pointer filter12 = Filter12Type::New(); filter12->SetInput1( this->GetInput1() ); filter12->SetInput2( this->GetInput2() ); typedef plm_DirectedHausdorffDistanceImageFilter Filter21Type; typename Filter21Type::Pointer filter21 = Filter21Type::New(); filter21->SetInput1( this->GetInput2() ); filter21->SetInput2( this->GetInput1() ); // Register the filter with the with progress accumulator using // equal weight proportion progress->RegisterInternalFilter(filter12,.5f); progress->RegisterInternalFilter(filter21,.5f); filter12->SetUseImageSpacing(m_UseImageSpacing); filter21->SetUseImageSpacing(m_UseImageSpacing); filter12->Update(); distance12 = filter12->GetDirectedHausdorffDistance(); filter21->Update(); distance21 = filter21->GetDirectedHausdorffDistance(); if ( distance12 > distance21 ) { m_HausdorffDistance = distance12; } else { m_HausdorffDistance = distance21; } m_AverageHausdorffDistance = ( filter12->GetAverageHausdorffDistance() + filter21->GetAverageHausdorffDistance() ) / 2.0; } template void plm_HausdorffDistanceImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); os << indent << "HausdorffDistance: " << m_HausdorffDistance << std::endl; os << indent << "AverageHausdorffDistance: " << m_AverageHausdorffDistance << std::endl; os << indent << "Use Image Spacing : " << m_UseImageSpacing << std::endl; } }// end namespace itk #endif plm_OptMattesMutualInformationImageToImageMetric.h000066400000000000000000000414521321604176500356200ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: itkOptMattesMutualInformationImageToImageMetric.h Language: C++ Date: $Date$ Version: $Revision$ 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. =========================================================================*/ #ifndef __plm_MattesMutualInformationImageToImageMetric_h #define __plm_MattesMutualInformationImageToImageMetric_h #include "itkOptImageToImageMetric.h" #include "itkCovariantVector.h" #include "itkPoint.h" #include "itkIndex.h" #include "itkBSplineKernelFunction.h" #include "itkBSplineDerivativeKernelFunction.h" #include "itkCentralDifferenceImageFunction.h" #include "itkBSplineInterpolateImageFunction.h" #include "itkBSplineDeformableTransform.h" #include "itkArray2D.h" #include "itkMultiThreader.h" namespace itk { /** \class MattesMutualInformationImageToImageMetric * \brief Computes the mutual information between two images to be * registered using the method of Mattes et al. * * MattesMutualInformationImageToImageMetric computes the mutual * information between a fixed and moving image to be registered. * * This class is templated over the FixedImage type and the MovingImage * type. * * The fixed and moving images are set via methods SetFixedImage() and * SetMovingImage(). This metric makes use of user specified Transform and * Interpolator. The Transform is used to map points from the fixed image to * the moving image domain. The Interpolator is used to evaluate the image * intensity at user specified geometric points in the moving image. * The Transform and Interpolator are set via methods SetTransform() and * SetInterpolator(). * * If a BSplineInterpolationFunction is used, this class obtain * image derivatives from the BSpline interpolator. Otherwise, * image derivatives are computed using central differencing. * * \warning This metric assumes that the moving image has already been * connected to the interpolator outside of this class. * * The method GetValue() computes of the mutual information * while method GetValueAndDerivative() computes * both the mutual information and its derivatives with respect to the * transform parameters. * * The calculations are based on the method of Mattes et al [1,2] * where the probability density distribution are estimated using * Parzen histograms. Since the fixed image PDF does not contribute * to the derivatives, it does not need to be smooth. Hence, * a zero order (box car) BSpline kernel is used * for the fixed image intensity PDF. On the other hand, to ensure * smoothness a third order BSpline kernel is used for the * moving image intensity PDF. * * On Initialize(), the FixedImage is uniformly sampled within * the FixedImageRegion. The number of samples used can be set * via SetNumberOfSpatialSamples(). Typically, the number of * spatial samples used should increase with the image size. * * The option UseAllPixelOn() disables the random sampling and uses * all the pixels of the FixedImageRegion in order to estimate the * joint intensity PDF. * * During each call of GetValue(), GetDerivatives(), * GetValueAndDerivatives(), marginal and joint intensity PDF's * values are estimated at discrete position or bins. * The number of bins used can be set via SetNumberOfHistogramBins(). * To handle data with arbitray magnitude and dynamic range, * the image intensity is scale such that any contribution to the * histogram will fall into a valid bin. * * One the PDF's have been contructed, the mutual information * is obtained by doubling summing over the discrete PDF values. * * * Notes: * 1. This class returns the negative mutual information value. * 2. This class in not thread safe due the private data structures * used to the store the sampled points and the marginal and joint pdfs. * * References: * [1] "Nonrigid multimodality image registration" * D. Mattes, D. R. Haynor, H. Vesselle, T. Lewellen and W. Eubank * Medical Imaging 2001: Image Processing, 2001, pp. 1609-1620. * [2] "PET-CT Image Registration in the Chest Using Free-form Deformations" * D. Mattes, D. R. Haynor, H. Vesselle, T. Lewellen and W. Eubank * IEEE Transactions in Medical Imaging. Vol.22, No.1, January 2003. pp.120-128. * [3] "Optimization of Mutual Information for MultiResolution Image * Registration" * P. Thevenaz and M. Unser * IEEE Transactions in Image Processing, 9(12) December 2000. * * \ingroup RegistrationMetrics */ template class ITK_EXPORT plm_MattesMutualInformationImageToImageMetric : public ImageToImageMetric< TFixedImage, TMovingImage > { public: /** Standard class typedefs. */ typedef plm_MattesMutualInformationImageToImageMetric Self; typedef ImageToImageMetric< TFixedImage, TMovingImage > Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(plm_MattesMutualInformationImageToImageMetric, ImageToImageMetric); /** Types inherited from Superclass. */ typedef typename Superclass::TransformType TransformType; typedef typename Superclass::TransformPointer TransformPointer; typedef typename Superclass::TransformJacobianType TransformJacobianType; typedef typename Superclass::InterpolatorType InterpolatorType; typedef typename Superclass::MeasureType MeasureType; typedef typename Superclass::DerivativeType DerivativeType; typedef typename Superclass::ParametersType ParametersType; typedef typename Superclass::FixedImageType FixedImageType; typedef typename Superclass::MovingImageType MovingImageType; typedef typename Superclass::MovingImagePointType MovingImagePointType; typedef typename Superclass::FixedImageConstPointer FixedImageConstPointer; typedef typename Superclass::MovingImageConstPointer MovingImageConstPointer; typedef typename Superclass::BSplineTransformWeightsType BSplineTransformWeightsType; typedef typename Superclass::BSplineTransformIndexArrayType BSplineTransformIndexArrayType; typedef typename Superclass::CoordinateRepresentationType CoordinateRepresentationType; typedef typename Superclass::FixedImageSampleContainer FixedImageSampleContainer; typedef typename Superclass::ImageDerivativesType ImageDerivativesType; typedef typename Superclass::WeightsValueType WeightsValueType; typedef typename Superclass::IndexValueType IndexValueType; typedef typename FixedImageType::OffsetValueType OffsetValueType; /** The moving image dimension. */ itkStaticConstMacro( MovingImageDimension, unsigned int, MovingImageType::ImageDimension ); /** * Initialize the Metric by * (1) making sure that all the components are present and plugged * together correctly, * (2) uniformly select NumberOfSpatialSamples within * the FixedImageRegion, and * (3) allocate memory for pdf data structures. */ virtual void Initialize(void) throw ( ExceptionObject ); /** Get the value. */ MeasureType GetValue( const ParametersType & parameters ) const; /** Get the derivatives of the match measure. */ void GetDerivative( const ParametersType & parameters, DerivativeType & Derivative ) const; /** Get the value and derivatives for single valued optimizers. */ void GetValueAndDerivative( const ParametersType & parameters, MeasureType & Value, DerivativeType & Derivative ) const; /** Number of bins to used in the histogram. Typical value is * 50. The minimum value is 5 due to the padding required by the Parzen * windowing with a cubic-BSpline kernel. Note that even if the metric * is used on binary images, the number of bins should at least be * equal to five. */ itkSetClampMacro( NumberOfHistogramBins, unsigned long, 5, NumericTraits::max() ); itkGetConstReferenceMacro( NumberOfHistogramBins, unsigned long); /** This variable selects the method to be used for computing the Metric * derivatives with respect to the Transform parameters. Two modes of * computation are available. The choice between one and the other is a * trade-off between computation speed and memory allocations. The two modes * are described in detail below: * * UseExplicitPDFDerivatives = True * will compute the Metric derivative by first calculating the derivatives of * each one of the Joint PDF bins with respect to each one of the Transform * parameters and then accumulating these contributions in the final metric * derivative array by using a bin-specific weight. The memory required for * storing the intermediate derivatives is a 3D array of doubles with size * equals to the product of (number of histogram bins)^2 times number of * transform parameters. This method is well suited for Transform with a small * number of parameters. * * UseExplicitPDFDerivatives = False will compute the Metric derivative by * first computing the weights for each one of the Joint PDF bins and caching * them into an array. Then it will revisit each one of the PDF bins for * computing its weighted contribution to the full derivative array. In this * method an extra 2D array is used for storing the weights of each one of * the PDF bins. This is an array of doubles with size equals to (number of * histogram bins)^2. This method is well suited for Transforms with a large * number of parameters, such as, BSplineDeformableTransforms. */ itkSetMacro(UseExplicitPDFDerivatives,bool); itkGetConstReferenceMacro(UseExplicitPDFDerivatives,bool); itkBooleanMacro(UseExplicitPDFDerivatives); /*New methods to set min and max intensity values to manually define an intensity range for MI calculation. If values are not set by user min and max values will be calculated from images. */ itkSetMacro(FixedImageMin,double); itkSetMacro(FixedImageMax,double); itkSetMacro(MovingImageMin,double); itkSetMacro(MovingImageMax,double); protected: plm_MattesMutualInformationImageToImageMetric(); virtual ~plm_MattesMutualInformationImageToImageMetric(); void PrintSelf(std::ostream& os, Indent indent) const; private: //purposely not implemented plm_MattesMutualInformationImageToImageMetric(const Self &); //purposely not implemented void operator=(const Self &); /** The marginal PDFs are stored as std::vector. */ typedef float PDFValueType; typedef float * MarginalPDFType; mutable MarginalPDFType m_FixedImageMarginalPDF; /** The moving image marginal PDF. */ mutable MarginalPDFType m_MovingImageMarginalPDF; /** Helper array for storing the values of the JointPDF ratios. */ typedef double PRatioType; typedef Array2D< PRatioType > PRatioArrayType; mutable PRatioArrayType m_PRatioArray; /** Helper variable for accumulating the derivative of the metric. */ mutable DerivativeType m_MetricDerivative; mutable DerivativeType * m_ThreaderMetricDerivative; /** Typedef for the joint PDF and PDF derivatives are stored as ITK Images. */ typedef Image JointPDFType; typedef Image JointPDFDerivativesType; typedef JointPDFType::IndexType JointPDFIndexType; typedef JointPDFType::PixelType JointPDFValueType; typedef JointPDFType::RegionType JointPDFRegionType; typedef JointPDFType::SizeType JointPDFSizeType; typedef JointPDFDerivativesType::IndexType JointPDFDerivativesIndexType; typedef JointPDFDerivativesType::PixelType JointPDFDerivativesValueType; typedef JointPDFDerivativesType::RegionType JointPDFDerivativesRegionType; typedef JointPDFDerivativesType::SizeType JointPDFDerivativesSizeType; /** The joint PDF and PDF derivatives. */ typename JointPDFType::Pointer m_JointPDF; unsigned long m_JointPDFBufferSize; typename JointPDFDerivativesType::Pointer m_JointPDFDerivatives; unsigned long m_JointPDFDerivativesBufferSize; /** Variables to define the marginal and joint histograms. */ unsigned long m_NumberOfHistogramBins; double m_MovingImageNormalizedMin; double m_FixedImageNormalizedMin; double m_FixedImageMin; double m_FixedImageMax; double m_MovingImageMin; double m_MovingImageMax; double m_FixedImageBinSize; double m_MovingImageBinSize; /** Typedefs for BSpline kernel and derivative functions. */ typedef BSplineKernelFunction<3> CubicBSplineFunctionType; typedef BSplineDerivativeKernelFunction<3> CubicBSplineDerivativeFunctionType; /** Cubic BSpline kernel for computing Parzen histograms. */ typename CubicBSplineFunctionType::Pointer m_CubicBSplineKernel; typename CubicBSplineDerivativeFunctionType::Pointer m_CubicBSplineDerivativeKernel; /** Precompute fixed image parzen window indices. */ virtual void ComputeFixedImageParzenWindowIndices( FixedImageSampleContainer & samples ); /** Compute PDF derivative contribution for each parameter. */ virtual void ComputePDFDerivatives( unsigned int threadID, unsigned int sampleNumber, int movingImageParzenWindowIndex, const ImageDerivativesType & movingImageGradientValue, double cubicBSplineDerivativeValue ) const; PDFValueType * m_ThreaderFixedImageMarginalPDF; typename JointPDFType::Pointer * m_ThreaderJointPDF; typename JointPDFDerivativesType::Pointer * m_ThreaderJointPDFDerivatives; int * m_ThreaderJointPDFStartBin; int * m_ThreaderJointPDFEndBin; mutable double * m_ThreaderJointPDFSum; mutable double m_JointPDFSum; bool m_UseExplicitPDFDerivatives; mutable bool m_ImplicitDerivativesSecondPass; virtual inline void GetValueThreadPreProcess( unsigned int threadID, bool withinSampleThread ) const; virtual inline bool GetValueThreadProcessSample( unsigned int threadID, unsigned long fixedImageSample, const MovingImagePointType & mappedPoint, double movingImageValue ) const; virtual inline void GetValueThreadPostProcess( unsigned int threadID, bool withinSampleThread ) const; virtual inline void GetValueAndDerivativeThreadPreProcess( unsigned int threadID, bool withinSampleThread ) const; virtual inline bool GetValueAndDerivativeThreadProcessSample( unsigned int threadID, unsigned long fixedImageSample, const MovingImagePointType & mappedPoint, double movingImageValue, const ImageDerivativesType & movingImageGradientValue ) const; virtual inline void GetValueAndDerivativeThreadPostProcess( unsigned int threadID, bool withinSampleThread ) const; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "plm_OptMattesMutualInformationImageToImageMetric.hxx" #endif #endif plm_OptMattesMutualInformationImageToImageMetric.hxx000066400000000000000000001307771321604176500362110ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/itk-3.20.0/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: plm_MattesMutualInformationImageToImageMetric.txx Language: C++ Date: $Date$ Version: $Revision$ 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. =========================================================================*/ #ifndef __plm_MattesMutualInformationImageToImageMetric_txx #define __plm_MattesMutualInformationImageToImageMetric_txx #include "plm_OptMattesMutualInformationImageToImageMetric.h" #include "itkCovariantVector.h" #include "itkImageRandomConstIteratorWithIndex.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionIterator.h" #include "itkImageIterator.h" #include "vnl/vnl_math.h" #include "itkStatisticsImageFilter.h" #include "vnl/vnl_vector.txx" #include "vnl/vnl_c_vector.txx" namespace itk { /** * Constructor */ template < class TFixedImage, class TMovingImage > plm_MattesMutualInformationImageToImageMetric ::plm_MattesMutualInformationImageToImageMetric() { m_NumberOfHistogramBins = 50; this->SetComputeGradient(false); // don't use the default gradient for now // Initialize PDFs to NULL m_JointPDF = NULL; m_JointPDFDerivatives = NULL; // Initialize memory m_FixedImageMarginalPDF = NULL; m_MovingImageMarginalPDF = NULL; m_MovingImageNormalizedMin = 0.0; m_FixedImageNormalizedMin = 0.0; m_MovingImageMin = 0.0; m_MovingImageMax = 0.0; m_FixedImageMin = 0.0; m_FixedImageMax = 0.0; m_FixedImageBinSize = 0.0; m_MovingImageBinSize = 0.0; m_CubicBSplineDerivativeKernel = NULL; // For multi-threading the metric m_ThreaderFixedImageMarginalPDF = NULL; m_ThreaderJointPDF = NULL; m_ThreaderJointPDFDerivatives = NULL; m_ThreaderJointPDFStartBin = NULL; m_ThreaderJointPDFEndBin = NULL; m_ThreaderJointPDFSum = NULL; this->m_WithinThreadPreProcess = true; this->m_WithinThreadPostProcess = false; this->m_ThreaderMetricDerivative = NULL; this->m_UseExplicitPDFDerivatives = true; this->m_ImplicitDerivativesSecondPass = false; } template < class TFixedImage, class TMovingImage > plm_MattesMutualInformationImageToImageMetric ::~plm_MattesMutualInformationImageToImageMetric() { if(m_FixedImageMarginalPDF != NULL) { delete [] m_FixedImageMarginalPDF; } m_FixedImageMarginalPDF = NULL; if(m_MovingImageMarginalPDF != NULL) { delete [] m_MovingImageMarginalPDF; } m_MovingImageMarginalPDF = NULL; if(m_ThreaderJointPDF != NULL) { delete [] m_ThreaderJointPDF; } m_ThreaderJointPDF = NULL; if(m_ThreaderJointPDFDerivatives != NULL) { delete [] m_ThreaderJointPDFDerivatives; } m_ThreaderJointPDFDerivatives = NULL; if(m_ThreaderFixedImageMarginalPDF != NULL) { delete [] m_ThreaderFixedImageMarginalPDF; } m_ThreaderFixedImageMarginalPDF = NULL; if(m_ThreaderJointPDFStartBin != NULL) { delete [] m_ThreaderJointPDFStartBin; } m_ThreaderJointPDFStartBin = NULL; if(m_ThreaderJointPDFEndBin != NULL) { delete [] m_ThreaderJointPDFEndBin; } m_ThreaderJointPDFEndBin = NULL; if(m_ThreaderJointPDFSum != NULL) { delete [] m_ThreaderJointPDFSum; } m_ThreaderJointPDFSum = NULL; if( this->m_ThreaderMetricDerivative != NULL ) { delete [] this->m_ThreaderMetricDerivative; } this->m_ThreaderMetricDerivative = NULL; } /** * Print out internal information about this class */ template < class TFixedImage, class TMovingImage > void plm_MattesMutualInformationImageToImageMetric ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "NumberOfHistogramBins: "; os << this->m_NumberOfHistogramBins << std::endl; // Debugging information os << indent << "FixedImageNormalizedMin: "; os << this->m_FixedImageNormalizedMin << std::endl; os << indent << "MovingImageNormalizedMin: "; os << this->m_MovingImageNormalizedMin << std::endl; os << indent << "MovingImageMin: "; os << this->m_MovingImageMin << std::endl; os << indent << "MovingImageMax: "; os << this->m_MovingImageMax << std::endl; os << indent << "FixedImageBinSize: "; os << this->m_FixedImageBinSize << std::endl; os << indent << "MovingImageBinSize: "; os << this->m_MovingImageBinSize << std::endl; os << indent << "UseExplicitPDFDerivatives: "; os << this->m_UseExplicitPDFDerivatives << std::endl; os << indent << "ImplicitDerivativesSecondPass: "; os << this->m_ImplicitDerivativesSecondPass << std::endl; } /** * Initialize */ template void plm_MattesMutualInformationImageToImageMetric ::Initialize(void) throw ( ExceptionObject ) { this->Superclass::Initialize(); this->Superclass::MultiThreadingInitialize(); typedef StatisticsImageFilter FixedImageStatisticsFilterType; typename FixedImageStatisticsFilterType::Pointer fixedImageStats = FixedImageStatisticsFilterType::New(); float diffFixed =m_FixedImageMax-m_FixedImageMin; if(diffFixed<=0) { fixedImageStats->SetInput( this->m_FixedImage ); fixedImageStats->SetNumberOfThreads( this->m_NumberOfThreads ); fixedImageStats->Update(); m_FixedImageMin = fixedImageStats->GetMinimum(); m_FixedImageMax = fixedImageStats->GetMaximum(); } double fixedImageMin = m_FixedImageMin; double fixedImageMax = m_FixedImageMax; typedef StatisticsImageFilter MovingImageStatisticsFilterType; typename MovingImageStatisticsFilterType::Pointer movingImageStats = MovingImageStatisticsFilterType::New(); float diffMoving =m_MovingImageMax-m_MovingImageMin; if(diffMoving<=0) { movingImageStats->SetInput( this->m_MovingImage ); movingImageStats->SetNumberOfThreads( this->m_NumberOfThreads ); movingImageStats->Update(); m_MovingImageMin = movingImageStats->GetMinimum(); m_MovingImageMax = movingImageStats->GetMaximum(); } double movingImageMin = m_MovingImageMin; double movingImageMax = m_MovingImageMax; std::cout<<" FixedImageMin: " << fixedImageMin << " FixedImageMax: " << fixedImageMax << std::endl ; std::cout<< " MovingImageMin: " << movingImageMin << " MovingImageMax: " << movingImageMax << std::endl; /** * Compute binsize for the histograms. * * The binsize for the image intensities needs to be adjusted so that * we can avoid dealing with boundary conditions using the cubic * spline as the Parzen window. We do this by increasing the size * of the bins so that the joint histogram becomes "padded" at the * borders. Because we are changing the binsize, * we also need to shift the minimum by the padded amount in order to * avoid minimum values filling in our padded region. * * Note that there can still be non-zero bin values in the padded region, * it's just that these bins will never be a central bin for the Parzen * window. * */ const int padding = 2; // this will pad by 2 bins m_FixedImageBinSize = ( fixedImageMax - fixedImageMin ) / static_cast( m_NumberOfHistogramBins - 2 * padding ); m_FixedImageNormalizedMin = fixedImageMin / m_FixedImageBinSize - static_cast( padding ); m_MovingImageBinSize = ( movingImageMax - movingImageMin ) / static_cast( m_NumberOfHistogramBins - 2 * padding ); m_MovingImageNormalizedMin = movingImageMin / m_MovingImageBinSize - static_cast( padding ); std::cout<< "FixedImageNormalizedMin: " << m_FixedImageNormalizedMin <m_JointPDFDerivatives = NULL; // by destroying the dynamic array this->m_PRatioArray.SetSize( 1, 1 ); // and by allocating very small the static ones this->m_MetricDerivative = DerivativeType( 1 ); JointPDFDerivativesRegionType jointPDFDerivativesRegion; // // Now allocate memory according to the user-selected method. // if( this->m_UseExplicitPDFDerivatives ) { this->m_JointPDFDerivatives = JointPDFDerivativesType::New(); JointPDFDerivativesIndexType jointPDFDerivativesIndex; JointPDFDerivativesSizeType jointPDFDerivativesSize; // For the derivatives of the joint PDF define a region starting from {0,0,0} // with size {m_NumberOfParameters,m_NumberOfHistogramBins, // m_NumberOfHistogramBins}. The dimension represents transform parameters, // fixed image parzen window index and moving image parzen window index, // respectively. jointPDFDerivativesIndex.Fill( 0 ); jointPDFDerivativesSize[0] = this->m_NumberOfParameters; jointPDFDerivativesSize[1] = this->m_NumberOfHistogramBins; jointPDFDerivativesSize[2] = this->m_NumberOfHistogramBins; jointPDFDerivativesRegion.SetIndex( jointPDFDerivativesIndex ); jointPDFDerivativesRegion.SetSize( jointPDFDerivativesSize ); // Set the regions and allocate m_JointPDFDerivatives->SetRegions( jointPDFDerivativesRegion ); m_JointPDFDerivatives->Allocate(); m_JointPDFDerivativesBufferSize = jointPDFDerivativesSize[0] * jointPDFDerivativesSize[1] * jointPDFDerivativesSize[2] * sizeof(JointPDFDerivativesValueType); } else { /** Allocate memory for helper array that will contain the pRatios * for each bin of the joint histogram. This is part of the effort * for flattening the computation of the PDF Jacobians. */ this->m_PRatioArray.SetSize( this->m_NumberOfHistogramBins, this->m_NumberOfHistogramBins ); this->m_MetricDerivative = DerivativeType( this->GetNumberOfParameters() ); } // For the joint PDF define a region starting from {0,0} // with size {m_NumberOfHistogramBins, m_NumberOfHistogramBins}. // The dimension represents fixed image parzen window index // and moving image parzen window index, respectively. jointPDFIndex.Fill( 0 ); jointPDFSize.Fill( m_NumberOfHistogramBins ); jointPDFRegion.SetIndex( jointPDFIndex ); jointPDFRegion.SetSize( jointPDFSize ); // Set the regions and allocate m_JointPDF->SetRegions( jointPDFRegion ); m_JointPDF->Allocate(); m_JointPDFBufferSize = jointPDFSize[0] * jointPDFSize[1] * sizeof(PDFValueType); /** * Setup the kernels used for the Parzen windows. */ m_CubicBSplineKernel = CubicBSplineFunctionType::New(); m_CubicBSplineDerivativeKernel = CubicBSplineDerivativeFunctionType::New(); /** * Pre-compute the fixed image parzen window index for * each point of the fixed image sample points list. */ this->ComputeFixedImageParzenWindowIndices( this->m_FixedImageSamples ); if(m_ThreaderFixedImageMarginalPDF != NULL) { delete [] m_ThreaderFixedImageMarginalPDF; } // Assumes number of threads doesn't change between calls to Initialize m_ThreaderFixedImageMarginalPDF = new PDFValueType[(this->m_NumberOfThreads-1) * m_NumberOfHistogramBins]; if(m_ThreaderJointPDF != NULL) { delete [] m_ThreaderJointPDF; } m_ThreaderJointPDF = new typename JointPDFType::Pointer[this->m_NumberOfThreads-1]; if(m_ThreaderJointPDFStartBin != NULL) { delete [] m_ThreaderJointPDFStartBin; } m_ThreaderJointPDFStartBin = new int[this->m_NumberOfThreads]; if(m_ThreaderJointPDFEndBin != NULL) { delete [] m_ThreaderJointPDFEndBin; } m_ThreaderJointPDFEndBin = new int[this->m_NumberOfThreads]; if(m_ThreaderJointPDFSum != NULL) { delete [] m_ThreaderJointPDFSum; } m_ThreaderJointPDFSum = new double[this->m_NumberOfThreads]; unsigned int threadID; int binRange = m_NumberOfHistogramBins / this->m_NumberOfThreads; for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) { m_ThreaderJointPDF[threadID] = JointPDFType::New(); m_ThreaderJointPDF[threadID]->SetRegions( jointPDFRegion ); m_ThreaderJointPDF[threadID]->Allocate(); m_ThreaderJointPDFStartBin[threadID] = threadID * binRange; m_ThreaderJointPDFEndBin[threadID] = (threadID + 1) * binRange - 1; } m_ThreaderJointPDFStartBin[this->m_NumberOfThreads-1] = (this->m_NumberOfThreads - 1 ) * binRange; m_ThreaderJointPDFEndBin[this->m_NumberOfThreads-1] = m_NumberOfHistogramBins - 1; // Release memory of arrays that may have been used for // previous executions of this metric with different settings // of the memory caching flags. if(m_ThreaderJointPDFDerivatives != NULL) { delete [] m_ThreaderJointPDFDerivatives; } m_ThreaderJointPDFDerivatives = NULL; if(m_ThreaderMetricDerivative != NULL) { delete [] m_ThreaderMetricDerivative; } m_ThreaderMetricDerivative = NULL; if( this->m_UseExplicitPDFDerivatives ) { m_ThreaderJointPDFDerivatives = new typename JointPDFDerivativesType::Pointer[this->m_NumberOfThreads-1]; for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) { m_ThreaderJointPDFDerivatives[threadID] = JointPDFDerivativesType::New(); m_ThreaderJointPDFDerivatives[threadID]->SetRegions( jointPDFDerivativesRegion ); m_ThreaderJointPDFDerivatives[threadID]->Allocate(); } } else { m_ThreaderMetricDerivative = new DerivativeType[this->m_NumberOfThreads-1]; for(threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++) { this->m_ThreaderMetricDerivative[threadID] = DerivativeType( this->GetNumberOfParameters() ); } } } /** * Uniformly sample the fixed image domain using a random walk */ template < class TFixedImage, class TMovingImage > void plm_MattesMutualInformationImageToImageMetric ::ComputeFixedImageParzenWindowIndices( FixedImageSampleContainer& samples ) { typename FixedImageSampleContainer::iterator iter; typename FixedImageSampleContainer::const_iterator end=samples.end(); for( iter=samples.begin(); iter != end; ++iter ) { // Determine parzen window arguments (see eqn 6 of Mattes paper [2]). double windowTerm = static_cast( (*iter).value ) / m_FixedImageBinSize - m_FixedImageNormalizedMin; OffsetValueType pindex = static_cast( windowTerm ); // Make sure the extreme values are in valid bins if ( pindex < 2 ) { pindex = 2; } else { const OffsetValueType nindex = static_cast< OffsetValueType >( this->m_NumberOfHistogramBins ) - 3; if ( pindex > nindex ) { pindex = nindex; } } (*iter).valueIndex = pindex; } } template < class TFixedImage, class TMovingImage > inline void plm_MattesMutualInformationImageToImageMetric ::GetValueThreadPreProcess( unsigned int threadID, bool withinSampleThread ) const { this->Superclass::GetValueThreadPreProcess( threadID, withinSampleThread ); if(threadID > 0) { memset( m_ThreaderJointPDF[threadID-1]->GetBufferPointer(), 0, m_JointPDFBufferSize ); memset( &(m_ThreaderFixedImageMarginalPDF[(threadID-1) *m_NumberOfHistogramBins]), 0, m_NumberOfHistogramBins*sizeof(PDFValueType) ); } else { // zero-th thread uses the variables directly memset( m_JointPDF->GetBufferPointer(), 0, m_JointPDFBufferSize ); memset( m_FixedImageMarginalPDF, 0, m_NumberOfHistogramBins*sizeof(PDFValueType) ); } } template < class TFixedImage, class TMovingImage > inline bool plm_MattesMutualInformationImageToImageMetric ::GetValueThreadProcessSample( unsigned int threadID, unsigned long fixedImageSample, const MovingImagePointType & itkNotUsed(mappedPoint), double movingImageValue) const { /** * Compute this sample's contribution to the marginal and * joint distributions. * */ if(movingImageValue < m_MovingImageMin) { return false; } else if(movingImageValue > m_MovingImageMax) { return false; } // Determine parzen window arguments (see eqn 6 of Mattes paper [2]). double movingImageParzenWindowTerm = movingImageValue / m_MovingImageBinSize - m_MovingImageNormalizedMin; // Same as floor OffsetValueType movingImageParzenWindowIndex = static_cast( movingImageParzenWindowTerm ); if( movingImageParzenWindowIndex < 2 ) { movingImageParzenWindowIndex = 2; } else { const OffsetValueType nindex = static_cast< OffsetValueType >( this->m_NumberOfHistogramBins ) - 3; if( movingImageParzenWindowIndex > nindex ) { movingImageParzenWindowIndex = nindex; } } unsigned int fixedImageParzenWindowIndex = this->m_FixedImageSamples[fixedImageSample].valueIndex; if(threadID > 0) { m_ThreaderFixedImageMarginalPDF[(threadID-1)*m_NumberOfHistogramBins + fixedImageParzenWindowIndex] += 1; } else { m_FixedImageMarginalPDF[fixedImageParzenWindowIndex] += 1; } // Pointer to affected bin to be updated JointPDFValueType *pdfPtr; if(threadID > 0) { pdfPtr = m_ThreaderJointPDF[threadID-1]->GetBufferPointer() + ( fixedImageParzenWindowIndex * m_ThreaderJointPDF[threadID-1] ->GetOffsetTable()[1] ); } else { pdfPtr = m_JointPDF->GetBufferPointer() + ( fixedImageParzenWindowIndex * m_JointPDF->GetOffsetTable()[1] ); } // Move the pointer to the first affected bin int pdfMovingIndex = static_cast( movingImageParzenWindowIndex ) - 1; pdfPtr += pdfMovingIndex; int pdfMovingIndexMax = static_cast(movingImageParzenWindowIndex) + 2; double movingImageParzenWindowArg = static_cast( pdfMovingIndex ) - movingImageParzenWindowTerm; while( pdfMovingIndex <= pdfMovingIndexMax ) { *(pdfPtr++) += static_cast( m_CubicBSplineKernel ->Evaluate( movingImageParzenWindowArg ) ); movingImageParzenWindowArg += 1; ++pdfMovingIndex; } return true; } template < class TFixedImage, class TMovingImage > inline void plm_MattesMutualInformationImageToImageMetric ::GetValueThreadPostProcess( unsigned int threadID, bool itkNotUsed(withinSampleThread) ) const { unsigned int t; int i; int maxI; maxI = m_NumberOfHistogramBins * ( m_ThreaderJointPDFEndBin[threadID] - m_ThreaderJointPDFStartBin[threadID] + 1); JointPDFValueType *pdfPtr; JointPDFValueType *pdfPtrStart; pdfPtrStart = m_JointPDF->GetBufferPointer() + ( m_ThreaderJointPDFStartBin[threadID] * m_JointPDF->GetOffsetTable()[1] ); JointPDFValueType *tPdfPtr; JointPDFValueType *tPdfPtrEnd; unsigned int tPdfPtrOffset; tPdfPtrOffset = ( m_ThreaderJointPDFStartBin[threadID] * m_JointPDF->GetOffsetTable()[1] ); for(t=0; tm_NumberOfThreads-1; t++) { pdfPtr = pdfPtrStart; tPdfPtr = m_ThreaderJointPDF[t]->GetBufferPointer() + tPdfPtrOffset; tPdfPtrEnd = tPdfPtr + maxI; //for(i=0; i < maxI; i++) while(tPdfPtr < tPdfPtrEnd) { *(pdfPtr++) += *(tPdfPtr++); } for(i = m_ThreaderJointPDFStartBin[threadID]; i <= m_ThreaderJointPDFEndBin[threadID]; i++) { m_FixedImageMarginalPDF[i] += m_ThreaderFixedImageMarginalPDF[ (t*m_NumberOfHistogramBins) + i]; } } double jointPDFSum = 0.0; pdfPtr = pdfPtrStart; for(i = 0; i < maxI; i++) { jointPDFSum += *(pdfPtr++); } if(threadID > 0) { m_ThreaderJointPDFSum[threadID-1] = jointPDFSum; } else { m_JointPDFSum = jointPDFSum; } } template < class TFixedImage, class TMovingImage > typename plm_MattesMutualInformationImageToImageMetric ::MeasureType plm_MattesMutualInformationImageToImageMetric ::GetValue( const ParametersType & parameters ) const { // Set up the parameters in the transform this->m_Transform->SetParameters( parameters ); this->m_Parameters = parameters; // MUST BE CALLED TO INITIATE PROCESSING this->GetValueMultiThreadedInitiate(); // MUST BE CALLED TO INITIATE PROCESSING this->GetValueMultiThreadedPostProcessInitiate(); for(unsigned int threadID = 0; threadIDm_NumberOfThreads-1; threadID++) { m_JointPDFSum += m_ThreaderJointPDFSum[threadID]; } if ( m_JointPDFSum == 0.0 ) { itkExceptionMacro( "Joint PDF summed to zero" ); } memset( m_MovingImageMarginalPDF, 0, m_NumberOfHistogramBins*sizeof(PDFValueType) ); JointPDFValueType * pdfPtr; PDFValueType * movingMarginalPtr; unsigned int i, j; double fixedPDFSum = 0.0; double nFactor = 1.0 / m_JointPDFSum; pdfPtr = m_JointPDF->GetBufferPointer(); for(i=0; im_NumberOfPixelsCounted < this->m_NumberOfFixedImageSamples / 16 ) { itkExceptionMacro( "Too many samples map outside moving image buffer: " << this->m_NumberOfPixelsCounted << " / " << this->m_NumberOfFixedImageSamples << std::endl ); } // Normalize the fixed image marginal PDF if ( fixedPDFSum == 0.0 ) { itkExceptionMacro( "Fixed image marginal PDF summed to zero" ); } for( unsigned int bin=0; bin < m_NumberOfHistogramBins; bin++ ) { m_FixedImageMarginalPDF[bin] /= fixedPDFSum; } /** * Compute the metric by double summation over histogram. */ // Setup pointer to point to the first bin JointPDFValueType * jointPDFPtr = m_JointPDF->GetBufferPointer(); double sum = 0.0; for( unsigned int fixedIndex = 0; fixedIndex < m_NumberOfHistogramBins; ++fixedIndex ) { double fixedImagePDFValue = m_FixedImageMarginalPDF[fixedIndex]; for( unsigned int movingIndex = 0; movingIndex < m_NumberOfHistogramBins; ++movingIndex, jointPDFPtr++ ) { double movingImagePDFValue = m_MovingImageMarginalPDF[movingIndex]; double jointPDFValue = *(jointPDFPtr); // check for non-zero bin contribution if( jointPDFValue > 1e-16 && movingImagePDFValue > 1e-16 ) { double pRatio = vcl_log(jointPDFValue / movingImagePDFValue ); if( fixedImagePDFValue > 1e-16) { sum += jointPDFValue * ( pRatio - vcl_log(fixedImagePDFValue ) ); } } // end if-block to check non-zero bin contribution } // end for-loop over moving index } // end for-loop over fixed index return static_cast( -1.0 * sum ); } template < class TFixedImage, class TMovingImage > inline void plm_MattesMutualInformationImageToImageMetric ::GetValueAndDerivativeThreadPreProcess( unsigned int threadID, bool itkNotUsed(withinSampleThread) ) const { if(threadID > 0) { memset( m_ThreaderJointPDF[threadID-1]->GetBufferPointer(), 0, m_JointPDFBufferSize ); memset( &(m_ThreaderFixedImageMarginalPDF[(threadID-1) * m_NumberOfHistogramBins]), 0, m_NumberOfHistogramBins*sizeof(PDFValueType) ); if( this->m_UseExplicitPDFDerivatives ) { memset( m_ThreaderJointPDFDerivatives[threadID-1]->GetBufferPointer(), 0, m_JointPDFDerivativesBufferSize ); } } else { memset( m_JointPDF->GetBufferPointer(), 0, m_JointPDFBufferSize ); memset( m_FixedImageMarginalPDF, 0, m_NumberOfHistogramBins*sizeof(PDFValueType) ); if( this->m_UseExplicitPDFDerivatives ) { memset( m_JointPDFDerivatives->GetBufferPointer(), 0, m_JointPDFDerivativesBufferSize ); } } } template < class TFixedImage, class TMovingImage > inline bool plm_MattesMutualInformationImageToImageMetric ::GetValueAndDerivativeThreadProcessSample( unsigned int threadID, unsigned long fixedImageSample, const MovingImagePointType & itkNotUsed(mappedPoint), double movingImageValue, const ImageDerivativesType & movingImageGradientValue) const { /** * Compute this sample's contribution to the marginal * and joint distributions. * */ if(movingImageValue < m_MovingImageMin) { return false; } else if(movingImageValue > m_MovingImageMax) { return false; } unsigned int fixedImageParzenWindowIndex = this->m_FixedImageSamples[fixedImageSample].valueIndex; // Determine parzen window arguments (see eqn 6 of Mattes paper [2]). double movingImageParzenWindowTerm = movingImageValue / m_MovingImageBinSize - m_MovingImageNormalizedMin; OffsetValueType movingImageParzenWindowIndex = static_cast( movingImageParzenWindowTerm ); // Make sure the extreme values are in valid bins if ( movingImageParzenWindowIndex < 2 ) { movingImageParzenWindowIndex = 2; } else { const OffsetValueType nindex = static_cast< OffsetValueType >( this->m_NumberOfHistogramBins ) - 3; if ( movingImageParzenWindowIndex > nindex ) { movingImageParzenWindowIndex = nindex; } } // Since a zero-order BSpline (box car) kernel is used for // the fixed image marginal pdf, we need only increment the // fixedImageParzenWindowIndex by value of 1.0. if(threadID > 0) { ++m_ThreaderFixedImageMarginalPDF[(threadID-1)*m_NumberOfHistogramBins + fixedImageParzenWindowIndex]; } else { ++m_FixedImageMarginalPDF[fixedImageParzenWindowIndex]; } /** * The region of support of the parzen window determines which bins * of the joint PDF are effected by the pair of image values. * Since we are using a cubic spline for the moving image parzen * window, four bins are effected. The fixed image parzen window is * a zero-order spline (box car) and thus effects only one bin. * * The PDF is arranged so that moving image bins corresponds to the * zero-th (column) dimension and the fixed image bins corresponds * to the first (row) dimension. * */ // Pointer to affected bin to be updated JointPDFValueType *pdfPtr; if(threadID > 0) { pdfPtr = m_ThreaderJointPDF[threadID-1] ->GetBufferPointer() + ( fixedImageParzenWindowIndex * m_NumberOfHistogramBins ); } else { pdfPtr = m_JointPDF->GetBufferPointer() + ( fixedImageParzenWindowIndex * m_NumberOfHistogramBins ); } // Move the pointer to the fist affected bin int pdfMovingIndex = static_cast( movingImageParzenWindowIndex ) - 1; pdfPtr += pdfMovingIndex; int pdfMovingIndexMax = static_cast(movingImageParzenWindowIndex) + 2; double movingImageParzenWindowArg = static_cast( pdfMovingIndex ) - static_cast( movingImageParzenWindowTerm ); while( pdfMovingIndex <= pdfMovingIndexMax ) { *(pdfPtr++) += static_cast( m_CubicBSplineKernel ->Evaluate( movingImageParzenWindowArg ) ); if( this->m_UseExplicitPDFDerivatives || this->m_ImplicitDerivativesSecondPass ) { // Compute the cubicBSplineDerivative for later repeated use. double cubicBSplineDerivativeValue = m_CubicBSplineDerivativeKernel->Evaluate( movingImageParzenWindowArg ); // Compute PDF derivative contribution. this->ComputePDFDerivatives( threadID, fixedImageSample, pdfMovingIndex, movingImageGradientValue, cubicBSplineDerivativeValue ); } movingImageParzenWindowArg += 1; ++pdfMovingIndex; } return true; } template < class TFixedImage, class TMovingImage > inline void plm_MattesMutualInformationImageToImageMetric ::GetValueAndDerivativeThreadPostProcess( unsigned int threadID, bool withinSampleThread ) const { this->GetValueThreadPostProcess( threadID, withinSampleThread ); if( this->m_UseExplicitPDFDerivatives ) { const unsigned int rowSize = this->m_NumberOfParameters * m_NumberOfHistogramBins; const unsigned int maxI = rowSize * ( m_ThreaderJointPDFEndBin[threadID] - m_ThreaderJointPDFStartBin[threadID] + 1 ); JointPDFDerivativesValueType *pdfDPtr; JointPDFDerivativesValueType *pdfDPtrStart; pdfDPtrStart = m_JointPDFDerivatives->GetBufferPointer() + ( m_ThreaderJointPDFStartBin[threadID] * rowSize ); JointPDFDerivativesValueType *tPdfDPtr; JointPDFDerivativesValueType *tPdfDPtrEnd; unsigned int tPdfDPtrOffset; tPdfDPtrOffset = m_ThreaderJointPDFStartBin[threadID] * rowSize; for(unsigned int t=0; tm_NumberOfThreads-1; t++) { pdfDPtr = pdfDPtrStart; tPdfDPtr = m_ThreaderJointPDFDerivatives[t]->GetBufferPointer() + tPdfDPtrOffset; tPdfDPtrEnd = tPdfDPtr + maxI; // for(i = 0; i < maxI; i++) while(tPdfDPtr < tPdfDPtrEnd) { *(pdfDPtr++) += *(tPdfDPtr++); } } double nFactor = 1.0 / (m_MovingImageBinSize * this->m_NumberOfPixelsCounted); pdfDPtr = pdfDPtrStart; tPdfDPtrEnd = pdfDPtrStart + maxI; //for(int i = 0; i < maxI; i++) while(pdfDPtr < tPdfDPtrEnd) { *(pdfDPtr++) *= nFactor; } } } /** * Get the both Value and Derivative Measure */ template < class TFixedImage, class TMovingImage > void plm_MattesMutualInformationImageToImageMetric ::GetValueAndDerivative( const ParametersType & parameters, MeasureType & value, DerivativeType & derivative) const { // Set output values to zero value = NumericTraits< MeasureType >::Zero; if( this->m_UseExplicitPDFDerivatives ) { // Set output values to zero if(derivative.GetSize() != this->m_NumberOfParameters) { derivative = DerivativeType( this->m_NumberOfParameters ); } memset( derivative.data_block(), 0, this->m_NumberOfParameters * sizeof(double) ); } else { this->m_PRatioArray.Fill( 0.0 ); this->m_MetricDerivative.Fill( NumericTraits< MeasureType >::Zero ); for(unsigned int threadID = 0; threadID < this->m_NumberOfThreads-1; threadID++ ) { this->m_ThreaderMetricDerivative[threadID].Fill( NumericTraits< MeasureType >::Zero ); } this->m_ImplicitDerivativesSecondPass = false; } // Set up the parameters in the transform this->m_Transform->SetParameters( parameters ); this->m_Parameters = parameters; // MUST BE CALLED TO INITIATE PROCESSING ON SAMPLES this->GetValueAndDerivativeMultiThreadedInitiate(); // CALL IF DOING THREADED POST PROCESSING this->GetValueAndDerivativeMultiThreadedPostProcessInitiate(); for(unsigned int threadID = 0; threadIDm_NumberOfThreads-1; threadID++) { m_JointPDFSum += m_ThreaderJointPDFSum[threadID]; } if ( m_JointPDFSum == 0.0 ) { itkExceptionMacro( "Joint PDF summed to zero" ); } memset( m_MovingImageMarginalPDF, 0, m_NumberOfHistogramBins*sizeof(PDFValueType) ); JointPDFValueType * pdfPtr; PDFValueType * movingMarginalPtr; unsigned int i, j; double fixedPDFSum = 0.0; const double normalizationFactor = 1.0 / m_JointPDFSum; pdfPtr = m_JointPDF->GetBufferPointer(); for(i=0; im_NumberOfPixelsCounted < this->m_NumberOfFixedImageSamples / 16 ) { itkExceptionMacro( "Too many samples map outside moving image buffer: " << this->m_NumberOfPixelsCounted << " / " << this->m_NumberOfFixedImageSamples << std::endl ); } // Normalize the fixed image marginal PDF if ( fixedPDFSum == 0.0 ) { itkExceptionMacro( "Fixed image marginal PDF summed to zero" ); } for( unsigned int bin=0; bin < m_NumberOfHistogramBins; bin++ ) { m_FixedImageMarginalPDF[bin] /= fixedPDFSum; } /** * Compute the metric by double summation over histogram. */ // Setup pointer to point to the first bin JointPDFValueType * jointPDFPtr = m_JointPDF->GetBufferPointer(); // Initialize sum to zero double sum = 0.0; const double nFactor = 1.0 / (m_MovingImageBinSize * this->m_NumberOfPixelsCounted); for( unsigned int fixedIndex = 0; fixedIndex < m_NumberOfHistogramBins; ++fixedIndex ) { double fixedImagePDFValue = m_FixedImageMarginalPDF[fixedIndex]; for( unsigned int movingIndex = 0; movingIndex < m_NumberOfHistogramBins; ++movingIndex, jointPDFPtr++ ) { double movingImagePDFValue = m_MovingImageMarginalPDF[movingIndex]; double jointPDFValue = *(jointPDFPtr); // check for non-zero bin contribution if( jointPDFValue > 1e-16 && movingImagePDFValue > 1e-16 ) { double pRatio = vcl_log(jointPDFValue / movingImagePDFValue ); if( fixedImagePDFValue > 1e-16) { sum += jointPDFValue * ( pRatio - vcl_log(fixedImagePDFValue ) ); } if( this->m_UseExplicitPDFDerivatives ) { // move joint pdf derivative pointer to the right position JointPDFValueType * derivPtr = m_JointPDFDerivatives->GetBufferPointer() + ( fixedIndex * m_JointPDFDerivatives->GetOffsetTable()[2] ) + ( movingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] ); for( unsigned int parameter=0; parameter < this->m_NumberOfParameters; ++parameter, derivPtr++ ) { // Ref: eqn 23 of Thevenaz & Unser paper [3] derivative[parameter] -= (*derivPtr) * pRatio; } // end for-loop over parameters } else { this->m_PRatioArray[fixedIndex][movingIndex] = pRatio * nFactor; } } // end if-block to check non-zero bin contribution } // end for-loop over moving index } // end for-loop over fixed index if( !(this->m_UseExplicitPDFDerivatives ) ) { // Second pass: This one is done for accumulating the contributions // to the derivative array. // this->m_ImplicitDerivativesSecondPass = true; // // MUST BE CALLED TO INITIATE PROCESSING ON SAMPLES this->GetValueAndDerivativeMultiThreadedInitiate(); // CALL IF DOING THREADED POST PROCESSING this->GetValueAndDerivativeMultiThreadedPostProcessInitiate(); // Consolidate the contributions from each one of the threads to the total // derivative. for(unsigned int t = 0; t < this->m_NumberOfThreads-1; t++ ) { DerivativeType * source = &(this->m_ThreaderMetricDerivative[t]); for(unsigned int pp=0; pp < this->m_NumberOfParameters; pp++ ) { this->m_MetricDerivative[pp] += (*source)[pp]; } } derivative = this->m_MetricDerivative; } value = static_cast( -1.0 * sum ); } /** * Get the match measure derivative */ template < class TFixedImage, class TMovingImage > void plm_MattesMutualInformationImageToImageMetric ::GetDerivative( const ParametersType & parameters, DerivativeType & derivative ) const { MeasureType value; // call the combined version this->GetValueAndDerivative( parameters, value, derivative ); } /** * Compute PDF derivatives contribution for each parameter */ template < class TFixedImage, class TMovingImage > void plm_MattesMutualInformationImageToImageMetric ::ComputePDFDerivatives( unsigned int threadID, unsigned int sampleNumber, int pdfMovingIndex, const ImageDerivativesType & movingImageGradientValue, double cubicBSplineDerivativeValue ) const { // Update bins in the PDF derivatives for the current intensity pair // Could pre-compute JointPDFDerivativesValueType * derivPtr; double precomputedWeight = 0.0; const int pdfFixedIndex = this->m_FixedImageSamples[sampleNumber].valueIndex; DerivativeType * derivativeHelperArray = NULL; if( this->m_UseExplicitPDFDerivatives ) { if(threadID > 0) { derivPtr = m_ThreaderJointPDFDerivatives[threadID-1]->GetBufferPointer() + ( pdfFixedIndex * m_JointPDFDerivatives->GetOffsetTable()[2] ) + ( pdfMovingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] ); } else { derivPtr = m_JointPDFDerivatives->GetBufferPointer() + ( pdfFixedIndex * m_JointPDFDerivatives->GetOffsetTable()[2] ) + ( pdfMovingIndex * m_JointPDFDerivatives->GetOffsetTable()[1] ); } } else { derivPtr = 0; // Recover the precomputed weight for this specific PDF bin precomputedWeight = this->m_PRatioArray[pdfFixedIndex][pdfMovingIndex]; if(threadID > 0) { derivativeHelperArray = &(this->m_ThreaderMetricDerivative[threadID-1]); } else { derivativeHelperArray = &(this->m_MetricDerivative); } } if( !this->m_TransformIsBSpline ) { /** * Generic version which works for all transforms. */ // Compute the transform Jacobian. // Should pre-compute typedef typename TransformType::JacobianType JacobianType; // Need to use one of the threader transforms if we're // not in thread 0. // // Use a raw pointer here to avoid the overhead of smart pointers. // For instance, Register and UnRegister have mutex locks around // the reference counts. TransformType* transform; if (threadID > 0) { transform = this->m_ThreaderTransform[threadID - 1]; } else { transform = this->m_Transform; } const JacobianType& jacobian = transform->GetJacobian( this->m_FixedImageSamples[sampleNumber].point ); for ( unsigned int mu = 0; mu < this->m_NumberOfParameters; mu++ ) { double innerProduct = 0.0; for ( unsigned int dim = 0; dim < Superclass::FixedImageDimension; dim++ ) { innerProduct += jacobian[dim][mu] * movingImageGradientValue[dim]; } const double derivativeContribution = innerProduct * cubicBSplineDerivativeValue; if( this->m_UseExplicitPDFDerivatives ) { *(derivPtr) -= derivativeContribution; ++derivPtr; } else { (*derivativeHelperArray)[mu] += precomputedWeight * derivativeContribution; } } } else { const WeightsValueType * weights = NULL; const IndexValueType * indices = NULL; BSplineTransformWeightsType * weightsHelper = NULL; BSplineTransformIndexArrayType * indicesHelper = NULL; if( this->m_UseCachingOfBSplineWeights ) { // // If the transform is of type BSplineDeformableTransform, we can obtain // a speed up by only processing the affected parameters. Note that // these pointers are just pointing to pre-allocated rows of the caching // arrays. There is therefore, no need to free this memory. // weights = this->m_BSplineTransformWeightsArray[sampleNumber]; indices = this->m_BSplineTransformIndicesArray[sampleNumber]; } else { if( threadID > 0 ) { weightsHelper = &(this->m_ThreaderBSplineTransformWeights[threadID-1]); indicesHelper = &(this->m_ThreaderBSplineTransformIndices[threadID-1]); } else { weightsHelper = &(this->m_BSplineTransformWeights); indicesHelper = &(this->m_BSplineTransformIndices); } this->m_BSplineTransform->GetJacobian( this->m_FixedImageSamples[sampleNumber].point, *weightsHelper, *indicesHelper ); } for( unsigned int dim = 0; dim < Superclass::FixedImageDimension; dim++ ) { double innerProduct; int parameterIndex; for( unsigned int mu = 0; mu < this->m_NumBSplineWeights; mu++ ) { /* The array weights contains the Jacobian values in a 1-D array * (because for each parameter the Jacobian is non-zero in only 1 of the * possible dimensions) which is multiplied by the moving image * gradient. */ if( this->m_UseCachingOfBSplineWeights ) { innerProduct = movingImageGradientValue[dim] * weights[mu]; parameterIndex = indices[mu] + this->m_BSplineParametersOffset[dim]; } else { innerProduct = movingImageGradientValue[dim] * (*weightsHelper)[mu]; parameterIndex = (*indicesHelper)[mu] + this->m_BSplineParametersOffset[dim]; } const double derivativeContribution = innerProduct * cubicBSplineDerivativeValue; if( this->m_UseExplicitPDFDerivatives ) { JointPDFValueType * ptr = derivPtr + parameterIndex; *(ptr) -= derivativeContribution; } else { (*derivativeHelperArray)[parameterIndex] += precomputedWeight * derivativeContribution; } } //end mu for loop } //end dim for loop } // end if-block transform is BSpline } } // end namespace itk #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/000077500000000000000000000000001321604176500245415ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/AUTHORS000066400000000000000000000000501321604176500256040ustar00rootroot00000000000000Naoaki Okazaki plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/CMakeLists.txt000066400000000000000000000004271321604176500273040ustar00rootroot00000000000000project (liblbfgs) set (LIBLBFGS_LIBRARY_SRC lib/lbfgs.c lib/arithmetic_ansi.h lib/arithmetic_sse_float.h lib/arithmetic_sse_double.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include) plm_add_static_library (lbfgs "${LIBLBFGS_LIBRARY_SRC}" "" "" "") plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/COPYING000066400000000000000000000021311321604176500255710ustar00rootroot00000000000000The MIT License Copyright (c) 1990 Jorge Nocedal Copyright (c) 2007-2010 Naoaki Okazaki Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/ChangeLog000066400000000000000000000105571321604176500263230ustar00rootroot000000000000002010-01-29 Naoaki Okazaki * libLBFGS 1.9: - Fixed a mistake in checking the validity of the parameters "ftol" and "wolfe"; this mistake was discovered by Kevin S. Van Horn. 2009-07-13 Naoaki Okazaki * libLBFGS 1.8: - Accepted the patch submitted by Takashi Imamichi; the backtracking method now has three criteria for choosing the step length. - Updated the documentation to explain the above three criteria. 2009-02-28 Naoaki Okazaki * libLBFGS 1.7: - Improved OWL-QN routines for stability. - Removed the support of OWL-QN method in MoreThuente algorithm because it accidentally fails in early stages of iterations for some objectives. Because of this change, the OW-LQN method must be used with the backtracking algorithm (LBFGS_LINESEARCH_BACKTRACKING), or the library returns LBFGSERR_INVALID_LINESEARCH. - Renamed line search algorithms as follows: - LBFGS_LINESEARCH_BACKTRACKING: regular Wolfe condition. - LBFGS_LINESEARCH_BACKTRACKING_LOOSE: regular Wolfe condition. - LBFGS_LINESEARCH_BACKTRACKING_STRONG: strong Wolfe condition. - Source code clean-up. 2008-11-02 Naoaki Okazaki * libLBFGS 1.6: - Improved line-search algorithm with strong Wolfe condition, which was contributed by Takashi Imamichi. This routine is now default for LBFGS_LINESEARCH_BACKTRACKING. The previous line search algorithm with regular Wolfe condition is still available as LBFGS_LINESEARCH_BACKTRACKING_LOOSE. - Configurable stop index for L1-norm computation. A member variable lbfgs_parameter_t::orthantwise_end was added to specify the index number at which the library stops computing the L1 norm of the variables. This is useful to prevent some variables from being regularized by the OW-LQN method. - A sample program written in C++ (sample/sample.cpp). 2008-07-10 Naoaki Okazaki * libLBFGS 1.5: - Configurable starting index for L1-norm computation. A member variable lbfgs_parameter_t::orthantwise_start was added to specify the index number from which the library computes the L1 norm of the variables. - Fixed a zero-division error when the initial variables have already been a minimizer (reported by Takashi Imamichi). In this case, the library returns LBFGS_ALREADY_MINIMIZED status code. - Defined LBFGS_SUCCESS status code as zero; removed unused constants, LBFGSFALSE and LBFGSTRUE. - Fixed a compile error in an implicit down-cast. 2008-04-25 Naoaki Okazaki * libLBFGS 1.4: - Configurable line search algorithms. A member variable lbfgs_parameter_t::linesearch was added to choose either MoreThuente method (LBFGS_LINESEARCH_MORETHUENTE) or backtracking algorithm (LBFGS_LINESEARCH_BACKTRACKING). - Fixed a bug: the previous version did not compute psuedo-gradients properly in the line search routines for OW-LQN. This bug might quit an iteration process too early when the OW-LQN routine was activated (0 < lbfgs_parameter_t::orthantwise_c). - Configure script for POSIX environments. - SSE/SSE2 optimizations with GCC. - New functions lbfgs_malloc and lbfgs_free to use SSE/SSE2 routines transparently. It is uncessary to use these functions for libLBFGS built without SSE/SSE2 routines; you can still use any memory allocators if SSE/SSE2 routines are disabled in libLBFGS. 2007-12-16 Naoaki Okazaki * libLBFGS 1.3: - An API change. An argument was added to lbfgs() function to receive the final value of the objective function. This argument can be set to NULL if the final value is unnecessary. - Fixed a null-pointer bug in the sample code (reported by Takashi Imamichi). - Added build scripts for Microsoft Visual Studio 2005 and GCC. - Added README file. 2007-12-13 Naoaki Okazaki * libLBFGS 1.2: - Fixed a serious bug in orthant-wise L-BFGS. An important variable was used without initialization. - Configurable L-BFGS parameters (number of limited memories, epsilon). 2007-12-01 Naoaki Okazaki * libLBFGS 1.1: - Implemented orthant-wise L-BFGS. - Implemented lbfgs_parameter_init() function. - Fixed several bugs. - API documentation. 2007-09-20 Naoaki Okazaki * libLBFGS 1.0 - Initial release. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/INSTALL000066400000000000000000000220711321604176500255740ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PREFIX', the package will use PREFIX as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/Makefile.am000066400000000000000000000003231321604176500265730ustar00rootroot00000000000000# $Id: Makefile.am 6 2008-04-25 09:07:12Z naoaki $ SUBDIRS = lib sample docdir = $(prefix)/share/doc/@PACKAGE@ doc_DATA = README INSTALL COPYING AUTHORS ChangeLog NEWS EXTRA_DIST = \ autogen.sh \ lbfgs.sln plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/Makefile.in000066400000000000000000000473511321604176500266200ustar00rootroot00000000000000# Makefile.in generated by automake 1.9.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # $Id: Makefile.am 6 2008-04-25 09:07:12Z naoaki $ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = . am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/config.h.in \ $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ config.guess config.sub depcomp install-sh ltmain.sh missing subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno configure.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-exec-recursive install-info-recursive \ install-recursive installcheck-recursive installdirs-recursive \ pdf-recursive ps-recursive uninstall-info-recursive \ uninstall-recursive am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(docdir)" docDATA_INSTALL = $(INSTALL_DATA) DATA = $(doc_DATA) ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ { test ! -d $(distdir) \ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr $(distdir); }; } DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ INCLUDES = @INCLUDES@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ prefix = @prefix@ program_transform_name = @program_transform_name@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ SUBDIRS = lib sample docdir = $(prefix)/share/doc/@PACKAGE@ doc_DATA = README INSTALL COPYING AUTHORS ChangeLog NEWS EXTRA_DIST = \ autogen.sh \ lbfgs.sln all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ cd $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) config.h: stamp-h1 @if test ! -f $@; then \ rm -f stamp-h1; \ $(MAKE) stamp-h1; \ else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_srcdir) && $(AUTOHEADER) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-docDATA: $(doc_DATA) @$(NORMAL_INSTALL) test -z "$(docdir)" || $(mkdir_p) "$(DESTDIR)$(docdir)" @list='$(doc_DATA)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \ $(docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \ done uninstall-docDATA: @$(NORMAL_UNINSTALL) @list='$(doc_DATA)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \ rm -f "$(DESTDIR)$(docdir)/$$f"; \ done # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @set fnord $$MAKEFLAGS; amf=$$2; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" mostlyclean-recursive clean-recursive distclean-recursive \ maintainer-clean-recursive: @set fnord $$MAKEFLAGS; amf=$$2; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(am__remove_distdir) mkdir $(distdir) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(mkdir_p) "$(distdir)/$$subdir" \ || exit 1; \ distdir=`$(am__cd) $(distdir) && pwd`; \ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ (cd $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$top_distdir" \ distdir="$$distdir/$$subdir" \ distdir) \ || exit 1; \ fi; \ done -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r $(distdir) dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && cd $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' distuninstallcheck: @cd $(distuninstallcheck_dir) \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(DATA) config.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(docdir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive info: info-recursive info-am: install-data-am: install-docDATA install-exec-am: install-info: install-info-recursive install-man: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-docDATA uninstall-info-am uninstall-info: uninstall-info-recursive .PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \ check-am clean clean-generic clean-libtool clean-recursive \ ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \ dist-shar dist-tarZ dist-zip distcheck distclean \ distclean-generic distclean-hdr distclean-libtool \ distclean-recursive distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-docDATA install-exec install-exec-am install-info \ install-info-am install-man install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic maintainer-clean-recursive \ mostlyclean mostlyclean-generic mostlyclean-libtool \ mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am uninstall-docDATA uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/NEWS000066400000000000000000000000001321604176500252260ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/README000066400000000000000000000051751321604176500254310ustar00rootroot00000000000000 libLBFGS: C library of limited-memory BFGS (L-BFGS) Copyright (c) 1990, Jorge Nocedal Copyright (c) 2007-2010, Naoaki Okazaki ========================================================================= 1. Introduction ========================================================================= libLBFGS is a C port of the implementation of Limited-memory Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) method written by Jorge Nocedal. The original FORTRAN source code is available at: http://www.ece.northwestern.edu/~nocedal/lbfgs.html The L-BFGS method solves the unconstrainted minimization problem: minimize F(x), x = (x1, x2, ..., xN), only if the objective function F(x) and its gradient G(x) are computable. Refer to the libLBFGS web site for more information. http://www.chokkan.org/software/liblbfgs/ ========================================================================= 2. How to build ========================================================================= [Microsoft Visual Studio 2008] Open the solution file "lbfgs.sln" and build it. [GCC] $ ./configure $ make $ make install # To install libLBFGS library and header. ========================================================================= 3. Note on SSE/SSE2 optimization ========================================================================= This library has SSE/SSE2 optimization routines for vector arithmetic operations on Intel/AMD processors. The SSE2 routine is for 64 bit double values, and the SSE routine is for 32 bit float values. Since the default parameters in libLBFGS are tuned for double precision values, it may need to modify these parameters to use the SSE optimization routines. To use the SSE2 optimization routine, specify --enable-sse2 option to the configure script. $ ./configure --enable-sse2 To build libLBFGS with SSE2 optimization enabled on Microsoft Visual Studio 2005, define USE_SSE and __SSE2__ symbols. Make sure to run libLBFGS on processors where SSE2 instrunctions are available. The library does not check the existence of SSE2 instructions. To package maintainers, Please do not enable SSE/SSE2 optimization routine. The library built with SSE/SSE2 optimization will crash without any notice when necessary SSE/SSE2 instructions are unavailable on CPUs. ========================================================================= 4. License ========================================================================= libLBFGS is distributed under the term of the MIT license. Please refer to COPYING file in the distribution. $Id: README 62 2010-01-13 07:28:37Z naoaki $ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/aclocal.m4000066400000000000000000007451701321604176500264170ustar00rootroot00000000000000# generated automatically by aclocal 1.9.2 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 # Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # serial 47 AC_PROG_LIBTOOL # AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) # ----------------------------------------------------------- # If this macro is not defined by Autoconf, define it here. m4_ifdef([AC_PROVIDE_IFELSE], [], [m4_define([AC_PROVIDE_IFELSE], [m4_ifdef([AC_PROVIDE_$1], [$2], [$3])])]) # AC_PROG_LIBTOOL # --------------- AC_DEFUN([AC_PROG_LIBTOOL], [AC_REQUIRE([_AC_PROG_LIBTOOL])dnl dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. AC_PROVIDE_IFELSE([AC_PROG_CXX], [AC_LIBTOOL_CXX], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX ])]) dnl And a similar setup for Fortran 77 support AC_PROVIDE_IFELSE([AC_PROG_F77], [AC_LIBTOOL_F77], [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 ])]) dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [AC_LIBTOOL_GCJ], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [AC_LIBTOOL_GCJ], [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], [AC_LIBTOOL_GCJ], [ifdef([AC_PROG_GCJ], [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) ifdef([A][M_PROG_GCJ], [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) ifdef([LT_AC_PROG_GCJ], [define([LT_AC_PROG_GCJ], defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) ])])# AC_PROG_LIBTOOL # _AC_PROG_LIBTOOL # ---------------- AC_DEFUN([_AC_PROG_LIBTOOL], [AC_REQUIRE([AC_LIBTOOL_SETUP])dnl AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl # Prevent multiple expansion define([AC_PROG_LIBTOOL], []) ])# _AC_PROG_LIBTOOL # AC_LIBTOOL_SETUP # ---------------- AC_DEFUN([AC_LIBTOOL_SETUP], [AC_PREREQ(2.50)dnl AC_REQUIRE([AC_ENABLE_SHARED])dnl AC_REQUIRE([AC_ENABLE_STATIC])dnl AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_LD])dnl AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl AC_REQUIRE([AC_PROG_NM])dnl AC_REQUIRE([AC_PROG_LN_S])dnl AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl # Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! AC_REQUIRE([AC_OBJEXT])dnl AC_REQUIRE([AC_EXEEXT])dnl dnl AC_LIBTOOL_SYS_MAX_CMD_LEN AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE AC_LIBTOOL_OBJDIR AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl _LT_AC_PROG_ECHO_BACKSLASH case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e s/^X//' [sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] # Same as above, but do not quote variable references. [double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Constants: rm="rm -f" # Global variables: default_ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except M$VC, # which needs '.lib'). libext=a ltmain="$ac_aux_dir/ltmain.sh" ofile="$default_ofile" with_gnu_ld="$lt_cv_prog_gnu_ld" AC_CHECK_TOOL(AR, ar, false) AC_CHECK_TOOL(RANLIB, ranlib, :) AC_CHECK_TOOL(STRIP, strip, :) old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru test -z "$AS" && AS=as test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$DLLTOOL" && DLLTOOL=dlltool test -z "$LD" && LD=ld test -z "$LN_S" && LN_S="ln -s" test -z "$MAGIC_CMD" && MAGIC_CMD=file test -z "$NM" && NM=nm test -z "$SED" && SED=sed test -z "$OBJDUMP" && OBJDUMP=objdump test -z "$RANLIB" && RANLIB=: test -z "$STRIP" && STRIP=: test -z "$ac_objext" && ac_objext=o # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" ;; *) old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi # Only perform the check for file, if the check method requires it case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then AC_PATH_MAGIC fi ;; esac AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], enable_win32_dll=yes, enable_win32_dll=no) AC_ARG_ENABLE([libtool-lock], [AC_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes AC_ARG_WITH([pic], [AC_HELP_STRING([--with-pic], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [pic_mode="$withval"], [pic_mode=default]) test -z "$pic_mode" && pic_mode=default # Use C for the default configuration in the libtool script tagname= AC_LIBTOOL_LANG_C_CONFIG _LT_AC_TAGCONFIG ])# AC_LIBTOOL_SETUP # _LT_AC_SYS_COMPILER # ------------------- AC_DEFUN([_LT_AC_SYS_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_AC_SYS_COMPILER # _LT_AC_SYS_LIBPATH_AIX # ---------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], [AC_LINK_IFELSE(AC_LANG_PROGRAM,[ aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi],[]) if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ])# _LT_AC_SYS_LIBPATH_AIX # _LT_AC_SHELL_INIT(ARG) # ---------------------- AC_DEFUN([_LT_AC_SHELL_INIT], [ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], [AC_DIVERT_PUSH(NOTICE)]) $1 AC_DIVERT_POP ])# _LT_AC_SHELL_INIT # _LT_AC_PROG_ECHO_BACKSLASH # -------------------------- # Add some code to the start of the generated configure script which # will find an echo command which doesn't interpret backslashes. AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], [_LT_AC_SHELL_INIT([ # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` ;; esac echo=${ECHO-echo} if test "X[$]1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X[$]1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then # Yippee, $echo works! : else # Restart under the correct shell. exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} fi if test "X[$]1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null && echo_test_string="`eval $cmd`" && (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null then break fi done fi if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$echo" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. echo='print -r' elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} else # Try using printf. echo='printf %s\n' if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL echo="$CONFIG_SHELL [$]0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$CONFIG_SHELL [$]0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "[$]0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} else # Oops. We lost completely, so just stick with echo. echo=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. ECHO=$echo if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" fi AC_SUBST(ECHO) ])])# _LT_AC_PROG_ECHO_BACKSLASH # _LT_AC_LOCK # ----------- AC_DEFUN([_LT_AC_LOCK], [AC_ARG_ENABLE([libtool-lock], [AC_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case "`/usr/bin/file conftest.o`" in *32-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], [*-*-cygwin* | *-*-mingw* | *-*-pw32*) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; ]) esac need_locks="$enable_libtool_lock" ])# _LT_AC_LOCK # AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [AC_REQUIRE([LT_AC_PROG_SED]) AC_CACHE_CHECK([$1], [$2], [$2=no ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then $2=yes fi fi $rm conftest* ]) if test x"[$]$2" = xyes; then ifelse([$5], , :, [$5]) else ifelse([$6], , :, [$6]) fi ])# AC_LIBTOOL_COMPILER_OPTION # AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ------------------------------------------------------------ # Check whether the given compiler option works AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" printf "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD else $2=yes fi fi $rm conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then ifelse([$4], , :, [$4]) else ifelse([$5], , :, [$5]) fi ])# AC_LIBTOOL_LINKER_OPTION # AC_LIBTOOL_SYS_MAX_CMD_LEN # -------------------------- AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [# find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; *) # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ = "XX$teststring") >/dev/null 2>&1 && new_result=`expr "X$teststring" : ".*" 2>&1` && lt_cv_sys_max_cmd_len=$new_result && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done teststring= # Add a significant safety factor because C++ compilers can tack on massive # amounts of additional arguments before passing them to the linker. # It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi ])# AC_LIBTOOL_SYS_MAX_CMD_LEN # _LT_AC_CHECK_DLFCN # -------------------- AC_DEFUN([_LT_AC_CHECK_DLFCN], [AC_CHECK_HEADERS(dlfcn.h)dnl ])# _LT_AC_CHECK_DLFCN # _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ------------------------------------------------------------------ AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], [AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); }] EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_unknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_AC_TRY_DLOPEN_SELF # AC_LIBTOOL_DLOPEN_SELF # ------------------- AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_AC_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then LDFLAGS="$LDFLAGS $link_static_flag" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_AC_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi ])# AC_LIBTOOL_DLOPEN_SELF # AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) # --------------------------------- # Check to see if options -c and -o are simultaneously supported by compiler AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], [AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s out/conftest.err; then _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* ]) ])# AC_LIBTOOL_PROG_CC_C_O # AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) # ----------------------------------------- # Check to see if we can do hard links to lock some files if needed AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_REQUIRE([_LT_AC_LOCK])dnl hard_links="nottested" if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi ])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS # AC_LIBTOOL_OBJDIR # ----------------- AC_DEFUN([AC_LIBTOOL_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir ])# AC_LIBTOOL_OBJDIR # AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) # ---------------------------------------------- # Check hardcoding attributes. AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_AC_TAGVAR(hardcode_action, $1)= if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \ test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then # We can hardcode non-existant directories. if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_AC_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_AC_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_AC_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi ])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH # AC_LIBTOOL_SYS_LIB_STRIP # ------------------------ AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], [striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi ])# AC_LIBTOOL_SYS_LIB_STRIP # AC_LIBTOOL_SYS_DYNAMIC_LINKER # ----------------------------- # PORTME Fill in your ld.so characteristics AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_MSG_CHECKING([dynamic linker characteristics]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case "$host_cpu" in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # find out which ABI we are using libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *64-bit*) libsuff=64 sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; esac fi rm -rf conftest* ;; esac # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`$SED -e 's/[:,\t]/ /g;s/=[^=]*$//;s/=[^= ]* / /g' /etc/ld.so.conf | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; knetbsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos need_lib_prefix=no need_version=yes library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no ])# AC_LIBTOOL_SYS_DYNAMIC_LINKER # _LT_AC_TAGCONFIG # ---------------- AC_DEFUN([_LT_AC_TAGCONFIG], [AC_ARG_WITH([tags], [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], [include additional configurations @<:@automatic@:>@])], [tagnames="$withval"]) if test -f "$ltmain" && test -n "$tagnames"; then if test ! -f "${ofile}"; then AC_MSG_WARN([output file `$ofile' does not exist]) fi if test -z "$LTCC"; then eval "`$SHELL ${ofile} --config | grep '^LTCC='`" if test -z "$LTCC"; then AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) else AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) fi fi # Extract list of available tagged configurations in $ofile. # Note that this assumes the entire list is on one line. available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for tagname in $tagnames; do IFS="$lt_save_ifs" # Check whether tagname contains only valid characters case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in "") ;; *) AC_MSG_ERROR([invalid tag name: $tagname]) ;; esac if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null then AC_MSG_ERROR([tag name \"$tagname\" already exists]) fi # Update the list of available tags. if test -n "$tagname"; then echo appending configuration tag \"$tagname\" to $ofile case $tagname in CXX) if test -n "$CXX" && test "X$CXX" != "Xno"; then AC_LIBTOOL_LANG_CXX_CONFIG else tagname="" fi ;; F77) if test -n "$F77" && test "X$F77" != "Xno"; then AC_LIBTOOL_LANG_F77_CONFIG else tagname="" fi ;; GCJ) if test -n "$GCJ" && test "X$GCJ" != "Xno"; then AC_LIBTOOL_LANG_GCJ_CONFIG else tagname="" fi ;; RC) AC_LIBTOOL_LANG_RC_CONFIG ;; *) AC_MSG_ERROR([Unsupported tag name: $tagname]) ;; esac # Append the new tag name to the list of available tags. if test -n "$tagname" ; then available_tags="$available_tags $tagname" fi fi done IFS="$lt_save_ifs" # Now substitute the updated list of available tags. if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then mv "${ofile}T" "$ofile" chmod +x "$ofile" else rm -f "${ofile}T" AC_MSG_ERROR([unable to update list of available tagged configurations.]) fi fi ])# _LT_AC_TAGCONFIG # AC_LIBTOOL_DLOPEN # ----------------- # enable checks for dlopen support AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) ])# AC_LIBTOOL_DLOPEN # AC_LIBTOOL_WIN32_DLL # -------------------- # declare package support for building win32 dll's AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) ])# AC_LIBTOOL_WIN32_DLL # AC_ENABLE_SHARED([DEFAULT]) # --------------------------- # implement the --enable-shared flag # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. AC_DEFUN([AC_ENABLE_SHARED], [define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE([shared], [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]AC_ENABLE_SHARED_DEFAULT) ])# AC_ENABLE_SHARED # AC_DISABLE_SHARED # ----------------- #- set the default shared flag to --disable-shared AC_DEFUN([AC_DISABLE_SHARED], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_SHARED(no) ])# AC_DISABLE_SHARED # AC_ENABLE_STATIC([DEFAULT]) # --------------------------- # implement the --enable-static flag # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. AC_DEFUN([AC_ENABLE_STATIC], [define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE([static], [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]AC_ENABLE_STATIC_DEFAULT) ])# AC_ENABLE_STATIC # AC_DISABLE_STATIC # ----------------- # set the default static flag to --disable-static AC_DEFUN([AC_DISABLE_STATIC], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_STATIC(no) ])# AC_DISABLE_STATIC # AC_ENABLE_FAST_INSTALL([DEFAULT]) # --------------------------------- # implement the --enable-fast-install flag # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. AC_DEFUN([AC_ENABLE_FAST_INSTALL], [define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE([fast-install], [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) ])# AC_ENABLE_FAST_INSTALL # AC_DISABLE_FAST_INSTALL # ----------------------- # set the default to --disable-fast-install AC_DEFUN([AC_DISABLE_FAST_INSTALL], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_FAST_INSTALL(no) ])# AC_DISABLE_FAST_INSTALL # AC_LIBTOOL_PICMODE([MODE]) # -------------------------- # implement the --with-pic flag # MODE is either `yes' or `no'. If omitted, it defaults to `both'. AC_DEFUN([AC_LIBTOOL_PICMODE], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl pic_mode=ifelse($#,1,$1,default) ])# AC_LIBTOOL_PICMODE # AC_PROG_EGREP # ------------- # This is predefined starting with Autoconf 2.54, so this conditional # definition can be removed once we require Autoconf 2.54 or later. m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], [AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi]) EGREP=$ac_cv_prog_egrep AC_SUBST([EGREP]) ])]) # AC_PATH_TOOL_PREFIX # ------------------- # find a file program which can recognise shared library AC_DEFUN([AC_PATH_TOOL_PREFIX], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="ifelse([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi ])# AC_PATH_TOOL_PREFIX # AC_PATH_MAGIC # ------------- # find a file program which can recognise a shared library AC_DEFUN([AC_PATH_MAGIC], [AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# AC_PATH_MAGIC # AC_PROG_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([AC_PROG_LD], [AC_ARG_WITH([gnu-ld], [AC_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no]) AC_REQUIRE([LT_AC_PROG_SED])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case "$host_cpu" in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux*) case $host_cpu in alpha*|hppa*|i*86|ia64*|m68*|mips*|powerpc*|sparc*|s390*|sh*|x86_64*) lt_cv_deplibs_check_method=pass_all ;; *) # glibc up to 2.1.1 does not perform some relocations on ARM # this will be overridden with pass_all, but let us keep it just in case lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; esac lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; nto-qnx*) lt_cv_deplibs_check_method=unknown ;; openbsd*) lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' else lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; sco3.2v5*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; esac ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown ])# AC_DEPLIBS_CHECK_METHOD # AC_PROG_NM # ---------- # find the pathname to a BSD-compatible name lister AC_DEFUN([AC_PROG_NM], [AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/${ac_tool_prefix}nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac esac fi done IFS="$lt_save_ifs" test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm fi]) NM="$lt_cv_path_NM" ])# AC_PROG_NM # AC_CHECK_LIBM # ------------- # check for math library AC_DEFUN([AC_CHECK_LIBM], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac ])# AC_CHECK_LIBM # AC_LIBLTDL_CONVENIENCE([DIRECTORY]) # ----------------------------------- # sets LIBLTDL to the link flags for the libltdl convenience library and # LTDLINCL to the include flags for the libltdl header and adds # --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL # and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If # DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will # be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with # '${top_srcdir}/' (note the single quotes!). If your package is not # flat and you're not using automake, define top_builddir and # top_srcdir appropriately in the Makefiles. AC_DEFUN([AC_LIBLTDL_CONVENIENCE], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl case $enable_ltdl_convenience in no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; "") enable_ltdl_convenience=yes ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; esac LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) # For backwards non-gettext consistent compatibility... INCLTDL="$LTDLINCL" ])# AC_LIBLTDL_CONVENIENCE # AC_LIBLTDL_INSTALLABLE([DIRECTORY]) # ----------------------------------- # sets LIBLTDL to the link flags for the libltdl installable library and # LTDLINCL to the include flags for the libltdl header and adds # --enable-ltdl-install to the configure arguments. Note that LIBLTDL # and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If # DIRECTORY is not provided and an installed libltdl is not found, it is # assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/' # and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single # quotes!). If your package is not flat and you're not using automake, # define top_builddir and top_srcdir appropriately in the Makefiles. # In the future, this macro may have to be called after AC_PROG_LIBTOOL. AC_DEFUN([AC_LIBLTDL_INSTALLABLE], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_CHECK_LIB(ltdl, lt_dlinit, [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], [if test x"$enable_ltdl_install" = xno; then AC_MSG_WARN([libltdl not installed, but installation disabled]) else enable_ltdl_install=yes fi ]) if test x"$enable_ltdl_install" = x"yes"; then ac_configure_args="$ac_configure_args --enable-ltdl-install" LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) else ac_configure_args="$ac_configure_args --enable-ltdl-install=no" LIBLTDL="-lltdl" LTDLINCL= fi # For backwards non-gettext consistent compatibility... INCLTDL="$LTDLINCL" ])# AC_LIBLTDL_INSTALLABLE # AC_LIBTOOL_CXX # -------------- # enable support for C++ libraries AC_DEFUN([AC_LIBTOOL_CXX], [AC_REQUIRE([_LT_AC_LANG_CXX]) ])# AC_LIBTOOL_CXX # _LT_AC_LANG_CXX # --------------- AC_DEFUN([_LT_AC_LANG_CXX], [AC_REQUIRE([AC_PROG_CXX]) AC_REQUIRE([AC_PROG_CXXCPP]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) ])# _LT_AC_LANG_CXX # AC_LIBTOOL_F77 # -------------- # enable support for Fortran 77 libraries AC_DEFUN([AC_LIBTOOL_F77], [AC_REQUIRE([_LT_AC_LANG_F77]) ])# AC_LIBTOOL_F77 # _LT_AC_LANG_F77 # --------------- AC_DEFUN([_LT_AC_LANG_F77], [AC_REQUIRE([AC_PROG_F77]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) ])# _LT_AC_LANG_F77 # AC_LIBTOOL_GCJ # -------------- # enable support for GCJ libraries AC_DEFUN([AC_LIBTOOL_GCJ], [AC_REQUIRE([_LT_AC_LANG_GCJ]) ])# AC_LIBTOOL_GCJ # _LT_AC_LANG_GCJ # --------------- AC_DEFUN([_LT_AC_LANG_GCJ], [AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) ])# _LT_AC_LANG_GCJ # AC_LIBTOOL_RC # -------------- # enable support for Windows resource files AC_DEFUN([AC_LIBTOOL_RC], [AC_REQUIRE([LT_AC_PROG_RC]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) ])# AC_LIBTOOL_RC # AC_LIBTOOL_LANG_C_CONFIG # ------------------------ # Ensure that the configuration vars for the C compiler are # suitably defined. Those variables are subsequently used by # AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) AC_DEFUN([_LT_AC_LANG_C_CONFIG], [lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_AC_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}\n' _LT_AC_SYS_COMPILER # # Check for any special shared library compilation flags. # _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)= if test "$GCC" = no; then case $host_os in sco3.2v5*) _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf' ;; esac fi if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries]) if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[ ]]" >/dev/null; then : else AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure]) _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no fi fi # # Check to make sure the static flag actually works. # AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works], _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), $_LT_AC_TAGVAR(lt_prog_compiler_static, $1), [], [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) AC_LIBTOOL_PROG_COMPILER_PIC($1) AC_LIBTOOL_PROG_CC_C_O($1) AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) AC_LIBTOOL_PROG_LD_SHLIBS($1) AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) AC_LIBTOOL_SYS_LIB_STRIP AC_LIBTOOL_DLOPEN_SELF($1) # Report which librarie types wil actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case "$host_os" in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4* | aix5*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; darwin* | rhapsody*) if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no case "$host_os" in rhapsody* | darwin1.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' ;; 10.*) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' ;; esac fi ;; esac output_verbose_link_cmd='echo' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring' _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_automatic, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) AC_LIBTOOL_CONFIG($1) AC_LANG_POP CC="$lt_save_CC" ])# AC_LIBTOOL_LANG_C_CONFIG # AC_LIBTOOL_LANG_CXX_CONFIG # -------------------------- # Ensure that the configuration vars for the C compiler are # suitably defined. Those variables are subsequently used by # AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], [AC_LANG_PUSH(C++) AC_REQUIRE([AC_PROG_CXX]) AC_REQUIRE([AC_PROG_CXXCPP]) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(allow_undefined_flag, $1)= _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(archive_expsym_cmds, $1)= _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= _LT_AC_TAGVAR(hardcode_minus_L, $1)=no _LT_AC_TAGVAR(hardcode_automatic, $1)=no _LT_AC_TAGVAR(module_cmds, $1)= _LT_AC_TAGVAR(module_expsym_cmds, $1)= _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown _LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_AC_TAGVAR(no_undefined_flag, $1)= _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Dependencies to place before and after the object being linked: _LT_AC_TAGVAR(predep_objects, $1)= _LT_AC_TAGVAR(postdep_objects, $1)= _LT_AC_TAGVAR(predeps, $1)= _LT_AC_TAGVAR(postdeps, $1)= _LT_AC_TAGVAR(compiler_lib_search_path, $1)= # Source file extension for C++ test sources. ac_ext=cc # Object file extension for compiled C++ test sources. objext=o _LT_AC_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_AC_SYS_COMPILER # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC _LT_AC_TAGVAR(compiler, $1)=$CC cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` # We don't want -fno-exception wen compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration AC_PROG_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ grep 'no-whole-archive' > /dev/null; then _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_AC_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_AC_TAGVAR(archive_cmds, $1)='' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes if test "$GXX" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=yes else # We have old collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_AC_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) _LT_AC_TAGVAR(always_export_symbols, $1)=yes # Exported symbols can be pulled into shared objects from archives _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds it's shared libraries. _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; darwin* | rhapsody*) if test "$GXX" = yes; then _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no case "$host_os" in rhapsody* | darwin1.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' ;; 10.*) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_automatic, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; dgux*) case $cc_basename in ec++) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; ghcx) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd[12]*) # C++ shared libraries reported to be fairly broken before switch to ELF _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | kfreebsd*-gnu) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_AC_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; hpux9*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; aCC) _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then case "$host_cpu" in hppa*64*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; ia64*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; *) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case "$host_cpu" in hppa*64*) _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; ia64*) _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; *) _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; aCC) case "$host_cpu" in hppa*64*|ia64*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case "$host_cpu" in ia64*|hppa*64*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; irix5* | irix6*) case $cc_basename in CC) # SGI C++ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' fi fi _LT_AC_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; linux*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc) # Intel C++ with_gnu_ld=yes _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; cxx) # Compaq C++ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; osf3*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; RCC) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; cxx) _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; osf4* | osf5*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; RCC) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; cxx) _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ $rm $lib.exp' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; sco*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no case $cc_basename in CC) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; sunos4*) case $cc_basename in CC) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; lcc) # Lucid # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC) # Sun C++ 4.2, 5.x and Centerline C++ _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The C++ compiler is used as linker so we must use $wl # flag to pass the commands to the underlying system # linker. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac _LT_AC_TAGVAR(link_all_deplibs, $1)=yes # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx) # Green Hills C++ Compiler _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | grep -v '^2\.7' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' fi ;; esac ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;; tandem*) case $cc_basename in NCC) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_AC_TAGVAR(GCC, $1)="$GXX" _LT_AC_TAGVAR(LD, $1)="$LD" AC_LIBTOOL_POSTDEP_PREDEP($1) AC_LIBTOOL_PROG_COMPILER_PIC($1) AC_LIBTOOL_PROG_CC_C_O($1) AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) AC_LIBTOOL_PROG_LD_SHLIBS($1) AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) AC_LIBTOOL_SYS_LIB_STRIP AC_LIBTOOL_DLOPEN_SELF($1) AC_LIBTOOL_CONFIG($1) AC_LANG_POP CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ldcxx=$with_gnu_ld with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld ])# AC_LIBTOOL_LANG_CXX_CONFIG # AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) # ------------------------ # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" ifelse([$1], [], [#! $SHELL # `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. # # This file is part of GNU Libtool: # Originally by Gordon Matzigkeit , 1996 # # 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 of the License, 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 to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="$SED -e s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi # The names of the tagged configurations supported by this script. available_tags= # ### BEGIN LIBTOOL CONFIG], [# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) # Is the compiler the GNU C compiler? with_gcc=$_LT_AC_TAGVAR(GCC, $1) # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_[]_LT_AC_TAGVAR(LD, $1) # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) # Commands used to build and install a shared archive. archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) # Flag that forces no undefined symbols. no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" # Set to yes if exported symbols are required. always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) # The commands to list exported symbols. export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) # Symbols that must always be exported. include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) ifelse([$1],[], [# ### END LIBTOOL CONFIG], [# ### END LIBTOOL TAG CONFIG: $tagname]) __EOF__ ifelse([$1],[], [ case $host_os in aix3*) cat <<\EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi EOF ;; esac # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || \ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ]) else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ])# AC_LIBTOOL_CONFIG # AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------------------- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi ])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE # --------------------------------- AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_PROG_NM]) AC_REQUIRE([AC_OBJEXT]) # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Transform the above into a raw symbol and a C symbol. symxfrm='\1 \2\3 \3' # Transform an extracted symbol line into a proper C declaration lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32*) symcode='[[ABCDGISTW]]' ;; hpux*) # Its linker distinguishes data from code symbols if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris* | sysv5*) symcode='[[BDRT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Try without a prefix undercore, then with it. for ac_symprfx in "" "_"; do # Write the raw and C identifiers. lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if grep ' nm_test_var$' "$nlist" >/dev/null; then if grep ' nm_test_func$' "$nlist" >/dev/null; then cat < conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' cat <> conftest.$ac_ext #if defined (__STDC__) && __STDC__ # define lt_ptr_t void * #else # define lt_ptr_t char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr_t address; } lt_preloaded_symbols[[]] = { EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext cat <<\EOF >> conftest.$ac_ext {0, (lt_ptr_t) 0} }; #ifdef __cplusplus } #endif EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -f conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi ]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE # AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) # --------------------------------------- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], [_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_static, $1)= AC_MSG_CHECKING([for $compiler option to produce PIC]) ifelse([$1],[CXX],[ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | os2* | pw32*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= ;; sysv4*MP*) if test -d /usr/nec; then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix4* | aix5*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68) # Green Hills C++ Compiler # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; dgux*) case $cc_basename in ec++) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx) # Green Hills C++ Compiler _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | kfreebsd*-gnu) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" if test "$host_cpu" != ia64; then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux*) case $cc_basename in KCC) # KAI C++ Compiler _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; icpc) # Intel C++ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; cxx) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; osf3* | osf4* | osf5*) case $cc_basename in KCC) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC) # Rational C++ 2.4.1 _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx) # Digital/Compaq C++ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; sco*) case $cc_basename in CC) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; *) ;; esac ;; solaris*) case $cc_basename in CC) # Sun C++ 4.2, 5.x and Centerline C++ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx) # Green Hills C++ Compiler _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC) # Sun C++ 4.x _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc) # Lucid _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; tandem*) case $cc_basename in NCC) # NonStop-UX NCC 3.20 _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; unixware*) ;; vxworks*) ;; *) _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; newsos6) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; linux*) case $CC in icc* | ecc*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; ccc*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; sco3.2v5*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn' ;; solaris*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sunos4*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; uts4*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi case "$host_os" in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" ;; esac ]) # AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) # ------------------------------------ # See if the linker supports building shared libraries. AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) ifelse([$1],[CXX],[ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix4* | aix5*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' else _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw*) _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' ;; *) _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ],[ runpath_var= _LT_AC_TAGVAR(allow_undefined_flag, $1)= _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_AC_TAGVAR(archive_cmds, $1)= _LT_AC_TAGVAR(archive_expsym_cmds, $1)= _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_minus_L, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown _LT_AC_TAGVAR(hardcode_automatic, $1)=no _LT_AC_TAGVAR(module_cmds, $1)= _LT_AC_TAGVAR(module_expsym_cmds, $1)= _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_AC_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; openbsd*) with_gnu_ld=no ;; esac _LT_AC_TAGVAR(ld_shlibs, $1)=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_AC_TAGVAR(ld_shlibs, $1)=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris* | sysv5*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then _LT_AC_TAGVAR(ld_shlibs, $1)=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; sunos4*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_cmds, $1)="$tmp_archive_cmds" supports_anon_versioning=no case `$LD -v 2>/dev/null` in *\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac if test $supports_anon_versioning = yes; then _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ $echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' else _LT_AC_TAGVAR(archive_expsym_cmds, $1)="$tmp_archive_cmds" fi else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then runpath_var=LD_RUN_PATH _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= fi fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(always_export_symbols, $1)=yes _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$link_static_flag"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' else _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_AC_TAGVAR(archive_cmds, $1)='' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=yes else # We have old collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_AC_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) _LT_AC_TAGVAR(always_export_symbols, $1)=yes # Exported symbols can be pulled into shared objects from archives _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds it's shared libraries. _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # see comment about different semantics on the GNU ld section _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; bsdi4*) _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; darwin* | rhapsody*) if test "$GXX" = yes ; then _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no case "$host_os" in rhapsody* | darwin1.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' ;; 10.*) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_automatic, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; dgux*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; freebsd1*) _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10* | hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*|ia64*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case "$host_cpu" in hppa*64*|ia64*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; esac fi if test "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; ia64*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes ;; *) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; openbsd*) _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi ;; os2*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; sco3.2v5*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ;; solaris*) _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_AC_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_AC_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_AC_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4.2uw2*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no hardcode_runpath_var=yes runpath_var=LD_RUN_PATH ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text' if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' fi runpath_var='LD_RUN_PATH' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv5*) _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' ;; uts4*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac fi ]) AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi # # Do we need to explicitly link libc? # case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_AC_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_MSG_CHECKING([whether -lc should be explicitly linked in]) $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) _LT_AC_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) then _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no else _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) ;; esac fi ;; esac ])# AC_LIBTOOL_PROG_LD_SHLIBS # _LT_AC_FILE_LTDLL_C # ------------------- # Be careful that the start marker always follows a newline. AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ # /* ltdll.c starts here */ # #define WIN32_LEAN_AND_MEAN # #include # #undef WIN32_LEAN_AND_MEAN # #include # # #ifndef __CYGWIN__ # # ifdef __CYGWIN32__ # # define __CYGWIN__ __CYGWIN32__ # # endif # #endif # # #ifdef __cplusplus # extern "C" { # #endif # BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); # #ifdef __cplusplus # } # #endif # # #ifdef __CYGWIN__ # #include # DECLARE_CYGWIN_DLL( DllMain ); # #endif # HINSTANCE __hDllInstance_base; # # BOOL APIENTRY # DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) # { # __hDllInstance_base = hInst; # return TRUE; # } # /* ltdll.c ends here */ ])# _LT_AC_FILE_LTDLL_C # _LT_AC_TAGVAR(VARNAME, [TAGNAME]) # --------------------------------- AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) # old names AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) # This is just to silence aclocal about the macro not being used ifelse([AC_DISABLE_FAST_INSTALL]) AC_DEFUN([LT_AC_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj, no) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS) ]) AC_DEFUN([LT_AC_PROG_RC], [AC_CHECK_TOOL(RC, windres, no) ]) # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # # LT_AC_PROG_SED # -------------- # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. AC_DEFUN([LT_AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && break cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done SED=$lt_cv_path_SED ]) AC_MSG_RESULT([$SED]) ]) # -*- Autoconf -*- # Copyright (C) 2002, 2003 Free Software Foundation, Inc. # Generated from amversion.in; do not edit by hand. # 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 # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION so it can be traced. # This function is AC_REQUIREd by AC_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.9.2])]) # AM_AUX_DIR_EXPAND # Copyright (C) 2001, 2003 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. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004 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. # serial 6 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE]) AC_SUBST([$1_FALSE]) if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # serial 7 -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 # 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. # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf case $depmode in nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; none) break ;; esac # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. if depmode=$depmode \ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH]) ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 # 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. #serial 2 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [for mf in $CONFIG_FILES; do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # So let's grep whole file. if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # This macro actually does too much some checks are only needed if # your package does certain things. But this isn't really a big deal. # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 # 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. # serial 11 # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.58])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl # test to see if srcdir already configured if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AM_PROG_INSTALL_SH AM_PROG_INSTALL_STRIP AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl ]) ]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $1 | $1:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. # Copyright (C) 2001, 2003 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. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl install_sh=${install_sh-"$am_aux_dir/install-sh"} AC_SUBST(install_sh)]) # -*- Autoconf -*- # Copyright (C) 2003 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. # serial 1 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. # From Jim Meyering # Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004 # 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. # serial 3 AC_DEFUN([AM_MAINTAINER_MODE], [AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode is disabled by default AC_ARG_ENABLE(maintainer-mode, [ --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer], USE_MAINTAINER_MODE=$enableval, USE_MAINTAINER_MODE=no) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST(MAINT)dnl ] ) AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003 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. # serial 2 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo done .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # We grep out `Entering directory' and `Leaving directory' # messages which can occur if `w' ends up in MAKEFLAGS. # In particular we don't look at `^make:' because GNU make might # be invoked under some other name (usually "gmake"), in which # case it prints its new name instead of `make'. if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then am__include=include am__quote= _am_result=GNU fi # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then am__include=.include am__quote="\"" _am_result=BSD fi fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003 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. # serial 3 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # AM_PROG_MKDIR_P # --------------- # Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. # Copyright (C) 2003, 2004 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. # Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories # created by `make install' are always world readable, even if the # installer happens to have an overly restrictive umask (e.g. 077). # This was a mistake. There are at least two reasons why we must not # use `-m 0755': # - it causes special bits like SGID to be ignored, # - it may be too restrictive (some setups expect 775 directories). # # Do not use -m 0755 and let people choose whatever they expect by # setting umask. # # We cannot accept any implementation of `mkdir' that recognizes `-p'. # Some implementations (such as Solaris 8's) are not thread-safe: if a # parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' # concurrently, both version can detect that a/ is missing, but only # one can create it and the other will error out. Consequently we # restrict ourselves to GNU make (using the --version option ensures # this.) AC_DEFUN([AM_PROG_MKDIR_P], [if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then # We used to keeping the `.' as first argument, in order to # allow $(mkdir_p) to be used without argument. As in # $(mkdir_p) $(somedir) # where $(somedir) is conditionally defined. However this is wrong # for two reasons: # 1. if the package is installed by a user who cannot write `.' # make install will fail, # 2. the above comment should most certainly read # $(mkdir_p) $(DESTDIR)$(somedir) # so it does not work when $(somedir) is undefined and # $(DESTDIR) is not. # To support the latter case, we have to write # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), # so the `.' trick is pointless. mkdir_p='mkdir -p --' else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. for d in ./-p ./--version; do test -d $d && rmdir $d done # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. if test -f "$ac_aux_dir/mkinstalldirs"; then mkdir_p='$(mkinstalldirs)' else mkdir_p='$(install_sh) -d' fi fi AC_SUBST([mkdir_p])]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003 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. # serial 2 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # ------------------------------ # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # # Check to make sure that the build environment is sane. # # Copyright (C) 1996, 1997, 2000, 2001, 2003 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. # serial 3 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # AM_PROG_INSTALL_STRIP # Copyright (C) 2001, 2003 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. # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004 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. # serial 1 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. AM_MISSING_PROG([AMTAR], [tar]) m4_if([$1], [v7], [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/autogen.sh000077500000000000000000000011051321604176500265370ustar00rootroot00000000000000#!/bin/sh # $Id: autogen.sh 2 2008-04-24 15:04:59Z naoaki $ if [ "$1" = "--force" ]; then FORCE=--force NOFORCE= FORCE_MISSING=--force-missing else FORCE= NOFORCE=--no-force FORCE_MISSING= fi libtoolize --copy $FORCE 2>&1 | sed '/^You should/d' || { echo "libtoolize failed!" exit 1 } aclocal $FORCE || { echo "aclocal failed!" exit 1 } autoheader $FORCE || { echo "autoheader failed!" exit 1 } automake -a -c $NOFORCE || { echo "automake failed!" exit 1 } autoconf $FORCE || { echo "autoconf failed!" exit 1 } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/config.h.in000066400000000000000000000032321321604176500265640ustar00rootroot00000000000000/* config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_EMMINTRIN_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_XMMINTRIN_H /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/configure000077500000000000000000024574141321604176500264710ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59. # # Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` ;; esac echo=${ECHO-echo} if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then # Yippee, $echo works! : else # Restart under the correct shell. exec $SHELL "$0" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null && echo_test_string="`eval $cmd`" && (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null then break fi done fi if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$echo" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. echo='print -r' elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} else # Try using printf. echo='printf %s\n' if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL echo="$CONFIG_SHELL $0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$CONFIG_SHELL $0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "$0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} else # Oops. We lost completely, so just stick with echo. echo=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. ECHO=$echo if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" fi tagnames=${tagnames+${tagnames},}CXX tagnames=${tagnames+${tagnames},}F77 # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= ac_unique_file="lib/lbfgs.c" # Factoring default headers for most tests. ac_includes_default="\ #include #if HAVE_SYS_TYPES_H # include #endif #if HAVE_SYS_STAT_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_STRING_H # if !STDC_HEADERS && HAVE_MEMORY_H # include # endif # include #endif #if HAVE_STRINGS_H # include #endif #if HAVE_INTTYPES_H # include #else # if HAVE_STDINT_H # include # endif #endif #if HAVE_UNISTD_H # include #endif" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL INCLUDES LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias ac_env_CC_set=${CC+set} ac_env_CC_value=$CC ac_cv_env_CC_set=${CC+set} ac_cv_env_CC_value=$CC ac_env_CFLAGS_set=${CFLAGS+set} ac_env_CFLAGS_value=$CFLAGS ac_cv_env_CFLAGS_set=${CFLAGS+set} ac_cv_env_CFLAGS_value=$CFLAGS ac_env_LDFLAGS_set=${LDFLAGS+set} ac_env_LDFLAGS_value=$LDFLAGS ac_cv_env_LDFLAGS_set=${LDFLAGS+set} ac_cv_env_LDFLAGS_value=$LDFLAGS ac_env_CPPFLAGS_set=${CPPFLAGS+set} ac_env_CPPFLAGS_value=$CPPFLAGS ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} ac_cv_env_CPPFLAGS_value=$CPPFLAGS ac_env_CPP_set=${CPP+set} ac_env_CPP_value=$CPP ac_cv_env_CPP_set=${CPP+set} ac_cv_env_CPP_value=$CPP ac_env_CXX_set=${CXX+set} ac_env_CXX_value=$CXX ac_cv_env_CXX_set=${CXX+set} ac_cv_env_CXX_value=$CXX ac_env_CXXFLAGS_set=${CXXFLAGS+set} ac_env_CXXFLAGS_value=$CXXFLAGS ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set} ac_cv_env_CXXFLAGS_value=$CXXFLAGS ac_env_CXXCPP_set=${CXXCPP+set} ac_env_CXXCPP_value=$CXXCPP ac_cv_env_CXXCPP_set=${CXXCPP+set} ac_cv_env_CXXCPP_value=$CXXCPP ac_env_F77_set=${F77+set} ac_env_F77_value=$F77 ac_cv_env_F77_set=${F77+set} ac_cv_env_F77_value=$F77 ac_env_FFLAGS_set=${FFLAGS+set} ac_env_FFLAGS_value=$FFLAGS ac_cv_env_FFLAGS_set=${FFLAGS+set} ac_cv_env_FFLAGS_value=$FFLAGS # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] _ACEOF cat <<_ACEOF Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data [PREFIX/share] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --disable-libtool-lock avoid locking (might break parallel builds) --enable-debug build for debugging --enable-profile build for profiling --enable-sse2 enable SSE2 optimization routines Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-pic try to use only PIC/non-PIC objects [default=use both] --with-tags[=TAGS] include additional configurations [automatic] Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor F77 Fortran 77 compiler command FFLAGS Fortran 77 compiler flags Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style configure. if test -f $ac_srcdir/configure.gnu; then echo $SHELL $ac_srcdir/configure.gnu --help=recursive elif test -f $ac_srcdir/configure; then echo $SHELL $ac_srcdir/configure --help=recursive elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd $ac_popdir done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF Copyright (C) 2003 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` hostinfo = `(hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_sep= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val="\$ac_cv_env_${ac_var}_value" eval ac_new_val="\$ac_env_${ac_var}_value" case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version="1.9" ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f $ac_dir/shtool; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo "$as_me:$LINENO: checking whether build environment is sane" >&5 echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 # Just in case sleep 1 echo timestamp > conftest.file # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" >&5 echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" >&2;} { (exit 1); exit 1; }; } fi test "$2" = conftest.file ) then # Ok. : else { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! Check your system clock" >&5 echo "$as_me: error: newly created file is older than distributed files! Check your system clock" >&2;} { (exit 1); exit 1; }; } fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 test "$program_prefix" != NONE && program_transform_name="s,^,$program_prefix,;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s,\$,$program_suffix,;$program_transform_name" # Double any \ or $. echo might interpret backslashes. # By default was `s,x,x', remove it if useless. cat <<\_ACEOF >conftest.sed s/[\\$]/&&/g;s/;s,x,x,$// _ACEOF program_transform_name=`echo $program_transform_name | sed -f conftest.sed` rm conftest.sed # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then # We used to keeping the `.' as first argument, in order to # allow $(mkdir_p) to be used without argument. As in # $(mkdir_p) $(somedir) # where $(somedir) is conditionally defined. However this is wrong # for two reasons: # 1. if the package is installed by a user who cannot write `.' # make install will fail, # 2. the above comment should most certainly read # $(mkdir_p) $(DESTDIR)$(somedir) # so it does not work when $(somedir) is undefined and # $(DESTDIR) is not. # To support the latter case, we have to write # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), # so the `.' trick is pointless. mkdir_p='mkdir -p --' else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. for d in ./-p ./--version; do test -d $d && rmdir $d done # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. if test -f "$ac_aux_dir/mkinstalldirs"; then mkdir_p='$(mkinstalldirs)' else mkdir_p='$(install_sh) -d' fi fi for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_AWK+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then echo "$as_me:$LINENO: result: $AWK" >&5 echo "${ECHO_T}$AWK" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$AWK" && break done echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF all: @echo 'ac_maketemp="$(MAKE)"' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_set=yes else eval ac_cv_prog_make_${ac_make}_set=no fi rm -f conftest.make fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 SET_MAKE= else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # test to see if srcdir already configured if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} { (exit 1); exit 1; }; } fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE=liblbfgs VERSION=1.9 cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} install_sh=${install_sh-"$am_aux_dir/install-sh"} # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_STRIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then echo "$as_me:$LINENO: result: $STRIP" >&5 echo "${ECHO_T}$STRIP" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 echo "${ECHO_T}$ac_ct_STRIP" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi STRIP=$ac_ct_STRIP else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. AMTAR=${AMTAR-"${am_missing_run}tar"} am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' ac_config_headers="$ac_config_headers config.h" echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6 # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then enableval="$enable_maintainer_mode" USE_MAINTAINER_MODE=$enableval else USE_MAINTAINER_MODE=no fi; echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5 echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6 if test $USE_MAINTAINER_MODE = yes; then MAINTAINER_MODE_TRUE= MAINTAINER_MODE_FALSE='#' else MAINTAINER_MODE_TRUE='#' MAINTAINER_MODE_FALSE= fi MAINT=$MAINTAINER_MODE_TRUE # Check whether --enable-shared or --disable-shared was given. if test "${enable_shared+set}" = set; then enableval="$enable_shared" p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi; # Check whether --enable-static or --disable-static was given. if test "${enable_static+set}" = set; then enableval="$enable_static" p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi; # Check whether --enable-fast-install or --disable-fast-install was given. if test "${enable_fast_install+set}" = set; then enableval="$enable_fast_install" p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi; # Make sure we can run config.sub. $ac_config_sub sun4 >/dev/null 2>&1 || { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 echo "$as_me: error: cannot run $ac_config_sub" >&2;} { (exit 1); exit 1; }; } echo "$as_me:$LINENO: checking build system type" >&5 echo $ECHO_N "checking build system type... $ECHO_C" >&6 if test "${ac_cv_build+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_build_alias=$build_alias test -z "$ac_cv_build_alias" && ac_cv_build_alias=`$ac_config_guess` test -z "$ac_cv_build_alias" && { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 echo "$as_me: error: cannot guess build type; you must specify one" >&2;} { (exit 1); exit 1; }; } ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} { (exit 1); exit 1; }; } fi echo "$as_me:$LINENO: result: $ac_cv_build" >&5 echo "${ECHO_T}$ac_cv_build" >&6 build=$ac_cv_build build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$as_me:$LINENO: checking host system type" >&5 echo $ECHO_N "checking host system type... $ECHO_C" >&6 if test "${ac_cv_host+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_host_alias=$host_alias test -z "$ac_cv_host_alias" && ac_cv_host_alias=$ac_cv_build_alias ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} { (exit 1); exit 1; }; } fi echo "$as_me:$LINENO: result: $ac_cv_host" >&5 echo "${ECHO_T}$ac_cv_host" >&6 host=$ac_cv_host host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo done .PHONY: am__doit END # If we don't find an include directive, just comment out the code. echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # We grep out `Entering directory' and `Leaving directory' # messages which can occur if `w' ends up in MAKEFLAGS. # In particular we don't look at `^make:' because GNU make might # be invoked under some other name (usually "gmake"), in which # case it prints its new name instead of `make'. if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then am__include=include am__quote= _am_result=GNU fi # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then am__include=.include am__quote="\"" _am_result=BSD fi fi echo "$as_me:$LINENO: result: $_am_result" >&5 echo "${ECHO_T}$_am_result" >&6 rm -f confinc confmf # Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then enableval="$enable_dependency_tracking" fi; if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CC" && break done CC=$ac_ct_CC fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last # resort. # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= # b.out is created by i960 compilers. for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; conftest.$ac_ext ) # This is the source file. ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` # FIXME: I believe we export ac_cv_exeext for Libtool, # but it would be cool to find out if it's true. Does anybody # maintain Libtool? --akim. export ac_cv_exeext break;; * ) break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cc_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_stdc=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std1 is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std1. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF # Don't try gcc -ansi; that turns off useful extensions and # breaks some systems' header files. # AIX -qlanglvl=ansi # Ultrix and OSF/1 -std1 # HP-UX 10.20 and later -Ae # HP-UX older versions -Aa -D_HPUX_SOURCE # SVR4 -Xc -D__EXTENSIONS__ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_stdc=$ac_arg break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext done rm -f conftest.$ac_ext conftest.$ac_objext CC=$ac_save_CC fi case "x$ac_cv_prog_cc_stdc" in x|xno) echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6 ;; *) echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 CC="$CC $ac_cv_prog_cc_stdc" ;; esac # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide # the declaration of exit, since it's the most demanding environment. cat >conftest.$ac_ext <<_ACEOF #ifndef __cplusplus choke me #endif _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ '' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration #include int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf case $depmode in nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; none) break ;; esac # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. if depmode=$depmode \ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6 if test "${lt_cv_path_SED+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && break cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done SED=$lt_cv_path_SED fi echo "$as_me:$LINENO: result: $SED" >&5 echo "${ECHO_T}$SED" >&6 echo "$as_me:$LINENO: checking for egrep" >&5 echo $ECHO_N "checking for egrep... $ECHO_C" >&6 if test "${ac_cv_prog_egrep+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi fi echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 echo "${ECHO_T}$ac_cv_prog_egrep" >&6 EGREP=$ac_cv_prog_egrep # Check whether --with-gnu-ld or --without-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then withval="$with_gnu_ld" test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi; ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. echo "$as_me:$LINENO: checking for ld used by $CC" >&5 echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6 case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then echo "$as_me:$LINENO: checking for GNU ld" >&5 echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 else echo "$as_me:$LINENO: checking for non-GNU ld" >&5 echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 fi if test "${lt_cv_path_LD+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 echo "${ECHO_T}$LD" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} { (exit 1); exit 1; }; } echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 if test "${lt_cv_prog_gnu_ld+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 &5 echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 with_gnu_ld=$lt_cv_prog_gnu_ld echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6 if test "${lt_cv_ld_reload_flag+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_cv_ld_reload_flag='-r' fi echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6 reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6 if test "${lt_cv_path_NM+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/${ac_tool_prefix}nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac esac fi done IFS="$lt_save_ifs" test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm fi fi echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5 echo "${ECHO_T}$lt_cv_path_NM" >&6 NM="$lt_cv_path_NM" echo "$as_me:$LINENO: checking whether ln -s works" >&5 echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no, using $LN_S" >&5 echo "${ECHO_T}no, using $LN_S" >&6 fi echo "$as_me:$LINENO: checking how to recognise dependent libraries" >&5 echo $ECHO_N "checking how to recognise dependent libraries... $ECHO_C" >&6 if test "${lt_cv_deplibs_check_method+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix4* | aix5*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi4*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump'. lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | kfreebsd*-gnu) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case "$host_cpu" in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux*) case $host_cpu in alpha*|hppa*|i*86|ia64*|m68*|mips*|powerpc*|sparc*|s390*|sh*|x86_64*) lt_cv_deplibs_check_method=pass_all ;; *) # glibc up to 2.1.1 does not perform some relocations on ARM # this will be overridden with pass_all, but let us keep it just in case lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; esac lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; nto-qnx*) lt_cv_deplibs_check_method=unknown ;; openbsd*) lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object' else lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; sco3.2v5*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; esac ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; esac fi echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6 file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # Check whether --enable-libtool-lock or --disable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then enableval="$enable_libtool_lock" fi; test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 3682 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then case "`/usr/bin/file conftest.o`" in *32-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6 if test "${lt_cv_cc_needs_belf+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then lt_cv_cc_needs_belf=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 lt_cv_cc_needs_belf=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6 if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; esac need_locks="$enable_libtool_lock" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi echo "$as_me:$LINENO: result: $CPP" >&5 echo "${ECHO_T}$CPP" >&6 ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6 if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_ext=cc ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -n "$ac_tool_prefix"; then for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CXX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then echo "$as_me:$LINENO: result: $CXX" >&5 echo "${ECHO_T}$CXX" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 echo "${ECHO_T}$ac_ct_CXX" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CXX" && break done test -n "$ac_ct_CXX" || ac_ct_CXX="g++" CXX=$ac_ct_CXX fi # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C++ compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 if test "${ac_cv_cxx_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 GXX=`test $ac_compiler_gnu = yes && echo yes` ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS CXXFLAGS="-g" echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cxx_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cxx_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cxx_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi for ac_declaration in \ '' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration #include int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi ac_ext=cc ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu depcc="$CXX" am_compiler_list= echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf case $depmode in nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; none) break ;; esac # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. if depmode=$depmode \ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6 CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi ac_ext=cc ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6 if test -z "$CXXCPP"; then if test "${ac_cv_prog_CXXCPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi echo "$as_me:$LINENO: result: $CXXCPP" >&5 echo "${ECHO_T}$CXXCPP" >&6 ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_cxx_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi ac_ext=cc ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_ext=f ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_f77_compiler_gnu if test -n "$ac_tool_prefix"; then for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_F77+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$F77"; then ac_cv_prog_F77="$F77" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_F77="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi F77=$ac_cv_prog_F77 if test -n "$F77"; then echo "$as_me:$LINENO: result: $F77" >&5 echo "${ECHO_T}$F77" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$F77" && break done fi if test -z "$F77"; then ac_ct_F77=$F77 for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_F77+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_F77"; then ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_F77="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_F77=$ac_cv_prog_ac_ct_F77 if test -n "$ac_ct_F77"; then echo "$as_me:$LINENO: result: $ac_ct_F77" >&5 echo "${ECHO_T}$ac_ct_F77" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_F77" && break done F77=$ac_ct_F77 fi # Provide some information about the compiler. echo "$as_me:5254:" \ "checking for Fortran 77 compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } rm -f a.out # If we don't use `.F' as extension, the preprocessor is not run on the # input file. (Note that this only needs to work for GNU compilers.) ac_save_ext=$ac_ext ac_ext=F echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5 echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6 if test "${ac_cv_f77_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF program main #ifndef __GNUC__ choke me #endif end _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_f77_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6 ac_ext=$ac_save_ext ac_test_FFLAGS=${FFLAGS+set} ac_save_FFLAGS=$FFLAGS FFLAGS= echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5 echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_f77_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else FFLAGS=-g cat >conftest.$ac_ext <<_ACEOF program main end _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_f77_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_f77_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5 echo "${ECHO_T}$ac_cv_prog_f77_g" >&6 if test "$ac_test_FFLAGS" = set; then FFLAGS=$ac_save_FFLAGS elif test $ac_cv_prog_f77_g = yes; then if test "x$ac_cv_f77_compiler_gnu" = xyes; then FFLAGS="-g -O2" else FFLAGS="-g" fi else if test "x$ac_cv_f77_compiler_gnu" = xyes; then FFLAGS="-O2" else FFLAGS= fi fi G77=`test $ac_compiler_gnu = yes && echo yes` ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! # find the maximum length of command line arguments echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5 echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6 if test "${lt_cv_sys_max_cmd_len+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; *) # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while (test "X"`$CONFIG_SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \ = "XX$teststring") >/dev/null 2>&1 && new_result=`expr "X$teststring" : ".*" 2>&1` && lt_cv_sys_max_cmd_len=$new_result && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done teststring= # Add a significant safety factor because C++ compilers can tack on massive # amounts of additional arguments before passing them to the linker. # It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5 echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6 else echo "$as_me:$LINENO: result: none" >&5 echo "${ECHO_T}none" >&6 fi # Check for command to grab the raw symbol name followed by C symbol from nm. echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5 echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6 if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Transform the above into a raw symbol and a C symbol. symxfrm='\1 \2\3 \3' # Transform an extracted symbol line into a proper C declaration lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32*) symcode='[ABCDGISTW]' ;; hpux*) # Its linker distinguishes data from code symbols if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris* | sysv5*) symcode='[BDRT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Try without a prefix undercore, then with it. for ac_symprfx in "" "_"; do # Write the raw and C identifiers. lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Now try to grab the symbols. nlist=conftest.nm if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if grep ' nm_test_var$' "$nlist" >/dev/null; then if grep ' nm_test_func$' "$nlist" >/dev/null; then cat < conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' cat <> conftest.$ac_ext #if defined (__STDC__) && __STDC__ # define lt_ptr_t void * #else # define lt_ptr_t char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr_t address; } lt_preloaded_symbols[] = { EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext cat <<\EOF >> conftest.$ac_ext {0, (lt_ptr_t) 0} }; #ifdef __cplusplus } #endif EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then echo "$as_me:$LINENO: result: failed" >&5 echo "${ECHO_T}failed" >&6 else echo "$as_me:$LINENO: result: ok" >&5 echo "${ECHO_T}ok" >&6 fi echo "$as_me:$LINENO: checking for objdir" >&5 echo $ECHO_N "checking for objdir... $ECHO_C" >&6 if test "${lt_cv_objdir+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5 echo "${ECHO_T}$lt_cv_objdir" >&6 objdir=$lt_cv_objdir case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e s/^X//' sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Constants: rm="rm -f" # Global variables: default_ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except M$VC, # which needs '.lib'). libext=a ltmain="$ac_aux_dir/ltmain.sh" ofile="$default_ofile" with_gnu_ld="$lt_cv_prog_gnu_ld" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_AR+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then echo "$as_me:$LINENO: result: $AR" >&5 echo "${ECHO_T}$AR" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_AR+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="false" fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 echo "${ECHO_T}$ac_ct_AR" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi AR=$ac_ct_AR else AR="$ac_cv_prog_AR" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then echo "$as_me:$LINENO: result: $RANLIB" >&5 echo "${ECHO_T}$RANLIB" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 echo "${ECHO_T}$ac_ct_RANLIB" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi RANLIB=$ac_ct_RANLIB else RANLIB="$ac_cv_prog_RANLIB" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_STRIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then echo "$as_me:$LINENO: result: $STRIP" >&5 echo "${ECHO_T}$STRIP" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 echo "${ECHO_T}$ac_ct_STRIP" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi STRIP=$ac_ct_STRIP else STRIP="$ac_cv_prog_STRIP" fi old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru test -z "$AS" && AS=as test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$DLLTOOL" && DLLTOOL=dlltool test -z "$LD" && LD=ld test -z "$LN_S" && LN_S="ln -s" test -z "$MAGIC_CMD" && MAGIC_CMD=file test -z "$NM" && NM=nm test -z "$SED" && SED=sed test -z "$OBJDUMP" && OBJDUMP=objdump test -z "$RANLIB" && RANLIB=: test -z "$STRIP" && STRIP=: test -z "$ac_objext" && ac_objext=o # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" ;; *) old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi # Only perform the check for file, if the check method requires it case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6 if test "${lt_cv_path_MAGIC_CMD+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 echo "${ECHO_T}$MAGIC_CMD" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then echo "$as_me:$LINENO: checking for file" >&5 echo $ECHO_N "checking for file... $ECHO_C" >&6 if test "${lt_cv_path_MAGIC_CMD+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 echo "${ECHO_T}$MAGIC_CMD" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi else MAGIC_CMD=: fi fi fi ;; esac enable_dlopen=no enable_win32_dll=no # Check whether --enable-libtool-lock or --disable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then enableval="$enable_libtool_lock" fi; test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Check whether --with-pic or --without-pic was given. if test "${with_pic+set}" = set; then withval="$with_pic" pic_mode="$withval" else pic_mode=default fi; test -z "$pic_mode" && pic_mode=default # Use C for the default configuration in the libtool script tagname= lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}\n' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # # Check for any special shared library compilation flags. # lt_prog_cc_shlib= if test "$GCC" = no; then case $host_os in sco3.2v5*) lt_prog_cc_shlib='-belf' ;; esac fi if test -n "$lt_prog_cc_shlib"; then { echo "$as_me:$LINENO: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&5 echo "$as_me: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&2;} if echo "$old_CC $old_CFLAGS " | grep "[ ]$lt_prog_cc_shlib[ ]" >/dev/null; then : else { echo "$as_me:$LINENO: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5 echo "$as_me: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;} lt_cv_prog_cc_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # echo "$as_me:$LINENO: checking if $compiler static flag $lt_prog_compiler_static works" >&5 echo $ECHO_N "checking if $compiler static flag $lt_prog_compiler_static works... $ECHO_C" >&6 if test "${lt_prog_compiler_static_works+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_prog_compiler_static" printf "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 else lt_prog_compiler_static_works=yes fi fi $rm conftest* LDFLAGS="$save_LDFLAGS" fi echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5 echo "${ECHO_T}$lt_prog_compiler_static_works" >&6 if test x"$lt_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then lt_prog_compiler_no_builtin_flag=' -fno-builtin' echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:6288: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:6292: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $rm conftest* fi echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6 if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; *) lt_prog_compiler_pic='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; linux*) case $CC in icc* | ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; sco3.2v5*) lt_prog_compiler_pic='-Kpic' lt_prog_compiler_static='-dn' ;; solaris*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5 echo "${ECHO_T}$lt_prog_compiler_pic" >&6 # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6 if test "${lt_prog_compiler_pic_works+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:6521: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:6525: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_prog_compiler_pic_works=yes fi fi $rm conftest* fi echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5 echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6 if test x"$lt_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi case "$host_os" in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 if test "${lt_cv_prog_compiler_c_o+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_cv_prog_compiler_c_o=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:6581: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:6585: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s out/conftest.err; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6 hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no echo "$as_me:$LINENO: result: $hard_links" >&5 echo "${ECHO_T}$hard_links" >&6 if test "$hard_links" = no; then { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 runpath_var= allow_undefined_flag= enable_shared_with_static_runtimes=no archive_cmds= archive_expsym_cmds= old_archive_From_new_cmds= old_archive_from_expsyms_cmds= export_dynamic_flag_spec= whole_archive_flag_spec= thread_safe_flag_spec= hardcode_libdir_flag_spec= hardcode_libdir_flag_spec_ld= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no hardcode_shlibpath_var=unsupported link_all_deplibs=unknown hardcode_automatic=no module_cmds= module_expsym_cmds= always_export_symbols=no export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris* | sysv5*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_cmds="$tmp_archive_cmds" supports_anon_versioning=no case `$LD -v 2>/dev/null` in *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac if test $supports_anon_versioning = yes; then archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ $echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' else archive_expsym_cmds="$tmp_archive_cmds" fi else ld_shlibs=no fi ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = yes; then runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$link_static_flag"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_libdir_separator=':' link_all_deplibs=yes if test "$GCC" = yes; then case $host_os in aix4.012|aix4.012.*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct=yes else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an empty executable. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) always_export_symbols=yes # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec=' ' archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds it's shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; bsdi4*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_From_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes=yes ;; darwin* | rhapsody*) if test "$GXX" = yes ; then archive_cmds_need_lc=no case "$host_os" in rhapsody* | darwin1.[012]) allow_undefined_flag='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag='-flat_namespace -undefined suppress' ;; 10.*) allow_undefined_flag='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_cmds='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else archive_cmds='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi module_cmds='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported whole_archive_flag_spec='-all_load $convenience' link_all_deplibs=yes else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; freebsd1*) ld_shlibs=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu) archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10* | hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*|ia64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case "$host_cpu" in hppa*64*|ia64*) archive_cmds='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' ;; *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; esac fi if test "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld='+b $libdir' hardcode_libdir_separator=: hardcode_direct=no hardcode_shlibpath_var=no ;; ia64*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=no hardcode_shlibpath_var=no # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; *) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_ld='-rpath $libdir' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: link_all_deplibs=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; openbsd*) hardcode_direct=yes hardcode_shlibpath_var=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; sco3.2v5*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='${wl}-Bexport' runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ;; solaris*) no_undefined_flag=' -z text' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4.2uw2*) archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=no hardcode_shlibpath_var=no hardcode_runpath_var=yes runpath_var=LD_RUN_PATH ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) no_undefined_flag='${wl}-z ${wl}text' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' fi runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv5*) no_undefined_flag=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' hardcode_libdir_flag_spec= hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac fi echo "$as_me:$LINENO: result: $ld_shlibs" >&5 echo "${ECHO_T}$ld_shlibs" >&6 test "$ld_shlibs" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } then archive_cmds_need_lc=no else archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5 echo "${ECHO_T}$archive_cmds_need_lc" >&6 ;; esac fi ;; esac echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.01* | freebsdelf3.01*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case "$host_cpu" in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # find out which ABI we are using libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) echo '#line 7915 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then case `/usr/bin/file conftest.$ac_objext` in *64-bit*) libsuff=64 sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; esac fi rm -rf conftest* ;; esac # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; knetbsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos need_lib_prefix=no need_version=yes library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac echo "$as_me:$LINENO: result: $dynamic_linker" >&5 echo "${ECHO_T}$dynamic_linker" >&6 test "$dynamic_linker" = no && can_build_shared=no echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 hardcode_action= if test -n "$hardcode_libdir_flag_spec" || \ test -n "$runpath_var " || \ test "X$hardcode_automatic"="Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi echo "$as_me:$LINENO: result: $hardcode_action" >&5 echo "${ECHO_T}$hardcode_action" >&6 if test "$hardcode_action" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi striplib= old_striplib= echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi ;; *) echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 ;; esac fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 if test "${ac_cv_lib_dl_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); int main () { dlopen (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dl_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dl_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 if test $ac_cv_lib_dl_dlopen = yes; then lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) echo "$as_me:$LINENO: checking for shl_load" >&5 echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 if test "${ac_cv_func_shl_load+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define shl_load to an innocuous variant, in case declares shl_load. For example, HP-UX 11i declares gettimeofday. */ #define shl_load innocuous_shl_load /* System header to define __stub macros and hopefully few prototypes, which can conflict with char shl_load (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef shl_load /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_shl_load) || defined (__stub___shl_load) choke me #else char (*f) () = shl_load; #endif #ifdef __cplusplus } #endif int main () { return f != shl_load; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_shl_load=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_shl_load=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 echo "${ECHO_T}$ac_cv_func_shl_load" >&6 if test $ac_cv_func_shl_load = yes; then lt_cv_dlopen="shl_load" else echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 if test "${ac_cv_lib_dld_shl_load+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load (); int main () { shl_load (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dld_shl_load=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dld_shl_load=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 if test $ac_cv_lib_dld_shl_load = yes; then lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" else echo "$as_me:$LINENO: checking for dlopen" >&5 echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 if test "${ac_cv_func_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define dlopen to an innocuous variant, in case declares dlopen. For example, HP-UX 11i declares gettimeofday. */ #define dlopen innocuous_dlopen /* System header to define __stub macros and hopefully few prototypes, which can conflict with char dlopen (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef dlopen /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_dlopen) || defined (__stub___dlopen) choke me #else char (*f) () = dlopen; #endif #ifdef __cplusplus } #endif int main () { return f != dlopen; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 echo "${ECHO_T}$ac_cv_func_dlopen" >&6 if test $ac_cv_func_dlopen = yes; then lt_cv_dlopen="dlopen" else echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 if test "${ac_cv_lib_dl_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); int main () { dlopen (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dl_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dl_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 if test $ac_cv_lib_dl_dlopen = yes; then lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 if test "${ac_cv_lib_svld_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); int main () { dlopen (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_svld_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_svld_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 if test $ac_cv_lib_svld_dlopen = yes; then lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6 if test "${ac_cv_lib_dld_dld_link+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dld_link (); int main () { dld_link (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dld_dld_link=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dld_dld_link=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6 if test $ac_cv_lib_dld_dld_link = yes; then lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 if test "${lt_cv_dlopen_self+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 echo "${ECHO_T}$lt_cv_dlopen_self" >&6 if test "x$lt_cv_dlopen_self" = xyes; then LDFLAGS="$LDFLAGS $link_static_flag" echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 if test "${lt_cv_dlopen_self_static+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi # Report which librarie types wil actually be built echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $can_build_shared" >&5 echo "${ECHO_T}$can_build_shared" >&6 echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6 test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case "$host_os" in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4* | aix5*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; darwin* | rhapsody*) if test "$GCC" = yes; then archive_cmds_need_lc=no case "$host_os" in rhapsody* | darwin1.[012]) allow_undefined_flag='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag='-flat_namespace -undefined suppress' ;; 10.*) allow_undefined_flag='-undefined dynamic_lookup' ;; esac fi ;; esac output_verbose_link_cmd='echo' archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring' module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported whole_archive_flag_spec='-all_load $convenience' link_all_deplibs=yes else ld_shlibs=no fi ;; esac echo "$as_me:$LINENO: result: $enable_shared" >&5 echo "${ECHO_T}$enable_shared" >&6 echo "$as_me:$LINENO: checking whether to build static libraries" >&5 echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6 # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes echo "$as_me:$LINENO: result: $enable_static" >&5 echo "${ECHO_T}$enable_static" >&6 # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \ SED SHELL STRIP \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler \ CC \ LD \ lt_prog_compiler_wl \ lt_prog_compiler_pic \ lt_prog_compiler_static \ lt_prog_compiler_no_builtin_flag \ export_dynamic_flag_spec \ thread_safe_flag_spec \ whole_archive_flag_spec \ enable_shared_with_static_runtimes \ old_archive_cmds \ old_archive_from_new_cmds \ predep_objects \ postdep_objects \ predeps \ postdeps \ compiler_lib_search_path \ archive_cmds \ archive_expsym_cmds \ postinstall_cmds \ postuninstall_cmds \ old_archive_from_expsyms_cmds \ allow_undefined_flag \ no_undefined_flag \ export_symbols_cmds \ hardcode_libdir_flag_spec \ hardcode_libdir_flag_spec_ld \ hardcode_libdir_separator \ hardcode_automatic \ module_cmds \ module_expsym_cmds \ lt_cv_prog_compiler_c_o \ exclude_expsyms \ include_expsyms; do case $var in old_archive_cmds | \ old_archive_from_new_cmds | \ archive_cmds | \ archive_expsym_cmds | \ module_cmds | \ module_expsym_cmds | \ old_archive_from_expsyms_cmds | \ export_symbols_cmds | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="${ofile}T" trap "$rm \"$cfgfile\"; exit 1" 1 2 15 $rm -f "$cfgfile" { echo "$as_me:$LINENO: creating $ofile" >&5 echo "$as_me: creating $ofile" >&6;} cat <<__EOF__ >> "$cfgfile" #! $SHELL # `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. # # This file is part of GNU Libtool: # Originally by Gordon Matzigkeit , 1996 # # 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 of the License, 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 to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="$SED -e s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi # The names of the tagged configurations supported by this script. available_tags= # ### BEGIN LIBTOOL CONFIG # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_compiler # Is the compiler the GNU C compiler? with_gcc=$GCC # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_predep_objects # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_postdep_objects # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # ### END LIBTOOL CONFIG __EOF__ case $host_os in aix3*) cat <<\EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi EOF ;; esac # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || \ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" # Check whether --with-tags or --without-tags was given. if test "${with_tags+set}" = set; then withval="$with_tags" tagnames="$withval" fi; if test -f "$ltmain" && test -n "$tagnames"; then if test ! -f "${ofile}"; then { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5 echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;} fi if test -z "$LTCC"; then eval "`$SHELL ${ofile} --config | grep '^LTCC='`" if test -z "$LTCC"; then { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5 echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;} else { echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5 echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;} fi fi # Extract list of available tagged configurations in $ofile. # Note that this assumes the entire list is on one line. available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for tagname in $tagnames; do IFS="$lt_save_ifs" # Check whether tagname contains only valid characters case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in "") ;; *) { { echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5 echo "$as_me: error: invalid tag name: $tagname" >&2;} { (exit 1); exit 1; }; } ;; esac if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null then { { echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5 echo "$as_me: error: tag name \"$tagname\" already exists" >&2;} { (exit 1); exit 1; }; } fi # Update the list of available tags. if test -n "$tagname"; then echo appending configuration tag \"$tagname\" to $ofile case $tagname in CXX) if test -n "$CXX" && test "X$CXX" != "Xno"; then ac_ext=cc ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu archive_cmds_need_lc_CXX=no allow_undefined_flag_CXX= always_export_symbols_CXX=no archive_expsym_cmds_CXX= export_dynamic_flag_spec_CXX= hardcode_direct_CXX=no hardcode_libdir_flag_spec_CXX= hardcode_libdir_flag_spec_ld_CXX= hardcode_libdir_separator_CXX= hardcode_minus_L_CXX=no hardcode_automatic_CXX=no module_cmds_CXX= module_expsym_cmds_CXX= link_all_deplibs_CXX=unknown old_archive_cmds_CXX=$old_archive_cmds no_undefined_flag_CXX= whole_archive_flag_spec_CXX= enable_shared_with_static_runtimes_CXX=no # Dependencies to place before and after the object being linked: predep_objects_CXX= postdep_objects_CXX= predeps_CXX= postdeps_CXX= compiler_lib_search_path_CXX= # Source file extension for C++ test sources. ac_ext=cc # Object file extension for compiled C++ test sources. objext=o objext_CXX=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *) { return(0); }\n' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC compiler_CXX=$CC cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` # We don't want -fno-exception wen compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' else lt_prog_compiler_no_builtin_flag_CXX= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration # Check whether --with-gnu-ld or --without-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then withval="$with_gnu_ld" test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi; ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. echo "$as_me:$LINENO: checking for ld used by $CC" >&5 echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6 case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then echo "$as_me:$LINENO: checking for GNU ld" >&5 echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 else echo "$as_me:$LINENO: checking for non-GNU ld" >&5 echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 fi if test "${lt_cv_path_LD+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 echo "${ECHO_T}$LD" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} { (exit 1); exit 1; }; } echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 if test "${lt_cv_prog_gnu_ld+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 &5 echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 with_gnu_ld=$lt_cv_prog_gnu_ld # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_CXX= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 ld_shlibs_CXX=yes case $host_os in aix3*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_CXX='' hardcode_direct_CXX=yes hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes if test "$GXX" = yes; then case $host_os in aix4.012|aix4.012.*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct_CXX=yes else # We have old collect2 hardcode_direct_CXX=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_CXX=yes hardcode_libdir_flag_spec_CXX='-L$libdir' hardcode_libdir_separator_CXX= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols_CXX=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_CXX='-berok' # Determine the default libpath from the value encoded in an empty executable. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_CXX="-z nodefs" archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_CXX=' ${wl}-bernotok' allow_undefined_flag_CXX=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) always_export_symbols_CXX=yes # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_CXX=' ' archive_cmds_need_lc_CXX=yes # This is similar to how AIX traditionally builds it's shared libraries. archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_CXX='-L$libdir' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=no enable_shared_with_static_runtimes_CXX=yes if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else ld_shlibs_CXX=no fi ;; darwin* | rhapsody*) if test "$GXX" = yes; then archive_cmds_need_lc_CXX=no case "$host_os" in rhapsody* | darwin1.[012]) allow_undefined_flag_CXX='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag_CXX='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag_CXX='-flat_namespace -undefined suppress' ;; 10.*) allow_undefined_flag_CXX='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else archive_cmds_CXX='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi module_cmds_CXX='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' hardcode_direct_CXX=no hardcode_automatic_CXX=yes hardcode_shlibpath_var_CXX=unsupported whole_archive_flag_spec_CXX='-all_load $convenience' link_all_deplibs_CXX=yes else ld_shlibs_CXX=no fi ;; dgux*) case $cc_basename in ec++) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; ghcx) # Green Hills C++ Compiler # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; freebsd12*) # C++ shared libraries reported to be fairly broken before switch to ELF ld_shlibs_CXX=no ;; freebsd-elf*) archive_cmds_need_lc_CXX=no ;; freebsd* | kfreebsd*-gnu) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions ld_shlibs_CXX=yes ;; gnu*) ;; hpux9*) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='${wl}-E' hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC) archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then case "$host_cpu" in hppa*64*) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld_CXX='+b $libdir' hardcode_libdir_separator_CXX=: ;; ia64*) hardcode_libdir_flag_spec_CXX='-L$libdir' ;; *) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='${wl}-E' ;; esac fi case "$host_cpu" in hppa*64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no ;; ia64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; *) hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC) case "$host_cpu" in hppa*64*|ia64*) archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' ;; *) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case "$host_cpu" in ia64*|hppa*64*) archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' ;; *) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; irix5* | irix6*) case $cc_basename in CC) # SGI C++ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' else archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' fi fi link_all_deplibs_CXX=yes ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: ;; linux*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc) # Intel C++ with_gnu_ld=yes archive_cmds_need_lc_CXX=no archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; cxx) # Compaq C++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; esac ;; lynxos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; m88k*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; mvs*) case $cc_basename in cxx) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; osf3*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; RCC) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx) allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; osf4* | osf5*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # the KAI C++ compiler. old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; RCC) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx) allow_undefined_flag_CXX=' -expect_unresolved \*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ $rm $lib.exp' hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; sco*) archive_cmds_need_lc_CXX=no case $cc_basename in CC) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; sunos4*) case $cc_basename in CC) # Sun C++ 4.x # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; lcc) # Lucid # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; solaris*) case $cc_basename in CC) # Sun C++ 4.2, 5.x and Centerline C++ no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_shlibpath_var_CXX=no case $host_os in solaris2.0-5 | solaris2.0-5.*) ;; *) # The C++ compiler is used as linker so we must use $wl # flag to pass the commands to the underlying system # linker. # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac link_all_deplibs_CXX=yes # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[LR]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; gcx) # Green Hills C++ Compiler archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then no_undefined_flag_CXX=' ${wl}-z ${wl}defs' if $CC --version | grep -v '^2\.7' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" fi hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' fi ;; esac ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) archive_cmds_need_lc_CXX=no ;; tandem*) case $cc_basename in NCC) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 echo "${ECHO_T}$ld_shlibs_CXX" >&6 test "$ld_shlibs_CXX" = no && can_build_shared=no GCC_CXX="$GXX" LD_CXX="$LD" cat > conftest.$ac_ext <&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no # The `*' in the case matches for architectures that use `case' in # $output_verbose_cmd can trigger glob expansion during the loop # eval without this substitution. output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`" for p in `eval $output_verbose_link_cmd`; do case $p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" \ || test $p = "-R"; then prev=$p continue else prev= fi if test "$pre_test_object_deps_done" = no; then case $p in -L* | -R*) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$compiler_lib_search_path_CXX"; then compiler_lib_search_path_CXX="${prev}${p}" else compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$postdeps_CXX"; then postdeps_CXX="${prev}${p}" else postdeps_CXX="${postdeps_CXX} ${prev}${p}" fi fi ;; *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$predep_objects_CXX"; then predep_objects_CXX="$p" else predep_objects_CXX="$predep_objects_CXX $p" fi else if test -z "$postdep_objects_CXX"; then postdep_objects_CXX="$p" else postdep_objects_CXX="$postdep_objects_CXX $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling CXX test program" fi $rm -f confest.$objext case " $postdeps_CXX " in *" -lc "*) archive_cmds_need_lc_CXX=no ;; esac lt_prog_compiler_wl_CXX= lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX= echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | os2* | pw32*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_CXX='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all lt_prog_compiler_pic_CXX= ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_CXX=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac else case $host_os in aix4* | aix5*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' else lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68) # Green Hills C++ Compiler # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; dgux*) case $cc_basename in ec++) lt_prog_compiler_pic_CXX='-KPIC' ;; ghcx) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; freebsd* | kfreebsd*-gnu) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" if test "$host_cpu" != ia64; then lt_prog_compiler_pic_CXX='+Z' fi ;; aCC) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_CXX='+Z' ;; esac ;; *) ;; esac ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux*) case $cc_basename in KCC) # KAI C++ Compiler lt_prog_compiler_wl_CXX='--backend -Wl,' lt_prog_compiler_pic_CXX='-fPIC' ;; icpc) # Intel C++ lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-static' ;; cxx) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx) lt_prog_compiler_pic_CXX='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; osf3* | osf4* | osf5*) case $cc_basename in KCC) lt_prog_compiler_wl_CXX='--backend -Wl,' ;; RCC) # Rational C++ 2.4.1 lt_prog_compiler_pic_CXX='-pic' ;; cxx) # Digital/Compaq C++ lt_prog_compiler_wl_CXX='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; psos*) ;; sco*) case $cc_basename in CC) lt_prog_compiler_pic_CXX='-fPIC' ;; *) ;; esac ;; solaris*) case $cc_basename in CC) # Sun C++ 4.2, 5.x and Centerline C++ lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; gcx) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC) # Sun C++ 4.x lt_prog_compiler_pic_CXX='-pic' lt_prog_compiler_static_CXX='-Bstatic' ;; lcc) # Lucid lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; tandem*) case $cc_basename in NCC) # NonStop-UX NCC 3.20 lt_prog_compiler_pic_CXX='-KPIC' ;; *) ;; esac ;; unixware*) ;; vxworks*) ;; *) lt_prog_compiler_can_build_shared_CXX=no ;; esac fi echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5 echo "${ECHO_T}$lt_prog_compiler_pic_CXX" >&6 # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_CXX"; then echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... $ECHO_C" >&6 if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_prog_compiler_pic_works_CXX=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:11063: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:11067: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_prog_compiler_pic_works_CXX=yes fi fi $rm conftest* fi echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_CXX" >&5 echo "${ECHO_T}$lt_prog_compiler_pic_works_CXX" >&6 if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then case $lt_prog_compiler_pic_CXX in "" | " "*) ;; *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; esac else lt_prog_compiler_pic_CXX= lt_prog_compiler_can_build_shared_CXX=no fi fi case "$host_os" in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_CXX= ;; *) lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" ;; esac echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_cv_prog_compiler_c_o_CXX=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:11123: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:11127: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s out/conftest.err; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5 echo "${ECHO_T}$lt_cv_prog_compiler_c_o_CXX" >&6 hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no echo "$as_me:$LINENO: result: $hard_links" >&5 echo "${ECHO_T}$hard_links" >&6 if test "$hard_links" = no; then { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix4* | aix5*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) export_symbols_cmds_CXX="$ltdll_cmds" ;; cygwin* | mingw*) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 echo "${ECHO_T}$ld_shlibs_CXX" >&6 test "$ld_shlibs_CXX" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_CXX" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_CXX=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_CXX in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_CXX compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_CXX allow_undefined_flag_CXX= if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } then archive_cmds_need_lc_CXX=no else archive_cmds_need_lc_CXX=yes fi allow_undefined_flag_CXX=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5 echo "${ECHO_T}$archive_cmds_need_lc_CXX" >&6 ;; esac fi ;; esac echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.01* | freebsdelf3.01*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case "$host_cpu" in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # find out which ABI we are using libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) echo '#line 11634 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then case `/usr/bin/file conftest.$ac_objext` in *64-bit*) libsuff=64 sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; esac fi rm -rf conftest* ;; esac # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; knetbsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos need_lib_prefix=no need_version=yes library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac echo "$as_me:$LINENO: result: $dynamic_linker" >&5 echo "${ECHO_T}$dynamic_linker" >&6 test "$dynamic_linker" = no && can_build_shared=no echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 hardcode_action_CXX= if test -n "$hardcode_libdir_flag_spec_CXX" || \ test -n "$runpath_var CXX" || \ test "X$hardcode_automatic_CXX"="Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct_CXX" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no && test "$hardcode_minus_L_CXX" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_CXX=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_CXX=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_CXX=unsupported fi echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5 echo "${ECHO_T}$hardcode_action_CXX" >&6 if test "$hardcode_action_CXX" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi striplib= old_striplib= echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi ;; *) echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 ;; esac fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 if test "${ac_cv_lib_dl_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); int main () { dlopen (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dl_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dl_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 if test $ac_cv_lib_dl_dlopen = yes; then lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) echo "$as_me:$LINENO: checking for shl_load" >&5 echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 if test "${ac_cv_func_shl_load+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define shl_load to an innocuous variant, in case declares shl_load. For example, HP-UX 11i declares gettimeofday. */ #define shl_load innocuous_shl_load /* System header to define __stub macros and hopefully few prototypes, which can conflict with char shl_load (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef shl_load /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_shl_load) || defined (__stub___shl_load) choke me #else char (*f) () = shl_load; #endif #ifdef __cplusplus } #endif int main () { return f != shl_load; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_shl_load=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_shl_load=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 echo "${ECHO_T}$ac_cv_func_shl_load" >&6 if test $ac_cv_func_shl_load = yes; then lt_cv_dlopen="shl_load" else echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 if test "${ac_cv_lib_dld_shl_load+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load (); int main () { shl_load (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dld_shl_load=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dld_shl_load=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 if test $ac_cv_lib_dld_shl_load = yes; then lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" else echo "$as_me:$LINENO: checking for dlopen" >&5 echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 if test "${ac_cv_func_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define dlopen to an innocuous variant, in case declares dlopen. For example, HP-UX 11i declares gettimeofday. */ #define dlopen innocuous_dlopen /* System header to define __stub macros and hopefully few prototypes, which can conflict with char dlopen (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef dlopen /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_dlopen) || defined (__stub___dlopen) choke me #else char (*f) () = dlopen; #endif #ifdef __cplusplus } #endif int main () { return f != dlopen; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 echo "${ECHO_T}$ac_cv_func_dlopen" >&6 if test $ac_cv_func_dlopen = yes; then lt_cv_dlopen="dlopen" else echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 if test "${ac_cv_lib_dl_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); int main () { dlopen (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dl_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dl_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 if test $ac_cv_lib_dl_dlopen = yes; then lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 if test "${ac_cv_lib_svld_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); int main () { dlopen (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_svld_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_svld_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 if test $ac_cv_lib_svld_dlopen = yes; then lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6 if test "${ac_cv_lib_dld_dld_link+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dld_link (); int main () { dld_link (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dld_dld_link=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dld_dld_link=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6 if test $ac_cv_lib_dld_dld_link = yes; then lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 if test "${lt_cv_dlopen_self+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 echo "${ECHO_T}$lt_cv_dlopen_self" >&6 if test "x$lt_cv_dlopen_self" = xyes; then LDFLAGS="$LDFLAGS $link_static_flag" echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 if test "${lt_cv_dlopen_self_static+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \ SED SHELL STRIP \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_CXX \ CC_CXX \ LD_CXX \ lt_prog_compiler_wl_CXX \ lt_prog_compiler_pic_CXX \ lt_prog_compiler_static_CXX \ lt_prog_compiler_no_builtin_flag_CXX \ export_dynamic_flag_spec_CXX \ thread_safe_flag_spec_CXX \ whole_archive_flag_spec_CXX \ enable_shared_with_static_runtimes_CXX \ old_archive_cmds_CXX \ old_archive_from_new_cmds_CXX \ predep_objects_CXX \ postdep_objects_CXX \ predeps_CXX \ postdeps_CXX \ compiler_lib_search_path_CXX \ archive_cmds_CXX \ archive_expsym_cmds_CXX \ postinstall_cmds_CXX \ postuninstall_cmds_CXX \ old_archive_from_expsyms_cmds_CXX \ allow_undefined_flag_CXX \ no_undefined_flag_CXX \ export_symbols_cmds_CXX \ hardcode_libdir_flag_spec_CXX \ hardcode_libdir_flag_spec_ld_CXX \ hardcode_libdir_separator_CXX \ hardcode_automatic_CXX \ module_cmds_CXX \ module_expsym_cmds_CXX \ lt_cv_prog_compiler_c_o_CXX \ exclude_expsyms_CXX \ include_expsyms_CXX; do case $var in old_archive_cmds_CXX | \ old_archive_from_new_cmds_CXX | \ archive_cmds_CXX | \ archive_expsym_cmds_CXX | \ module_cmds_CXX | \ module_expsym_cmds_CXX | \ old_archive_from_expsyms_cmds_CXX | \ export_symbols_cmds_CXX | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_CXX # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_compiler_CXX # Is the compiler the GNU C compiler? with_gcc=$GCC_CXX # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_CXX # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_CXX # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_CXX pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_CXX # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_CXX old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_CXX archive_expsym_cmds=$lt_archive_expsym_cmds_CXX postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_CXX module_expsym_cmds=$lt_module_expsym_cmds_CXX # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_predep_objects_CXX # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_postdep_objects_CXX # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_CXX # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_CXX # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_CXX # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_CXX # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_CXX # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_CXX # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_CXX # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_CXX # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_CXX # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_CXX # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_CXX" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_CXX # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_CXX # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_CXX # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_CXX # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ldcxx=$with_gnu_ld with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld else tagname="" fi ;; F77) if test -n "$F77" && test "X$F77" != "Xno"; then ac_ext=f ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_f77_compiler_gnu archive_cmds_need_lc_F77=no allow_undefined_flag_F77= always_export_symbols_F77=no archive_expsym_cmds_F77= export_dynamic_flag_spec_F77= hardcode_direct_F77=no hardcode_libdir_flag_spec_F77= hardcode_libdir_flag_spec_ld_F77= hardcode_libdir_separator_F77= hardcode_minus_L_F77=no hardcode_automatic_F77=no module_cmds_F77= module_expsym_cmds_F77= link_all_deplibs_F77=unknown old_archive_cmds_F77=$old_archive_cmds no_undefined_flag_F77= whole_archive_flag_spec_F77= enable_shared_with_static_runtimes_F77=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o objext_F77=$objext # Code to be used in simple compile tests lt_simple_compile_test_code=" subroutine t\n return\n end\n" # Code to be used in simple link tests lt_simple_link_test_code=" program t\n end\n" # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # Allow CC to be a program name with arguments. lt_save_CC="$CC" CC=${F77-"f77"} compiler=$CC compiler_F77=$CC cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $can_build_shared" >&5 echo "${ECHO_T}$can_build_shared" >&6 echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6 test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case "$host_os" in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4* | aix5*) test "$enable_shared" = yes && enable_static=no ;; esac echo "$as_me:$LINENO: result: $enable_shared" >&5 echo "${ECHO_T}$enable_shared" >&6 echo "$as_me:$LINENO: checking whether to build static libraries" >&5 echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6 # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes echo "$as_me:$LINENO: result: $enable_static" >&5 echo "${ECHO_T}$enable_static" >&6 test "$ld_shlibs_F77" = no && can_build_shared=no GCC_F77="$G77" LD_F77="$LD" lt_prog_compiler_wl_F77= lt_prog_compiler_pic_F77= lt_prog_compiler_static_F77= echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 if test "$GCC" = yes; then lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_static_F77='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_F77='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_F77='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_F77='-fno-common' ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared_F77=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_F77=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_F77='-fPIC' ;; esac ;; *) lt_prog_compiler_pic_F77='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl_F77='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_F77='-Bstatic' else lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_F77='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl_F77='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_F77='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static_F77='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl_F77='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static_F77='-non_shared' ;; newsos6) lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-Bstatic' ;; linux*) case $CC in icc* | ecc*) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-static' ;; ccc*) lt_prog_compiler_wl_F77='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static_F77='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl_F77='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static_F77='-non_shared' ;; sco3.2v5*) lt_prog_compiler_pic_F77='-Kpic' lt_prog_compiler_static_F77='-dn' ;; solaris*) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-Bstatic' ;; sunos4*) lt_prog_compiler_wl_F77='-Qoption ld ' lt_prog_compiler_pic_F77='-PIC' lt_prog_compiler_static_F77='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic_F77='-Kconform_pic' lt_prog_compiler_static_F77='-Bstatic' fi ;; uts4*) lt_prog_compiler_pic_F77='-pic' lt_prog_compiler_static_F77='-Bstatic' ;; *) lt_prog_compiler_can_build_shared_F77=no ;; esac fi echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5 echo "${ECHO_T}$lt_prog_compiler_pic_F77" >&6 # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_F77"; then echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5 echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... $ECHO_C" >&6 if test "${lt_prog_compiler_pic_works_F77+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_prog_compiler_pic_works_F77=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_F77" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:13430: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:13434: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_prog_compiler_pic_works_F77=yes fi fi $rm conftest* fi echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_F77" >&5 echo "${ECHO_T}$lt_prog_compiler_pic_works_F77" >&6 if test x"$lt_prog_compiler_pic_works_F77" = xyes; then case $lt_prog_compiler_pic_F77 in "" | " "*) ;; *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;; esac else lt_prog_compiler_pic_F77= lt_prog_compiler_can_build_shared_F77=no fi fi case "$host_os" in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_F77= ;; *) lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77" ;; esac echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_cv_prog_compiler_c_o_F77=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:13490: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:13494: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s out/conftest.err; then lt_cv_prog_compiler_c_o_F77=yes fi fi chmod u+w . $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5 echo "${ECHO_T}$lt_cv_prog_compiler_c_o_F77" >&6 hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no echo "$as_me:$LINENO: result: $hard_links" >&5 echo "${ECHO_T}$hard_links" >&6 if test "$hard_links" = no; then { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 runpath_var= allow_undefined_flag_F77= enable_shared_with_static_runtimes_F77=no archive_cmds_F77= archive_expsym_cmds_F77= old_archive_From_new_cmds_F77= old_archive_from_expsyms_cmds_F77= export_dynamic_flag_spec_F77= whole_archive_flag_spec_F77= thread_safe_flag_spec_F77= hardcode_libdir_flag_spec_F77= hardcode_libdir_flag_spec_ld_F77= hardcode_libdir_separator_F77= hardcode_direct_F77=no hardcode_minus_L_F77=no hardcode_shlibpath_var_F77=unsupported link_all_deplibs_F77=unknown hardcode_automatic_F77=no module_cmds_F77= module_expsym_cmds_F77= always_export_symbols_F77=no export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms_F77= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs_F77=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs_F77=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_minus_L_F77=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. ld_shlibs_F77=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_F77=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_F77=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_F77='-L$libdir' allow_undefined_flag_F77=unsupported always_export_symbols_F77=no enable_shared_with_static_runtimes_F77=yes export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris* | sysv5*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs_F77=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_F77=no fi ;; sunos4*) archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_cmds_F77="$tmp_archive_cmds" supports_anon_versioning=no case `$LD -v 2>/dev/null` in *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac if test $supports_anon_versioning = yes; then archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ $echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' else archive_expsym_cmds_F77="$tmp_archive_cmds" fi else ld_shlibs_F77=no fi ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_F77=no fi ;; esac if test "$ld_shlibs_F77" = yes; then runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_F77='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_F77= fi fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag_F77=unsupported always_export_symbols_F77=yes archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L_F77=yes if test "$GCC" = yes && test -z "$link_static_flag"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct_F77=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_F77='' hardcode_direct_F77=yes hardcode_libdir_separator_F77=':' link_all_deplibs_F77=yes if test "$GCC" = yes; then case $host_os in aix4.012|aix4.012.*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct_F77=yes else # We have old collect2 hardcode_direct_F77=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_F77=yes hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_libdir_separator_F77= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols_F77=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_F77='-berok' # Determine the default libpath from the value encoded in an empty executable. cat >conftest.$ac_ext <<_ACEOF program main end _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_F77="-z nodefs" archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat >conftest.$ac_ext <<_ACEOF program main end _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_F77=' ${wl}-bernotok' allow_undefined_flag_F77=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) always_export_symbols_F77=yes # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_F77=' ' archive_cmds_need_lc_F77=yes # This is similar to how AIX traditionally builds it's shared libraries. archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_minus_L_F77=yes # see comment about different semantics on the GNU ld section ld_shlibs_F77=no ;; bsdi4*) export_dynamic_flag_spec_F77=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_F77=' ' allow_undefined_flag_F77=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_From_new_cmds_F77='true' # FIXME: Should let the user specify the lib program. old_archive_cmds_F77='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes_F77=yes ;; darwin* | rhapsody*) if test "$GXX" = yes ; then archive_cmds_need_lc_F77=no case "$host_os" in rhapsody* | darwin1.[012]) allow_undefined_flag_F77='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag_F77='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag_F77='-flat_namespace -undefined suppress' ;; 10.*) allow_undefined_flag_F77='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_cmds_F77='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else archive_cmds_F77='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi module_cmds_F77='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' hardcode_direct_F77=no hardcode_automatic_F77=yes hardcode_shlibpath_var_F77=unsupported whole_archive_flag_spec_F77='-all_load $convenience' link_all_deplibs_F77=yes else ld_shlibs_F77=no fi ;; dgux*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_shlibpath_var_F77=no ;; freebsd1*) ld_shlibs_F77=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes hardcode_minus_L_F77=yes hardcode_shlibpath_var_F77=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu) archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' hardcode_libdir_separator_F77=: hardcode_direct_F77=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_F77=yes export_dynamic_flag_spec_F77='${wl}-E' ;; hpux10* | hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*|ia64*) archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case "$host_cpu" in hppa*64*|ia64*) archive_cmds_F77='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' ;; *) archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; esac fi if test "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*) hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld_F77='+b $libdir' hardcode_libdir_separator_F77=: hardcode_direct_F77=no hardcode_shlibpath_var_F77=no ;; ia64*) hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_direct_F77=no hardcode_shlibpath_var_F77=no # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_F77=yes ;; *) hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' hardcode_libdir_separator_F77=: hardcode_direct_F77=yes export_dynamic_flag_spec_F77='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_F77=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_ld_F77='-rpath $libdir' fi hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_F77=: link_all_deplibs_F77=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; newsos6) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_F77=: hardcode_shlibpath_var_F77=no ;; openbsd*) hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' export_dynamic_flag_spec_F77='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_F77='-R$libdir' ;; *) archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_minus_L_F77=yes allow_undefined_flag_F77=unsupported archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag_F77=' -expect_unresolved \*' archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_F77=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' else allow_undefined_flag_F77=' -expect_unresolved \*' archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec_F77='-rpath $libdir' fi hardcode_libdir_separator_F77=: ;; sco3.2v5*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_F77=no export_dynamic_flag_spec_F77='${wl}-Bexport' runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ;; solaris*) no_undefined_flag_F77=' -z text' if test "$GCC" = yes; then archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_shlibpath_var_F77=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs_F77=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_direct_F77=yes hardcode_minus_L_F77=yes hardcode_shlibpath_var_F77=no ;; sysv4) case $host_vendor in sni) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds_F77='$CC -r -o $output$reload_objs' hardcode_direct_F77=no ;; motorola) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var_F77=no ;; sysv4.3*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_F77=no export_dynamic_flag_spec_F77='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_F77=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs_F77=yes fi ;; sysv4.2uw2*) archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes hardcode_minus_L_F77=no hardcode_shlibpath_var_F77=no hardcode_runpath_var=yes runpath_var=LD_RUN_PATH ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) no_undefined_flag_F77='${wl}-z ${wl}text' if test "$GCC" = yes; then archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_F77='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' fi runpath_var='LD_RUN_PATH' hardcode_shlibpath_var_F77=no ;; sysv5*) no_undefined_flag_F77=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' hardcode_libdir_flag_spec_F77= hardcode_shlibpath_var_F77=no runpath_var='LD_RUN_PATH' ;; uts4*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_shlibpath_var_F77=no ;; *) ld_shlibs_F77=no ;; esac fi echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5 echo "${ECHO_T}$ld_shlibs_F77" >&6 test "$ld_shlibs_F77" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_F77" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_F77=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_F77 in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_F77 compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_F77 allow_undefined_flag_F77= if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } then archive_cmds_need_lc_F77=no else archive_cmds_need_lc_F77=yes fi allow_undefined_flag_F77=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5 echo "${ECHO_T}$archive_cmds_need_lc_F77" >&6 ;; esac fi ;; esac echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.01* | freebsdelf3.01*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case "$host_cpu" in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # find out which ABI we are using libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) echo '#line 14804 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then case `/usr/bin/file conftest.$ac_objext` in *64-bit*) libsuff=64 sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; esac fi rm -rf conftest* ;; esac # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; knetbsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos need_lib_prefix=no need_version=yes library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac echo "$as_me:$LINENO: result: $dynamic_linker" >&5 echo "${ECHO_T}$dynamic_linker" >&6 test "$dynamic_linker" = no && can_build_shared=no echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 hardcode_action_F77= if test -n "$hardcode_libdir_flag_spec_F77" || \ test -n "$runpath_var F77" || \ test "X$hardcode_automatic_F77"="Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct_F77" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no && test "$hardcode_minus_L_F77" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_F77=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_F77=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_F77=unsupported fi echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5 echo "${ECHO_T}$hardcode_action_F77" >&6 if test "$hardcode_action_F77" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi striplib= old_striplib= echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi ;; *) echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 ;; esac fi # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \ SED SHELL STRIP \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_F77 \ CC_F77 \ LD_F77 \ lt_prog_compiler_wl_F77 \ lt_prog_compiler_pic_F77 \ lt_prog_compiler_static_F77 \ lt_prog_compiler_no_builtin_flag_F77 \ export_dynamic_flag_spec_F77 \ thread_safe_flag_spec_F77 \ whole_archive_flag_spec_F77 \ enable_shared_with_static_runtimes_F77 \ old_archive_cmds_F77 \ old_archive_from_new_cmds_F77 \ predep_objects_F77 \ postdep_objects_F77 \ predeps_F77 \ postdeps_F77 \ compiler_lib_search_path_F77 \ archive_cmds_F77 \ archive_expsym_cmds_F77 \ postinstall_cmds_F77 \ postuninstall_cmds_F77 \ old_archive_from_expsyms_cmds_F77 \ allow_undefined_flag_F77 \ no_undefined_flag_F77 \ export_symbols_cmds_F77 \ hardcode_libdir_flag_spec_F77 \ hardcode_libdir_flag_spec_ld_F77 \ hardcode_libdir_separator_F77 \ hardcode_automatic_F77 \ module_cmds_F77 \ module_expsym_cmds_F77 \ lt_cv_prog_compiler_c_o_F77 \ exclude_expsyms_F77 \ include_expsyms_F77; do case $var in old_archive_cmds_F77 | \ old_archive_from_new_cmds_F77 | \ archive_cmds_F77 | \ archive_expsym_cmds_F77 | \ module_cmds_F77 | \ module_expsym_cmds_F77 | \ old_archive_from_expsyms_cmds_F77 | \ export_symbols_cmds_F77 | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_F77 # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77 # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_compiler_F77 # Is the compiler the GNU C compiler? with_gcc=$GCC_F77 # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_F77 # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_F77 # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_F77 pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77 # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_F77 # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77 # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77 # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77 # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77 # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_F77 old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77 # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77 # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_F77 archive_expsym_cmds=$lt_archive_expsym_cmds_F77 postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_F77 module_expsym_cmds=$lt_module_expsym_cmds_F77 # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_predep_objects_F77 # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_postdep_objects_F77 # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_F77 # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_F77 # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_F77 # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_F77 # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_F77 # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_F77 # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77 # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77 # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77 # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_F77 # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_F77 # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_F77 # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_F77 # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_F77 # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_F77" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_F77 # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_F77 # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_F77 # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_F77 # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" else tagname="" fi ;; GCJ) if test -n "$GCJ" && test "X$GCJ" != "Xno"; then # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o objext_GCJ=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}\n" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String argv) {}; }\n' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # Allow CC to be a program name with arguments. lt_save_CC="$CC" CC=${GCJ-"gcj"} compiler=$CC compiler_GCJ=$CC # GCJ did not exist at the time GCC didn't implicitly link libc in. archive_cmds_need_lc_GCJ=no lt_prog_compiler_no_builtin_flag_GCJ= if test "$GCC" = yes; then lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin' echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:15545: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:15549: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $rm conftest* fi echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6 if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl_GCJ= lt_prog_compiler_pic_GCJ= lt_prog_compiler_static_GCJ= echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 if test "$GCC" = yes; then lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_static_GCJ='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_GCJ='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_GCJ='-fno-common' ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared_GCJ=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_GCJ=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_GCJ='-fPIC' ;; esac ;; *) lt_prog_compiler_pic_GCJ='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl_GCJ='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_GCJ='-Bstatic' else lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl_GCJ='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_GCJ='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl_GCJ='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static_GCJ='-non_shared' ;; newsos6) lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; linux*) case $CC in icc* | ecc*) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-static' ;; ccc*) lt_prog_compiler_wl_GCJ='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static_GCJ='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl_GCJ='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static_GCJ='-non_shared' ;; sco3.2v5*) lt_prog_compiler_pic_GCJ='-Kpic' lt_prog_compiler_static_GCJ='-dn' ;; solaris*) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; sunos4*) lt_prog_compiler_wl_GCJ='-Qoption ld ' lt_prog_compiler_pic_GCJ='-PIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic_GCJ='-Kconform_pic' lt_prog_compiler_static_GCJ='-Bstatic' fi ;; uts4*) lt_prog_compiler_pic_GCJ='-pic' lt_prog_compiler_static_GCJ='-Bstatic' ;; *) lt_prog_compiler_can_build_shared_GCJ=no ;; esac fi echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5 echo "${ECHO_T}$lt_prog_compiler_pic_GCJ" >&6 # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_GCJ"; then echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5 echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... $ECHO_C" >&6 if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_prog_compiler_pic_works_GCJ=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_GCJ" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:15778: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:15782: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_prog_compiler_pic_works_GCJ=yes fi fi $rm conftest* fi echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_GCJ" >&5 echo "${ECHO_T}$lt_prog_compiler_pic_works_GCJ" >&6 if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then case $lt_prog_compiler_pic_GCJ in "" | " "*) ;; *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;; esac else lt_prog_compiler_pic_GCJ= lt_prog_compiler_can_build_shared_GCJ=no fi fi case "$host_os" in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_GCJ= ;; *) lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ" ;; esac echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else lt_cv_prog_compiler_c_o_GCJ=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:15838: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:15842: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s out/conftest.err; then lt_cv_prog_compiler_c_o_GCJ=yes fi fi chmod u+w . $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5 echo "${ECHO_T}$lt_cv_prog_compiler_c_o_GCJ" >&6 hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no echo "$as_me:$LINENO: result: $hard_links" >&5 echo "${ECHO_T}$hard_links" >&6 if test "$hard_links" = no; then { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 runpath_var= allow_undefined_flag_GCJ= enable_shared_with_static_runtimes_GCJ=no archive_cmds_GCJ= archive_expsym_cmds_GCJ= old_archive_From_new_cmds_GCJ= old_archive_from_expsyms_cmds_GCJ= export_dynamic_flag_spec_GCJ= whole_archive_flag_spec_GCJ= thread_safe_flag_spec_GCJ= hardcode_libdir_flag_spec_GCJ= hardcode_libdir_flag_spec_ld_GCJ= hardcode_libdir_separator_GCJ= hardcode_direct_GCJ=no hardcode_minus_L_GCJ=no hardcode_shlibpath_var_GCJ=unsupported link_all_deplibs_GCJ=unknown hardcode_automatic_GCJ=no module_cmds_GCJ= module_expsym_cmds_GCJ= always_export_symbols_GCJ=no export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms_GCJ= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs_GCJ=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs_GCJ=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_minus_L_GCJ=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. ld_shlibs_GCJ=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_GCJ=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_GCJ=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_GCJ='-L$libdir' allow_undefined_flag_GCJ=unsupported always_export_symbols_GCJ=no enable_shared_with_static_runtimes_GCJ=yes export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris* | sysv5*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs_GCJ=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_GCJ=no fi ;; sunos4*) archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then tmp_archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_cmds_GCJ="$tmp_archive_cmds" supports_anon_versioning=no case `$LD -v 2>/dev/null` in *\ 01.* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac if test $supports_anon_versioning = yes; then archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ $echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' else archive_expsym_cmds_GCJ="$tmp_archive_cmds" fi else ld_shlibs_GCJ=no fi ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_GCJ=no fi ;; esac if test "$ld_shlibs_GCJ" = yes; then runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_GCJ='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_GCJ= fi fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag_GCJ=unsupported always_export_symbols_GCJ=yes archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L_GCJ=yes if test "$GCC" = yes && test -z "$link_static_flag"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct_GCJ=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_GCJ='' hardcode_direct_GCJ=yes hardcode_libdir_separator_GCJ=':' link_all_deplibs_GCJ=yes if test "$GCC" = yes; then case $host_os in aix4.012|aix4.012.*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct_GCJ=yes else # We have old collect2 hardcode_direct_GCJ=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_GCJ=yes hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_libdir_separator_GCJ= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols_GCJ=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_GCJ='-berok' # Determine the default libpath from the value encoded in an empty executable. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_GCJ="-z nodefs" archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_GCJ=' ${wl}-bernotok' allow_undefined_flag_GCJ=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) always_export_symbols_GCJ=yes # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_GCJ=' ' archive_cmds_need_lc_GCJ=yes # This is similar to how AIX traditionally builds it's shared libraries. archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_minus_L_GCJ=yes # see comment about different semantics on the GNU ld section ld_shlibs_GCJ=no ;; bsdi4*) export_dynamic_flag_spec_GCJ=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_GCJ=' ' allow_undefined_flag_GCJ=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_From_new_cmds_GCJ='true' # FIXME: Should let the user specify the lib program. old_archive_cmds_GCJ='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes_GCJ=yes ;; darwin* | rhapsody*) if test "$GXX" = yes ; then archive_cmds_need_lc_GCJ=no case "$host_os" in rhapsody* | darwin1.[012]) allow_undefined_flag_GCJ='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag_GCJ='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag_GCJ='-flat_namespace -undefined suppress' ;; 10.*) allow_undefined_flag_GCJ='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_cmds_GCJ='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else archive_cmds_GCJ='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi module_cmds_GCJ='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' hardcode_direct_GCJ=no hardcode_automatic_GCJ=yes hardcode_shlibpath_var_GCJ=unsupported whole_archive_flag_spec_GCJ='-all_load $convenience' link_all_deplibs_GCJ=yes else ld_shlibs_GCJ=no fi ;; dgux*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_shlibpath_var_GCJ=no ;; freebsd1*) ld_shlibs_GCJ=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes hardcode_minus_L_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu) archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' hardcode_libdir_separator_GCJ=: hardcode_direct_GCJ=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_GCJ=yes export_dynamic_flag_spec_GCJ='${wl}-E' ;; hpux10* | hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*|ia64*) archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case "$host_cpu" in hppa*64*|ia64*) archive_cmds_GCJ='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' ;; *) archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; esac fi if test "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*) hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld_GCJ='+b $libdir' hardcode_libdir_separator_GCJ=: hardcode_direct_GCJ=no hardcode_shlibpath_var_GCJ=no ;; ia64*) hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_direct_GCJ=no hardcode_shlibpath_var_GCJ=no # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_GCJ=yes ;; *) hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' hardcode_libdir_separator_GCJ=: hardcode_direct_GCJ=yes export_dynamic_flag_spec_GCJ='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_GCJ=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir' fi hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_GCJ=: link_all_deplibs_GCJ=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; newsos6) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_GCJ=: hardcode_shlibpath_var_GCJ=no ;; openbsd*) hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' export_dynamic_flag_spec_GCJ='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_GCJ='-R$libdir' ;; *) archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_minus_L_GCJ=yes allow_undefined_flag_GCJ=unsupported archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag_GCJ=' -expect_unresolved \*' archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_GCJ=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' else allow_undefined_flag_GCJ=' -expect_unresolved \*' archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec_GCJ='-rpath $libdir' fi hardcode_libdir_separator_GCJ=: ;; sco3.2v5*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_GCJ=no export_dynamic_flag_spec_GCJ='${wl}-Bexport' runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ;; solaris*) no_undefined_flag_GCJ=' -z text' if test "$GCC" = yes; then archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_shlibpath_var_GCJ=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs_GCJ=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_direct_GCJ=yes hardcode_minus_L_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; sysv4) case $host_vendor in sni) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds_GCJ='$CC -r -o $output$reload_objs' hardcode_direct_GCJ=no ;; motorola) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var_GCJ=no ;; sysv4.3*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_GCJ=no export_dynamic_flag_spec_GCJ='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_GCJ=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs_GCJ=yes fi ;; sysv4.2uw2*) archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes hardcode_minus_L_GCJ=no hardcode_shlibpath_var_GCJ=no hardcode_runpath_var=yes runpath_var=LD_RUN_PATH ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) no_undefined_flag_GCJ='${wl}-z ${wl}text' if test "$GCC" = yes; then archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_GCJ='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' fi runpath_var='LD_RUN_PATH' hardcode_shlibpath_var_GCJ=no ;; sysv5*) no_undefined_flag_GCJ=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' hardcode_libdir_flag_spec_GCJ= hardcode_shlibpath_var_GCJ=no runpath_var='LD_RUN_PATH' ;; uts4*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_shlibpath_var_GCJ=no ;; *) ld_shlibs_GCJ=no ;; esac fi echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5 echo "${ECHO_T}$ld_shlibs_GCJ" >&6 test "$ld_shlibs_GCJ" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_GCJ" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_GCJ=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_GCJ in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_GCJ compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ allow_undefined_flag_GCJ= if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } then archive_cmds_need_lc_GCJ=no else archive_cmds_need_lc_GCJ=yes fi allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5 echo "${ECHO_T}$archive_cmds_need_lc_GCJ" >&6 ;; esac fi ;; esac echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='$(test .$module = .yes && echo .so || echo .dylib)' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.01* | freebsdelf3.01*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case "$host_cpu" in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # find out which ABI we are using libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) echo '#line 17172 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then case `/usr/bin/file conftest.$ac_objext` in *64-bit*) libsuff=64 sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; esac fi rm -rf conftest* ;; esac # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`$SED -e 's/:,\t/ /g;s/=^=*$//;s/=^= * / /g' /etc/ld.so.conf | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; knetbsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos need_lib_prefix=no need_version=yes library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac echo "$as_me:$LINENO: result: $dynamic_linker" >&5 echo "${ECHO_T}$dynamic_linker" >&6 test "$dynamic_linker" = no && can_build_shared=no echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 hardcode_action_GCJ= if test -n "$hardcode_libdir_flag_spec_GCJ" || \ test -n "$runpath_var GCJ" || \ test "X$hardcode_automatic_GCJ"="Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct_GCJ" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no && test "$hardcode_minus_L_GCJ" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_GCJ=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_GCJ=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_GCJ=unsupported fi echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5 echo "${ECHO_T}$hardcode_action_GCJ" >&6 if test "$hardcode_action_GCJ" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi striplib= old_striplib= echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi ;; *) echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 ;; esac fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 if test "${ac_cv_lib_dl_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); int main () { dlopen (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dl_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dl_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 if test $ac_cv_lib_dl_dlopen = yes; then lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) echo "$as_me:$LINENO: checking for shl_load" >&5 echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 if test "${ac_cv_func_shl_load+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define shl_load to an innocuous variant, in case declares shl_load. For example, HP-UX 11i declares gettimeofday. */ #define shl_load innocuous_shl_load /* System header to define __stub macros and hopefully few prototypes, which can conflict with char shl_load (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef shl_load /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_shl_load) || defined (__stub___shl_load) choke me #else char (*f) () = shl_load; #endif #ifdef __cplusplus } #endif int main () { return f != shl_load; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_shl_load=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_shl_load=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 echo "${ECHO_T}$ac_cv_func_shl_load" >&6 if test $ac_cv_func_shl_load = yes; then lt_cv_dlopen="shl_load" else echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 if test "${ac_cv_lib_dld_shl_load+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load (); int main () { shl_load (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dld_shl_load=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dld_shl_load=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 if test $ac_cv_lib_dld_shl_load = yes; then lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" else echo "$as_me:$LINENO: checking for dlopen" >&5 echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 if test "${ac_cv_func_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define dlopen to an innocuous variant, in case declares dlopen. For example, HP-UX 11i declares gettimeofday. */ #define dlopen innocuous_dlopen /* System header to define __stub macros and hopefully few prototypes, which can conflict with char dlopen (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef dlopen /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_dlopen) || defined (__stub___dlopen) choke me #else char (*f) () = dlopen; #endif #ifdef __cplusplus } #endif int main () { return f != dlopen; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 echo "${ECHO_T}$ac_cv_func_dlopen" >&6 if test $ac_cv_func_dlopen = yes; then lt_cv_dlopen="dlopen" else echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 if test "${ac_cv_lib_dl_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); int main () { dlopen (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dl_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dl_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 if test $ac_cv_lib_dl_dlopen = yes; then lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 if test "${ac_cv_lib_svld_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); int main () { dlopen (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_svld_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_svld_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 if test $ac_cv_lib_svld_dlopen = yes; then lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6 if test "${ac_cv_lib_dld_dld_link+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dld_link (); int main () { dld_link (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dld_dld_link=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dld_dld_link=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6 if test $ac_cv_lib_dld_dld_link = yes; then lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 if test "${lt_cv_dlopen_self+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 echo "${ECHO_T}$lt_cv_dlopen_self" >&6 if test "x$lt_cv_dlopen_self" = xyes; then LDFLAGS="$LDFLAGS $link_static_flag" echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 if test "${lt_cv_dlopen_self_static+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \ SED SHELL STRIP \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_GCJ \ CC_GCJ \ LD_GCJ \ lt_prog_compiler_wl_GCJ \ lt_prog_compiler_pic_GCJ \ lt_prog_compiler_static_GCJ \ lt_prog_compiler_no_builtin_flag_GCJ \ export_dynamic_flag_spec_GCJ \ thread_safe_flag_spec_GCJ \ whole_archive_flag_spec_GCJ \ enable_shared_with_static_runtimes_GCJ \ old_archive_cmds_GCJ \ old_archive_from_new_cmds_GCJ \ predep_objects_GCJ \ postdep_objects_GCJ \ predeps_GCJ \ postdeps_GCJ \ compiler_lib_search_path_GCJ \ archive_cmds_GCJ \ archive_expsym_cmds_GCJ \ postinstall_cmds_GCJ \ postuninstall_cmds_GCJ \ old_archive_from_expsyms_cmds_GCJ \ allow_undefined_flag_GCJ \ no_undefined_flag_GCJ \ export_symbols_cmds_GCJ \ hardcode_libdir_flag_spec_GCJ \ hardcode_libdir_flag_spec_ld_GCJ \ hardcode_libdir_separator_GCJ \ hardcode_automatic_GCJ \ module_cmds_GCJ \ module_expsym_cmds_GCJ \ lt_cv_prog_compiler_c_o_GCJ \ exclude_expsyms_GCJ \ include_expsyms_GCJ; do case $var in old_archive_cmds_GCJ | \ old_archive_from_new_cmds_GCJ | \ archive_cmds_GCJ | \ archive_expsym_cmds_GCJ | \ module_cmds_GCJ | \ module_expsym_cmds_GCJ | \ old_archive_from_expsyms_cmds_GCJ | \ export_symbols_cmds_GCJ | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_GCJ # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_compiler_GCJ # Is the compiler the GNU C compiler? with_gcc=$GCC_GCJ # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_GCJ # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_GCJ # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_GCJ pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_GCJ # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_GCJ old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_GCJ archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_GCJ module_expsym_cmds=$lt_module_expsym_cmds_GCJ # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_predep_objects_GCJ # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_postdep_objects_GCJ # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_GCJ # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_GCJ # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_GCJ # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_GCJ # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_GCJ # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_GCJ # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_GCJ # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_GCJ # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_GCJ # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_GCJ" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_GCJ # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_GCJ # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_GCJ # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_GCJ # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" else tagname="" fi ;; RC) # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o objext_RC=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # Allow CC to be a program name with arguments. lt_save_CC="$CC" CC=${RC-"windres"} compiler=$CC compiler_RC=$CC lt_cv_prog_compiler_c_o_RC=yes # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM \ SED SHELL STRIP \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_RC \ CC_RC \ LD_RC \ lt_prog_compiler_wl_RC \ lt_prog_compiler_pic_RC \ lt_prog_compiler_static_RC \ lt_prog_compiler_no_builtin_flag_RC \ export_dynamic_flag_spec_RC \ thread_safe_flag_spec_RC \ whole_archive_flag_spec_RC \ enable_shared_with_static_runtimes_RC \ old_archive_cmds_RC \ old_archive_from_new_cmds_RC \ predep_objects_RC \ postdep_objects_RC \ predeps_RC \ postdeps_RC \ compiler_lib_search_path_RC \ archive_cmds_RC \ archive_expsym_cmds_RC \ postinstall_cmds_RC \ postuninstall_cmds_RC \ old_archive_from_expsyms_cmds_RC \ allow_undefined_flag_RC \ no_undefined_flag_RC \ export_symbols_cmds_RC \ hardcode_libdir_flag_spec_RC \ hardcode_libdir_flag_spec_ld_RC \ hardcode_libdir_separator_RC \ hardcode_automatic_RC \ module_cmds_RC \ module_expsym_cmds_RC \ lt_cv_prog_compiler_c_o_RC \ exclude_expsyms_RC \ include_expsyms_RC; do case $var in old_archive_cmds_RC | \ old_archive_from_new_cmds_RC | \ archive_cmds_RC | \ archive_expsym_cmds_RC | \ module_cmds_RC | \ module_expsym_cmds_RC | \ old_archive_from_expsyms_cmds_RC | \ export_symbols_cmds_RC | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_RC # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_compiler_RC # Is the compiler the GNU C compiler? with_gcc=$GCC_RC # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_RC # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_RC # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_RC pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_RC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_RC old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_RC archive_expsym_cmds=$lt_archive_expsym_cmds_RC postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_RC module_expsym_cmds=$lt_module_expsym_cmds_RC # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_predep_objects_RC # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_postdep_objects_RC # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_RC # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_RC # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_RC # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_RC # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_RC # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_RC # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_RC # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_RC # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_RC # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_RC # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_RC # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_RC" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_RC # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_RC # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_RC # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_RC # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ;; *) { { echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5 echo "$as_me: error: Unsupported tag name: $tagname" >&2;} { (exit 1); exit 1; }; } ;; esac # Append the new tag name to the list of available tags. if test -n "$tagname" ; then available_tags="$available_tags $tagname" fi fi done IFS="$lt_save_ifs" # Now substitute the updated list of available tags. if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then mv "${ofile}T" "$ofile" chmod +x "$ofile" else rm -f "${ofile}T" { { echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5 echo "$as_me: error: unable to update list of available tagged configurations." >&2;} { (exit 1); exit 1; }; } fi fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' # Prevent multiple expansion # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo "$as_me:$LINENO: checking whether ln -s works" >&5 echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no, using $LN_S" >&5 echo "${ECHO_T}no, using $LN_S" >&6 fi echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF all: @echo 'ac_maketemp="$(MAKE)"' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_set=yes else eval ac_cv_prog_make_${ac_make}_set=no fi rm -f conftest.make fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 SET_MAKE= else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 SET_MAKE="MAKE=${MAKE-make}" fi CFLAGS="${ac_save_CFLAGS}" LDFLAGS="${ac_save_LDFLAGS}" INCLUDES="-I\$(top_srcdir) -I\$(top_srcdir)/include" echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6 if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi for ac_header in xmmintrin.h emmintrin.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Check whether --enable-debug or --disable-debug was given. if test "${enable_debug+set}" = set; then enableval="$enable_debug" CFLAGS="-DDEBUG -O -g ${CFLAGS}" else CFLAGS="-O3 -ffast-math ${CFLAGS}" fi; # Check whether --enable-profile or --disable-profile was given. if test "${enable_profile+set}" = set; then enableval="$enable_profile" CFLAGS="-DPROFILE -pg ${CFLAGS}" fi; # Check whether --enable-sse2 or --disable-sse2 was given. if test "${enable_sse2+set}" = set; then enableval="$enable_sse2" CFLAGS="-msse2 -DUSE_SSE ${CFLAGS}" fi; echo "$as_me:$LINENO: checking for fabs in -lm" >&5 echo $ECHO_N "checking for fabs in -lm... $ECHO_C" >&6 if test "${ac_cv_lib_m_fabs+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char fabs (); int main () { fabs (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_m_fabs=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_m_fabs=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_m_fabs" >&5 echo "${ECHO_T}$ac_cv_lib_m_fabs" >&6 if test $ac_cv_lib_m_fabs = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi ac_config_files="$ac_config_files Makefile lib/Makefile sample/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by $as_me, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir INSTALL="$INSTALL" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "x$1" : 'x\([^=]*\)='` ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` ac_shift=: ;; -*) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # INIT-COMMANDS section. # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; "lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; "sample/Makefile" ) CONFIG_FILES="$CONFIG_FILES sample/Makefile" ;; "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@CYGPATH_W@,$CYGPATH_W,;t t s,@PACKAGE@,$PACKAGE,;t t s,@VERSION@,$VERSION,;t t s,@ACLOCAL@,$ACLOCAL,;t t s,@AUTOCONF@,$AUTOCONF,;t t s,@AUTOMAKE@,$AUTOMAKE,;t t s,@AUTOHEADER@,$AUTOHEADER,;t t s,@MAKEINFO@,$MAKEINFO,;t t s,@install_sh@,$install_sh,;t t s,@STRIP@,$STRIP,;t t s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t s,@mkdir_p@,$mkdir_p,;t t s,@AWK@,$AWK,;t t s,@SET_MAKE@,$SET_MAKE,;t t s,@am__leading_dot@,$am__leading_dot,;t t s,@AMTAR@,$AMTAR,;t t s,@am__tar@,$am__tar,;t t s,@am__untar@,$am__untar,;t t s,@MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t s,@MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t s,@MAINT@,$MAINT,;t t s,@build@,$build,;t t s,@build_cpu@,$build_cpu,;t t s,@build_vendor@,$build_vendor,;t t s,@build_os@,$build_os,;t t s,@host@,$host,;t t s,@host_cpu@,$host_cpu,;t t s,@host_vendor@,$host_vendor,;t t s,@host_os@,$host_os,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@EXEEXT@,$EXEEXT,;t t s,@OBJEXT@,$OBJEXT,;t t s,@DEPDIR@,$DEPDIR,;t t s,@am__include@,$am__include,;t t s,@am__quote@,$am__quote,;t t s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t s,@CCDEPMODE@,$CCDEPMODE,;t t s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t s,@EGREP@,$EGREP,;t t s,@LN_S@,$LN_S,;t t s,@ECHO@,$ECHO,;t t s,@AR@,$AR,;t t s,@ac_ct_AR@,$ac_ct_AR,;t t s,@RANLIB@,$RANLIB,;t t s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t s,@CPP@,$CPP,;t t s,@CXX@,$CXX,;t t s,@CXXFLAGS@,$CXXFLAGS,;t t s,@ac_ct_CXX@,$ac_ct_CXX,;t t s,@CXXDEPMODE@,$CXXDEPMODE,;t t s,@am__fastdepCXX_TRUE@,$am__fastdepCXX_TRUE,;t t s,@am__fastdepCXX_FALSE@,$am__fastdepCXX_FALSE,;t t s,@CXXCPP@,$CXXCPP,;t t s,@F77@,$F77,;t t s,@FFLAGS@,$FFLAGS,;t t s,@ac_ct_F77@,$ac_ct_F77,;t t s,@LIBTOOL@,$LIBTOOL,;t t s,@INCLUDES@,$INCLUDES,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;t t s,@srcdir@,$ac_srcdir,;t t s,@abs_srcdir@,$ac_abs_srcdir,;t t s,@top_srcdir@,$ac_top_srcdir,;t t s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t s,@builddir@,$ac_builddir,;t t s,@abs_builddir@,$ac_abs_builddir,;t t s,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # # CONFIG_HEADER section. # # These sed commands are passed to sed as "A NAME B NAME C VALUE D", where # NAME is the cpp macro being defined and VALUE is the value it is being given. # # ac_d sets the value in "#define NAME VALUE" lines. ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' ac_dB='[ ].*$,\1#\2' ac_dC=' ' ac_dD=',;t' # ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_uB='$,\1#\2define\3' ac_uC=' ' ac_uD=',;t' for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } # Do quote $f, to prevent DOS paths from being IFS'd. echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } # Remove the trailing spaces. sed 's/[ ]*$//' $ac_file_inputs >$tmp/in _ACEOF # Transform confdefs.h into two sed scripts, `conftest.defines' and # `conftest.undefs', that substitutes the proper values into # config.h.in to produce config.h. The first handles `#define' # templates, and the second `#undef' templates. # And first: Protect against being on the right side of a sed subst in # config.status. Protect against being in an unquoted here document # in config.status. rm -f conftest.defines conftest.undefs # Using a here document instead of a string reduces the quoting nightmare. # Putting comments in sed scripts is not portable. # # `end' is used to avoid that the second main sed command (meant for # 0-ary CPP macros) applies to n-ary macro definitions. # See the Autoconf documentation for `clear'. cat >confdef2sed.sed <<\_ACEOF s/[\\&,]/\\&/g s,[\\$`],\\&,g t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp t end s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp : end _ACEOF # If some macros were called several times there might be several times # the same #defines, which is useless. Nevertheless, we may not want to # sort them, since we want the *last* AC-DEFINE to be honored. uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs rm -f confdef2sed.sed # This sed command replaces #undef with comments. This is necessary, for # example, in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. cat >>conftest.undefs <<\_ACEOF s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, _ACEOF # Break up conftest.defines because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS echo ' :' >>$CONFIG_STATUS rm -f conftest.tail while grep . conftest.defines >/dev/null do # Write a limited-size here document to $tmp/defines.sed. echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS # Speed up: don't consider the non `#define' lines. echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS # Work around the forget-to-reset-the-flag bug. echo 't clr' >>$CONFIG_STATUS echo ': clr' >>$CONFIG_STATUS sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS echo 'CEOF sed -f $tmp/defines.sed $tmp/in >$tmp/out rm -f $tmp/in mv $tmp/out $tmp/in ' >>$CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail rm -f conftest.defines mv conftest.tail conftest.defines done rm -f conftest.defines echo ' fi # grep' >>$CONFIG_STATUS echo >>$CONFIG_STATUS # Break up conftest.undefs because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #undef templates' >>$CONFIG_STATUS rm -f conftest.tail while grep . conftest.undefs >/dev/null do # Write a limited-size here document to $tmp/undefs.sed. echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS # Speed up: don't consider the non `#undef' echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS # Work around the forget-to-reset-the-flag bug. echo 't clr' >>$CONFIG_STATUS echo ': clr' >>$CONFIG_STATUS sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS echo 'CEOF sed -f $tmp/undefs.sed $tmp/in >$tmp/out rm -f $tmp/in mv $tmp/out $tmp/in ' >>$CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail rm -f conftest.undefs mv conftest.tail conftest.undefs done rm -f conftest.undefs cat >>$CONFIG_STATUS <<\_ACEOF # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then echo "/* Generated by configure. */" >$tmp/config.h else echo "/* $ac_file. Generated by configure. */" >$tmp/config.h fi cat $tmp/in >>$tmp/config.h rm -f $tmp/in if test x"$ac_file" != x-; then if diff $ac_file $tmp/config.h >/dev/null 2>&1; then { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } rm -f $ac_file mv $tmp/config.h $ac_file fi else cat $tmp/config.h rm -f $tmp/config.h fi # Compute $ac_file's index in $config_headers. _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $ac_file | $ac_file:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null || $as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X$ac_file : 'X\(//\)[^/]' \| \ X$ac_file : 'X\(//\)$' \| \ X$ac_file : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X$ac_file | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'`/stamp-h$_am_stamp_count done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # # CONFIG_COMMANDS section. # for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue ac_dest=`echo "$ac_file" | sed 's,:.*,,'` ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_dir=`(dirname "$ac_dest") 2>/dev/null || $as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_dest" : 'X\(//\)[^/]' \| \ X"$ac_dest" : 'X\(//\)$' \| \ X"$ac_dest" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_dest" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 echo "$as_me: executing $ac_dest commands" >&6;} case $ac_dest in depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # So let's grep whole file. if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then dirpart=`(dirname "$mf") 2>/dev/null || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`(dirname "$file") 2>/dev/null || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p $dirpart/$fdir else as_dir=$dirpart/$fdir as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5 echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} { (exit 1); exit 1; }; }; } # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done ;; esac done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/configure.in000066400000000000000000000057771321604176500270720ustar00rootroot00000000000000dnl $Id: configure.in 65 2010-01-29 12:19:16Z naoaki $ dnl dnl dnl Exported and configured variables: dnl CFLAGS dnl LDFLAGS dnl INCLUDES dnl ------------------------------------------------------------------ dnl Initialization for autoconf dnl ------------------------------------------------------------------ AC_PREREQ(2.59) AC_INIT AC_CONFIG_SRCDIR([lib/lbfgs.c]) dnl ------------------------------------------------------------------ dnl Initialization for automake dnl ------------------------------------------------------------------ AM_INIT_AUTOMAKE(liblbfgs, 1.9) AC_CONFIG_HEADERS(config.h) AM_MAINTAINER_MODE dnl ------------------------------------------------------------------ dnl Checks for program dnl ------------------------------------------------------------------ AC_PROG_LIBTOOL AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET dnl ------------------------------------------------------------------ dnl Initialization for variables dnl ------------------------------------------------------------------ CFLAGS="${ac_save_CFLAGS}" LDFLAGS="${ac_save_LDFLAGS}" INCLUDES="-I\$(top_srcdir) -I\$(top_srcdir)/include" dnl ------------------------------------------------------------------ dnl Checks for header files. dnl ------------------------------------------------------------------ AC_HEADER_STDC AC_CHECK_HEADERS(xmmintrin.h emmintrin.h) dnl ------------------------------------------------------------------ dnl Checks for debugging mode dnl ------------------------------------------------------------------ AC_ARG_ENABLE( debug, [AS_HELP_STRING( [--enable-debug], [build for debugging] )], [CFLAGS="-DDEBUG -O -g ${CFLAGS}"], [CFLAGS="-O3 -ffast-math ${CFLAGS}"] ) dnl ------------------------------------------------------------------ dnl Checks for profiling mode dnl ------------------------------------------------------------------ AC_ARG_ENABLE( profile, [AS_HELP_STRING( [--enable-profile], [build for profiling] )], [CFLAGS="-DPROFILE -pg ${CFLAGS}"] ) dnl ------------------------------------------------------------------ dnl Checks for SSE2 build dnl ------------------------------------------------------------------ AC_ARG_ENABLE( sse2, [AS_HELP_STRING( [--enable-sse2], [enable SSE2 optimization routines] )], [CFLAGS="-msse2 -DUSE_SSE ${CFLAGS}"] ) dnl ------------------------------------------------------------------ dnl Checks for library functions. dnl ------------------------------------------------------------------ AC_CHECK_LIB(m, fabs) dnl ------------------------------------------------------------------ dnl Export variables dnl ------------------------------------------------------------------ AC_SUBST(CFLAGS) AC_SUBST(LDFLAGS) AC_SUBST(INCLUDES) dnl ------------------------------------------------------------------ dnl Output the configure results. dnl ------------------------------------------------------------------ AC_CONFIG_FILES(Makefile lib/Makefile sample/Makefile) AC_OUTPUT plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/depcomp000077500000000000000000000355451321604176500261320ustar00rootroot00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2004-05-31.23 # Copyright (C) 1999, 2000, 2003, 2004 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 to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputing dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit 0 ;; -v | --v*) echo "depcomp $scriptversion" exit 0 ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> $depfile echo >> $depfile # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> $depfile else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` tmpdepfile="$stripped.u" if test "$libtool" = yes; then "$@" -Wc,-M else "$@" -M fi stat=$? if test -f "$tmpdepfile"; then : else stripped=`echo "$stripped" | sed 's,^.*/,,'` tmpdepfile="$stripped.u" fi if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi if test -f "$tmpdepfile"; then outname="$stripped.o" # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # Dependencies are output in .lo.d with libtool 1.4. # With libtool 1.5 they are output both in $dir.libs/$base.o.d # and in $dir.libs/$base.o.d and $dir$base.o.d. We process the # latter, because the former will be cleaned when $dir.libs is # erased. tmpdepfile1="$dir.libs/$base.lo.d" tmpdepfile2="$dir$base.o.d" tmpdepfile3="$dir.libs/$base.d" "$@" -Wc,-MD else tmpdepfile1="$dir$base.o.d" tmpdepfile2="$dir$base.d" tmpdepfile3="$dir$base.d" "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi if test -f "$tmpdepfile1"; then tmpdepfile="$tmpdepfile1" elif test -f "$tmpdepfile2"; then tmpdepfile="$tmpdepfile2" else tmpdepfile="$tmpdepfile3" fi if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # X makedepend shift cleared=no for arg in "$@"; do case $cleared in no) set ""; shift cleared=yes ;; esac case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix="`echo $object | sed 's/^.*\././'`" touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. "$@" || exit $? IFS=" " for arg do case "$arg" in "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/include/000077500000000000000000000000001321604176500261645ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/include/lbfgs.h000066400000000000000000000762761321604176500274540ustar00rootroot00000000000000/* * C library of Limited memory BFGS (L-BFGS). * * Copyright (c) 1990, Jorge Nocedal * Copyright (c) 2007-2010 Naoaki Okazaki * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* $Id: lbfgs.h 65 2010-01-29 12:19:16Z naoaki $ */ #ifndef __LBFGS_H__ #define __LBFGS_H__ #ifdef __cplusplus extern "C" { #endif/*__cplusplus*/ /* * The default precision of floating point values is 64bit (double). */ #ifndef LBFGS_FLOAT #define LBFGS_FLOAT 64 #endif/*LBFGS_FLOAT*/ /* * Activate optimization routines for IEEE754 floating point values. */ #ifndef LBFGS_IEEE_FLOAT #define LBFGS_IEEE_FLOAT 1 #endif/*LBFGS_IEEE_FLOAT*/ #if LBFGS_FLOAT == 32 typedef float lbfgsfloatval_t; #elif LBFGS_FLOAT == 64 typedef double lbfgsfloatval_t; #else #error "libLBFGS supports single (float; LBFGS_FLOAT = 32) or double (double; LBFGS_FLOAT=64) precision only." #endif /** * \addtogroup liblbfgs_api libLBFGS API * @{ * * The libLBFGS API. */ /** * Return values of lbfgs(). * * Roughly speaking, a negative value indicates an error. */ enum { /** L-BFGS reaches convergence. */ LBFGS_SUCCESS = 0, LBFGS_CONVERGENCE = 0, LBFGS_STOP, /** The initial variables already minimize the objective function. */ LBFGS_ALREADY_MINIMIZED, /** Unknown error. */ LBFGSERR_UNKNOWNERROR = -1024, /** Logic error. */ LBFGSERR_LOGICERROR, /** Insufficient memory. */ LBFGSERR_OUTOFMEMORY, /** The minimization process has been canceled. */ LBFGSERR_CANCELED, /** Invalid number of variables specified. */ LBFGSERR_INVALID_N, /** Invalid number of variables (for SSE) specified. */ LBFGSERR_INVALID_N_SSE, /** The array x must be aligned to 16 (for SSE). */ LBFGSERR_INVALID_X_SSE, /** Invalid parameter lbfgs_parameter_t::epsilon specified. */ LBFGSERR_INVALID_EPSILON, /** Invalid parameter lbfgs_parameter_t::past specified. */ LBFGSERR_INVALID_TESTPERIOD, /** Invalid parameter lbfgs_parameter_t::delta specified. */ LBFGSERR_INVALID_DELTA, /** Invalid parameter lbfgs_parameter_t::linesearch specified. */ LBFGSERR_INVALID_LINESEARCH, /** Invalid parameter lbfgs_parameter_t::max_step specified. */ LBFGSERR_INVALID_MINSTEP, /** Invalid parameter lbfgs_parameter_t::max_step specified. */ LBFGSERR_INVALID_MAXSTEP, /** Invalid parameter lbfgs_parameter_t::ftol specified. */ LBFGSERR_INVALID_FTOL, /** Invalid parameter lbfgs_parameter_t::wolfe specified. */ LBFGSERR_INVALID_WOLFE, /** Invalid parameter lbfgs_parameter_t::gtol specified. */ LBFGSERR_INVALID_GTOL, /** Invalid parameter lbfgs_parameter_t::xtol specified. */ LBFGSERR_INVALID_XTOL, /** Invalid parameter lbfgs_parameter_t::max_linesearch specified. */ LBFGSERR_INVALID_MAXLINESEARCH, /** Invalid parameter lbfgs_parameter_t::orthantwise_c specified. */ LBFGSERR_INVALID_ORTHANTWISE, /** Invalid parameter lbfgs_parameter_t::orthantwise_start specified. */ LBFGSERR_INVALID_ORTHANTWISE_START, /** Invalid parameter lbfgs_parameter_t::orthantwise_end specified. */ LBFGSERR_INVALID_ORTHANTWISE_END, /** The line-search step went out of the interval of uncertainty. */ LBFGSERR_OUTOFINTERVAL, /** A logic error occurred; alternatively, the interval of uncertainty became too small. */ LBFGSERR_INCORRECT_TMINMAX, /** A rounding error occurred; alternatively, no line-search step satisfies the sufficient decrease and curvature conditions. */ LBFGSERR_ROUNDING_ERROR, /** The line-search step became smaller than lbfgs_parameter_t::min_step. */ LBFGSERR_MINIMUMSTEP, /** The line-search step became larger than lbfgs_parameter_t::max_step. */ LBFGSERR_MAXIMUMSTEP, /** The line-search routine reaches the maximum number of evaluations. */ LBFGSERR_MAXIMUMLINESEARCH, /** The algorithm routine reaches the maximum number of iterations. */ LBFGSERR_MAXIMUMITERATION, /** Relative width of the interval of uncertainty is at most lbfgs_parameter_t::xtol. */ LBFGSERR_WIDTHTOOSMALL, /** A logic error (negative line-search step) occurred. */ LBFGSERR_INVALIDPARAMETERS, /** The current search direction increases the objective function value. */ LBFGSERR_INCREASEGRADIENT, }; /** * Line search algorithms. */ enum { /** The default algorithm (MoreThuente method). */ LBFGS_LINESEARCH_DEFAULT = 0, /** MoreThuente method proposd by More and Thuente. */ LBFGS_LINESEARCH_MORETHUENTE = 0, /** * Backtracking method with the Armijo condition. * The backtracking method finds the step length such that it satisfies * the sufficient decrease (Armijo) condition, * - f(x + a * d) <= f(x) + lbfgs_parameter_t::ftol * a * g(x)^T d, * * where x is the current point, d is the current search direction, and * a is the step length. */ LBFGS_LINESEARCH_BACKTRACKING_ARMIJO = 1, /** The backtracking method with the defualt (regular Wolfe) condition. */ LBFGS_LINESEARCH_BACKTRACKING = 2, /** * Backtracking method with regular Wolfe condition. * The backtracking method finds the step length such that it satisfies * both the Armijo condition (LBFGS_LINESEARCH_BACKTRACKING_ARMIJO) * and the curvature condition, * - g(x + a * d)^T d >= lbfgs_parameter_t::wolfe * g(x)^T d, * * where x is the current point, d is the current search direction, and * a is the step length. */ LBFGS_LINESEARCH_BACKTRACKING_WOLFE = 2, /** * Backtracking method with strong Wolfe condition. * The backtracking method finds the step length such that it satisfies * both the Armijo condition (LBFGS_LINESEARCH_BACKTRACKING_ARMIJO) * and the following condition, * - |g(x + a * d)^T d| <= lbfgs_parameter_t::wolfe * |g(x)^T d|, * * where x is the current point, d is the current search direction, and * a is the step length. */ LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE = 3, }; /** * L-BFGS optimization parameters. * Call lbfgs_parameter_init() function to initialize parameters to the * default values. */ typedef struct { /** * The number of corrections to approximate the inverse hessian matrix. * The L-BFGS routine stores the computation results of previous \ref m * iterations to approximate the inverse hessian matrix of the current * iteration. This parameter controls the size of the limited memories * (corrections). The default value is \c 6. Values less than \c 3 are * not recommended. Large values will result in excessive computing time. */ int m; /** * Epsilon for convergence test. * This parameter determines the accuracy with which the solution is to * be found. A minimization terminates when * ||g|| < \ref epsilon * max(1, ||x||), * where ||.|| denotes the Euclidean (L2) norm. The default value is * \c 1e-5. */ lbfgsfloatval_t epsilon; /** * Distance for delta-based convergence test. * This parameter determines the distance, in iterations, to compute * the rate of decrease of the objective function. If the value of this * parameter is zero, the library does not perform the delta-based * convergence test. The default value is \c 0. */ int past; /** * Delta for convergence test. * This parameter determines the minimum rate of decrease of the * objective function. The library stops iterations when the * following condition is met: * (f' - f) / f < \ref delta, * where f' is the objective value of \ref past iterations ago, and f is * the objective value of the current iteration. * The default value is \c 0. */ lbfgsfloatval_t delta; /** * The maximum number of iterations. * The lbfgs() function terminates an optimization process with * ::LBFGSERR_MAXIMUMITERATION status code when the iteration count * exceedes this parameter. Setting this parameter to zero continues an * optimization process until a convergence or error. The default value * is \c 0. */ int max_iterations; /** * The line search algorithm. * This parameter specifies a line search algorithm to be used by the * L-BFGS routine. */ int linesearch; /** * The maximum number of trials for the line search. * This parameter controls the number of function and gradients evaluations * per iteration for the line search routine. The default value is \c 20. */ int max_linesearch; /** * The minimum step of the line search routine. * The default value is \c 1e-20. This value need not be modified unless * the exponents are too large for the machine being used, or unless the * problem is extremely badly scaled (in which case the exponents should * be increased). */ lbfgsfloatval_t min_step; /** * The maximum step of the line search. * The default value is \c 1e+20. This value need not be modified unless * the exponents are too large for the machine being used, or unless the * problem is extremely badly scaled (in which case the exponents should * be increased). */ lbfgsfloatval_t max_step; /** * A parameter to control the accuracy of the line search routine. * The default value is \c 1e-4. This parameter should be greater * than zero and smaller than \c 0.5. */ lbfgsfloatval_t ftol; /** * A coefficient for the Wolfe condition. * This parameter is valid only when the backtracking line-search * algorithm is used with the Wolfe condition, * ::LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE or * ::LBFGS_LINESEARCH_BACKTRACKING_WOLFE . * The default value is \c 0.9. This parameter should be greater * the \ref ftol parameter and smaller than \c 1.0. */ lbfgsfloatval_t wolfe; /** * A parameter to control the accuracy of the line search routine. * The default value is \c 0.9. If the function and gradient * evaluations are inexpensive with respect to the cost of the * iteration (which is sometimes the case when solving very large * problems) it may be advantageous to set this parameter to a small * value. A typical small value is \c 0.1. This parameter shuold be * greater than the \ref ftol parameter (\c 1e-4) and smaller than * \c 1.0. */ lbfgsfloatval_t gtol; /** * The machine precision for floating-point values. * This parameter must be a positive value set by a client program to * estimate the machine precision. The line search routine will terminate * with the status code (::LBFGSERR_ROUNDING_ERROR) if the relative width * of the interval of uncertainty is less than this parameter. */ lbfgsfloatval_t xtol; /** * Coeefficient for the L1 norm of variables. * This parameter should be set to zero for standard minimization * problems. Setting this parameter to a positive value activates * Orthant-Wise Limited-memory Quasi-Newton (OWL-QN) method, which * minimizes the objective function F(x) combined with the L1 norm |x| * of the variables, {F(x) + C |x|}. This parameter is the coeefficient * for the |x|, i.e., C. As the L1 norm |x| is not differentiable at * zero, the library modifies function and gradient evaluations from * a client program suitably; a client program thus have only to return * the function value F(x) and gradients G(x) as usual. The default value * is zero. */ lbfgsfloatval_t orthantwise_c; /** * Start index for computing L1 norm of the variables. * This parameter is valid only for OWL-QN method * (i.e., \ref orthantwise_c != 0). This parameter b (0 <= b < N) * specifies the index number from which the library computes the * L1 norm of the variables x, * |x| := |x_{b}| + |x_{b+1}| + ... + |x_{N}| . * In other words, variables x_1, ..., x_{b-1} are not used for * computing the L1 norm. Setting b (0 < b < N), one can protect * variables, x_1, ..., x_{b-1} (e.g., a bias term of logistic * regression) from being regularized. The default value is zero. */ int orthantwise_start; /** * End index for computing L1 norm of the variables. * This parameter is valid only for OWL-QN method * (i.e., \ref orthantwise_c != 0). This parameter e (0 < e <= N) * specifies the index number at which the library stops computing the * L1 norm of the variables x, */ int orthantwise_end; } lbfgs_parameter_t; /** * Callback interface to provide objective function and gradient evaluations. * * The lbfgs() function call this function to obtain the values of objective * function and its gradients when needed. A client program must implement * this function to evaluate the values of the objective function and its * gradients, given current values of variables. * * @param instance The user data sent for lbfgs() function by the client. * @param x The current values of variables. * @param g The gradient vector. The callback function must compute * the gradient values for the current variables. * @param n The number of variables. * @param step The current step of the line search routine. * @retval lbfgsfloatval_t The value of the objective function for the current * variables. */ typedef lbfgsfloatval_t (*lbfgs_evaluate_t)( void *instance, const lbfgsfloatval_t *x, lbfgsfloatval_t *g, const int n, const lbfgsfloatval_t step ); /** * Callback interface to receive the progress of the optimization process. * * The lbfgs() function call this function for each iteration. Implementing * this function, a client program can store or display the current progress * of the optimization process. * * @param instance The user data sent for lbfgs() function by the client. * @param x The current values of variables. * @param g The current gradient values of variables. * @param fx The current value of the objective function. * @param xnorm The Euclidean norm of the variables. * @param gnorm The Euclidean norm of the gradients. * @param step The line-search step used for this iteration. * @param n The number of variables. * @param k The iteration count. * @param ls The number of evaluations called for this iteration. * @retval int Zero to continue the optimization process. Returning a * non-zero value will cancel the optimization process. */ typedef int (*lbfgs_progress_t)( void *instance, const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t fx, const lbfgsfloatval_t xnorm, const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step, int n, int k, int ls ); /* A user must implement a function compatible with ::lbfgs_evaluate_t (evaluation callback) and pass the pointer to the callback function to lbfgs() arguments. Similarly, a user can implement a function compatible with ::lbfgs_progress_t (progress callback) to obtain the current progress (e.g., variables, function value, ||G||, etc) and to cancel the iteration process if necessary. Implementation of a progress callback is optional: a user can pass \c NULL if progress notification is not necessary. In addition, a user must preserve two requirements: - The number of variables must be multiples of 16 (this is not 4). - The memory block of variable array ::x must be aligned to 16. This algorithm terminates an optimization when: ||G|| < \epsilon \cdot \max(1, ||x||) . In this formula, ||.|| denotes the Euclidean norm. */ /** * Start a L-BFGS optimization. * * @param n The number of variables. * @param x The array of variables. A client program can set * default values for the optimization and receive the * optimization result through this array. This array * must be allocated by ::lbfgs_malloc function * for libLBFGS built with SSE/SSE2 optimization routine * enabled. The library built without SSE/SSE2 * optimization does not have such a requirement. * @param ptr_fx The pointer to the variable that receives the final * value of the objective function for the variables. * This argument can be set to \c NULL if the final * value of the objective function is unnecessary. * @param proc_evaluate The callback function to provide function and * gradient evaluations given a current values of * variables. A client program must implement a * callback function compatible with \ref * lbfgs_evaluate_t and pass the pointer to the * callback function. * @param proc_progress The callback function to receive the progress * (the number of iterations, the current value of * the objective function) of the minimization * process. This argument can be set to \c NULL if * a progress report is unnecessary. * @param instance A user data for the client program. The callback * functions will receive the value of this argument. * @param param The pointer to a structure representing parameters for * L-BFGS optimization. A client program can set this * parameter to \c NULL to use the default parameters. * Call lbfgs_parameter_init() function to fill a * structure with the default values. * @retval int The status code. This function returns zero if the * minimization process terminates without an error. A * non-zero value indicates an error. */ int lbfgs( int n, lbfgsfloatval_t *x, lbfgsfloatval_t *ptr_fx, lbfgs_evaluate_t proc_evaluate, lbfgs_progress_t proc_progress, void *instance, lbfgs_parameter_t *param ); /** * Initialize L-BFGS parameters to the default values. * * Call this function to fill a parameter structure with the default values * and overwrite parameter values if necessary. * * @param param The pointer to the parameter structure. */ void lbfgs_parameter_init(lbfgs_parameter_t *param); /** * Allocate an array for variables. * * This function allocates an array of variables for the convenience of * ::lbfgs function; the function has a requreiemt for a variable array * when libLBFGS is built with SSE/SSE2 optimization routines. A user does * not have to use this function for libLBFGS built without SSE/SSE2 * optimization. * * @param n The number of variables. */ lbfgsfloatval_t* lbfgs_malloc(int n); /** * Free an array of variables. * * @param x The array of variables allocated by ::lbfgs_malloc * function. */ void lbfgs_free(lbfgsfloatval_t *x); /** @} */ #ifdef __cplusplus } #endif/*__cplusplus*/ /** @mainpage libLBFGS: a library of Limited-memory Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) @section intro Introduction This library is a C port of the implementation of Limited-memory Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) method written by Jorge Nocedal. The original FORTRAN source code is available at: http://www.ece.northwestern.edu/~nocedal/lbfgs.html The L-BFGS method solves the unconstrainted minimization problem,
    minimize F(x), x = (x1, x2, ..., xN),
only if the objective function F(x) and its gradient G(x) are computable. The well-known Newton's method requires computation of the inverse of the hessian matrix of the objective function. However, the computational cost for the inverse hessian matrix is expensive especially when the objective function takes a large number of variables. The L-BFGS method iteratively finds a minimizer by approximating the inverse hessian matrix by information from last m iterations. This innovation saves the memory storage and computational time drastically for large-scaled problems. Among the various ports of L-BFGS, this library provides several features: - Optimization with L1-norm (Orthant-Wise Limited-memory Quasi-Newton (OWL-QN) method): In addition to standard minimization problems, the library can minimize a function F(x) combined with L1-norm |x| of the variables, {F(x) + C |x|}, where C is a constant scalar parameter. This feature is useful for estimating parameters of sparse log-linear models (e.g., logistic regression and maximum entropy) with L1-regularization (or Laplacian prior). - Clean C code: Unlike C codes generated automatically by f2c (Fortran 77 into C converter), this port includes changes based on my interpretations, improvements, optimizations, and clean-ups so that the ported code would be well-suited for a C code. In addition to comments inherited from the original code, a number of comments were added through my interpretations. - Callback interface: The library receives function and gradient values via a callback interface. The library also notifies the progress of the optimization by invoking a callback function. In the original implementation, a user had to set function and gradient values every time the function returns for obtaining updated values. - Thread safe: The library is thread-safe, which is the secondary gain from the callback interface. - Cross platform. The source code can be compiled on Microsoft Visual Studio 2005, GNU C Compiler (gcc), etc. - Configurable precision: A user can choose single-precision (float) or double-precision (double) accuracy by changing ::LBFGS_FLOAT macro. - SSE/SSE2 optimization: This library includes SSE/SSE2 optimization (written in compiler intrinsics) for vector arithmetic operations on Intel/AMD processors. The library uses SSE for float values and SSE2 for double values. The SSE/SSE2 optimization routine is disabled by default. This library is used by: - CRFsuite: A fast implementation of Conditional Random Fields (CRFs) - Classias: A collection of machine-learning algorithms for classification - mlegp: an R package for maximum likelihood estimates for Gaussian processes - imaging2: the imaging2 class library - Algorithm::LBFGS - Perl extension for L-BFGS - YAP-LBFGS (an interface to call libLBFGS from YAP Prolog) @section download Download - Source code libLBFGS is distributed under the term of the MIT license. @section changelog History - Version 1.9 (2010-01-29): - Fixed a mistake in checking the validity of the parameters "ftol" and "wolfe"; this was discovered by Kevin S. Van Horn. - Version 1.8 (2009-07-13): - Accepted the patch submitted by Takashi Imamichi; the backtracking method now has three criteria for choosing the step length: - ::LBFGS_LINESEARCH_BACKTRACKING_ARMIJO: sufficient decrease (Armijo) condition only - ::LBFGS_LINESEARCH_BACKTRACKING_WOLFE: regular Wolfe condition (sufficient decrease condition + curvature condition) - ::LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE: strong Wolfe condition - Updated the documentation to explain the above three criteria. - Version 1.7 (2009-02-28): - Improved OWL-QN routines for stability. - Removed the support of OWL-QN method in MoreThuente algorithm because it accidentally fails in early stages of iterations for some objectives. Because of this change, the OW-LQN method must be used with the backtracking algorithm (::LBFGS_LINESEARCH_BACKTRACKING), or the library returns ::LBFGSERR_INVALID_LINESEARCH. - Renamed line search algorithms as follows: - ::LBFGS_LINESEARCH_BACKTRACKING: regular Wolfe condition. - ::LBFGS_LINESEARCH_BACKTRACKING_LOOSE: regular Wolfe condition. - ::LBFGS_LINESEARCH_BACKTRACKING_STRONG: strong Wolfe condition. - Source code clean-up. - Version 1.6 (2008-11-02): - Improved line-search algorithm with strong Wolfe condition, which was contributed by Takashi Imamichi. This routine is now default for ::LBFGS_LINESEARCH_BACKTRACKING. The previous line search algorithm with regular Wolfe condition is still available as ::LBFGS_LINESEARCH_BACKTRACKING_LOOSE. - Configurable stop index for L1-norm computation. A member variable ::lbfgs_parameter_t::orthantwise_end was added to specify the index number at which the library stops computing the L1 norm of the variables. This is useful to prevent some variables from being regularized by the OW-LQN method. - A sample program written in C++ (sample/sample.cpp). - Version 1.5 (2008-07-10): - Configurable starting index for L1-norm computation. A member variable ::lbfgs_parameter_t::orthantwise_start was added to specify the index number from which the library computes the L1 norm of the variables. This is useful to prevent some variables from being regularized by the OWL-QN method. - Fixed a zero-division error when the initial variables have already been a minimizer (reported by Takashi Imamichi). In this case, the library returns ::LBFGS_ALREADY_MINIMIZED status code. - Defined ::LBFGS_SUCCESS status code as zero; removed unused constants, LBFGSFALSE and LBFGSTRUE. - Fixed a compile error in an implicit down-cast. - Version 1.4 (2008-04-25): - Configurable line search algorithms. A member variable ::lbfgs_parameter_t::linesearch was added to choose either MoreThuente method (::LBFGS_LINESEARCH_MORETHUENTE) or backtracking algorithm (::LBFGS_LINESEARCH_BACKTRACKING). - Fixed a bug: the previous version did not compute psuedo-gradients properly in the line search routines for OWL-QN. This bug might quit an iteration process too early when the OWL-QN routine was activated (0 < ::lbfgs_parameter_t::orthantwise_c). - Configure script for POSIX environments. - SSE/SSE2 optimizations with GCC. - New functions ::lbfgs_malloc and ::lbfgs_free to use SSE/SSE2 routines transparently. It is uncessary to use these functions for libLBFGS built without SSE/SSE2 routines; you can still use any memory allocators if SSE/SSE2 routines are disabled in libLBFGS. - Version 1.3 (2007-12-16): - An API change. An argument was added to lbfgs() function to receive the final value of the objective function. This argument can be set to \c NULL if the final value is unnecessary. - Fixed a null-pointer bug in the sample code (reported by Takashi Imamichi). - Added build scripts for Microsoft Visual Studio 2005 and GCC. - Added README file. - Version 1.2 (2007-12-13): - Fixed a serious bug in orthant-wise L-BFGS. An important variable was used without initialization. - Version 1.1 (2007-12-01): - Implemented orthant-wise L-BFGS. - Implemented lbfgs_parameter_init() function. - Fixed several bugs. - API documentation. - Version 1.0 (2007-09-20): - Initial release. @section api Documentation - @ref liblbfgs_api "libLBFGS API" @section sample Sample code @include sample.c @section ack Acknowledgements The L-BFGS algorithm is described in: - Jorge Nocedal. Updating Quasi-Newton Matrices with Limited Storage. Mathematics of Computation, Vol. 35, No. 151, pp. 773--782, 1980. - Dong C. Liu and Jorge Nocedal. On the limited memory BFGS method for large scale optimization. Mathematical Programming B, Vol. 45, No. 3, pp. 503-528, 1989. The line search algorithms used in this implementation are described in: - John E. Dennis and Robert B. Schnabel. Numerical Methods for Unconstrained Optimization and Nonlinear Equations, Englewood Cliffs, 1983. - Jorge J. More and David J. Thuente. Line search algorithm with guaranteed sufficient decrease. ACM Transactions on Mathematical Software (TOMS), Vol. 20, No. 3, pp. 286-307, 1994. This library also implements Orthant-Wise Limited-memory Quasi-Newton (OWL-QN) method presented in: - Galen Andrew and Jianfeng Gao. Scalable training of L1-regularized log-linear models. In Proceedings of the 24th International Conference on Machine Learning (ICML 2007), pp. 33-40, 2007. Special thanks go to: - Yoshimasa Tsuruoka and Daisuke Okanohara for technical information about OWL-QN - Takashi Imamichi for the useful enhancements of the backtracking method Finally I would like to thank the original author, Jorge Nocedal, who has been distributing the effieicnt and explanatory implementation in an open source licence. @section reference Reference - L-BFGS by Jorge Nocedal. - Orthant-Wise Limited-memory Quasi-Newton Optimizer for L1-regularized Objectives by Galen Andrew. - C port (via f2c) by Taku Kudo. - C#/C++/Delphi/VisualBasic6 port in ALGLIB. - Computational Crystallography Toolbox includes scitbx::lbfgs. */ #endif/*__LBFGS_H__*/ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/install-sh000077500000000000000000000217661321604176500265610ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2004-09-10.20 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" chmodcmd="$chmodprog 0755" chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: -c (ignored) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test -n "$1"; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit 0;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --version) echo "$0 $scriptversion"; exit 0;; *) # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. test -n "$dir_arg$dstarg" && break # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done break;; esac done if test -z "$1"; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src src= if test -d "$dst"; then mkdircmd=: chmodcmd= else mkdircmd=$mkdirprog fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dstarg: Is a directory" >&2 exit 1 fi dst=$dst/`basename "$src"` fi fi # This sed command emulates the dirname command. dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # Skip lots of stat calls in the usual case. if test ! -d "$dstdir"; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` IFS=$oIFS pathcomp= while test $# -ne 0 ; do pathcomp=$pathcomp$1 shift if test ! -d "$pathcomp"; then $mkdirprog "$pathcomp" # mkdir can fail with a `File exist' error in case several # install-sh are creating the directory concurrently. This # is OK. test -d "$pathcomp" || exit fi pathcomp=$pathcomp/ done fi if test -n "$dir_arg"; then $doit $mkdircmd "$dst" \ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } else dstfile=`basename "$dst"` # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 trap '(exit $?); exit' 1 2 13 15 # Copy the file name to the temp name. $doit $cpprog "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ || { # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dstdir/$dstfile"; then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" } } fi || { (exit 1); exit; } done # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit } # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/lbfgs.sln000066400000000000000000000027161321604176500263620ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib", "lib\lib.vcproj", "{C4405B73-A899-44BF-8681-04CE040B6705}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample", "sample\sample.vcproj", "{B4D7D5F5-4A4E-49D5-B38A-E5673520DE66}" ProjectSection(ProjectDependencies) = postProject {C4405B73-A899-44BF-8681-04CE040B6705} = {C4405B73-A899-44BF-8681-04CE040B6705} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {C4405B73-A899-44BF-8681-04CE040B6705}.Debug|Win32.ActiveCfg = Debug|Win32 {C4405B73-A899-44BF-8681-04CE040B6705}.Debug|Win32.Build.0 = Debug|Win32 {C4405B73-A899-44BF-8681-04CE040B6705}.Release|Win32.ActiveCfg = Release|Win32 {C4405B73-A899-44BF-8681-04CE040B6705}.Release|Win32.Build.0 = Release|Win32 {B4D7D5F5-4A4E-49D5-B38A-E5673520DE66}.Debug|Win32.ActiveCfg = Debug|Win32 {B4D7D5F5-4A4E-49D5-B38A-E5673520DE66}.Debug|Win32.Build.0 = Debug|Win32 {B4D7D5F5-4A4E-49D5-B38A-E5673520DE66}.Release|Win32.ActiveCfg = Release|Win32 {B4D7D5F5-4A4E-49D5-B38A-E5673520DE66}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/lib/000077500000000000000000000000001321604176500253075ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/lib/Makefile.am000066400000000000000000000006561321604176500273520ustar00rootroot00000000000000# $Id: Makefile.am 4 2008-04-25 07:54:10Z naoaki $ EXTRA_DIST = \ lib.vcproj liblbfgsincludedir = $(includedir) liblbfgsinclude_HEADERS = \ ../include/lbfgs.h lib_LTLIBRARIES = liblbfgs.la liblbfgs_la_SOURCES = \ arithmetic_ansi.h \ arithmetic_sse_double.h \ arithmetic_sse_float.h \ ../include/lbfgs.h \ lbfgs.c liblbfgs_la_LDFLAGS = \ -no-undefined \ -release @VERSION@ AM_CFLAGS = @CFLAGS@ INCLUDES = @INCLUDES@ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/lib/Makefile.in000066400000000000000000000366541321604176500273720ustar00rootroot00000000000000# Makefile.in generated by automake 1.9.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # $Id: Makefile.am 4 2008-04-25 07:54:10Z naoaki $ SOURCES = $(liblbfgs_la_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = lib DIST_COMMON = $(liblbfgsinclude_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(libdir)" \ "$(DESTDIR)$(liblbfgsincludedir)" libLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(lib_LTLIBRARIES) liblbfgs_la_LIBADD = am_liblbfgs_la_OBJECTS = lbfgs.lo liblbfgs_la_OBJECTS = $(am_liblbfgs_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(liblbfgs_la_SOURCES) DIST_SOURCES = $(liblbfgs_la_SOURCES) liblbfgsincludeHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(liblbfgsinclude_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ INCLUDES = @INCLUDES@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ prefix = @prefix@ program_transform_name = @program_transform_name@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ EXTRA_DIST = \ lib.vcproj liblbfgsincludedir = $(includedir) liblbfgsinclude_HEADERS = \ ../include/lbfgs.h lib_LTLIBRARIES = liblbfgs.la liblbfgs_la_SOURCES = \ arithmetic_ansi.h \ arithmetic_sse_double.h \ arithmetic_sse_float.h \ ../include/lbfgs.h \ lbfgs.c liblbfgs_la_LDFLAGS = \ -no-undefined \ -release @VERSION@ AM_CFLAGS = @CFLAGS@ all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu lib/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ f=$(am__strip_dir) \ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ else :; fi; \ done uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ p=$(am__strip_dir) \ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done liblbfgs.la: $(liblbfgs_la_OBJECTS) $(liblbfgs_la_DEPENDENCIES) $(LINK) -rpath $(libdir) $(liblbfgs_la_LDFLAGS) $(liblbfgs_la_OBJECTS) $(liblbfgs_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lbfgs.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-liblbfgsincludeHEADERS: $(liblbfgsinclude_HEADERS) @$(NORMAL_INSTALL) test -z "$(liblbfgsincludedir)" || $(mkdir_p) "$(DESTDIR)$(liblbfgsincludedir)" @list='$(liblbfgsinclude_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(liblbfgsincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(liblbfgsincludedir)/$$f'"; \ $(liblbfgsincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(liblbfgsincludedir)/$$f"; \ done uninstall-liblbfgsincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(liblbfgsinclude_HEADERS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(liblbfgsincludedir)/$$f'"; \ rm -f "$(DESTDIR)$(liblbfgsincludedir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(mkdir_p) $(distdir)/../include @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(liblbfgsincludedir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-liblbfgsincludeHEADERS install-exec-am: install-libLTLIBRARIES install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES \ uninstall-liblbfgsincludeHEADERS .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am \ install-libLTLIBRARIES install-liblbfgsincludeHEADERS \ install-man install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-info-am uninstall-libLTLIBRARIES \ uninstall-liblbfgsincludeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/lib/arithmetic_ansi.h000066400000000000000000000065471321604176500306370ustar00rootroot00000000000000/* * ANSI C implementation of vector operations. * * Copyright (c) 2007-2010 Naoaki Okazaki * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* $Id: arithmetic_ansi.h 65 2010-01-29 12:19:16Z naoaki $ */ #include #include #if LBFGS_FLOAT == 32 && LBFGS_IEEE_FLOAT #define fsigndiff(x, y) (((*(uint32_t*)(x)) ^ (*(uint32_t*)(y))) & 0x80000000U) #else #define fsigndiff(x, y) (*(x) * (*(y) / fabs(*(y))) < 0.) #endif/*LBFGS_IEEE_FLOAT*/ inline static void* vecalloc(size_t size) { void *memblock = malloc(size); if (memblock) { memset(memblock, 0, size); } return memblock; } inline static void vecfree(void *memblock) { free(memblock); } inline static void vecset(lbfgsfloatval_t *x, const lbfgsfloatval_t c, const int n) { int i; for (i = 0;i < n;++i) { x[i] = c; } } inline static void veccpy(lbfgsfloatval_t *y, const lbfgsfloatval_t *x, const int n) { int i; for (i = 0;i < n;++i) { y[i] = x[i]; } } inline static void vecncpy(lbfgsfloatval_t *y, const lbfgsfloatval_t *x, const int n) { int i; for (i = 0;i < n;++i) { y[i] = -x[i]; } } inline static void vecadd(lbfgsfloatval_t *y, const lbfgsfloatval_t *x, const lbfgsfloatval_t c, const int n) { int i; for (i = 0;i < n;++i) { y[i] += c * x[i]; } } inline static void vecdiff(lbfgsfloatval_t *z, const lbfgsfloatval_t *x, const lbfgsfloatval_t *y, const int n) { int i; for (i = 0;i < n;++i) { z[i] = x[i] - y[i]; } } inline static void vecscale(lbfgsfloatval_t *y, const lbfgsfloatval_t c, const int n) { int i; for (i = 0;i < n;++i) { y[i] *= c; } } inline static void vecmul(lbfgsfloatval_t *y, const lbfgsfloatval_t *x, const int n) { int i; for (i = 0;i < n;++i) { y[i] *= x[i]; } } inline static void vecdot(lbfgsfloatval_t* s, const lbfgsfloatval_t *x, const lbfgsfloatval_t *y, const int n) { int i; *s = 0.; for (i = 0;i < n;++i) { *s += x[i] * y[i]; } } inline static void vec2norm(lbfgsfloatval_t* s, const lbfgsfloatval_t *x, const int n) { vecdot(s, x, x, n); *s = (lbfgsfloatval_t)sqrt(*s); } inline static void vec2norminv(lbfgsfloatval_t* s, const lbfgsfloatval_t *x, const int n) { vec2norm(s, x, n); *s = (lbfgsfloatval_t)(1.0 / *s); } arithmetic_sse_double.h000066400000000000000000000207131321604176500317410ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/lib/* * SSE2 implementation of vector oprations (64bit double). * * Copyright (c) 2007-2010 Naoaki Okazaki * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* $Id: arithmetic_sse_double.h 65 2010-01-29 12:19:16Z naoaki $ */ #include #include #include #if 1400 <= _MSC_VER #include #endif/*1400 <= _MSC_VER*/ #if HAVE_EMMINTRIN_H #include #endif/*HAVE_EMMINTRIN_H*/ inline static void* vecalloc(size_t size) { #ifdef _MSC_VER void *memblock = _aligned_malloc(size, 16); #else void *memblock = memalign(16, size); #endif if (memblock != NULL) { memset(memblock, 0, size); } return memblock; } inline static void vecfree(void *memblock) { #ifdef _MSC_VER _aligned_free(memblock); #else free(memblock); #endif } #define fsigndiff(x, y) \ ((_mm_movemask_pd(_mm_set_pd(*(x), *(y))) + 1) & 0x002) #define vecset(x, c, n) \ { \ int i; \ __m128d XMM0 = _mm_set1_pd(c); \ for (i = 0;i < (n);i += 8) { \ _mm_store_pd((x)+i , XMM0); \ _mm_store_pd((x)+i+2, XMM0); \ _mm_store_pd((x)+i+4, XMM0); \ _mm_store_pd((x)+i+6, XMM0); \ } \ } #define veccpy(y, x, n) \ { \ int i; \ for (i = 0;i < (n);i += 8) { \ __m128d XMM0 = _mm_load_pd((x)+i ); \ __m128d XMM1 = _mm_load_pd((x)+i+2); \ __m128d XMM2 = _mm_load_pd((x)+i+4); \ __m128d XMM3 = _mm_load_pd((x)+i+6); \ _mm_store_pd((y)+i , XMM0); \ _mm_store_pd((y)+i+2, XMM1); \ _mm_store_pd((y)+i+4, XMM2); \ _mm_store_pd((y)+i+6, XMM3); \ } \ } #define vecncpy(y, x, n) \ { \ int i; \ for (i = 0;i < (n);i += 8) { \ __m128d XMM0 = _mm_setzero_pd(); \ __m128d XMM1 = _mm_setzero_pd(); \ __m128d XMM2 = _mm_setzero_pd(); \ __m128d XMM3 = _mm_setzero_pd(); \ __m128d XMM4 = _mm_load_pd((x)+i ); \ __m128d XMM5 = _mm_load_pd((x)+i+2); \ __m128d XMM6 = _mm_load_pd((x)+i+4); \ __m128d XMM7 = _mm_load_pd((x)+i+6); \ XMM0 = _mm_sub_pd(XMM0, XMM4); \ XMM1 = _mm_sub_pd(XMM1, XMM5); \ XMM2 = _mm_sub_pd(XMM2, XMM6); \ XMM3 = _mm_sub_pd(XMM3, XMM7); \ _mm_store_pd((y)+i , XMM0); \ _mm_store_pd((y)+i+2, XMM1); \ _mm_store_pd((y)+i+4, XMM2); \ _mm_store_pd((y)+i+6, XMM3); \ } \ } #define vecadd(y, x, c, n) \ { \ int i; \ __m128d XMM7 = _mm_set1_pd(c); \ for (i = 0;i < (n);i += 4) { \ __m128d XMM0 = _mm_load_pd((x)+i ); \ __m128d XMM1 = _mm_load_pd((x)+i+2); \ __m128d XMM2 = _mm_load_pd((y)+i ); \ __m128d XMM3 = _mm_load_pd((y)+i+2); \ XMM0 = _mm_mul_pd(XMM0, XMM7); \ XMM1 = _mm_mul_pd(XMM1, XMM7); \ XMM2 = _mm_add_pd(XMM2, XMM0); \ XMM3 = _mm_add_pd(XMM3, XMM1); \ _mm_store_pd((y)+i , XMM2); \ _mm_store_pd((y)+i+2, XMM3); \ } \ } #define vecdiff(z, x, y, n) \ { \ int i; \ for (i = 0;i < (n);i += 8) { \ __m128d XMM0 = _mm_load_pd((x)+i ); \ __m128d XMM1 = _mm_load_pd((x)+i+2); \ __m128d XMM2 = _mm_load_pd((x)+i+4); \ __m128d XMM3 = _mm_load_pd((x)+i+6); \ __m128d XMM4 = _mm_load_pd((y)+i ); \ __m128d XMM5 = _mm_load_pd((y)+i+2); \ __m128d XMM6 = _mm_load_pd((y)+i+4); \ __m128d XMM7 = _mm_load_pd((y)+i+6); \ XMM0 = _mm_sub_pd(XMM0, XMM4); \ XMM1 = _mm_sub_pd(XMM1, XMM5); \ XMM2 = _mm_sub_pd(XMM2, XMM6); \ XMM3 = _mm_sub_pd(XMM3, XMM7); \ _mm_store_pd((z)+i , XMM0); \ _mm_store_pd((z)+i+2, XMM1); \ _mm_store_pd((z)+i+4, XMM2); \ _mm_store_pd((z)+i+6, XMM3); \ } \ } #define vecscale(y, c, n) \ { \ int i; \ __m128d XMM7 = _mm_set1_pd(c); \ for (i = 0;i < (n);i += 4) { \ __m128d XMM0 = _mm_load_pd((y)+i ); \ __m128d XMM1 = _mm_load_pd((y)+i+2); \ XMM0 = _mm_mul_pd(XMM0, XMM7); \ XMM1 = _mm_mul_pd(XMM1, XMM7); \ _mm_store_pd((y)+i , XMM0); \ _mm_store_pd((y)+i+2, XMM1); \ } \ } #define vecmul(y, x, n) \ { \ int i; \ for (i = 0;i < (n);i += 8) { \ __m128d XMM0 = _mm_load_pd((x)+i ); \ __m128d XMM1 = _mm_load_pd((x)+i+2); \ __m128d XMM2 = _mm_load_pd((x)+i+4); \ __m128d XMM3 = _mm_load_pd((x)+i+6); \ __m128d XMM4 = _mm_load_pd((y)+i ); \ __m128d XMM5 = _mm_load_pd((y)+i+2); \ __m128d XMM6 = _mm_load_pd((y)+i+4); \ __m128d XMM7 = _mm_load_pd((y)+i+6); \ XMM4 = _mm_mul_pd(XMM4, XMM0); \ XMM5 = _mm_mul_pd(XMM5, XMM1); \ XMM6 = _mm_mul_pd(XMM6, XMM2); \ XMM7 = _mm_mul_pd(XMM7, XMM3); \ _mm_store_pd((y)+i , XMM4); \ _mm_store_pd((y)+i+2, XMM5); \ _mm_store_pd((y)+i+4, XMM6); \ _mm_store_pd((y)+i+6, XMM7); \ } \ } #if 3 <= __SSE__ /* Horizontal add with haddps SSE3 instruction. The work register (rw) is unused. */ #define __horizontal_sum(r, rw) \ r = _mm_hadd_ps(r, r); \ r = _mm_hadd_ps(r, r); #else /* Horizontal add with SSE instruction. The work register (rw) is used. */ #define __horizontal_sum(r, rw) \ rw = r; \ r = _mm_shuffle_ps(r, rw, _MM_SHUFFLE(1, 0, 3, 2)); \ r = _mm_add_ps(r, rw); \ rw = r; \ r = _mm_shuffle_ps(r, rw, _MM_SHUFFLE(2, 3, 0, 1)); \ r = _mm_add_ps(r, rw); #endif #define vecdot(s, x, y, n) \ { \ int i; \ __m128d XMM0 = _mm_setzero_pd(); \ __m128d XMM1 = _mm_setzero_pd(); \ __m128d XMM2, XMM3, XMM4, XMM5; \ for (i = 0;i < (n);i += 4) { \ XMM2 = _mm_load_pd((x)+i ); \ XMM3 = _mm_load_pd((x)+i+2); \ XMM4 = _mm_load_pd((y)+i ); \ XMM5 = _mm_load_pd((y)+i+2); \ XMM2 = _mm_mul_pd(XMM2, XMM4); \ XMM3 = _mm_mul_pd(XMM3, XMM5); \ XMM0 = _mm_add_pd(XMM0, XMM2); \ XMM1 = _mm_add_pd(XMM1, XMM3); \ } \ XMM0 = _mm_add_pd(XMM0, XMM1); \ XMM1 = _mm_shuffle_pd(XMM0, XMM0, _MM_SHUFFLE2(1, 1)); \ XMM0 = _mm_add_pd(XMM0, XMM1); \ _mm_store_sd((s), XMM0); \ } #define vec2norm(s, x, n) \ { \ int i; \ __m128d XMM0 = _mm_setzero_pd(); \ __m128d XMM1 = _mm_setzero_pd(); \ __m128d XMM2, XMM3, XMM4, XMM5; \ for (i = 0;i < (n);i += 4) { \ XMM2 = _mm_load_pd((x)+i ); \ XMM3 = _mm_load_pd((x)+i+2); \ XMM4 = XMM2; \ XMM5 = XMM3; \ XMM2 = _mm_mul_pd(XMM2, XMM4); \ XMM3 = _mm_mul_pd(XMM3, XMM5); \ XMM0 = _mm_add_pd(XMM0, XMM2); \ XMM1 = _mm_add_pd(XMM1, XMM3); \ } \ XMM0 = _mm_add_pd(XMM0, XMM1); \ XMM1 = _mm_shuffle_pd(XMM0, XMM0, _MM_SHUFFLE2(1, 1)); \ XMM0 = _mm_add_pd(XMM0, XMM1); \ XMM0 = _mm_sqrt_pd(XMM0); \ _mm_store_sd((s), XMM0); \ } #define vec2norminv(s, x, n) \ { \ int i; \ __m128d XMM0 = _mm_setzero_pd(); \ __m128d XMM1 = _mm_setzero_pd(); \ __m128d XMM2, XMM3, XMM4, XMM5; \ for (i = 0;i < (n);i += 4) { \ XMM2 = _mm_load_pd((x)+i ); \ XMM3 = _mm_load_pd((x)+i+2); \ XMM4 = XMM2; \ XMM5 = XMM3; \ XMM2 = _mm_mul_pd(XMM2, XMM4); \ XMM3 = _mm_mul_pd(XMM3, XMM5); \ XMM0 = _mm_add_pd(XMM0, XMM2); \ XMM1 = _mm_add_pd(XMM1, XMM3); \ } \ XMM2 = _mm_set1_pd(1.0); \ XMM0 = _mm_add_pd(XMM0, XMM1); \ XMM1 = _mm_shuffle_pd(XMM0, XMM0, _MM_SHUFFLE2(1, 1)); \ XMM0 = _mm_add_pd(XMM0, XMM1); \ XMM0 = _mm_sqrt_pd(XMM0); \ XMM2 = _mm_div_pd(XMM2, XMM0); \ _mm_store_sd((s), XMM2); \ } arithmetic_sse_float.h000066400000000000000000000211641321604176500315750ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/lib/* * SSE/SSE3 implementation of vector oprations (32bit float). * * Copyright (c) 2007-2010 Naoaki Okazaki * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* $Id: arithmetic_sse_float.h 65 2010-01-29 12:19:16Z naoaki $ */ #include #include #include #if 1400 <= _MSC_VER #include #endif/*_MSC_VER*/ #if HAVE_XMMINTRIN_H #include #endif/*HAVE_XMMINTRIN_H*/ #if LBFGS_FLOAT == 32 && LBFGS_IEEE_FLOAT #define fsigndiff(x, y) (((*(uint32_t*)(x)) ^ (*(uint32_t*)(y))) & 0x80000000U) #else #define fsigndiff(x, y) (*(x) * (*(y) / fabs(*(y))) < 0.) #endif/*LBFGS_IEEE_FLOAT*/ inline static void* vecalloc(size_t size) { void *memblock = _aligned_malloc(size, 16); if (memblock != NULL) { memset(memblock, 0, size); } return memblock; } inline static void vecfree(void *memblock) { _aligned_free(memblock); } #define vecset(x, c, n) \ { \ int i; \ __m128 XMM0 = _mm_set_ps1(c); \ for (i = 0;i < (n);i += 16) { \ _mm_store_ps((x)+i , XMM0); \ _mm_store_ps((x)+i+ 4, XMM0); \ _mm_store_ps((x)+i+ 8, XMM0); \ _mm_store_ps((x)+i+12, XMM0); \ } \ } #define veccpy(y, x, n) \ { \ int i; \ for (i = 0;i < (n);i += 16) { \ __m128 XMM0 = _mm_load_ps((x)+i ); \ __m128 XMM1 = _mm_load_ps((x)+i+ 4); \ __m128 XMM2 = _mm_load_ps((x)+i+ 8); \ __m128 XMM3 = _mm_load_ps((x)+i+12); \ _mm_store_ps((y)+i , XMM0); \ _mm_store_ps((y)+i+ 4, XMM1); \ _mm_store_ps((y)+i+ 8, XMM2); \ _mm_store_ps((y)+i+12, XMM3); \ } \ } #define vecncpy(y, x, n) \ { \ int i; \ const uint32_t mask = 0x80000000; \ __m128 XMM4 = _mm_load_ps1((float*)&mask); \ for (i = 0;i < (n);i += 16) { \ __m128 XMM0 = _mm_load_ps((x)+i ); \ __m128 XMM1 = _mm_load_ps((x)+i+ 4); \ __m128 XMM2 = _mm_load_ps((x)+i+ 8); \ __m128 XMM3 = _mm_load_ps((x)+i+12); \ XMM0 = _mm_xor_ps(XMM0, XMM4); \ XMM1 = _mm_xor_ps(XMM1, XMM4); \ XMM2 = _mm_xor_ps(XMM2, XMM4); \ XMM3 = _mm_xor_ps(XMM3, XMM4); \ _mm_store_ps((y)+i , XMM0); \ _mm_store_ps((y)+i+ 4, XMM1); \ _mm_store_ps((y)+i+ 8, XMM2); \ _mm_store_ps((y)+i+12, XMM3); \ } \ } #define vecadd(y, x, c, n) \ { \ int i; \ __m128 XMM7 = _mm_set_ps1(c); \ for (i = 0;i < (n);i += 8) { \ __m128 XMM0 = _mm_load_ps((x)+i ); \ __m128 XMM1 = _mm_load_ps((x)+i+4); \ __m128 XMM2 = _mm_load_ps((y)+i ); \ __m128 XMM3 = _mm_load_ps((y)+i+4); \ XMM0 = _mm_mul_ps(XMM0, XMM7); \ XMM1 = _mm_mul_ps(XMM1, XMM7); \ XMM2 = _mm_add_ps(XMM2, XMM0); \ XMM3 = _mm_add_ps(XMM3, XMM1); \ _mm_store_ps((y)+i , XMM2); \ _mm_store_ps((y)+i+4, XMM3); \ } \ } #define vecdiff(z, x, y, n) \ { \ int i; \ for (i = 0;i < (n);i += 16) { \ __m128 XMM0 = _mm_load_ps((x)+i ); \ __m128 XMM1 = _mm_load_ps((x)+i+ 4); \ __m128 XMM2 = _mm_load_ps((x)+i+ 8); \ __m128 XMM3 = _mm_load_ps((x)+i+12); \ __m128 XMM4 = _mm_load_ps((y)+i ); \ __m128 XMM5 = _mm_load_ps((y)+i+ 4); \ __m128 XMM6 = _mm_load_ps((y)+i+ 8); \ __m128 XMM7 = _mm_load_ps((y)+i+12); \ XMM0 = _mm_sub_ps(XMM0, XMM4); \ XMM1 = _mm_sub_ps(XMM1, XMM5); \ XMM2 = _mm_sub_ps(XMM2, XMM6); \ XMM3 = _mm_sub_ps(XMM3, XMM7); \ _mm_store_ps((z)+i , XMM0); \ _mm_store_ps((z)+i+ 4, XMM1); \ _mm_store_ps((z)+i+ 8, XMM2); \ _mm_store_ps((z)+i+12, XMM3); \ } \ } #define vecscale(y, c, n) \ { \ int i; \ __m128 XMM7 = _mm_set_ps1(c); \ for (i = 0;i < (n);i += 8) { \ __m128 XMM0 = _mm_load_ps((y)+i ); \ __m128 XMM1 = _mm_load_ps((y)+i+4); \ XMM0 = _mm_mul_ps(XMM0, XMM7); \ XMM1 = _mm_mul_ps(XMM1, XMM7); \ _mm_store_ps((y)+i , XMM0); \ _mm_store_ps((y)+i+4, XMM1); \ } \ } #define vecmul(y, x, n) \ { \ int i; \ for (i = 0;i < (n);i += 16) { \ __m128 XMM0 = _mm_load_ps((x)+i ); \ __m128 XMM1 = _mm_load_ps((x)+i+ 4); \ __m128 XMM2 = _mm_load_ps((x)+i+ 8); \ __m128 XMM3 = _mm_load_ps((x)+i+12); \ __m128 XMM4 = _mm_load_ps((y)+i ); \ __m128 XMM5 = _mm_load_ps((y)+i+ 4); \ __m128 XMM6 = _mm_load_ps((y)+i+ 8); \ __m128 XMM7 = _mm_load_ps((y)+i+12); \ XMM4 = _mm_mul_ps(XMM4, XMM0); \ XMM5 = _mm_mul_ps(XMM5, XMM1); \ XMM6 = _mm_mul_ps(XMM6, XMM2); \ XMM7 = _mm_mul_ps(XMM7, XMM3); \ _mm_store_ps((y)+i , XMM4); \ _mm_store_ps((y)+i+ 4, XMM5); \ _mm_store_ps((y)+i+ 8, XMM6); \ _mm_store_ps((y)+i+12, XMM7); \ } \ } #if 3 <= __SSE__ /* Horizontal add with haddps SSE3 instruction. The work register (rw) is unused. */ #define __horizontal_sum(r, rw) \ r = _mm_hadd_ps(r, r); \ r = _mm_hadd_ps(r, r); #else /* Horizontal add with SSE instruction. The work register (rw) is used. */ #define __horizontal_sum(r, rw) \ rw = r; \ r = _mm_shuffle_ps(r, rw, _MM_SHUFFLE(1, 0, 3, 2)); \ r = _mm_add_ps(r, rw); \ rw = r; \ r = _mm_shuffle_ps(r, rw, _MM_SHUFFLE(2, 3, 0, 1)); \ r = _mm_add_ps(r, rw); #endif #define vecdot(s, x, y, n) \ { \ int i; \ __m128 XMM0 = _mm_setzero_ps(); \ __m128 XMM1 = _mm_setzero_ps(); \ __m128 XMM2, XMM3, XMM4, XMM5; \ for (i = 0;i < (n);i += 8) { \ XMM2 = _mm_load_ps((x)+i ); \ XMM3 = _mm_load_ps((x)+i+4); \ XMM4 = _mm_load_ps((y)+i ); \ XMM5 = _mm_load_ps((y)+i+4); \ XMM2 = _mm_mul_ps(XMM2, XMM4); \ XMM3 = _mm_mul_ps(XMM3, XMM5); \ XMM0 = _mm_add_ps(XMM0, XMM2); \ XMM1 = _mm_add_ps(XMM1, XMM3); \ } \ XMM0 = _mm_add_ps(XMM0, XMM1); \ __horizontal_sum(XMM0, XMM1); \ _mm_store_ss((s), XMM0); \ } #define vec2norm(s, x, n) \ { \ int i; \ __m128 XMM0 = _mm_setzero_ps(); \ __m128 XMM1 = _mm_setzero_ps(); \ __m128 XMM2, XMM3; \ for (i = 0;i < (n);i += 8) { \ XMM2 = _mm_load_ps((x)+i ); \ XMM3 = _mm_load_ps((x)+i+4); \ XMM2 = _mm_mul_ps(XMM2, XMM2); \ XMM3 = _mm_mul_ps(XMM3, XMM3); \ XMM0 = _mm_add_ps(XMM0, XMM2); \ XMM1 = _mm_add_ps(XMM1, XMM3); \ } \ XMM0 = _mm_add_ps(XMM0, XMM1); \ __horizontal_sum(XMM0, XMM1); \ XMM2 = XMM0; \ XMM1 = _mm_rsqrt_ss(XMM0); \ XMM3 = XMM1; \ XMM1 = _mm_mul_ss(XMM1, XMM1); \ XMM1 = _mm_mul_ss(XMM1, XMM3); \ XMM1 = _mm_mul_ss(XMM1, XMM0); \ XMM1 = _mm_mul_ss(XMM1, _mm_set_ss(-0.5f)); \ XMM3 = _mm_mul_ss(XMM3, _mm_set_ss(1.5f)); \ XMM3 = _mm_add_ss(XMM3, XMM1); \ XMM3 = _mm_mul_ss(XMM3, XMM2); \ _mm_store_ss((s), XMM3); \ } #define vec2norminv(s, x, n) \ { \ int i; \ __m128 XMM0 = _mm_setzero_ps(); \ __m128 XMM1 = _mm_setzero_ps(); \ __m128 XMM2, XMM3; \ for (i = 0;i < (n);i += 16) { \ XMM2 = _mm_load_ps((x)+i ); \ XMM3 = _mm_load_ps((x)+i+4); \ XMM2 = _mm_mul_ps(XMM2, XMM2); \ XMM3 = _mm_mul_ps(XMM3, XMM3); \ XMM0 = _mm_add_ps(XMM0, XMM2); \ XMM1 = _mm_add_ps(XMM1, XMM3); \ } \ XMM0 = _mm_add_ps(XMM0, XMM1); \ __horizontal_sum(XMM0, XMM1); \ XMM2 = XMM0; \ XMM1 = _mm_rsqrt_ss(XMM0); \ XMM3 = XMM1; \ XMM1 = _mm_mul_ss(XMM1, XMM1); \ XMM1 = _mm_mul_ss(XMM1, XMM3); \ XMM1 = _mm_mul_ss(XMM1, XMM0); \ XMM1 = _mm_mul_ss(XMM1, _mm_set_ss(-0.5f)); \ XMM3 = _mm_mul_ss(XMM3, _mm_set_ss(1.5f)); \ XMM3 = _mm_add_ss(XMM3, XMM1); \ _mm_store_ss((s), XMM3); \ } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/lib/lbfgs.c000066400000000000000000001227131321604176500265560ustar00rootroot00000000000000/* * Limited memory BFGS (L-BFGS). * * Copyright (c) 1990, Jorge Nocedal * Copyright (c) 2007-2010 Naoaki Okazaki * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* $Id: lbfgs.c 65 2010-01-29 12:19:16Z naoaki $ */ /* This library is a C port of the FORTRAN implementation of Limited-memory Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) method written by Jorge Nocedal. The original FORTRAN source code is available at: http://www.ece.northwestern.edu/~nocedal/lbfgs.html The L-BFGS algorithm is described in: - Jorge Nocedal. Updating Quasi-Newton Matrices with Limited Storage. Mathematics of Computation, Vol. 35, No. 151, pp. 773--782, 1980. - Dong C. Liu and Jorge Nocedal. On the limited memory BFGS method for large scale optimization. Mathematical Programming B, Vol. 45, No. 3, pp. 503-528, 1989. The line search algorithms used in this implementation are described in: - John E. Dennis and Robert B. Schnabel. Numerical Methods for Unconstrained Optimization and Nonlinear Equations, Englewood Cliffs, 1983. - Jorge J. More and David J. Thuente. Line search algorithm with guaranteed sufficient decrease. ACM Transactions on Mathematical Software (TOMS), Vol. 20, No. 3, pp. 286-307, 1994. This library also implements Orthant-Wise Limited-memory Quasi-Newton (OWL-QN) method presented in: - Galen Andrew and Jianfeng Gao. Scalable training of L1-regularized log-linear models. In Proceedings of the 24th International Conference on Machine Learning (ICML 2007), pp. 33-40, 2007. I would like to thank the original author, Jorge Nocedal, who has been distributing the effieicnt and explanatory implementation in an open source licence. */ #ifdef HAVE_CONFIG_H #include #endif/*HAVE_CONFIG_H*/ #include #include #include #include #ifdef _MSC_VER #define inline __inline typedef unsigned int uint32_t; #endif/*_MSC_VER*/ #if defined(USE_SSE) && defined(__SSE2__) && LBFGS_FLOAT == 64 /* Use SSE2 optimization for 64bit double precision. */ #include "arithmetic_sse_double.h" #elif defined(USE_SSE) && defined(__SSE__) && LBFGS_FLOAT == 32 /* Use SSE optimization for 32bit float precision. */ #include "arithmetic_sse_float.h" #else /* No CPU specific optimization. */ #include "arithmetic_ansi.h" #endif #define min2(a, b) ((a) <= (b) ? (a) : (b)) #define max2(a, b) ((a) >= (b) ? (a) : (b)) #define max3(a, b, c) max2(max2((a), (b)), (c)); struct tag_callback_data { int n; void *instance; lbfgs_evaluate_t proc_evaluate; lbfgs_progress_t proc_progress; }; typedef struct tag_callback_data callback_data_t; struct tag_iteration_data { lbfgsfloatval_t alpha; lbfgsfloatval_t *s; /* [n] */ lbfgsfloatval_t *y; /* [n] */ lbfgsfloatval_t ys; /* vecdot(y, s) */ }; typedef struct tag_iteration_data iteration_data_t; static const lbfgs_parameter_t _defparam = { 6, 1e-5, 0, 1e-5, 0, LBFGS_LINESEARCH_DEFAULT, 40, 1e-20, 1e20, 1e-4, 0.9, 0.9, 1.0e-16, 0.0, 0, -1, }; /* Forward function declarations. */ typedef int (*line_search_proc)( int n, lbfgsfloatval_t *x, lbfgsfloatval_t *f, lbfgsfloatval_t *g, lbfgsfloatval_t *s, lbfgsfloatval_t *stp, const lbfgsfloatval_t* xp, const lbfgsfloatval_t* gp, lbfgsfloatval_t *wa, callback_data_t *cd, const lbfgs_parameter_t *param ); static int line_search_backtracking( int n, lbfgsfloatval_t *x, lbfgsfloatval_t *f, lbfgsfloatval_t *g, lbfgsfloatval_t *s, lbfgsfloatval_t *stp, const lbfgsfloatval_t* xp, const lbfgsfloatval_t* gp, lbfgsfloatval_t *wa, callback_data_t *cd, const lbfgs_parameter_t *param ); static int line_search_backtracking_owlqn( int n, lbfgsfloatval_t *x, lbfgsfloatval_t *f, lbfgsfloatval_t *g, lbfgsfloatval_t *s, lbfgsfloatval_t *stp, const lbfgsfloatval_t* xp, const lbfgsfloatval_t* gp, lbfgsfloatval_t *wp, callback_data_t *cd, const lbfgs_parameter_t *param ); static int line_search_morethuente( int n, lbfgsfloatval_t *x, lbfgsfloatval_t *f, lbfgsfloatval_t *g, lbfgsfloatval_t *s, lbfgsfloatval_t *stp, const lbfgsfloatval_t* xp, const lbfgsfloatval_t* gp, lbfgsfloatval_t *wa, callback_data_t *cd, const lbfgs_parameter_t *param ); static int update_trial_interval( lbfgsfloatval_t *x, lbfgsfloatval_t *fx, lbfgsfloatval_t *dx, lbfgsfloatval_t *y, lbfgsfloatval_t *fy, lbfgsfloatval_t *dy, lbfgsfloatval_t *t, lbfgsfloatval_t *ft, lbfgsfloatval_t *dt, const lbfgsfloatval_t tmin, const lbfgsfloatval_t tmax, int *brackt ); static lbfgsfloatval_t owlqn_x1norm( const lbfgsfloatval_t* x, const int start, const int n ); static void owlqn_pseudo_gradient( lbfgsfloatval_t* pg, const lbfgsfloatval_t* x, const lbfgsfloatval_t* g, const int n, const lbfgsfloatval_t c, const int start, const int end ); static void owlqn_project( lbfgsfloatval_t* d, const lbfgsfloatval_t* sign, const int start, const int end ); #if defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__)) static int round_out_variables(int n) { n += 7; n /= 8; n *= 8; return n; } #endif/*defined(USE_SSE)*/ lbfgsfloatval_t* lbfgs_malloc(int n) { #if defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__)) n = round_out_variables(n); #endif/*defined(USE_SSE)*/ return (lbfgsfloatval_t*)vecalloc(sizeof(lbfgsfloatval_t) * n); } void lbfgs_free(lbfgsfloatval_t *x) { vecfree(x); } void lbfgs_parameter_init(lbfgs_parameter_t *param) { memcpy(param, &_defparam, sizeof(*param)); } /******************************************************************/ /* JAS 2011.11.03 * Making k global was the easiest way to make it available to * line_search_morethuente due to the callback architecture. * I didn't want to reprototype all the callbacks... Sorry. * * Needed to make liblbfgs report on every morethuente evaluation * in order to enforce max_feval */ int k; /******************************************************************/ int lbfgs( int n, lbfgsfloatval_t *x, lbfgsfloatval_t *ptr_fx, lbfgs_evaluate_t proc_evaluate, lbfgs_progress_t proc_progress, void *instance, lbfgs_parameter_t *_param ) { int ret; int i, j, /* k, */ ls, end, bound; lbfgsfloatval_t step; /* Constant parameters and their default values. */ lbfgs_parameter_t param = (_param != NULL) ? (*_param) : _defparam; const int m = param.m; lbfgsfloatval_t *xp = NULL; lbfgsfloatval_t *g = NULL, *gp = NULL, *pg = NULL; lbfgsfloatval_t *d = NULL, *w = NULL, *pf = NULL; iteration_data_t *lm = NULL, *it = NULL; lbfgsfloatval_t ys, yy; lbfgsfloatval_t xnorm, gnorm, beta; lbfgsfloatval_t fx = 0.; lbfgsfloatval_t rate = 0.; line_search_proc linesearch = line_search_morethuente; /* Construct a callback data. */ callback_data_t cd; cd.n = n; cd.instance = instance; cd.proc_evaluate = proc_evaluate; cd.proc_progress = proc_progress; #if defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__)) /* Round out the number of variables. */ n = round_out_variables(n); #endif/*defined(USE_SSE)*/ /* Check the input parameters for errors. */ if (n <= 0) { return LBFGSERR_INVALID_N; } #if defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__)) if (n % 8 != 0) { return LBFGSERR_INVALID_N_SSE; } if (((unsigned short)x & 0x000F) != 0) { return LBFGSERR_INVALID_X_SSE; } #endif/*defined(USE_SSE)*/ if (param.epsilon < 0.) { return LBFGSERR_INVALID_EPSILON; } if (param.past < 0) { return LBFGSERR_INVALID_TESTPERIOD; } if (param.delta < 0.) { return LBFGSERR_INVALID_DELTA; } if (param.min_step < 0.) { return LBFGSERR_INVALID_MINSTEP; } if (param.max_step < param.min_step) { return LBFGSERR_INVALID_MAXSTEP; } if (param.ftol < 0.) { return LBFGSERR_INVALID_FTOL; } if (param.linesearch == LBFGS_LINESEARCH_BACKTRACKING_WOLFE || param.linesearch == LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE) { if (param.wolfe <= param.ftol || 1. <= param.wolfe) { return LBFGSERR_INVALID_WOLFE; } } if (param.gtol < 0.) { return LBFGSERR_INVALID_GTOL; } if (param.xtol < 0.) { return LBFGSERR_INVALID_XTOL; } if (param.max_linesearch <= 0) { return LBFGSERR_INVALID_MAXLINESEARCH; } if (param.orthantwise_c < 0.) { return LBFGSERR_INVALID_ORTHANTWISE; } if (param.orthantwise_start < 0 || n < param.orthantwise_start) { return LBFGSERR_INVALID_ORTHANTWISE_START; } if (param.orthantwise_end < 0) { param.orthantwise_end = n; } if (n < param.orthantwise_end) { return LBFGSERR_INVALID_ORTHANTWISE_END; } if (param.orthantwise_c != 0.) { switch (param.linesearch) { case LBFGS_LINESEARCH_BACKTRACKING: linesearch = line_search_backtracking_owlqn; break; default: /* Only the backtracking method is available. */ return LBFGSERR_INVALID_LINESEARCH; } } else { switch (param.linesearch) { case LBFGS_LINESEARCH_MORETHUENTE: linesearch = line_search_morethuente; break; case LBFGS_LINESEARCH_BACKTRACKING_ARMIJO: case LBFGS_LINESEARCH_BACKTRACKING_WOLFE: case LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE: linesearch = line_search_backtracking; break; default: return LBFGSERR_INVALID_LINESEARCH; } } /* Allocate working space. */ xp = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); g = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); gp = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); d = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); w = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); if (xp == NULL || g == NULL || gp == NULL || d == NULL || w == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } if (param.orthantwise_c != 0.) { /* Allocate working space for OW-LQN. */ pg = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); if (pg == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } } /* Allocate limited memory storage. */ lm = (iteration_data_t*)vecalloc(m * sizeof(iteration_data_t)); if (lm == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } /* Initialize the limited memory. */ for (i = 0;i < m;++i) { it = &lm[i]; it->alpha = 0; it->ys = 0; it->s = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); it->y = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); if (it->s == NULL || it->y == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } } /* Allocate an array for storing previous values of the objective function. */ if (0 < param.past) { pf = (lbfgsfloatval_t*)vecalloc(param.past * sizeof(lbfgsfloatval_t)); } /* Evaluate the function value and its gradient. */ fx = cd.proc_evaluate(cd.instance, x, g, cd.n, 0); if (0. != param.orthantwise_c) { /* Compute the L1 norm of the variable and add it to the object value. */ xnorm = owlqn_x1norm(x, param.orthantwise_start, param.orthantwise_end); fx += xnorm * param.orthantwise_c; owlqn_pseudo_gradient( pg, x, g, n, param.orthantwise_c, param.orthantwise_start, param.orthantwise_end ); } /* Store the initial value of the objective function. */ if (pf != NULL) { pf[0] = fx; } /* Compute the direction; we assume the initial hessian matrix H_0 as the identity matrix. */ if (param.orthantwise_c == 0.) { vecncpy(d, g, n); } else { vecncpy(d, pg, n); } /* Make sure that the initial variables are not a minimizer. */ vec2norm(&xnorm, x, n); if (param.orthantwise_c == 0.) { vec2norm(&gnorm, g, n); } else { vec2norm(&gnorm, pg, n); } if (xnorm < 1.0) xnorm = 1.0; if (gnorm / xnorm <= param.epsilon) { ret = LBFGS_ALREADY_MINIMIZED; goto lbfgs_exit; } /* Compute the initial step: step = 1.0 / sqrt(vecdot(d, d, n)) */ vec2norminv(&step, d, n); k = 1; end = 0; for (;;) { /* Store the current position and gradient vectors. */ veccpy(xp, x, n); veccpy(gp, g, n); /* Search for an optimal step. */ if (param.orthantwise_c == 0.) { ls = linesearch(n, x, &fx, g, d, &step, xp, gp, w, &cd, ¶m); } else { ls = linesearch(n, x, &fx, g, d, &step, xp, pg, w, &cd, ¶m); owlqn_pseudo_gradient( pg, x, g, n, param.orthantwise_c, param.orthantwise_start, param.orthantwise_end ); } if (ls < 0) { /* Revert to the previous point. */ veccpy(x, xp, n); veccpy(g, gp, n); ret = ls; goto lbfgs_exit; } /* Compute x and g norms. */ vec2norm(&xnorm, x, n); if (param.orthantwise_c == 0.) { vec2norm(&gnorm, g, n); } else { vec2norm(&gnorm, pg, n); } /* Report the progress. */ if (cd.proc_progress) { if (ret = cd.proc_progress(cd.instance, x, g, fx, xnorm, gnorm, step, cd.n, k, ls)) { goto lbfgs_exit; } } /* Convergence test. The criterion is given by the following formula: |g(x)| / \max(1, |x|) < \epsilon */ if (xnorm < 1.0) xnorm = 1.0; if (gnorm / xnorm <= param.epsilon) { /* Convergence. */ ret = LBFGS_SUCCESS; break; } /* Test for stopping criterion. The criterion is given by the following formula: (f(past_x) - f(x)) / f(x) < \delta */ if (pf != NULL) { /* We don't test the stopping criterion while k < past. */ if (param.past <= k) { /* Compute the relative improvement from the past. */ rate = (pf[k % param.past] - fx) / fx; /* The stopping criterion. */ if (rate < param.delta) { ret = LBFGS_STOP; break; } } /* Store the current value of the objective function. */ pf[k % param.past] = fx; } if (param.max_iterations != 0 && param.max_iterations < k+1) { /* Maximum number of iterations. */ ret = LBFGSERR_MAXIMUMITERATION; break; } /* Update vectors s and y: s_{k+1} = x_{k+1} - x_{k} = \step * d_{k}. y_{k+1} = g_{k+1} - g_{k}. */ it = &lm[end]; vecdiff(it->s, x, xp, n); vecdiff(it->y, g, gp, n); /* Compute scalars ys and yy: ys = y^t \cdot s = 1 / \rho. yy = y^t \cdot y. Notice that yy is used for scaling the hessian matrix H_0 (Cholesky factor). */ vecdot(&ys, it->y, it->s, n); vecdot(&yy, it->y, it->y, n); it->ys = ys; /* Recursive formula to compute dir = -(H \cdot g). This is described in page 779 of: Jorge Nocedal. Updating Quasi-Newton Matrices with Limited Storage. Mathematics of Computation, Vol. 35, No. 151, pp. 773--782, 1980. */ bound = (m <= k) ? m : k; ++k; end = (end + 1) % m; /* Compute the steepest direction. */ if (param.orthantwise_c == 0.) { /* Compute the negative of gradients. */ vecncpy(d, g, n); } else { vecncpy(d, pg, n); } j = end; for (i = 0;i < bound;++i) { j = (j + m - 1) % m; /* if (--j == -1) j = m-1; */ it = &lm[j]; /* \alpha_{j} = \rho_{j} s^{t}_{j} \cdot q_{k+1}. */ vecdot(&it->alpha, it->s, d, n); it->alpha /= it->ys; /* q_{i} = q_{i+1} - \alpha_{i} y_{i}. */ vecadd(d, it->y, -it->alpha, n); } vecscale(d, ys / yy, n); for (i = 0;i < bound;++i) { it = &lm[j]; /* \beta_{j} = \rho_{j} y^t_{j} \cdot \gamma_{i}. */ vecdot(&beta, it->y, d, n); beta /= it->ys; /* \gamma_{i+1} = \gamma_{i} + (\alpha_{j} - \beta_{j}) s_{j}. */ vecadd(d, it->s, it->alpha - beta, n); j = (j + 1) % m; /* if (++j == m) j = 0; */ } /* Constrain the search direction for orthant-wise updates. */ if (param.orthantwise_c != 0.) { for (i = param.orthantwise_start;i < param.orthantwise_end;++i) { if (d[i] * pg[i] >= 0) { d[i] = 0; } } } /* Now the search direction d is ready. We try step = 1 first. */ step = 1.0; } lbfgs_exit: /* Return the final value of the objective function. */ if (ptr_fx != NULL) { *ptr_fx = fx; } vecfree(pf); /* Free memory blocks used by this function. */ if (lm != NULL) { for (i = 0;i < m;++i) { vecfree(lm[i].s); vecfree(lm[i].y); } vecfree(lm); } vecfree(pg); vecfree(w); vecfree(d); vecfree(gp); vecfree(g); vecfree(xp); return ret; } static int line_search_backtracking( int n, lbfgsfloatval_t *x, lbfgsfloatval_t *f, lbfgsfloatval_t *g, lbfgsfloatval_t *s, lbfgsfloatval_t *stp, const lbfgsfloatval_t* xp, const lbfgsfloatval_t* gp, lbfgsfloatval_t *wp, callback_data_t *cd, const lbfgs_parameter_t *param ) { int ret = 0, count = 0; lbfgsfloatval_t width, dg, norm = 0.; lbfgsfloatval_t finit, dginit = 0., dgtest; const lbfgsfloatval_t dec = 0.5, inc = 2.1; /* Check the input parameters for errors. */ if (*stp <= 0.) { return LBFGSERR_INVALIDPARAMETERS; } /* Compute the initial gradient in the search direction. */ vecdot(&dginit, g, s, n); /* Make sure that s points to a descent direction. */ if (0 < dginit) { return LBFGSERR_INCREASEGRADIENT; } /* The initial value of the objective function. */ finit = *f; dgtest = param->ftol * dginit; for (;;) { veccpy(x, xp, n); vecadd(x, s, *stp, n); /* Evaluate the function and gradient values. */ *f = cd->proc_evaluate(cd->instance, x, g, cd->n, *stp); ++count; if (*f > finit + *stp * dgtest) { width = dec; } else { /* The sufficient decrease condition (Armijo condition). */ if (param->linesearch == LBFGS_LINESEARCH_BACKTRACKING_ARMIJO) { /* Exit with the Armijo condition. */ return count; } /* Check the Wolfe condition. */ vecdot(&dg, g, s, n); if (dg < param->wolfe * dginit) { width = inc; } else { if(param->linesearch == LBFGS_LINESEARCH_BACKTRACKING_WOLFE) { /* Exit with the regular Wolfe condition. */ return count; } /* Check the strong Wolfe condition. */ if(dg > -param->wolfe * dginit) { width = dec; } else { /* Exit with the strong Wolfe condition. */ return count; } } } if (*stp < param->min_step) { /* The step is the minimum value. */ return LBFGSERR_MINIMUMSTEP; } if (*stp > param->max_step) { /* The step is the maximum value. */ return LBFGSERR_MAXIMUMSTEP; } if (param->max_linesearch <= count) { /* Maximum number of iteration. */ return LBFGSERR_MAXIMUMLINESEARCH; } (*stp) *= width; } } static int line_search_backtracking_owlqn( int n, lbfgsfloatval_t *x, lbfgsfloatval_t *f, lbfgsfloatval_t *g, lbfgsfloatval_t *s, lbfgsfloatval_t *stp, const lbfgsfloatval_t* xp, const lbfgsfloatval_t* gp, lbfgsfloatval_t *wp, callback_data_t *cd, const lbfgs_parameter_t *param ) { int i, ret = 0, count = 0; lbfgsfloatval_t width = 0.5, norm = 0.; lbfgsfloatval_t finit = *f, dgtest; /* Check the input parameters for errors. */ if (*stp <= 0.) { return LBFGSERR_INVALIDPARAMETERS; } /* Choose the orthant for the new point. */ for (i = 0;i < n;++i) { wp[i] = (xp[i] == 0.) ? -gp[i] : xp[i]; } for (;;) { /* Update the current point. */ veccpy(x, xp, n); vecadd(x, s, *stp, n); /* The current point is projected onto the orthant. */ owlqn_project(x, wp, param->orthantwise_start, param->orthantwise_end); /* Evaluate the function and gradient values. */ *f = cd->proc_evaluate(cd->instance, x, g, cd->n, *stp); /* Compute the L1 norm of the variables and add it to the object value. */ norm = owlqn_x1norm(x, param->orthantwise_start, param->orthantwise_end); *f += norm * param->orthantwise_c; ++count; dgtest = 0.; for (i = 0;i < n;++i) { dgtest += (x[i] - xp[i]) * gp[i]; } if (*f <= finit + param->ftol * dgtest) { /* The sufficient decrease condition. */ return count; } if (*stp < param->min_step) { /* The step is the minimum value. */ return LBFGSERR_MINIMUMSTEP; } if (*stp > param->max_step) { /* The step is the maximum value. */ return LBFGSERR_MAXIMUMSTEP; } if (param->max_linesearch <= count) { /* Maximum number of iteration. */ return LBFGSERR_MAXIMUMLINESEARCH; } (*stp) *= width; } } static int line_search_morethuente( int n, lbfgsfloatval_t *x, lbfgsfloatval_t *f, lbfgsfloatval_t *g, lbfgsfloatval_t *s, lbfgsfloatval_t *stp, const lbfgsfloatval_t* xp, const lbfgsfloatval_t* gp, lbfgsfloatval_t *wa, callback_data_t *cd, const lbfgs_parameter_t *param ) { int count = 0; int brackt, stage1, uinfo = 0; lbfgsfloatval_t dg; lbfgsfloatval_t stx, fx, dgx; lbfgsfloatval_t sty, fy, dgy; lbfgsfloatval_t fxm, dgxm, fym, dgym, fm, dgm; lbfgsfloatval_t finit, ftest1, dginit, dgtest; lbfgsfloatval_t width, prev_width; lbfgsfloatval_t stmin, stmax; /******************************************************************/ /* JAS 2011.11.03 * Used to make liblbfgs report on every morethuente evaluation */ lbfgsfloatval_t xnorm, gnorm; /******************************************************************/ /* Check the input parameters for errors. */ if (*stp <= 0.) { return LBFGSERR_INVALIDPARAMETERS; } /* Compute the initial gradient in the search direction. */ vecdot(&dginit, g, s, n); /* Make sure that s points to a descent direction. */ if (0 < dginit) { return LBFGSERR_INCREASEGRADIENT; } /* Initialize local variables. */ brackt = 0; stage1 = 1; finit = *f; dgtest = param->ftol * dginit; width = param->max_step - param->min_step; prev_width = 2.0 * width; /* The variables stx, fx, dgx contain the values of the step, function, and directional derivative at the best step. The variables sty, fy, dgy contain the value of the step, function, and derivative at the other endpoint of the interval of uncertainty. The variables stp, f, dg contain the values of the step, function, and derivative at the current step. */ stx = sty = 0.; fx = fy = finit; dgx = dgy = dginit; for (;;) { /* Set the minimum and maximum steps to correspond to the present interval of uncertainty. */ if (brackt) { stmin = min2(stx, sty); stmax = max2(stx, sty); } else { stmin = stx; stmax = *stp + 4.0 * (*stp - stx); } /* Clip the step in the range of [stpmin, stpmax]. */ if (*stp < param->min_step) *stp = param->min_step; if (param->max_step < *stp) *stp = param->max_step; /* If an unusual termination is to occur then let stp be the lowest point obtained so far. */ if ((brackt && ((*stp <= stmin || stmax <= *stp) || param->max_linesearch <= count + 1 || uinfo != 0)) || (brackt && (stmax - stmin <= param->xtol * stmax))) { *stp = stx; } /* Compute the current value of x: x <- x + (*stp) * s. */ veccpy(x, xp, n); vecadd(x, s, *stp, n); /* Evaluate the function and gradient values. */ *f = cd->proc_evaluate(cd->instance, x, g, cd->n, *stp); vecdot(&dg, g, s, n); /******************************************************************/ /* JAS 2011.11.03 * Used to make liblbfgs report on every morethuente evaluation * so that max_feval can be encfored */ /* Compute x and g norms. */ vec2norm(&xnorm, x, n); vec2norm(&gnorm, g, n); if (cd->proc_progress) { /* plm does not use ls, so setting it to zero should be ok */ if (cd->proc_progress(cd->instance, x, g, fx, xnorm, gnorm, *stp, cd->n, k, 0)) { return LBFGSERR_MAXIMUMLINESEARCH; } } /******************************************************************/ ftest1 = finit + *stp * dgtest; ++count; /* Test for errors and convergence. */ if (brackt && ((*stp <= stmin || stmax <= *stp) || uinfo != 0)) { /* Rounding errors prevent further progress. */ return LBFGSERR_ROUNDING_ERROR; } if (*stp == param->max_step && *f <= ftest1 && dg <= dgtest) { /* The step is the maximum value. */ return LBFGSERR_MAXIMUMSTEP; } if (*stp == param->min_step && (ftest1 < *f || dgtest <= dg)) { /* The step is the minimum value. */ return LBFGSERR_MINIMUMSTEP; } if (brackt && (stmax - stmin) <= param->xtol * stmax) { /* Relative width of the interval of uncertainty is at most xtol. */ return LBFGSERR_WIDTHTOOSMALL; } if (param->max_linesearch <= count) { /* Maximum number of iteration. */ return LBFGSERR_MAXIMUMLINESEARCH; } if (*f <= ftest1 && fabs(dg) <= param->gtol * (-dginit)) { /* The sufficient decrease condition and the directional derivative condition hold. */ return count; } /* In the first stage we seek a step for which the modified function has a nonpositive value and nonnegative derivative. */ if (stage1 && *f <= ftest1 && min2(param->ftol, param->gtol) * dginit <= dg) { stage1 = 0; } /* A modified function is used to predict the step only if we have not obtained a step for which the modified function has a nonpositive function value and nonnegative derivative, and if a lower function value has been obtained but the decrease is not sufficient. */ if (stage1 && ftest1 < *f && *f <= fx) { /* Define the modified function and derivative values. */ fm = *f - *stp * dgtest; fxm = fx - stx * dgtest; fym = fy - sty * dgtest; dgm = dg - dgtest; dgxm = dgx - dgtest; dgym = dgy - dgtest; /* Call update_trial_interval() to update the interval of uncertainty and to compute the new step. */ uinfo = update_trial_interval( &stx, &fxm, &dgxm, &sty, &fym, &dgym, stp, &fm, &dgm, stmin, stmax, &brackt ); /* Reset the function and gradient values for f. */ fx = fxm + stx * dgtest; fy = fym + sty * dgtest; dgx = dgxm + dgtest; dgy = dgym + dgtest; } else { /* Call update_trial_interval() to update the interval of uncertainty and to compute the new step. */ uinfo = update_trial_interval( &stx, &fx, &dgx, &sty, &fy, &dgy, stp, f, &dg, stmin, stmax, &brackt ); } /* Force a sufficient decrease in the interval of uncertainty. */ if (brackt) { if (0.66 * prev_width <= fabs(sty - stx)) { *stp = stx + 0.5 * (sty - stx); } prev_width = width; width = fabs(sty - stx); } } return LBFGSERR_LOGICERROR; } /** * Define the local variables for computing minimizers. */ #define USES_MINIMIZER \ lbfgsfloatval_t a, d, gamma, theta, p, q, r, s; /** * Find a minimizer of an interpolated cubic function. * @param cm The minimizer of the interpolated cubic. * @param u The value of one point, u. * @param fu The value of f(u). * @param du The value of f'(u). * @param v The value of another point, v. * @param fv The value of f(v). * @param du The value of f'(v). */ #define CUBIC_MINIMIZER(cm, u, fu, du, v, fv, dv) \ d = (v) - (u); \ theta = ((fu) - (fv)) * 3 / d + (du) + (dv); \ p = fabs(theta); \ q = fabs(du); \ r = fabs(dv); \ s = max3(p, q, r); \ /* gamma = s*sqrt((theta/s)**2 - (du/s) * (dv/s)) */ \ a = theta / s; \ gamma = s * sqrt(a * a - ((du) / s) * ((dv) / s)); \ if ((v) < (u)) gamma = -gamma; \ p = gamma - (du) + theta; \ q = gamma - (du) + gamma + (dv); \ r = p / q; \ (cm) = (u) + r * d; /** * Find a minimizer of an interpolated cubic function. * @param cm The minimizer of the interpolated cubic. * @param u The value of one point, u. * @param fu The value of f(u). * @param du The value of f'(u). * @param v The value of another point, v. * @param fv The value of f(v). * @param du The value of f'(v). * @param xmin The maximum value. * @param xmin The minimum value. */ #define CUBIC_MINIMIZER2(cm, u, fu, du, v, fv, dv, xmin, xmax) \ d = (v) - (u); \ theta = ((fu) - (fv)) * 3 / d + (du) + (dv); \ p = fabs(theta); \ q = fabs(du); \ r = fabs(dv); \ s = max3(p, q, r); \ /* gamma = s*sqrt((theta/s)**2 - (du/s) * (dv/s)) */ \ a = theta / s; \ gamma = s * sqrt(max2(0, a * a - ((du) / s) * ((dv) / s))); \ if ((u) < (v)) gamma = -gamma; \ p = gamma - (dv) + theta; \ q = gamma - (dv) + gamma + (du); \ r = p / q; \ if (r < 0. && gamma != 0.) { \ (cm) = (v) - r * d; \ } else if (a < 0) { \ (cm) = (xmax); \ } else { \ (cm) = (xmin); \ } /** * Find a minimizer of an interpolated quadratic function. * @param qm The minimizer of the interpolated quadratic. * @param u The value of one point, u. * @param fu The value of f(u). * @param du The value of f'(u). * @param v The value of another point, v. * @param fv The value of f(v). */ #define QUARD_MINIMIZER(qm, u, fu, du, v, fv) \ a = (v) - (u); \ (qm) = (u) + (du) / (((fu) - (fv)) / a + (du)) / 2 * a; /** * Find a minimizer of an interpolated quadratic function. * @param qm The minimizer of the interpolated quadratic. * @param u The value of one point, u. * @param du The value of f'(u). * @param v The value of another point, v. * @param dv The value of f'(v). */ #define QUARD_MINIMIZER2(qm, u, du, v, dv) \ a = (u) - (v); \ (qm) = (v) + (dv) / ((dv) - (du)) * a; /** * Update a safeguarded trial value and interval for line search. * * The parameter x represents the step with the least function value. * The parameter t represents the current step. This function assumes * that the derivative at the point of x in the direction of the step. * If the bracket is set to true, the minimizer has been bracketed in * an interval of uncertainty with endpoints between x and y. * * @param x The pointer to the value of one endpoint. * @param fx The pointer to the value of f(x). * @param dx The pointer to the value of f'(x). * @param y The pointer to the value of another endpoint. * @param fy The pointer to the value of f(y). * @param dy The pointer to the value of f'(y). * @param t The pointer to the value of the trial value, t. * @param ft The pointer to the value of f(t). * @param dt The pointer to the value of f'(t). * @param tmin The minimum value for the trial value, t. * @param tmax The maximum value for the trial value, t. * @param brackt The pointer to the predicate if the trial value is * bracketed. * @retval int Status value. Zero indicates a normal termination. * * @see * Jorge J. More and David J. Thuente. Line search algorithm with * guaranteed sufficient decrease. ACM Transactions on Mathematical * Software (TOMS), Vol 20, No 3, pp. 286-307, 1994. */ static int update_trial_interval( lbfgsfloatval_t *x, lbfgsfloatval_t *fx, lbfgsfloatval_t *dx, lbfgsfloatval_t *y, lbfgsfloatval_t *fy, lbfgsfloatval_t *dy, lbfgsfloatval_t *t, lbfgsfloatval_t *ft, lbfgsfloatval_t *dt, const lbfgsfloatval_t tmin, const lbfgsfloatval_t tmax, int *brackt ) { int bound; int dsign = fsigndiff(dt, dx); lbfgsfloatval_t mc; /* minimizer of an interpolated cubic. */ lbfgsfloatval_t mq; /* minimizer of an interpolated quadratic. */ lbfgsfloatval_t newt; /* new trial value. */ USES_MINIMIZER; /* for CUBIC_MINIMIZER and QUARD_MINIMIZER. */ /* Check the input parameters for errors. */ if (*brackt) { if (*t <= min2(*x, *y) || max2(*x, *y) <= *t) { /* The trival value t is out of the interval. */ return LBFGSERR_OUTOFINTERVAL; } if (0. <= *dx * (*t - *x)) { /* The function must decrease from x. */ return LBFGSERR_INCREASEGRADIENT; } if (tmax < tmin) { /* Incorrect tmin and tmax specified. */ return LBFGSERR_INCORRECT_TMINMAX; } } /* Trial value selection. */ if (*fx < *ft) { /* Case 1: a higher function value. The minimum is brackt. If the cubic minimizer is closer to x than the quadratic one, the cubic one is taken, else the average of the minimizers is taken. */ *brackt = 1; bound = 1; CUBIC_MINIMIZER(mc, *x, *fx, *dx, *t, *ft, *dt); QUARD_MINIMIZER(mq, *x, *fx, *dx, *t, *ft); if (fabs(mc - *x) < fabs(mq - *x)) { newt = mc; } else { newt = mc + 0.5 * (mq - mc); } } else if (dsign) { /* Case 2: a lower function value and derivatives of opposite sign. The minimum is brackt. If the cubic minimizer is closer to x than the quadratic (secant) one, the cubic one is taken, else the quadratic one is taken. */ *brackt = 1; bound = 0; CUBIC_MINIMIZER(mc, *x, *fx, *dx, *t, *ft, *dt); QUARD_MINIMIZER2(mq, *x, *dx, *t, *dt); if (fabs(mc - *t) > fabs(mq - *t)) { newt = mc; } else { newt = mq; } } else if (fabs(*dt) < fabs(*dx)) { /* Case 3: a lower function value, derivatives of the same sign, and the magnitude of the derivative decreases. The cubic minimizer is only used if the cubic tends to infinity in the direction of the minimizer or if the minimum of the cubic is beyond t. Otherwise the cubic minimizer is defined to be either tmin or tmax. The quadratic (secant) minimizer is also computed and if the minimum is brackt then the the minimizer closest to x is taken, else the one farthest away is taken. */ bound = 1; CUBIC_MINIMIZER2(mc, *x, *fx, *dx, *t, *ft, *dt, tmin, tmax); QUARD_MINIMIZER2(mq, *x, *dx, *t, *dt); if (*brackt) { if (fabs(*t - mc) < fabs(*t - mq)) { newt = mc; } else { newt = mq; } } else { if (fabs(*t - mc) > fabs(*t - mq)) { newt = mc; } else { newt = mq; } } } else { /* Case 4: a lower function value, derivatives of the same sign, and the magnitude of the derivative does not decrease. If the minimum is not brackt, the step is either tmin or tmax, else the cubic minimizer is taken. */ bound = 0; if (*brackt) { CUBIC_MINIMIZER(newt, *t, *ft, *dt, *y, *fy, *dy); } else if (*x < *t) { newt = tmax; } else { newt = tmin; } } /* Update the interval of uncertainty. This update does not depend on the new step or the case analysis above. - Case a: if f(x) < f(t), x <- x, y <- t. - Case b: if f(t) <= f(x) && f'(t)*f'(x) > 0, x <- t, y <- y. - Case c: if f(t) <= f(x) && f'(t)*f'(x) < 0, x <- t, y <- x. */ if (*fx < *ft) { /* Case a */ *y = *t; *fy = *ft; *dy = *dt; } else { /* Case c */ if (dsign) { *y = *x; *fy = *fx; *dy = *dx; } /* Cases b and c */ *x = *t; *fx = *ft; *dx = *dt; } /* Clip the new trial value in [tmin, tmax]. */ if (tmax < newt) newt = tmax; if (newt < tmin) newt = tmin; /* Redefine the new trial value if it is close to the upper bound of the interval. */ if (*brackt && bound) { mq = *x + 0.66 * (*y - *x); if (*x < *y) { if (mq < newt) newt = mq; } else { if (newt < mq) newt = mq; } } /* Return the new trial value. */ *t = newt; return 0; } static lbfgsfloatval_t owlqn_x1norm( const lbfgsfloatval_t* x, const int start, const int n ) { int i; lbfgsfloatval_t norm = 0.; for (i = start;i < n;++i) { norm += fabs(x[i]); } return norm; } static void owlqn_pseudo_gradient( lbfgsfloatval_t* pg, const lbfgsfloatval_t* x, const lbfgsfloatval_t* g, const int n, const lbfgsfloatval_t c, const int start, const int end ) { int i; /* Compute the negative of gradients. */ for (i = 0;i < start;++i) { pg[i] = g[i]; } /* Compute the psuedo-gradients. */ for (i = start;i < end;++i) { if (x[i] < 0.) { /* Differentiable. */ pg[i] = g[i] - c; } else if (0. < x[i]) { /* Differentiable. */ pg[i] = g[i] + c; } else { if (g[i] < -c) { /* Take the right partial derivative. */ pg[i] = g[i] + c; } else if (c < g[i]) { /* Take the left partial derivative. */ pg[i] = g[i] - c; } else { pg[i] = 0.; } } } for (i = end;i < n;++i) { pg[i] = g[i]; } } static void owlqn_project( lbfgsfloatval_t* d, const lbfgsfloatval_t* sign, const int start, const int end ) { int i; for (i = start;i < end;++i) { if (d[i] * sign[i] <= 0) { d[i] = 0; } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/lib/lib.vcproj000066400000000000000000000076061321604176500273130ustar00rootroot00000000000000 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/ltmain.sh000066400000000000000000005467021321604176500263770ustar00rootroot00000000000000# ltmain.sh - Provide generalized library-building support services. # NOTE: Changing this file will not affect anything until you rerun configure. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004 # Free Software Foundation, Inc. # Originally by Gordon Matzigkeit , 1996 # # 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 of the License, 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 to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. basename="s,^.*/,,g" # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" # RH: define SED for historic ltconfig's generated by Libtool 1.3 [ -z "$SED" ] && SED=sed # The name of this program: progname=`echo "$progpath" | $SED $basename` modename="$progname" # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 PROGRAM=ltmain.sh PACKAGE=libtool VERSION=1.5.6 TIMESTAMP=" (1.1220.2.95 2004/04/11 05:50:42)" EGREP="grep -E" # Check that we have a working $echo. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then # Yippee, $echo works! : else # Restart under the correct shell, and then maybe $echo will work. exec $SHELL "$progpath" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat <&2 $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit $EXIT_FAILURE fi # Global variables. mode=$default_mode nonopt= prev= prevopt= run= show="$echo" show_help= execute_dlfiles= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" ##################################### # Shell function definitions: # This seems to be the best place for them # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. func_win32_libid () { win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then win32_nmres=`eval $NM -f posix -A $1 | \ sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'` if test "X$win32_nmres" = "Ximport" ; then win32_libid_type="x86 archive import" else win32_libid_type="x86 archive static" fi fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $echo $win32_libid_type } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac CC_quoted="$CC_quoted $arg" done case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac CC_quoted="$CC_quoted $arg" done case "$@ " in " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then $echo "$modename: unable to infer tagged configuration" $echo "$modename: specify a tag with \`--tag'" 1>&2 exit $EXIT_FAILURE # else # $echo "$modename: using $tagname tagged configuration" fi ;; esac fi } # End of Shell function definitions ##################################### # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Parse our command line options once, thoroughly. while test "$#" -gt 0 do arg="$1" shift case $arg in -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in execute_dlfiles) execute_dlfiles="$execute_dlfiles $arg" ;; tag) tagname="$arg" preserve_args="${preserve_args}=$arg" # Check whether tagname contains only valid characters case $tagname in *[!-_A-Za-z0-9,/]*) $echo "$progname: invalid tag name: $tagname" 1>&2 exit $EXIT_FAILURE ;; esac case $tagname in CC) # Don't test for the "default" C tag, as we know, it's there, but # not specially marked. ;; *) if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then taglist="$taglist $tagname" # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" else $echo "$progname: ignoring unknown tag $tagname" 1>&2 fi ;; esac ;; *) eval "$prev=\$arg" ;; esac prev= prevopt= continue fi # Have we seen a non-optional argument yet? case $arg in --help) show_help=yes ;; --version) $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" $echo $echo "Copyright (C) 2003 Free Software Foundation, Inc." $echo "This is free software; see the source for copying conditions. There is NO" $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." exit $EXIT_SUCCESS ;; --config) ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath # Now print the configurations for the tags. for tagname in $taglist; do ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" done exit $EXIT_SUCCESS ;; --debug) $echo "$progname: enabling shell trace mode" set -x preserve_args="$preserve_args $arg" ;; --dry-run | -n) run=: ;; --features) $echo "host: $host" if test "$build_libtool_libs" = yes; then $echo "enable shared libraries" else $echo "disable shared libraries" fi if test "$build_old_libs" = yes; then $echo "enable static libraries" else $echo "disable static libraries" fi exit $EXIT_SUCCESS ;; --finish) mode="finish" ;; --mode) prevopt="--mode" prev=mode ;; --mode=*) mode="$optarg" ;; --preserve-dup-deps) duplicate_deps="yes" ;; --quiet | --silent) show=: preserve_args="$preserve_args $arg" ;; --tag) prevopt="--tag" prev=tag ;; --tag=*) set tag "$optarg" ${1+"$@"} shift prev=tag preserve_args="$preserve_args --tag" ;; -dlopen) prevopt="-dlopen" prev=execute_dlfiles ;; -*) $echo "$modename: unrecognized option \`$arg'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE ;; *) nonopt="$arg" break ;; esac done if test -n "$prevopt"; then $echo "$modename: option \`$prevopt' requires an argument" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= if test -z "$show_help"; then # Infer the operation mode. if test -z "$mode"; then $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2 case $nonopt in *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) mode=link for arg do case $arg in -c) mode=compile break ;; esac done ;; *db | *dbx | *strace | *truss) mode=execute ;; *install*|cp|mv) mode=install ;; *rm) mode=uninstall ;; *) # If we have no mode, but dlfiles were specified, then do execute mode. test -n "$execute_dlfiles" && mode=execute # Just use the default operation mode. if test -z "$mode"; then if test -n "$nonopt"; then $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 else $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 fi fi ;; esac fi # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then $echo "$modename: unrecognized option \`-dlopen'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$modename --help --mode=$mode' for more information." # These modes are in order of execution frequency so that they run quickly. case $mode in # libtool compile mode compile) modename="$modename: compile" # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= for arg do case "$arg_mode" in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) if test -n "$libobj" ; then $echo "$modename: you cannot specify \`-o' more than once" 1>&2 exit $EXIT_FAILURE fi arg_mode=target continue ;; -static | -prefer-pic | -prefer-non-pic) later="$later $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac lastarg="$lastarg $arg" done IFS="$save_ifs" lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` # Add the arguments to base_compile. base_compile="$base_compile $lastarg" continue ;; * ) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` case $lastarg in # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") lastarg="\"$lastarg\"" ;; esac base_compile="$base_compile $lastarg" done # for arg case $arg_mode in arg) $echo "$modename: you must specify an argument for -Xcompile" exit $EXIT_FAILURE ;; target) $echo "$modename: you must specify a target with \`-o'" 1>&2 exit $EXIT_FAILURE ;; *) # Get the name of the library object. [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo xform='[cCFSifmso]' case $libobj in *.ada) xform=ada ;; *.adb) xform=adb ;; *.ads) xform=ads ;; *.asm) xform=asm ;; *.c++) xform=c++ ;; *.cc) xform=cc ;; *.ii) xform=ii ;; *.class) xform=class ;; *.cpp) xform=cpp ;; *.cxx) xform=cxx ;; *.f90) xform=f90 ;; *.for) xform=for ;; *.java) xform=java ;; esac libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` case $libobj in *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; *) $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 exit $EXIT_FAILURE ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -static) build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$obj"; then xdir= else xdir=$xdir/ fi lobj=${xdir}$objdir/$objname if test -z "$base_compile"; then $echo "$modename: you must specify a compilation command" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi $run $rm $removelist trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" removelist="$removelist $output_obj $lockfile" trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $run ln "$progpath" "$lockfile" 2>/dev/null; do $show "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $echo "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit $EXIT_FAILURE fi $echo $srcfile > "$lockfile" fi if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi $run $rm "$libobj" "${libobj}T" # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then $echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then $show "$mv $output_obj $lobj" if $run $mv $output_obj $lobj; then : else error=$? $run $rm $removelist exit $error fi fi # Append the name of the PIC object to the libtool object file. test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then $echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then $show "$mv $output_obj $obj" if $run $mv $output_obj $obj; then : else error=$? $run $rm $removelist exit $error fi fi # Append the name of the non-PIC object the libtool object file. # Only append if the libtool object file exists. test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi else if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi fi build_libtool_libs=no build_old_libs=yes prefer_static_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test ;; *) qarg=$arg ;; esac libtool_args="$libtool_args $qarg" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) compile_command="$compile_command @OUTPUT@" finalize_command="$finalize_command @OUTPUT@" ;; esac case $prev in dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. compile_command="$compile_command @SYMFILE@" finalize_command="$finalize_command @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" else dlprefiles="$dlprefiles $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" if test ! -f "$arg"; then $echo "$modename: symbol file \`$arg' does not exist" exit $EXIT_FAILURE fi prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat $save_arg` do # moreargs="$moreargs $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then pic_object= non_pic_object= # Read the .lo file # If there is no directory component, then add one. case $arg in */* | *\\*) . $arg ;; *) . ./$arg ;; esac if test -z "$pic_object" || \ test -z "$non_pic_object" || test "$pic_object" = none && \ test "$non_pic_object" = none; then $echo "$modename: cannot find name of object for \`$arg'" 1>&2 exit $EXIT_FAILURE fi # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. libobjs="$libobjs $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object non_pic_objects="$non_pic_objects $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi fi else # Only an error if not doing a dry-run. if test -z "$run"; then $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 exit $EXIT_FAILURE else # Dry-run case. # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` libobjs="$libobjs $pic_object" non_pic_objects="$non_pic_objects $non_pic_object" fi fi done else $echo "$modename: link input file \`$save_arg' does not exist" exit $EXIT_FAILURE fi arg=$save_arg prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) $echo "$modename: only absolute run-paths are allowed" 1>&2 exit $EXIT_FAILURE ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) rpath="$rpath $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) xrpath="$xrpath $arg" ;; esac fi prev= continue ;; xcompiler) compiler_flags="$compiler_flags $qarg" prev= compile_command="$compile_command $qarg" finalize_command="$finalize_command $qarg" continue ;; xlinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $wl$qarg" prev= compile_command="$compile_command $wl$qarg" finalize_command="$finalize_command $wl$qarg" continue ;; xcclinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $qarg" prev= compile_command="$compile_command $qarg" finalize_command="$finalize_command $qarg" continue ;; shrext) shrext_cmds="$arg" prev= continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then compile_command="$compile_command $link_static_flag" finalize_command="$finalize_command $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 continue ;; -avoid-version) avoid_version=yes continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: more than one -exported-symbols argument is not allowed" exit $EXIT_FAILURE fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" ;; esac continue ;; -L*) dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 exit $EXIT_FAILURE fi dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "*) ;; *) deplibs="$deplibs -L$dir" lib_search_path="$lib_search_path $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) case :$dllsearchpath: in *":$dir:"*) ;; *) dllsearchpath="$dllsearchpath:$dir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-pw32* | *-*-beos*) # These systems don't actually have a C or math library (as such) continue ;; *-*-mingw* | *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework deplibs="$deplibs -framework System" continue esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi deplibs="$deplibs $arg" continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) deplibs="$deplibs $arg" continue ;; -module) module=yes continue ;; # gcc -m* arguments should be passed to the linker via $compiler_flags # in order to pass architecture information to the linker # (e.g. 32 vs 64-bit). This may also be accomplished via -Wl,-mfoo # but this is not reliable with gcc because gcc may use -mfoo to # select a different linker, different libraries, etc, while # -Wl,-mfoo simply passes -mfoo to the linker. -m*) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" if test "$with_gcc" = "yes" ; then compiler_flags="$compiler_flags $arg" fi continue ;; -shrext) prev=shrext continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) # The PATH hackery in wrapper scripts is required on Windows # in order for the loader to find any dlls it needs. $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) $echo "$modename: only absolute run-paths are allowed" 1>&2 exit $EXIT_FAILURE ;; esac case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac continue ;; -static) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -Wc,*) args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" case $flag in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") flag="\"$flag\"" ;; esac arg="$arg $wl$flag" compiler_flags="$compiler_flags $flag" done IFS="$save_ifs" arg=`$echo "X$arg" | $Xsed -e "s/^ //"` ;; -Wl,*) args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" case $flag in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") flag="\"$flag\"" ;; esac arg="$arg $wl$flag" compiler_flags="$compiler_flags $wl$flag" linker_flags="$linker_flags $flag" done IFS="$save_ifs" arg=`$echo "X$arg" | $Xsed -e "s/^ //"` ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # Some other compiler flag. -* | +*) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac ;; *.$objext) # A standard object. objs="$objs $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then pic_object= non_pic_object= # Read the .lo file # If there is no directory component, then add one. case $arg in */* | *\\*) . $arg ;; *) . ./$arg ;; esac if test -z "$pic_object" || \ test -z "$non_pic_object" || test "$pic_object" = none && \ test "$non_pic_object" = none; then $echo "$modename: cannot find name of object for \`$arg'" 1>&2 exit $EXIT_FAILURE fi # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. libobjs="$libobjs $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object non_pic_objects="$non_pic_objects $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi fi else # Only an error if not doing a dry-run. if test -z "$run"; then $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 exit $EXIT_FAILURE else # Dry-run case. # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` libobjs="$libobjs $pic_object" non_pic_objects="$non_pic_objects $non_pic_object" fi fi ;; *.$libext) # An archive. deplibs="$deplibs $arg" old_deplibs="$old_deplibs $arg" continue ;; *.la) # A libtool-controlled library. if test "$prev" = dlfiles; then # This library was specified with -dlopen. dlfiles="$dlfiles $arg" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. dlprefiles="$dlprefiles $arg" prev= else deplibs="$deplibs $arg" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi done # argument parsing loop if test -n "$prev"; then $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi oldlibs= # calculate the name of the file, without its directory outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` if test "X$output_objdir" = "X$output"; then output_objdir="$objdir" else output_objdir="$output_objdir/$objdir" fi # Create the object directory. if test ! -d "$output_objdir"; then $show "$mkdir $output_objdir" $run $mkdir $output_objdir status=$? if test "$status" -ne 0 && test ! -d "$output_objdir"; then exit $status fi fi # Determine the type of output case $output in "") $echo "$modename: you must specify an output file" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac case $host in *cygwin* | *mingw* | *pw32*) # don't eliminate duplications in $postdeps and $predeps duplicate_compiler_generated_deps=yes ;; *) duplicate_compiler_generated_deps=$duplicate_deps ;; esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if test "X$duplicate_deps" = "Xyes" ; then case "$libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi libs="$libs $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; esac pre_post_deps="$pre_post_deps $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 exit $EXIT_FAILURE ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 continue fi if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then library_names= old_library= case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` test "X$ladir" = "X$lib" && ladir="." lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` ;; *) $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) lib="$deplib" ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) if test "$deplibs_check_method" != pass_all; then $echo $echo "*** Warning: Trying to link with static lib archive $deplib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have" $echo "*** because the file extensions .$libext of this argument makes me believe" $echo "*** that it is just a static archive that I should not used here." else $echo $echo "*** Warning: Linking the shared library $output against the" $echo "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. newdlprefiles="$newdlprefiles $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else newdlfiles="$newdlfiles $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else $echo "$modename: cannot find the library \`$lib'" 1>&2 exit $EXIT_FAILURE fi # Check to see that this really is a libtool archive. if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` test "X$ladir" = "X$lib" && ladir="." dlname= dlopen= dlpreopen= libdir= library_names= old_library= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no # Read the .la file case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && dlfiles="$dlfiles $dlopen" test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 exit $EXIT_FAILURE fi # It is a libtool convenience library, so add in its objects. convenience="$convenience $ladir/$objdir/$old_library" old_convenience="$old_convenience $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then $echo "$modename: \`$lib' is not a convenience library" 1>&2 exit $EXIT_FAILURE fi continue fi # $pass = conv # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 exit $EXIT_FAILURE fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 exit $EXIT_FAILURE fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. dlprefiles="$dlprefiles $lib $dependency_libs" else newdlfiles="$newdlfiles $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 abs_ladir="$ladir" fi ;; esac laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then $echo "$modename: warning: library \`$lib' was moved." 1>&2 dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$libdir" absdir="$libdir" fi else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" fi # $installed = yes name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir"; then $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 exit $EXIT_FAILURE fi # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then newdlprefiles="$newdlprefiles $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then newdlprefiles="$newdlprefiles $dir/$dlname" else newdlprefiles="$newdlprefiles $dir/$linklib" fi fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then newlib_search_path="$newlib_search_path $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { test "$prefer_static_libs" = no || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var"; then # Make sure the rpath contains only unique directories. case "$temp_rpath " in *" $dir "*) ;; *" $absdir "*) ;; *) temp_rpath="$temp_rpath $dir" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically if test -n "$library_names" && { test "$prefer_static_libs" = no || test -z "$old_library"; }; then if test "$installed" = no; then notinst_deplibs="$notinst_deplibs $lib" need_relink=yes fi # This is a shared library # Warn about portability, can't link against -module's on # some systems (darwin) if test "$shouldnotlink" = yes && test "$pass" = link ; then $echo if test "$linkmode" = prog; then $echo "*** Warning: Linking the executable $output against the loadable module" else $echo "*** Warning: Linking the shared library $output against the loadable module" fi $echo "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names realname="$2" shift; shift libname=`eval \\$echo \"$libname_spec\"` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw*) major=`expr $current - $age` versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" soname=`$echo $soroot | ${SED} -e 's/^.*\///'` newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else $show "extracting exported symbol list from \`$soname'" save_ifs="$IFS"; IFS='~' cmds=$extract_expsyms_cmds for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else $show "generating import library for \`$soname'" save_ifs="$IFS"; IFS='~' cmds=$old_archive_from_expsyms_cmds for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5* ) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a module then we can not link against # it, someone is ignoring the new warnings I added if /usr/bin/file -L $add 2> /dev/null | $EGREP "bundle" >/dev/null ; then $echo "** Warning, lib $linklib is a module, not a shared library" if test -z "$old_library" ; then $echo $echo "** And there doesn't seem to be a static archive available" $echo "** The link will probably fail, sorry" else add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$dir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case "$libdir" in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then $echo "$modename: configuration error: unsupported hardcode properties" exit $EXIT_FAILURE fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && \ test "$hardcode_minus_L" != yes && \ test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case "$libdir" in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. $echo $echo "*** Warning: This system can not link to static lib archive $lib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then $echo "*** But as you try to build a module library, libtool will still create " $echo "*** a static module, that should work as long as the dlopening application" $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then $echo $echo "*** However, this would only work if libtool was able to extract symbol" $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" $echo "*** not find such a program. So, this module is probably useless." $echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else convenience="$convenience $dir/$old_library" old_convenience="$old_convenience $dir/$old_library" deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` case " $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; *) temp_deplibs="$temp_deplibs $libdir";; esac done dependency_libs="$temp_deplibs" fi newlib_search_path="$newlib_search_path $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do case $deplib in -L*) path="$deplib" ;; *.la) dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$deplib" && dir="." # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 absdir="$dir" fi ;; esac if grep "^installed=no" $deplib > /dev/null; then path="$absdir/$objdir" else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` if test -z "$libdir"; then $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi if test "$absdir" != "$libdir"; then $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 fi path="$absdir" fi depdepl= case $host in *-*-darwin*) # we do not want to link against static libs, # but need to link against shared eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$path/$depdepl" ; then depdepl="$path/$depdepl" fi # do not add paths which are already there case " $newlib_search_path " in *" $path "*) ;; *) newlib_search_path="$newlib_search_path $path";; esac fi path="" ;; *) path="-L$path" ;; esac ;; -l*) case $host in *-*-darwin*) # Again, we only want to link against shared libraries eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` for tmp in $newlib_search_path ; do if test -f "$tmp/lib$tmp_libs.dylib" ; then eval depdepl="$tmp/lib$tmp_libs.dylib" break fi done path="" ;; *) continue ;; esac ;; *) continue ;; esac case " $deplibs " in *" $depdepl "*) ;; *) deplibs="$depdepl $deplibs" ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$deplibs $path" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) tmp_libs="$tmp_libs $deplib" ;; esac ;; *) tmp_libs="$tmp_libs $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then tmp_libs="$tmp_libs $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 fi if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 fi if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 fi # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" objs="$objs$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) if test "$module" = no; then $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 exit $EXIT_FAILURE else $echo $echo "*** Warning: Linking the shared library $output against the non-libtool" $echo "*** objects $objs is not portable!" libobjs="$libobjs $objs" fi fi if test "$dlself" != no; then $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 fi set dummy $rpath if test "$#" -gt 2; then $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 fi install_libdir="$2" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 fi else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 IFS="$save_ifs" if test -n "$8"; then $echo "$modename: too many parameters to \`-version-info'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$2" number_minor="$3" number_revision="$4" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in darwin|linux|osf|windows) current=`expr $number_major + $number_minor` age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) current=`expr $number_major + $number_minor - 1` age="$number_minor" revision="$number_minor" ;; esac ;; no) current="$2" revision="$3" age="$4" ;; esac # Check that each of the things are valid numbers. case $current in [0-9]*) ;; *) $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE ;; esac case $revision in [0-9]*) ;; *) $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE ;; esac case $age in [0-9]*) ;; *) $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE ;; esac if test "$age" -gt "$current"; then $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header major=.`expr $current - $age` versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... minor_current=`expr $current + 1` verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current"; ;; irix | nonstopux) major=`expr $current - $age + 1` case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do iface=`expr $revision - $loop` loop=`expr $loop - 1` verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) major=.`expr $current - $age` versuffix="$major.$age.$revision" ;; osf) major=.`expr $current - $age` versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do iface=`expr $current - $loop` loop=`expr $loop - 1` verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. major=`expr $current - $age` versuffix="-$major" ;; *) $echo "$modename: unknown library version type \`$version_type'" 1>&2 $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit $EXIT_FAILURE ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi if test "$mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$echo "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi removelist="$removelist $p" ;; *) ;; esac done if test -n "$removelist"; then $show "${rm}r $removelist" $run ${rm}r $removelist fi fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` fi # Eliminate all temporary directories. for path in $notinst_path; do lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'` deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'` dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'` done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) dlfiles="$dlfiles $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) dlprefiles="$dlprefiles $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework deplibs="$deplibs -framework System" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then deplibs="$deplibs -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $rm conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null \ | grep " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ | ${SED} 10q \ | $EGREP "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $echo $echo "*** Warning: linker path does not have real file for library $a_deplib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have" $echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $echo "*** with $libname but no candidates were found. (...for file magic test)" else $echo "*** with $libname and none of the candidates passed a file format test" $echo "*** using a file magic. Last file checked: $potlib" fi fi else # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" fi done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` for a_deplib in $deplibs; do name="`expr $a_deplib : '-l\(.*\)'`" # If $name is empty we are operating on a -L argument. if test -n "$name" && test "$name" != "0"; then if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) newdeplibs="$newdeplibs $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval \\$echo \"$libname_spec\"` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval $echo \"$potent_lib\" 2>/dev/null \ | ${SED} 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $echo $echo "*** Warning: linker path does not have real file for library $a_deplib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have" $echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $echo "*** with $libname but no candidates were found. (...for regex pattern test)" else $echo "*** with $libname and none of the candidates passed a file format test" $echo "*** using a regex pattern. Last file checked: $potlib" fi fi else # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" fi done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ -e 's/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` done fi if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ | grep . >/dev/null; then $echo if test "X$deplibs_check_method" = "Xnone"; then $echo "*** Warning: inter-library dependencies are not supported in this platform." else $echo "*** Warning: inter-library dependencies are not known to be supported." fi $echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes fi ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then $echo $echo "*** Warning: libtool could not satisfy all declared inter-library" $echo "*** dependencies of module $libname. Therefore, libtool will create" $echo "*** a static module, that should work as long as the dlopening" $echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then $echo $echo "*** However, this would only work if libtool was able to extract symbol" $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" $echo "*** not find such a program. So, this module is probably useless." $echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else $echo "*** The inter-library dependencies that have been dropped here will be" $echo "*** automatically added whenever a program is linked with this library" $echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then $echo $echo "*** Since this library must not contain undefined symbols," $echo "*** because either the platform does not support them or" $echo "*** it was explicitly requested with -no-undefined," $echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" dep_rpath="$dep_rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" if test -n "$hardcode_libdir_flag_spec_ld"; then eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" else eval dep_rpath=\"$hardcode_libdir_flag_spec\" fi fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names realname="$2" shift; shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" for link do linknames="$linknames $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then $show "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $run $rm $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" if len=`expr "X$cmd" : ".*"` && test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then $show "$cmd" $run eval "$cmd" || exit $? skipped_export=false else # The command line is too long to execute in one step. $show "using reloadable object file for export list..." skipped_export=: fi done IFS="$save_ifs" if test -n "$export_symbols_regex"; then $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' $show "$mv \"${export_symbols}T\" \"$export_symbols\"" $run eval '$mv "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) tmp_deplibs="$tmp_deplibs $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" else gentop="$output_objdir/${outputname}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "$mkdir $gentop" $run $mkdir "$gentop" status=$? if test "$status" -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" for xlib in $convenience; do # Extract the objects. case $xlib in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "$mkdir $xdir" $run $mkdir "$xdir" status=$? if test "$status" -ne 0 && test ! -d "$xdir"; then exit $status fi # We will extract separately just the conflicting names and we will no # longer touch any unique names. It is faster to leave these extract # automatically by $AR in one run. $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then : else $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 $AR t "$xabs" | sort | uniq -cd | while read -r count name do i=1 while test "$i" -le "$count" do # Put our $i before any first dot (extension) # Never overwrite any file name_to="$name" while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" do name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` done $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? i=`expr $i + 1` done done fi libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` done fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" fi # Make a backup of the uninstalled library when relinking if test "$mode" = relink; then $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` && test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise. $echo "creating reloadable object files..." # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= delfiles= last_robj= k=1 output=$output_objdir/$save_output-${k}.$objext # Loop over the list of objects to be linked. for obj in $save_libobjs do eval test_cmds=\"$reload_cmds $objlist $last_robj\" if test "X$objlist" = X || { len=`expr "X$test_cmds" : ".*"` && test "$len" -le "$max_cmd_len"; }; then objlist="$objlist $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. eval concat_cmds=\"$reload_cmds $objlist $last_robj\" else # All subsequent reloadable object files will link in # the last one created. eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" fi last_robj=$output_objdir/$save_output-${k}.$objext k=`expr $k + 1` output=$output_objdir/$save_output-${k}.$objext objlist=$obj len=1 fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" if ${skipped_export-false}; then $show "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $run $rm $export_symbols libobjs=$output # Append the command to create the export file. eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" fi # Set up a command to remove the reloadale object files # after they are used. i=0 while test "$i" -lt "$k" do i=`expr $i + 1` delfiles="$delfiles $output_objdir/$save_output-${i}.$objext" done $echo "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi # Append the command to remove the reloadable object files # to the just-reset $cmds. eval cmds=\"\$cmds~\$rm $delfiles\" fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$mode" = relink; then $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 fi if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 fi case $output in *.lo) if test -n "$objs$old_deplibs"; then $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 exit $EXIT_FAILURE fi libobj="$output" obj=`$echo "X$output" | $Xsed -e "$lo2o"` ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $run $rm $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" else gentop="$output_objdir/${obj}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "$mkdir $gentop" $run $mkdir "$gentop" status=$? if test "$status" -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" for xlib in $convenience; do # Extract the objects. case $xlib in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "$mkdir $xdir" $run $mkdir "$xdir" status=$? if test "$status" -ne 0 && test ! -d "$xdir"; then exit $status fi # We will extract separately just the conflicting names and we will no # longer touch any unique names. It is faster to leave these extract # automatically by $AR in one run. $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then : else $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 $AR t "$xabs" | sort | uniq -cd | while read -r count name do i=1 while test "$i" -le "$count" do # Put our $i before any first dot (extension) # Never overwrite any file name_to="$name" while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" do name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` done $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? i=`expr $i + 1` done done fi reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` done fi fi # Create the old-style object. reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" cmds=$reload_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $run eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" cmds=$reload_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; esac if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 fi if test "$preload" = yes; then if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && test "$dlopen_self_static" = unknown; then $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." fi fi case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` ;; esac case $host in *darwin*) # Don't allow lazy linking, it breaks C++ global constructors if test "$tagname" = CXX ; then compile_command="$compile_command ${wl}-bind_at_load" finalize_command="$finalize_command ${wl}-bind_at_load" fi ;; esac compile_command="$compile_command $compile_deplibs" finalize_command="$finalize_command $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) case :$dllsearchpath: in *":$libdir:"*) ;; *) dllsearchpath="$dllsearchpath:$libdir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` fi dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then dlsyms="${outputname}S.c" else $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 fi fi if test -n "$dlsyms"; then case $dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${outputname}.nm" $show "$rm $nlist ${nlist}S ${nlist}T" $run $rm "$nlist" "${nlist}S" "${nlist}T" # Parse the name list into a source file. $show "creating $output_objdir/$dlsyms" test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ /* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ /* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ #ifdef __cplusplus extern \"C\" { #endif /* Prevent the only kind of declaration conflicts we can make. */ #define lt_preloaded_symbols some_other_symbol /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then $show "generating symbol list for \`$output'" test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` for arg in $progfiles; do $show "extracting global C symbols from \`$arg'" $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi if test -n "$export_symbols_regex"; then $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$output.exp" $run $rm $export_symbols $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' else $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' $run eval 'mv "$nlist"T "$nlist"' fi fi for arg in $dlprefiles; do $show "extracting global C symbols from \`$arg'" name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` $run eval '$echo ": $name " >> "$nlist"' $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -z "$run"; then # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $mv "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if grep -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else grep -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' else $echo '/* NONE */' >> "$output_objdir/$dlsyms" fi $echo >> "$output_objdir/$dlsyms" "\ #undef lt_preloaded_symbols #if defined (__STDC__) && __STDC__ # define lt_ptr void * #else # define lt_ptr char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr address; } lt_preloaded_symbols[] = {\ " eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" $echo >> "$output_objdir/$dlsyms" "\ {0, (lt_ptr) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " fi pic_flag_for_symtable= case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; esac;; *-*-hpux*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag";; esac esac # Now compile the dynamic symbol file. $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? # Clean up the generated files. $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" # Transform the symbol file into the correct name. compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` ;; *) $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 exit $EXIT_FAILURE ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` fi if test "$need_relink" = no || test "$build_libtool_libs" != yes; then # Replace the output file specification. compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. $show "$link_command" $run eval "$link_command" status=$? # Delete the generated files. if test -n "$dlsyms"; then $show "$rm $output_objdir/${outputname}S.${objext}" $run $rm "$output_objdir/${outputname}S.${objext}" fi exit $status fi if test -n "$shlibpath_var"; then # We should set the shlibpath_var rpath= for dir in $temp_rpath; do case $dir in [\\/]* | [A-Za-z]:[\\/]*) # Absolute path. rpath="$rpath$dir:" ;; *) # Relative path: add a thisdir entry. rpath="$rpath\$thisdir/$dir:" ;; esac done temp_rpath="$rpath" fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $run $rm $output # Link the executable and exit $show "$link_command" $run eval "$link_command" || exit $? exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 $echo "$modename: \`$output' will be relinked during installation" 1>&2 else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname $show "$link_command" $run eval "$link_command" || exit $? # Now create the wrapper script. $show "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` relink_command="$var=\"$var_value\"; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` fi # Quote $echo for shipping. if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then case $progpath in [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; esac qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` else qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` fi # Only actually do things if our run command is non-null. if test -z "$run"; then # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) cwrappersource=`$echo ${objdir}/lt-${output}.c` cwrapper=`$echo ${output}.exe` $rm $cwrappersource $cwrapper trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 cat > $cwrappersource <> $cwrappersource<<"EOF" #include #include #include #include #include #include #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef DIR_SEPARATOR #define DIR_SEPARATOR '/' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) #define HAVE_DOS_BASED_FILE_SYSTEM #ifndef DIR_SEPARATOR_2 #define DIR_SEPARATOR_2 '\\' #endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) const char *program_name = NULL; void * xmalloc (size_t num); char * xstrdup (const char *string); char * basename (const char *name); char * fnqualify(const char *path); char * strendzap(char *str, const char *pat); void lt_fatal (const char *message, ...); int main (int argc, char *argv[]) { char **newargz; int i; program_name = (char *) xstrdup ((char *) basename (argv[0])); newargz = XMALLOC(char *, argc+2); EOF cat >> $cwrappersource <> $cwrappersource <<"EOF" newargz[1] = fnqualify(argv[0]); /* we know the script has the same name, without the .exe */ /* so make sure newargz[1] doesn't end in .exe */ strendzap(newargz[1],".exe"); for (i = 1; i < argc; i++) newargz[i+1] = xstrdup(argv[i]); newargz[argc+1] = NULL; EOF cat >> $cwrappersource <> $cwrappersource <<"EOF" } void * xmalloc (size_t num) { void * p = (void *) malloc (num); if (!p) lt_fatal ("Memory exhausted"); return p; } char * xstrdup (const char *string) { return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL ; } char * basename (const char *name) { const char *base; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) /* Skip over the disk name in MSDOS pathnames. */ if (isalpha (name[0]) && name[1] == ':') name += 2; #endif for (base = name; *name; name++) if (IS_DIR_SEPARATOR (*name)) base = name + 1; return (char *) base; } char * fnqualify(const char *path) { size_t size; char *p; char tmp[LT_PATHMAX + 1]; assert(path != NULL); /* Is it qualified already? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha (path[0]) && path[1] == ':') return xstrdup (path); #endif if (IS_DIR_SEPARATOR (path[0])) return xstrdup (path); /* prepend the current directory */ /* doesn't handle '~' */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */ p = XMALLOC(char, size); sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path); return p; } char * strendzap(char *str, const char *pat) { size_t len, patlen; assert(str != NULL); assert(pat != NULL); len = strlen(str); patlen = strlen(pat); if (patlen <= len) { str += len - patlen; if (strcmp(str, pat) == 0) *str = '\0'; } return str; } static void lt_error_core (int exit_status, const char * mode, const char * message, va_list ap) { fprintf (stderr, "%s: %s: ", program_name, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, "FATAL", message, ap); va_end (ap); } EOF # we should really use a build-platform specific compiler # here, but OTOH, the wrappers (shell script and this C one) # are only useful if you want to execute the "real" binary. # Since the "real" binary is built for $host, then this # wrapper might as well be built for $host, too. $run $LTCC -s -o $cwrapper $cwrappersource ;; esac $rm $output trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 $echo > $output "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='${SED} -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variable: notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$echo are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then echo=\"$qecho\" file=\"\$0\" # Make sure echo works. if test \"X\$1\" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then # Yippee, \$echo works! : else # Restart under the correct shell, and then maybe \$echo will work. exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} fi fi\ " $echo >> $output "\ # Find the directory that this script lives in. thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` done # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $echo >> $output "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || \\ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $mkdir \"\$progdir\" else $rm \"\$progdir/\$file\" fi" $echo >> $output "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $echo \"\$relink_command_output\" >&2 $rm \"\$progdir/\$file\" exit $EXIT_FAILURE fi fi $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $rm \"\$progdir/\$program\"; $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } $rm \"\$progdir/\$file\" fi" else $echo >> $output "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $echo >> $output "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $echo >> $output "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $echo >> $output "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $echo >> $output "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2*) $echo >> $output "\ exec \$progdir\\\\\$program \${1+\"\$@\"} " ;; *) $echo >> $output "\ exec \$progdir/\$program \${1+\"\$@\"} " ;; esac $echo >> $output "\ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" exit $EXIT_FAILURE fi else # The program doesn't exist. \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 \$echo \"This script is just a wrapper for \$program.\" 1>&2 $echo \"See the $PACKAGE documentation for more information.\" 1>&2 exit $EXIT_FAILURE fi fi\ " chmod +x $output fi exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "$mkdir $gentop" $run $mkdir "$gentop" status=$? if test "$status" -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" # Add in members from convenience archives. for xlib in $addlibs; do # Extract the objects. case $xlib in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "$mkdir $xdir" $run $mkdir "$xdir" status=$? if test "$status" -ne 0 && test ! -d "$xdir"; then exit $status fi # We will extract separately just the conflicting names and we will no # longer touch any unique names. It is faster to leave these extract # automatically by $AR in one run. $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then : else $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 $AR t "$xabs" | sort | uniq -cd | while read -r count name do i=1 while test "$i" -le "$count" do # Put our $i before any first dot (extension) # Never overwrite any file name_to="$name" while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" do name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` done $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? i=`expr $i + 1` done done fi oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` done fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else eval cmds=\"$old_archive_cmds\" if len=`expr "X$cmds" : ".*"` && test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts $echo "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs # GNU ar 2.10+ was changed to match POSIX; thus no paths are # encoded into archives. This makes 'ar r' malfunction in # this piecewise linking case whenever conflicting object # names appear in distinct ar calls; check, warn and compensate. if (for obj in $save_oldobjs do $echo "X$obj" | $Xsed -e 's%^.*/%%' done | sort | sort -uc >/dev/null 2>&1); then : else $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2 $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2 AR_FLAGS=cq fi # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done for obj in $save_oldobjs do oldobjs="$objlist $obj" objlist="$objlist $obj" eval test_cmds=\"$old_archive_cmds\" if len=`expr "X$test_cmds" : ".*"` && test "$len" -le "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do eval cmd=\"$cmd\" IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$generated"; then $show "${rm}r$generated" $run ${rm}r$generated fi # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" $show "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` relink_command="$var=\"$var_value\"; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. if test -z "$run"; then for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` if test -z "$libdir"; then $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi newdependency_libs="$newdependency_libs $libdir/$name" ;; *) newdependency_libs="$newdependency_libs $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` if test -z "$libdir"; then $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi newdlfiles="$newdlfiles $libdir/$name" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` if test -z "$libdir"; then $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi newdlprefiles="$newdlprefiles $libdir/$name" done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlfiles="$newdlfiles $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlprefiles="$newdlprefiles $abs" done dlprefiles="$newdlprefiles" fi $rm $output # place dlname in correct position for cygwin tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; esac $echo > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $echo >> $output "\ relink_command=\"$relink_command\"" fi done fi # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? ;; esac exit $EXIT_SUCCESS ;; # libtool install mode install) modename="$modename: install" # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then # Aesthetically quote it. arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$arg " arg="$1" shift else install_prog= arg="$nonopt" fi # The real first argument should be the name of the installation program. # Aesthetically quote it. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$install_prog$arg" # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= for arg do if test -n "$dest"; then files="$files $dest" dest="$arg" continue fi case $arg in -d) isdir=yes ;; -f) prev="-f" ;; -g) prev="-g" ;; -m) prev="-m" ;; -o) prev="-o" ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then prev= else dest="$arg" continue fi ;; esac # Aesthetically quote the argument. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$install_prog $arg" done if test -z "$install_prog"; then $echo "$modename: you must specify an install program" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi if test -n "$prev"; then $echo "$modename: the \`$prev' option requires an argument" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi if test -z "$files"; then if test -z "$dest"; then $echo "$modename: no file or destination specified" 1>&2 else $echo "$modename: you must specify a destination" 1>&2 fi $echo "$help" 1>&2 exit $EXIT_FAILURE fi # Strip any trailing slash from the destination. dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` test "X$destdir" = "X$dest" && destdir=. destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` # Not a directory, so check to see that there is only one file specified. set dummy $files if test "$#" -gt 2; then $echo "$modename: \`$dest' is not a directory" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi library_names= old_library= relink_command= # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ test "X$dir" = "X$file/" && dir= dir="$dir$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. if test "$inst_prefix_dir" = "$destdir"; then $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 exit $EXIT_FAILURE fi if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi $echo "$modename: warning: relinking \`$file'" 1>&2 $show "$relink_command" if $run eval "$relink_command"; then : else $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 exit $EXIT_FAILURE fi fi # See the names of the shared library. set dummy $library_names if test -n "$2"; then realname="$2" shift shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. $show "$install_prog $dir/$srcname $destdir/$realname" $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? if test -n "$stripme" && test -n "$striplib"; then $show "$striplib $destdir/$realname" $run eval "$striplib $destdir/$realname" || exit $? fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. for linkname do if test "$linkname" != "$realname"; then $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" fi done fi # Do each command in the postinstall commands. lib="$destdir/$realname" cmds=$postinstall_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # Install the pseudo-library for information purposes. name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` instname="$dir/$name"i $show "$install_prog $instname $destdir/$name" $run eval "$install_prog $instname $destdir/$name" || exit $? # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` ;; *.$objext) staticdest="$destfile" destfile= ;; *) $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE ;; esac # Install the libtool object if requested. if test -n "$destfile"; then $show "$install_prog $file $destfile" $run eval "$install_prog $file $destfile" || exit $? fi # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` $show "$install_prog $staticobj $staticdest" $run eval "$install_prog \$staticobj \$staticdest" || exit $? fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then file=`$echo $file|${SED} 's,.exe$,,'` stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin*|*mingw*) wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` ;; *) wrapper=$file ;; esac if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then notinst_deplibs= relink_command= # To insure that "foo" is sourced, and not "foo.exe", # finese the cygwin/MSYS system by explicitly sourcing "foo." # which disallows the automatic-append-.exe behavior. case $build in *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; *) wrapperdot=${wrapper} ;; esac # If there is no directory component, then add one. case $file in */* | *\\*) . ${wrapperdot} ;; *) . ./${wrapperdot} ;; esac # Check the variables that should have been set. if test -z "$notinst_deplibs"; then $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 exit $EXIT_FAILURE fi finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then # If there is no directory component, then add one. case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac fi libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 finalize=no fi done relink_command= # To insure that "foo" is sourced, and not "foo.exe", # finese the cygwin/MSYS system by explicitly sourcing "foo." # which disallows the automatic-append-.exe behavior. case $build in *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; *) wrapperdot=${wrapper} ;; esac # If there is no directory component, then add one. case $file in */* | *\\*) . ${wrapperdot} ;; *) . ./${wrapperdot} ;; esac outputname= if test "$fast_install" = no && test -n "$relink_command"; then if test "$finalize" = yes && test -z "$run"; then tmpdir="/tmp" test -n "$TMPDIR" && tmpdir="$TMPDIR" tmpdir="$tmpdir/libtool-$$" save_umask=`umask` umask 0077 if $mkdir "$tmpdir"; then umask $save_umask else umask $save_umask $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 continue fi file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` $show "$relink_command" if $run eval "$relink_command"; then : else $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 ${rm}r "$tmpdir" continue fi file="$outputname" else $echo "$modename: warning: cannot relink \`$file'" 1>&2 fi else # Install the binary that we compiled earlier. file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyways case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` ;; esac ;; esac $show "$install_prog$stripme $file $destfile" $run eval "$install_prog\$stripme \$file \$destfile" || exit $? test -n "$outputname" && ${rm}r "$tmpdir" ;; esac done for file in $staticlibs; do name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` # Set up the ranlib parameters. oldlib="$destdir/$name" $show "$install_prog $file $oldlib" $run eval "$install_prog \$file \$oldlib" || exit $? if test -n "$stripme" && test -n "$old_striplib"; then $show "$old_striplib $oldlib" $run eval "$old_striplib $oldlib" || exit $? fi # Do each command in the postinstall commands. cmds=$old_postinstall_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$future_libdirs"; then $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 fi if test -n "$current_libdirs"; then # Maybe just do a dry run. test -n "$run" && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi ;; # libtool finish mode finish) modename="$modename: finish" libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. cmds=$finish_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || admincmds="$admincmds $cmd" done IFS="$save_ifs" fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $run eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. test "$show" = : && exit $EXIT_SUCCESS $echo "----------------------------------------------------------------------" $echo "Libraries have been installed in:" for libdir in $libdirs; do $echo " $libdir" done $echo $echo "If you ever happen to want to link against installed libraries" $echo "in a given directory, LIBDIR, you must either use libtool, and" $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" $echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" $echo " during execution" fi if test -n "$runpath_var"; then $echo " - add LIBDIR to the \`$runpath_var' environment variable" $echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $echo " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $echo " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi $echo $echo "See any operating system documentation about shared libraries for" $echo "more information, such as the ld(1) and ld.so(8) manual pages." $echo "----------------------------------------------------------------------" exit $EXIT_SUCCESS ;; # libtool execute mode execute) modename="$modename: execute" # The first argument is the command name. cmd="$nonopt" if test -z "$cmd"; then $echo "$modename: you must specify a COMMAND" 1>&2 $echo "$help" exit $EXIT_FAILURE fi # Handle -dlopen flags immediately. for file in $execute_dlfiles; do if test ! -f "$file"; then $echo "$modename: \`$file' is not a file" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi dir= case $file in *.la) # Check to see that this really is a libtool archive. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi # Read the libtool library. dlname= library_names= # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" continue fi dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 exit $EXIT_FAILURE fi ;; *.lo) # Just add the directory containing the .lo file. dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. ;; *) $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -*) ;; *) # Do a test to see if this is really a libtool program. if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` args="$args \"$file\"" done if test -z "$run"; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables if test "${save_LC_ALL+set}" = set; then LC_ALL="$save_LC_ALL"; export LC_ALL fi if test "${save_LANG+set}" = set; then LANG="$save_LANG"; export LANG fi # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" $echo "export $shlibpath_var" fi $echo "$cmd$args" exit $EXIT_SUCCESS fi ;; # libtool clean and uninstall mode clean | uninstall) modename="$modename: $mode" rm="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) rm="$rm $arg"; rmforce=yes ;; -*) rm="$rm $arg" ;; *) files="$files $arg" ;; esac done if test -z "$rm"; then $echo "$modename: you must specify an RM program" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi rmdirs= origobjdir="$objdir" for file in $files; do dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` if test "X$dir" = "X$file"; then dir=. objdir="$origobjdir" else objdir="$dir/$origobjdir" fi name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` test "$mode" = uninstall && objdir="$dir" # Remember objdir for removal later, being careful to avoid duplicates if test "$mode" = clean; then case " $rmdirs " in *" $objdir "*) ;; *) rmdirs="$rmdirs $objdir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if (test -L "$file") >/dev/null 2>&1 \ || (test -h "$file") >/dev/null 2>&1 \ || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then . $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $objdir/$n" done test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" if test "$mode" = uninstall; then if test -n "$library_names"; then # Do each command in the postuninstall commands. cmds=$postuninstall_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" if test "$?" -ne 0 && test "$rmforce" != yes; then exit_status=1 fi done IFS="$save_ifs" fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. cmds=$old_postuninstall_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" if test "$?" -ne 0 && test "$rmforce" != yes; then exit_status=1 fi done IFS="$save_ifs" fi # FIXME: should reinstall the best remaining shared library. fi fi ;; *.lo) # Possibly a libtool object, so verify it. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then # Read the .lo file . $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" \ && test "$pic_object" != none; then rmfiles="$rmfiles $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" \ && test "$non_pic_object" != none; then rmfiles="$rmfiles $dir/$non_pic_object" fi fi ;; *) if test "$mode" = clean ; then noexename=$name case $file in *.exe) file=`$echo $file|${SED} 's,.exe$,,'` noexename=`$echo $name|${SED} 's,.exe$,,'` # $file with .exe has already been added to rmfiles, # add $file without .exe rmfiles="$rmfiles $file" ;; esac # Do a test to see if this is a libtool program. if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then relink_command= . $dir/$noexename # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then rmfiles="$rmfiles $objdir/lt-$name" fi if test "X$noexename" != "X$name" ; then rmfiles="$rmfiles $objdir/lt-${noexename}.c" fi fi fi ;; esac $show "$rm $rmfiles" $run $rm $rmfiles || exit_status=1 done objdir="$origobjdir" # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then $show "rmdir $dir" $run rmdir $dir >/dev/null 2>&1 fi done exit $exit_status ;; "") $echo "$modename: you must specify a MODE" 1>&2 $echo "$generic_help" 1>&2 exit $EXIT_FAILURE ;; esac if test -z "$exec_cmd"; then $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$generic_help" 1>&2 exit $EXIT_FAILURE fi fi # test -z "$show_help" if test -n "$exec_cmd"; then eval exec $exec_cmd exit $EXIT_FAILURE fi # We need to display help for each of the modes. case $mode in "") $echo \ "Usage: $modename [OPTION]... [MODE-ARG]... Provide generalized library-building support services. --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --finish same as \`--mode=finish' --help display this help message and exit --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] --quiet same as \`--silent' --silent don't print informational messages --tag=TAG use configuration variables from tag TAG --version print version information MODE must be one of the following: clean remove files from the build directory compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for a more detailed description of MODE. Report bugs to ." exit $EXIT_SUCCESS ;; clean) $echo \ "Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $echo \ "Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -prefer-pic try to building PIC objects only -prefer-non-pic try to building non-PIC objects only -static always build a \`.o' file suitable for static linking COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $echo \ "Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $echo \ "Usage: $modename [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $echo \ "Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $echo \ "Usage: $modename [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -static do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $echo \ "Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE ;; esac $echo $echo "Try \`$modename --help' for more information about other modes." exit $EXIT_SUCCESS # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/missing000077500000000000000000000245331321604176500261470ustar00rootroot00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2004-09-07.08 # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004 # Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # 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 to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case "$1" in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Send bug reports to ." exit 0 ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit 0 ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). case "$1" in lex|yacc) # Not GNU programs, they don't have --version. ;; tar) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case "$1" in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` fi if [ -f "$file" ]; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` fi touch $file ;; tar) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case "$firstarg" in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case "$firstarg" in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/sample/000077500000000000000000000000001321604176500260225ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/sample/Makefile.am000066400000000000000000000003501321604176500300540ustar00rootroot00000000000000# $Id: Makefile.am 25 2008-11-02 04:50:00Z naoaki $ EXTRA_DIST = \ sample.cpp \ sample.vcproj noinst_PROGRAMS = sample sample_SOURCES = \ sample.c sample_LDADD = ../lib/liblbfgs.la AM_CFLAGS = @CFLAGS@ INCLUDES = @INCLUDES@ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/sample/Makefile.in000066400000000000000000000314271321604176500300760ustar00rootroot00000000000000# Makefile.in generated by automake 1.9.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # $Id: Makefile.am 25 2008-11-02 04:50:00Z naoaki $ SOURCES = $(sample_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ noinst_PROGRAMS = sample$(EXEEXT) subdir = sample DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = PROGRAMS = $(noinst_PROGRAMS) am_sample_OBJECTS = sample.$(OBJEXT) sample_OBJECTS = $(am_sample_OBJECTS) sample_DEPENDENCIES = ../lib/liblbfgs.la DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(sample_SOURCES) DIST_SOURCES = $(sample_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ INCLUDES = @INCLUDES@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ prefix = @prefix@ program_transform_name = @program_transform_name@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ EXTRA_DIST = \ sample.cpp \ sample.vcproj sample_SOURCES = \ sample.c sample_LDADD = ../lib/liblbfgs.la AM_CFLAGS = @CFLAGS@ all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu sample/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu sample/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; for p in $$list; do \ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ echo " rm -f $$p $$f"; \ rm -f $$p $$f ; \ done sample$(EXEEXT): $(sample_OBJECTS) $(sample_DEPENDENCIES) @rm -f sample$(EXEEXT) $(LINK) $(sample_LDFLAGS) $(sample_OBJECTS) $(sample_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sample.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstPROGRAMS ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/sample/sample.c000066400000000000000000000037031321604176500274520ustar00rootroot00000000000000#include #include static lbfgsfloatval_t evaluate( void *instance, const lbfgsfloatval_t *x, lbfgsfloatval_t *g, const int n, const lbfgsfloatval_t step ) { int i; lbfgsfloatval_t fx = 0.0; for (i = 0;i < n;i += 2) { lbfgsfloatval_t t1 = 1.0 - x[i]; lbfgsfloatval_t t2 = 10.0 * (x[i+1] - x[i] * x[i]); g[i+1] = 20.0 * t2; g[i] = -2.0 * (x[i] * g[i+1] + t1); fx += t1 * t1 + t2 * t2; } return fx; } static int progress( void *instance, const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t fx, const lbfgsfloatval_t xnorm, const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step, int n, int k, int ls ) { printf("Iteration %d:\n", k); printf(" fx = %f, x[0] = %f, x[1] = %f\n", fx, x[0], x[1]); printf(" xnorm = %f, gnorm = %f, step = %f\n", xnorm, gnorm, step); printf("\n"); return 0; } #define N 100 int main(int argc, char *argv) { int i, ret = 0; lbfgsfloatval_t fx; lbfgsfloatval_t *x = lbfgs_malloc(N); lbfgs_parameter_t param; if (x == NULL) { printf("ERROR: Failed to allocate a memory block for variables.\n"); return 1; } /* Initialize the variables. */ for (i = 0;i < N;i += 2) { x[i] = -1.2; x[i+1] = 1.0; } /* Initialize the parameters for the L-BFGS optimization. */ lbfgs_parameter_init(¶m); //param.orthantwise_c = 1; //param.linesearch = LBFGS_LINESEARCH_BACKTRACKING; /* Start the L-BFGS optimization; this will invoke the callback functions evaluate() and progress() when necessary. */ ret = lbfgs(N, x, &fx, evaluate, progress, NULL, ¶m); /* Report the result. */ printf("L-BFGS optimization terminated with status code = %d\n", ret); printf(" fx = %f, x[0] = %f, x[1] = %f\n", fx, x[0], x[1]); lbfgs_free(x); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/sample/sample.cpp000066400000000000000000000057121321604176500300140ustar00rootroot00000000000000#include #include class objective_function { protected: lbfgsfloatval_t *m_x; public: objective_function() : m_x(NULL) { } virtual ~objective_function() { if (m_x != NULL) { lbfgs_free(m_x); m_x = NULL; } } int run(int N) { lbfgsfloatval_t fx; lbfgsfloatval_t *m_x = lbfgs_malloc(N); if (m_x == NULL) { printf("ERROR: Failed to allocate a memory block for variables.\n"); return 1; } /* Initialize the variables. */ for (int i = 0;i < N;i += 2) { m_x[i] = -1.2; m_x[i+1] = 1.0; } /* Start the L-BFGS optimization; this will invoke the callback functions evaluate() and progress() when necessary. */ int ret = lbfgs(N, m_x, &fx, _evaluate, _progress, this, NULL); /* Report the result. */ printf("L-BFGS optimization terminated with status code = %d\n", ret); printf(" fx = %f, x[0] = %f, x[1] = %f\n", fx, m_x[0], m_x[1]); return ret; } protected: static lbfgsfloatval_t _evaluate( void *instance, const lbfgsfloatval_t *x, lbfgsfloatval_t *g, const int n, const lbfgsfloatval_t step ) { return reinterpret_cast(instance)->evaluate(x, g, n, step); } lbfgsfloatval_t evaluate( const lbfgsfloatval_t *x, lbfgsfloatval_t *g, const int n, const lbfgsfloatval_t step ) { lbfgsfloatval_t fx = 0.0; for (int i = 0;i < n;i += 2) { lbfgsfloatval_t t1 = 1.0 - x[i]; lbfgsfloatval_t t2 = 10.0 * (x[i+1] - x[i] * x[i]); g[i+1] = 20.0 * t2; g[i] = -2.0 * (x[i] * g[i+1] + t1); fx += t1 * t1 + t2 * t2; } return fx; } static int _progress( void *instance, const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t fx, const lbfgsfloatval_t xnorm, const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step, int n, int k, int ls ) { return reinterpret_cast(instance)->progress(x, g, fx, xnorm, gnorm, step, n, k, ls); } int progress( const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t fx, const lbfgsfloatval_t xnorm, const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step, int n, int k, int ls ) { printf("Iteration %d:\n", k); printf(" fx = %f, x[0] = %f, x[1] = %f\n", fx, x[0], x[1]); printf(" xnorm = %f, gnorm = %f, step = %f\n", xnorm, gnorm, step); printf("\n"); return 0; } }; #define N 100 int main(int argc, char *argv) { objective_function obj; return obj.run(N); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/liblbfgs-1.9/sample/sample.vcproj000066400000000000000000000077361321604176500305450ustar00rootroot00000000000000 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/nSIFT/000077500000000000000000000000001321604176500233735ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/nSIFT/COPYRIGHT000077500000000000000000000033721321604176500246760ustar00rootroot00000000000000Copyright (c) 2005,2006,2007 Warren Cheung All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of the Insight Consortium, nor the names of any consortium members, nor of any contributors, may be used to endorse or promote products derived from this software without specific prior written permission. * Modified source versions must be plainly marked as such, and must not be misrepresented as being the original software. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This routine was modified by Chiara Paganelli and Marta Peroni from the one proposed by Warren Cheung in: http://www.insight-journal.org/browse/publication/207plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/nSIFT/README000077500000000000000000000002271321604176500242570ustar00rootroot00000000000000This is a modified version of the ITK nSIFT program, written by Warren Cheung. Please see the file COPYRIGHT for copyright and license information. itkScaleInvariantFeatureImageFilter.h000066400000000000000000000254731321604176500325400ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/nSIFT/*========================================================================= Program: ITK nSIFT Implemention (Header) Module: $RCSfile: itkScaleInvariantFeatureImageFilter.h,v $ Language: C++ Date: $Date: 2007/11/25 15:51:48 $ Version: $Revision: 1.0 $ Copyright (c) 2005,2006,2007 Warren Cheung All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of the Insight Consortium, nor the names of any consortium members, nor of any contributors, may be used to endorse or promote products derived from this software without specific prior written permission. * Modified source versions must be plainly marked as such, and must not be misrepresented as being the original software. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This routine was modified by Chiara Paganelli and Marta Peroni from the one proposed by Warren Cheung in: http://www.insight-journal.org/browse/publication/207 =========================================================================*/ #define VERBOSE #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #ifndef __itkScaleInvariantFeatureImageFilter_h #define __itkScaleInvariantFeatureImageFilter_h #include "itkImageRegistrationMethod.h" #include "itkLinearInterpolateImageFunction.h" #include "itkNearestNeighborInterpolateImageFunction.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkAffineTransform.h" #include "itkIdentityTransform.h" #include "itkResampleImageFilter.h" #include "itkDiscreteGaussianImageFilter.h" #include "itkSubtractImageFilter.h" #include "itkGradientImageFilter.h" #include "itkGradientMagnitudeImageFilter.h" #include "itkMultiplyImageFilter.h" #include "itkGaussianImageSource.h" #include "itkConstNeighborhoodIterator.h" #include "itkPointSet.h" #include "itkVector.h" #include "itkDiscreteHessianGaussianImageFunction.h" #include #include "itkRescaleIntensityImageFilter.h" #include namespace itk { /** \class ScaleInvariantFeatureImageFilter * \brief Generate and match scale invariant features from an image input. * * This class takes the input image and locates scale invariant features in * the image. The result is a set of keypoints, each with an associated * vector of values (the corresponding feature). Two sets of keypoints * can then be matched, to determine which points in the sets are likely * to correspond, by comparing feature vectors. * */ template class ITK_EXPORT ScaleInvariantFeatureImageFilter { public: /** typedefs to facilitate access to the image-related types */ typedef typename TFixedImageType::PixelType PixelType; typedef typename TFixedImageType::Pointer FixedImagePointer; typedef typename TFixedImageType::IndexType IndexType; typedef typename TFixedImageType::SizeType::SizeValueType SizeValueType; /** used for validating results from synthetic images */ typedef typename itk::AffineTransform< double,VDimension> TransformType; /** multidimensional histogram for the features */ typedef Array< float > FeatureType; /** keypoints, storing the associated feature as well */ typedef PointSet< FeatureType, VDimension, DefaultStaticMeshTraits< FeatureType, VDimension, VDimension, double > > PointSetType; typedef typename PointSetType::PointType PointType; typedef typename PointSetType::Pointer PointSetTypePointer; /** Filters for scaling and resampling images for the multiple scales */ typedef ResampleImageFilter< TFixedImageType, TFixedImageType > ResampleFilterType; /** Constructor to set default values */ ScaleInvariantFeatureImageFilter(); /** Writes an image to disk */ void writeImage(FixedImagePointer fixedImage, const char *filename); /** Create a filter that resamples the image (scale up or down) */ typename ResampleFilterType::Pointer getScaleResampleFilter ( typename TFixedImageType::Pointer fixedImage, float scale ); /** Set Parameters */ void SetDoubling (bool tmp); void SetNumScales ( unsigned int tmp); void SetMatchRatio ( float tmp); void SetInitialSigma(float InitialSigma); void SetDescriptorDimension (float descriptor_dim); void SetContrast (float contrast); void SetCurvature (float curvature); /** Generate and return the scale invariant keypoints and features */ PointSetTypePointer getSiftFeatures(FixedImagePointer fixedImageInput, bool flag_curve, bool normalization, const char *filename_phy_max, const char *filename_phy_min, const char *filename_im_max, const char *filename_im_min,const char *filename_rej_contrast,const char *filename_rej_curvature); /* Save the keypoints to a file */ void save_pointset (const char* filename); /** Match keypoints based on similarity of features. Matches are printed * to standard out. Supply the inverse transform to get performance * measures.*/ static void MatchKeypointsFeatures( PointSetTypePointer keypoints1, PointSetTypePointer keypoints2, const char *filename_phy_match1, const char *filename_phy_match2, float max_feature_distance_ratio); private: /** Filter to obtain gradient directions and magnitudes */ typedef itk::GradientImageFilter GradientFilterType; typedef typename GradientFilterType::OutputImageType GradientImageType; typedef itk::GradientMagnitudeImageFilter GradientMagFilterType; /** Shorthand for an identity transform */ typedef IdentityTransform< double, VDimension > IdentityTransformType; typename IdentityTransformType::Pointer m_IdentityTransform; /** Scale up the original image by a factor of 2 before processing */ bool m_DoubleOriginalImage; /** Number of image pyramid levels (octaves) to test */ unsigned int m_ImageScalesTestedNumber; /** Factor by which the images are scaled between pyramid levels */ float m_ScalingFactor; /** The range of Gaussian sigma that will be tested */ float m_GaussianSigma; /** Number of Gaussian Images that will be used to sample the range of * sigma values ... */ unsigned int m_GaussianImagesNumber; /** ... determining the number of difference of gaussian images ... */ unsigned int m_DifferenceOfGaussianImagesNumber; /** ... determining the number of sets of images we can test for * feature points */ unsigned int m_DifferenceOfGaussianTestsNumber; /** Threshold on image contrast. Minimum voxel intensity for a feature point */ float m_MinKeypointValue; /** Threshold on image curvature */ float m_ThresholdPrincipalCurve; /** When looking for difference of Gaussian extrema in the images, * consider a voxel to be extremal even if there are voxels * that are this much more extreme.*/ float m_ErrorThreshold; /** When matching points, reject a match if the ratio: * \frac{\textrm{distance to best match}}{\textrm{distance to second-best match}} * is greater than this value*/ float m_MaxFeatureDistanceRatio; PointSetTypePointer m_KeypointSet; long m_PointsCount; /** Distance from the centre to the edge of the hypercube * summarised by the nSIFT feature*/ unsigned int m_SIFTHalfWidth; /** The hypercube edge length (in voxels) of the subregion summarised * by each multidimensional histogram of the nSIFT feature*/ unsigned int m_SIFTSubfeatureWidth; /** Number of bin used to summarise the hyperspherical coordinates * of the voxels in each subregion*/ unsigned int m_SIFTSubfeatureBins; /** The sigma for the Gaussian filtering for the j-th image on a level * of the image pyramid*/ double GetGaussianScale( int j ); /** Returns an image where all gradients are converted to hyperspherical * coordinates*/ typename GradientImageType::Pointer GetHypersphericalCoordinates(typename GradientImageType::Pointer inputImg); /** Returns the value of the principal curvature - thresholding on image curvature */ typedef itk::DiscreteHessianGaussianImageFunction< TFixedImageType, PixelType > HessianGaussianImageFunctionType; typedef itk::HessianRecursiveGaussianImageFilter< TFixedImageType > myFilterType; typedef typename myFilterType::OutputImageType myHessianImageType; unsigned int GetHessian(typename myHessianImageType::Pointer ImgInput, IndexType pixelIndex, bool isMax, bool isMin, int i, int j); /** Size of the nSIFT feature */ unsigned int SiftFeatureSize(); /** Used when generating nSIFT features to figure out what portion * of the nSIFT feature vector the current summary histogram starts at*/ unsigned int DeltaToSiftIndex (int delta[]); /** Generate nSIFT feature for pixel at pixelIndex */ FeatureType GetSiftKey(typename GradientImageType::Pointer inputImg, FixedImagePointer multImg, IndexType pixelIndex); /** Determine whether voxel at pixelIndex with intensity * pixelvalue is the local max/min*/ void CheckLocalExtrema(FixedImagePointer image, IndexType pixelIndex, PixelType pixelValue, bool &isMax, bool &isMin, bool checkCentre); /** Generate the nSIFT feature at a point*/ FeatureType GetFeatures( FixedImagePointer fixedImage, typename GradientImageType::Pointer hgradImage, PointType &point, float currScale); }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkScaleInvariantFeatureImageFilter.hxx" #endif #endif /* SIFTKEY_H */ itkScaleInvariantFeatureImageFilter.hxx000066400000000000000000001464461321604176500331240ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/nSIFT/*========================================================================= Program: ITK nSIFT Implemention (Template Source) Module: $RCSfile: itkScaleInvariantFeatureImageFilter.txx,v $ Language: C++ Date: $Date: 2007/11/25 15:51:48 $ Version: $Revision: 1.0 $ Copyright (c) 2005,2006,2007 Warren Cheung All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of the Insight Consortium, nor the names of any consortium members, nor of any contributors, may be used to endorse or promote products derived from this software without specific prior written permission. * Modified source versions must be plainly marked as such, and must not be misrepresented as being the original software. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This routine was modified by Chiara Paganelli and Marta Peroni from the one proposed by Warren Cheung in: http://www.insight-journal.org/browse/publication/207 =========================================================================*/ #define VERBOSE #ifndef SIFTKEY_CLASS #define SIFTKEY_CLASS #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "itkScaleInvariantFeatureImageFilter.h" #include #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkImage.h" #include #include #include "itkRescaleIntensityImageFilter.h" /* GCS 2012-09-27: The original code had a #ifdef which included legal C++ for MSVC, but illegal C++ for other compilers. I've replaced this so it uses the following ifdef instead. If you want the illegal code, uncomment the below. */ //#define USE_ORIGINAL_BROKEN_CODE 1 const float PI=3.14159265; namespace itk { // ---- PARAMETERS: template void ScaleInvariantFeatureImageFilter ::SetNumScales ( unsigned int tmp) //number of octaves { m_ImageScalesTestedNumber = tmp; //m_ImageScalesTestedNumber = 3; } template ScaleInvariantFeatureImageFilter::ScaleInvariantFeatureImageFilter() { m_ScalingFactor = 2.0; //scaling factor m_DifferenceOfGaussianTestsNumber = 3; //2 m_ErrorThreshold = 0.0; // Derived from above: m_DifferenceOfGaussianImagesNumber = m_DifferenceOfGaussianTestsNumber+2; m_GaussianImagesNumber = m_DifferenceOfGaussianImagesNumber+1; m_IdentityTransform = IdentityTransformType::New(); } template void ScaleInvariantFeatureImageFilter ::SetInitialSigma( float InitialSigma) //initial sigma for Gaussian blur { m_GaussianSigma = InitialSigma; } template void ScaleInvariantFeatureImageFilter ::SetContrast( float contrast) //contrast threshold value { m_MinKeypointValue = contrast; //0.03; // if we assume image pixel value in the range [0,1] (otherwise 72) } template void ScaleInvariantFeatureImageFilter ::SetCurvature( float curvature) //curvature threshold value { m_ThresholdPrincipalCurve = curvature; //172.3025; //if we assume image pixel value in the range [0,1] } template void ScaleInvariantFeatureImageFilter ::SetDescriptorDimension( float descriptor_dim) //descriptor dimension { m_SIFTHalfWidth = descriptor_dim; //12.0; //8.0; // This MUST be a multiple of m_SIFTSubfeatureWidth: // it is half the size of the descriptor // for phantom: region of the descriptor=16 so m_SIFTHalfWidth=8.0 // for image: region of the descriptor=24 so m_SIFTHalfWidth=12.0 m_SIFTSubfeatureWidth = 4; //number of subregions along the dimension of the descriptor m_SIFTSubfeatureBins = 8; //bins of the descriptor } template void ScaleInvariantFeatureImageFilter ::SetMatchRatio ( float tmp) //Matching threshold { m_MaxFeatureDistanceRatio = tmp; } template void ScaleInvariantFeatureImageFilter ::SetDoubling (bool tmp) //Image Doubling { m_DoubleOriginalImage = tmp; } template double ScaleInvariantFeatureImageFilter ::GetGaussianScale( int j ) //Sigma update { /*sigma{i}=k*sigma{i-1}; with k=2^(1/s); but for indipendent variables: sigma_{total}^2 = sigma_{i}^2 + sigma_{i-1}^2; so sigma_{i}^2 = sigma_{total}^2 - sigma_{i-1}^2;*/ double k=0; k = pow( 2.0, 1.0 / (double) m_DifferenceOfGaussianTestsNumber); if (j==0){ return m_GaussianSigma;} else{ double sig_prev=0; double sig_total=0; double variance_gauss=0; sig_prev = pow( k, j-1 ) * m_GaussianSigma; sig_total = sig_prev * k; variance_gauss = sqrt( sig_total * sig_total - sig_prev * sig_prev ); return variance_gauss; } } template typename ScaleInvariantFeatureImageFilter::GradientImageType::Pointer ScaleInvariantFeatureImageFilter ::GetHypersphericalCoordinates(typename GradientImageType::Pointer inputImg) // Compute hypersferical coordinates (spherycal coordinates for 3D) from Gradient Image // Returns an image in which each voxel is described by its hypersferical coordinates { typedef itk::ImageRegionIteratorWithIndex< GradientImageType > ImageIteratorType; typedef itk::ImageRegionConstIteratorWithIndex< GradientImageType > ConstImageIteratorType; typedef itk::ImageRegionConstIteratorWithIndex< TFixedImageType > ConstFixedImageIteratorType; typename GradientImageType::Pointer outputImg = GradientImageType::New(); // Copy attributes outputImg->SetRegions(inputImg->GetLargestPossibleRegion()); outputImg->CopyInformation( inputImg ); outputImg->Allocate(); ConstImageIteratorType inputIt(inputImg, inputImg->GetLargestPossibleRegion()); ImageIteratorType outputIt(outputImg, inputImg->GetLargestPossibleRegion()); for ( inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd(); ++inputIt, ++outputIt) { typename GradientImageType::PixelType x = inputIt.Get(); typename GradientImageType::PixelType p; // position 0 is the norm p[0] = x.GetNorm(); // position 1 is arctan (x0 / x1) (azimuth) p[1] = atan2( x[0],x[1] ); // Iterate over all the positions // position k is arctan (x_k-1 / (x_k * cos p_k)) for (unsigned int k = 2; k < x.Size(); ++k) { p[k] = atan2( x[k-1], x[k] * cos(p[k-1])); //p[2]: elevation } outputIt.Set(p); } return outputImg; } template unsigned int ScaleInvariantFeatureImageFilter ::SiftFeatureSize() // compute: 4^n*8^(n-1), with n=dimension // example for 3D: in a region of 16*16*16 we build sub-regions 4*4*4 // with 8*8 bin (for each orientation - azimuth and elevation) { unsigned int size = 1; for (unsigned int i = 0; i < VDimension; ++i) { size *= (m_SIFTHalfWidth * 2 / m_SIFTSubfeatureWidth ); if (i > 0) size *= m_SIFTSubfeatureBins; } return size; } template unsigned int ScaleInvariantFeatureImageFilter ::DeltaToSiftIndex (int delta[]) // Convert the delta iterator into index to the // start of the SIFT histogram { unsigned int bin = 0; unsigned int binpos = 1; //std::cerr << "Converting delta: "; for (unsigned int i = 0; i < VDimension; ++i) { //std::cerr << delta[i]; unsigned int tmp = (delta[i] + m_SIFTHalfWidth) / m_SIFTSubfeatureWidth; bin += tmp * binpos; binpos *= (m_SIFTHalfWidth * 2 / m_SIFTSubfeatureWidth ); } for (unsigned int i = 1; i < VDimension; ++i) { bin *= m_SIFTSubfeatureBins;} return bin; } template typename ScaleInvariantFeatureImageFilter::FeatureType ScaleInvariantFeatureImageFilter ::GetSiftKey(typename GradientImageType::Pointer inputImg, FixedImagePointer multImg, IndexType pixelIndex) //Computes ORIENTATION HISTOGRAM { //std::cerr << "GetSiftKey..." << std::endl; FeatureType sifthistogram(this->SiftFeatureSize()); sifthistogram.Fill(0); // delta iterates from -m_SIFTHalfWidth to m_SIFTHalfWidth-1 // in each dimensions int delta[VDimension]; for (int k = 0; k < VDimension; ++k) { delta[k] = -m_SIFTHalfWidth; } typename GradientImageType::SizeType regionSize = inputImg->GetLargestPossibleRegion().GetSize(); while(1) { unsigned int siftbin = this->DeltaToSiftIndex(delta); // std::cerr << "Siftbin:" << siftbin << std::endl; // Get pixel index. Clamp to image edges IndexType tmpIndex; for (int k=0; k < VDimension; ++k) { if ((pixelIndex[k] + delta[k]) < 0) { tmpIndex[k] = 0; } else { tmpIndex[k] = pixelIndex[k] + delta[k]; if (((SizeValueType) tmpIndex[k]) >= regionSize[k]) tmpIndex[k] = regionSize[k]-1; } //std::cout << "tmpIndex: "<< tmpIndex[k] << std::endl; } //std::cerr << "Pixel:" << tmpIndex << std::endl; typename GradientImageType::PixelType x = inputImg->GetPixel(tmpIndex); // Get histogram bin // Iterate over all the positions unsigned int bin = 0; unsigned int binpos = 1; for (unsigned int k = 1; k < x.Size(); ++k) { // Rescale from -PI to PI -> 0 to m_HistogramBinsNumber-1 float p; p = (x[k] + PI) * (float) m_SIFTSubfeatureBins / (2.0 * PI); if (p < 0 || p >= m_SIFTSubfeatureBins) p = 0; bin += (unsigned int) p * binpos; binpos *= m_SIFTSubfeatureBins; //std::cout << "p: "<< p << std::endl; } bin += siftbin; // Fill Sift Index bin if (bin > this->SiftFeatureSize()) { // VERY BAD std::cerr << bin << " > " << this->SiftFeatureSize() << " Warning -- Overload2\n"; } sifthistogram[bin] += x[0] * multImg->GetPixel(tmpIndex); //fill histogram bin //std::cerr << "x0: "<GetPixel(tmpIndex)< void ScaleInvariantFeatureImageFilter ::CheckLocalExtrema(FixedImagePointer image, IndexType pixelIndex, PixelType pixelValue, bool &isMax, bool &isMin, bool checkCentre) // Computes Local Extrema (Maxima & Minima) { int delta[VDimension]; for (int k = 0; k < VDimension; ++k) { delta[k] = -1; } while(1) { bool isZero=true; if (!checkCentre) { for (int k=0; k < VDimension; ++k) { if(delta[k] != 0) { isZero = false; break; } } } if (checkCentre || !isZero) { // Check if not the centre IndexType tmpIndex; for (int k=0; k < VDimension; ++k) { tmpIndex[k] = pixelIndex[k] + delta[k]; } typename TFixedImageType::PixelType tmpValue = image->GetPixel(tmpIndex); //std::cout << "...Comparing to ( "; // //for (int k = 0; k < VDimension; ++k) //{ // std::cout << tmpIndex[k] << " "; // std::cout << pixelIndex[k] << " "; // std::cout << delta[k] << "\n"; ////std::cout << ") = " << tmpValue << "\n"; //} // Treat as equality if within the error bound //Finite difference derivative if (((tmpValue - pixelValue) <= m_ErrorThreshold) && ((tmpValue - pixelValue) >= -m_ErrorThreshold)) { isMax = false; isMin = false; } else if (tmpValue > pixelValue) { isMax = false; } else if (tmpValue < pixelValue) { isMin = false; } if (!isMax && !isMin) break; } // Increment delta bool resetdelta=false; for(int k=0; k <= VDimension; ++k) { if (k == VDimension) { resetdelta = true; break; // done } if (delta[k] < 1) { ++delta[k]; //std::cout << "...increment delta ( "; //std::cout << delta[k] << " \n"; break; } delta[k] = -1; // reset and increment the next pos } if(resetdelta) break; } } template typename ScaleInvariantFeatureImageFilter::FeatureType ScaleInvariantFeatureImageFilter ::GetFeatures( FixedImagePointer fixedImage, typename GradientImageType::Pointer hgradImage, PointType &point, float currScale) { // KEYPOINT DESCRIPTOR: // Input: Image, Gradient Image, Point // Output: Vector of direction // Generate the Gaussian typedef GaussianImageSource GaussianImageSourceType; typename GaussianImageSourceType::Pointer gaussImgSource; typename GaussianImageSourceType::ArrayType sigma; gaussImgSource = GaussianImageSourceType::New(); gaussImgSource->SetNormalized(true); gaussImgSource->SetSpacing(fixedImage->GetSpacing()); gaussImgSource->SetSize(fixedImage->GetLargestPossibleRegion().GetSize()); gaussImgSource->SetDirection(fixedImage->GetDirection()); gaussImgSource->SetOrigin(fixedImage->GetOrigin()); gaussImgSource->SetMean(point); // Simulate the 16x16 Gaussian window descriptor // use sigma equal to half the descriptor window width for (int i = 0; i < VDimension; ++i) sigma[i]=m_SIFTHalfWidth; //sigma[i] = 8.00; gaussImgSource->SetSigma(sigma); gaussImgSource->Update(); /*char filename[256]; sprintf(filename, "GaussianCircle.mha"); this->writeImage(gaussImgSource->GetOutput(), filename);*/ IndexType pixelIndex; fixedImage->TransformPhysicalPointToIndex(point, pixelIndex); // return the Gaussian weighted Histogram return this->GetSiftKey(hgradImage, gaussImgSource->GetOutput(), pixelIndex); } template void ScaleInvariantFeatureImageFilter ::writeImage(FixedImagePointer fixedImage, const char *filename) { typedef itk::Image< float, VDimension > myImageType; typedef itk::ImageFileWriter< myImageType > myWriterType; typedef itk::ResampleImageFilter< TFixedImageType, myImageType > myResampleFilterType; typename myResampleFilterType::Pointer resampler = myResampleFilterType::New(); resampler->SetInput(fixedImage); resampler->SetReferenceImage(fixedImage); resampler->SetUseReferenceImage(true); typename myWriterType::Pointer writer = myWriterType::New(); writer->SetFileName( filename ); //outputFilename writer->SetInput( resampler->GetOutput()); std::cout << "[Writing file << " << filename << "]"; try { writer->Update(); } catch( itk::ExceptionObject & err ) { std::cerr << "ExceptionObject caught !" << std::endl; std::cerr << err << std::endl; } } template typename ScaleInvariantFeatureImageFilter::ResampleFilterType::Pointer ScaleInvariantFeatureImageFilter ::getScaleResampleFilter ( typename TFixedImageType::Pointer fixedImage, float scale ) // Create a filter that resamples the image (scale up or down) { typename ResampleFilterType::Pointer scaler = ResampleFilterType::New(); scaler->SetInput( fixedImage ); // Change the size of the image typename TFixedImageType::SizeType size = fixedImage->GetLargestPossibleRegion().GetSize(); for (int k = 0; k < VDimension; ++k) size[k] = (unsigned int) floor(size[k] * scale); scaler->SetSize( size ); //std::cout << " VDIM: " << VDimension << std::endl; //std::cout << " SIZE AFTER RASAMPLE: " << size[0] << " " << size[1] << std::endl; // Change the spacing of the image typename TFixedImageType::SpacingType spacing = fixedImage->GetSpacing(); for (int k = 0; k < VDimension; ++k) spacing[k] = (spacing[k] / scale); scaler->SetOutputSpacing( spacing ); //std::cout << " SPACING AFTER RESAMPLE: " << spacing[0] << " " << spacing[1] << std::endl; //Origin // typename TFixedImageType::PointType origin = fixedImage->GetOrigin(); scaler->SetOutputOrigin( fixedImage->GetOrigin() ); //Orientation typename TFixedImageType::DirectionType direction; direction.SetIdentity(); direction = fixedImage->GetDirection(); scaler->SetOutputDirection( fixedImage->GetDirection() ); //Interpolation: linear interpolation typedef itk::LinearInterpolateImageFunction< TFixedImageType, double > InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); scaler->SetInterpolator( interpolator ); scaler->SetDefaultPixelValue( 0 ); scaler->SetTransform( m_IdentityTransform ); scaler->Update(); return scaler; } template unsigned int ScaleInvariantFeatureImageFilter ::GetHessian(typename myHessianImageType::Pointer ImgInput, IndexType pixelIndex, bool isMax, bool isMin, int i, int j) { // (GLOBAL) HESSIAN - for threshold on curvature typename HessianGaussianImageFunctionType::TensorType hessian; hessian.Fill(0.0); hessian=ImgInput->GetPixel(pixelIndex); /*std::cout<<"Global Hessian "<0){P=1;} PrincipalCurve=(Tr*Tr)/Det; // if (PrincipalCurve0){M=1;} } if(VDimension==3) { Tr=hessian[0]+hessian[3]+hessian[5]; Det=hessian[0]*hessian[3]*hessian[5]+2*hessian[1]*hessian[4]*hessian[2]-hessian[0]*hessian[4]*hessian[4]-hessian[3]*(hessian[2])*hessian[2]-hessian[5]*(hessian[1])*hessian[1]; Product=Tr*Det; // if (Product>0){P=1;} PrincipalCurve=(Tr*Tr*Tr)/Det; // if (PrincipalCurve0){M=1;} } if ((Product>0) && (Minors>0)&&(PrincipalCurve typename ScaleInvariantFeatureImageFilter::PointSetTypePointer ScaleInvariantFeatureImageFilter ::getSiftFeatures ( FixedImagePointer fixedImageInput, bool flag_curve, bool normalization, const char *filename_phy_max, const char *filename_phy_min, const char *filename_im_max, const char *filename_im_min, const char *filename_rej_contrast, const char *filename_rej_curvature) { unsigned int numMin = 0, numMax = 0, numReject = 0; m_KeypointSet = PointSetType::New(); m_PointsCount = 0; // Image normalization [0,1] typedef itk::RescaleIntensityImageFilter< TFixedImageType, TFixedImageType > RescaleFilterType; typename RescaleFilterType::Pointer rescaleFilter = RescaleFilterType::New(); rescaleFilter->SetInput(fixedImageInput); rescaleFilter->SetOutputMinimum(0); rescaleFilter->SetOutputMaximum(1); typename TFixedImageType::Pointer fixedImage = TFixedImageType::New(); if (!normalization) {fixedImage=fixedImageInput;} //no normalization -> implies no curvature threshold else{fixedImage=rescaleFilter->GetOutput();} //normalization //fixedImage->DisconnectPipeline(); /*char filename[256]; sprintf(filename, "InputImage.mha"); this->writeImage(fixedImage, filename);*/ // Declare Gaussian typedef itk::DiscreteGaussianImageFilter GaussianFilterType; // Declare DoG typedef itk::SubtractImageFilter DifferenceFilterType; #if USE_ORIGINAL_BROKEN_CODE typename TFixedImageType::Pointer dogImage[m_DifferenceOfGaussianImagesNumber]; #else std::vector dogImage(m_DifferenceOfGaussianImagesNumber); #endif typename TFixedImageType::Pointer gaussianImage_ref = TFixedImageType::New(); // Declare Gradient #if USE_ORIGINAL_BROKEN_CODE typename GradientImageType::Pointer gradImage[m_ImageScalesTestedNumber]; typename GradientImageType::Pointer hgradImage[m_ImageScalesTestedNumber]; FixedImagePointer gradMagImage[m_ImageScalesTestedNumber]; #else std::vector gradImage(m_ImageScalesTestedNumber); std::vector hgradImage(m_ImageScalesTestedNumber); std::vector gradMagImage(m_ImageScalesTestedNumber); #endif float currScale = 0.5; // FOR EACH OCTAVE i for (unsigned int i = 0; i < m_ImageScalesTestedNumber; ++i) { std::cout << "Computing Octave Level " << i << "... ("; typename TFixedImageType::Pointer scaleImage = TFixedImageType::New(); typename ResampleFilterType::Pointer scaler = ResampleFilterType::New(); typename GaussianFilterType::Pointer tmpGaussianFilter = GaussianFilterType::New(); //this is a new gaussian filter for aliasing correction tmpGaussianFilter->ReleaseDataFlagOn(); //if(i>0 ) //{ //char filename[256]; //sprintf(filename, "gauss_ref-%d.mha", i); //this->writeImage(gaussianImage_ref, filename);} if (i == 0 && !m_DoubleOriginalImage) { //NO DOUBLING && FIRST OCTAVE //ANTI_ALIASING FILTER: sigma=0.5 double variance_anti = 0.5*0.5; tmpGaussianFilter->SetVariance(variance_anti); tmpGaussianFilter->SetInput( fixedImage ); //Image Spacing-wise smoothing (physical space) tmpGaussianFilter->SetUseImageSpacing(true); //pixel-wise smoothing (pixel space) //tmpGaussianFilter->SetUseImageSpacing(false); try { tmpGaussianFilter->Update(); } catch( itk::ExceptionObject & excep ) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } scaleImage = tmpGaussianFilter->GetOutput(); scaleImage->DisconnectPipeline(); //scaleImage = fixedImage; //gaussianImage_ref=fixedImage; } else { if (i == 0 && m_DoubleOriginalImage) {// DOUBLING && FIRST OCTAVE // Input is the fixed Image. //ANTI_ALIASING FILTER: sigma=0.5; //this->writeImage(fixedImage, "Input.mha"); //gaussianImage_ref=fixedImage; //double variance = (double)m_SigmaAliasing*m_SigmaAliasing; double variance_anti = 0.5*0.5; tmpGaussianFilter->SetVariance(variance_anti); tmpGaussianFilter->SetInput( fixedImage ); //Image Spacing-wise smoothing tmpGaussianFilter->SetUseImageSpacing(true); try { tmpGaussianFilter->Update(); } catch( itk::ExceptionObject & excep ) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } scaleImage = tmpGaussianFilter->GetOutput(); scaleImage->DisconnectPipeline(); scaler = getScaleResampleFilter ( scaleImage, m_ScalingFactor ); //doubled image typename GaussianFilterType::Pointer tmpGaussianFilter = GaussianFilterType::New(); //now we need to filter with sigma == 1 because we doubled the size of the image //ANTI_ALIASING FILTER: sigma=1; double variance1 = 1*1; tmpGaussianFilter->SetVariance(variance1); tmpGaussianFilter->SetInput( scaler->GetOutput() ); //Image Spacing-wise smoothing tmpGaussianFilter->SetUseImageSpacing(true); try { tmpGaussianFilter->Update(); } catch( itk::ExceptionObject & excep ) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } scaleImage = tmpGaussianFilter->GetOutput(); scaleImage->DisconnectPipeline(); char filename[256]; sprintf(filename, "double_image.mha"); this->writeImage(scaleImage, filename); } else { //DOWN_SAMPLING (by a factor of 2) FOR THE NEXT OCTAVE // Input is the 2*sigma smoothed image from the previous octave scaler = getScaleResampleFilter ( gaussianImage_ref , 1.0 / m_ScalingFactor ); scaleImage = scaler->GetOutput(); } // typename TFixedImageType::SpacingType spacing = scaleImage->GetSpacing(); // typename TFixedImageType::PointType origin = scaleImage->GetOrigin(); // typename TFixedImageType::DirectionType direction = scaleImage->GetDirection(); //std::cout << " SPACING AFTER ALIAS: " << spacing[0] << " " << spacing[1] <<" "<< spacing[2] <GetLargestPossibleRegion().GetSize(); for (int j = 0; j < VDimension; ++j) std::cout << gsize[j] << " "; } //COMPUTE GRADIENT std::cout << "...Computing Gradient..."; typename GradientFilterType::Pointer tmpGradFilter = GradientFilterType::New(); tmpGradFilter->ReleaseDataFlagOn(); tmpGradFilter->SetInput(scaleImage); // Do this in physical space tmpGradFilter->SetUseImageSpacing(true); tmpGradFilter->Update(); gradImage[i] = tmpGradFilter->GetOutput(); hgradImage[i] = this->GetHypersphericalCoordinates(gradImage[i]); typename GradientMagFilterType::Pointer tmpGradMagFilter = GradientMagFilterType::New(); tmpGradMagFilter->ReleaseDataFlagOn(); tmpGradMagFilter->SetInput(scaleImage); // Do this in physical space tmpGradMagFilter->SetUseImageSpacing(true); tmpGradMagFilter->Update(); gradMagImage[i] = tmpGradMagFilter->GetOutput(); std::cout << "...Done\n"; typename TFixedImageType::Pointer gaussianImage_old = TFixedImageType::New(); typename TFixedImageType::Pointer gaussianImage_new = TFixedImageType::New(); typename TFixedImageType::Pointer gaussianImage_start = TFixedImageType::New(); // COMPUTE GAUSSIAN FOR EACH SCALE j IN EACH OCTAVE i for (unsigned int j = 0; j < m_GaussianImagesNumber; ++j) { #ifdef VERBOSE std::cout << "Setting Up Gaussian Filter " << i << "-" << j << "..."; std::cout.flush(); #endif if (j==0) { typename GaussianFilterType::Pointer tmpGaussianFilter = GaussianFilterType::New(); /* Variance is square of the sigma * sigma = (2^(j/s)*sigma) */ double variance = this->GetGaussianScale(j); std::cout<<"scale: "<ReleaseDataFlagOn(); tmpGaussianFilter->SetVariance(variance); tmpGaussianFilter->SetInput( scaleImage ); // physical-wise smoothing tmpGaussianFilter->SetUseImageSpacing(true); try { tmpGaussianFilter->Update(); } catch( itk::ExceptionObject & excep ) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } gaussianImage_start= tmpGaussianFilter->GetOutput(); gaussianImage_start->DisconnectPipeline(); /*char filename[256]; sprintf(filename, "gauss-%d-%d.mha", i, j); this->writeImage(gaussianImage_start, filename);*/ //tmpGaussianFilter->ReleaseDataFlagOff(); } if(j>0) { if(j==1) gaussianImage_old=gaussianImage_start; typename GaussianFilterType::Pointer tmpGaussianFilter = GaussianFilterType::New(); /* Variance is square of the sigma * sigma = (2^(j/s)*sigma) */ double variance = this->GetGaussianScale(j); std::cout<<"scale: "<ReleaseDataFlagOn(); tmpGaussianFilter->SetVariance(variance); tmpGaussianFilter->SetInput( scaleImage ); // physical-wise smoothing tmpGaussianFilter->SetUseImageSpacing(true); try { tmpGaussianFilter->Update(); } catch( itk::ExceptionObject & excep ) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } gaussianImage_new = tmpGaussianFilter->GetOutput(); gaussianImage_new->DisconnectPipeline(); //tmpGaussianFilter->ReleaseDataFlagOff(); if(j==m_DifferenceOfGaussianTestsNumber) { gaussianImage_ref=gaussianImage_new; } // typename TFixedImageType::SpacingType spacing = gaussianImage_new->GetSpacing(); #ifdef VERBOSE std::cout << "Done\n"; std::cout.flush(); #endif #ifdef VERBOSE std::cout << "Setting Up DoG Filter " << i << "-" << j << "..."; std::cout.flush(); #endif if (jSetInput1( gaussianImage_old ); tmpDogFilter->SetInput2( gaussianImage_new ); tmpDogFilter->Update(); dogImage[j-1] = tmpDogFilter->GetOutput(); //tmpDogFilter->ReleaseDataFlagOff(); //typename TFixedImageType::SpacingType spacing = dogImage[j-1]->GetSpacing(); //std::cout << " SPACING DOG IMAGE: " << spacing[0] << " " << spacing[1] << std::endl; /*char filename[256]; sprintf(filename, "dog-%d-%d.mha", i, j-1); this->writeImage(dogImage[j-1], filename);*/ } #ifdef VERBOSE std::cout << "Done\n"; std::cout.flush(); #endif //char filename[256]; //sprintf(filename, "gauss-%d-%d.mha", i, j); //this->writeImage(gaussianImage_new, filename); gaussianImage_old=gaussianImage_new; //update } //if (j>=0) } //for gaussian // SEARCH MAXIMA & MINIMA EXTREMA IN ADJACENT DOGs for (unsigned int j=1; j < (m_DifferenceOfGaussianImagesNumber - 1); ++j) { // Search the dogImages for local maxima, w.r.t. corresponding point in the scale above and below // Only use the middle dogs (ones with both neighbours above and below) // Iterate over each position in the dog filter typedef itk::ImageRegionIteratorWithIndex< TFixedImageType > ImageIteratorType; IndexType regionStart; // Avoid the edges for (int k=0; k < VDimension; ++k) regionStart[k] = 1; typename TFixedImageType::SizeType regionSize = dogImage[j]->GetLargestPossibleRegion().GetSize(); //HESSIAN OF CURRENT DOG typedef itk::HessianRecursiveGaussianImageFilter< TFixedImageType > myFilterType; typedef typename myFilterType::OutputImageType myHessianImageType; typename myHessianImageType::Pointer HessianImage = myHessianImageType::New(); typename myFilterType::Pointer filter_hess = myFilterType::New(); filter_hess->SetInput( dogImage[j] ); filter_hess->SetSigma( 2.0 ); filter_hess->Update(); HessianImage = filter_hess->GetOutput(); HessianImage->DisconnectPipeline(); filter_hess->ReleaseDataFlagOn(); #ifdef VERBOSE std::cout << "Searching for Extrema in DoG Image " << i << "-" << j; std::cout << " ( "; for (int k=0; k < VDimension; ++k) std::cout << regionSize[k] << " "; std::cout << ") Scale " << currScale << "\n"; std::cout.flush(); #endif // Avoid far edge for (int k=0; k < VDimension; ++k) regionSize[k] -= 2; typename TFixedImageType::RegionType itregion; itregion.SetIndex(regionStart); itregion.SetSize(regionSize); ImageIteratorType pixelIt(dogImage[j],itregion); // this iterates on the pixels of dogImage[j] for ( pixelIt.GoToBegin(); !pixelIt.IsAtEnd(); ++pixelIt) { // Make sure to start sufficiently into the image so that all neighbours are present IndexType pixelIndex = pixelIt.GetIndex(); typename TFixedImageType::PixelType pixelValue = pixelIt.Get(); PointType point; //typename TFixedImageType::SpacingType spacing; //typename TFixedImageType::OriginType origin; PointType vertex; dogImage[j]->TransformIndexToPhysicalPoint (pixelIndex, point); // Compare to the 8 immediate neighbours in the current DOG bool isMax=true; bool isMin=true; this->CheckLocalExtrema(dogImage[j], pixelIndex, pixelValue, isMax, isMin, false); if (!isMax && !isMin) continue; // Compare to scale above if (j < (m_GaussianImagesNumber-1)) { this->CheckLocalExtrema(dogImage[j+1], pixelIndex, pixelValue, isMax, isMin, true); } if (!isMax && !isMin) continue; // Compare to scale below if (j > 0) { this->CheckLocalExtrema(dogImage[j-1], pixelIndex, pixelValue, isMax, isMin, true); } /*if(isMax) std::cout<< "MAX:" < 0.3 || abs(pixelValue) < 0.005) { //std::cout<< "module: "<GetHessian(HessianImage, pixelIndex, isMax, isMin, i, j); if ( Curvature==0){ ++numReject; /*point[0]=-1.0*point[0]; point[1]=-1.0*point[1]; pFileRejectCurvature=fopen(filename_rej_curvature,"a"); if(isMax){ fprintf(pFileRejectCurvature,"M"); } if(isMin){ fprintf(pFileRejectCurvature,"m"); } fprintf(pFileRejectCurvature, "-%d-%d-%d,",numReject,i,j); for(int k=0; kSetPoint( m_PointsCount, point); m_KeypointSet->SetPointData( m_PointsCount, this->GetFeatures( gaussianImage_start, hgradImage[i], point, this->GetGaussianScale(j))); ++m_PointsCount; if (isMax) { // Maxima detected. ++numMax; //std::cout << "max phys coord: "<< point << std::endl; //std::cout << "max image coord: "<< pixelIndex << std::endl; if (filename_phy_max && filename_phy_max[0]) { FILE* pFile; pFile=fopen(filename_phy_max,"a"); //FILE* pFile1; //pFile1=fopen(filename_im_max,"a"); //physical coordinates point[0]=-1.0*point[0]; point[1]=-1.0*point[1]; fprintf(pFile, "M-%d-%d-%d,", numMax,i,j); for(int k=0; kGetOrigin()[k])/fixedImage->GetSpacing()[k]; fprintf(pFile1,"%.3f, ",vertex[k]); } fprintf(pFile1,"\n"); fclose(pFile1);*/ } if (isMin) { // Minima detected. ++numMin; //std::cout << "min phys coord: "<< point << std::endl; //std::cout << "min image coord: "<< pixelIndex << std::endl; if (filename_phy_min && filename_phy_min[0]) { FILE* pFile; pFile=fopen(filename_phy_min,"a"); //pFile1=fopen(filename_im_min,"a"); //physical coordinates point[0]=-1.0*point[0]; point[1]=-1.0*point[1]; fprintf(pFile, "m-%d-%d-%d,", numMin,i,j); for(int k=0; kGetOrigin()[k])/fixedImage->GetSpacing()[k]; fprintf(pFile1,"%.3f, ",vertex[k]); } fprintf(pFile1,"\n"); fclose(pFile1);*/ } //std::cout << "current scale: "<< currScale << std::endl; } #ifdef VERBOSE std::cout << "Acc. Num Max: " << numMax << "\nAcc. Num Min: " << numMin << "\nAcc. Num Reject: " << numReject << std::endl; std::cout.flush(); #endif } currScale *= m_ScalingFactor; } #ifdef VERBOSE std::cout << "Total Num Max: " << numMax << "\nTotal Num Min: " << numMin << "\nTotal Num Reject: " << numReject << std::endl; std::cout.flush(); #endif return m_KeypointSet; } template void ScaleInvariantFeatureImageFilter ::save_pointset (const char* filename) { FILE *fp = fopen (filename, "w"); unsigned long num_points = m_KeypointSet->GetNumberOfPoints(); for (unsigned int i = 0; i < num_points; ++i) { PointType point; point.Fill(0.0); m_KeypointSet->GetPoint(i, &point); fprintf (fp, "p-%03d,%f,%f,%f\n", i, - point[0], - point[1], point[2]); // FeatureType ft2; // m_KeypointSet->GetPointData(i, &ft2); // std::cout << ft2 << "\n"; } fclose (fp); } template void ScaleInvariantFeatureImageFilter ::MatchKeypointsFeatures( PointSetTypePointer keypoints1, PointSetTypePointer keypoints2, const char *filename_phy_match1, const char *filename_phy_match2, float max_feature_distance_ratio) { // Compare Keypoints. Check Coverage and Accuracy // This does the comparison based on position of the keypoints // Find: // # of points that match which will tell us // # of points that did not scale // # of points created by the scale FILE* fp1 = 0; FILE* fp2 = 0; // unsigned int numMatches; unsigned int numMatchesTried; // unsigned int numMatches2; // unsigned int numMatches5; typename PointSetType::PointsContainer::Pointer keyps1, keyps2; /* Open files, we will stream into them */ if (filename_phy_match1 && filename_phy_match1[0]) { fp1 = fopen (filename_phy_match1, "w"); } if (filename_phy_match2 && filename_phy_match2[0]) { fp2 = fopen (filename_phy_match2, "w"); } unsigned long numpoints1, numpoints2; numpoints1 = keypoints1->GetNumberOfPoints(); std::cout << "Keypoints1 Found: " << numpoints1 << std::endl; numpoints2 = keypoints2->GetNumberOfPoints(); std::cout << "Keypoints2 Found: " << numpoints2 << std::endl; std::cout << "***Keypoint Matches***\n"; // numMatches = 0; // numMatches2 = 0; // numMatches5 = 0; numMatchesTried = 0; for (unsigned int i = 0; i < numpoints2; ++i) { PointType pp2; pp2.Fill(0.0); keypoints2->GetPoint(i, &pp2); FeatureType ft2; keypoints2->GetPointData(i, &ft2); FeatureType bestft; float bestdist = -1.0; float nextbestdist = -1.0; unsigned int bestj=0; for (unsigned int j = 0; j < numpoints1; ++j) { PointType pp; keypoints1->GetPoint(j, &pp); FeatureType ft; keypoints1->GetPointData(j, &ft); /* Compute feature distance */ float dist = 0.0; for (unsigned int k = 0; k < ft.Size(); ++k) { dist += (ft[k] - ft2[k])*(ft[k] - ft2[k]); } //std::cout<<"dist: "< m_MaxFeatureDistanceRatio) if ((bestdist / nextbestdist) > max_feature_distance_ratio) { //std::cout << "MATCH REJECTED 1:" << std::endl; //PointType pp; //keypoints1->GetPoint(bestj, &pp); //std::cout << pp << std::endl; //matches rejected on Image1: /*FILE* pFileMatch1_rej; FILE* pFileMatch2_rej; pFileMatch1_rej=fopen("point_match1_rej.fcsv","a"); pp[0]=-1.0*pp[0]; pp[1]=-1.0*pp[1]; fprintf(pFileMatch1_rej, "p1-%d,",bestj); for(int k=0; k " << pp2 << std::endl; continue; } /* NEW IDEA: Bi-directional mapping -- look to make sure it is a reciprocal best match */ /* Take the best feature found, see if pp2 makes the cut */ bestdist = -1.0; nextbestdist = -1.0; FeatureType bestft2; // unsigned int bestj2 = -1; for (unsigned int j = 0; j < numpoints2; ++j) { PointType pp; keypoints2->GetPoint(j, &pp); FeatureType ft; keypoints2->GetPointData(j, &ft); float dist = 0.0; for (unsigned int k = 0; k < ft.Size(); ++k) dist += (ft[k] - bestft[k])*(ft[k] - bestft[k]); if (nextbestdist < 0.0 || dist < bestdist) { nextbestdist = bestdist; bestdist=dist; bestft2 = ft; // bestj2 = j; } } /* Reject if not reciprocal best hit or "too close" matches */ // if ( bestft2 != ft2 || ((bestdist / nextbestdist) > m_MaxFeatureDistanceRatio)) if (bestft2 != ft2 || (bestdist / nextbestdist) > max_feature_distance_ratio) { continue; } /* END NEW IDEA */ ++numMatchesTried; // Check goodness of best feature PointType tmpp, pp; tmpp.Fill (0.0); pp.Fill (0.0); keypoints1->GetPoint(bestj, &tmpp); // Print the match std::cout << tmpp << " => " << pp2 << std::endl; if (fp1) { fprintf (fp1, "p1-%d,%.3f,%.3f,%.3f\n", bestj, - tmpp[0], - tmpp[1], tmpp[2]); } if (fp2) { fprintf (fp2, "p1-%d,%.3f,%.3f,%.3f\n", bestj, - pp2[0], - pp2[1], pp2[2]); } } std::cout << "\n***Features Matches: " << numMatchesTried << std::endl; if (fp1) { fclose (fp1); } if (fp2) { fclose (fp2); } } } // end namespace itk #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/nkidecompress/000077500000000000000000000000001321604176500253165ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/nkidecompress/CMakeLists.txt000066400000000000000000000002241321604176500300540ustar00rootroot00000000000000project (nkidecompress) set (NKIDECOMPRESS_SRC nkidecompress.cxx ) plm_add_static_library (nkidecompress "${NKIDECOMPRESS_SRC}" "" "" "") plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/nkidecompress/license.txt000066400000000000000000000010141321604176500274750ustar00rootroot00000000000000From the project web page (2012-12-21) http://ingenium.home.xs4all.nl/dicom.html Within the EC Conquest project, a full featured DICOM server has been developed based on and heavily extending the public domain UCDMC DICOM code developed by Mark Oskin when he was at the Medical Center of the University of California at Davis. The Conquest DICOM software was written by Marcel van Herk and Lambert Zijp at the Netherlands Cancer Institute. We have decided to provide our extended DICOM software also to the public domain. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/nkidecompress/nkidecompress.cxx000066400000000000000000000355071321604176500307220ustar00rootroot00000000000000#include "nkidecompress.h" /* Copied from nkiqrsop.cpp */ static const unsigned int CRC32_table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; typedef struct { unsigned int iOrgSize; /* NOTE: this is the number of short pixels !!!! */ unsigned int iMode; unsigned int iCompressedSize; /* in bytes, not pixels */ unsigned int iOrgCRC; unsigned int iCompressedCRC; /* Excluding this header */ } NKI_MODE2; int nki_private_decompress(short int *dest, signed char *src, int size) { int npixels, retvalue, mode, iMode, val, j; NKI_MODE2* pHeader = (NKI_MODE2*)src; unsigned int iCRC=0, iCRC2=0; signed char *save, *end; //NKIPrivateDecompress++; retvalue = npixels = pHeader->iOrgSize; iMode = pHeader->iMode; // safety: this value is checked in case statement if (npixels<1) return 0; // safety: check for invalid npixels value /* Up till now only Mode=1, 2, 3, and 4 are supported */ switch (iMode) { case 1: src += 8; // mode 1 only has 8 bytes header: iOrgSize and iMode end = src + size - 3; // for overflow check if we are close to end of input buffer *dest = *(short int *)src; src += 2; npixels--; do { if (src > end) // check whether the last few messages fit in input buffer { if (src= -64 && val <= 63) mode = 1; // 7 bit difference else if (val==0x7f) mode = 3; // 16 bit value else if ((val&0xff)==0x80) mode = 2; // run length encoding else mode = 2; if (src+mode > end+3) return 0; // safety: overflow input data } val = *src; if (val >= -64 && val <= 63) // 7 bit difference { dest[1] = dest[0] + val; dest++; src++; } else if (val==0x7f) // 16 bit value { dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2]; dest++; src+=3; } else if ((val&0xff)==0x80) // run length encoding { mode = ((unsigned char *)src)[1]; npixels -= mode-1; if (npixels<=0) return 0; // safety: overflow output data do { dest[1] = dest[0]; dest++; } while (--mode); src+=2; } else { signed short diff = ((val^0x40)<<8) + (unsigned char)(src[1]); dest[1] = dest[0] + diff; // 15 bit difference dest++; src+=2; } } while (--npixels); break; case 2: src += sizeof(NKI_MODE2); save = src; end = src + pHeader->iCompressedSize - 3; if (end > src + size - 3) end = src + size - 3; // may occur if pHeader is corrupted *dest = val = *(short int *)src; iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); src+=2; npixels--; do { if (src > end) // check whether the last few messages fit in input buffer { if (src= -64 && val <= 63) mode = 1; // 7 bit difference else if (val==0x7f) mode = 3; // 16 bit value else if ((val&0xff)==0x80) mode = 2; // run length encoding else mode = 2; if (src+mode > end+3) break; // safety: overflow input data } val = *src; if (val >= -64 && val <= 63) // 7 bits difference { dest[1] = val = dest[0] + val; iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); dest++; src++; } else if (val==0x7f) // 16 bit value { dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2]; iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); dest++; src+=3; } else if ((val&0xff)==0x80) // run length encoding { mode = ((unsigned char *)src)[1]; npixels -= mode-1; if (npixels<=0) break; // safety: overflow output data do { dest[1] = val = dest[0]; iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); dest++; } while (--mode); src+=2; } else { signed short diff = ((val^0x40)<<8) + ((unsigned char *)src)[1]; dest[1] = val = dest[0] + diff; // 15 bit difference iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); dest++; src+=2; } } while (--npixels); if (iCRC2 != pHeader->iOrgCRC) // if error in output CRC: { src = save; // check input CRC while (src < end) { iCRC = CRC32_table[(unsigned char)iCRC ^ (unsigned char)src[0]] ^ ((iCRC >> 8)); src++; } if (iCRC != pHeader->iCompressedCRC) { //OperatorConsole.printf("NKI decompression: the file is corrupted\n"); retvalue=0; } else { //OperatorConsole.printf("NKI private decompression: internal error\n"); retvalue=0; } } break; case 3: src += 8; // mode 3 only has 8 bytes header: iOrgSize and iMode end = src + size - 3; // for overflow check if we are close to end of input buffer *dest = *(short int *)src; src += 2; npixels--; do { if (src > end) // check whether the last few messages fit in input buffer { if (src= -63 && val <= 63) mode = 1; // 7 bit difference else if (val==0x7f) mode = 3; // 16 bit value else if ((val&0xff)==0x80) mode = 2; // run length encoding else if ((val&0xff)==0xC0) mode = 2; // 4 bit encoding else mode = 2; if (src+mode > end+3) return 0; // safety: overflow input data } val = *src; if (val >= -63 && val <= 63) // 7 bit difference { dest[1] = dest[0] + val; dest++; src++; } else if (val==0x7f) // 16 bit value { dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2]; dest++; src+=3; } else if ((val&0xff)==0x80) // run length encoding { mode = ((unsigned char *)src)[1]; npixels -= mode-1; if (npixels<=0) return 0; // safety: overflow output data do { dest[1] = dest[0]; dest++; } while (--mode); src+=2; } else if ((val&0xff)==0xC0) // 4 bit run { mode = ((unsigned char *)src)[1]; npixels -= mode-1; mode/=2; src+=2; if (npixels<=0) return 0; // safety: overflow output data do { val = *src++; dest[1] = dest[0] + (val>>4); dest++; if (val&8) val |= 0xfffffff0; else val &= 0x0f; dest[1] = dest[0] + val; dest++; } while (--mode); } else { signed short diff = ((val^0x40)<<8) + (unsigned char)(src[1]); dest[1] = dest[0] + diff; // 15 bit difference dest++; src+=2; } } while (--npixels); break; case 4: src += sizeof(NKI_MODE2); save = src; end = src + pHeader->iCompressedSize - 3; if (end > src + size - 3) end = src + size - 3; // may occur if pHeader is corrupted *dest = val = *(short int *)src; iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); src += 2; npixels--; do { if (src > end) // check whether the last few messages fit in input buffer { if (src= -63 && val <= 63) mode = 1; // 7 bit difference else if (val==0x7f) mode = 3; // 16 bit value else if ((val&0xff)==0x80) mode = 2; // run length encoding else if ((val&0xff)==0xC0) mode = 2; // 4 bit encoding else mode = 2; if (src+mode > end+3) return 0; // safety: overflow input data } val = *src; if (val >= -63 && val <= 63) // 7 bit difference { dest[1] = val = dest[0] + val; iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); dest++; src++; } else if (val==0x7f) // 16 bit value { dest[1] = val = ((int)(((unsigned char *)src)[1])<<8) + ((unsigned char*)src)[2]; iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); dest++; src+=3; } else if ((val&0xff)==0x80) // run length encoding { mode = ((unsigned char *)src)[1]; npixels -= mode-1; if (npixels<=0) return 0; // safety: overflow output data do { dest[1] = val = dest[0]; iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); dest++; } while (--mode); src+=2; } else if ((val&0xff)==0xC0) // 4 bit run { mode = ((unsigned char *)src)[1]; npixels -= mode-1; mode/=2; src+=2; if (npixels<=0) return 0; // safety: overflow output data do { val = *src++; dest[1] = j = dest[0] + (val>>4); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)j] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(j>>8)] ^ ((iCRC2 >> 8)); dest++; if (val&8) val |= 0xfffffff0; else val &= 0x0f; dest[1] = j = dest[0] + val; iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)j] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(j>>8)] ^ ((iCRC2 >> 8)); dest++; } while (--mode); } else { signed short diff = ((val^0x40)<<8) + (unsigned char)(src[1]); dest[1] = val = dest[0] + diff; // 15 bit difference iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val] ^ ((iCRC2 >> 8)); iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8)); dest++; src+=2; } } while (--npixels); if (iCRC2 != pHeader->iOrgCRC) // if error in output CRC: retvalue=0; break; default: //OperatorConsole.printf("NKI private decompression: unsupported mode\n"); return 0; } return retvalue; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/nkidecompress/nkidecompress.h000066400000000000000000000002041321604176500303310ustar00rootroot00000000000000#ifndef _nkidecompress_h_ #define _nkidecompress_h_ int nki_private_decompress(short int *dest, signed char *src, int size); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/000077500000000000000000000000001321604176500237175ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/CMakeLists.txt000066400000000000000000000032061321604176500264600ustar00rootroot00000000000000# GCS: Why? #cmake_minimum_required(VERSION 2.8) PROJECT( RANSAC ) # # Find ITK # FIND_PACKAGE(ITK) IF(ITK_FOUND) INCLUDE(${ITK_USE_FILE}) ELSE(ITK_FOUND) MESSAGE(FATAL_ERROR "Cannot find ITK. Please set ITK_DIR.") ENDIF(ITK_FOUND) INCLUDE_DIRECTORIES ( ${RANSAC_SOURCE_DIR} ${RANSAC_SOURCE_DIR}/Common ) SET(RANSAC_HDRS RANSAC.h RANSAC.txx ParametersEstimator.h ParametersEstimator.txx ) SET(EXAMPLES_DIRECTORY ${RANSAC_SOURCE_DIR}/Examples ) LINK_LIBRARIES ( ITKCommon itkvnl itkvnl_algo ) # # First example program showing the use of RANSAC for plane fitting # SET(PLANE_ESTIMATION_HDRS ${RANSAC_HDRS} PlaneParametersEstimator.h PlaneParametersEstimator.txx ) SET(PLANE_ESTIMATION_SRCS ${EXAMPLES_DIRECTORY}/planeEstimation.cxx ) ## ADD_EXECUTABLE(planeEstimation ${PLANE_ESTIMATION_HDRS} ${PLANE_ESTIMATION_SRCS}) ## TARGET_LINK_LIBRARIES(planeEstimation ${LINK_LIBRARIES}) # # Second example program showing the use of RANSAC for sphere fitting # SET(SPHERE_ESTIMATION_HDRS ${RANSAC_HDRS} SphereParametersEstimator.h SphereParametersEstimator.txx ) SET(SPHERE_ESTIMATION_SRCS ${EXAMPLES_DIRECTORY}/sphereEstimation.cxx ) ## ADD_EXECUTABLE(sphereEstimation ${SPHERE_ESTIMATION_HDRS} ${SPHERE_ESTIMATION_SRCS}) ## TARGET_LINK_LIBRARIES(sphereEstimation ${LINK_LIBRARIES}) # # Optional testing of the plane and sphere estimation code # #OPTION(BUILD_TESTING "Build the Testing directory." ON) #IF (BUILD_TESTING) # ENABLE_TESTING() # ADD_SUBDIRECTORY(Testing) #ENDIF (BUILD_TESTING) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/CMakeLists.txt.ori000066400000000000000000000031471321604176500272540ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) PROJECT( RANSAC ) # # Find ITK # FIND_PACKAGE(ITK) IF(ITK_FOUND) INCLUDE(${ITK_USE_FILE}) ELSE(ITK_FOUND) MESSAGE(FATAL_ERROR "Cannot find ITK. Please set ITK_DIR.") ENDIF(ITK_FOUND) INCLUDE_DIRECTORIES ( ${RANSAC_SOURCE_DIR} ${RANSAC_SOURCE_DIR}/Common ) SET(RANSAC_HDRS RANSAC.h RANSAC.txx ParametersEstimator.h ParametersEstimator.txx ) SET(EXAMPLES_DIRECTORY ${RANSAC_SOURCE_DIR}/Examples ) LINK_LIBRARIES ( ITKCommon itkvnl itkvnl_algo ) # # First example program showing the use of RANSAC for plane fitting # SET(PLANE_ESTIMATION_HDRS ${RANSAC_HDRS} PlaneParametersEstimator.h PlaneParametersEstimator.txx ) SET(PLANE_ESTIMATION_SRCS ${EXAMPLES_DIRECTORY}/planeEstimation.cxx ) ADD_EXECUTABLE(planeEstimation ${PLANE_ESTIMATION_HDRS} ${PLANE_ESTIMATION_SRCS}) TARGET_LINK_LIBRARIES(planeEstimation ${LINK_LIBRARIES}) # # Second example program showing the use of RANSAC for sphere fitting # SET(SPHERE_ESTIMATION_HDRS ${RANSAC_HDRS} SphereParametersEstimator.h SphereParametersEstimator.txx ) SET(SPHERE_ESTIMATION_SRCS ${EXAMPLES_DIRECTORY}/sphereEstimation.cxx ) ADD_EXECUTABLE(sphereEstimation ${SPHERE_ESTIMATION_HDRS} ${SPHERE_ESTIMATION_SRCS}) TARGET_LINK_LIBRARIES(sphereEstimation ${LINK_LIBRARIES}) # # Optional testing of the plane and sphere estimation code # OPTION(BUILD_TESTING "Build the Testing directory." ON) IF (BUILD_TESTING) ENABLE_TESTING() ADD_SUBDIRECTORY(Testing) ENDIF (BUILD_TESTING) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/Common/000077500000000000000000000000001321604176500251475ustar00rootroot00000000000000RandomNumberGenerator.h000066400000000000000000000025671321604176500315130ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/Common#ifndef _RANDOM_NUMBER_GENERATOR_H_ #define _RANDOM_NUMBER_GENERATOR_H_ #include /** * Random number generator, uniform and normal distributions. * This implementation wraps the vnl_random object and uses "nicer" * naming conventions, i.e. uniform instead of drand64. * * @author: Ziv Yaniv (zivy@isis.georgetown.edu) * */ class RandomNumberGenerator { public: RandomNumberGenerator() { generator = new vnl_random(); } RandomNumberGenerator( unsigned long seed ) { generator = new vnl_random(seed); } ~RandomNumberGenerator() { delete generator; } /** * Get a random number uniformly distributed in (a,b). * @param a Lower bound for random numbers, default is 0.0. * @param b Upper bound for random numbers, default is 1.0. */ virtual double uniform(double a=0.0, double b=1.0) { return generator->drand64(a,b); } /** * Get a random number normally distributed with given mean and standard deviation. * @param sigma Normal distributions standard deviation, default is one. * @param mu Normal distribution's mean, default is zero. */ virtual double normal(double sigma=1.0, double mu=0.0) { return sigma*generator->normal64() + mu; } private: vnl_random *generator; }; #endif //_RANDOM_NUMBER_GENERATOR_H_ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/Examples/000077500000000000000000000000001321604176500254755ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/Examples/planeEstimation.cxx000066400000000000000000000310351321604176500313570ustar00rootroot00000000000000#include #include "RANSAC.h" #include "PlaneParametersEstimator.h" #include "RandomNumberGenerator.h" /** * Generate points on a (hyper)plane with additive zero mean Gaussian noise and * outliers. * @param numInliers How many points are inliers. * @param numOutliers How many points are outliers. * @param outlierDistance Threshold defining outliers, points that are further * than this distance from the plane. * @param data The points are added to the end of this vector. * @param planeParameters [n,a], plane normal and point on plane. Plane is * defined as the set of points p such that n^T(p-a)=0. */ template void GenerateData( unsigned int numInliers, unsigned int numOutliers, double outlierDistance, std::vector< itk::Point > &data, std::vector &planeParameters ); /** * This function only works in 3D. * * Save an open inventor ASCII scene file showing the points identified as * inliers/outliers and the estimated plane. The output file is * "planeEstimation.iv". The format is compatible with the viewers available in * the open source coin3D toolkit (www.coin3d.org). * * @param outputFileName Write the scene to this file. * @param data The 3D points. * @param estimatedPlaneParameters [n,a], plane normal and point on plane. Plane * is the set of points p such that n^T(p-a)=0. * @param parameterEstimator The plane parameter estimator whoes Agree() method * is used to identify inliers. */ template void SaveOIVFile( std::string &outputFileName, std::vector< itk::Point > &data, std::vector &estimatedPlaneParameters, typename itk::PlaneParametersEstimator::Pointer parameterEstimator ); /** * Given the hard coded dimension, and number of outliers and inliers generate * a random dataset accordingly. Then estimate the (hyper)plane parameter values * using a least squares estimate and the RANSAC algorithm. Compare the results * to the known (hyper)plane. Code is written for nD data except the * visualization which is limited to 3D. If DIMENSION is set to three, two * open inventor scene files are written, showing the least squares and RANSAC * estimates. Data points are colored spheres, those that agree with the * estimated model are green, otherwise they are red. * * @author Ziv Yaniv (zivy@isis.georgetown.edu) */ int main(int argc, char *argv[]) { const unsigned int DIMENSION = 3; const unsigned int INLIERS = 90; const unsigned int OUTLIERS = 10; std::string leastSquaresOutputFileName = "leastSquaresPlaneEstimation.iv"; std::string ransacOutputFileName = "RANSACPlaneEstimation.iv"; typedef itk::PlaneParametersEstimator PlaneEstimatorType; typedef itk::RANSAC, double> RANSACType; std::vector< itk::Point > data; std::vector truePlaneParameters, planeParameters; double outlierDistance = 20.0; unsigned int i; double dotProduct; GenerateData( INLIERS, OUTLIERS, outlierDistance, data, truePlaneParameters ); std::cout<<"Known (hyper)plane parameters [n,a]\n\t [ "; for( i=0; i<(2*DIMENSION-1); i++ ) std::cout<SetDelta( maximalDistanceFromPlane ); planeEstimator->LeastSquaresEstimate( data, planeParameters ); if( planeParameters.empty() ) std::cout<<"Least squares estimate failed, degenerate configuration?\n"; else { std::cout<<"Least squares hyper(plane) parameters: [n,a]\n\t [ "; for( i=0; i<(2*DIMENSION-1); i++ ) std::cout<SetData( data ); ransacEstimator->SetParametersEstimator( planeEstimator.GetPointer() ); percentageOfDataUsed = ransacEstimator->Compute( planeParameters, desiredProbabilityForNoOutliers ); if( planeParameters.empty() ) std::cout<<"RANSAC estimate failed, degenerate configuration?\n"; else { std::cout<<"RANSAC hyper(plane) parameters: [n,a]\n\t [ "; for( i=0; i<(2*DIMENSION-1); i++ ) std::cout< void GenerateData( unsigned int numInliers, unsigned int numOutliers, double outlierDistance, std::vector< itk::Point > &data, std::vector &planeParameters ) { itk::Vector normal, noise, tmp; itk::Point pointOnPlane, randomPoint; double noiseStandardDeviation = 0.4; //noise standard deviation double coordinateMax = 1000.0; unsigned int i, j; RandomNumberGenerator random; planeParameters.clear(); //generate points on random (hyper) plane for( i=0; i= outlierDistance ) data.push_back( randomPoint ); else i--; } } template void SaveOIVFile( std::string &outputFileName, std::vector< itk::Point > &data, std::vector &estimatedPlaneParameters, typename itk::PlaneParametersEstimator::Pointer parameterEstimator ) { if( dimension != 3 ) return; double sphereRadius = 50.0; //outliers are metalic red std::string outlierMaterial = "Material {\n"; outlierMaterial+="\tambientColor 1.0 0.0 0.0\n"; outlierMaterial+="\tdiffuseColor 0.27 0.15 0.0\n"; outlierMaterial+="\tspecularColor 1.0 0.0 0.0\n"; outlierMaterial+="}\n"; //inliers are metalic green std::string inlierMaterial = "\tMaterial {\n"; inlierMaterial+="\t\tambientColor 0.0 1.0 0.0\n"; inlierMaterial+="\t\tdiffuseColor 0.0 0.27 0.15\n"; inlierMaterial+="\t\tspecularColor 0.0 1.0 0.0\n"; inlierMaterial+="\t}\n"; //plane is gray std::string planeMaterial = "\tMaterial {\n"; planeMaterial+="\t\tambientColor 0.5 0.5 0.5\n"; planeMaterial+="\t\tdiffuseColor 0.2 0.2 0.2\n"; planeMaterial+="\t\tspecularColor 0.8 0.8 0.8\n"; planeMaterial+="\t\ttransparency 0.4\n"; planeMaterial+="\t}\n"; std::ofstream out( outputFileName.c_str() ); out<<"#Inventor V2.1 ascii\n\n"; //go over all the points, find the coordinate ranges and write //the outliers and inliers to the scene graph double minX, maxX, minY, maxY, minZ, maxZ; minX = maxX = data[0][0]; minY = maxY = data[0][1]; minZ = maxZ = data[0][2]; unsigned int inlierIndex = 0; for( unsigned int i=0; iAgree( estimatedPlaneParameters, data[i] ) ) { out<maxX ) maxX = data[i][0]; if( data[i][1]maxY ) maxY = data[i][1]; if( data[i][2]maxZ ) maxZ = data[i][2]; } //create polygon representing estimated plane and write to file double rangeX = maxX - minX; double rangeY = maxY - minY; double rangeZ = maxZ - minZ; double maxRange = rangeX; if( rangeY>maxRange ) maxRange = rangeY; if( rangeZ>maxRange ) maxRange = rangeZ; double halfRange = sqrt(3.0)*maxRange/2.0; itk::Vector tmp, e1, e2, normal; normal[0] = estimatedPlaneParameters[0]; normal[1] = estimatedPlaneParameters[1]; normal[2] = estimatedPlaneParameters[2]; tmp[0] = data[inlierIndex][0] - estimatedPlaneParameters[3]; tmp[1] = data[inlierIndex][1] - estimatedPlaneParameters[4]; tmp[2] = data[inlierIndex][2] - estimatedPlaneParameters[5]; e1 = tmp - tmp*normal; e1.Normalize(); e2 = CrossProduct( normal, e1 ); itk::Point p1, p2, p3, p4; p1[0] = p2[0] = p3[0] = p4[0] = estimatedPlaneParameters[3]; p1[1] = p2[1] = p3[1] = p4[1] = estimatedPlaneParameters[4]; p1[2] = p2[2] = p3[2] = p4[2] = estimatedPlaneParameters[5]; p1 = p1 + halfRange*e1; p2 = p2 + halfRange*e2; p3 = p3 - halfRange*e1; p4 = p4 - halfRange*e2; out<<"Separator {\n"; out< #include "RANSAC.h" #include "RandomNumberGenerator.h" #include "SphereParametersEstimator.h" /** * Generate points on a (hyper)sphere with additive zero mean Gaussian noise and * outliers. * @param numInliers How many points are inliers. * @param numOutliers How many points are outliers. * @param outlierDistance Threshold defining outliers, points that are further * than this distance from the sphere. * @param data The points are added to the end of this vector. * @param sphereParameters [c,r], sphere center and radius. Sphere is * defined as the set of points p such that * (p-c)^T(p-c)=r^2. */ template void GenerateData( unsigned int numInliers, unsigned int numOutliers, double outlierDistance, std::vector< itk::Point > &data, std::vector &sphereParameters ); /** * This function only works in 3D. * * Save an open inventor ASCII scene file showing the points identified as * inliers/outliers and the estimated sphere. The output file is * "sphereEstimation.iv". The format is compatible with the viewers available in * the open source coin3D toolkit (www.coin3d.org). * * @param outputFileName Write the scene to this file. * @param data The 3D points. * @param estimatedSphereParameters [c,r], sphere center and radius. Sphere is * defined as the set of points p such that * (p-c)^T(p-c)=r^2. * @param parameterEstimator The sphere parameter estimator whoes Agree() method * is used to identify inliers. */ template void SaveOIVFile( std::string &outputFileName, std::vector< itk::Point > &data, std::vector &estimatedSphereParameters, typename itk::SphereParametersEstimator::Pointer parameterEstimator ); /** * Given the hard coded dimension, and number of outliers and inliers generate * a random dataset accordingly. Then estimate the (hyper)sphere parameter values * using a least squares estimate and the RANSAC algorithm. Compare the results * to the known (hyper)sphere. Code is written for nD data except the * visualization which is limited to 3D. If DIMENSION is set to three, then two * open inventor scene files are written, showing the least squares and RANSAC * estimates. Data points are colored spheres, those that agree with the * estimated model are green, otherwise they are red. * * @author Ziv Yaniv (zivy@isis.georgetown.edu) */ int main(int argc, char *argv[]) { const unsigned int DIMENSION = 3; const unsigned int INLIERS = 90; const unsigned int OUTLIERS = 10; std::string leastSquaresOutputFileName = "leastSquaresSphereEstimation.iv"; std::string ransacOutputFileName = "RANSACSphereEstimation.iv"; typedef itk::SphereParametersEstimator SphereEstimatorType; typedef itk::RANSAC, double> RANSACType; std::vector< itk::Point > data; std::vector trueSphereParameters, sphereParameters; double outlierDistance = 20.0; unsigned int i; itk::Vector tmp; GenerateData( INLIERS, OUTLIERS, outlierDistance, data, trueSphereParameters ); std::cout<<"Known hyper(sphere) parameters [c,r]\n\t [ "; for( i=0; iSetDelta( maximalDistanceFromSphere ); sphereEstimator->SetLeastSquaresType( itk::SphereParametersEstimator::GEOMETRIC ); sphereEstimator->LeastSquaresEstimate( data, sphereParameters ); if( sphereParameters.empty() ) std::cout<<"Least squares estimate failed, degenerate configuration?\n"; else { std::cout<<"Least squares hyper(sphere) parameters: [c,r]\n\t [ "; for( i=0; iSetData( data ); ransacEstimator->SetParametersEstimator( sphereEstimator.GetPointer() ); percentageOfDataUsed = ransacEstimator->Compute( sphereParameters, desiredProbabilityForNoOutliers ); if( sphereParameters.empty() ) std::cout<<"RANSAC estimate failed, degenerate configuration?\n"; else { std::cout<<"RANSAC hyper(sphere) parameters: [c,r]\n\t [ "; for( i=0; i void GenerateData( unsigned int numInliers, unsigned int numOutliers, double outlierDistance, std::vector< itk::Point > &data, std::vector &sphereParameters ) { itk::Vector tmp, noise; itk::Point sphereCenter, randomPoint; double sphereRadius; double noiseStandardDeviation = 0.4; //noise standard deviation double coordinateMax = 1000.0; unsigned int i, j; RandomNumberGenerator random; sphereParameters.clear(); //generate points on random (hyper) sphere for( i=0; i= outlierDistance ) data.push_back( randomPoint ); else i--; } } template void SaveOIVFile( std::string &outputFileName, std::vector< itk::Point > &data, std::vector &estimatedSphereParameters, typename itk::SphereParametersEstimator::Pointer parameterEstimator ) { if( dimension != 3 ) return; double dataSphereRadius = 50.0; //outliers are metalic red std::string outlierMaterial = "Material {\n"; outlierMaterial+="\tambientColor 1.0 0.0 0.0\n"; outlierMaterial+="\tdiffuseColor 0.27 0.15 0.0\n"; outlierMaterial+="\tspecularColor 1.0 0.0 0.0\n"; outlierMaterial+="}\n"; //inliers are metalic green std::string inlierMaterial = "\tMaterial {\n"; inlierMaterial+="\t\tambientColor 0.0 1.0 0.0\n"; inlierMaterial+="\t\tdiffuseColor 0.0 0.27 0.15\n"; inlierMaterial+="\t\tspecularColor 0.0 1.0 0.0\n"; inlierMaterial+="\t}\n"; //estimated sphere is gray std::string sphereMaterial = "\tMaterial {\n"; sphereMaterial+="\t\tambientColor 0.5 0.5 0.5\n"; sphereMaterial+="\t\tdiffuseColor 0.2 0.2 0.2\n"; sphereMaterial+="\t\tspecularColor 0.8 0.8 0.8\n"; sphereMaterial+="\ttransparency 0.4\n"; sphereMaterial+="\t}\n"; std::ofstream out( outputFileName.c_str() ); out<<"#Inventor V2.1 ascii\n\n"; //go over all the points and write //the outliers and inliers to the scene graph for( unsigned int i=0; iAgree( estimatedSphereParameters, data[i] ) ) { out< #include namespace itk { /** * This class defines the interface for parameter estimators. * Classes which inherit from it can be used by the RANSAC class to perform * robust parameter estimation. * The interface includes three methods: * 1.Estimate() - Estimation of the parameters using the minimal amount of * data (exact estimate). * 2.LeastSquaresEstimate() - Estimation of the parameters using * overdetermined data, so that the estimate * minimizes a least squres error criteria. * 3.Agree() - Does the given data agree with the model parameters. * * Template parameters: * T - data type (e.g. itk::Point). * S - parameter's type (e.g. double). * * @author: Ziv Yaniv zivy@isis.georgetown.edu */ template class ParametersEstimator : public Object { public: typedef ParametersEstimator Self; typedef Object Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkTypeMacro( ParametersEstimator, Object ); /** * Exact estimation of parameters. * @param data The data used for the estimate. * @param parameters This vector is cleared and then filled with the estimated * parameter values. */ virtual void Estimate( std::vector &data, std::vector ¶meters ) = 0; virtual void Estimate( std::vector &data, std::vector ¶meters ) = 0; /** * Least squares estimation of parameters. * @param data The data used for the estimate. * @param parameters This vector is cleared and then filled with the computed * parameters. */ virtual void LeastSquaresEstimate( std::vector &data, std::vector ¶meters ) = 0; virtual void LeastSquaresEstimate( std::vector &data, std::vector ¶meters ) = 0; /** * This method tests if the given data agrees with the model defined by the * parameters. */ virtual bool Agree( std::vector ¶meters, T &data ) = 0; /** * Set the minimal number of data objects required for computation of an exact * estimate. * @param minForEstimate Minimal number of data objects required for * computation of an exact estimate. */ void SetMinimalForEstimate( unsigned int minForEstimate ); unsigned int GetMinimalForEstimate(); protected: ParametersEstimator(){ this->minForEstimate=0; } ~ParametersEstimator(){} //minimal number of data objects required for an exact estimate unsigned int minForEstimate; private: ParametersEstimator( const Self& ); //purposely not implemented void operator=( const Self& ); //purposely not implemented }; } // end namespace itk #include "ParametersEstimator.txx" #endif //_PARAMETERS_ESTIMATOR_H_ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/ParametersEstimator.txx000066400000000000000000000011511321604176500304550ustar00rootroot00000000000000#ifndef _PARAMETERS_ESTIMATOR_TXX_ #define _PARAMETERS_ESTIMATOR_TXX_ namespace itk { template void ParametersEstimator::SetMinimalForEstimate( unsigned int minForEstimate ) { if( minForEstimate == 0 ) throw ExceptionObject(__FILE__,__LINE__, "Invalid minimal number of objects for exact estimate."); this->minForEstimate = minForEstimate; } template unsigned int ParametersEstimator::GetMinimalForEstimate() { return this->minForEstimate; } } // end namespace itk #endif //_PARAMETERS_ESTIMATOR_TXX_ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/PlaneParametersEstimator.h000066400000000000000000000106621321604176500310500ustar00rootroot00000000000000#ifndef _PLANE_PARAM_ESTIMATOR_H_ #define _PLANE_PARAM_ESTIMATOR_H_ #include "ParametersEstimator.h" #include #include namespace itk { /** * This class estimates the parameters of a (hyper)plane (2D line, 3D plane...). * * A (hyper)plane is represented as: (*) dot(n,p-a)=0 * where n is the (hyper)plane normal * (|n| = 1) and 'a' is a point on the * (hyper)plane. * All points 'p' which satisfy equation (*) are on the (hyper)plane. * * @author: Ziv Yaniv (zivy@isis.georgetown.edu) * */ template< unsigned int dimension > class PlaneParametersEstimator : public ParametersEstimator< Point, double > { public: typedef PlaneParametersEstimator Self; typedef ParametersEstimator< Point, double > Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkTypeMacro( PlaneParametersEstimator, ParametersEstimator ); /** New method for creating an object using a factory. */ itkNewMacro( Self ) /** * Compute the (hyper)plane defined by the given data points. * @param data A vector containing k kD points. * @param parameters This vector is cleared and then filled with the computed * parameters. The parameters of the plane passing through * these points [n_0,...,n_k,a_0,...,a_k] where * ||(n_0,...,nk)|| = 1. * If the vector contains less than k points or the first k * points are linearly dependent then the resulting * parameters vector is empty (size = 0). */ virtual void Estimate( std::vector< Point *> &data, std::vector ¶meters ); virtual void Estimate( std::vector< Point > &data, std::vector ¶meters ); /** * Compute a least squares estimate of the (hyper)plane defined by the given * points. This implementation is of an orthogonal least squares error. * * @param data The (hyper)plane should minimize the least squares error to * these points. * @param parameters This vector is cleared and then filled with the computed * parameters. The parameters of the plane passing through * these points [n_0,...,n_k,a_0,...,a_k] where * ||(n_0,...,nk)|| = 1. * If the vector contains less than k, kD, linearly * independent points then the resulting parameters vector * is empty (size = 0). */ virtual void LeastSquaresEstimate( std::vector< Point *> &data, std::vector ¶meters ); virtual void LeastSquaresEstimate( std::vector< Point > &data, std::vector ¶meters ); /** * Return true if the distance between the line defined by the parameters and * the * given point is smaller than 'delta' (see constructor). * @param parameters The line parameters [n_x,n_y,a_x,a_y]. * @param data Check that the distance between this point and the line is * less than 'delta'. */ virtual bool Agree( std::vector ¶meters, Point &data ); /** * Set parameter which defines a threshold for a point to be considered on the * plane. * @param delta A point is on the (hyper)plane if its distance from the * (hyper)plane is less than 'delta'. */ void SetDelta( double delta ); double GetDelta(); protected: PlaneParametersEstimator(); ~PlaneParametersEstimator(); private: PlaneParametersEstimator(const Self& ); //purposely not implemented void operator=(const Self& ); //purposely not implemented //given line L and point P, if dist(L,P)^2 < delta^2 then the //point is on the line double deltaSquared; }; } // end namespace itk //the implementation is in this file #include "PlaneParametersEstimator.txx" #endif //_PLANE_PARAM_ESTIMATOR_H_ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/PlaneParametersEstimator.txx000066400000000000000000000160341321604176500314430ustar00rootroot00000000000000#ifndef _PLANE_PARAM_ESTIMATOR_TXX_ #define _PLANE_PARAM_ESTIMATOR_TXX_ #include #include namespace itk { template< unsigned int dimension > PlaneParametersEstimator::PlaneParametersEstimator() { this->deltaSquared = NumericTraits::min(); this->minForEstimate = dimension; } template< unsigned int dimension > PlaneParametersEstimator::~PlaneParametersEstimator() { } template< unsigned int dimension > void PlaneParametersEstimator::SetDelta( double delta ) { this->deltaSquared = delta*delta; } template< unsigned int dimension > double PlaneParametersEstimator::GetDelta() { return sqrt( this->deltaSquared ); } /* * Estimate the plane parameters [n_0,...,n_k,a_0,...,a_k], note that point * dimension is k+1. * The plane is given as dot(n,p-a) = dot(n,p) - dot(n,a) = 0 * The second dot product is a constant, d, so each point gives us one * equation in the equation system (Ax=0): * [n_0] * . * [p_0,...,p_k,-1] . = 0 * . * [n_k] * [ d ] * * If all k+1 points are linearly independent then the matrix A has a one * dimensional null space [A is a (k+1)X(k+2) matrix] which is the answer we * seek. * */ template< unsigned int dimension > void PlaneParametersEstimator::Estimate( std::vector< Point *> &data, std::vector ¶meters ) { unsigned int i, j; double norm; const double EPS = 2*NumericTraits::epsilon(); parameters.clear(); //user forgot to initialize the minimal number of required //elements or there are not enough data elements for computation if( this->minForEstimate==0 || data.size() < this->minForEstimate ) return; if( dimension == 3 ) { //compute plane normal directly double nx,ny,nz; vnl_vector v1(3), v2(3); v1[0] = (*data[1])[0] - (*data[0])[0]; v1[1] = (*data[1])[1] - (*data[0])[1]; v1[2] = (*data[1])[2] - (*data[0])[2]; v2[0] = (*data[2])[0] - (*data[0])[0]; v2[1] = (*data[2])[1] - (*data[0])[1]; v2[2] = (*data[2])[2] - (*data[0])[2]; nx = v1[1]*v2[2] - v1[2]*v2[1]; ny = v1[2]*v2[0] - v1[0]*v2[2]; nz = v1[0]*v2[1] - v1[1]*v2[0]; norm = sqrt(nx*nx+ny*ny+nz*nz); if( norm< EPS ) //points are collinear return; parameters.push_back(nx/norm); parameters.push_back(ny/norm); parameters.push_back(nz/norm); } else { //get the plane normal as the null space of the matrix described above vnl_matrix A( this->minForEstimate, this->minForEstimate+1 ); for( i=0; iminForEstimate; i++ ) { Point &pnt = *(data[i]); for( j=0; jminForEstimate; j++ ) A(i,j) = pnt[j]; A(i,j) = -1; } vnl_svd svdA( A ); //explicitly zero out small singular values svdA.zero_out_absolute( EPS ); //the points are linearly dependent, need at least k linearly //independent points (gives us rank(A)=k) if( svdA.rank()minForEstimate ) return; //the one dimensional null space of A is the solution we seek vnl_vector x(this->minForEstimate+1); x = svdA.nullvector(); //get the (hyper)plane normal, we need to set it so ||n||=1, this //means we need to scale our solution to be // 1/||n_computed||*[n_computed,d] which is also a solution to the //equation system. norm = 0; for( i=0; iminForEstimate; i++ ) { norm+=x[i]*x[i]; parameters.push_back( x[i] ); } norm = 1.0/sqrt(norm); for( i=0; iminForEstimate; i++ ) parameters[i]*=norm; } //first point is arbitrarily chosen to be the //"point on plane" for( i=0; i void PlaneParametersEstimator::Estimate(std::vector< Point > &data, std::vector ¶meters ) { std::vector< Point *> usedData; int dataSize = data.size(); for( int i=0; i void PlaneParametersEstimator::LeastSquaresEstimate( std::vector< Point *> &data, std::vector ¶meters ) { parameters.clear(); //user forgot to initialize the minimal number of required //elements or there are not enough data elements for computation if( this->minForEstimate==0 || data.size() < this->minForEstimate ) return; unsigned int i, j, k, pointNum = data.size(); vnl_matrix meanMat( dimension, dimension ), covariance( dimension,dimension,0 ); vnl_vector mean(dimension,0); //create covariance matrix double sqrtN = sqrt((double)pointNum); for( i=0; i eigenSystem( covariance ); //the (hyper)plane normal is the eigen-vector corresponding to //the smallest eigen-value, I assume ||eigenSystem.V(i,0)|| = 1 for( i=0; i void PlaneParametersEstimator::LeastSquaresEstimate( std::vector< Point > &data, std::vector ¶meters ) { std::vector< Point *> usedData; int dataSize = data.size(); for( int i=0; i bool PlaneParametersEstimator::Agree( std::vector ¶meters, Point &data ) { double signedDistance = 0; for( unsigned int i=0; ideltaSquared ); } } // end namespace itk #endif //_PLANE_PARAM_ESTIMATOR_TXX_ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/RANSAC.h000066400000000000000000000150171321604176500250430ustar00rootroot00000000000000#ifndef _RANSAC_H_ #define _RANSAC_H_ #include #include #include #include #include #include #include "ParametersEstimator.h" #include "itkMultiThreader.h" #include "itkSimpleFastMutexLock.h" #include "itkExceptionObject.h" /** * This class implements a multi-threaded version of the RAndom SAmple * Consensus (RANSAC) framework, a framework for robust parameter estimation. * Given data containing outliers we estimate the model parameters using subsets * of the original data: * 1. Choose the minimal subset from the data for computing the exact model * parameters. * 2. See how much of the input data agrees with the computed parameters. * 3. Goto step 1. This can be done up to (N choose m) times, where m is the * number of data objects required for an exact estimate and N is the total * number of data objects. * 4. Take the largest subset of objects which agreed on the parameters and * compute a least squares fit using them. * * This is based on: * Fischler M.A., Bolles R.C., * "Random Sample Consensus: A Paradigm for Model Fitting with Applications to * Image Analysis and Automated Cartography", * Communications of the ACM, Vol. 24(6), 1981. * * Hartely R., Zisserman A., "Multiple View Geometry in Computer Vision", 2001. * * The class template parameters are T - objects used for the parameter estimation * (e.g. Point2D in line estimation, * std::pair in * homography estimation). * S - type of parameter (e.g. double). * * @author: Ziv Yaniv (zivy@isis.georgetown.edu) * */ namespace itk { template class RANSAC : public Object { public: typedef RANSAC Self; typedef Object Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkTypeMacro( RANSAC, Object ); /** New method for creating an object using a factory. */ itkNewMacro( Self ) /** * Set/Get the number of threads used by the RANSAC implementation. * * @param numberOfThreads Number of threads the algorithm uses. Valid values * are in [1, #cores]. */ void SetNumberOfThreads( unsigned int numberOfThreads ); unsigned int GetNumberOfThreads(); /** * Set the function object that is able to estimate the desired parametric * entity (e.g. PlaneParametersEstimator). * @param paramEstimator An object which can estimate the desired parameters * using both an exact fit and a least squares fit. */ void SetParametersEstimator( typename ParametersEstimator::Pointer paramEstimator ); /** * Set the data objects we want to use (e.g. point pairs for estimating a * homography. * @param data The input from which the parameters will be estimated. */ void SetData( std::vector &data ); /** * Estimate the model parameters using the RANSAC framework. * @param parameters A vector which will contain the estimated parameters. * If there is an error then this vector will be empty. * Errors are: 1. Parameter estimation object or data not * set, see SetParameterEstimator and * SetData. * 2. The given data is in a singular * configuration (e.g. trying to fit a circle * to a set of colinear points). * 3. The given parameter desiredProbabilityForNoOutliers * is not in (0,1) * @param desiredProbabilityForNoOutliers The probability that at least one of * the selected subsets doesn't contain * an outlier, must be in (0,1). * @return Returns the percentage of data used in the least squares estimate. */ double Compute( std::vector ¶meters, double desiredProbabilityForNoOutliers ); protected: /** * Construct an instance of the RANSAC algorithm. The number of threads used * in the computation is 1, valid values are in [1, #cores]. * */ RANSAC(); ~RANSAC(); private: /** * Compute n choose m [ n!/(m!*(n-m)!)]. * If choose(n,m)>std::numeric_limits::max(), or there is an * overflow during the computations then we return * std::numeric_limits::max(), otherwise the correct value * is returned. */ unsigned int Choose( unsigned int n, unsigned int m ); class SubSetIndexComparator { private: int length; public: SubSetIndexComparator(int arrayLength) : length(arrayLength){} bool operator()(const int *arr1, const int *arr2) const { for(int i=0; ilength; i++) { if(arr1[i] < arr2[i]) return true; else if(arr1[i] > arr2[i]) return false; } return false; } }; static ITK_THREAD_RETURN_TYPE RANSACThreadCallback( void *arg ); //number of threads used in computing the RANSAC hypotheses unsigned int numberOfThreads; //the following variables are shared by all threads used in the RANSAC //computation //array corresponding to length of data array, data[i]== true if it //agrees with the best model, otherwise false bool *bestVotes; unsigned int numVotesForBest; std::vector data; //set which holds all of the subgroups/hypotheses already selected std::set *chosenSubSets; //number of iterations, equivalent to desired number of hypotheses unsigned int numTries; double numerator; unsigned int allTries; /* GCS - best hypothesis during RANSAC, so we can skip the final lsq estimate */ std::vector best_estimate; typename ParametersEstimator::Pointer paramEstimator; itk::SimpleFastMutexLock hypothesisMutex; itk::SimpleFastMutexLock resultsMutex; }; } // end namespace itk #include "RANSAC.txx" #endif //_RANSAC_H_ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/RANSAC.txx000066400000000000000000000232051321604176500254350ustar00rootroot00000000000000#ifndef _RANSAC_TXX_ #define _RANSAC_TXX_ namespace itk { template RANSAC::RANSAC( ) { this->numberOfThreads = 1; } template RANSAC::~RANSAC( ) { } template void RANSAC::SetNumberOfThreads( unsigned int numberOfThreads ) { if( numberOfThreads==0 || numberOfThreads>itk::MultiThreader::GetGlobalDefaultNumberOfThreads() ) throw ExceptionObject(__FILE__,__LINE__, "Invalid setting for number of threads."); this->numberOfThreads = numberOfThreads; } template unsigned int RANSAC::GetNumberOfThreads() { return this->numberOfThreads; } template void RANSAC::SetParametersEstimator( typename ParametersEstimator::Pointer paramEstimator ) { //check if the given parameter estimator can be used in combination //with the data, if there aren't enough data elements then throw an //exception. If there is no data then any parameter estimator works if( !this->data.empty() ) if( data.size() < paramEstimator->GetMinimalForEstimate() ) throw ExceptionObject(__FILE__,__LINE__, "Not enough data elements for use with this parameter estimator."); this->paramEstimator = paramEstimator; } template void RANSAC::SetData( std::vector &data ) { //check if the given data vector has enough elements for use with //the parameter estimator. If the parameter estimator hasn't been //set yet then any vector is good. if( this->paramEstimator.IsNotNull() ) if( data.size() < this->paramEstimator->GetMinimalForEstimate() ) throw ExceptionObject(__FILE__,__LINE__, "Not enough data elements for use with the parameter estimator."); this->data = data; } template double RANSAC::Compute( std::vector ¶meters, double desiredProbabilityForNoOutliers ) { //STEP1: setup parameters.clear(); //the data or the parameter estimator were not set //or desiredProbabilityForNoOutliers is not in (0.0,1.0) if( this->paramEstimator.IsNull() || this->data.empty() || desiredProbabilityForNoOutliers>=1.0 || desiredProbabilityForNoOutliers<=0.0 ) return 0; unsigned int numForEstimate = this->paramEstimator->GetMinimalForEstimate(); size_t numDataObjects = this->data.size(); this->bestVotes = new bool[numDataObjects]; //initalize with 0 so that the first computation which gives //any type of fit will be set to best this->numVotesForBest = 0; SubSetIndexComparator subSetIndexComparator( numForEstimate ); this->chosenSubSets = new std::set( subSetIndexComparator ); //initialize with the number of all possible subsets this->allTries = Choose( numDataObjects, numForEstimate ); this->numTries = this->allTries; this->numerator = log( 1.0-desiredProbabilityForNoOutliers ); srand( (unsigned)time(NULL) ); //seed random number generator //STEP2: create the threads that generate hypotheses and test itk::MultiThreader::Pointer threader = itk::MultiThreader::New(); threader->SetNumberOfThreads( this->numberOfThreads ); threader->SetSingleMethod( RANSAC::RANSACThreadCallback, this ); //runs all threads and blocks till they finish threader->SingleMethodExecute(); //STEP3: least squares estimate using largest consensus set and cleanup #if defined (commentout) std::vector leastSquaresEstimateData; if( this->numVotesForBest > 0 ) { for( unsigned int j=0; jbestVotes[j] ) leastSquaresEstimateData.push_back( &(data[j]) ); } paramEstimator->LeastSquaresEstimate( leastSquaresEstimateData,parameters ); } #endif /* GCS Skip this step, instead return best hypothesis */ parameters = best_estimate; //cleanup typename std::set::iterator it = this->chosenSubSets->begin(); typename std::set::iterator chosenSubSetsEnd = this->chosenSubSets->end(); while( it!=chosenSubSetsEnd ) { delete [] (*it); it++; } this->chosenSubSets->clear(); delete this->chosenSubSets; delete [] this->bestVotes; return (double)this->numVotesForBest/(double)numDataObjects; } template ITK_THREAD_RETURN_TYPE RANSAC::RANSACThreadCallback( void *arg ) { typedef itk::MultiThreader::ThreadInfoStruct ThreadInfoType; ThreadInfoType *infoStruct = static_cast( arg ); //dynamic_cast doesn't work with void * RANSAC *caller = reinterpret_cast< RANSAC * >( infoStruct->UserData ); if( caller!=NULL ) { unsigned int i, k, l, m, maxIndex, numVotesForCur; int j; int *curSubSetIndexes; unsigned int numDataObjects = caller->data.size(); unsigned int numForEstimate = caller->paramEstimator->GetMinimalForEstimate(); std::vector exactEstimateData; std::vector exactEstimateParameters; double denominator; //true if data[i] agrees with the current model, otherwise false bool *curVotes = new bool[numDataObjects]; //true if data[i] is NOT chosen for computing the exact fit, otherwise false bool *notChosen = new bool[numDataObjects]; for( i=0; inumTries; i++ ) { //randomly select data for exact model fit ('numForEstimate' objects). std::fill( notChosen,notChosen+numDataObjects, true ); curSubSetIndexes = new int[numForEstimate]; exactEstimateData.clear(); maxIndex = numDataObjects-1; for( l=0; ldata[k]) ); notChosen[k] = false; maxIndex--; } //get the indexes of the chosen objects so we can check that //this sub-set hasn't been chosen already for( l=0, m=0; mhypothesisMutex.Lock(); //check that the sub-set just chosen is unique std::pair< typename std::set::iterator, bool> res = caller->chosenSubSets->insert( curSubSetIndexes ); caller->hypothesisMutex.Unlock(); if(res.second == true) { //first time we chose this sub set //use the selected data for an exact model parameter fit caller->paramEstimator->Estimate( exactEstimateData, exactEstimateParameters ); //selected data is a singular configuration (e.g. three //colinear points for a circle fit) if( exactEstimateParameters.size() == 0 ) continue; //see how many agree on this estimate numVotesForCur = 0; std::fill( curVotes, curVotes+numDataObjects, false ); //continue checking data until there is no chance of getting a larger consensus set //or all the data has been checked for( m=0; mnumVotesForBest-numVotesForCurparamEstimator->Agree( exactEstimateParameters, caller->data[m] ) ) { curVotes[m] = true; numVotesForCur++; } } // Did we find a larger consensus set? caller->resultsMutex.Lock(); if( numVotesForCur > caller->numVotesForBest ) { caller->numVotesForBest = numVotesForCur; std::copy( curVotes, curVotes+numDataObjects, caller->bestVotes ); /* GCS - Save the best parameters */ caller->best_estimate = exactEstimateParameters; //all data objects are inliers, terminate the search if( caller->numVotesForBest == numDataObjects ) { i= caller->numTries; } else { //update the estimate of outliers and the number of iterations we need denominator = log( 1.0- pow((double)numVotesForCur/(double)numDataObjects, (double)(numForEstimate)) ); caller->numTries = (int)( caller->numerator/denominator + 0.5 ); //there are cases when the probablistic number of tries is greater than all possible sub-sets caller->numTries = caller->numTriesallTries ? caller->numTries : caller->allTries; } } caller->resultsMutex.Unlock(); } else { //this sub set already appeared, release memory delete [] curSubSetIndexes; } } delete [] curVotes; delete [] notChosen; } return ITK_THREAD_RETURN_VALUE; } /*****************************************************************************/ template unsigned int RANSAC::Choose(unsigned int n, unsigned int m) { double denominatorEnd, numeratorStart, numerator,denominator, i, result; //perform smallest number of multiplications if( (n-m) > m ) { numeratorStart = n-m+1; denominatorEnd = m; } else { numeratorStart = m+1; denominatorEnd = n-m; } for( i=numeratorStart, numerator=1; i<=n; i++ ) numerator*=i; for( i=1, denominator=1; i<=denominatorEnd; i++ ) denominator*=i; result = numerator/denominator; //check for overflow both in computation and in result if( denominator>std::numeric_limits::max() || numerator>std::numeric_limits::max() || static_cast(std::numeric_limits::max())::max(); else return static_cast( result ); } } // end namespace itk #endif //_RANSAC_TXX_ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/SphereParametersEstimator.h000066400000000000000000000205521321604176500312360ustar00rootroot00000000000000#ifndef _SPHERE_PARAM_ESTIMATOR_H_ #define _SPHERE_PARAM_ESTIMATOR_H_ #include "ParametersEstimator.h" #include #include #include namespace itk { /** * This class estimates the parameters of a (hyper)sphere. * A sphere is represented as: (1) (p-c)^T(p-c) = sum(p_i-c_i)^2 = r^2 * where p in R^n is a point on the (hyper)sphere, c in R^n is the sphere's * center, and r its radius. * * @author: Ziv Yaniv (zivy@isis.georgetown.edu) * */ template< unsigned int dimension > class SphereParametersEstimator : public ParametersEstimator< Point, double > { public: typedef SphereParametersEstimator Self; typedef ParametersEstimator< Point, double > Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkTypeMacro( SphereParametersEstimator, ParametersEstimator ); /** New method for creating an object using a factory. */ itkNewMacro( Self ) enum LeastSquaresType {ALGEBRAIC = 0, GEOMETRIC}; /** * Compute the hyper(sphere) defined by the given data points. * @param data A vector containing k+1 kD points. * @param parameters This vector is cleared and then filled with the computed * parameter values. The parameter values of the * hyper(sphere) passing through these points [c_0,...,c_k,r]. * If the vector contains less than k+1 points or the points * are linearly dependent (e.g. four coplanar points in the * 3D case) then the resulting parameters vector is empty * (size = 0). */ virtual void Estimate( std::vector< Point *> &data, std::vector ¶meters ); virtual void Estimate( std::vector< Point > &data, std::vector ¶meters ); /** * Compute a least squares estimate of the (hyper) sphere defined by the given * points. This may be either an algebraic or geomtric least squares * estimate depending on the LeastSquaresType settings. * @param data The sphere should minimize the least squares error to these * points. * @param parameters This vector is cleared and then filled with the estimated * parameter values. The parameters of the hyper(sphere) * passing through these points [c_0,...,c_k,r]. If the * vector contains less than k+1 points or the points are * linearly dependent (e.g. all points are coplanar in the * 3D case) then the resulting parameters vector is empty * (size = 0). */ virtual void LeastSquaresEstimate( std::vector< Point *> &data, std::vector ¶meters ); virtual void LeastSquaresEstimate( std::vector< Point > &data, std::vector ¶meters ); /** * Return true if the distance between the (hyper)sphere and the given point * is smaller than 'delta' (see SetDelta()). * * @param parameters The sphere parameters [c_0,...,c_k,r]. * @param data Check that the Euclidean distance between this point and the * sphere is smaller than 'delta'. */ virtual bool Agree( std::vector ¶meters, Point &data ); /** * Change the type of least squares solution. * @param lsType When the leastSquaresEstimate() method is called it computes * an algebraic or geometric fit. This flag tells it which one. */ void SetLeastSquaresType( LeastSquaresType lsType ); /** * Compute a least squares estimate of the (hyper)sphere defined by the given * points. * This implementation is of an algebraic least squares error: * min||Ax-b||, where A = [-2p_0,-2p_1,...,-2p_{k-1},1], x = [c_0,c_1,...,c_{k-1},d], b = [-p_0^2 - p_1^2 - ... -p_{k-1}^2] * * @param data The (hyper)sphere should minimize the algebraic least squares * error to these points. * @param parameters This vector is cleared and then filled with the estimated * parameter values. The parameters of the hyper(sphere) * passing through these points [c_0,...,c_k,r]. * If the vector contains less than k+1 points or the points * are linearly dependent (e.g. all points are coplanar in * the 3D case) then the resulting parameters vector is * empty (size = 0). */ void AlgebraicLeastSquaresEstimate( std::vector< Point *> &data, std::vector ¶meters ); /** * Compute a least squares estimate of the circle defined by the given points. * This implementation is of a geometric least squares error: * min (sum (r - sqrt((p_0-c_0)^2 + (p_1-c_1)^2 +...+ (p_{k-1}-c_{k-1})^2))^2 * * @param data The (hyper)sphere should minimize the geometric least squares error to these points. * @param initialParameters This vector contains the initial parameter values for nonlinear estimation. * @param finalParameters This vector is cleared and then filled with the computed sphere parameters [centerX,centerY,centerZ,r]. */ void GeometricLeastSquaresEstimate( std::vector< Point *> &data, std::vector &initialParameters, std::vector &finalParameters ); /** * Set parameter which defines a threshold for a point to be considered on the * sphere. * @param delta A point is on the (hyper)sphere if its distance from the * (hyper)sphere is less than 'delta'. */ void SetDelta( double delta ); double GetDelta(); /** * Get the distances between the given (hyper)sphere and the given points. * These are pushed at the end of the 'distances' vector. * * @param parameters The (hyper)sphere parameters [c,r]. * @param data The points whose distance from the (hyper)sphere we want. * @param distances The computed distances. If the vector is empty then the * point and distance indexes match, * otherwise there is an offset due to the original number * of entries previously found in the vector. * @param min Minimal distance. * @param max Maximal distance. * @param mean Mean distance. */ static void GetDistanceStatistics( std::vector ¶meters, std::vector< Point > &data, std::vector &distances, double &min, double &max, double &mean ); protected: SphereParametersEstimator(); ~SphereParametersEstimator(); private: SphereParametersEstimator( const Self& ); //purposely not implemented void operator=( const Self& ); //purposely not implemented enum {CIRCLE = 2, SPHERE=3}; double delta; LeastSquaresType lsType; //algebraic or geometric least squares inline void Estimate2D( std::vector< Point * > &data, std::vector ¶meters ); inline void Estimate3D( std::vector< Point * > &data, std::vector ¶meters ); inline void EstimateND( std::vector< Point * > &data, std::vector ¶meters ); class SumSquaresSpherePointsDistanceFunction : public vnl_least_squares_function { public: SumSquaresSpherePointsDistanceFunction( std::vector *> *data ); virtual void f( vnl_vector const &x, vnl_vector &fx ); virtual void gradf( vnl_vector const& x, vnl_matrix& jacobian ); private: std::vector *> *data; }; }; } // end namespace itk #include "SphereParametersEstimator.txx" //the implementation is in this file #endif //_SPHERE_PARAM_ESTIMATOR_H_ SphereParametersEstimator.txx000066400000000000000000000410011321604176500315430ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac#ifndef _SPHERE_PARAM_ESTIMATOR_TXX_ #define _SPHERE_PARAM_ESTIMATOR_TXX_ #include #include namespace itk { template< unsigned int dimension > SphereParametersEstimator::SphereParametersEstimator() { this->delta = NumericTraits::min(); this->lsType = GEOMETRIC; this->minForEstimate = dimension+1; } template< unsigned int dimension > SphereParametersEstimator::~SphereParametersEstimator() { } template< unsigned int dimension > void SphereParametersEstimator::SetLeastSquaresType(LeastSquaresType lsType) { if( lsType!=ALGEBRAIC && lsType!=GEOMETRIC ) throw ExceptionObject(__FILE__,__LINE__, "Invalid value for least squares type."); this->lsType = lsType; } template< unsigned int dimension > void SphereParametersEstimator::SetDelta( double delta ) { if( delta<0 ) throw ExceptionObject(__FILE__,__LINE__, "Invalid setting for delta, must be >0."); this->delta = delta; } template< unsigned int dimension > double SphereParametersEstimator::GetDelta() { return this->delta; } /* * Given k+1 points we compute the (hyper)sphere that goes through them. * We know that (p_1-center)^2 = (p_2-center)^2 =...= (p_{k+1}-center)^2 = r^2 * This gives us k linearly independent equations in k unknowns (center_1,center_2,...,center_k): * (p_1-center)^2 = (p_2-center)^2 * (p_1-center)^2 = (p_3-center)^2 * : * (p_1-center)^2 = (p_{k+1}-center)^2, * after simplification we get: * [(p_11 - p_21) (p_12 - p_22) ... (p_1k - p_2k) ] [center_1] [(p_11^2 - p_21^2) + (p_12^2 - p_22^2) + ... + (p_1k^2 - p_2k^2) ] * [(p_11 - p_31) (p_12 - p_32) ... (p_1k - p_3k) ] [center_2] = 0.5* [(p_11^2 - p_31^2) + (p_12^2 - p_32^2) + ... + (p_1k^2 - p_3k^2) ] * [ : : : : ] [ : ] [ : : : : ] * [(p_11 - p_{k+1}1) (p_12 - p_{k+1}2) ... (p_1k - p_{k+1}k)] [center_k] [(p_11^2 - p_{k+1}1^2) + (p_12^2 - p_{k+1}2^2) + ... + (p_1k^2 - p_{k+1}k^2)] * * * Solving this set of linear equations yields the (hyper)sphere center, after which the radius is computed as sqrt((center-p_1)^T(center-p_1)). * * For dimension = 2, a circle, and dimension = 3, a sphere we solve the linear equations (compute the matrix inverse) * using Cramer's rule: A^-1 = C^T/det(A) where C is the * cofactor matrix, C_ij = -1^(i+j)detM_ij. * * In 2D we get: * [a b] [d -b] * A = we get A^-1 = 1/(ad - bc) [ ] * [c d] [-c a] * * In 3D we get: * [a b c] [ei-fh ch-bi bf-ce] * A = [d e f] we get A^-1 = 1/(a(ei-fh) - b(di-fg) + c(dh-eg)) [fg-di ai-cg cd-af] * [g h i] [dh-eg bg-ah ae-bd] */ template< unsigned int dimension > void SphereParametersEstimator::Estimate( std::vector< Point *> &data, std::vector ¶meters ) { parameters.clear(); //user forgot to initialize the minimal number of required //elements or there are not enough data elements for computation if( this->minForEstimate==0 || data.size() < this->minForEstimate ) return; switch( dimension ) { case CIRCLE: Estimate2D( data, parameters ); break; case SPHERE: Estimate3D( data, parameters ); break; default: //hyper-sphere EstimateND( data, parameters ); break; } } template< unsigned int dimension > void SphereParametersEstimator::Estimate( std::vector< Point > &data, std::vector ¶meters ) { std::vector< Point *> usedData; int dataSize = data.size(); for( int i=0; i void SphereParametersEstimator::Estimate2D( std::vector< Point * > &data, std::vector ¶meters ) { const double EPS = 2*NumericTraits::epsilon(); double A00,A01,A10,A11; double b0, b1; double detA; Point &p0 = (*data[0]); Point &p1 = (*data[1]); Point &p2 = (*data[2]); A00 = p0[0] - p1[0]; A01 = p0[1] - p1[1]; A10 = p0[0] - p2[0]; A11 = p0[1] - p2[1]; detA = (A00*A11 - A01*A10); //the three points are colinear (A is singular, det(A) void SphereParametersEstimator::Estimate3D( std::vector< Point * > &data, std::vector ¶meters ) { const double EPS = 2*NumericTraits::epsilon(); double A00,A01,A02,A10,A11,A12,A20,A21,A22; double CT00,CT01,CT02,CT10,CT11,CT12,CT20,CT21,CT22; double b0, b1, b2; double detA; Point &p0 = (*data[0]); Point &p1 = (*data[1]); Point &p2 = (*data[2]); Point &p3 = (*data[3]); A00 = p0[0] - p1[0]; A01 = p0[1] - p1[1]; A02 = p0[2] - p1[2]; A10 = p0[0] - p2[0]; A11 = p0[1] - p2[1]; A12 = p0[2] - p2[2]; A20 = p0[0] - p3[0]; A21 = p0[1] - p3[1]; A22 = p0[2] - p3[2]; CT00 = A11*A22 - A12*A21; CT10 = A12*A20 - A10*A22; CT20 = A10*A21 - A11*A20; detA = A00*CT00 + A01*CT10 + A02*CT20; if( fabs(detA) void SphereParametersEstimator::EstimateND( std::vector< Point * > &data, std::vector ¶meters ) { const double EPS = 2*NumericTraits::epsilon(); double rSquared; unsigned int i,j, index; vnl_matrix A( dimension,dimension ); vnl_vector b( dimension, 0 ); vnl_vector x( dimension ); //create the matrix A Point &p0 = ( *data[0] ); for( i=0, index=1; i &p = ( *data[index] ); A(i,j) = p0[j] - p[j]; b[i] += A(i,j)*( p0[j] + p[j] ); } } vnl_matrix_inverse Ainv(A); //explicitly zero out small singular values //this is ugly as it exposes that the inverse is computed via SVD Ainv.zero_out_absolute(EPS); //points are coplanar if( Ainv.rank() bool SphereParametersEstimator::Agree( std::vector ¶meters, Point &data ) { double delta = 0; for(unsigned int i=0; idelta; } template< unsigned int dimension > void SphereParametersEstimator::AlgebraicLeastSquaresEstimate( std::vector< Point *> &data, std::vector ¶meters ) { const double EPS = 2*NumericTraits::epsilon(); parameters.clear(); if( data.size()minForEstimate ) //not enough points for estimate return; unsigned int numPoints = data.size(); vnl_matrix A(numPoints,dimension+1); vnl_vector x(dimension+1); vnl_vector b(numPoints,0); unsigned int i,j; for( i=0; i Ainv( A ); //explicitly zero out small singular values //this is ugly as it exposes that the inverse is computed via SVD Ainv.zero_out_absolute( EPS ); if( Ainv.rank()minForEstimate ) //all the points are collinear return; x = Ainv * b; double rSquared = -x[dimension]; for( i=0; i0 ) parameters.push_back( sqrt(rSquared) ); else parameters.clear(); } template< unsigned int dimension > void SphereParametersEstimator::LeastSquaresEstimate( std::vector *> &data, std::vector ¶meters ) { parameters.clear(); //user forgot to initialize the minimal number of required //elements or there are not enough data elements for computation if( this->minForEstimate==0 || data.size() < this->minForEstimate ) return; std::vector initialParameters; switch( this->lsType ) { case ALGEBRAIC: AlgebraicLeastSquaresEstimate( data, parameters ); break; case GEOMETRIC: //algebraic least squares for initial estimate AlgebraicLeastSquaresEstimate( data, initialParameters ); if(initialParameters.size() == 0) //the points are coplanar return; GeometricLeastSquaresEstimate( data, initialParameters, parameters ); break; } } template< unsigned int dimension > void SphereParametersEstimator::LeastSquaresEstimate( std::vector< Point > &data, std::vector ¶meters ) { std::vector *> usedData; int dataSize = data.size(); for( int i=0; i void SphereParametersEstimator::GeometricLeastSquaresEstimate( std::vector< Point *> &data, std::vector &initialParameters, std::vector &finalParameters ) { vnl_vector parameters(dimension+1); unsigned int i; for(i=0; i<=dimension; i++) parameters[i] = initialParameters[i]; SphereParametersEstimator::SumSquaresSpherePointsDistanceFunction optimizedFunction( &data ); vnl_levenberg_marquardt lmOptimization( optimizedFunction ); double gradTolerance = 10e-16; double parametersChangeTolerance = 10e-16; int maxIterations = 500; lmOptimization.set_x_tolerance( parametersChangeTolerance ); lmOptimization.set_g_tolerance( gradTolerance ); lmOptimization.set_max_function_evals( maxIterations ); lmOptimization.minimize( parameters ); finalParameters.clear(); for(i=0; i<=dimension; i++) finalParameters.push_back( parameters[i] ); } template< unsigned int dimension > void SphereParametersEstimator::GetDistanceStatistics( std::vector ¶meters, std::vector< Point > &data, std::vector &distances, double &min, double &max, double &mean ) { if( parameters.size() < dimension+1 ) throw ExceptionObject( __FILE__,__LINE__, "Number of (hyper) sphere parameters does not match dimension."); unsigned int i,j,n; double dist; //use first point for initialization dist = 0.0; for( j=0; j &pnt = data[i]; dist = 0.0; for( j=0; jmax ) max = dist; else if( dist SphereParametersEstimator::SumSquaresSpherePointsDistanceFunction::SumSquaresSpherePointsDistanceFunction(std::vector *> *data) : vnl_least_squares_function( dimension+1, data->size(), vnl_least_squares_function::use_gradient ) { this->data = data; } //x = [c_0,c_1,...c_k,r] template< unsigned int dimension > void SphereParametersEstimator::SumSquaresSpherePointsDistanceFunction::f( vnl_vector const &x, vnl_vector &fx ) { unsigned int i,j, numPoints = this->data->size(); double sqrVal; for(i=0; i &pnt = *((*this->data)[i]); for(j=0; j void SphereParametersEstimator::SumSquaresSpherePointsDistanceFunction::gradf( vnl_vector const& x, vnl_matrix& jacobian ) { unsigned int i,j,numPoints = this->data->size(); double sqrtVal; for( i=0; i &p = (*(*this->data)[i]); for( j=0; j #include #include #include #include "RandomNumberGenerator.h" #include "PlaneParametersEstimator.h" /** * Generate points on a plane with additive Gaussian noise, except the first * three points. * @param numPoints How many points, in total there will be numPoints+3. * @param data The points are added to the end of this vector. The first three * points define the plane the rest numPoints points are * approximatly on the plane. */ void GeneratePlaneData( unsigned int numPoints, std::vector< itk::Point > &data ); /** * Save the points to file. */ void SaveData( const std::string &fileName, std::vector< itk::Point > &data ); /** * Load the points from file. It is assumed that the first three points * have no noise component, the rest do have additive Gaussian noise (see * GeneratePlaneData()). */ void LoadData( const std::string &fileName, std::vector< itk::Point > &data ); /* * Test the plane estimator's methods. We arbitrarily choose to work with 3D * planes even though the tested code works for any dimension. */ int main( int argc, char *argv[] ) { const int NUM_SAMPLES = 20; //number of points sampled on plane std::vector< itk::Point > pointData, minPointData; itk::Point v1, v2, v3; bool succeedExact, succeedLeastSquares; if( argc == 1 ) { GeneratePlaneData( NUM_SAMPLES, pointData ); //SaveData( std::string("planeTestData.txt"), pointData ); } else { try { LoadData( std::string( argv[1] ), pointData ); } catch( std::exception & ) { std::cerr<<"Failed to load input file.\n"; return EXIT_FAILURE; } } minPointData.push_back( pointData[0] ); minPointData.push_back( pointData[1] ); minPointData.push_back( pointData[2] ); //2. Test the code. Compare the known plane parameters to // (a) their exact estimate using three points; and // (b) their least squares estimate. std::vector planeParameters; double maxDistanceToPlane = 0.5; itk::PlaneParametersEstimator<3>::Pointer ppEstimator = itk::PlaneParametersEstimator<3>::New(); ppEstimator->SetDelta( maxDistanceToPlane ); double tmp; //The known plane parameters v1 = pointData[0]; v2 = pointData[1]; v3 = pointData[2]; vnl_vector vec1(3), vec2(3), planeNormal(3); vec1[0] = v2[0] - v1[0]; vec1[1] = v2[1] - v1[1]; vec1[2] = v2[2] - v1[2]; vec2[0] = v3[0] - v1[0]; vec2[1] = v3[1] - v1[1]; vec2[2] = v3[2] - v1[2]; planeNormal = vnl_cross_3d( vec1, vec2 ); planeNormal.normalize(); std::cout<<"Known plane parameters [nx,ny,nz,ax,ay,az]:\n\t [ "; std::cout< pointOnPlane = pointData[0]; itk::Point pointOffPlane; pointOffPlane[0] = v1[0] + 2 * maxDistanceToPlane * planeParameters[0]; pointOffPlane[1] = v1[1] + 2 * maxDistanceToPlane * planeParameters[1]; pointOffPlane[2] = v1[2] + 2 * maxDistanceToPlane * planeParameters[2]; if( !ppEstimator->Agree( planeParameters, pointOnPlane ) || ppEstimator->Agree( planeParameters, pointOffPlane ) ) return EXIT_FAILURE; //compute an estimate using three points ppEstimator->Estimate( minPointData, planeParameters ); if( planeParameters.size() == 0 ) { std::cout<<"Plane going through three points [nx,ny,nz,ax,ay,az]: DEGENERATE CONFIGURATION\n\n"; succeedExact = true; } else { std::cout<<"Plane going through three points [nx,ny,nz,ax,ay,az], no noise:\n\t [ "; std::cout< 0.99619469809174553229501040247389; std::cout<<"\tDot product of known and computed plane normals[+-1=correct]: "<LeastSquaresEstimate( pointData, planeParameters ); if( planeParameters.size() == 0 ) { std::cout<<"Least squares plane parameters [nx,ny,nz,ax,ay,az]: DEGENERATE CONFIGURATION\n\n"; succeedLeastSquares = true; } else { std::cout<<"Least squares plane parameters [nx,ny,nz,ax,ay,az]:\n\t [ "; std::cout< 0.99619469809174553229501040247389; std::cout<<"\tDot product of known and computed plane normals[+-1=correct]: "< > &data ) { itk::Point pnt; double v1[3], v2[3], v3[3]; double bounds = 1000.0; double noiseSigma = 1.0; //noise is ~N(0,noiseSigma) //1.Create data with noise: randomly select three points in // [-bounds,bounds]x[-bounds,bounds]x[-bounds,bounds], then // generate points on the plane defined by these points. // For each point sampled on the plane add random noise. RandomNumberGenerator random; //create random plane double threshold = 0.17453292519943295769236907684886; //sin(10^o) bool done = false; while( !done ) { //three random points v1[0] = random.uniform( -bounds, bounds ); v1[1] = random.uniform( -bounds, bounds ); v1[2] = random.uniform( -bounds, bounds ); v2[0] = random.uniform( -bounds, bounds ); v2[1] = random.uniform( -bounds, bounds ); v2[2] = random.uniform( -bounds, bounds ); v3[0] = random.uniform( -bounds, bounds ); v3[1] = random.uniform( -bounds, bounds ); v3[2] = random.uniform( -bounds, bounds ); //compute plane normal and check for degenerate point //configuration vnl_vector vec1(3), vec2(3), planeNormal(3); vec1[0] = v2[0] - v1[0]; vec1[1] = v2[1] - v1[1]; vec1[2] = v2[2] - v1[2]; vec2[0] = v3[0] - v1[0]; vec2[1] = v3[1] - v1[1]; vec2[2] = v3[2] - v1[2]; planeNormal = vnl_cross_3d( vec1.normalize(), vec2.normalize() ); if( planeNormal.magnitude() > threshold ) done = true; } //push the three points without adding noise data.push_back( itk::Point( v1 ) ); data.push_back( itk::Point( v2 ) ); data.push_back( itk::Point( v3 ) ); //randomly generate points in the triangle defined by the above //three points using barycentric coordinates, the number of //generated points is numSamples double w1,w2; for(unsigned int i=0; i1) { w1 = 1-w1; w2 = 1-w2; } pnt[0] = w1*v1[0] + w2*v2[0] + (1-w1-w2)*v3[0] + random.normal( noiseSigma ); pnt[1] = w1*v1[1] + w2*v2[1] + (1-w1-w2)*v3[1] + random.normal( noiseSigma ); pnt[2] = w1*v1[2] + w2*v2[2] + (1-w1-w2)*v3[2] + random.normal( noiseSigma ); data.push_back( pnt ); } } void SaveData( const std::string &fileName, std::vector< itk::Point > &data ) { std::ofstream out; out.open( fileName.c_str() ); if( out.fail() ) throw std::exception(); for( unsigned int i=0; i > &data ) { itk::Point pnt; std::ifstream in; in.open( fileName.c_str() ); if( in.fail() ) throw std::exception(); while( !in.eof() ) { in>>pnt[0]>>pnt[1]>>pnt[2]; data.push_back( pnt ); } in.close(); } SphereParametersEstimatorTest.cxx000066400000000000000000000511461321604176500340120ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/Testing#include #include #include #include "RandomNumberGenerator.h" #include "SphereParametersEstimator.h" bool Test3D( std::ostream &out ); bool Test2D( std::ostream &out ); template bool TestnD( std::ostream &out ); template bool CompareAndPrint( const std::string &title, double threshold, std::vector &knownSphere, std::vector &estimatedSphere, std::ostream &out ); /** * Generate points on a (hyper)sphere with additive zero mean Gaussian noise. * @param numPoints How many points to generate. * @param data The points are added to the end of this vector. Theses points are * with noise. * @param cleanData The points are added to the end of this vector. Theses points are * without noise. * @param sphereParameters [c,r], sphere center and radius. Sphere is * defined as the set of points p such that * (p-c)^T(p-c)=r^2. */ template void GenerateData( unsigned int numPoints, double noiseStandardDeviation, std::vector< itk::Point > &data, std::vector< itk::Point > &cleanData, std::vector &sphereParameters ); /* * Specifically test 2D and 3D as the code for sphere estimation of these * dimensions is not the same as for general nD spheres. * Then test 4D as this covers all the code for dimensionality greater than 3. */ int main( int argc, char *argv[] ) { bool succeeded2D = Test2D( std::cout ); bool succeeded3D = Test3D( std::cout ); bool succeedednD = TestnD<4>( std::cout ); if( succeeded2D && succeeded3D && succeedednD ) return EXIT_SUCCESS; return EXIT_FAILURE; } /* * The following is taken from the comp.graphics.algorithms newsgroup faq. * It describes a method for uniformly generating random points on the unit * sphere. This is the method used for generating the data. * * There are several methods. Perhaps the easiest to understand is the rejection * method: generate random points in an origin- centered cube with opposite * corners (r,r,r) and (-r,-r,-r). Reject any point p that falls outside of the * sphere of radius r. Scale the vector to lie on the surface. Because the cube * to sphere volume ratio is pi/6, the average number of iterations before an * acceptable vector is found is 6/pi = 1.90986. This essentially doubles the * effort, and makes this method slower than the trig method. A timing * comparison conducted by Ken Sloan showed that the trig method runs in about * 2/3’s the time of the rejection method. He found that methods based on the * use of normal distributions are twice as slow as the rejection method. * The trig method: * This method works only in 3-space, but it is very fast. It depends on the * slightly counterintuitive fact (see proof below) that each of the three * coordinates is uniformly distributed on [-1,1] (but the three are not * independent, obviously). Therefore, it suffices to choose one axis (Z, say) * and generate a uniformly distributed value on that axis. This constrains the * chosen point to lie on a circle parallel to the X-Y plane, and the obvious * trig method may be used to obtain the remaining coordinates. * * 1. Choose z uniformly distributed in [-1,1]. * 2. Choose t uniformly distributed on [0, 2pi). * 3. Let r = sqrt(1-z^2). * 4. Let x = r * cos(t). * 5. Let y = r * sin(t). * * This method uses uniform deviates (faster to generate than normal deviates), * and no set of coordinates is ever rejected. * Here is a proof of correctness for the fact that the z-coordinate is * uniformly distributed. The proof also works for the x- and y- coordinates, * but note that this works only in 3-space. * * The area of a surface of revolution in 3-space is given by * A = 2 * pi * int_a^b f(x) * sqrt(1 + [f'(x}]^2) dx * * Consider a zone of a sphere of radius R. Since we are integrating in the z * direction, we have * f(z) = sqrt(R^2 - z^2) * f'(z) = -z / sqrt(R^2-z^2) * 1 + [f'(z)]^2 = r^2 / (R^2-z^2) * A = 2 * pi * int_a^b sqrt(R^2-z^2) * R/sqrt(R^2-z^2) dz * = 2 * pi * R int_a^b dz * = 2 * pi * R * (b-a) * = 2 * pi * R * h * where h = b-a is the vertical height of the zone. Notice how the integrand * reduces to a constant. The density is therefore uniform. */ bool Test3D( std::ostream &out ) { typedef itk::Point Point3D; bool succeedExact, succeedAlgebraic, succeedGeometric; std::vector trueSphereParameters; Point3D pnt; std::vector pointData, cleanPointData, minPointData; //number of points sampled on circle int numSamples = 20; //noise is distributed IID ~N(0,noiseSigma) double noiseSigma = 1.0; //random circle radius is in the range [0,maxRadius] double maxRadius = 50.0; int i; RandomNumberGenerator random; //points sampled with a uniform distribution over the sphere, with //additive Gaussian noise. randomly select the radius in the range //[0,maxRadius] and create a sphere whose center is at the origin with //this radius. trueSphereParameters.push_back( 0.0 ); trueSphereParameters.push_back( 0.0 ); trueSphereParameters.push_back( 0.0 ); //get random radius trueSphereParameters.push_back( random.uniform( 0.0, maxRadius ) ); //add 'numSamples' points for( i=0; i sphereParameters; itk::SphereParametersEstimator<3>::Pointer spEstimator = itk::SphereParametersEstimator<3>::New(); spEstimator->SetDelta( 0.5 ); //The known circle parameters out<<"Known sphere parameters [c_x,c_y,c_z,r]:\n\t"; out<<"["<GetMinimalForEstimate(); for( i=0; iEstimate( minPointData, sphereParameters ); succeedExact = CompareAndPrint<3>( "Sphere going through four points [c_x,c_y,c_z,r], no noise:\n\t", 3*noiseSigma, trueSphereParameters, sphereParameters, out ); //Algebraic least squares estimate of circle parameters spEstimator->SetLeastSquaresType( itk::SphereParametersEstimator<3>::ALGEBRAIC ); spEstimator->LeastSquaresEstimate( pointData, sphereParameters ); succeedAlgebraic = CompareAndPrint<3>( "Algebraic least squares sphere parameters [c_x,c_y,c_z,r]:\n\t", 3*noiseSigma, trueSphereParameters, sphereParameters, out ); //Geometric least squares estimate of circle parameters spEstimator->SetLeastSquaresType( itk::SphereParametersEstimator<3>::GEOMETRIC ); spEstimator->LeastSquaresEstimate( pointData, sphereParameters ); succeedGeometric = CompareAndPrint<3>( "Geometric least squares sphere parameters [c_x,c_y,c_z,r]:\n\t", 3*noiseSigma, trueSphereParameters, sphereParameters, out ); return ( succeedExact && succeedAlgebraic && succeedGeometric ); } bool Test2D( std::ostream &out ) { typedef itk::Point Point2D; bool succeedExact, succeedAlgebraic, succeedGeometric; double angleStepSize; std::vector trueCircleParameters; Point2D pnt; std::vector pointData, cleanPointData, minPointData; int numSamples = 20; //number of points sampled on circle double noiseSigma = 1.0; //noise is distributed IID ~N(0,noiseSigma) double maxRadius = 50.0; //random circle radius is in the range [0,maxRadius] int i; //1.Create data with noise: randomly select the radius in the range // [0,maxRadius] and create a circle whose center is at the origin with // this radius. Points are sampled uniformly and random noise is added. trueCircleParameters.push_back( 0.0 ); trueCircleParameters.push_back( 0.0 ); //uniform sampling around the circle angleStepSize = 6.283185307179586476925286766559/numSamples; RandomNumberGenerator random; //get random radius trueCircleParameters.push_back( random.uniform(0.0,maxRadius) ); //add 'numSamples' points for(i=0; i circleParameters; itk::SphereParametersEstimator<2>::Pointer cpEstimator = itk::SphereParametersEstimator<2>::New(); cpEstimator->SetDelta( 0.5 ); //The known circle parameters out<<"Known circle parameters [c_x,c_y,r]:\n\t ["<Estimate( minPointData, circleParameters ); succeedExact = CompareAndPrint<2>( "Circle going through three points [c_x,c_y,r], no noise:\n\t", 3*noiseSigma, trueCircleParameters, circleParameters, out ); //Algebraic least squares estimate of circle parameters cpEstimator->SetLeastSquaresType( itk::SphereParametersEstimator<2>::ALGEBRAIC ); cpEstimator->LeastSquaresEstimate( pointData, circleParameters ); succeedAlgebraic = CompareAndPrint<2>( "Algebraic least squares circle parameters [c_x,c_y,r]:\n\t", 3*noiseSigma, trueCircleParameters, circleParameters, out ); //Geometric least squares estimate of circle parameters cpEstimator->SetLeastSquaresType( itk::SphereParametersEstimator<2>::GEOMETRIC ); cpEstimator->LeastSquaresEstimate( pointData, circleParameters ); succeedGeometric = CompareAndPrint<2>( "Geometric least squares circle parameters [c_x,c_y,r]:\n\t", 3*noiseSigma, trueCircleParameters, circleParameters, out ); //clear the data minPointData.clear(); pointData.clear(); //The following data is taken from: // W. Gander, G.H. Golub, R. Strebel, "Least-Squares Fitting of // Circles and Ellipses", BIT, 34, pp. 558-578, 1994. // The circle they got with an algebraic distance is: // (centerX = 5.3794, centerY = 7.2532, r = 3.0370). // The circle they got with a geometric distance is: // (centerX = 4.7398, centerY = 2.9835, r = 4.7142). //The algebaric estimate we obtain is much closer to their geometric //one, as a consequence the improvement between algebraic and //geometric is not as dramatic as in their work. This is due to the //difference between our algebraic formulation and theirs. pnt[0] = 1; pnt[1] = 7; pointData.push_back( pnt ); pnt[0] = 2; pnt[1] = 6; pointData.push_back( pnt ); pnt[0] = 5; pnt[1] = 8; pointData.push_back( pnt ); pnt[0] = 7; pnt[1] = 7; pointData.push_back( pnt ); pnt[0] = 9; pnt[1] = 5; pointData.push_back( pnt ); pnt[0] = 3; pnt[1] = 7; pointData.push_back( pnt ); double sum,err; int numPoints = pointData.size(); out<<"Circle parameters from data found in the paper by Gander et al. :\n\n"; cpEstimator->SetLeastSquaresType( itk::SphereParametersEstimator<2>::ALGEBRAIC ); cpEstimator->LeastSquaresEstimate( pointData, circleParameters ); if( circleParameters.size() == 0 ) { out<<"Algebraic least squares circle parameters [c_x,c_y,r]: "; out<<"DEGENERATE CONFIGURATION\n\n"; } else { sum = 0.0; for( i=0; iSetLeastSquaresType( itk::SphereParametersEstimator<2>::GEOMETRIC ); cpEstimator->LeastSquaresEstimate( pointData, circleParameters ); if( circleParameters.size() == 0 ) { out<<"Geometric least squares circle parameters [c_x,c_y,r]: "; out<<"DEGENERATE CONFIGURATION\n\n"; } else { sum = 0.0; for( i=0; i bool TestnD( std::ostream &out ) { typedef itk::Point PointnD; unsigned int i; unsigned int numPoints = 10*(dimension+1); std::vector< PointnD > data, cleanData; itk::Vector tmp; std::vector trueSphereParameters, sphereParameters; double noiseSigma = 1.0; //noise standard deviation std::ostringstream titleStr; bool succeedExact, succeedAlgebraic, succeedGeometric; typename itk::SphereParametersEstimator::Pointer estimator; estimator = itk::SphereParametersEstimator::New(); estimator->SetDelta( 0.5 ); GenerateData( numPoints, noiseSigma, data, cleanData, trueSphereParameters ); out<<"Known (hyper)sphere parameters [c,r]\n\t [ "; for( i=0; iEstimate( cleanData, sphereParameters ); titleStr<<"Sphere going through "<( titleStr.str(), 3*noiseSigma, trueSphereParameters, sphereParameters, out ); //estimate using algebraic least squares estimator->SetLeastSquaresType( itk::SphereParametersEstimator::ALGEBRAIC ); estimator->LeastSquaresEstimate( data, sphereParameters ); succeedAlgebraic = CompareAndPrint( "Algebraic least squares estimate [c,r]:\n\t", 3*noiseSigma, trueSphereParameters, sphereParameters, out ); //estimate using geometric least squares estimator->SetLeastSquaresType( itk::SphereParametersEstimator::GEOMETRIC ); estimator->LeastSquaresEstimate( data, sphereParameters ); succeedGeometric = CompareAndPrint( "Geometric least squares estimate [c,r]:\n\t", 3*noiseSigma, trueSphereParameters, sphereParameters, out ); return ( succeedExact && succeedAlgebraic && succeedGeometric ); } template void GenerateData( unsigned int numPoints, double noiseStandardDeviation, std::vector< itk::Point > &data, std::vector< itk::Point > &cleanData, std::vector &sphereParameters ) { itk::Vector tmp, noise; itk::Point sphereCenter, randomPoint; double sphereRadius; double coordinateMax = 1000.0; unsigned int i, j; RandomNumberGenerator random; sphereParameters.clear(); //random (hyper) sphere for( i=0; i bool CompareAndPrint( const std::string &title, double threshold, std::vector &knownSphere, std::vector &estimatedSphere, std::ostream &out ) { unsigned int i; out.setf(std::ios_base::fixed, std::ios_base::floatfield); out.precision(2); out< tmp; for( i=0; i threshold || (estimatedSphere[dimension] - knownSphere[dimension]) > threshold ) return false; return true; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/Utility/000077500000000000000000000000001321604176500253625ustar00rootroot00000000000000coin3dSceneViewer.cxx000066400000000000000000000026421321604176500313520ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/Utility#include #include #include #include #include #include #include int main(int argc, char **argv) { if(argc!=2) { std::cout<<"Usage: "<setBackgroundColor(SbColor(1.0,1.0,1.0)); //open the scene file and load it into the data base SoInput in; if(!in.openFile(argv[1])) { std::cerr<<"Error opening input file ("<setSceneGraph(root); viewer->show(); //show window and run the event loop SoWin::show(window); SoWin::mainLoop(); //cleanup and exit delete viewer; root->unref(); return EXIT_SUCCESS; }plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/license.txt000066400000000000000000000030151321604176500261010ustar00rootroot00000000000000Copyright (c) 2010, Ziv Yaniv, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. (3) Neither the name of Georgetown University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/ransac/readme.txt000066400000000000000000000033111321604176500257130ustar00rootroot00000000000000This is the source code for a C++ templated implementation of the RANSAC algorithm. The implementation is multi-threaded. In addition to the RANSAC algorithm the code includes estimators for two parametric entities, n dimensional planes and spheres. Example programs showing the use of the RANSAC algorithm combined with the parameter estimators are also given. Testing programs are only provided for the two parameter estimators. The code is "in the style of ITK". That is, it is very similar to the official ITK style but does not follow all of the required conventions. Manifest: RANSAC.{h,txx} - Multi-threaded implementation of the generic RANSAC algorithm. ParametersEstimator.{h,txx} - Super class of all parameter estimation objects that can be used with the RANSAC algorithm. This is an abstract class that defines an interface. PlaneParametersEstimator.{h,txx} - Estimation code for n-dimensional planes. SphereParametersEstimator.{h,txx} - Estimation code for n-dimensional spheres. Examples/{sphereEstimation.cxx,planeEstimation.cxx} - Example programs combining RANSAC with the parameter estimators. The dimensionality is hard coded (set to 3). The programs work for any dimensionality, just change the DIMENSION constant. For DIMENSION==3 the programs have a side effect of writing two open inventor scene files corresponding to the least squares and RANSAC based estimates. Testing/*.cxx - Tests of the two parameter estimators. Utility/coin3dSceneViewer.cxx - Viewer for open inventor scene files. Requires Coin3D and SoWin libraries (www.coin3d.org) Common/RandomNumberGenerator.h - Wrapper for the vnl random number generator. Used by the testing code and the example code. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/000077500000000000000000000000001321604176500241135ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/CMakeLists.txt000066400000000000000000000002371321604176500266550ustar00rootroot00000000000000project (specfun) # We only need this one file set (SPECFUN_LIBRARY_C_SRC mpbdv.c ) plm_add_static_library (specfun "${SPECFUN_LIBRARY_C_SRC}" "" "" "") plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/errata.pdf000066400000000000000000000353321321604176500260720ustar00rootroot00000000000000%PDF-1.2 %Çì¢ 6 0 obj <> stream xœí]ßsÛ6~×_¹'ù&F‰ßdfò;N/Äil]Úéä%Û‰[ÛI´þ÷ŠXRVå8¾]§3±­®–€Å·‹Å(¤Ò¢¨ÿƒ_Þ]N~Ÿ|wdÅûÏ“WñW£4ÆU”óŸ—í'ÞEüE\LlU)‰~ߺ˜|˜ü$®&¿‹ùßñ“úY‹¿¿»{³øàJ(1;›¢’Æ‹Ýù¿…pNÉ"xa•´VÌ.'oUUŠÙ_“©Ø™ý:9˜‰WsÄÖi=G£M 4"î> :áójí'Í·n±ª¼¶¬ñNeŒNKç›nÕJ9ƒuë]‚R€Y)©K±ÛüˆVêB íJYÌazT#-¤/¼©%f'“éió‘«\°:}ög.vŽˆ}&ö1»ÊÅ YÔºŠ}ún²ÿTõßfÞßÅ\‰’eQ:Õ|¡)¬vÎèúË_8?6_U(Czêuä#‚÷}.vˆ½ÍÅ.·nÖùvͺoóf}É|†÷"öa‰ô6ëDœdÍZ²ŒÜ~B9 õ¿‰g´§š3NV‰ º"LÊËJGŠ(ã`Íâùðï›ÓˆñO?åb bˆ¿&6Œo6̩ٜê5ï3qœ›÷'Èé°w>¬õâiþX¬7¯†=ö½iú^?—[¢kô®tmõKöAx¶êJ–¥ê‚;.¸­Ž†±€{úã0‹°Ì{D ñëÈêÓ—â0Ÿ\Ø,¼\ãéöºŠñòœÛãçóÆ1°eœÏÌéñƒL adÌm!bÛF¬_Äóþ¨‡­‰”6e½Ž£cšà`Q:”)Â9Æ= ×´›m¢ósÎUVZ£*ceKfÿþƒ°|,Ž©Cæ5Ä2‹¡Q,4r"wOK¡Ý®u¶!-Pœ‹1Úbè°››Ä.b£Ø(6Šbÿb“sˆ:ƒÈê•<×tw—¶W÷¥“–S4âËøËb4ò"Ÿ­Ï‘ÙŠ¬9¾GÄ~ÉÅ^Ò7KA+KeKÚË‹„¹K.ø¼¿5qìÎË0ß`PõdE;›“@wkï'Y‡÷¦æ_ Ó$Q†¦æxÖ|a1ëò™ij;  =¸¸ïvD»×÷i©7¥êi02hd÷ŸÒ²HÌ_J«•æá­ÚtÊÿ|ú9dúá±Ëêü£ÝÅ®¦å¦‘ð8S¸PHÅi׺TçBÆa2&̽Á‡%ŽUð‘@ß]ðQˆÆà#õ:ƒàÒ>)«à8ú΂ÓïæÁÇ!ñÙÆÎWF–vCå„9s‚œÉ’Õ¤IjvprÞêø#š™å0R]Ø¢ó!ı³ [è.lY—\±ù7Ó\N!r6+±"{³C»ËâR{]ô  ‹‰ÕùÇŒsÀFÜÜCd»aÑ r{èUW ê¨[·j]xé<¯…-`—^é8Øeç¯oÅ.ŸäÞwúqæ{ˆ3?Î9ºTüÑ×xô…2WøÑ7CôID²ô”ˆ:déù•S"ŸÉ”ðÖJN«×·òâ˜c„¬f¹ØëatLtOz‚Sý4`îb$SHuØYÅ6 ô-Ç6È&úcd2í ›šXVù‘ûn º\n`ä5CÄn5òjzŽ®X­›P-ºê†tNR %ÎÇà „ʶ½–þR|Û_ɺ!uˆ”±¯{­‰îtaÇ•œ þi}bG'ÈØž þâ!í6º¸´^[½O¶/¤æ¶¢N˜Y…¨ 3«lãn_HéS‚!±Û>ZQ"^^Ùb}üR¤s `~„ÑȱÓy›–j¿–ÔѵŒú5 ʼní‚aw `fÅv 3+¶ÛÀع<«‰"uQÅ-0Ûm0ÉS„qÕøÒaÀ8Ï}‹¯l· å ±C %¢¯@Ô!¯l´ …] t›ïñxDáÈy>ÿFĨWj6£·´ro‰\… Ñó|Úö/‘k‘ö–Ȥë©FjÐ F%r€™UôäʳDŽn‡:WÌ»sÛÝL´¢«!#Ιô+ú:¤}}&ï«Ý¨VôA¹UôUe4fëÝ„™Õz7afå±À6ÆŠ¾ûPÑ—F“[‰Œ­g7³Œ`æÄP€™Cµ¶1VôÝ·Š>Zvtã?n‡fVt•0³¢+°±¢/×G´œÆŒ[.ßš f ;ÀÜ[ч¥V-ñö0ªèÌ÷¾¢¹È‰¸±ªèkùçWôA™UôÙú’Tn+ê„™Uˆš0³ QÁ6ÆŠ¾±¢µ n}Öë壇ïä´ýQǨcÔ1êuŒ:îL]çk*ˤ´¬ Æ"ïU}c‘7f(ìÃu™sù튼ù¼) =ÁélTÀÜ{!½G†%oùÂïiWøœÅŽJ•À AŒ ¿3«”.ÏÂïAg£š\¡G'!ú•ÔR¨¤vH7#g£b1ÑJjh#³Jj[–ËgÎsØUI˜Yíª$̬\ØÆXIÝSIÝoÒ½…+#‰Öx·H™MºB±;W0sâNÀ̉;[Ûk¼o„n7 -;ºR†Ý!Ó€™]%̬è lc¬ñÎõMØ Jåÿ´3kendstream endobj 7 0 obj 2900 endobj 15 0 obj <> stream xœí]ßoÔ8~Ï_áÇ-´Æ¿ õØVªJ -+Áotw¢HœNºÿœlêo“¶*=ÏR!ØÝ0;ùì™|=^Á¥b¢ý“Þ|¹®~Vá¯Všk­™õúõº¿â¬á û^™¦‘^Ißú^ýQ}d?ªŸlý9\io²ùþË5{½ª^\ÊšI¶úV ÖpíØÁú_Á¬•\xÇŒäÆ°Õu6µÒ««Û[ýU­ØÅ²±J­á(Ý" ‡+^E€Nn½Ò}ëA ËÆ1oêðB Ò*n]×±JJ«QÇ>¶/(‘0KÉUͺ—ðQ®„¼¡æFIE³4š«Á!wÂéV`uU-DwÉ6Ö¯éÂÛã4ï<¼áÁ- (_óî¡|•Ûà°Á?¹Ø×\LpÑ ¨&èþR„²ý¬×]ò7ûÞ~CòZÔVF%‚{ýÈîÕjFY«U«x¬÷+S^ßøÚýhoán¤½æ^un$¤Š‚™ZÅgøÑ°íÕ æ“Ü˲ÛhEÓµqÓ» 6t¼QƆˆ¹ÂКæžJ¥çFˆæþ±E.½y‰m¤?Öáo¡ÄÎ)©õ¼’H$Ë™[ß9Þ1ËNÚïÄ[,óÛ.d~Ÿ}@b*oÓÂnSW®g¸@z’Û©†×51¶‹˜I±]ÄLŠí’o ¶ËÂS˺(R‰ÖÀlAl‰IŽã¼É‰éó0Î Ð÷y(<Ì  }¨[nQW®£Ø&8uë(Ð$â6*tùù-Îò(üˆÂ—¹Ø;/»ÙÞvÖ /á9.{Þ!¹fKî£`ìÖq¿ÎÉ6EÖH ¾[‰ŽfK¢£Üþ×Îj%’KtúIIC¾ÌCûoóAMbPÇ:‘«[nSW®­÷„f0Ör­fñWÀë>äbØñmåöDxüº)¨áµ4uÙsŒˆyØk:™ç„ÔÀAûùí‚ÙÃ\L1°pðˆäbç@l•‹¥9ÚHn4q+<úŽÐNp¹öšÅAéHS ‚¨5M…Göx‘Ë) ö<{ƒ¬»Wviè̤æ>H»ûó߇;f:•ÑÇ;› €G Ô­€ºðD(À:÷L”NÖ‹ö ð$á$ÿó\ßàñ¦tpÒsWŠ™]ÞËúGÌC¤hr⪠ÇN*RŒ w+dòPáNC*”ˆe—÷µÄ6RÛ×RË€“çG̤Vz#fR+½É7úÇ6ŸŸOòê1ëâï1±¢­~Pñ"(ç®`+L6°|ÞcŸò‘ezåv;˜îÜ _—¥¦{£Õ]FjCˆÉðc²ˆ™“E̤˜,ùÆý™¬ì†Y¡ânùùÝ*¼y¨ì¨ã¹:õ˜4,Ž–¥–DPÂqëuáíuÙ=Aiá-aÒ):ïoÌÒÞBÕD óneXt>p9ÞÂ݈T5QÏÄ;œuIm$–uQ²á†XÖ%a¦4WI˜)ÍUzßxª&ꪉò‘c¦âàôÞsˆ}0‡(tµ8¹ µÝõJ·&–¦I˜IQ_ÄLŠú’oì&õ½ŒsfpNÁæ–¹r£±Ârí½±¤Ð/R'ópü@;^žc>FB;hžM:Q¯nΉ¶í 9-uMêng%·”âzcx㈠n3©Á-b&5¸%ßè§ãyjm2¥´Q(›eÄ J‡û+O¾ &…hŸh±ÃR´Tù1{¤ÃZа´Ü¹a)v· ¯”–d¬'wvMÂ<,DÈŒ-añ€)¼=”""æÝZˆùB81¯p7¢µ‘øç©˜fp2 © `b"G-Ñ1S¬fè±SªfH wkˆ£SÍúŸR5CO,»¼®ÛHm]½·¥–‹˜Iåß"fRù·äOÕ ¿Q5C²:µjÕ¸ñù5˜,b&Åd3)&K¾AŽÉP¥?:b`°M€h Ahœž€©¶\‹S+Ð!|f¦à„Ê÷/x_vOP*H˜'sð˜¥Ð§¨o¡|¼[ ƒ/4ážúHPLv™èGÖÍ>;A}Æ>ä‚K ‰Vêši?˜´•GwHá©{„‹ãüQx â—‡½uŽVn¿·;/ ¡ÙZˆÍÆ¿—ðëãœwe÷©8'b¾sœ£ o¥8'bþ=âœÛXæ¦ãI°6åîò«èŒÎr}VÈ@?… ÿK¿“ ´á³¿2rüåm.†æ«²›MèWFäÉ3 =Œ¼ÇNiSF=ÄÛâß>y»¡ó ͨÁéáèlóO¹Ø>ã9Š)÷s1´ÍôÂfs1ÄÀéúÅ=oÒ9]»ÇÜÇwwèÉŠÁMÖÀ¥GO® |úös}hã¤êЂŒÊÕÝö :ð{’¨CÁN Ô•îýN‡ sÑÎUè¦@endstream endobj 16 0 obj 1850 endobj 23 0 obj <> stream xœí][w¹~Ÿ_Ño;dq£k«ûab09${ çòÀš›_0Y¯O÷´Ô—Ñ×—ÁØ®Ÿ= f(4ŸªJuSI©T‰¨þ ?ž,Þ/ž”ÿk¥S­u"E¾þý¤ù$³B”?$Ç S2…Ÿ„u¼x·øGrºxŸ¬ÿ\~R}I÷çÓdwµ¸³¯²D&«7 ‘©Î’õ¯"±V¦Âe‰‘©1ÉêdQ"-r'ódõÇb™ÜZý{±·Jž¬!«ÔŽÒÒrû‰S`&?©ÿÕ7,‹,q&¯/5iV¥6««¤´1öÊu!˜¥LË?ìÔ¿•&UB&Úéjw÷*¤"ÍD¦+ŠÕ«ÅòCý‘-¬3ªÿY—ì% ;ÈvD*„QÖj•¬ËO'´Yc”H¨¨¦¡ Ú"•YZ(™(gS‘oâ>\ó_VÖëY¼X&w«‰È4¹•^lg@”'±ÄdŸb²s@örÙQL†°&gÑ$6­?í7ÉAý\árןN÷Ë^ƒ/;ŒÉŽæÍð8¹+`Øé¼o½Ã:dÚö1©Á)¡d {q‹¶–[Y¤Â0ZªHó\¶î·§¥„qU*K÷ò×yàíÀš¢;Å,÷<+-†,Ä"NÕXŽç§C@F\TÒ9¿ú¥I–Yi“¥ µIÿ@|Ú¹ð¦£ü£¤æ +[º™ZÁ–w[)8$ , „jûEo¸Ãx¸s0Üî wJœ·¹Nb亭MµêºÀxayCvCvCöÝ“¶XÂù–Ç®ŒLº˜Ì¡áìÍpãÃÑUûLº4ç”c—™§êÖ–ŸcUÿ<¯æsD{Ьrl¹Í±ø=RcK¦K’¯“¬®¿u‹ƒ·ã¯ÊQq^Ž8Z >IÎëq»…àw¨(ìÆ„(#‹ÿ°dy“QÝ𪠅M‹µ.蚣ô·­;ü3f¸$Ž=©ìD0”‘fi^ïS> ‚tüí¬­piV’V;~5C˜C uyý‹å<ƒRoZôéþE{–¦´(j­6Eªd!-‹Ò©ŽuLJY’Ö«ŠÔ÷_V´Z½@xJÖôjh„‘fÒ¯ËÚEnðž¸U)5‚W‰5—%ίȀþK{>¥å¦Nw2©œã ƒËOwTœÆhâ<)D4É’7LÖRöïÇr¼ äx“=d‰O›Õv£Ý ¨îos7öô]ai¸ê–ωKÊšÂgLLœT¡KkÞuR:^1TcJÝÚ ¸cjxÀ—ïdäF«e:9ŠŠ`£ßpš<Œýèù ˜Ìó˜Œê¢öòRV¦Y^+Y.MN»3ǃn]å½í´çñ¶Úc“q õ y¹ÛÉ£XÉöisÝ”ùm­*d“Á€´4ùVµÉ e¤e¸vN65¥~˯ýÜ‹£Ÿ+^€6^€³”+øzË„©'±‰·”ÈR›ñŒ·v6ñVL.Þ²7ñÖ˜¼XÅ[ôâ-½öˆä¯?|¼ÕØQòñVƒ”|¼Õ"eo5Né"ñÖ·^€ß_¼ØÌ.Þ’Ejz›04!ÑÆÎ'Þò€Ûx 59hà©Ò&ž¯#s1ÕMä†e… ~•fJÓ¶¹tòØybkÏ21o´y_:jɳ¤Öо)¾ l>d¯c2t næqÐLˆF£®Ü&Ï}‡aÅg£2ÊÝ (:Šæ¦íÖ@½m¬ÞcÃÙx¸ÍÝ0M5’ <¬ºØ„ Z•ao7TÈù„ ;ŸPÁþºÒ áùdÚwâú¦bÔu;DûEš©…~²™v4ÄRÛV@šºÜÜL°©Ëuåø¨í£X»wisQeÖWôyÐMDŠ\ΰ´C‘ãuŽª«<÷P’­¿ †‹}ºyåÀMEëÝÏó‚z0Õí/äªvaŠAµ,Ä mp»mJÄ+é°\(¶Ý$^©šE Aƒ•‚C+ÔñšñÒx<Ø#|?ƒá@€†#¾2ŠÜLb~cÒ¢»›W핊æ&t–ŽüuAs[1Ú22ëZc®÷…=Ãc2TZÅdæE~OÙmÁµûl¢AºõrÊ}t?sa“~°1ñû±'ØcËÓI_¾ÜD\fe–iÝPª¬[ßÝÈʃx̬<ˆÇL.ÃCm8È]Ä]!Ð]ܧÍþöö‚þe4A?ÐÕ‡ÔhÍÀ&Àâ*ÃkÀ•Ìž:cÀº-hχӡ̀ùŠÚ6 3 ×áú ª%÷€´ÙPÔrê³ð Û¬ù3q ¶üzåÏçÊÒÞ‚ô ;µÐ/Ä‘*ÅêõUÚ/=uØÁ2r¦~>¬œ©Ç|ùÎtë­Óƒxët€<‹ñ>Ú­¢Ë¥×¬'ò~Çcný΃í”á~ÓV×=J2à?AîÆd3w;÷Ý™ÃMQ´Ûù0&Ûd S‘†ÁÑU^ ~tÇïwÔ{Öè´~k à6Vp‡¤Ž\ ·@uÒ] º(¥uncö§Ön w† s›¸ý£™ZoÀ?÷âñ~ãP_IYÁë Udýw8”¿=fVåoùjËßè<éhP÷8YEAÝÖgÝ딀® J÷g 8Oõ ¯ºÞS°ùùMT‡¸¢pÛËÔ¢r>ùzâS¢]ña>œòõ€ùòóu¢íæ šâ7ƒZbÝfÌŸ'µ1ÙG@E§ÏFíëÛd/®·¼ßNºÍ{ N0>Â6qѸƒƒKië§žà€¹“ë™»'mýG øýnâ26âþÁZ±ž6J|Á¬Q70Õ¼²™"§Mø2vê¿+Ë © ˜¯ã®!ª]á OÝ40oÔ¾ íÝü_}©”z½ãZ«ÛˆÀâ§u¡—UîÑ=èdmj˜Ró˜Gù7Ô÷tèͪ7¤P±Û½nêšm•óM0nÚl×ûB]­­qÃ%F‚°«“ b¢hQóB5ÿõóaU´ð˜ 6ÄEÅpGKxšãœ6¯•2¾¸(Åú¾ ÒFU(8$¾ï´M «×¯¶yÇI¥ÇqÃq©«"ÂÌx"0‡t!+ÂSP¿Äºq ÃŒò¢]’äBzªìCzQv>£¢ípQVÏž3Cê sÿÊVwU³õ%imÎê=mªþô‰û*£hÖχU4ë1_K)¼‘Œ®¸¤bíX§DxæQªT0‘wœ>…ÐëX¹Æñ6 ûmÈAÈš×`¦Êï¨×5ý®æ€¹ð€óò°5±+g $hcA;$iÿÑNHk.R…z@Õ‘j†V¸ri‘1yG&€þŠÃ+d=D˜’묂 ii_eçú·é«(P¤[Ny@³×Ë92Õ3gÌê(¦üaò!MTö&Zãóá´Ÿ0¿¯‰6µf†ñ3_|)ølT7,ãtïcÝF@ &Abò»3“žv.‚¬d•dh²ê ÈΦÍÊßyÐ7ùP—Ìü)ÒœYÏTÀLÐ? >Q²þÁ³‘—ð ´|(L›•ð oò¡.3˜ù‡Lm<’63"ú®K˜«|Èc¾üÞªk'0€SoK=ÞÛ‚\8=„‚@Æ*üü)H7>4°9;srDd  ‰ºhµeNTñÌп=?€þŠö¢nZ¡ûRlq3 G]ÔÕ™aEúýÊ©óO:\—|At»yÙŠ .ïr†¾sIëlj¦êú¨©“hoY˜«8Öcþaûm@þ±ßióØï–5L²~ª¼á ˆtv¸‰^øx¢tîHQNÙ Åa͵YÈ*»X£ ö¯“Wµp§îUˆŽUš—Ûßùy>Èì žÅ㢤jf Ð Ú]?jߺwA…ãY:œ‚ñ~ÃÁA¡ à›:õ1^×ïÀ—Å_ö €?ŽÁJüUò[,¡×´×^V½ËèüWõÄ'·‡þfNýÌ­mþ[tƒñï󬸲ì½íŒt³çéÿ!# \Ni}ßÄ„g€„hþà-¡?Ù°^§±õz;åô‚í=㽤­¶Úœ`tBÅ Ù½Ž… ˜9Y¨€ùÒž"]½È:绯äùS*cô‚¾áüß§Ú@ƒv|Z–#ËQálË÷Kç¼ bÒËÒ¾Âîä§hp\ËÔ`> stream xœí]Mã6½ûWèèÁlsÄoêK‚,à …½Ì%é$Ènº'Kvì_É&eÙ|–(Û®òA¦»ré‘E¾*²ŠT-¤ªêî¿ôËãóêÕ÷íÿZi¡µ®d¶?ŸûOœ­ëö—êiešF øIúÖÓê×Õ?«O«?ªíßí'ÝC†¿?>W_oVïþ¡M%«Í/«ºj„vÕÃöߺ²VŠÚ»ÊHaLµy^µH›àe¨6ÿY­«7›¯¾ÝTßo!«ÔŽÒÒòþ¯"@'O~²ûÖE ËÆUÞ„ðÚi•°n×±JJ«QÇ^},¸„YJ¡Bõ°ûÑþY¡j¹ A% ÌÒh¡:ÌÒ £eó6NÄÁQ×NÕ ºº®û¬ßü´zè$Œ²V«¡„m¬7j'2Ôñ¸ý‚ìþÖ[ùzû…öñµ’:—?÷™ëëìkëȹqí«C¸ßTrØ7>ø¨DäÏÒàY!³@L—‰Ù\Lå9Ó>‡ýí :Ü¢× ÇãG>WŸu±ï⤽.Ò~`Є֔©3@£=u]ûSªSs— néD£˜Q{ÄÌŠÚ#æëQ»¼1µ›qí€ÚMµ;ð,•‹ &s1Äê\ øIrÔnsõY»2jÚ%àb Ъ2u¨ ´§.;jWµG̬¨=b¾µƒ@óªÔž‡È—‰ÚQœ»ÈÙ àì¢õ‹¨ÂçFí:×^.v­êd™:O{ê²£v£ÚþeFí3+j˜¯GíúÆÔž‡ÈSÔn‹¨]‚g uþ¾ îP»ÊÕg]ì˨ݗq±h=PruhCFÑžºì¨ÝZ¡¹mÈD̬¨=b¾µ›S{¾­q™¨…ã`½P í܃5èLrÔ¶LÎÚm®íµ£¨=”©CžBÒžºì¨Ý…öfÔ1³¢öˆùzÔn¯Híhc;‘/µ£gÎF;-`K¾Ì)]0j§;4m­Ä®Nedœè£Q0¤ëèºÉÙtÔ¶Ã ìº:ÔÁÊÃa0µY¯ò‡ÁUð‹ÀÕ ×µ§š ˆöcçz‚lq2s=3+×1_Ïõ¸»?®ýìUr æ¦ÌB¹U؃Ìîªhoríêë2u 'M¶‚'N]vÔÞh 3j˜YQ{Ä|=jðU©=§Û)jŸ(/9Ô;ÅÙe µçN ùIrÔâ쬋›2j/ÌX€Uðu qA¶‚'N]nÔ®j'¬ãEí 3'jO˜¯GíáÆÔ>¿8s"¤¡âHbA¥9…ÔN.Í[g]¬Ë¨]åÚÑM ÐZ ®°8³¦=uÙQ»l„a¶!“0³¢öˆùzÔÞܘÚó÷)jŸ(/9tSd\¸oSHí Šµ—gNìyœB2(ÍëÊÀ¢2~¢2iê²£v­„b¶!“0³¢öˆ¹œÚQâ(—_óxl٥˄éh$lå£Zœ²hžC˜^RY¦»\{éæ:*Ùuû¨ˆh5fš«ì¸ÜÑpÛ‰˜YqyÄ<ƒËÁV.GgTç_up~e=`_DÒ ./<‚EîÐ`Û’« +ëO‘/݉d}Ý}Ð]„3µ9tøÑ°ÝÇU9ZÓn4;ïb=»ËfVÞ%bžá]@:ïR½_¦ ypÖ‰Eáµ<äÊp@½¼ÎÕŸ»ë|ª›å° §p¥ÐО«ì¸¼u¸n¸ëƒ¢+4þ‰²HíqR„m{Zê”Ê{6è}Óz“Ûà`ƒs±§™àç4Û‡µÔ(è.¬uüv«Öíûm¤ ´ý탘*º/pž]Ø=—x‚:&ƒ*@¯¤Í6Q$vØ“‚nOÖS‡L©ý<¹`8Jõ`þÞC÷g¯(Š»gä–¸‹ÁÂǨ9™a§Ï¹=£Ü2Gw “ókÎYQŸtlq‡ö±ÜvÕ#æý¾‡ì@k˜û¸gý»Ãà±EìâbÈåb©³‹º/U]VuM#jÃÈë6ŽÝÍB 3+¯1ï½.¸ä,B ò t«k+µ1#•ª šgØÞ}¾Xáqˆ™'4d%vKŸ‰|ÎÜq'ˆ»– bš€ú¸3Ê‹f›},½ÕPGçk@:í;±¹IÎYRË—×Óð0‹˜xÖñ©ó=ˆî²¶>^ÅU„¡;Ý¿ðè¬C¸iÞP3Ã4-Þ‰¤SÃt)de¸ÆI?•¬âj-»·¡qµKWlv²0·alˆ·’±4Œ—#†¡‡[×Ýþ¯õxÂL«Â‚p?5>•Ö}üH»A¬ê>zÐKÝ KÝÇë˜|©ûXê>–º/¤î#ù5num”Îît 3§ T¼Ô},b·cTl°¨#£Ž.«r«ûÐÚn/ L˜Yy݈ùê>æ+…§1 ·Ÿ@uJM¾ºh‡W³¥I,e8õVŠÓMݾ…G^Ñ!=ôÞX Vx2$öA'Ž‹Y·Ì¹.ÈÅç½8;?¶¶¤;ɦâ{è÷—Šï›Æ2ߣ¿¿T|jÏT|þîRñ}ËX¦â{ô÷—Šï›Æ2ߣ疊7]šöŒËˆ^·—ÚÃéò†„™ViÁô* ø`áGô>‡ÔëJ™¶ŽzÛ †Ê’×'tÉ뿎ɗ¼þ’×ç›×§ë:\çïÎY:;÷Äe¶Ù¨Ö¤äV{ຠQ™eA"fVYˆy©=XÄn/Æ(Ὠ#£Ž.«²«=ðZp{ï|ÂÌÊëFÌ·¨= Ûƒ«¨Îëi“¶û ߪYx9¨À(ÔæX>¨^ëRŠÝgt FÿÞ‰=ÒþÞ 0P×1T*Š] ¢²—ŒŒ­™/ 9Í^³wBà{´Åè³îY­uñ «ôdBß¿å~òÆ©iAÇ”KÃtÇeïÒ.NÖ‰…ÚåìÝR†Ñ!îc²4Œ•1½?Ã8+Øz×®ÃNÛ… î`[·Ál1ßiÁÕ‹ b¯ó*I —‚*@—‚‘×1ùR0²Œð-™m§/ü"ˆèרc4mxÌ­#bf•Š˜—bŒEìöbŒ*n£Ž.”œß;ÙHØ Ï8©#l*f%"¦ó£ÌJDfN±@Â|ûë)Ð[1À2ý²ïØ@be·:5Ù½Úõç,ÜÑ[ÖÑëD ï¹u ¨ã@êÝ’›á°Év^“'kçg,èЋÓÅø³F?«C‰ xfñ{ô÷—Åï›Æ2‹ß£¿»,~jÏ,~þþ²ø}ÓXfñ{ô÷—Åï›Æ1‹ßƒg–Å7í?x¯2ºÆ_zÚíátE¼¯Jø¸Î€j€­Ð²¢PÌçbßï²þe]ݾ҆ƒµiåÖÎ?껺Œ‡í¿•5Âx]i›†ãsZú´|ýDº²ín¡;%ôûoûÿâà¾cçÝg/DÚsjÌxw’Á\¦>quãâJLv+dül¥‹Û¤´'®UJÄá2˜¹Îs˜¹VË„ý`ÎÜ´/ó‘öœ5ƦÐj8yOܱ~¤>smž{FµíÛuÞn ÝVnÄ|ëÜAMvº¥.cáFÐÔ#\­„lxF¸:£ï*ÂMcæ^"ÜÔNnÄL>—e„gîE¸iÔÜK„›ÚÃ-Â5õD„‹îf áÆö°Šp#æ}„û”Ûà_ÀŸæ•|ü ÞH2Zq`«¿—Õž|}"„¦Û×ûód­‡U²!}ž,Þ‡ÆòìòUÙB ”9½bßåb€8™¨ý0ÁÚÚ\nB5—˜vWãï2ÔïO-\ìñ.—Cw÷¼Ížáb§ jG¶J˜–òh/#æAˆ= €FM…Ǩ{›«û¨ûÔm€º@p °R¹u Ñ¿Göx“Ûã]ápy›ë;ŽÔ¿¡N]Ìéò$‚¸]w»Ü0RõÄèNM»=¬"õˆùõ#uªË«Ô]Åènƒªý¥m«íÃç?s«ý¬Œ[xš‡ËÅ^€ØË‰‡ÒíW#`s”&b„Rçø{o%üÃÑàÑp£Fh]è q»ÛŽ¬Ù¸Oo… îe±´ÛÃÊ}FÌóS¹àbâüVÏRÂ&­¦.c•Ê ÷÷/â@­ŽQáL=paÿ%Ž´O¹1ñ¡W_1v âÿ-¤:¿endstream endobj 32 0 obj 3170 endobj 5 0 obj <> /Contents 6 0 R >> endobj 14 0 obj <> /Contents 15 0 R >> endobj 22 0 obj <> /Contents 23 0 R >> endobj 30 0 obj <> /Contents 31 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 5 0 R 14 0 R 22 0 R 30 0 R ] /Count 4 >> endobj 1 0 obj <> endobj 4 0 obj <> endobj 12 0 obj <> endobj 13 0 obj <> endobj 21 0 obj <> endobj 29 0 obj <> endobj 37 0 obj <> endobj 34 0 obj <> endobj 26 0 obj <> endobj 20 0 obj <> endobj 35 0 obj <> endobj 33 0 obj <> endobj 27 0 obj <> endobj 25 0 obj <> endobj 19 0 obj <> endobj 17 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 36 0 obj <> endobj 28 0 obj <> endobj 38 0 obj <> endobj 11 0 obj <> endobj 18 0 obj <> endobj 2 0 obj <>endobj xref 0 39 0000000000 65535 f 0000012604 00000 n 0000014048 00000 n 0000012524 00000 n 0000012652 00000 n 0000011928 00000 n 0000000015 00000 n 0000002985 00000 n 0000013546 00000 n 0000013607 00000 n 0000013488 00000 n 0000013902 00000 n 0000012707 00000 n 0000012737 00000 n 0000012089 00000 n 0000003005 00000 n 0000004927 00000 n 0000013426 00000 n 0000013973 00000 n 0000013368 00000 n 0000013057 00000 n 0000012778 00000 n 0000012234 00000 n 0000004948 00000 n 0000008644 00000 n 0000013306 00000 n 0000012982 00000 n 0000013248 00000 n 0000013751 00000 n 0000012821 00000 n 0000012379 00000 n 0000008665 00000 n 0000011907 00000 n 0000013186 00000 n 0000012907 00000 n 0000013128 00000 n 0000013680 00000 n 0000012864 00000 n 0000013838 00000 n trailer << /Size 39 /Root 1 0 R /Info 2 0 R >> startxref 14207 %%EOF plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/license.txt000077500000000000000000000002631321604176500263020ustar00rootroot00000000000000The special functions fortran library may be distributed according to the 3-clause BSD licence, as per personal e-mail communication with Dr. Jian-Ming Jin. -Greg Sharp, 2012. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mairya.for000077500000000000000000000201361321604176500261120ustar00rootroot00000000000000 PROGRAM MAIRYA C C ============================================================ C Purpose: This program computes Airy functions and their C derivatives using subroutine AIRYA C Input: x --- Argument of Airy function C Output: AI --- Ai(x) C BI --- Bi(x) C AD --- Ai'(x) C BD --- Bi'(x) C Example: C C x Ai(x) Bi(x) Ai'(x) Bi'(x) C ---------------------------------------------------------------- C 0 .35502805D+00 .61492663D+00 -.25881940D+00 .44828836D+00 C 10 .11047533D-09 .45564115D+09 -.35206337D-09 .14292361D+10 C 20 .16916729D-26 .21037650D+26 -.75863916D-26 .93818393D+26 C 30 .32082176D-48 .90572885D+47 -.17598766D-47 .49533045D+48 C C x Ai(-x) Bi(-x) Ai'(-x) Bi'(-x) C ---------------------------------------------------------------- C 0 .35502805 .61492663 -.25881940 .44828836 C 10 .04024124 -.31467983 .99626504 .11941411 C 20 -.17640613 -.20013931 .89286286 -.79142903 C 30 -.08796819 -.22444694 1.22862060 -.48369473 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X CALL AIRYA(X,AI,BI,AD,BD) WRITE(*,30) WRITE(*,40) WRITE(*,10)X,AI,BI,AD,BD WRITE(*,*) CALL AIRYA(-X,AI,BI,AD,BD) WRITE(*,50) WRITE(*,40) WRITE(*,20)X,AI,BI,AD,BD 10 FORMAT(1X,F5.1,4D16.8) 20 FORMAT(1X,F5.1,4D16.8) 30 FORMAT(4X,'x',8X,'Ai(x)',11X,'Bi(x)',11X,'Ai''(x)', & 10X,'Bi''(x)') 40 FORMAT(2X,'----------------------------------', & '-----------------------------------') 50 FORMAT(4X,'x',8X,'Ai(-x)',10X,'Bi(-x)',10X, & 'Ai''(-x)',9X,'Bi''(-x)') END SUBROUTINE AIRYA(X,AI,BI,AD,BD) C C ====================================================== C Purpose: Compute Airy functions and their derivatives C Input: x --- Argument of Airy function C Output: AI --- Ai(x) C BI --- Bi(x) C AD --- Ai'(x) C BD --- Bi'(x) C Routine called: C AJYIK for computing Jv(x), Yv(x), Iv(x) and C Kv(x) with v=1/3 and 2/3 C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) XA=DABS(X) PIR=0.318309886183891D0 C1=0.355028053887817D0 C2=0.258819403792807D0 SR3=1.732050807568877D0 Z=XA**1.5/1.5D0 XQ=DSQRT(XA) CALL AJYIK(Z,VJ1,VJ2,VY1,VY2,VI1,VI2,VK1,VK2) IF (X.EQ.0.0D0) THEN AI=C1 BI=SR3*C1 AD=-C2 BD=SR3*C2 ELSE IF (X.GT.0.0D0) THEN AI=PIR*XQ/SR3*VK1 BI=XQ*(PIR*VK1+2.0D0/SR3*VI1) AD=-XA/SR3*PIR*VK2 BD=XA*(PIR*VK2+2.0D0/SR3*VI2) ELSE AI=0.5D0*XQ*(VJ1-VY1/SR3) BI=-0.5D0*XQ*(VJ1/SR3+VY1) AD=0.5D0*XA*(VJ2+VY2/SR3) BD=0.5D0*XA*(VJ2/SR3-VY2) ENDIF RETURN END SUBROUTINE AJYIK(X,VJ1,VJ2,VY1,VY2,VI1,VI2,VK1,VK2) C C ======================================================= C Purpose: Compute Bessel functions Jv(x) and Yv(x), C and modified Bessel functions Iv(x) and C Kv(x), and their derivatives with v=1/3,2/3 C Input : x --- Argument of Jv(x),Yv(x),Iv(x) and C Kv(x) ( x ò 0 ) C Output: VJ1 --- J1/3(x) C VJ2 --- J2/3(x) C VY1 --- Y1/3(x) C VY2 --- Y2/3(x) C VI1 --- I1/3(x) C VI2 --- I2/3(x) C VK1 --- K1/3(x) C VK2 --- K2/3(x) C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (X.EQ.0.0D0) THEN VJ1=0.0D0 VJ2=0.0D0 VY1=-1.0D+300 VY2=1.0D+300 VI1=0.0D0 VI2=0.0D0 VK1=-1.0D+300 VK2=-1.0D+300 RETURN ENDIF PI=3.141592653589793D0 RP2=.63661977236758D0 GP1=.892979511569249D0 GP2=.902745292950934D0 GN1=1.3541179394264D0 GN2=2.678938534707747D0 VV0=0.444444444444444D0 UU0=1.1547005383793D0 X2=X*X K0=12 IF (X.GE.35.0) K0=10 IF (X.GE.50.0) K0=8 IF (X.LE.12.0) THEN DO 25 L=1,2 VL=L/3.0D0 VJL=1.0D0 R=1.0D0 DO 15 K=1,40 R=-0.25D0*R*X2/(K*(K+VL)) VJL=VJL+R IF (DABS(R).LT.1.0D-15) GO TO 20 15 CONTINUE 20 A0=(0.5D0*X)**VL IF (L.EQ.1) VJ1=A0/GP1*VJL IF (L.EQ.2) VJ2=A0/GP2*VJL 25 CONTINUE ELSE DO 40 L=1,2 VV=VV0*L*L PX=1.0D0 RP=1.0D0 DO 30 K=1,K0 RP=-0.78125D-2*RP*(VV-(4.0*K-3.0)**2.0)*(VV- & (4.0*K-1.0)**2.0)/(K*(2.0*K-1.0)*X2) 30 PX=PX+RP QX=1.0D0 RQ=1.0D0 DO 35 K=1,K0 RQ=-0.78125D-2*RQ*(VV-(4.0*K-1.0)**2.0)*(VV- & (4.0*K+1.0)**2.0)/(K*(2.0*K+1.0)*X2) 35 QX=QX+RQ QX=0.125D0*(VV-1.0)*QX/X XK=X-(0.5D0*L/3.0D0+0.25D0)*PI A0=DSQRT(RP2/X) CK=DCOS(XK) SK=DSIN(XK) IF (L.EQ.1) THEN VJ1=A0*(PX*CK-QX*SK) VY1=A0*(PX*SK+QX*CK) ELSE IF (L.EQ.2) THEN VJ2=A0*(PX*CK-QX*SK) VY2=A0*(PX*SK+QX*CK) ENDIF 40 CONTINUE ENDIF IF (X.LE.12.0D0) THEN DO 55 L=1,2 VL=L/3.0D0 VJL=1.0D0 R=1.0D0 DO 45 K=1,40 R=-0.25D0*R*X2/(K*(K-VL)) VJL=VJL+R IF (DABS(R).LT.1.0D-15) GO TO 50 45 CONTINUE 50 B0=(2.0D0/X)**VL IF (L.EQ.1) UJ1=B0*VJL/GN1 IF (L.EQ.2) UJ2=B0*VJL/GN2 55 CONTINUE PV1=PI/3.0D0 PV2=PI/1.5D0 VY1=UU0*(VJ1*DCOS(PV1)-UJ1) VY2=UU0*(VJ2*DCOS(PV2)-UJ2) ENDIF IF (X.LE.18.0) THEN DO 70 L=1,2 VL=L/3.0D0 VIL=1.0D0 R=1.0D0 DO 60 K=1,40 R=0.25D0*R*X2/(K*(K+VL)) VIL=VIL+R IF (DABS(R).LT.1.0D-15) GO TO 65 60 CONTINUE 65 A0=(0.5D0*X)**VL IF (L.EQ.1) VI1=A0/GP1*VIL IF (L.EQ.2) VI2=A0/GP2*VIL 70 CONTINUE ELSE C0=DEXP(X)/DSQRT(2.0D0*PI*X) DO 80 L=1,2 VV=VV0*L*L VSL=1.0D0 R=1.0D0 DO 75 K=1,K0 R=-0.125D0*R*(VV-(2.0D0*K-1.0D0)**2.0)/(K*X) 75 VSL=VSL+R IF (L.EQ.1) VI1=C0*VSL IF (L.EQ.2) VI2=C0*VSL 80 CONTINUE ENDIF IF (X.LE.9.0D0) THEN DO 95 L=1,2 VL=L/3.0D0 IF (L.EQ.1) GN=GN1 IF (L.EQ.2) GN=GN2 A0=(2.0D0/X)**VL/GN SUM=1.0D0 R=1.0D0 DO 85 K=1,60 R=0.25D0*R*X2/(K*(K-VL)) SUM=SUM+R IF (DABS(R).LT.1.0D-15) GO TO 90 85 CONTINUE 90 IF (L.EQ.1) VK1=0.5D0*UU0*PI*(SUM*A0-VI1) IF (L.EQ.2) VK2=0.5D0*UU0*PI*(SUM*A0-VI2) 95 CONTINUE ELSE C0=DEXP(-X)*DSQRT(0.5D0*PI/X) DO 105 L=1,2 VV=VV0*L*L SUM=1.0D0 R=1.0D0 DO 100 K=1,K0 R=0.125D0*R*(VV-(2.0*K-1.0)**2.0)/(K*X) 100 SUM=SUM+R IF (L.EQ.1) VK1=C0*SUM IF (L.EQ.2) VK2=C0*SUM 105 CONTINUE ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mairyb.for000077500000000000000000000127271321604176500261220ustar00rootroot00000000000000 PROGRAM MAIRYB C C ============================================================ C Purpose: This program computes Airy functions and their C derivatives using subroutine AIRYB C Input: x --- Argument of Airy function C Output: AI --- Ai(x) C BI --- Bi(x) C AD --- Ai'(x) C BD --- Bi'(x) C Example: C C x Ai(x) Bi(x) Ai'(x) Bi'(x) C ---------------------------------------------------------------- C 0 .35502805D+00 .61492663D+00 -.25881940D+00 .44828836D+00 C 10 .11047533D-09 .45564115D+09 -.35206337D-09 .14292361D+10 C 20 .16916729D-26 .21037650D+26 -.75863916D-26 .93818393D+26 C 30 .32082176D-48 .90572885D+47 -.17598766D-47 .49533045D+48 C C x Ai(-x) Bi(-x) Ai'(-x) Bi'(-x) C ---------------------------------------------------------------- C 0 .35502805 .61492663 -.25881940 .44828836 C 10 .04024124 -.31467983 .99626504 .11941411 C 20 -.17640613 -.20013931 .89286286 -.79142903 C 30 -.08796819 -.22444694 1.22862060 -.48369473 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X CALL AIRYB(X,AI,BI,AD,BD) WRITE(*,30) WRITE(*,40) WRITE(*,10)X,AI,BI,AD,BD WRITE(*,*) CALL AIRYB(-X,AI,BI,AD,BD) WRITE(*,50) WRITE(*,40) WRITE(*,20)X,AI,BI,AD,BD 10 FORMAT(1X,F5.1,4D16.8) 20 FORMAT(1X,F5.1,4D16.8) 30 FORMAT(4X,'x',8X,'Ai(x)',11X,'Bi(x)',11X,'Ai''(x)', & 10X,'Bi''(x)') 40 FORMAT(2X,'----------------------------------', & '-----------------------------------') 50 FORMAT(4X,'x',8X,'Ai(-x)',10X,'Bi(-x)',10X, & 'Ai''(-x)',9X,'Bi''(-x)') END SUBROUTINE AIRYB(X,AI,BI,AD,BD) C C ======================================================= C Purpose: Compute Airy functions and their derivatives C Input: x --- Argument of Airy function C Output: AI --- Ai(x) C BI --- Bi(x) C AD --- Ai'(x) C BD --- Bi'(x) C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION CK(41),DK(41) EPS=1.0D-15 PI=3.141592653589793D0 C1=0.355028053887817D0 C2=0.258819403792807D0 SR3=1.732050807568877D0 XA=DABS(X) XQ=DSQRT(XA) IF (X.GT.0.0D0) XM=5.0 IF (X.LE.0.0D0) XM=8.0 IF (X.EQ.0.0D0) THEN AI=C1 BI=SR3*C1 AD=-C2 BD=SR3*C2 RETURN ENDIF IF (XA.LE.XM) THEN FX=1.0D0 R=1.0D0 DO 10 K=1,40 R=R*X/(3.0D0*K)*X/(3.0D0*K-1.0D0)*X FX=FX+R IF (DABS(R).LT.DABS(FX)*EPS) GO TO 15 10 CONTINUE 15 GX=X R=X DO 20 K=1,40 R=R*X/(3.0D0*K)*X/(3.0D0*K+1.0D0)*X GX=GX+R IF (DABS(R).LT.DABS(GX)*EPS) GO TO 25 20 CONTINUE 25 AI=C1*FX-C2*GX BI=SR3*(C1*FX+C2*GX) DF=0.5D0*X*X R=DF DO 30 K=1,40 R=R*X/(3.0D0*K)*X/(3.0D0*K+2.0D0)*X DF=DF+R IF (DABS(R).LT.DABS(DF)*EPS) GO TO 35 30 CONTINUE 35 DG=1.0D0 R=1.0D0 DO 40 K=1,40 R=R*X/(3.0D0*K)*X/(3.0D0*K-2.0D0)*X DG=DG+R IF (DABS(R).LT.DABS(DG)*EPS) GO TO 45 40 CONTINUE 45 AD=C1*DF-C2*DG BD=SR3*(C1*DF+C2*DG) ELSE XE=XA*XQ/1.5D0 XR1=1.0D0/XE XAR=1.0D0/XQ XF=DSQRT(XAR) RP=0.5641895835477563D0 R=1.0D0 DO 50 K=1,40 R=R*(6.0D0*K-1.0D0)/216.0D0*(6.0D0*K-3.0D0) & /K*(6.0D0*K-5.0D0)/(2.0D0*K-1.0D0) CK(K)=R 50 DK(K)=-(6.0D0*K+1.0D0)/(6.0D0*K-1.0D0)*CK(K) KM=INT(24.5-XA) IF (XA.LT.6.0) KM=14 IF (XA.GT.15.0) KM=10 IF (X.GT.0.0D0) THEN SAI=1.0D0 SAD=1.0D0 R=1.0D0 DO 55 K=1,KM R=-R*XR1 SAI=SAI+CK(K)*R 55 SAD=SAD+DK(K)*R SBI=1.0D0 SBD=1.0D0 R=1.0D0 DO 60 K=1,KM R=R*XR1 SBI=SBI+CK(K)*R 60 SBD=SBD+DK(K)*R XP1=DEXP(-XE) AI=0.5D0*RP*XF*XP1*SAI BI=RP*XF/XP1*SBI AD=-.5D0*RP/XF*XP1*SAD BD=RP/XF/XP1*SBD ELSE XCS=DCOS(XE+PI/4.0D0) XSS=DSIN(XE+PI/4.0D0) SSA=1.0D0 SDA=1.0D0 R=1.0D0 XR2=1.0D0/(XE*XE) DO 65 K=1,KM R=-R*XR2 SSA=SSA+CK(2*K)*R 65 SDA=SDA+DK(2*K)*R SSB=CK(1)*XR1 SDB=DK(1)*XR1 R=XR1 DO 70 K=1,KM R=-R*XR2 SSB=SSB+CK(2*K+1)*R 70 SDB=SDB+DK(2*K+1)*R AI=RP*XF*(XSS*SSA-XCS*SSB) BI=RP*XF*(XCS*SSA+XSS*SSB) AD=-RP/XF*(XCS*SDA+XSS*SDB) BD=RP/XF*(XSS*SDA-XCS*SDB) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mairyzo.for000077500000000000000000000233261321604176500263260ustar00rootroot00000000000000 PROGRAM MAIRYZO C C ========================================================= C Purpose: This program computes the first NT zeros of Airy C functions Ai(x) and Ai'(x), and the associated C values of Ai(a') and Ai'(a), and the first NT C zeros of Airy functions Bi(x) and Bi'(x), and C the associated values of Bi(b') and Bi'(b) using C subroutine AIRYZO C Input : NT --- Total number of zeros C KF --- Function code C KF=1 for Ai(x) and Ai'(x) C KF=2 for Bi(x) and Bi'(x) C Output: XA(m) --- a, the m-th zero of Ai(x) or C b, the m-th zero of Bi(x) C XB(m) --- a', the m-th zero of Ai'(x) or C b', the m-th zero of Bi'(x) C XC(m) --- Ai(a') or Bi(b') C XD(m) --- Ai'(a) or Bi'(b) C ( m --- Serial number of zeros ) C Example: NT=5 C C m a Ai'(a) a' Ai(a') C ----------------------------------------------------------- C 1 -2.33810741 .70121082 -1.01879297 .53565666 C 2 -4.08794944 -.80311137 -3.24819758 -.41901548 C 3 -5.52055983 .86520403 -4.82009921 .38040647 C 4 -6.78670809 -.91085074 -6.16330736 -.35790794 C 5 -7.94413359 .94733571 -7.37217726 .34230124 C C m b Bi'(b) b' Bi(b') C ----------------------------------------------------------- C 1 -1.17371322 .60195789 -2.29443968 -.45494438 C 2 -3.27109330 -.76031014 -4.07315509 .39652284 C 3 -4.83073784 .83699101 -5.51239573 -.36796916 C 4 -6.16985213 -.88947990 -6.78129445 .34949912 C 5 -7.37676208 .92998364 -7.94017869 -.33602624 C ========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION XA(50),XB(50),XC(50),XD(50) WRITE(*,35) WRITE(*,40) WRITE(*,*)'Please enter KF,NT ' READ(*,*)KF,NT WRITE(*,30)KF,NT IF (KF.EQ.1) THEN WRITE(*,*)' m a Ai''(a) a''', & ' Ai(a'')' ELSE IF (KF.EQ.2) THEN WRITE(*,*)' m b Bi''(b) b''', & ' Bi(b'')' ENDIF WRITE(*,*)'---------------------------------', & & '---------------------------' CALL AIRYZO(NT,KF,XA,XB,XC,XD) DO 10 K=1,NT 10 WRITE(*,20)K,XA(K),XD(K),XB(K),XC(K) 20 FORMAT(1X,I3,1X,3F14.8,F13.8) 30 FORMAT(1X,3HKF=,I2,', ',3HNT=,I3) 35 FORMAT(10X,'KF=1 for Ai(x) and Ai''(x); KF=2 for Bi(x)', & ' and Bi''(x)') 40 FORMAT(10X,'NT is the number of the zeros') END SUBROUTINE AIRYZO(NT,KF,XA,XB,XC,XD) C C ======================================================== C Purpose: Compute the first NT zeros of Airy functions C Ai(x) and Ai'(x), a and a', and the associated C values of Ai(a') and Ai'(a); and the first NT C zeros of Airy functions Bi(x) and Bi'(x), b and C b', and the associated values of Bi(b') and C Bi'(b) C Input : NT --- Total number of zeros C KF --- Function code C KF=1 for Ai(x) and Ai'(x) C KF=2 for Bi(x) and Bi'(x) C Output: XA(m) --- a, the m-th zero of Ai(x) or C b, the m-th zero of Bi(x) C XB(m) --- a', the m-th zero of Ai'(x) or C b', the m-th zero of Bi'(x) C XC(m) --- Ai(a') or Bi(b') C XD(m) --- Ai'(a) or Bi'(b) C ( m --- Serial number of zeros ) C Routine called: AIRYB for computing Airy functions and C their derivatives C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION XA(NT),XB(NT),XC(NT),XD(NT) PI=3.141592653589793D0 DO 15 I=1,NT IF (KF.EQ.1) THEN U=3.0*PI*(4.0*I-1)/8.0D0 U1=1/(U*U) RT0=-(U*U)**(1.0/3.0)*((((-15.5902*U1+.929844)*U1 & -.138889)*U1+.10416667D0)*U1+1.0D0) ELSE IF (KF.EQ.2) THEN IF (I.EQ.1) THEN RT0=-1.17371 ELSE U=3.0*PI*(4.0*I-3.0)/8.0 U1=1.0D0/(U*U) RT0=-(U*U)**(1.0/3.0)*((((-15.5902*U1+.929844)*U1 & -.138889)*U1+.10416667)*U1+1.0) ENDIF ENDIF 10 X=RT0 CALL AIRYB(X,AI,BI,AD,BD) IF (KF.EQ.1) RT=RT0-AI/AD IF (KF.EQ.2) RT=RT0-BI/BD IF (DABS((RT-RT0)/RT).GT.1.D-9) THEN RT0=RT GOTO 10 ELSE XA(I)=RT IF (KF.EQ.1) XD(I)=AD IF (KF.EQ.2) XD(I)=BD ENDIF 15 CONTINUE DO 25 I=1,NT IF (KF.EQ.1) THEN IF (I.EQ.1) THEN RT0=-1.01879 ELSE U=3.0*PI*(4.0*I-3.0)/8.0 U1=1/(U*U) RT0=-(U*U)**(1.0/3.0)*((((15.0168*U1-.873954) & *U1+.121528)*U1-.145833D0)*U1+1.0D0) ENDIF ELSE IF (KF.EQ.2) THEN IF (I.EQ.1) THEN RT0=-2.29444 ELSE U=3.0*PI*(4.0*I-1.0)/8.0 U1=1.0/(U*U) RT0=-(U*U)**(1.0/3.0)*((((15.0168*U1-.873954) & *U1+.121528)*U1-.145833)*U1+1.0) ENDIF ENDIF 20 X=RT0 CALL AIRYB(X,AI,BI,AD,BD) IF (KF.EQ.1) RT=RT0-AD/(AI*X) IF (KF.EQ.2) RT=RT0-BD/(BI*X) IF (DABS((RT-RT0)/RT).GT.1.0D-9) THEN RT0=RT GOTO 20 ELSE XB(I)=RT IF (KF.EQ.1) XC(I)=AI IF (KF.EQ.2) XC(I)=BI ENDIF 25 CONTINUE RETURN END SUBROUTINE AIRYB(X,AI,BI,AD,BD) C C ======================================================= C Purpose: Compute Airy functions and their derivatives C Input: x --- Argument of Airy function C Output: AI --- Ai(x) C BI --- Bi(x) C AD --- Ai'(x) C BD --- Bi'(x) C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION CK(41),DK(41) EPS=1.0D-15 PI=3.141592653589793D0 C1=0.355028053887817D0 C2=0.258819403792807D0 SR3=1.732050807568877D0 XA=DABS(X) XQ=DSQRT(XA) IF (X.GT.0.0D0) XM=5.0 IF (X.LE.0.0D0) XM=8.0 IF (X.EQ.0.0D0) THEN AI=C1 BI=SR3*C1 AD=-C2 BD=SR3*C2 RETURN ENDIF IF (XA.LE.XM) THEN FX=1.0D0 R=1.0D0 DO 10 K=1,40 R=R*X/(3.0D0*K)*X/(3.0D0*K-1.0D0)*X FX=FX+R IF (DABS(R/FX).LT.EPS) GO TO 15 10 CONTINUE 15 GX=X R=X DO 20 K=1,40 R=R*X/(3.0D0*K)*X/(3.0D0*K+1.0D0)*X GX=GX+R IF (DABS(R/GX).LT.EPS) GO TO 25 20 CONTINUE 25 AI=C1*FX-C2*GX BI=SR3*(C1*FX+C2*GX) DF=.5D0*X*X R=DF DO 30 K=1,40 R=R*X/(3.0D0*K)*X/(3.0D0*K+2.0D0)*X DF=DF+R IF (DABS(R/DF).LT.EPS) GO TO 35 30 CONTINUE 35 DG=1.0D0 R=1.0D0 DO 40 K=1,40 R=R*X/(3.0D0*K)*X/(3.0D0*K-2.0D0)*X DG=DG+R IF (DABS(R/DG).LT.EPS) GO TO 45 40 CONTINUE 45 AD=C1*DF-C2*DG BD=SR3*(C1*DF+C2*DG) ELSE XE=XA*XQ/1.5D0 XR1=1.0D0/XE XAR=1.0D0/XQ XF=DSQRT(XAR) RP=.5641895835477563D0 R=1.0D0 DO 50 K=1,40 R=R*(6.0D0*K-1.0D0)/216.0D0*(6.0D0*K-3.0D0) & /K*(6.0D0*K-5.0D0)/(2.0D0*K-1.0D0) CK(K)=R 50 DK(K)=-(6.0D0*K+1.0D0)/(6.0D0*K-1.0D0)*CK(K) KM=INT(24.5-XA) IF (XA.LT.6.0) KM=14 IF (XA.GT.15.0) KM=10 IF (X.GT.0.0D0) THEN SAI=1.0D0 SAD=1.0D0 R=1.0D0 DO 55 K=1,KM R=-R*XR1 SAI=SAI+CK(K)*R 55 SAD=SAD+DK(K)*R SBI=1.0D0 SBD=1.0D0 R=1.0D0 DO 60 K=1,KM R=R*XR1 SBI=SBI+CK(K)*R 60 SBD=SBD+DK(K)*R XP1=DEXP(-XE) AI=.5D0*RP*XF*XP1*SAI BI=RP*XF/XP1*SBI AD=-.5D0*RP/XF*XP1*SAD BD=RP/XF/XP1*SBD ELSE XCS=DCOS(XE+PI/4.0D0) XSS=DSIN(XE+PI/4.0D0) SSA=1.0D0 SDA=1.0D0 R=1.0D0 XR2=1.0D0/(XE*XE) DO 65 K=1,KM R=-R*XR2 SSA=SSA+CK(2*K)*R 65 SDA=SDA+DK(2*K)*R SSB=CK(1)*XR1 SDB=DK(1)*XR1 R=XR1 DO 70 K=1,KM R=-R*XR2 SSB=SSB+CK(2*K+1)*R 70 SDB=SDB+DK(2*K+1)*R AI=RP*XF*(XSS*SSA-XCS*SSB) BI=RP*XF*(XCS*SSA+XSS*SSB) AD=-RP/XF*(XCS*SDA+XSS*SDB) BD=RP/XF*(XSS*SDA-XCS*SDB) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/maswfa.for000077500000000000000000000253601321604176500261120ustar00rootroot00000000000000 PROGRAM MASWFA C C ============================================================ C Purpose: This program computes the prolate and oblate C spheroidal angular functions of the first C kind and their derivatives using subroutine ASWFA C Input : m --- Mode parameter, m = 0,1,2,... C n --- Mode parameter, n = m,m+1,... C c --- Spheroidal parameter C x --- Argument of angular function, |x| < 1.0 C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C cv --- Characteristic value C Output: S1F --- Angular function of the first kind C S1D --- Derivative of the angular function of C the first kind C Examples: C KD = 1, m = 2, n = 3, c = 3.0 and cv = 14.8277782138 C x Smn(c,x) Smn'(c,x) C -------------------------------------------- C 0.2 .28261309D+01 .12418631D+02 C 0.5 .49938554D+01 .92761604D+00 C 0.8 .31693975D+01 -.12646552D+02 C C KD =-1, m = 2, n = 3, c = 3.0 and cv = 8.8093939208 C x Smn(-ic,x) Smn'(-ic,x) C -------------------------------------------- C 0.2 .29417848D+01 .14106305D+02 C 0.5 .64138827D+01 .76007194D+01 C 0.8 .60069873D+01 -.14387479D+02 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EG(200) WRITE(*,*)'Please enter KD, m, n and c ' READ(*,*)KD,M,N,C WRITE(*,10)KD,M,N,C CALL SEGV(M,N,C,KD,CV,EG) WRITE(*,20)CV WRITE(*,*) IF (KD.EQ.1 ) THEN WRITE(*,*)' x Smn(c,x) Smn''(c,x)' ELSE IF (KD.EQ.-1) THEN WRITE(*,*)' x Smn(-ic,x) Smn''(-ic,x)' ENDIF WRITE(*,*)' --------------------------------------------' DO 5 I=0,20 X=-1.0D0+0.1D0*I CALL ASWFA(M,N,C,X,KD,CV,S1F,S1D) 5 WRITE(*,30)X,S1F,S1D 10 FORMAT(1X,'KD ='I2,', ','m =',I2,', ','n =',I2,', ','c =',F5.1) 20 FORMAT(1X,' cv =',F18.10) 30 FORMAT(1X,F5.1,2D20.8) END SUBROUTINE ASWFA(M,N,C,X,KD,CV,S1F,S1D) C C =========================================================== C Purpose: Compute the prolate and oblate spheroidal angular C functions of the first kind and their derivatives C Input : m --- Mode parameter, m = 0,1,2,... C n --- Mode parameter, n = m,m+1,... C c --- Spheroidal parameter C x --- Argument of angular function, |x| < 1.0 C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C cv --- Characteristic value C Output: S1F --- Angular function of the first kind C S1D --- Derivative of the angular function of C the first kind C Routine called: C SCKB for computing expansion coefficients ck C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION CK(200),DF(200) EPS=1.0D-14 X0=X X=DABS(X) IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 NM=10+INT((N-M)/2+C) NM2=NM/2-2 CALL SDMN(M,N,C,CV,KD,DF) CALL SCKB(M,N,C,DF,CK) X1=1.0D0-X*X IF (M.EQ.0.AND.X1.EQ.0.0D0) THEN A0=1.0D0 ELSE A0=X1**(0.5D0*M) ENDIF SU1=CK(1) DO 10 K=1,NM2 R=CK(K+1)*X1**K SU1=SU1+R IF (K.GE.10.AND.DABS(R/SU1).LT.EPS) GO TO 15 10 CONTINUE 15 S1F=A0*X**IP*SU1 IF (X.EQ.1.0D0) THEN IF (M.EQ.0) S1D=IP*CK(1)-2.0D0*CK(2) IF (M.EQ.1) S1D=-1.0D+100 IF (M.EQ.2) S1D=-2.0D0*CK(1) IF (M.GE.3) S1D=0.0D0 ELSE D0=IP-M/X1*X**(IP+1.0D0) D1=-2.0D0*A0*X**(IP+1.0D0) SU2=CK(2) DO 20 K=2,NM2 R=K*CK(K+1)*X1**(K-1.0D0) SU2=SU2+R IF (K.GE.10.AND.DABS(R/SU2).LT.EPS) GO TO 25 20 CONTINUE 25 S1D=D0*A0*SU1+D1*SU2 ENDIF IF (X0.LT.0.0D0.AND.IP.EQ.0) S1D=-S1D IF (X0.LT.0.0D0.AND.IP.EQ.1) S1F=-S1F X=X0 RETURN END SUBROUTINE SCKB(M,N,C,DF,CK) C C ====================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C DF(k) --- Expansion coefficients dk C Output: CK(k) --- Expansion coefficients ck; C CK(1), CK(2), ... correspond to C c0, c2, ... C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DF(200),CK(200) IF (C.LE.1.0D-10) C=1.0D-10 NM=25+INT(0.5*(N-M)+C) IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 REG=1.0D0 IF (M+NM.GT.80) REG=1.0D-200 FAC=-0.5D0**M DO 35 K=0,NM-1 FAC=-FAC I1=2*K+IP+1 R=REG DO 10 I=I1,I1+2*M-1 10 R=R*I I2=K+M+IP DO 15 I=I2,I2+K-1 15 R=R*(I+0.5D0) SUM=R*DF(K+1) DO 20 I=K+1,NM D1=2.0D0*I+IP D2=2.0D0*M+D1 D3=I+M+IP-0.5D0 R=R*D2*(D2-1.0D0)*I*(D3+K)/(D1*(D1-1.0D0)*(I-K)*D3) SUM=SUM+R*DF(I+1) IF (DABS(SW-SUM).LT.DABS(SUM)*1.0D-14) GOTO 25 20 SW=SUM 25 R1=REG DO 30 I=2,M+K 30 R1=R1*I 35 CK(K+1)=FAC*SUM/R1 RETURN END SUBROUTINE SDMN(M,N,C,CV,KD,DF) C C ===================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions, dk C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C cv --- Characteristic value C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C Output: DF(k) --- Expansion coefficients dk; C DF(1), DF(2), ... correspond to C d0, d2, ... for even n-m and d1, C d3, ... for odd n-m C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(200),D(200),G(200),DF(200) NM=25+INT(0.5*(N-M)+C) IF (C.LT.1.0D-10) THEN DO 5 I=1,NM 5 DF(I)=0D0 DF((N-M)/2+1)=1.0D0 RETURN ENDIF CS=C*C*KD IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 DO 10 I=1,NM+2 IF (IP.EQ.0) K=2*(I-1) IF (IP.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS 10 CONTINUE FS=1.0D0 F1=0.0D0 F0=1.0D-100 KB=0 DF(NM+1)=0.0D0 DO 30 K=NM,1,-1 F=-((D(K+1)-CV)*F0+A(K+1)*F1)/G(K+1) IF (DABS(F).GT.DABS(DF(K+1))) THEN DF(K)=F F1=F0 F0=F IF (DABS(F).GT.1.0D+100) THEN DO 12 K1=K,NM 12 DF(K1)=DF(K1)*1.0D-100 F1=F1*1.0D-100 F0=F0*1.0D-100 ENDIF ELSE KB=K FL=DF(K+1) F1=1.0D-100 F2=-(D(1)-CV)/A(1)*F1 DF(1)=F1 IF (KB.EQ.1) THEN FS=F2 ELSE IF (KB.EQ.2) THEN DF(2)=F2 FS=-((D(2)-CV)*F2+G(2)*F1)/A(2) ELSE DF(2)=F2 DO 20 J=3,KB+1 F=-((D(J-1)-CV)*F2+G(J-1)*F1)/A(J-1) IF (J.LE.KB) DF(J)=F IF (DABS(F).GT.1.0D+100) THEN DO 15 K1=1,J 15 DF(K1)=DF(K1)*1.0D-100 F=F*1.0D-100 F2=F2*1.0D-100 ENDIF F1=F2 20 F2=F FS=F ENDIF GO TO 35 ENDIF 30 CONTINUE 35 SU1=0.0D0 R1=1.0D0 DO 40 J=M+IP+1,2*(M+IP) 40 R1=R1*J SU1=DF(1)*R1 DO 45 K=2,KB R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) 45 SU1=SU1+R1*DF(K) SU2=0.0D0 DO 50 K=KB+1,NM IF (K.NE.1) R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) SU2=SU2+R1*DF(K) IF (DABS(SW-SU2).LT.DABS(SU2)*1.0D-14) GOTO 55 50 SW=SU2 55 R3=1.0D0 DO 60 J=1,(M+N+IP)/2 60 R3=R3*(J+0.5D0*(N+M+IP)) R4=1.0D0 DO 65 J=1,(N-M-IP)/2 65 R4=-4.0D0*R4*J S0=R3/(FL*(SU1/FS)+SU2)/R4 DO 70 K=1,KB 70 DF(K)=FL/FS*S0*DF(K) DO 75 K=KB+1,NM 75 DF(K)=S0*DF(K) RETURN END SUBROUTINE SEGV(M,N,C,KD,CV,EG) C C ========================================================= C Purpose: Compute the characteristic values of spheroidal C wave functions C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C KD --- Function code C KD=1 for Prolate; KD=-1 for Oblate C Output: CV --- Characteristic value for given m, n and c C EG(L) --- Characteristic value for mode m and n' C ( L = n' - m + 1 ) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION B(100),H(100),D(300),E(300),F(300),CV0(100), & A(300),G(300),EG(200) IF (C.LT.1.0D-10) THEN DO 5 I=1,N 5 EG(I)=(I+M)*(I+M-1.0D0) GO TO 70 ENDIF ICM=(N-M+2)/2 NM=10+INT(0.5*(N-M)+C) CS=C*C*KD DO 60 L=0,1 DO 10 I=1,NM IF (L.EQ.0) K=2*(I-1) IF (L.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS 10 G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS DO 15 K=2,NM E(K)=DSQRT(A(K-1)*G(K)) 15 F(K)=E(K)*E(K) F(1)=0.0D0 E(1)=0.0D0 XA=D(NM)+DABS(E(NM)) XB=D(NM)-DABS(E(NM)) NM1=NM-1 DO 20 I=1,NM1 T=DABS(E(I))+DABS(E(I+1)) T1=D(I)+T IF (XA.LT.T1) XA=T1 T1=D(I)-T IF (T1.LT.XB) XB=T1 20 CONTINUE DO 25 I=1,ICM B(I)=XA 25 H(I)=XB DO 55 K=1,ICM DO 30 K1=K,ICM IF (B(K1).LT.B(K)) THEN B(K)=B(K1) GO TO 35 ENDIF 30 CONTINUE 35 IF (K.NE.1.AND.H(K).LT.H(K-1)) H(K)=H(K-1) 40 X1=(B(K)+H(K))/2.0D0 CV0(K)=X1 IF (DABS((B(K)-H(K))/X1).LT.1.0D-14) GO TO 50 J=0 S=1.0D0 DO 45 I=1,NM IF (S.EQ.0.0D0) S=S+1.0D-30 T=F(I)/S S=D(I)-T-X1 IF (S.LT.0.0D0) J=J+1 45 CONTINUE IF (J.LT.K) THEN H(K)=X1 ELSE B(K)=X1 IF (J.GE.ICM) THEN B(ICM)=X1 ELSE IF (H(J+1).LT.X1) H(J+1)=X1 IF (X1.LT.B(J)) B(J)=X1 ENDIF ENDIF GO TO 40 50 CV0(K)=X1 IF (L.EQ.0) EG(2*K-1)=CV0(K) IF (L.EQ.1) EG(2*K)=CV0(K) 55 CONTINUE 60 CONTINUE 70 CV=EG(N-M+1) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/maswfb.for000077500000000000000000000247741321604176500261230ustar00rootroot00000000000000 PROGRAM MASWFB C C ============================================================ C Purpose: This program computes the prolate and oblate C spheroidal angular functions of the first kind C and their derivatives using subroutine ASWFB C Input : m --- Mode parameter, m = 0,1,2,... C n --- Mode parameter, n = m,m+1,... C c --- Spheroidal parameter C x --- Argument of angular function, |x| ó 1.0 C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C cv --- Characteristic value C Output: S1F --- Angular function of the first kind C S1D --- Derivative of the angular function of C the first kind C Examples: C KD = 1, m = 2, n = 3, c = 3.0 and cv = 14.8277782138 C x Smn(c,x) Smn'(c,x) C -------------------------------------------- C 0.2 .28261309D+01 .12418631D+02 C 0.5 .49938554D+01 .92761604D+00 C 0.8 .31693975D+01 -.12646552D+02 C C KD =-1, m = 2, n = 3, c = 3.0 and cv = 8.8093939208 C x Smn(-ic,x) Smn'(-ic,x) C -------------------------------------------- C 0.2 .29417848D+01 .14106305D+02 C 0.5 .64138827D+01 .76007194D+01 C 0.8 .60069873D+01 -.14387479D+02 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EG(200) WRITE(*,*)'Please enter KD, m, n and c ' READ(*,*)KD,M,N,C WRITE(*,10)KD,M,N,C CALL SEGV(M,N,C,KD,CV,EG) WRITE(*,20)CV WRITE(*,*) IF (KD.EQ.1 ) THEN WRITE(*,*)' x Smn(c,x) Smn''(c,x)' ELSE IF (KD.EQ.-1) THEN WRITE(*,*)' x Smn(-ic,x) Smn''(-ic,x)' ENDIF WRITE(*,*)' --------------------------------------------' DO 5 I=0,20 X=-1.0D0+0.1D0*I CALL ASWFB(M,N,C,X,KD,CV,S1F,S1D) 5 WRITE(*,30)X,S1F,S1D 10 FORMAT(1X,'KD ='I2,', ','m =',I2,', ','n =',I2,', ','c =',F5.1) 20 FORMAT(1X,' cv =',F18.10) 30 FORMAT(1X,F5.1,2D20.8) END SUBROUTINE ASWFB(M,N,C,X,KD,CV,S1F,S1D) C C =========================================================== C Purpose: Compute the prolate and oblate spheroidal angular C functions of the first kind and their derivatives C Input : m --- Mode parameter, m = 0,1,2,... C n --- Mode parameter, n = m,m+1,... C c --- Spheroidal parameter C x --- Argument of angular function, |x| < 1.0 C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C cv --- Characteristic value C Output: S1F --- Angular function of the first kind C S1D --- Derivative of the angular function of C the first kind C Routines called: C (1) SDMN for computing expansion coefficients dk C (2) LPMNS for computing associated Legendre function C of the first kind Pmn(x) C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DF(200),PM(0:251),PD(0:251) EPS=1.0D-14 IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 NM=25+INT((N-M)/2+C) NM2=2*NM+M CALL SDMN(M,N,C,CV,KD,DF) CALL LPMNS(M,NM2,X,PM,PD) SU1=0.0D0 DO 10 K=1,NM MK=M+2*(K-1)+IP SU1=SU1+DF(K)*PM(MK) IF (DABS(SW-SU1).LT.DABS(SU1)*EPS) GOTO 15 10 SW=SU1 15 S1F=(-1)**M*SU1 SU1=0.0D0 DO 20 K=1,NM MK=M+2*(K-1)+IP SU1=SU1+DF(K)*PD(MK) IF (DABS(SW-SU1).LT.DABS(SU1)*EPS) GOTO 25 20 SW=SU1 25 S1D=(-1)**M*SU1 RETURN END SUBROUTINE SDMN(M,N,C,CV,KD,DF) C C ===================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions, dk C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C cv --- Characteristic value C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C Output: DF(k) --- Expansion coefficients dk; C DF(1), DF(2), ... correspond to C d0, d2, ... for even n-m and d1, C d3, ... for odd n-m C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(200),D(200),G(200),DF(200) NM=25+INT(0.5*(N-M)+C) IF (C.LT.1.0D-10) THEN DO 5 I=1,NM 5 DF(I)=0D0 DF((N-M)/2+1)=1.0D0 RETURN ENDIF CS=C*C*KD IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 DO 10 I=1,NM+2 IF (IP.EQ.0) K=2*(I-1) IF (IP.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS 10 CONTINUE FS=1.0D0 F1=0.0D0 F0=1.0D-100 KB=0 DF(NM+1)=0.0D0 DO 30 K=NM,1,-1 F=-((D(K+1)-CV)*F0+A(K+1)*F1)/G(K+1) IF (DABS(F).GT.DABS(DF(K+1))) THEN DF(K)=F F1=F0 F0=F IF (DABS(F).GT.1.0D+100) THEN DO 12 K1=K,NM 12 DF(K1)=DF(K1)*1.0D-100 F1=F1*1.0D-100 F0=F0*1.0D-100 ENDIF ELSE KB=K FL=DF(K+1) F1=1.0D-100 F2=-(D(1)-CV)/A(1)*F1 DF(1)=F1 IF (KB.EQ.1) THEN FS=F2 ELSE IF (KB.EQ.2) THEN DF(2)=F2 FS=-((D(2)-CV)*F2+G(2)*F1)/A(2) ELSE DF(2)=F2 DO 20 J=3,KB+1 F=-((D(J-1)-CV)*F2+G(J-1)*F1)/A(J-1) IF (J.LE.KB) DF(J)=F IF (DABS(F).GT.1.0D+100) THEN DO 15 K1=1,J 15 DF(K1)=DF(K1)*1.0D-100 F=F*1.0D-100 F2=F2*1.0D-100 ENDIF F1=F2 20 F2=F FS=F ENDIF GO TO 35 ENDIF 30 CONTINUE 35 SU1=0.0D0 R1=1.0D0 DO 40 J=M+IP+1,2*(M+IP) 40 R1=R1*J SU1=DF(1)*R1 DO 45 K=2,KB R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) 45 SU1=SU1+R1*DF(K) SU2=0.0D0 DO 50 K=KB+1,NM IF (K.NE.1) R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) SU2=SU2+R1*DF(K) IF (DABS(SW-SU2).LT.DABS(SU2)*1.0D-14) GOTO 55 50 SW=SU2 55 R3=1.0D0 DO 60 J=1,(M+N+IP)/2 60 R3=R3*(J+0.5D0*(N+M+IP)) R4=1.0D0 DO 65 J=1,(N-M-IP)/2 65 R4=-4.0D0*R4*J S0=R3/(FL*(SU1/FS)+SU2)/R4 DO 70 K=1,KB 70 DF(K)=FL/FS*S0*DF(K) DO 75 K=KB+1,NM 75 DF(K)=S0*DF(K) RETURN END SUBROUTINE SEGV(M,N,C,KD,CV,EG) C C ========================================================= C Purpose: Compute the characteristic values of spheroidal C wave functions C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C KD --- Function code C KD=1 for Prolate; KD=-1 for Oblate C Output: CV --- Characteristic value for given m, n and c C EG(L) --- Characteristic value for mode m and n' C ( L = n' - m + 1 ) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION B(100),H(100),D(300),E(300),F(300),CV0(100), & A(300),G(300),EG(200) IF (C.LT.1.0D-10) THEN DO 5 I=1,N 5 EG(I)=(I+M)*(I+M-1.0D0) GO TO 70 ENDIF ICM=(N-M+2)/2 NM=10+INT(0.5*(N-M)+C) CS=C*C*KD DO 60 L=0,1 DO 10 I=1,NM IF (L.EQ.0) K=2*(I-1) IF (L.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS 10 G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS DO 15 K=2,NM E(K)=DSQRT(A(K-1)*G(K)) 15 F(K)=E(K)*E(K) F(1)=0.0D0 E(1)=0.0D0 XA=D(NM)+DABS(E(NM)) XB=D(NM)-DABS(E(NM)) NM1=NM-1 DO 20 I=1,NM1 T=DABS(E(I))+DABS(E(I+1)) T1=D(I)+T IF (XA.LT.T1) XA=T1 T1=D(I)-T IF (T1.LT.XB) XB=T1 20 CONTINUE DO 25 I=1,ICM B(I)=XA 25 H(I)=XB DO 55 K=1,ICM DO 30 K1=K,ICM IF (B(K1).LT.B(K)) THEN B(K)=B(K1) GO TO 35 ENDIF 30 CONTINUE 35 IF (K.NE.1.AND.H(K).LT.H(K-1)) H(K)=H(K-1) 40 X1=(B(K)+H(K))/2.0D0 CV0(K)=X1 IF (DABS((B(K)-H(K))/X1).LT.1.0D-14) GO TO 50 J=0 S=1.0D0 DO 45 I=1,NM IF (S.EQ.0.0D0) S=S+1.0D-30 T=F(I)/S S=D(I)-T-X1 IF (S.LT.0.0D0) J=J+1 45 CONTINUE IF (J.LT.K) THEN H(K)=X1 ELSE B(K)=X1 IF (J.GE.ICM) THEN B(ICM)=X1 ELSE IF (H(J+1).LT.X1) H(J+1)=X1 IF (X1.LT.B(J)) B(J)=X1 ENDIF ENDIF GO TO 40 50 CV0(K)=X1 IF (L.EQ.0) EG(2*K-1)=CV0(K) IF (L.EQ.1) EG(2*K)=CV0(K) 55 CONTINUE 60 CONTINUE 70 CV=EG(N-M+1) RETURN END SUBROUTINE LPMNS(M,N,X,PM,PD) C C ======================================================== C Purpose: Compute associated Legendre functions Pmn(x) C and Pmn'(x) for a given order C Input : x --- Argument of Pmn(x) C m --- Order of Pmn(x), m = 0,1,2,...,n C n --- Degree of Pmn(x), n = 0,1,2,...,N C Output: PM(n) --- Pmn(x) C PD(n) --- Pmn'(x) C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION PM(0:N),PD(0:N) DO 10 K=0,N PM(K)=0.0D0 10 PD(K)=0.0D0 IF (DABS(X).EQ.1.0D0) THEN DO 15 K=0,N IF (M.EQ.0) THEN PM(K)=1.0D0 PD(K)=0.5D0*K*(K+1.0) IF (X.LT.0.0) THEN PM(K)=(-1)**K*PM(K) PD(K)=(-1)**(K+1)*PD(K) ENDIF ELSE IF (M.EQ.1) THEN PD(K)=1.0D+300 ELSE IF (M.EQ.2) THEN PD(K)=-0.25D0*(K+2.0)*(K+1.0)*K*(K-1.0) IF (X.LT.0.0) PD(K)=(-1)**(K+1)*PD(K) ENDIF 15 CONTINUE RETURN ENDIF X0=DABS(1.0D0-X*X) PM0=1.0D0 PMK=PM0 DO 20 K=1,M PMK=(2.0D0*K-1.0D0)*DSQRT(X0)*PM0 20 PM0=PMK PM1=(2.0D0*M+1.0D0)*X*PM0 PM(M)=PMK PM(M+1)=PM1 DO 25 K=M+2,N PM2=((2.0D0*K-1.0D0)*X*PM1-(K+M-1.0D0)*PMK)/(K-M) PM(K)=PM2 PMK=PM1 25 PM1=PM2 PD(0)=((1.0D0-M)*PM(1)-X*PM(0))/(X*X-1.0) DO 30 K=1,N 30 PD(K)=(K*X*PM(K)-(K+M)*PM(K-1))/(X*X-1.0D0) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mbernoa.for000077500000000000000000000033351321604176500262550ustar00rootroot00000000000000 PROGRAM MBERNOA C C =========================================================== C Purpose: This program computes Bernoulli number Bn using C subroutine BERNOA C Example: Compute Bernouli number Bn for n = 0,1,...,10 C Computed results: C C n Bn C -------------------------- C 0 .100000000000D+01 C 1 -.500000000000D+00 C 2 .166666666667D+00 C 4 -.333333333333D-01 C 6 .238095238095D-01 C 8 -.333333333333D-01 C 10 .757575757576D-01 C =========================================================== C DOUBLE PRECISION B DIMENSION B(0:200) WRITE(*,*)' Please enter Nmax' READ(*,*)N CALL BERNOA(N,B) WRITE(*,*)' n Bn' WRITE(*,*)' --------------------------' WRITE(*,20)0,B(0) WRITE(*,20)1,B(1) DO 10 K=2,N,2 10 WRITE(*,20)K,B(K) 20 FORMAT(2X,I3,D22.12) END SUBROUTINE BERNOA(N,BN) C C ====================================== C Purpose: Compute Bernoulli number Bn C Input : n --- Serial number C Output: BN(n) --- Bn C ====================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BN(0:N) BN(0)=1.0D0 BN(1)=-0.5D0 DO 30 M=2,N S=-(1.0D0/(M+1.0D0)-0.5D0) DO 20 K=2,M-1 R=1.0D0 DO 10 J=2,K 10 R=R*(J+M-K)/J 20 S=S-R*BN(K) 30 BN(M)=S DO 40 M=3,N,2 40 BN(M)=0.0D0 RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mbernob.for000077500000000000000000000034451321604176500262600ustar00rootroot00000000000000 PROGRAM MBERNOB C C =========================================================== C Purpose: This program computes Bernoulli number Bn using C subroutine BERNOB C Example: Compute Bernouli number Bn for n = 0,1,...,10 C Computed results: C C n Bn C -------------------------- C 0 .100000000000D+01 C 1 -.500000000000D+00 C 2 .166666666667D+00 C 4 -.333333333333D-01 C 6 .238095238095D-01 C 8 -.333333333333D-01 C 10 .757575757576D-01 C =========================================================== C DOUBLE PRECISION B DIMENSION B(0:200) WRITE(*,*)' Please enter Nmax' READ(*,*)N CALL BERNOB(N,B) WRITE(*,*)' n Bn' WRITE(*,*)' --------------------------' WRITE(*,20)0,B(0) WRITE(*,20)1,B(1) DO 10 K=2,N,2 10 WRITE(*,20)K,B(K) 20 FORMAT(2X,I3,D22.12) END SUBROUTINE BERNOB(N,BN) C C ====================================== C Purpose: Compute Bernoulli number Bn C Input : n --- Serial number C Output: BN(n) --- Bn C ====================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BN(0:N) TPI=6.283185307179586D0 BN(0)=1.0D0 BN(1)=-0.5D0 BN(2)=1.0D0/6.0D0 R1=(2.0D0/TPI)**2 DO 20 M=4,N,2 R1=-R1*(M-1)*M/(TPI*TPI) R2=1.0D0 DO 10 K=2,10000 S=(1.0D0/K)**M R2=R2+S IF (S.LT.1.0D-15) GOTO 20 10 CONTINUE 20 BN(M)=R1*R2 RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mbeta.for000077500000000000000000000063741321604176500257300ustar00rootroot00000000000000 PROGRAM MBETA C C ==================================================== C Purpose: This program computes the beta function C B(p,q) for p > 0 and q > 0 using C subroutine BETA C Input : p --- Parameter ( p > 0 ) C q --- Parameter ( q > 0 ) C Output: BT --- B(p,q) C Examples: C p q B(p,q) C --------------------------------- C 1.5 2.0 .2666666667D+00 C 2.5 2.0 .1142857143D+00 C 1.5 3.0 .1523809524D+00 C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter p and q' READ(*,*)P,Q WRITE(*,*) WRITE(*,*)' p q B(p,q)' WRITE(*,*)' ---------------------------------' CALL BETA(P,Q,BT) WRITE(*,10)P,Q,BT 10 FORMAT(2X,F5.1,3X,F5.1,D20.10) END SUBROUTINE BETA(P,Q,BT) C C ========================================== C Purpose: Compute the beta function B(p,q) C Input : p --- Parameter ( p > 0 ) C q --- Parameter ( q > 0 ) C Output: BT --- B(p,q) C Routine called: GAMMA for computing â(x) C ========================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) CALL GAMMA(P,GP) CALL GAMMA(Q,GQ) PPQ=P+Q CALL GAMMA(PPQ,GPQ) BT=GP*GQ/GPQ RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcchg.for000077500000000000000000000151001321604176500257040ustar00rootroot00000000000000 PROGRAM MCCHG C C =========================================================== C Purpose: This program computes confluent hypergeometric C function M(a,b,z) with real parameters a, b, and C a complex argument z using subroutine CCHG C Input : a --- Parameter C b --- Parameter C z --- Complex argument C Output: CHG --- M(a,b,z) C Examples: C a b z Re[M(a,b,z)] Im[M(a,b,z)] C ------------------------------------------------------- C 3.3 4.25 10 + 0i .61677489D+04 0 C 3.3 4.25 25 + 0i .95781835D+10 -.15738228D-03 C 3.3 4.25 3 - i .75828716D+01 -.86815474D+01 C 3.3 4.25 15 +10i -.58313765D+06 -.48195426D+05 C =========================================================== C IMPLICIT DOUBLE PRECISION (A,B,X,Y) IMPLICIT COMPLEX *16 (C,Z) WRITE(*,*)'Please enter a, b, x and y (z=x+iy) ' READ(*,*)A,B,X,Y WRITE(*,20)A,B,X,Y Z=CMPLX(X,Y) CALL CCHG(A,B,Z,CHG) WRITE(*,10)CHG 10 FORMAT(10X,'M(a,b,z) =',D18.8,' + i ',D18.8) 20 FORMAT(1X,'a =',F5.1,', ','b =',F5.1,', ','x =',F5.1, & ', ','y =',F5.1) END SUBROUTINE CCHG(A,B,Z,CHG) C C =================================================== C Purpose: Compute confluent hypergeometric function C M(a,b,z) with real parameters a, b and a C complex argument z C Input : a --- Parameter C b --- Parameter C z --- Complex argument C Output: CHG --- M(a,b,z) C Routine called: GAMMA for computing gamma function C =================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX *16 (C,Z) PI=3.141592653589793D0 CI=(0.0D0,1.0D0) A0=A A1=A Z0=Z IF (B.EQ.0.0.OR.B.EQ.-INT(ABS(B))) THEN CHG=(1.0D+300,0.0D0) ELSE IF (A.EQ.0.0D0.OR.Z.EQ.0.0D0) THEN CHG=(1.0D0,0.0D0) ELSE IF (A.EQ.-1.0D0) THEN CHG=1.0D0-Z/B ELSE IF (A.EQ.B) THEN CHG=CDEXP(Z) ELSE IF (A-B.EQ.1.0D0) THEN CHG=(1.0D0+Z/B)*CDEXP(Z) ELSE IF (A.EQ.1.0D0.AND.B.EQ.2.0D0) THEN CHG=(CDEXP(Z)-1.0D0)/Z ELSE IF (A.EQ.INT(A).AND.A.LT.0.0D0) THEN M=INT(-A) CR=(1.0D0,0.0D0) CHG=(1.0D0,0.0D0) DO 10 K=1,M CR=CR*(A+K-1.0D0)/K/(B+K-1.0D0)*Z 10 CHG=CHG+CR ELSE X0=REAL(Z) IF (X0.LT.0.0D0) THEN A=B-A A0=A Z=-Z ENDIF IF (A.LT.2.0D0) NL=0 IF (A.GE.2.0D0) THEN NL=1 LA=INT(A) A=A-LA-1.0D0 ENDIF DO 30 N=0,NL IF (A0.GE.2.0D0) A=A+1.0D0 IF (CDABS(Z).LT.20.0D0+ABS(B).OR.A.LT.0.0D0) THEN CHG=(1.0D0,0.0D0) CRG=(1.0D0,0.0D0) DO 15 J=1,500 CRG=CRG*(A+J-1.0D0)/(J*(B+J-1.0D0))*Z CHG=CHG+CRG IF (CDABS((CHG-CHW)/CHG).LT.1.D-15) GO TO 25 CHW=CHG 15 CONTINUE ELSE CALL GAMMA(A,G1) CALL GAMMA(B,G2) BA=B-A CALL GAMMA(BA,G3) CS1=(1.0D0,0.0D0) CS2=(1.0D0,0.0D0) CR1=(1.0D0,0.0D0) CR2=(1.0D0,0.0D0) DO 20 I=1,8 CR1=-CR1*(A+I-1.0D0)*(A-B+I)/(Z*I) CR2=CR2*(B-A+I-1.0D0)*(I-A)/(Z*I) CS1=CS1+CR1 20 CS2=CS2+CR2 X=REAL(Z) Y=DIMAG(Z) IF (X.EQ.0.0.AND.Y.GE.0.0) THEN PHI=0.5D0*PI ELSE IF (X.EQ.0.0.AND.Y.LE.0.0) THEN PHI=-0.5D0*PI ELSE PHI=DATAN(Y/X) ENDIF IF (PHI.GT.-0.5*PI.AND.PHI.LT.1.5*PI) NS=1 IF (PHI.GT.-1.5*PI.AND.PHI.LE.-0.5*PI) NS=-1 CFAC=CDEXP(NS*CI*PI*A) IF (Y.EQ.0.0D0) CFAC=DCOS(PI*A) CHG1=G2/G3*Z**(-A)*CFAC*CS1 CHG2=G2/G1*CDEXP(Z)*Z**(A-B)*CS2 CHG=CHG1+CHG2 ENDIF 25 IF (N.EQ.0) CY0=CHG IF (N.EQ.1) CY1=CHG 30 CONTINUE IF (A0.GE.2.0D0) THEN DO 35 I=1,LA-1 CHG=((2.0D0*A-B+Z)*CY1+(B-A)*CY0)/A CY0=CY1 CY1=CHG 35 A=A+1.0D0 ENDIF IF (X0.LT.0.0D0) CHG=CHG*CDEXP(-Z) ENDIF A=A1 Z=Z0 RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcerror.for000077500000000000000000000043041321604176500263000ustar00rootroot00000000000000 PROGRAM MCERROR C C ============================================================ C Purpose: This program computes the error function erf(z) C for a complex argument using subroutine CERROR C Input : x --- Real part of z C y --- Imaginary part of z ( y ó 3.0 ) C Output: ERR --- Real part of erf(z) C ERI --- Imaginary part of erf(z) C Example: C x y Re[erf(z)] Im[erf(z)] C --------------------------------------------- C 1.0 2.0 -.53664357 -5.04914370 C 2.0 2.0 1.15131087 .12729163 C 3.0 2.0 .99896328 -.00001155 C 4.0 2.0 1.00000057 -.00000051 C 5.0 2.0 1.00000000 .00000000 C ============================================================ C IMPLICIT COMPLEX *16 (C,Z) DOUBLE PRECISION X,Y WRITE(*,*)'X,Y=?' READ(*,*)X,Y WRITE(*,*)' x y Re[erf(z)] Im[erf(z)]' WRITE(*,*)' ---------------------------------------------' Z=CMPLX(X,Y) CALL CERROR(Z,CER) WRITE(*,10) Z,CER 10 FORMAT(1X,F5.1,2X,F5.1,1X,2E16.8) END SUBROUTINE CERROR(Z,CER) C C ==================================================== C Purpose: Compute error function erf(z) for a complex C argument (z=x+iy) C Input : z --- Complex argument C Output: CER --- erf(z) C ==================================================== C IMPLICIT COMPLEX *16 (C,Z) DOUBLE PRECISION A0,PI A0=CDABS(Z) C0=CDEXP(-Z*Z) PI=3.141592653589793D0 Z1=Z IF (REAL(Z).LT.0.0) THEN Z1=-Z ENDIF IF (A0.LE.5.8D0) THEN CS=Z1 CR=Z1 DO 10 K=1,120 CR=CR*Z1*Z1/(K+0.5D0) CS=CS+CR IF (CDABS(CR/CS).LT.1.0D-15) GO TO 15 10 CONTINUE 15 CER=2.0D0*C0*CS/DSQRT(PI) ELSE CL=1.0D0/Z1 CR=CL DO 20 K=1,13 CR=-CR*(K-0.5D0)/(Z1*Z1) CL=CL+CR IF (CDABS(CR/CL).LT.1.0D-15) GO TO 25 20 CONTINUE 25 CER=1.0D0-C0*CL/DSQRT(PI) ENDIF IF (REAL(Z).LT.0.0) THEN CER=-CER ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcerzo.for000077500000000000000000000113521321604176500261270ustar00rootroot00000000000000 PROGRAM MCERZO C C =============================================================== C Purpose : This program evaluates the complex zeros of error C function erf(z) using subroutine CERZO C Input: NT --- Total number of zeros C Example: NT = 10 C C n complex zeros of erf(z) n complex zeros of erf(z) C ------------------------------------------------------------------- C 1 1.450616163 + i 1.880943000 6 4.158998400 + i 4.435571444 C 2 2.244659274 + i 2.616575141 7 4.516319400 + i 4.780447644 C 3 2.839741047 + i 3.175628100 8 4.847970309 + i 5.101588043 C 4 3.335460735 + i 3.646174376 9 5.158767908 + i 5.403332643 C 5 3.769005567 + i 4.060697234 10 5.452192201 + i 5.688837437 C =============================================================== C IMPLICIT DOUBLE PRECISION (E,P,W) IMPLICIT COMPLEX *16 (C,Z) DIMENSION ZO(100) WRITE(*,*)'Please Enter NT ' READ(*,*)NT WRITE(*,20)NT CALL CERZO(NT,ZO) WRITE(*,*)' ***** Please Wait ! *****' WRITE(*,*) WRITE(*,*)' n Complex zeros of erf(z)' WRITE(*,*)'-------------------------------------' DO 10 I=1,NT 10 WRITE(*,30) I,ZO(I) 20 FORMAT(2X,'NT=',I3) 30 FORMAT(1X,I3,2X,F13.8,2X,2H+i,F13.8) END SUBROUTINE CERZO(NT,ZO) C C =============================================================== C Purpose : Evaluate the complex zeros of error function erf(z) C using the modified Newton's iteration method C Input : NT --- Total number of zeros C Output: ZO(L) --- L-th zero of erf(z), L=1,2,...,NT C Routine called: CERF for computing erf(z) and erf'(z) C =============================================================== C IMPLICIT DOUBLE PRECISION (E,P,W) IMPLICIT COMPLEX *16 (C,Z) DIMENSION ZO(NT) PI=3.141592653589793D0 DO 35 NR=1,NT PU=DSQRT(PI*(4.0D0*NR-0.5D0)) PV=PI*DSQRT(2.0D0*NR-0.25D0) PX=0.5*PU-0.5*DLOG(PV)/PU PY=0.5*PU+0.5*DLOG(PV)/PU Z=CMPLX(PX,PY) IT=0 15 IT=IT+1 CALL CERF(Z,ZF,ZD) ZP=(1.0D0,0.0D0) DO 20 I=1,NR-1 20 ZP=ZP*(Z-ZO(I)) ZFD=ZF/ZP ZQ=(0.0D0,0.0D0) DO 30 I=1,NR-1 ZW=(1.0D0,0.0D0) DO 25 J=1,NR-1 IF (J.EQ.I) GO TO 25 ZW=ZW*(Z-ZO(J)) 25 CONTINUE 30 ZQ=ZQ+ZW ZGD=(ZD-ZQ*ZFD)/ZP Z=Z-ZFD/ZGD W0=W W=CDABS(Z) IF (IT.LE.50.AND.DABS((W-W0)/W).GT.1.0D-11) GO TO 15 35 ZO(NR)=Z RETURN END SUBROUTINE CERF(Z,CER,CDER) C C ========================================================== C Purpose: Compute complex Error function erf(z) & erf'(z) C Input: z --- Complex argument of erf(z) C x --- Real part of z C y --- Imaginary part of z C Output: CER --- erf(z) C CDER --- erf'(z) C ========================================================== IMPLICIT DOUBLE PRECISION (A-H,O-Z) COMPLEX *16 Z,CER,CDER EPS=1.0D-12 PI=3.141592653589793D0 X=REAL(Z) Y=DIMAG(Z) X2=X*X IF (X.LE.3.5D0) THEN ER=1.0D0 R=1.0D0 DO 10 K=1,100 R=R*X2/(K+0.5D0) ER=ER+R IF (DABS(ER-W).LE.EPS*DABS(ER)) GO TO 15 10 W=ER 15 C0=2.0D0/DSQRT(PI)*X*DEXP(-X2) ER0=C0*ER ELSE ER=1.0D0 R=1.0D0 DO 20 K=1,12 R=-R*(K-0.5D0)/X2 20 ER=ER+R C0=DEXP(-X2)/(X*DSQRT(PI)) ER0=1.0D0-C0*ER ENDIF IF (Y.EQ.0.0D0) THEN ERR=ER0 ERI=0.0D0 ELSE CS=DCOS(2.0D0*X*Y) SS=DSIN(2.0D0*X*Y) ER1=DEXP(-X2)*(1.0D0-CS)/(2.0D0*PI*X) EI1=DEXP(-X2)*SS/(2.0D0*PI*X) ER2=0.0D0 DO 25 N=1,100 ER2=ER2+DEXP(-.25D0*N*N)/(N*N+4.0D0*X2)*(2.0D0*X & -2.0D0*X*DCOSH(N*Y)*CS+N*DSINH(N*Y)*SS) IF (DABS((ER2-W1)/ER2).LT.EPS) GO TO 30 25 W1=ER2 30 C0=2.0D0*DEXP(-X2)/PI ERR=ER0+ER1+C0*ER2 EI2=0.0D0 DO 35 N=1,100 EI2=EI2+DEXP(-.25D0*N*N)/(N*N+4.0D0*X2)*(2.0D0*X & *DCOSH(N*Y)*SS+N*DSINH(N*Y)*CS) IF (DABS((EI2-W2)/EI2).LT.EPS) GO TO 40 35 W2=EI2 40 ERI=EI1+C0*EI2 ENDIF CER=CMPLX(ERR,ERI) CDER=2.0D0/DSQRT(PI)*CDEXP(-Z*Z) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcgama.for000077500000000000000000000104351321604176500260560ustar00rootroot00000000000000 PROGRAM MCGAMA C C ========================================================== C Purpose: This program computes the gamma function â(z) C or ln[â(z)] for a complex argument using C subroutine CGAMA C Input : x --- Real part of z C y --- Imaginary part of z C KF --- Function code C KF=0 for ln[â(z)] C KF=1 for â(z) C Output: GR --- Real part of ln[â(z)] or â(z) C GI --- Imaginary part of ln[â(z)] or â(z) C Examples: C C x y Re[â(z)] Im[â(z)] C -------------------------------------------------------- C 2.50 5.00 .2267360319D-01 -.1172284404D-01 C 5.00 10.00 .1327696517D-01 .3639011746D-02 C 2.50 -5.00 .2267360319D-01 .1172284404D-01 C 5.00 -10.00 .1327696517D-01 -.3639011746D-02 C C x y Re[lnâ(z)] Im[lnâ(z)] C --------------------------------------------------------- C 2.50 5.00 -.3668103262D+01 .5806009801D+01 C 5.00 10.00 -.4285507444D+01 .1911707090D+02 C 2.50 -5.00 -.3668103262D+01 -.5806009801D+01 C 5.00 -10.00 -.4285507444D+01 -.1911707090D+02 C ========================================================== C DOUBLE PRECISION X,Y,GR,GI WRITE(*,*)' Please enter KF, x and y' READ(*,*)KF,X,Y WRITE(*,*) IF (KF.EQ.1) THEN WRITE(*,*)' x y Re[â(z)]', & ' Im[â(z)]' ELSE WRITE(*,*)' x y Re[lnâ(z)]', & ' Im[lnâ(z)]' ENDIF WRITE(*,*)' ------------------------------------', & '---------------------' CALL CGAMA(X,Y,KF,GR,GI) WRITE(*,10)X,Y,GR,GI 10 FORMAT(1X,2F10.2,2D20.10) END SUBROUTINE CGAMA(X,Y,KF,GR,GI) C C ========================================================= C Purpose: Compute the gamma function â(z) or ln[â(z)] C for a complex argument C Input : x --- Real part of z C y --- Imaginary part of z C KF --- Function code C KF=0 for ln[â(z)] C KF=1 for â(z) C Output: GR --- Real part of ln[â(z)] or â(z) C GI --- Imaginary part of ln[â(z)] or â(z) C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(10) PI=3.141592653589793D0 DATA A/8.333333333333333D-02,-2.777777777777778D-03, & 7.936507936507937D-04,-5.952380952380952D-04, & 8.417508417508418D-04,-1.917526917526918D-03, & 6.410256410256410D-03,-2.955065359477124D-02, & 1.796443723688307D-01,-1.39243221690590D+00/ IF (Y.EQ.0.0D0.AND.X.EQ.INT(X).AND.X.LE.0.0D0) THEN GR=1.0D+300 GI=0.0D0 RETURN ELSE IF (X.LT.0.0D0) THEN X1=X Y1=Y X=-X Y=-Y ENDIF X0=X IF (X.LE.7.0) THEN NA=INT(7-X) X0=X+NA ENDIF Z1=DSQRT(X0*X0+Y*Y) TH=DATAN(Y/X0) GR=(X0-.5D0)*DLOG(Z1)-TH*Y-X0+0.5D0*DLOG(2.0D0*PI) GI=TH*(X0-0.5D0)+Y*DLOG(Z1)-Y DO 10 K=1,10 T=Z1**(1-2*K) GR=GR+A(K)*T*DCOS((2.0D0*K-1.0D0)*TH) 10 GI=GI-A(K)*T*DSIN((2.0D0*K-1.0D0)*TH) IF (X.LE.7.0) THEN GR1=0.0D0 GI1=0.0D0 DO 15 J=0,NA-1 GR1=GR1+.5D0*DLOG((X+J)**2+Y*Y) 15 GI1=GI1+DATAN(Y/(X+J)) GR=GR-GR1 GI=GI-GI1 ENDIF IF (X1.LT.0.0D0) THEN Z1=DSQRT(X*X+Y*Y) TH1=DATAN(Y/X) SR=-DSIN(PI*X)*DCOSH(PI*Y) SI=-DCOS(PI*X)*DSINH(PI*Y) Z2=DSQRT(SR*SR+SI*SI) TH2=DATAN(SI/SR) IF (SR.LT.0.0D0) TH2=PI+TH2 GR=DLOG(PI/(Z1*Z2))-GR GI=-TH1-TH2-GI X=X1 Y=Y1 ENDIF IF (KF.EQ.1) THEN G0=DEXP(GR) GR=G0*DCOS(GI) GI=G0*DSIN(GI) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mch12n.for000077500000000000000000000330061321604176500257200ustar00rootroot00000000000000 PROGRAM MCH12N C C ===================================================== C Purpose: This program computes Hankel functions of C the first and second kinds and their C derivatives for a complex argument using C subroutine CH12N C Input : z --- Complex argument C n --- Order of Hn(1)(z) and Hn(2)(z) C ( n = 0,1,úúú, n ó 250 ) C Output: CHF1(n) --- Hn(1)(z) C CHD1(n) --- Hn(1)'(z) C CHF2(n) --- Hn(2)(z) C CHD2(n) --- Hn(2)'(z) C ===================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CHF1(0:250),CHD1(0:250),CHF2(0:250),CHD2(0:250) WRITE(*,*)' Please enter n, x and y (z=x+iy) ' READ(*,*)N,X,Y WRITE(*,45)X,Y,N Z=CMPLX(X,Y) IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL CH12N(N,Z,NM,CHF1,CHD1,CHF2,CHD2) WRITE(*,*) WRITE(*,*)' n Re[Hn(1)(z)] Im[Hn(1)(z)]', & ' Re[Hn(1)''(z)] Im[Hn(1)''(z)]' WRITE(*,*)' -------------------------------------', & '---------------------------------------' DO 30 K=0,NM,NS 30 WRITE(*,40)K,CHF1(K),CHD1(K) WRITE(*,*) WRITE(*,*)' n Re[Hn(2)(z)] Im[Hn(2)(z)]', & ' Re[Hn(2)''(z)] Im[Hn(2)''(z)]' WRITE(*,*)' -------------------------------------', & '---------------------------------------' DO 35 K=0,NM,NS 35 WRITE(*,40)K,CHF2(K),CHD2(K) 40 FORMAT(1X,I4,4D18.10) 45 FORMAT(3X,3Hz =,F8.3,' + i ',F8.3,' ,',6X,6HNmax =,I4) END SUBROUTINE CH12N(N,Z,NM,CHF1,CHD1,CHF2,CHD2) C C ==================================================== C Purpose: Compute Hankel functions of the first and C second kinds and their derivatives for a C complex argument C Input : z --- Complex argument C n --- Order of Hn(1)(z) and Hn(2)(z) C Output: CHF1(n) --- Hn(1)(z) C CHD1(n) --- Hn(1)'(z) C CHF2(n) --- Hn(2)(z) C CHD2(n) --- Hn(2)'(z) C NM --- Highest order computed C Routines called: C (1) CJYNB for computing Jn(z) and Yn(z) C (2) CIKNB for computing In(z) and Kn(z) C ==================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBJ(0:250),CDJ(0:250),CBY(0:250),CDY(0:250), & CBI(0:250),CDI(0:250),CBK(0:250),CDK(0:250) DIMENSION CHF1(0:N),CHD1(0:N),CHF2(0:N),CHD2(0:N) CI=(0.0D0,1.0D0) PI=3.141592653589793D0 IF (DIMAG(Z).LT.0.0D0) THEN CALL CJYNB(N,Z,NM,CBJ,CDJ,CBY,CDY) DO 10 K=0,NM CHF1(K)=CBJ(K)+CI*CBY(K) 10 CHD1(K)=CDJ(K)+CI*CDY(K) ZI=CI*Z CALL CIKNB(N,ZI,NM,CBI,CDI,CBK,CDK) CFAC=-2.0D0/(PI*CI) DO 15 K=0,NM CHF2(K)=CFAC*CBK(K) CHD2(K)=CFAC*CI*CDK(K) 15 CFAC=CFAC*CI ELSE IF (DIMAG(Z).GT.0.0D0) THEN ZI=-CI*Z CALL CIKNB(N,ZI,NM,CBI,CDI,CBK,CDK) CF1=-CI CFAC=2.0D0/(PI*CI) DO 20 K=0,NM CHF1(K)=CFAC*CBK(K) CHD1(K)=-CFAC*CI*CDK(K) 20 CFAC=CFAC*CF1 CALL CJYNB(N,Z,NM,CBJ,CDJ,CBY,CDY) DO 25 K=0,NM CHF2(K)=CBJ(K)-CI*CBY(K) 25 CHD2(K)=CDJ(K)-CI*CDY(K) ELSE CALL CJYNB(N,Z,NM,CBJ,CDJ,CBY,CDY) DO 30 K=0,NM CHF1(K)=CBJ(K)+CI*CBY(K) CHD1(K)=CDJ(K)+CI*CDY(K) CHF2(K)=CBJ(K)-CI*CBY(K) 30 CHD2(K)=CDJ(K)-CI*CDY(K) ENDIF RETURN END SUBROUTINE CJYNB(N,Z,NM,CBJ,CDJ,CBY,CDY) C C ======================================================= C Purpose: Compute Bessel functions Jn(z), Yn(z) and C their derivatives for a complex argument C Input : z --- Complex argument of Jn(z) and Yn(z) C n --- Order of Jn(z) and Yn(z) C Output: CBJ(n) --- Jn(z) C CDJ(n) --- Jn'(z) C CBY(n) --- Yn(z) C CDY(n) --- Yn'(z) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 to calculate the starting C point for backward recurrence C ======================================================= C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBJ(0:N),CDJ(0:N),CBY(0:N),CDY(0:N), & A(4),B(4),A1(4),B1(4) EL=0.5772156649015329D0 PI=3.141592653589793D0 R2P=.63661977236758D0 Y0=DABS(DIMAG(Z)) A0=CDABS(Z) NM=N IF (A0.LT.1.0D-100) THEN DO 10 K=0,N CBJ(K)=(0.0D0,0.0D0) CDJ(K)=(0.0D0,0.0D0) CBY(K)=-(1.0D+300,0.0D0) 10 CDY(K)=(1.0D+300,0.0D0) CBJ(0)=(1.0D0,0.0D0) CDJ(1)=(0.5D0,0.0D0) RETURN ENDIF IF (A0.LE.300.D0.OR.N.GT.80) THEN IF (N.EQ.0) NM=1 M=MSTA1(A0,200) IF (M.LT.NM) THEN NM=M ELSE M=MSTA2(A0,NM,15) ENDIF CBS=(0.0D0,0.0D0) CSU=(0.0D0,0.0D0) CSV=(0.0D0,0.0D0) CF2=(0.0D0,0.0D0) CF1=(1.0D-100,0.0D0) DO 15 K=M,0,-1 CF=2.0D0*(K+1.0D0)/Z*CF1-CF2 IF (K.LE.NM) CBJ(K)=CF IF (K.EQ.2*INT(K/2).AND.K.NE.0) THEN IF (Y0.LE.1.0D0) THEN CBS=CBS+2.0D0*CF ELSE CBS=CBS+(-1)**(K/2)*2.0D0*CF ENDIF CSU=CSU+(-1)**(K/2)*CF/K ELSE IF (K.GT.1) THEN CSV=CSV+(-1)**(K/2)*K/(K*K-1.0D0)*CF ENDIF CF2=CF1 15 CF1=CF IF (Y0.LE.1.0D0) THEN CS0=CBS+CF ELSE CS0=(CBS+CF)/CDCOS(Z) ENDIF DO 20 K=0,NM 20 CBJ(K)=CBJ(K)/CS0 CE=CDLOG(Z/2.0D0)+EL CBY(0)=R2P*(CE*CBJ(0)-4.0D0*CSU/CS0) CBY(1)=R2P*(-CBJ(0)/Z+(CE-1.0D0)*CBJ(1)-4.0D0*CSV/CS0) ELSE DATA A/-.7031250000000000D-01,.1121520996093750D+00, & -.5725014209747314D+00,.6074042001273483D+01/ DATA B/ .7324218750000000D-01,-.2271080017089844D+00, & .1727727502584457D+01,-.2438052969955606D+02/ DATA A1/.1171875000000000D+00,-.1441955566406250D+00, & .6765925884246826D+00,-.6883914268109947D+01/ DATA B1/-.1025390625000000D+00,.2775764465332031D+00, & -.1993531733751297D+01,.2724882731126854D+02/ CT1=Z-0.25D0*PI CP0=(1.0D0,0.0D0) DO 25 K=1,4 25 CP0=CP0+A(K)*Z**(-2*K) CQ0=-0.125D0/Z DO 30 K=1,4 30 CQ0=CQ0+B(K)*Z**(-2*K-1) CU=CDSQRT(R2P/Z) CBJ0=CU*(CP0*CDCOS(CT1)-CQ0*CDSIN(CT1)) CBY0=CU*(CP0*CDSIN(CT1)+CQ0*CDCOS(CT1)) CBJ(0)=CBJ0 CBY(0)=CBY0 CT2=Z-0.75D0*PI CP1=(1.0D0,0.0D0) DO 35 K=1,4 35 CP1=CP1+A1(K)*Z**(-2*K) CQ1=0.375D0/Z DO 40 K=1,4 40 CQ1=CQ1+B1(K)*Z**(-2*K-1) CBJ1=CU*(CP1*CDCOS(CT2)-CQ1*CDSIN(CT2)) CBY1=CU*(CP1*CDSIN(CT2)+CQ1*CDCOS(CT2)) CBJ(1)=CBJ1 CBY(1)=CBY1 DO 45 K=2,NM CBJK=2.0D0*(K-1.0D0)/Z*CBJ1-CBJ0 CBJ(K)=CBJK CBJ0=CBJ1 45 CBJ1=CBJK ENDIF CDJ(0)=-CBJ(1) DO 50 K=1,NM 50 CDJ(K)=CBJ(K-1)-K/Z*CBJ(K) IF (CDABS(CBJ(0)).GT.1.0D0) THEN CBY(1)=(CBJ(1)*CBY(0)-2.0D0/(PI*Z))/CBJ(0) ENDIF DO 55 K=2,NM IF (CDABS(CBJ(K-1)).GE.CDABS(CBJ(K-2))) THEN CYY=(CBJ(K)*CBY(K-1)-2.0D0/(PI*Z))/CBJ(K-1) ELSE CYY=(CBJ(K)*CBY(K-2)-4.0D0*(K-1.0D0)/(PI*Z*Z))/CBJ(K-2) ENDIF CBY(K)=CYY 55 CONTINUE CDY(0)=-CBY(1) DO 60 K=1,NM 60 CDY(K)=CBY(K-1)-K/Z*CBY(K) RETURN END SUBROUTINE CIKNB(N,Z,NM,CBI,CDI,CBK,CDK) C C ============================================================ C Purpose: Compute modified Bessel functions In(z) and Kn(z), C and their derivatives for a complex argument C Input: z --- Complex argument C n --- Order of In(z) and Kn(z) C Output: CBI(n) --- In(z) C CDI(n) --- In'(z) C CBK(n) --- Kn(z) C CDK(n) --- Kn'(z) C NM --- Highest order computed C Routones called: C MSTA1 and MSTA2 to compute the starting point for C backward recurrence C =========================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBI(0:N),CDI(0:N),CBK(0:N),CDK(0:N) PI=3.141592653589793D0 EL=0.57721566490153D0 A0=CDABS(Z) NM=N IF (A0.LT.1.0D-100) THEN DO 10 K=0,N CBI(K)=(0.0D0,0.0D0) CBK(K)=(1.0D+300,0.0D0) CDI(K)=(0.0D0,0.0D0) 10 CDK(K)=-(1.0D+300,0.0D0) CBI(0)=(1.0D0,0.0D0) CDI(1)=(0.5D0,0.0D0) RETURN ENDIF Z1=Z CI=(0.0D0,1.0D0) IF (REAL(Z).LT.0.0) Z1=-Z IF (N.EQ.0) NM=1 M=MSTA1(A0,200) IF (M.LT.NM) THEN NM=M ELSE M=MSTA2(A0,NM,15) ENDIF CBS=0.0D0 CSK0=0.0D0 CF0=0.0D0 CF1=1.0D-100 DO 15 K=M,0,-1 CF=2.0D0*(K+1.0D0)*CF1/Z1+CF0 IF (K.LE.NM) CBI(K)=CF IF (K.NE.0.AND.K.EQ.2*INT(K/2)) CSK0=CSK0+4.0D0*CF/K CBS=CBS+2.0D0*CF CF0=CF1 15 CF1=CF CS0=CDEXP(Z1)/(CBS-CF) DO 20 K=0,NM 20 CBI(K)=CS0*CBI(K) IF (A0.LE.9.0) THEN CBK(0)=-(CDLOG(0.5D0*Z1)+EL)*CBI(0)+CS0*CSK0 CBK(1)=(1.0D0/Z1-CBI(1)*CBK(0))/CBI(0) ELSE CA0=CDSQRT(PI/(2.0D0*Z1))*CDEXP(-Z1) K0=16 IF (A0.GE.25.0) K0=10 IF (A0.GE.80.0) K0=8 IF (A0.GE.200.0) K0=6 DO 30 L=0,1 CBKL=1.0D0 VT=4.0D0*L CR=(1.0D0,0.0D0) DO 25 K=1,K0 CR=0.125D0*CR*(VT-(2.0*K-1.0)**2)/(K*Z1) 25 CBKL=CBKL+CR CBK(L)=CA0*CBKL 30 CONTINUE ENDIF CG0=CBK(0) CG1=CBK(1) DO 35 K=2,NM CG=2.0D0*(K-1.0D0)/Z1*CG1+CG0 CBK(K)=CG CG0=CG1 35 CG1=CG IF (REAL(Z).LT.0.0) THEN FAC=1.0D0 DO 45 K=0,NM IF (DIMAG(Z).LT.0.0) THEN CBK(K)=FAC*CBK(K)+CI*PI*CBI(K) ELSE CBK(K)=FAC*CBK(K)-CI*PI*CBI(K) ENDIF CBI(K)=FAC*CBI(K) FAC=-FAC 45 CONTINUE ENDIF CDI(0)=CBI(1) CDK(0)=-CBK(1) DO 50 K=1,NM CDI(K)=CBI(K-1)-K/Z*CBI(K) 50 CDK(K)=-CBK(K-1)-K/Z*CBK(K) RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mchgm.for000077500000000000000000000133711321604176500257260ustar00rootroot00000000000000 PROGRAM MCHGM C C ======================================================= C Purpose: This program computes the confluent C hypergeometric function M(a,b,x) using C subroutine CHGM C Input : a --- Parameter C b --- Parameter ( b <> 0,-1,-2,... ) C x --- Argument C Output: HG --- M(a,b,x) C Example: C a b x M(a,b,x) C ----------------------------------------- C 1.5 2.0 20.0 .1208527185D+09 C 4.5 2.0 20.0 .1103561117D+12 C -1.5 2.0 20.0 .1004836854D+05 C -4.5 2.0 20.0 -.3936045244D+03 C 1.5 2.0 50.0 .8231906643D+21 C 4.5 2.0 50.0 .9310512715D+25 C -1.5 2.0 50.0 .2998660728D+16 C -4.5 2.0 50.0 -.1806547113D+13 C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter a, b and x ' READ(*,*)A,B,X WRITE(*,*)' a b x M(a,b,x)' WRITE(*,*)' -----------------------------------------' CALL CHGM(A,B,X,HG) WRITE(*,10)A,B,X,HG 10 FORMAT(1X,F5.1,3X,F5.1,3X,F5.1,D20.10) END SUBROUTINE CHGM(A,B,X,HG) C C =================================================== C Purpose: Compute confluent hypergeometric function C M(a,b,x) C Input : a --- Parameter C b --- Parameter ( b <> 0,-1,-2,... ) C x --- Argument C Output: HG --- M(a,b,x) C Routine called: GAMMA for computing â(x) C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 A0=A A1=A X0=X HG=0.0D0 IF (B.EQ.0.0D0.OR.B.EQ.-ABS(INT(B))) THEN HG=1.0D+300 ELSE IF (A.EQ.0.0D0.OR.X.EQ.0.0D0) THEN HG=1.0D0 ELSE IF (A.EQ.-1.0D0) THEN HG=1.0D0-X/B ELSE IF (A.EQ.B) THEN HG=DEXP(X) ELSE IF (A-B.EQ.1.0D0) THEN HG=(1.0D0+X/B)*DEXP(X) ELSE IF (A.EQ.1.0D0.AND.B.EQ.2.0D0) THEN HG=(DEXP(X)-1.0D0)/X ELSE IF (A.EQ.INT(A).AND.A.LT.0.0D0) THEN M=INT(-A) R=1.0D0 HG=1.0D0 DO 10 K=1,M R=R*(A+K-1.0D0)/K/(B+K-1.0D0)*X 10 HG=HG+R ENDIF IF (HG.NE.0.0D0) RETURN IF (X.LT.0.0D0) THEN A=B-A A0=A X=DABS(X) ENDIF IF (A.LT.2.0D0) NL=0 IF (A.GE.2.0D0) THEN NL=1 LA=INT(A) A=A-LA-1.0D0 ENDIF DO 30 N=0,NL IF (A0.GE.2.0D0) A=A+1.0D0 IF (X.LE.30.0D0+DABS(B).OR.A.LT.0.0D0) THEN HG=1.0D0 RG=1.0D0 DO 15 J=1,500 RG=RG*(A+J-1.0D0)/(J*(B+J-1.0D0))*X HG=HG+RG IF (DABS(RG/HG).LT.1.0D-15) GO TO 25 15 CONTINUE ELSE CALL GAMMA(A,TA) CALL GAMMA(B,TB) XG=B-A CALL GAMMA(XG,TBA) SUM1=1.0D0 SUM2=1.0D0 R1=1.0D0 R2=1.0D0 DO 20 I=1,8 R1=-R1*(A+I-1.0D0)*(A-B+I)/(X*I) R2=-R2*(B-A+I-1.0D0)*(A-I)/(X*I) SUM1=SUM1+R1 20 SUM2=SUM2+R2 HG1=TB/TBA*X**(-A)*DCOS(PI*A)*SUM1 HG2=TB/TA*DEXP(X)*X**(A-B)*SUM2 HG=HG1+HG2 ENDIF 25 IF (N.EQ.0) Y0=HG IF (N.EQ.1) Y1=HG 30 CONTINUE IF (A0.GE.2.0D0) THEN DO 35 I=1,LA-1 HG=((2.0D0*A-B+X)*Y1+(B-A)*Y0)/A Y0=Y1 Y1=HG 35 A=A+1.0D0 ENDIF IF (X0.LT.0.0D0) HG=HG*DEXP(X0) A=A1 X=X0 RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mchgu.for000077500000000000000000000405461321604176500257420ustar00rootroot00000000000000 PROGRAM MCHGU C C ======================================================= C Purpose: This program computes the confluent C hypergeometric function U(a,b,x) using C subroutine CHGU C Input : a --- Parameter C b --- Parameter C x --- Argument ( x ò 0 ) C Output: HU --- U(a,b,x) C MD --- Method code C Example: C a b x U(a,b,x) C -------------------------------------- C -2.5 2.5 5.0 -9.02812446 C -1.5 2.5 5.0 2.15780560 C -.5 2.5 5.0 1.76649370 C .0 2.5 5.0 1.00000000 C .5 2.5 5.0 .49193496 C 1.5 2.5 5.0 .08944272 C 2.5 2.5 5.0 .01239387 C C a b x U(a,b,x) C -------------------------------------- C -2.5 5.0 10.0 -2.31982196 C -1.5 5.0 10.0 8.65747115 C -.5 5.0 10.0 2.37997143 C .0 5.0 10.0 1.00000000 C .5 5.0 10.0 .38329536 C 1.5 5.0 10.0 .04582817 C 2.5 5.0 10.0 .00444535 C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Pleas enter a, b and x ' READ(*,*)A,B,X WRITE(*,*)' a b x U(a,b,x)' WRITE(*,*)'--------------------------------------' CALL CHGU(A,B,X,HU,MD) WRITE(*,10)A,B,X,HU 10 FORMAT(1X,F5.1,3X,F5.1,3X,F5.1,E15.8) END SUBROUTINE CHGU(A,B,X,HU,MD) C C ======================================================= C Purpose: Compute the confluent hypergeometric function C U(a,b,x) C Input : a --- Parameter C b --- Parameter C x --- Argument ( x > 0 ) C Output: HU --- U(a,b,x) C MD --- Method code C Routines called: C (1) CHGUS for small x ( MD=1 ) C (2) CHGUL for large x ( MD=2 ) C (3) CHGUBI for integer b ( MD=3 ) C (4) CHGUIT for numerical integration ( MD=4 ) C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) LOGICAL IL1,IL2,IL3,BL1,BL2,BL3,BN AA=A-B+1.0D0 IL1=A.EQ.INT(A).AND.A.LE.0.0 IL2=AA.EQ.INT(AA).AND.AA.LE.0.0 IL3=ABS(A*(A-B+1.0))/X.LE.2.0 BL1=X.LE.5.0.OR.(X.LE.10.0.AND.A.LE.2.0) BL2=(X.GT.5.0.AND.X.LE.12.5).AND.(A.GE.1.0.AND.B.GE.A+4.0) BL3=X.GT.12.5.AND.A.GE.5.0.AND.B.GE.A+5.0 BN=B.EQ.INT(B).AND.B.NE.0.0 ID1=-100 IF (B.NE.INT(B)) THEN CALL CHGUS(A,B,X,HU,ID1) MD=1 IF (ID1.GE.6) RETURN HU1=HU ENDIF IF (IL1.OR.IL2.OR.IL3) THEN CALL CHGUL(A,B,X,HU,ID) MD=2 IF (ID.GE.6) RETURN IF (ID1.GT.ID) THEN MD=1 ID=ID1 HU=HU1 ENDIF ENDIF IF (A.GE.0.0) THEN IF (BN.AND.(BL1.OR.BL2.OR.BL3)) THEN CALL CHGUBI(A,B,X,HU,ID) MD=3 ELSE CALL CHGUIT(A,B,X,HU,ID) MD=4 ENDIF ELSE IF (B.LE.A) THEN A00=A B00=B A=A-B+1.0D0 B=2.0D0-B CALL CHGUIT(A,B,X,HU,ID) HU=X**(1.0D0-B00)*HU A=A00 B=B00 MD=4 ELSE IF (BN.AND.(.NOT.IL1)) THEN CALL CHGUBI(A,B,X,HU,ID) MD=3 ENDIF ENDIF IF (ID.LT.6) WRITE(*,*)'No accurate result obtained' RETURN END SUBROUTINE CHGUS(A,B,X,HU,ID) C C ====================================================== C Purpose: Compute confluent hypergeometric function C U(a,b,x) for small argument x C Input : a --- Parameter C b --- Parameter ( b <> 0,-1,-2,...) C x --- Argument C Output: HU --- U(a,b,x) C ID --- Estimated number of significant digits C Routine called: GAMMA for computing gamma function C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) ID=-100 PI=3.141592653589793D0 CALL GAMMA(A,GA) CALL GAMMA(B,GB) XG1=1.0D0+A-B CALL GAMMA(XG1,GAB) XG2=2.0D0-B CALL GAMMA(XG2,GB2) HU0=PI/DSIN(PI*B) R1=HU0/(GAB*GB) R2=HU0*X**(1.0D0-B)/(GA*GB2) HU=R1-R2 HMAX=0.0D0 HMIN=1.0D+300 DO 10 J=1,150 R1=R1*(A+J-1.0D0)/(J*(B+J-1.0D0))*X R2=R2*(A-B+J)/(J*(1.0D0-B+J))*X HU=HU+R1-R2 HUA=DABS(HU) IF (HUA.GT.HMAX) HMAX=HUA IF (HUA.LT.HMIN) HMIN=HUA IF (DABS(HU-H0).LT.DABS(HU)*1.0D-15) GO TO 15 10 H0=HU 15 D1=LOG10(HMAX) IF (HMIN.NE.0.0) D2=LOG10(HMIN) ID=15-ABS(D1-D2) RETURN END SUBROUTINE CHGUL(A,B,X,HU,ID) C C ======================================================= C Purpose: Compute the confluent hypergeometric function C U(a,b,x) for large argument x C Input : a --- Parameter C b --- Parameter C x --- Argument C Output: HU --- U(a,b,x) C ID --- Estimated number of significant digits C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) LOGICAL IL1,IL2 ID=-100 AA=A-B+1.0D0 IL1=A.EQ.INT(A).AND.A.LE.0.0 IL2=AA.EQ.INT(AA).AND.AA.LE.0.0 IF (IL1) NM=ABS(A) IF (IL2) NM=ABS(AA) IF (IL1.OR.IL2) THEN HU=1.0D0 R=1.0D0 DO 10 K=1,NM R=-R*(A+K-1.0D0)*(A-B+K)/(K*X) HU=HU+R 10 CONTINUE HU=X**(-A)*HU ID=10 ELSE HU=1.0D0 R=1.0D0 DO 15 K=1,25 R=-R*(A+K-1.0D0)*(A-B+K)/(K*X) RA=DABS(R) IF (K.GT.5.AND.RA.GE.R0.OR.RA.LT.1.0D-15) GO TO 20 R0=RA 15 HU=HU+R 20 ID=ABS(LOG10(RA)) HU=X**(-A)*HU ENDIF RETURN END SUBROUTINE CHGUBI(A,B,X,HU,ID) C C ====================================================== C Purpose: Compute confluent hypergeometric function C U(a,b,x) with integer b ( b = ñ1,ñ2,... ) C Input : a --- Parameter C b --- Parameter C x --- Argument C Output: HU --- U(a,b,x) C ID --- Estimated number of significant digits C Routines called: C (1) GAMMA for computing gamma function â(x) C (2) PSI for computing psi function C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) ID=-100 EL=0.5772156649015329D0 N=ABS(B-1) RN1=1.0D0 RN=1.0D0 DO 10 J=1,N RN=RN*J IF (J.EQ.N-1) RN1=RN 10 CONTINUE CALL PSI(A,PS) CALL GAMMA(A,GA) IF (B.GT.0.0) THEN A0=A A1=A-N A2=A1 CALL GAMMA(A1,GA1) UA=(-1)**(N-1)/(RN*GA1) UB=RN1/GA*X**(-N) ELSE A0=A+N A1=A0 A2=A CALL GAMMA(A1,GA1) UA=(-1)**(N-1)/(RN*GA)*X**N UB=RN1/GA1 ENDIF HM1=1.0D0 R=1.0D0 HMAX=0.0D0 HMIN=1.0D+300 DO 15 K=1,150 R=R*(A0+K-1.0D0)*X/((N+K)*K) HM1=HM1+R HU1=DABS(HM1) IF (HU1.GT.HMAX) HMAX=HU1 IF (HU1.LT.HMIN) HMIN=HU1 IF (DABS(HM1-H0).LT.DABS(HM1)*1.0D-15) GO TO 20 15 H0=HM1 20 DA1=LOG10(HMAX) IF (HMIN.NE.0.0) DA2=LOG10(HMIN) ID=15-ABS(DA1-DA2) HM1=HM1*DLOG(X) S0=0.0D0 DO 25 M=1,N IF (B.GE.0.0) S0=S0-1.0D0/M 25 IF (B.LT.0.0) S0=S0+(1.0D0-A)/(M*(A+M-1.0D0)) HM2=PS+2.0D0*EL+S0 R=1.0D0 HMAX=0.0D0 HMIN=1.0D+300 DO 50 K=1,150 S1=0.0D0 S2=0.0D0 IF (B.GT.0.0) THEN DO 30 M=1,K 30 S1=S1-(M+2.0D0*A-2.0D0)/(M*(M+A-1.0D0)) DO 35 M=1,N 35 S2=S2+1.0D0/(K+M) ELSE DO 40 M=1,K+N 40 S1=S1+(1.0D0-A)/(M*(M+A-1.0D0)) DO 45 M=1,K 45 S2=S2+1.0D0/M ENDIF HW=2.0D0*EL+PS+S1-S2 R=R*(A0+K-1.0D0)*X/((N+K)*K) HM2=HM2+R*HW HU2=DABS(HM2) IF (HU2.GT.HMAX) HMAX=HU2 IF (HU2.LT.HMIN) HMIN=HU2 IF (DABS((HM2-H0)/HM2).LT.1.0D-15) GO TO 55 50 H0=HM2 55 DB1=LOG10(HMAX) IF (HMIN.NE.0.0) DB2=LOG10(HMIN) ID1=15-ABS(DB1-DB2) IF (ID1.LT.ID) ID=ID1 HM3=1.0D0 IF (N.EQ.0) HM3=0.0D0 R=1.0D0 DO 60 K=1,N-1 R=R*(A2+K-1.0D0)/((K-N)*K)*X 60 HM3=HM3+R SA=UA*(HM1+HM2) SB=UB*HM3 HU=SA+SB IF (SA.NE.0.0) ID1=INT(LOG10(ABS(SA))) IF (HU.NE.0.0) ID2=INT(LOG10(ABS(HU))) IF (SA*SB.LT.0.0) ID=ID-ABS(ID1-ID2) RETURN END SUBROUTINE CHGUIT(A,B,X,HU,ID) C C ====================================================== C Purpose: Compute hypergeometric function U(a,b,x) by C using Gaussian-Legendre integration (n=60) C Input : a --- Parameter ( a > 0 ) C b --- Parameter C x --- Argument ( x > 0 ) C Output: HU --- U(a,b,z) C ID --- Estimated number of significant digits C Routine called: GAMMA for computing â(x) C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION T(30),W(30) DATA T/ .259597723012478D-01, .778093339495366D-01, & .129449135396945D+00, .180739964873425D+00, & .231543551376029D+00, .281722937423262D+00, & .331142848268448D+00, .379670056576798D+00, & .427173741583078D+00, .473525841761707D+00, & .518601400058570D+00, .562278900753945D+00, & .604440597048510D+00, .644972828489477D+00, & .683766327381356D+00, .720716513355730D+00, & .755723775306586D+00, .788693739932264D+00, & .819537526162146D+00, .848171984785930D+00, & .874519922646898D+00, .898510310810046D+00, & .920078476177628D+00, .939166276116423D+00, & .955722255839996D+00, .969701788765053D+00, & .981067201752598D+00, .989787895222222D+00, & .995840525118838D+00, .999210123227436D+00/ DATA W/ .519078776312206D-01, .517679431749102D-01, & .514884515009810D-01, .510701560698557D-01, & .505141845325094D-01, .498220356905502D-01, & .489955754557568D-01, .480370318199712D-01, & .469489888489122D-01, .457343797161145D-01, & .443964787957872D-01, .429388928359356D-01, & .413655512355848D-01, .396806954523808D-01, & .378888675692434D-01, .359948980510845D-01, & .340038927249464D-01, .319212190192963D-01, & .297524915007890D-01, .275035567499248D-01, & .251804776215213D-01, .227895169439978D-01, & .203371207294572D-01, .178299010142074D-01, & .152746185967848D-01, .126781664768159D-01, & .100475571822880D-01, .738993116334531D-02, & .471272992695363D-02, .202681196887362D-02/ ID=7 A1=A-1.0D0 B1=B-A-1.0D0 C=12.0/X DO 20 M=10,100,5 HU1=0.0D0 G=0.5D0*C/M D=G DO 15 J=1,M S=0.0D0 DO 10 K=1,30 T1=D+G*T(K) T2=D-G*T(K) F1=DEXP(-X*T1)*T1**A1*(1.0D0+T1)**B1 F2=DEXP(-X*T2)*T2**A1*(1.0D0+T2)**B1 S=S+W(K)*(F1+F2) 10 CONTINUE HU1=HU1+S*G D=D+2.0D0*G 15 CONTINUE IF (DABS(1.0D0-HU0/HU1).LT.1.0D-7) GO TO 25 HU0=HU1 20 CONTINUE 25 CALL GAMMA(A,GA) HU1=HU1/GA DO 40 M=2,10,2 HU2=0.0D0 G=0.5D0/M D=G DO 35 J=1,M S=0.0D0 DO 30 K=1,30 T1=D+G*T(K) T2=D-G*T(K) T3=C/(1.0D0-T1) T4=C/(1.0D0-T2) F1=T3*T3/C*DEXP(-X*T3)*T3**A1*(1.0D0+T3)**B1 F2=T4*T4/C*DEXP(-X*T4)*T4**A1*(1.0D0+T4)**B1 S=S+W(K)*(F1+F2) 30 CONTINUE HU2=HU2+S*G D=D+2.0D0*G 35 CONTINUE IF (DABS(1.0D0-HU0/HU2).LT.1.0D-7) GO TO 45 HU0=HU2 40 CONTINUE 45 CALL GAMMA(A,GA) HU2=HU2/GA HU=HU1+HU2 RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END SUBROUTINE PSI(X,PS) C C ====================================== C Purpose: Compute Psi function C Input : x --- Argument of psi(x) C Output: PS --- psi(x) C ====================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) XA=DABS(X) PI=3.141592653589793D0 EL=.5772156649015329D0 S=0.0D0 IF (X.EQ.INT(X).AND.X.LE.0.0) THEN PS=1.0D+300 RETURN ELSE IF (XA.EQ.INT(XA)) THEN N=XA DO 10 K=1 ,N-1 10 S=S+1.0D0/K PS=-EL+S ELSE IF (XA+.5.EQ.INT(XA+.5)) THEN N=XA-.5 DO 20 K=1,N 20 S=S+1.0/(2.0D0*K-1.0D0) PS=-EL+2.0D0*S-1.386294361119891D0 ELSE IF (XA.LT.10.0) THEN N=10-INT(XA) DO 30 K=0,N-1 30 S=S+1.0D0/(XA+K) XA=XA+N ENDIF X2=1.0D0/(XA*XA) A1=-.8333333333333D-01 A2=.83333333333333333D-02 A3=-.39682539682539683D-02 A4=.41666666666666667D-02 A5=-.75757575757575758D-02 A6=.21092796092796093D-01 A7=-.83333333333333333D-01 A8=.4432598039215686D0 PS=DLOG(XA)-.5D0/XA+X2*(((((((A8*X2+A7)*X2+ & A6)*X2+A5)*X2+A4)*X2+A3)*X2+A2)*X2+A1) PS=PS-S ENDIF IF (X.LT.0.0) PS=PS-PI*DCOS(PI*X)/DSIN(PI*X)-1.0D0/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcik01.for000077500000000000000000000142411321604176500257140ustar00rootroot00000000000000 PROGRAM MCIK01 C C ============================================================= C Purpose: This program computes the modified Bessel functions C I0(z), I1(z), K0(z), K1(z), and their derivatives C for a complex argument using subroutine CIK01 C Input : z --- Complex argument C Output: CBI0 --- I0(z) C CDI0 --- I0'(z) C CBI1 --- I1(z) C CDI1 --- I1'(z) C CBK0 --- K0(z) C CDK0 --- K0'(z) C CBK1 --- K1(z) C CDK1 --- K1'(z) C Example: z = 20.0 + i 10.0 C C n Re[In(z)] Im[In(z)] Re[In'(z)] Im[In'(z)] C ----------------------------------------------------------------- C 0 -.38773811D+08 -.13750292D+08 -.37852037D+08 -.13869150D+08 C 1 -.37852037D+08 -.13869150D+08 -.36982347D+08 -.13952566D+08 C C n Re[Kn(z)] Im[Kn(z)] Re[Kn'(z)] Im[Kn'(z)] C ----------------------------------------------------------------- C 0 -.37692389D-09 .39171613D-09 .38056380D-09 -.40319029D-09 C 1 -.38056380D-09 .40319029D-09 .38408264D-09 -.41545502D-09 C ============================================================= C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX*16 (C,Z) WRITE(*,*)' Please enter x and y (z=x+iy) ' READ(*,*)X,Y Z=CMPLX(X,Y) WRITE(*,30)X,Y CALL CIK01(Z,CBI0,CDI0,CBI1,CDI1,CBK0,CDK0,CBK1,CDK1) WRITE(*,*) WRITE(*,*)' n Re[In(z)] Im[In(z)]', & ' Re[In''(z)] Im[In''(z)]' WRITE(*,*)' -------------------------------', & '----------------------------------' WRITE(*,10)CBI0,CDI0 WRITE(*,20)CBI1,CDI1 WRITE(*,*) WRITE(*,*)' n Re[Kn(z)] Im[Kn(z)]', & ' Re[Kn''(z)] Im[Kn''(z)]' WRITE(*,*)' -------------------------------', & '----------------------------------' WRITE(*,10)CBK0,CDK0 WRITE(*,20)CBK1,CDK1 10 FORMAT(3X,'0',2X,4D15.7) 20 FORMAT(3X,'1',2X,4D15.7) 30 FORMAT(3X,3Hz =,F7.2,' + i',F7.2) END SUBROUTINE CIK01(Z,CBI0,CDI0,CBI1,CDI1,CBK0,CDK0,CBK1,CDK1) C C ========================================================== C Purpose: Compute modified Bessel functions I0(z), I1(z), C K0(z), K1(z), and their derivatives for a C complex argument C Input : z --- Complex argument C Output: CBI0 --- I0(z) C CDI0 --- I0'(z) C CBI1 --- I1(z) C CDI1 --- I1'(z) C CBK0 --- K0(z) C CDK0 --- K0'(z) C CBK1 --- K1(z) C CDK1 --- K1'(z) C ========================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION A(12),B(12),A1(10) PI=3.141592653589793D0 CI=(0.0D0,1.0D0) A0=CDABS(Z) Z2=Z*Z Z1=Z IF (A0.EQ.0.0D0) THEN CBI0=(1.0D0,0.0D0) CBI1=(0.0D0,0.0D0) CDI0=(0.0D0,0.0D0) CDI1=(0.5D0,0.0D0) CBK0=(1.0D+300,0.0D0) CBK1=(1.0D+300,0.0D0) CDK0=-(1.0D+300,0.0D0) CDK1=-(1.0D+300,0.0D0) RETURN ENDIF IF (REAL(Z).LT.0.0) Z1=-Z IF (A0.LE.18.0) THEN CBI0=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 10 K=1,50 CR=0.25D0*CR*Z2/(K*K) CBI0=CBI0+CR IF (CDABS(CR/CBI0).LT.1.0D-15) GO TO 15 10 CONTINUE 15 CBI1=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 20 K=1,50 CR=0.25D0*CR*Z2/(K*(K+1)) CBI1=CBI1+CR IF (CDABS(CR/CBI1).LT.1.0D-15) GO TO 25 20 CONTINUE 25 CBI1=0.5D0*Z1*CBI1 ELSE DATA A/0.125D0,7.03125D-2, & 7.32421875D-2,1.1215209960938D-1, & 2.2710800170898D-1,5.7250142097473D-1, & 1.7277275025845D0,6.0740420012735D0, & 2.4380529699556D01,1.1001714026925D02, & 5.5133589612202D02,3.0380905109224D03/ DATA B/-0.375D0,-1.171875D-1, & -1.025390625D-1,-1.4419555664063D-1, & -2.7757644653320D-1,-6.7659258842468D-1, & -1.9935317337513D0,-6.8839142681099D0, & -2.7248827311269D01,-1.2159789187654D02, & -6.0384407670507D02,-3.3022722944809D03/ K0=12 IF (A0.GE.35.0) K0=9 IF (A0.GE.50.0) K0=7 CA=CDEXP(Z1)/CDSQRT(2.0D0*PI*Z1) CBI0=(1.0D0,0.0D0) ZR=1.0D0/Z1 DO 30 K=1,K0 30 CBI0=CBI0+A(K)*ZR**K CBI0=CA*CBI0 CBI1=(1.0D0,0.0D0) DO 35 K=1,K0 35 CBI1=CBI1+B(K)*ZR**K CBI1=CA*CBI1 ENDIF IF (A0.LE.9.0) THEN CS=(0.0D0,0.0D0) CT=-CDLOG(0.5D0*Z1)-0.5772156649015329D0 W0=0.0D0 CR=(1.0D0,0.0D0) DO 40 K=1,50 W0=W0+1.0D0/K CR=0.25D0*CR/(K*K)*Z2 CS=CS+CR*(W0+CT) IF (CDABS((CS-CW)/CS).LT.1.0D-15) GO TO 45 40 CW=CS 45 CBK0=CT+CS ELSE DATA A1/0.125D0,0.2109375D0, & 1.0986328125D0,1.1775970458984D01, & 2.1461706161499D02,5.9511522710323D03, & 2.3347645606175D05,1.2312234987631D07, & 8.401390346421D08,7.2031420482627D10/ CB=0.5D0/Z1 ZR2=1.0D0/Z2 CBK0=(1.0D0,0.0D0) DO 50 K=1,10 50 CBK0=CBK0+A1(K)*ZR2**K CBK0=CB*CBK0/CBI0 ENDIF CBK1=(1.0D0/Z1-CBI1*CBK0)/CBI0 IF (REAL(Z).LT.0.0) THEN IF (DIMAG(Z).LT.0.0) CBK0=CBK0+CI*PI*CBI0 IF (DIMAG(Z).GT.0.0) CBK0=CBK0-CI*PI*CBI0 IF (DIMAG(Z).LT.0.0) CBK1=-CBK1+CI*PI*CBI1 IF (DIMAG(Z).GT.0.0) CBK1=-CBK1-CI*PI*CBI1 CBI1=-CBI1 ENDIF CDI0=CBI1 CDI1=CBI0-1.0D0/Z*CBI1 CDK0=-CBK1 CDK1=-CBK0-1.0D0/Z*CBK1 RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mciklv.for000077500000000000000000000110251321604176500261120ustar00rootroot00000000000000 PROGRAM MCIKLV C C ========================================================= C Purpose: This program computes modified Bessel functions C Iv(z) and Kv(z) and their derivatives for a C large order and a complex argument using C subroutine CIKLV C Input: v --- Order of Iv(z) and Kv(z) C z --- Complex argument C Output: CBIV --- Iv(z) C CDIV --- Iv'(z) C CBKV --- Kv(z) C CDKV --- Kv'(z) C Examples: C v =100.00, z = 4.00 + i 2.00 C C Iv(z) = -.7373606617-123 + .6461109082-123 i C Iv'(z)= -.8307094243-122 + .2030132500-121 i C Kv(z) = -.3836166007+121 - .3356017795+121 i C Kv'(z)= .1103271276+123 + .2886519240+122 i C C v =100.50, z = 4.00 + i 2.00 C Iv(z) = -.1289940051-123 + .6845756182-124 i C Iv'(z)= -.1907996261-122 + .2672465997-122 i C Kv(z) = -.3008779281+122 - .1593719779+122 i C Kv'(z)= .7653781978+123 + .1857772148+122 i C ========================================================= C IMPLICIT DOUBLE PRECISION (V,X,Y) IMPLICIT COMPLEX*16 (C,Z) WRITE(*,*)'Please enter v,x,y ( z = x+iy )' READ(*,*)V,X,Y WRITE(*,10)V,X,Y Z=CMPLX(X,Y) CALL CIKLV(V,Z,CBIV,CDIV,CBKV,CDKV) WRITE(*,*) WRITE(*,20)CBIV WRITE(*,30)CDIV WRITE(*,*) WRITE(*,40)CBKV WRITE(*,50)CDKV 10 FORMAT(8X,'v =',F6.2,', ','z =',F7.2,' + i',F7.2) 20 FORMAT(8X,'Iv(z) =',D17.10,' + i ',D17.10) 30 FORMAT(8X,'Iv''(z)=',D17.10,' + i ',D17.10) 40 FORMAT(8X,'Kv(z) =',D17.10,' + i ',D17.10) 50 FORMAT(8X,'Kv''(z)=',D17.10,' + i ',D17.10) END SUBROUTINE CIKLV(V,Z,CBIV,CDIV,CBKV,CDKV) C C ===================================================== C Purpose: Compute modified Bessel functions Iv(z) and C Kv(z) and their derivatives with a complex C argument and a large order C Input: v --- Order of Iv(z) and Kv(z) C z --- Complex argument C Output: CBIV --- Iv(z) C CDIV --- Iv'(z) C CBKV --- Kv(z) C CDKV --- Kv'(z) C Routine called: C CJK to compute the expansion coefficients C ==================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CF(12),A(91) PI=3.141592653589793D0 KM=12 CALL CJK(KM,A) DO 30 L=1,0,-1 V0=V-L CWS=CDSQRT(1.0D0+(Z/V0)*(Z/V0)) CETA=CWS+CDLOG(Z/V0/(1.0D0+CWS)) CT=1.0D0/CWS CT2=CT*CT DO 15 K=1,KM L0=K*(K+1)/2+1 LF=L0+K CF(K)=A(LF) DO 10 I=LF-1,L0,-1 10 CF(K)=CF(K)*CT2+A(I) 15 CF(K)=CF(K)*CT**K VR=1.0D0/V0 CSI=(1.0D0,0.0D0) DO 20 K=1,KM 20 CSI=CSI+CF(K)*VR**K CBIV=CDSQRT(CT/(2.0D0*PI*V0))*CDEXP(V0*CETA)*CSI IF (L.EQ.1) CFI=CBIV CSK=(1.0D0,0.0D0) DO 25 K=1,KM 25 CSK=CSK+(-1)**K*CF(K)*VR**K CBKV=CDSQRT(PI*CT/(2.0D0*V0))*CDEXP(-V0*CETA)*CSK IF (L.EQ.1) CFK=CBKV 30 CONTINUE CDIV=CFI-V/Z*CBIV CDKV=-CFK-V/Z*CBKV RETURN END SUBROUTINE CJK(KM,A) C C ======================================================== C Purpose: Compute the expansion coefficients for the C asymptotic expansion of Bessel functions C with large orders C Input : Km --- Maximum k C Output: A(L) --- Cj(k) where j and k are related to L C by L=j+1+[k*(k+1)]/2; j,k=0,1,...,Km C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(*) A(1)=1.0D0 F0=1.0D0 G0=1.0D0 DO 10 K=0,KM-1 L1=(K+1)*(K+2)/2+1 L2=(K+1)*(K+2)/2+K+2 F=(0.5D0*K+0.125D0/(K+1))*F0 G=-(1.5D0*K+0.625D0/(3.0*(K+1.0D0)))*G0 A(L1)=F A(L2)=G F0=F 10 G0=G DO 15 K=1,KM-1 DO 15 J=1,K L3=K*(K+1)/2+J+1 L4=(K+1)*(K+2)/2+J+1 A(L4)=(J+0.5D0*K+0.125D0/(2.0*J+K+1.0))*A(L3) & -(J+0.5D0*K-1.0+0.625D0/(2.0*J+K+1.0))*A(L3-1) 15 CONTINUE RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcikna.for000077500000000000000000000262141321604176500260750ustar00rootroot00000000000000 PROGRAM MCIKNA C C ============================================================= C Purpose: This program computes the modified Bessel functions C In(z) and Kn(z), and their derivatives for a C complex argument using subroutine CIKNA C Input : z --- Complex argument of In(z) and Kn(z) C n --- Order of In(z) and Kn(z) C ( n = 0,1,úúú, n ó 250 ) C Output: CBI(n) --- In(z) C CDI(n) --- In'(z) C CBK(n) --- Kn(z) C CDK(n) --- Kn'(z) C Example: z = 4.0 + i 2.0 , Nmax = 5 C C n Re[In(z)] Im[In(z)] Re[In'(z)] Im[In'(z)] C ----------------------------------------------------------------- C 0 -.19056142D+01 .10403505D+02 -.23059657D+01 .92222463D+01 C 1 -.23059657D+01 .92222463D+01 -.23666457D+01 .83284588D+01 C 2 -.28276772D+01 .62534130D+01 -.24255774D+01 .61553456D+01 C 3 -.25451891D+01 .30884450D+01 -.22270972D+01 .36367893D+01 C 4 -.16265172D+01 .10201656D+01 -.16520416D+01 .16217056D+01 C 5 -.75889410D+00 .15496632D+00 -.94510625D+00 .48575220D+00 C C n Re[Kn(z)] Im[Kn(z)] Re[Kn'(z)] Im[Kn'(z)] C ----------------------------------------------------------------- C 0 -.64221754D-02 -.84393648D-02 .74307276D-02 .89585853D-02 C 1 -.74307276D-02 -.89585853D-02 .88041795D-02 .94880091D-02 C 2 -.11186184D-01 -.10536653D-01 .14012532D-01 .10936010D-01 C 3 -.20594336D-01 -.12913435D-01 .27416815D-01 .12106413D-01 C 4 -.43647447D-01 -.13676173D-01 .60982763D-01 .63953943D-02 C 5 -.10137119D+00 .12264588D-03 .14495731D+00 -.37132068D-01 C ============================================================= C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) COMMON CBI(0:250),CDI(0:250),CBK(0:250),CDK(0:250) WRITE(*,*)' Please input n, x,y (z=x+iy)=?' READ(*,*)N,X,Y Z=CMPLX(X,Y) WRITE(*,40)X,Y,N IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL CIKNA(N,Z,NM,CBI,CDI,CBK,CDK) WRITE(*,*) WRITE(*,*)' n Re[In(z)] Im[In(z)]', & ' Re[In''(z)] Im[In''(z)]' WRITE(*,*)' -----------------------------------', & '----------------------------------' DO 10 K=0,NM,NS WRITE(*,30)K,CBI(K),CDI(K) 10 CONTINUE WRITE(*,*) WRITE(*,*)' n Re[Kn(z)] Im[Kn(z)]', & ' Re[Kn''(z)] Im[Kn''(z)]' WRITE(*,*)' -----------------------------------', & '----------------------------------' DO 20 K=0,NM,NS WRITE(*,30)K,CBK(K),CDK(K) 20 CONTINUE 30 FORMAT(1X,I4,1X,4D16.8) 40 FORMAT(3X,3Hz =,F7.1,' + i',F7.1,' ,',6X,6HNmax =,I4) END SUBROUTINE CIKNA(N,Z,NM,CBI,CDI,CBK,CDK) C C ======================================================== C Purpose: Compute modified Bessel functions In(z), Kn(x) C and their derivatives for a complex argument C Input : z --- Complex argument of In(z) and Kn(z) C n --- Order of In(z) and Kn(z) C Output: CBI(n) --- In(z) C CDI(n) --- In'(z) C CBK(n) --- Kn(z) C CDK(n) --- Kn'(z) C NM --- Highest order computed C Routines called: C (1) CIK01 to compute I0(z), I1(z) K0(z) & K1(z) C (2) MSTA1 and MSTA2 to compute the starting C point for backward recurrence C ======================================================== C IMPLICIT DOUBLE PRECISION (A,B,P,W,X,Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBI(0:N),CDI(0:N),CBK(0:N),CDK(0:N) A0=CDABS(Z) NM=N IF (A0.LT.1.0D-100) THEN DO 10 K=0,N CBI(K)=(0.0D0,0.0D0) CDI(K)=(0.0D0,0.0D0) CBK(K)=-(1.0D+300,0.0D0) 10 CDK(K)=(1.0D+300,0.0D0) CBI(0)=(1.0D0,0.0D0) CDI(1)=(0.5D0,0.0D0) RETURN ENDIF CALL CIK01(Z,CBI0,CDI0,CBI1,CDI1,CBK0,CDK0,CBK1,CDK1) CBI(0)=CBI0 CBI(1)=CBI1 CBK(0)=CBK0 CBK(1)=CBK1 CDI(0)=CDI0 CDI(1)=CDI1 CDK(0)=CDK0 CDK(1)=CDK1 IF (N.LE.1) RETURN M=MSTA1(A0,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(A0,N,15) ENDIF CF2=(0.0D0,0.0D0) CF1=(1.0D-100,0.0D0) DO 45 K=M,0,-1 CF=2.0D0*(K+1.0D0)/Z*CF1+CF2 IF (K.LE.NM) CBI(K)=CF CF2=CF1 45 CF1=CF CS=CBI0/CF DO 50 K=0,NM 50 CBI(K)=CS*CBI(K) DO 60 K=2,NM IF (CDABS(CBI(K-1)).GT.CDABS(CBI(K-2))) THEN CKK=(1.0D0/Z-CBI(K)*CBK(K-1))/CBI(K-1) ELSE CKK=(CBI(K)*CBK(K-2)+2.0D0*(K-1.0D0)/(Z*Z))/CBI(K-2) ENDIF 60 CBK(K)=CKK DO 70 K=2,NM CDI(K)=CBI(K-1)-K/Z*CBI(K) 70 CDK(K)=-CBK(K-1)-K/Z*CBK(K) RETURN END SUBROUTINE CIK01(Z,CBI0,CDI0,CBI1,CDI1,CBK0,CDK0,CBK1,CDK1) C C ========================================================== C Purpose: Compute modified complex Bessel functions I0(z), C I1(z), K0(z), K1(z), and their derivatives C Input : z --- Complex argument C Output: CBI0 --- I0(z) C CDI0 --- I0'(z) C CBI1 --- I1(z) C CDI1 --- I1'(z) C CBK0 --- K0(z) C CDK0 --- K0'(z) C CBK1 --- K1(z) C CDK1 --- K1'(z) C ========================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION A(12),B(12),A1(10) PI=3.141592653589793D0 CI=(0.0D0,1.0D0) A0=CDABS(Z) Z2=Z*Z Z1=Z IF (A0.EQ.0.0D0) THEN CBI0=(1.0D0,0.0D0) CBI1=(0.0D0,0.0D0) CDI0=(0.0D0,0.0D0) CDI1=(0.5D0,0.0D0) CBK0=(1.0D+300,0.0D0) CBK1=(1.0D+300,0.0D0) CDK0=-(1.0D+300,0.0D0) CDK1=-(1.0D+300,0.0D0) RETURN ENDIF IF (REAL(Z).LT.0.0) Z1=-Z IF (A0.LE.18.0) THEN CBI0=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 10 K=1,50 CR=0.25D0*CR*Z2/(K*K) CBI0=CBI0+CR IF (CDABS(CR/CBI0).LT.1.0D-15) GO TO 15 10 CONTINUE 15 CBI1=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 20 K=1,50 CR=0.25D0*CR*Z2/(K*(K+1)) CBI1=CBI1+CR IF (CDABS(CR/CBI1).LT.1.0D-15) GO TO 25 20 CONTINUE 25 CBI1=0.5D0*Z1*CBI1 ELSE DATA A/0.125D0,7.03125D-2, & 7.32421875D-2,1.1215209960938D-1, & 2.2710800170898D-1,5.7250142097473D-1, & 1.7277275025845D0,6.0740420012735D0, & 2.4380529699556D01,1.1001714026925D02, & 5.5133589612202D02,3.0380905109224D03/ DATA B/-0.375D0,-1.171875D-1, & -1.025390625D-1,-1.4419555664063D-1, & -2.7757644653320D-1,-6.7659258842468D-1, & -1.9935317337513D0,-6.8839142681099D0, & -2.7248827311269D01,-1.2159789187654D02, & -6.0384407670507D02,-3.3022722944809D03/ K0=12 IF (A0.GE.35.0) K0=9 IF (A0.GE.50.0) K0=7 CA=CDEXP(Z1)/CDSQRT(2.0D0*PI*Z1) CBI0=(1.0D0,0.0D0) ZR=1.0D0/Z1 DO 30 K=1,K0 30 CBI0=CBI0+A(K)*ZR**K CBI0=CA*CBI0 CBI1=(1.0D0,0.0D0) DO 35 K=1,K0 35 CBI1=CBI1+B(K)*ZR**K CBI1=CA*CBI1 ENDIF IF (A0.LE.9.0) THEN CS=(0.0D0,0.0D0) CT=-CDLOG(0.5D0*Z1)-0.5772156649015329D0 W0=0.0D0 CR=(1.0D0,0.0D0) DO 40 K=1,50 W0=W0+1.0D0/K CR=0.25D0*CR/(K*K)*Z2 CS=CS+CR*(W0+CT) IF (CDABS((CS-CW)/CS).LT.1.0D-15) GO TO 45 40 CW=CS 45 CBK0=CT+CS ELSE DATA A1/0.125D0,0.2109375D0, & 1.0986328125D0,1.1775970458984D01, & 2.1461706161499D02,5.9511522710323D03, & 2.3347645606175D05,1.2312234987631D07, & 8.401390346421D08,7.2031420482627D10/ CB=0.5D0/Z1 ZR2=1.0D0/Z2 CBK0=(1.0D0,0.0D0) DO 50 K=1,10 50 CBK0=CBK0+A1(K)*ZR2**K CBK0=CB*CBK0/CBI0 ENDIF CBK1=(1.0D0/Z1-CBI1*CBK0)/CBI0 IF (REAL(Z).LT.0.0) THEN IF (DIMAG(Z).LT.0.0) CBK0=CBK0+CI*PI*CBI0 IF (DIMAG(Z).GT.0.0) CBK0=CBK0-CI*PI*CBI0 IF (DIMAG(Z).LT.0.0) CBK1=-CBK1+CI*PI*CBI1 IF (DIMAG(Z).GT.0.0) CBK1=-CBK1-CI*PI*CBI1 CBI1=-CBI1 ENDIF CDI0=CBI1 CDI1=CBI0-1.0D0/Z*CBI1 CDK0=-CBK1 CDK1=-CBK0-1.0D0/Z*CBK1 RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mciknb.for000077500000000000000000000200151321604176500260670ustar00rootroot00000000000000 PROGRAM MCIKNB C C ============================================================= C Purpose: This program computes the modified Bessel functions C In(z) and Kn(z), and their derivatives for a C complex argument using subroutine CIKNB C Input: z --- Complex argument C n --- Order of In(z) and Kn(z) C ( n = 0,1,úúú, n ó 250 ) C Output: CBI(n) --- In(z) C CDI(n) --- In'(z) C CBK(n) --- Kn(z) C CDK(n) --- Kn'(z) C Example: Nmax = 5, z = 4.0 + i 2.0 C C n Re[In(z)] Im[In(z)] Re[In'(z)] Im[In'(z)] C ----------------------------------------------------------------- C 0 -.19056142D+01 .10403505D+02 -.23059657D+01 .92222463D+01 C 1 -.23059657D+01 .92222463D+01 -.23666457D+01 .83284588D+01 C 2 -.28276772D+01 .62534130D+01 -.24255774D+01 .61553456D+01 C 3 -.25451891D+01 .30884450D+01 -.22270972D+01 .36367893D+01 C 4 -.16265172D+01 .10201656D+01 -.16520416D+01 .16217056D+01 C 5 -.75889410D+00 .15496632D+00 -.94510625D+00 .48575220D+00 C C n Re[Kn(z)] Im[Kn(z)] Re[Kn'(z)] Im[Kn'(z)] C ----------------------------------------------------------------- C 0 -.64221754D-02 -.84393648D-02 .74307276D-02 .89585853D-02 C 1 -.74307276D-02 -.89585853D-02 .88041795D-02 .94880091D-02 C 2 -.11186184D-01 -.10536653D-01 .14012532D-01 .10936010D-01 C 3 -.20594336D-01 -.12913435D-01 .27416815D-01 .12106413D-01 C 4 -.43647447D-01 -.13676173D-01 .60982763D-01 .63953943D-02 C 5 -.10137119D+00 .12264588D-03 .14495731D+00 -.37132068D-01 C ============================================================= C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBI(0:250),CDI(0:250),CBK(0:250),CDK(0:250) WRITE(*,*)' Please enter n, x and y (z = x+iy) ' READ(*,*)N,X,Y WRITE(*,25)N,X,Y Z=CMPLX(X,Y) WRITE(*,*) IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL CIKNB(N,Z,NM,CBI,CDI,CBK,CDK) WRITE(*,*)' n Re[In(z)] Im[In(z)]', & ' Re[In''(z)] Im[In''(z)]' WRITE(*,*)' ---------------------------------', & '------------------------------------' DO 10 K=0,NM,NS WRITE(*,20)K,CBI(K),CDI(K) 10 CONTINUE WRITE(*,*) WRITE(*,*)' n Re[Kn(z)] Im[Kn(z)]', & ' Re[Kn''(z)] Im[Kn''(z)]' WRITE(*,*)' ---------------------------------', & '------------------------------------' DO 15 K=0,NM,NS WRITE(*,20)K,CBK(K),CDK(K) 15 CONTINUE 20 FORMAT(1X,1X,I3,1X,4D16.8) 25 FORMAT(3X,6HNmaz =,I3,', ','z =', F6.1,' + i',F6.1) END SUBROUTINE CIKNB(N,Z,NM,CBI,CDI,CBK,CDK) C C ============================================================ C Purpose: Compute modified Bessel functions In(z) and Kn(z), C and their derivatives for a complex argument C Input: z --- Complex argument C n --- Order of In(z) and Kn(z) C Output: CBI(n) --- In(z) C CDI(n) --- In'(z) C CBK(n) --- Kn(z) C CDK(n) --- Kn'(z) C NM --- Highest order computed C Routones called: C MSTA1 and MSTA2 to compute the starting point for C backward recurrence C =========================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBI(0:N),CDI(0:N),CBK(0:N),CDK(0:N) PI=3.141592653589793D0 EL=0.57721566490153D0 A0=CDABS(Z) NM=N IF (A0.LT.1.0D-100) THEN DO 10 K=0,N CBI(K)=(0.0D0,0.0D0) CBK(K)=(1.0D+300,0.0D0) CDI(K)=(0.0D0,0.0D0) 10 CDK(K)=-(1.0D+300,0.0D0) CBI(0)=(1.0D0,0.0D0) CDI(1)=(0.5D0,0.0D0) RETURN ENDIF Z1=Z CI=(0.0D0,1.0D0) IF (REAL(Z).LT.0.0) Z1=-Z IF (N.EQ.0) NM=1 M=MSTA1(A0,200) IF (M.LT.NM) THEN NM=M ELSE M=MSTA2(A0,NM,15) ENDIF CBS=0.0D0 CSK0=0.0D0 CF0=0.0D0 CF1=1.0D-100 DO 15 K=M,0,-1 CF=2.0D0*(K+1.0D0)*CF1/Z1+CF0 IF (K.LE.NM) CBI(K)=CF IF (K.NE.0.AND.K.EQ.2*INT(K/2)) CSK0=CSK0+4.0D0*CF/K CBS=CBS+2.0D0*CF CF0=CF1 15 CF1=CF CS0=CDEXP(Z1)/(CBS-CF) DO 20 K=0,NM 20 CBI(K)=CS0*CBI(K) IF (A0.LE.9.0) THEN CBK(0)=-(CDLOG(0.5D0*Z1)+EL)*CBI(0)+CS0*CSK0 CBK(1)=(1.0D0/Z1-CBI(1)*CBK(0))/CBI(0) ELSE CA0=CDSQRT(PI/(2.0D0*Z1))*CDEXP(-Z1) K0=16 IF (A0.GE.25.0) K0=10 IF (A0.GE.80.0) K0=8 IF (A0.GE.200.0) K0=6 DO 30 L=0,1 CBKL=1.0D0 VT=4.0D0*L CR=(1.0D0,0.0D0) DO 25 K=1,K0 CR=0.125D0*CR*(VT-(2.0*K-1.0)**2)/(K*Z1) 25 CBKL=CBKL+CR CBK(L)=CA0*CBKL 30 CONTINUE ENDIF CG0=CBK(0) CG1=CBK(1) DO 35 K=2,NM CG=2.0D0*(K-1.0D0)/Z1*CG1+CG0 CBK(K)=CG CG0=CG1 35 CG1=CG IF (REAL(Z).LT.0.0) THEN FAC=1.0D0 DO 45 K=0,NM IF (DIMAG(Z).LT.0.0) THEN CBK(K)=FAC*CBK(K)+CI*PI*CBI(K) ELSE CBK(K)=FAC*CBK(K)-CI*PI*CBI(K) ENDIF CBI(K)=FAC*CBI(K) FAC=-FAC 45 CONTINUE ENDIF CDI(0)=CBI(1) CDK(0)=-CBK(1) DO 50 K=1,NM CDI(K)=CBI(K-1)-K/Z*CBI(K) 50 CDK(K)=-CBK(K-1)-K/Z*CBK(K) RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcikva.for000077500000000000000000000275521321604176500261130ustar00rootroot00000000000000 PROGRAM MCIKVA C C ============================================================== C Purpose: This program computes the modified Bessel functions C Iv(z), Kv(z) and their derivatives for an arbitrary C order and complex argument using subroutine CIKVA C Input : z --- Complex argument z C v --- Real order of Iv(z) and Kv(z) C ( v =n+v0, 0 ó n ó 250, 0 ó v0 < 1 ) C Output: CBI(n) --- In+v0(z) C CDI(n) --- In+v0'(z) C CBK(n) --- Kn+v0(z) C CDK(n) --- Kn+v0'(z) C Example: Compute Iv(z), Kv(z) and their derivatives for C v =n+v0, v0=0.25, n =0(1)5, and z =4.0 +i 2.0 C Computation results: C C v= n+v0, v0 = .25, z = 4.0+ i 2.0 C C n Re[Iv(z)] Im[Iv(z)] Re[Iv'(z)] Im[Iv'(z)] C ----------------------------------------------------------------- C 0 -.19336550D+01 .10328998D+02 -.23119621D+01 .91612230D+01 C 1 -.24735044D+01 .85964317D+01 -.23898329D+01 .78707023D+01 C 2 -.28460107D+01 .54124063D+01 -.24105909D+01 .55204965D+01 C 3 -.23476775D+01 .24445612D+01 -.21145027D+01 .30604463D+01 C 4 -.13829947D+01 .70848630D+00 -.14732387D+01 .12545751D+01 C 5 -.59879982D+00 .64588999D-01 -.78816416D+00 .32629794D+00 C C n Re[Kv(z)] Im[Kv(z)] Re[Kv'(z)] Im[Kv'(z)] C ---------------------------------------------------------------- C 0 -.64820386D-02 -.84715754D-02 .75118612D-02 .89920077D-02 C 1 -.80477525D-02 -.92535355D-02 .96506687D-02 .97789903D-02 C 2 -.12819299D-01 -.11086405D-01 .16310878D-01 .11358076D-01 C 3 -.24574004D-01 -.13462616D-01 .33167751D-01 .11850554D-01 C 4 -.53516204D-01 -.12614703D-01 .75424026D-01 .14407268D-02 C 5 -.12627405D+00 .10581162D-01 .18054884D+00 -.64789392D-01 C ============================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) COMMON CBI(0:250),CDI(0:250),CBK(0:250),CDK(0:250) WRITE(*,*)' Please enter v, x,y ( z=x+iy )' READ(*,*)V,X,Y Z=CMPLX(X,Y) N=INT(V) V0=V-N WRITE(*,25)V0,X,Y IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL CIKVA(V,Z,VM,CBI,CDI,CBK,CDK) NM=INT(VM) WRITE(*,*) WRITE(*,*)' n Re[Iv(z)] Im[Iv(z)] ', & ' Re[Iv''(z)] Im[Iv''(z)] ' WRITE(*,*)' ---------------------------------------', & '------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20)K,CBI(K),CDI(K) WRITE(*,*) WRITE(*,*)' n Re[Kv(z)] Im[Kv(z)] ', & ' Re[Kv''(z)] Im[Kv''(z)] ' WRITE(*,*)' ---------------------------------------', & '------------------------------' DO 15 K=0,NM,NS 15 WRITE(*,20)K,CBK(K),CDK(K) 20 FORMAT(1X,I4,1X,4D16.8) 25 FORMAT(8X,'v= n+v0',', ','v0 =',F7.2,', ','z =',F6.1, & '+ i',F6.1) END SUBROUTINE CIKVA(V,Z,VM,CBI,CDI,CBK,CDK) C C ============================================================ C Purpose: Compute the modified Bessel functions Iv(z), Kv(z) C and their derivatives for an arbitrary order and C complex argument C Input : z --- Complex argument C v --- Real order of Iv(z) and Kv(z) C ( v = n+v0, n = 0,1,2,úúú, 0 ó v0 < 1 ) C Output: CBI(n) --- In+v0(z) C CDI(n) --- In+v0'(z) C CBK(n) --- Kn+v0(z) C CDK(n) --- Kn+v0'(z) C VM --- Highest order computed C Routines called: C (1) GAMMA for computing the gamma function C (2) MSTA1 and MSTA2 for computing the starting C point for backward recurrence C ============================================================ C IMPLICIT DOUBLE PRECISION (A,G,P,R,V,W) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBI(0:*),CDI(0:*),CBK(0:*),CDK(0:*) PI=3.141592653589793D0 CI=(0.0D0,1.0D0) A0=CDABS(Z) Z1=Z Z2=Z*Z N=INT(V) V0=V-N PIV=PI*V0 VT=4.0D0*V0*V0 IF (N.EQ.0) N=1 IF (A0.LT.1.0D-100) THEN DO 10 K=0,N CBI(K)=0.0D0 CDI(K)=0.0D0 CBK(K)=-1.0D+300 10 CDK(K)=1.0D+300 IF (V0.EQ.0.0) THEN CBI(0)=(1.0D0,0.0D0) CDI(1)=(0.5D0,0.0D0) ENDIF VM=V RETURN ENDIF K0=14 IF (A0.GE.35.0) K0=10 IF (A0.GE.50.0) K0=8 IF (REAL(Z).LT.0.0) Z1=-Z IF (A0.LT.18.0) THEN IF (V0.EQ.0.0) THEN CA1=(1.0D0,0.0D0) ELSE V0P=1.0D0+V0 CALL GAMMA(V0P,GAP) CA1=(0.5D0*Z1)**V0/GAP ENDIF CI0=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 15 K=1,50 CR=0.25D0*CR*Z2/(K*(K+V0)) CI0=CI0+CR IF (CDABS(CR).LT.CDABS(CI0)*1.0D-15) GO TO 20 15 CONTINUE 20 CBI0=CI0*CA1 ELSE CA=CDEXP(Z1)/CDSQRT(2.0D0*PI*Z1) CS=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 25 K=1,K0 CR=-0.125D0*CR*(VT-(2.0D0*K-1.0D0)**2.0)/(K*Z1) 25 CS=CS+CR CBI0=CA*CS ENDIF M=MSTA1(A0,200) IF (M.LT.N) THEN N=M ELSE M=MSTA2(A0,N,15) ENDIF CF2=(0.0D0,0.0D0) CF1=(1.0D-100,0.0D0) DO 30 K=M,0,-1 CF=2.0D0*(V0+K+1.0D0)/Z1*CF1+CF2 IF (K.LE.N) CBI(K)=CF CF2=CF1 30 CF1=CF CS=CBI0/CF DO 35 K=0,N 35 CBI(K)=CS*CBI(K) IF (A0.LE.9.0) THEN IF (V0.EQ.0.0) THEN CT=-CDLOG(0.5D0*Z1)-0.5772156649015329D0 CS=(0.0D0,0.0D0) W0=0.0D0 CR=(1.0D0,0.0D0) DO 40 K=1,50 W0=W0+1.0D0/K CR=0.25D0*CR/(K*K)*Z2 CP=CR*(W0+CT) CS=CS+CP IF (K.GE.10.AND.CDABS(CP/CS).LT.1.0D-15) GO TO 45 40 CONTINUE 45 CBK0=CT+CS ELSE V0N=1.0D0-V0 CALL GAMMA(V0N,GAN) CA2=1.0D0/(GAN*(0.5D0*Z1)**V0) CA1=(0.5D0*Z1)**V0/GAP CSU=CA2-CA1 CR1=(1.0D0,0.0D0) CR2=(1.0D0,0.0D0) DO 50 K=1,50 CR1=0.25D0*CR1*Z2/(K*(K-V0)) CR2=0.25D0*CR2*Z2/(K*(K+V0)) CSU=CSU+CA2*CR1-CA1*CR2 WS=CDABS(CSU) IF (K.GE.10.AND.DABS(WS-WS0)/WS.LT.1.0D-15) GO TO 55 WS0=WS 50 CONTINUE 55 CBK0=0.5D0*PI*CSU/DSIN(PIV) ENDIF ELSE CB=CDEXP(-Z1)*CDSQRT(0.5D0*PI/Z1) CS=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 60 K=1,K0 CR=0.125D0*CR*(VT-(2.0D0*K-1.0D0)**2.0)/(K*Z1) 60 CS=CS+CR CBK0=CB*CS ENDIF CBK1=(1.0D0/Z1-CBI(1)*CBK0)/CBI(0) CBK(0)=CBK0 CBK(1)=CBK1 CG0=CBK0 CG1=CBK1 DO 65 K=2,N CGK=2.0D0*(V0+K-1.0D0)/Z1*CG1+CG0 CBK(K)=CGK CG0=CG1 65 CG1=CGK IF (REAL(Z).LT.0.0) THEN DO 70 K=0,N CVK=CDEXP((K+V0)*PI*CI) IF (DIMAG(Z).LT.0.0D0) THEN CBK(K)=CVK*CBK(K)+PI*CI*CBI(K) CBI(K)=CBI(K)/CVK ELSE IF (DIMAG(Z).GT.0.0) THEN CBK(K)=CBK(K)/CVK-PI*CI*CBI(K) CBI(K)=CVK*CBI(K) ENDIF 70 CONTINUE ENDIF CDI(0)=V0/Z*CBI(0)+CBI(1) CDK(0)=V0/Z*CBK(0)-CBK(1) DO 75 K=1,N CDI(K)=-(K+V0)/Z*CBI(K)+CBI(K-1) 75 CDK(K)=-(K+V0)/Z*CBK(K)-CBK(K-1) VM=N+V0 RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcikvb.for000077500000000000000000000270111321604176500261020ustar00rootroot00000000000000 PROGRAM MCIKVB C C ============================================================= C Purpose: This program computes the modified Bessel functions C Iv(z), Kv(z) and their derivatives for an arbitrary C order and complex argument using subroutine CIKVB C Input : z --- Complex argument z C v --- Real order of Iv(z) and Kv(z) C ( v = n+v0, 0 ó n ó 250, 0 ó v0 < 1 ) C Output: CBI(n) --- In+v0(z) C CDI(n) --- In+v0'(z) C CBK(n) --- Kn+v0(z) C CDK(n) --- Kn+v0'(z) C Example: v= n+v0, v0 = .25, z = 4.0+ i 2.0 C C n Re[Iv(z)] Im[Iv(z)] Re[Iv'(z)] Im[Iv'(z)] C ----------------------------------------------------------------- C 0 -.19336550D+01 .10328998D+02 -.23119621D+01 .91612230D+01 C 1 -.24735044D+01 .85964317D+01 -.23898329D+01 .78707023D+01 C 2 -.28460107D+01 .54124063D+01 -.24105909D+01 .55204965D+01 C 3 -.23476775D+01 .24445612D+01 -.21145027D+01 .30604463D+01 C 4 -.13829947D+01 .70848630D+00 -.14732387D+01 .12545751D+01 C 5 -.59879982D+00 .64588999D-01 -.78816416D+00 .32629794D+00 C C n Re[Kv(z)] Im[Kv(z)] Re[Kv'(z)] Im[Kv'(z)] C ---------------------------------------------------------------- C 0 -.64820386D-02 -.84715754D-02 .75118612D-02 .89920077D-02 C 1 -.80477525D-02 -.92535355D-02 .96506687D-02 .97789903D-02 C 2 -.12819299D-01 -.11086405D-01 .16310878D-01 .11358076D-01 C 3 -.24574004D-01 -.13462616D-01 .33167751D-01 .11850554D-01 C 4 -.53516204D-01 -.12614703D-01 .75424026D-01 .14407268D-02 C 5 -.12627405D+00 .10581162D-01 .18054884D+00 -.64789392D-01 C ============================================================= C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBI(0:250),CDI(0:250),CBK(0:250),CDK(0:250) WRITE(*,*)' Please enter v, x and y ( z=x+iy )' READ(*,*)V,X,Y Z=CMPLX(X,Y) N=INT(V) V0=V-N WRITE(*,25)V0,X,Y IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL CIKVB(V,Z,VM,CBI,CDI,CBK,CDK) NM=INT(VM) WRITE(*,*) WRITE(*,*)' n Re[Iv(z)] Im[Iv(z)] ', & ' Re[Iv''(z)] Im[Iv''(z)] ' WRITE(*,*)' ---------------------------------------', & '------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20) K,CBI(K),CDI(K) WRITE(*,*) WRITE(*,*)' n Re[Kv(z)] Im[Kv(z)] ', & ' Re[Kv''(z)] Im[Kv''(z)] ' WRITE(*,*)' ---------------------------------------', & '------------------------------' DO 15 K=0,NM,NS 15 WRITE(*,20)K,CBK(K),CDK(K) 20 FORMAT(1X,I4,1X,4D16.8) 25 FORMAT(8X,'v= n+v0',', ','v0 =',F6.2,', ','z =',F5.1, & '+ i',F5.1) END SUBROUTINE CIKVB(V,Z,VM,CBI,CDI,CBK,CDK) C C =========================================================== C Purpose: Compute the modified Bessel functions Iv(z), Kv(z) C and their derivatives for an arbitrary order and C complex argument C Input : z --- Complex argument z C v --- Real order of Iv(z) and Kv(z) C ( v =n+v0, n = 0,1,2,..., 0 ó v0 < 1 ) C Output: CBI(n) --- In+v0(z) C CDI(n) --- In+v0'(z) C CBK(n) --- Kn+v0(z) C CDK(n) --- Kn+v0'(z) C VM --- Highest order computed C Routines called: C (1) GAMMA for computing the gamma function C (2) MSTA1 and MSTA2 for computing the starting C point for backward recurrence C =========================================================== C IMPLICIT DOUBLE PRECISION (A,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBI(0:*),CDI(0:*),CBK(0:*),CDK(0:*) Z1=Z Z2=Z*Z A0=CDABS(Z) PI=3.141592653589793D0 CI=(0.0D0,1.0D0) N=INT(V) V0=V-N PIV=PI*V0 VT=4.0D0*V0*V0 IF (N.EQ.0) N=1 IF (A0.LT.1.0D-100) THEN DO 10 K=0,N CBI(K)=0.0D0 CDI(K)=0.0D0 CBK(K)=-1.0D+300 10 CDK(K)=1.0D+300 IF (V0.EQ.0.0) THEN CBI(0)=(1.0D0,0.0D0) CDI(1)=(0.5D0,0.0D0) ENDIF VM=V RETURN ENDIF K0=14 IF (A0.GE.35.0) K0=10 IF (A0.GE.50.0) K0=8 IF (REAL(Z).LT.0.0) Z1=-Z IF (A0.LT.18.0) THEN IF (V0.EQ.0.0) THEN CA1=(1.0D0,0.0D0) ELSE V0P=1.0D0+V0 CALL GAMMA(V0P,GAP) CA1=(0.5D0*Z1)**V0/GAP ENDIF CI0=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 15 K=1,50 CR=0.25D0*CR*Z2/(K*(K+V0)) CI0=CI0+CR IF (CDABS(CR/CI0).LT.1.0D-15) GO TO 20 15 CONTINUE 20 CBI0=CI0*CA1 ELSE CA=CDEXP(Z1)/CDSQRT(2.0D0*PI*Z1) CS=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 25 K=1,K0 CR=-0.125D0*CR*(VT-(2.0D0*K-1.0D0)**2.0)/(K*Z1) 25 CS=CS+CR CBI0=CA*CS ENDIF M=MSTA1(A0,200) IF (M.LT.N) THEN N=M ELSE M=MSTA2(A0,N,15) ENDIF CF2=(0.0D0,0.0D0) CF1=(1.0D-100,0.0D0) DO 30 K=M,0,-1 CF=2.0D0*(V0+K+1.0D0)/Z1*CF1+CF2 IF (K.LE.N) CBI(K)=CF CF2=CF1 30 CF1=CF CS=CBI0/CF DO 35 K=0,N 35 CBI(K)=CS*CBI(K) IF (A0.LE.9.0) THEN IF (V0.EQ.0.0) THEN CT=-CDLOG(0.5D0*Z1)-0.5772156649015329D0 CS=(0.0D0,0.0D0) W0=0.0D0 CR=(1.0D0,0.0D0) DO 40 K=1,50 W0=W0+1.0D0/K CR=0.25D0*CR/(K*K)*Z2 CP=CR*(W0+CT) CS=CS+CP IF (K.GE.10.AND.CDABS(CP/CS).LT.1.0D-15) GO TO 45 40 CONTINUE 45 CBK0=CT+CS ELSE V0N=1.0D0-V0 CALL GAMMA(V0N,GAN) CA2=1.0D0/(GAN*(0.5D0*Z1)**V0) CA1=(0.5D0*Z1)**V0/GAP CSU=CA2-CA1 CR1=(1.0D0,0.0D0) CR2=(1.0D0,0.0D0) DO 50 K=1,50 CR1=0.25D0*CR1*Z2/(K*(K-V0)) CR2=0.25D0*CR2*Z2/(K*(K+V0)) CP=CA2*CR1-CA1*CR2 CSU=CSU+CP IF (K.GE.10.AND.CDABS(CP/CSU).LT.1.0D-15) GO TO 55 50 CONTINUE 55 CBK0=0.5D0*PI*CSU/DSIN(PIV) ENDIF ELSE CB=CDEXP(-Z1)*CDSQRT(0.5D0*PI/Z1) CS=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 60 K=1,K0 CR=0.125D0*CR*(VT-(2.0D0*K-1.0D0)**2.0)/(K*Z1) 60 CS=CS+CR CBK0=CB*CS ENDIF CBK(0)=CBK0 IF (REAL(Z).LT.0.0) THEN DO 65 K=0,N CVK=CDEXP((K+V0)*PI*CI) IF (DIMAG(Z).LT.0.0D0) THEN CBK(K)=CVK*CBK(K)+PI*CI*CBI(K) CBI(K)=CBI(K)/CVK ELSE IF (DIMAG(Z).GT.0.0) THEN CBK(K)=CBK(K)/CVK-PI*CI*CBI(K) CBI(K)=CVK*CBI(K) ENDIF 65 CONTINUE ENDIF DO 70 K=1,N CKK=(1.0D0/Z-CBI(K)*CBK(K-1))/CBI(K-1) CBK(K)=CKK 70 CONTINUE CDI(0)=V0/Z*CBI(0)+CBI(1) CDK(0)=V0/Z*CBK(0)-CBK(1) DO 80 K=1,N CDI(K)=-(K+V0)/Z*CBI(K)+CBI(K-1) 80 CDK(K)=-(K+V0)/Z*CBK(K)-CBK(K-1) VM=N+V0 RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcisia.for000077500000000000000000000067301321604176500261010ustar00rootroot00000000000000 PROGRAM MCISIA C C ======================================================== C Purpose: This program computes the cosine and sine C integrals using subroutine CISIA C Input : x --- Argument of Ci(x) and Si(x) C Output: CI --- Ci(x) C SI --- Si(x) C Example: C x Ci(x) Si(x) C ------------------------------------ C 0.0 - ì .00000000 C 5.0 -.19002975 1.54993124 C 10.0 -.04545643 1.65834759 C 20.0 .04441982 1.54824170 C 30.0 -.03303242 1.56675654 C 40.0 .01902001 1.58698512 C ======================================================== C DOUBLE PRECISION CI,SI,X WRITE(*,*)'Please enter x ' READ(*,*) X WRITE(*,*)' x Ci(x) Si(x)' WRITE(*,*)'------------------------------------' CALL CISIA(X,CI,SI) IF (X.NE.0.0D0) WRITE(*,10)X,CI,SI IF (X.EQ.0.0D0) WRITE(*,20) 10 FORMAT(1X,F5.1,2F15.8) 20 FORMAT(3X,' .0',4X,' - ì',13X,'.00000000') END SUBROUTINE CISIA(X,CI,SI) C C ============================================= C Purpose: Compute cosine and sine integrals C Si(x) and Ci(x) ( x ò 0 ) C Input : x --- Argument of Ci(x) and Si(x) C Output: CI --- Ci(x) C SI --- Si(x) C ============================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BJ(101) P2=1.570796326794897D0 EL=.5772156649015329D0 EPS=1.0D-15 X2=X*X IF (X.EQ.0.0D0) THEN CI=-1.0D+300 SI=0.0D0 ELSE IF (X.LE.16.0D0) THEN XR=-.25D0*X2 CI=EL+DLOG(X)+XR DO 10 K=2,40 XR=-.5D0*XR*(K-1)/(K*K*(2*K-1))*X2 CI=CI+XR IF (DABS(XR).LT.DABS(CI)*EPS) GO TO 15 10 CONTINUE 15 XR=X SI=X DO 20 K=1,40 XR=-.5D0*XR*(2*K-1)/K/(4*K*K+4*K+1)*X2 SI=SI+XR IF (DABS(XR).LT.DABS(SI)*EPS) RETURN 20 CONTINUE ELSE IF (X.LE.32.0D0) THEN M=INT(47.2+.82*X) XA1=0.0D0 XA0=1.0D-100 DO 25 K=M,1,-1 XA=4.0D0*K*XA0/X-XA1 BJ(K)=XA XA1=XA0 25 XA0=XA XS=BJ(1) DO 30 K=3,M,2 30 XS=XS+2.0D0*BJ(K) BJ(1)=BJ(1)/XS DO 35 K=2,M 35 BJ(K)=BJ(K)/XS XR=1.0D0 XG1=BJ(1) DO 40 K=2,M XR=.25D0*XR*(2.0*K-3.0)**2/((K-1.0)*(2.0*K-1.0)**2)*X 40 XG1=XG1+BJ(K)*XR XR=1.0D0 XG2=BJ(1) DO 45 K=2,M XR=.25D0*XR*(2.0*K-5.0)**2/((K-1.0)*(2.0*K-3.0)**2)*X 45 XG2=XG2+BJ(K)*XR XCS=DCOS(X/2.0D0) XSS=DSIN(X/2.0D0) CI=EL+DLOG(X)-X*XSS*XG1+2*XCS*XG2-2*XCS*XCS SI=X*XCS*XG1+2*XSS*XG2-DSIN(X) ELSE XR=1.0D0 XF=1.0D0 DO 50 K=1,9 XR=-2.0D0*XR*K*(2*K-1)/X2 50 XF=XF+XR XR=1.0D0/X XG=XR DO 55 K=1,8 XR=-2.0D0*XR*(2*K+1)*K/X2 55 XG=XG+XR CI=XF*DSIN(X)/X-XG*DCOS(X)/X SI=P2-XF*DCOS(X)/X-XG*DSIN(X)/X ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcisib.for000077500000000000000000000047061321604176500261030ustar00rootroot00000000000000 PROGRAM MCISIB C C ======================================================== C Purpose: This program computes the cosine and sine C integrals using subroutine CISIB C Input : x --- Argument of Ci(x) and Si(x) C Output: CI --- Ci(x) C SI --- Si(x) C Example: C C x Ci(x) Si(x) C ------------------------------------ C 0.0 - ì 0 C 5.0 -.190030D+00 1.549931 C 10.0 -.454563D-01 1.658348 C 20.0 .444201D-01 1.548241 C 30.0 -.330326D-01 1.566757 C 40.0 .190201D-01 1.586985 C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*) X WRITE(*,*)' x Ci(x) Si(x)' WRITE(*,*)'------------------------------------' CALL CISIB(X,CI,SI) IF (X.NE.0.0D0) WRITE(*,10)X,CI,SI IF (X.EQ.0.0D0) WRITE(*,20) 10 FORMAT(1X,F5.1,D16.6,F14.6) 20 FORMAT(3X,' .0',3X,' - ì',17X,'0') END SUBROUTINE CISIB(X,CI,SI) C C ============================================= C Purpose: Compute cosine and sine integrals C Si(x) and Ci(x) ( x ò 0 ) C Input : x --- Argument of Ci(x) and Si(x) C Output: CI --- Ci(x) C SI --- Si(x) C ============================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) X2=X*X IF (X.EQ.0.0) THEN CI=-1.0D+300 SI=0.0D0 ELSE IF (X.LE.1.0D0) THEN CI=((((-3.0D-8*X2+3.10D-6)*X2-2.3148D-4) & *X2+1.041667D-2)*X2-0.25)*X2+0.577215665D0+LOG(X) SI=((((3.1D-7*X2-2.834D-5)*X2+1.66667D-003) & *X2-5.555556D-002)*X2+1.0)*X ELSE FX=((((X2+38.027264D0)*X2+265.187033D0)*X2 & +335.67732D0)*X2+38.102495D0)/((((X2 & +40.021433D0)*X2+322.624911D0)*X2 & +570.23628D0)*X2+157.105423D0) GX=((((X2+42.242855D0)*X2+302.757865D0)*X2 & +352.018498D0)*X2+21.821899D0)/((((X2 & +48.196927D0)*X2+482.485984D0)*X2 & +1114.978885D0)*X2+449.690326D0)/X CI=FX*SIN(X)/X-GX*COS(X)/X SI=1.570796327D0-FX*COS(X)/X-GX*SIN(X)/X ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcjk.for000077500000000000000000000036121321604176500255540ustar00rootroot00000000000000 PROGRAM MCJK C C ============================================================ C Purpose: This program computes the expansion coefficients C for the asymptotic expansion of Bessel functions C with large orders using subroutine CJK C Input : Km --- Maximum k C Output: A(L) --- Cj(k) where j and k are related to L by C L=j+1+[k*(k+1)]/2; j,k=0,1,2,...,Km C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(231) WRITE(*,*)'Please enter Km ( ó 20 )' READ(*,*)KM LM=KM+1+(KM*(KM+1))/2 CALL CJK(KM,A) DO 10 K=1,LM 10 WRITE(*,15)K,A(K) 15 FORMAT(1X,I3,D25.14) END SUBROUTINE CJK(KM,A) C C ======================================================== C Purpose: Compute the expansion coefficients for the C asymptotic expansion of Bessel functions C with large orders C Input : Km --- Maximum k C Output: A(L) --- Cj(k) where j and k are related to L C by L=j+1+[k*(k+1)]/2; j,k=0,1,...,Km C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(*) A(1)=1.0D0 F0=1.0D0 G0=1.0D0 DO 10 K=0,KM-1 L1=(K+1)*(K+2)/2+1 L2=(K+1)*(K+2)/2+K+2 F=(0.5D0*K+0.125D0/(K+1))*F0 G=-(1.5D0*K+0.625D0/(3.0*(K+1.0D0)))*G0 A(L1)=F A(L2)=G F0=F 10 G0=G DO 15 K=1,KM-1 DO 15 J=1,K L3=K*(K+1)/2+J+1 L4=(K+1)*(K+2)/2+J+1 A(L4)=(J+0.5D0*K+0.125D0/(2.0*J+K+1.0))*A(L3) & -(J+0.5D0*K-1.0+0.625D0/(2.0*J+K+1.0))*A(L3-1) 15 CONTINUE RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcjy01.for000077500000000000000000000164751321604176500257460ustar00rootroot00000000000000 PROGRAM MCJY01 C C ================================================================ C Purpose: This program computes Bessel functions J0(z), J1(z), C Y0(z), Y1(z), and their derivatives for a complex C argument using subroutine CJY01 C Input : z --- Complex argument C Output: CBJ0 --- J0(z) C CDJ0 --- J0'(z) C CBJ1 --- J1(z) C CDJ1 --- J1'(z) C CBY0 --- Y0(z) C CDY0 --- Y0'(z) C CBY1 --- Y1(z) C CDY1 --- Y1'(z) C Example: z = 4.0 + i 2.0 C C n Re[Jn(z)] Im[Jn(z)] Re[Jn'(z)] Im[Jn'(z)] C -------------------------------------------------------------------- C 0 -.13787022D+01 .39054236D+00 .50735255D+00 .12263041D+01 C 1 -.50735255D+00 -.12263041D+01 -.11546013D+01 .58506793D+00 C C n Re[Yn(z)] Im[Yn(z)] Re[Yn'(z)] Im[Yn'(z)] C -------------------------------------------------------------------- C 0 -.38145893D+00 -.13291649D+01 -.12793101D+01 .51220420D+00 C 1 .12793101D+01 -.51220420D+00 -.58610052D+00 -.10987930D+01 C ================================================================ C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX*16 (C,Z) WRITE(*,*)' Please enter x,y (z=x+iy) ' READ(*,*)X,Y Z=CMPLX(X,Y) WRITE(*,30)X,Y CALL CJY01(Z,CBJ0,CDJ0,CBJ1,CDJ1,CBY0,CDY0,CBY1,CDY1) WRITE(*,*) WRITE(*,*)' n Re[Jn(z)] Im[Jn(z)]', & ' Re[Jn''(z)] Im[Jn''(z)]' WRITE(*,*)' -------------------------------------', & '-------------------------------' WRITE(*,10)CBJ0,CDJ0 WRITE(*,20)CBJ1,CDJ1 WRITE(*,*) WRITE(*,*)' n Re[Yn(z)] Im[Yn(z)]', & ' Re[Yn''(z)] Im[Yn''(z)]' WRITE(*,*)' -------------------------------------', & '-------------------------------' WRITE(*,10)CBY0,CDY0 WRITE(*,20)CBY1,CDY1 10 FORMAT(3X,'0',2X,4D16.8) 20 FORMAT(3X,'1',2X,4D16.8) 30 FORMAT(3X,3Hz =,F6.2,' + i',F6.2) END SUBROUTINE CJY01(Z,CBJ0,CDJ0,CBJ1,CDJ1,CBY0,CDY0,CBY1,CDY1) C C ======================================================= C Purpose: Compute Bessel functions J0(z), J1(z), Y0(z), C Y1(z), and their derivatives for a complex C argument C Input : z --- Complex argument C Output: CBJ0 --- J0(z) C CDJ0 --- J0'(z) C CBJ1 --- J1(z) C CDJ1 --- J1'(z) C CBY0 --- Y0(z) C CDY0 --- Y0'(z) C CBY1 --- Y1(z) C CDY1 --- Y1'(z) C ======================================================= C IMPLICIT DOUBLE PRECISION (A,B,E,P,R,W) IMPLICIT COMPLEX*16 (C,Z) DIMENSION A(12),B(12),A1(12),B1(12) PI=3.141592653589793D0 EL=0.5772156649015329D0 RP2=2.0D0/PI CI=(0.0D0,1.0D0) A0=CDABS(Z) Z2=Z*Z Z1=Z IF (A0.EQ.0.0D0) THEN CBJ0=(1.0D0,0.0D0) CBJ1=(0.0D0,0.0D0) CDJ0=(0.0D0,0.0D0) CDJ1=(0.5D0,0.0D0) CBY0=-(1.0D300,0.0D0) CBY1=-(1.0D300,0.0D0) CDY0=(1.0D300,0.0D0) CDY1=(1.0D300,0.0D0) RETURN ENDIF IF (REAL(Z).LT.0.0) Z1=-Z IF (A0.LE.12.0) THEN CBJ0=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 10 K=1,40 CR=-0.25D0*CR*Z2/(K*K) CBJ0=CBJ0+CR IF (CDABS(CR).LT.CDABS(CBJ0)*1.0D-15) GO TO 15 10 CONTINUE 15 CBJ1=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 20 K=1,40 CR=-0.25D0*CR*Z2/(K*(K+1.0D0)) CBJ1=CBJ1+CR IF (CDABS(CR).LT.CDABS(CBJ1)*1.0D-15) GO TO 25 20 CONTINUE 25 CBJ1=0.5D0*Z1*CBJ1 W0=0.0D0 CR=(1.0D0,0.0D0) CS=(0.0D0,0.0D0) DO 30 K=1,40 W0=W0+1.0D0/K CR=-0.25D0*CR/(K*K)*Z2 CP=CR*W0 CS=CS+CP IF (CDABS(CP).LT.CDABS(CS)*1.0D-15) GO TO 35 30 CONTINUE 35 CBY0=RP2*(CDLOG(Z1/2.0D0)+EL)*CBJ0-RP2*CS W1=0.0D0 CR=(1.0D0,0.0D0) CS=(1.0D0,0.0D0) DO 40 K=1,40 W1=W1+1.0D0/K CR=-0.25D0*CR/(K*(K+1))*Z2 CP=CR*(2.0D0*W1+1.0D0/(K+1.0D0)) CS=CS+CP IF (CDABS(CP).LT.CDABS(CS)*1.0D-15) GO TO 45 40 CONTINUE 45 CBY1=RP2*((CDLOG(Z1/2.0D0)+EL)*CBJ1-1.0D0/Z1-.25D0*Z1*CS) ELSE DATA A/-.703125D-01,.112152099609375D+00, & -.5725014209747314D+00,.6074042001273483D+01, & -.1100171402692467D+03,.3038090510922384D+04, & -.1188384262567832D+06,.6252951493434797D+07, & -.4259392165047669D+09,.3646840080706556D+11, & -.3833534661393944D+13,.4854014686852901D+15/ DATA B/ .732421875D-01,-.2271080017089844D+00, & .1727727502584457D+01,-.2438052969955606D+02, & .5513358961220206D+03,-.1825775547429318D+05, & .8328593040162893D+06,-.5006958953198893D+08, & .3836255180230433D+10,-.3649010818849833D+12, & .4218971570284096D+14,-.5827244631566907D+16/ DATA A1/.1171875D+00,-.144195556640625D+00, & .6765925884246826D+00,-.6883914268109947D+01, & .1215978918765359D+03,-.3302272294480852D+04, & .1276412726461746D+06,-.6656367718817688D+07, & .4502786003050393D+09,-.3833857520742790D+11, & .4011838599133198D+13,-.5060568503314727D+15/ DATA B1/-.1025390625D+00,.2775764465332031D+00, & -.1993531733751297D+01,.2724882731126854D+02, & -.6038440767050702D+03,.1971837591223663D+05, & -.8902978767070678D+06,.5310411010968522D+08, & -.4043620325107754D+10,.3827011346598605D+12, & -.4406481417852278D+14,.6065091351222699D+16/ K0=12 IF (A0.GE.35.0) K0=10 IF (A0.GE.50.0) K0=8 CT1=Z1-.25D0*PI CP0=(1.0D0,0.0D0) DO 50 K=1,K0 50 CP0=CP0+A(K)*Z1**(-2*K) CQ0=-0.125D0/Z1 DO 55 K=1,K0 55 CQ0=CQ0+B(K)*Z1**(-2*K-1) CU=CDSQRT(RP2/Z1) CBJ0=CU*(CP0*CDCOS(CT1)-CQ0*CDSIN(CT1)) CBY0=CU*(CP0*CDSIN(CT1)+CQ0*CDCOS(CT1)) CT2=Z1-.75D0*PI CP1=(1.0D0,0.0D0) DO 60 K=1,K0 60 CP1=CP1+A1(K)*Z1**(-2*K) CQ1=0.375D0/Z1 DO 65 K=1,K0 65 CQ1=CQ1+B1(K)*Z1**(-2*K-1) CBJ1=CU*(CP1*CDCOS(CT2)-CQ1*CDSIN(CT2)) CBY1=CU*(CP1*CDSIN(CT2)+CQ1*CDCOS(CT2)) ENDIF IF (REAL(Z).LT.0.0) THEN IF (DIMAG(Z).LT.0.0) CBY0=CBY0-2.0D0*CI*CBJ0 IF (DIMAG(Z).GT.0.0) CBY0=CBY0+2.0D0*CI*CBJ0 IF (DIMAG(Z).LT.0.0) CBY1=-(CBY1-2.0D0*CI*CBJ1) IF (DIMAG(Z).GT.0.0) CBY1=-(CBY1+2.0D0*CI*CBJ1) CBJ1=-CBJ1 ENDIF CDJ0=-CBJ1 CDJ1=CBJ0-1.0D0/Z*CBJ1 CDY0=-CBY1 CDY1=CBY0-1.0D0/Z*CBY1 RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcjylv.for000077500000000000000000000111021321604176500261250ustar00rootroot00000000000000 PROGRAM MCJYLV C C ======================================================== C Purpose: This program computes Bessel functions Jv(z) C and Yv(z) and their derivatives with a large C order and complex argument using subroutine C CJYLV C Input: v --- Order of Jv(z) and Yv(z) C z --- Complex argument C Output: CBJV --- Jv(z) C CDJV --- Jv'(z) C CBYV --- Yv(z) C CDYV --- Yv'(z) C Examples: C v = 100.00, z = 4.00 + 2.00 i C C Jv(z) = -.6444792518-123 + .6619157435-123 i C Jv'(z)= -.6251103777-122 + .1967638668-121 i C Yv(z) = .2403065353+121 + .2472039414+121 i C Yv'(z)= -.7275814786+122 - .2533588851+122 i C C v =100.5, z = 4.00 + 2.00 i C C Jv(z) = -.1161315754-123 + .7390127781-124 i C Jv'(z)= -.1588519437-122 + .2652227059-122 i C Yv(z) = .1941381412+122 + .1237578195+122 i C Yv'(z)= -.5143285247+123 - .5320026773+122 i C ======================================================== C IMPLICIT DOUBLE PRECISION (V,X,Y) IMPLICIT COMPLEX*16 (C,Z) WRITE(*,*)'Please enter v,x and y ( z = x+iy )' READ(*,*)V,X,Y WRITE(*,10)V,X,Y Z=CMPLX(X,Y) CALL CJYLV(V,Z,CBJV,CDJV,CBYV,CDYV) WRITE(*,*) WRITE(*,20)CBJV WRITE(*,30)CDJV WRITE(*,*) WRITE(*,40)CBYV WRITE(*,50)CDYV 10 FORMAT(8X,'v = ',F6.2,', ','z =',F7.2,' + i ',F7.2) 20 FORMAT(8X,'Jv(z) =',D17.10,' + i',D17.10) 30 FORMAT(8X,'Jv''(z)=',D17.10,' + i',D17.10) 40 FORMAT(8X,'Yv(z) =',D17.10,' + i',D17.10) 50 FORMAT(8X,'Yv''(z)=',D17.10,' + i',D17.10) END SUBROUTINE CJYLV(V,Z,CBJV,CDJV,CBYV,CDYV) C C =================================================== C Purpose: Compute Bessel functions Jv(z) and Yv(z) C and their derivatives with a complex C argument and a large order C Input: v --- Order of Jv(z) and Yv(z) C z --- Complex argument C Output: CBJV --- Jv(z) C CDJV --- Jv'(z) C CBYV --- Yv(z) C CDYV --- Yv'(z) C Routine called: C CJK to compute the expansion coefficients C =================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CF(12),A(91) KM=12 CALL CJK(KM,A) PI=3.141592653589793D0 DO 30 L=1,0,-1 V0=V-L CWS=CDSQRT(1.0D0-(Z/V0)*(Z/V0)) CETA=CWS+CDLOG(Z/V0/(1.0D0+CWS)) CT=1.0D0/CWS CT2=CT*CT DO 15 K=1,KM L0=K*(K+1)/2+1 LF=L0+K CF(K)=A(LF) DO 10 I=LF-1,L0,-1 10 CF(K)=CF(K)*CT2+A(I) 15 CF(K)=CF(K)*CT**K VR=1.0D0/V0 CSJ=(1.0D0,0.0D0) DO 20 K=1,KM 20 CSJ=CSJ+CF(K)*VR**K CBJV=CDSQRT(CT/(2.0D0*PI*V0))*CDEXP(V0*CETA)*CSJ IF (L.EQ.1) CFJ=CBJV CSY=(1.0D0,0.0D0) DO 25 K=1,KM 25 CSY=CSY+(-1)**K*CF(K)*VR**K CBYV=-CDSQRT(2.0D0*CT/(PI*V0))*CDEXP(-V0*CETA)*CSY IF (L.EQ.1) CFY=CBYV 30 CONTINUE CDJV=-V/Z*CBJV+CFJ CDYV=-V/Z*CBYV+CFY RETURN END SUBROUTINE CJK(KM,A) C C ======================================================== C Purpose: Compute the expansion coefficients for the C asymptotic expansion of Bessel functions C with large orders C Input : Km --- Maximum k C Output: A(L) --- Cj(k) where j and k are related to L C by L=j+1+[k*(k+1)]/2; j,k=0,1,...,Km C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(*) A(1)=1.0D0 F0=1.0D0 G0=1.0D0 DO 10 K=0,KM-1 L1=(K+1)*(K+2)/2+1 L2=(K+1)*(K+2)/2+K+2 F=(0.5D0*K+0.125D0/(K+1))*F0 G=-(1.5D0*K+0.625D0/(3.0*(K+1.0D0)))*G0 A(L1)=F A(L2)=G F0=F 10 G0=G DO 15 K=1,KM-1 DO 15 J=1,K L3=K*(K+1)/2+J+1 L4=(K+1)*(K+2)/2+J+1 A(L4)=(J+0.5D0*K+0.125D0/(2.0*J+K+1.0))*A(L3) & -(J+0.5D0*K-1.0+0.625D0/(2.0*J+K+1.0))*A(L3-1) 15 CONTINUE RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcjyna.for000077500000000000000000000364331321604176500261200ustar00rootroot00000000000000 PROGRAM MCJYNA C C ================================================================ C Purpose: This program computes Bessel functions Jn(z), Yn(z) C and their derivatives for a complex argument using C subroutine CJYNA C Input : z --- Complex argument of Jn(z) and Yn(z) C n --- Order of Jn(z) and Yn(z) C ( n = 0,1,úúú, n ó 250 ) C Output: CBJ(n) --- Jn(z) C CDJ(n) --- Jn'(z) C CBY(n) --- Yn(z) C CDY(n) --- Yn'(z) C Eaxmple: z = 4.0 + i 2.0 C C n Re[Jn(z)] Im[Jn(z)] Re[Jn'(z)] Im[Jn'(z)] C ------------------------------------------------------------------- C 0 -.13787022D+01 .39054236D+00 .50735255D+00 .12263041D+01 C 1 -.50735255D+00 -.12263041D+01 -.11546013D+01 .58506793D+00 C 2 .93050039D+00 -.77959350D+00 -.72363400D+00 -.72836666D+00 C 3 .93991546D+00 .23042918D+00 .29742236D+00 -.63587637D+00 C 4 .33565567D+00 .49215925D+00 .47452722D+00 -.29035945D-01 C 5 -.91389835D-02 .28850107D+00 .20054412D+00 .19908868D+00 C C n Re[Yn(z)] Im[Yn(z)] Re[Yn'(z)] Im[Yn'(z)] C -------------------------------------------------------------------- C 0 -.38145893D+00 -.13291649D+01 -.12793101D+01 .51220420D+00 C 1 .12793101D+01 -.51220420D+00 -.58610052D+00 -.10987930D+01 C 2 .79074211D+00 .86842120D+00 .78932897D+00 -.70142425D+00 C 3 -.29934789D+00 .89064431D+00 .70315755D+00 .24423024D+00 C 4 -.61557299D+00 .37996071D+00 .41126221D-01 .34044655D+00 C 5 -.38160033D+00 .20975121D+00 -.33884827D+00 -.20590670D-01 C C z = 20.0 + i 10.0 , Nmax = 5 C C n Re[Jn(z)] Im[Jn(z)] Re[Jn'(z)] Im[Jn'(z)] C -------------------------------------------------------------------- C 0 .15460268D+04 -.10391216D+04 -.10601232D+04 -.15098284D+04 C 1 .10601232D+04 .15098284D+04 .14734253D+04 -.10783122D+04 C 2 -.14008238D+04 .11175029D+04 .11274890D+04 .13643952D+04 C 3 -.11948548D+04 -.12189620D+04 -.11843035D+04 .11920871D+04 C 4 .96778325D+03 -.12666712D+04 -.12483664D+04 -.93887194D+03 C 5 .13018781D+04 .65878188D+03 .64152944D+03 -.12682398D+04 C C n Re[Yn(z)] Im[Yn(z)] Re[Yn'(z)] Im[Yn'(z)] C -------------------------------------------------------------------- C 0 .10391216D+04 .15460268D+04 .15098284D+04 -.10601232D+04 C 1 -.15098284D+04 .10601232D+04 .10783122D+04 .14734253D+04 C 2 -.11175029D+04 -.14008238D+04 -.13643952D+04 .11274890D+04 C 3 .12189620D+04 -.11948548D+04 -.11920871D+04 -.11843035D+04 C 4 .12666712D+04 .96778324D+03 .93887194D+03 -.12483664D+04 C 5 -.65878189D+03 .13018781D+04 .12682398D+04 .64152944D+03 C ================================================================ C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) COMMON CBJ(0:251),CDJ(0:251),CBY(0:251),CDY(0:251) WRITE(*,*)' Please enter n, x,y (z=x+iy) ' READ(*,*)N,X,Y Z=CMPLX(X,Y) WRITE(*,40)X,Y,N IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL CJYNA(N,Z,NM,CBJ,CDJ,CBY,CDY) WRITE(*,*) WRITE(*,*)' n Re[Jn(z)] Im[Jn(z)]', & ' Re[Jn''(z)] Im[Jn''(z)]' WRITE(*,*)' -------------------------------------', & '-------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,30)K,CBJ(K),CDJ(K) WRITE(*,*) WRITE(*,*)' n Re[Yn(z)] Im[Yn(z)]', & ' Re[Yn''(z)] Im[Yn''(z)]' WRITE(*,*)' -------------------------------------', & '-------------------------------' DO 20 K=0,NM,NS 20 WRITE(*,30)K,CBY(K),CDY(K) 30 FORMAT(1X,I4,4D16.8) 40 FORMAT(3X,3Hz =,F5.1,' + i ',F5.1,' ,',6X,6HNmax =,I3) END SUBROUTINE CJYNA(N,Z,NM,CBJ,CDJ,CBY,CDY) C C ======================================================= C Purpose: Compute Bessel functions Jn(z), Yn(z) and C their derivatives for a complex argument C Input : z --- Complex argument of Jn(z) and Yn(z) C n --- Order of Jn(z) and Yn(z) C Output: CBJ(n) --- Jn(z) C CDJ(n) --- Jn'(z) C CBY(n) --- Yn(z) C CDY(n) --- Yn'(z) C NM --- Highest order computed C Rouitines called: C (1) CJY01 to calculate J0(z), J1(z), Y0(z), Y1(z) C (2) MSTA1 and MSTA2 to calculate the starting C point for backward recurrence C ======================================================= C IMPLICIT DOUBLE PRECISION (A,B,E,P,R,W,Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBJ(0:N),CDJ(0:N),CBY(0:N),CDY(0:N) PI=3.141592653589793D0 A0=CDABS(Z) NM=N IF (A0.LT.1.0D-100) THEN DO 5 K=0,N CBJ(K)=(0.0D0,0.0D0) CDJ(K)=(0.0D0,0.0D0) CBY(K)=-(1.0D+300,0.0D0) 5 CDY(K)=(1.0D+300,0.0D0) CBJ(0)=(1.0D0,0.0D0) CDJ(1)=(0.5D0,0.0D0) RETURN ENDIF CALL CJY01(Z,CBJ0,CDJ0,CBJ1,CDJ1,CBY0,CDY0,CBY1,CDY1) CBJ(0)=CBJ0 CBJ(1)=CBJ1 CBY(0)=CBY0 CBY(1)=CBY1 CDJ(0)=CDJ0 CDJ(1)=CDJ1 CDY(0)=CDY0 CDY(1)=CDY1 IF (N.LE.1) RETURN IF (N.LT.INT(0.25*A0)) THEN CJ0=CBJ0 CJ1=CBJ1 DO 70 K=2,N CJK=2.0D0*(K-1.0D0)/Z*CJ1-CJ0 CBJ(K)=CJK CJ0=CJ1 70 CJ1=CJK ELSE M=MSTA1(A0,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(A0,N,15) ENDIF CF2=(0.0D0,0.0D0) CF1=(1.0D-100,0.0D0) DO 75 K=M,0,-1 CF=2.0D0*(K+1.0D0)/Z*CF1-CF2 IF (K.LE.NM) CBJ(K)=CF CF2=CF1 75 CF1=CF IF (CDABS(CBJ0).GT.CDABS(CBJ1)) THEN CS=CBJ0/CF ELSE CS=CBJ1/CF2 ENDIF DO 80 K=0,NM 80 CBJ(K)=CS*CBJ(K) ENDIF DO 85 K=2,NM 85 CDJ(K)=CBJ(K-1)-K/Z*CBJ(K) YA0=CDABS(CBY0) LB=0 CG0=CBY0 CG1=CBY1 DO 90 K=2,NM CYK=2.0D0*(K-1.0D0)/Z*CG1-CG0 IF (CDABS(CYK).GT.1.0D+290) GO TO 90 YAK=CDABS(CYK) YA1=CDABS(CG0) IF (YAK.LT.YA0.AND.YAK.LT.YA1) LB=K CBY(K)=CYK CG0=CG1 CG1=CYK 90 CONTINUE IF (LB.LE.4.OR.DIMAG(Z).EQ.0.0D0) GO TO 125 95 IF (LB.EQ.LB0) GO TO 125 CH2=(1.0D0,0.0D0) CH1=(0.0D0,0.0D0) LB0=LB DO 100 K=LB,1,-1 CH0=2.0D0*K/Z*CH1-CH2 CH2=CH1 100 CH1=CH0 CP12=CH0 CP22=CH2 CH2=(0.0D0,0.0D0) CH1=(1.0D0,0.0D0) DO 105 K=LB,1,-1 CH0=2.0D0*K/Z*CH1-CH2 CH2=CH1 105 CH1=CH0 CP11=CH0 CP21=CH2 IF (LB.EQ.NM) CBJ(LB+1)=2.0D0*LB/Z*CBJ(LB)-CBJ(LB-1) IF (CDABS(CBJ(0)).GT.CDABS(CBJ(1))) THEN CBY(LB+1)=(CBJ(LB+1)*CBY0-2.0D0*CP11/(PI*Z))/CBJ(0) CBY(LB)=(CBJ(LB)*CBY0+2.0D0*CP12/(PI*Z))/CBJ(0) ELSE CBY(LB+1)=(CBJ(LB+1)*CBY1-2.0D0*CP21/(PI*Z))/CBJ(1) CBY(LB)=(CBJ(LB)*CBY1+2.0D0*CP22/(PI*Z))/CBJ(1) ENDIF CYL2=CBY(LB+1) CYL1=CBY(LB) DO 110 K=LB-1,0,-1 CYLK=2.0D0*(K+1.0D0)/Z*CYL1-CYL2 CBY(K)=CYLK CYL2=CYL1 110 CYL1=CYLK CYL1=CBY(LB) CYL2=CBY(LB+1) DO 115 K=LB+1,NM-1 CYLK=2.0D0*K/Z*CYL2-CYL1 CBY(K+1)=CYLK CYL1=CYL2 115 CYL2=CYLK DO 120 K=2,NM WA=CDABS(CBY(K)) IF (WA.LT.CDABS(CBY(K-1))) LB=K 120 CONTINUE GO TO 95 125 CONTINUE DO 130 K=2,NM 130 CDY(K)=CBY(K-1)-K/Z*CBY(K) RETURN END SUBROUTINE CJY01(Z,CBJ0,CDJ0,CBJ1,CDJ1,CBY0,CDY0,CBY1,CDY1) C C =========================================================== C Purpose: Compute complex Bessel functions J0(z), J1(z) C Y0(z), Y1(z), and their derivatives C Input : z --- Complex argument C Output: CBJ0 --- J0(z) C CDJ0 --- J0'(z) C CBJ1 --- J1(z) C CDJ1 --- J1'(z) C CBY0 --- Y0(z) C CDY0 --- Y0'(z) C CBY1 --- Y1(z) C CDY1 --- Y1'(z) C =========================================================== C IMPLICIT DOUBLE PRECISION (A,B,E,P,R,W) IMPLICIT COMPLEX*16 (C,Z) DIMENSION A(12),B(12),A1(12),B1(12) PI=3.141592653589793D0 EL=0.5772156649015329D0 RP2=2.0D0/PI CI=(0.0D0,1.0D0) A0=CDABS(Z) Z2=Z*Z Z1=Z IF (A0.EQ.0.0D0) THEN CBJ0=(1.0D0,0.0D0) CBJ1=(0.0D0,0.0D0) CDJ0=(0.0D0,0.0D0) CDJ1=(0.5D0,0.0D0) CBY0=-(1.0D300,0.0D0) CBY1=-(1.0D300,0.0D0) CDY0=(1.0D300,0.0D0) CDY1=(1.0D300,0.0D0) RETURN ENDIF IF (REAL(Z).LT.0.0) Z1=-Z IF (A0.LE.12.0) THEN CBJ0=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 10 K=1,40 CR=-0.25D0*CR*Z2/(K*K) CBJ0=CBJ0+CR IF (CDABS(CR/CBJ0).LT.1.0D-15) GO TO 15 10 CONTINUE 15 CBJ1=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 20 K=1,40 CR=-0.25D0*CR*Z2/(K*(K+1.0D0)) CBJ1=CBJ1+CR IF (CDABS(CR/CBJ1).LT.1.0D-15) GO TO 25 20 CONTINUE 25 CBJ1=0.5D0*Z1*CBJ1 W0=0.0D0 CR=(1.0D0,0.0D0) CS=(0.0D0,0.0D0) DO 30 K=1,40 W0=W0+1.0D0/K CR=-0.25D0*CR/(K*K)*Z2 CP=CR*W0 CS=CS+CP IF (CDABS(CP/CS).LT.1.0D-15) GO TO 35 30 CONTINUE 35 CBY0=RP2*(CDLOG(Z1/2.0D0)+EL)*CBJ0-RP2*CS W1=0.0D0 CR=(1.0D0,0.0D0) CS=(1.0D0,0.0D0) DO 40 K=1,40 W1=W1+1.0D0/K CR=-0.25D0*CR/(K*(K+1))*Z2 CP=CR*(2.0D0*W1+1.0D0/(K+1.0D0)) CS=CS+CP IF (CDABS(CP/CS).LT.1.0D-15) GO TO 45 40 CONTINUE 45 CBY1=RP2*((CDLOG(Z1/2.0D0)+EL)*CBJ1-1.0D0/Z1-.25D0*Z1*CS) ELSE DATA A/-.703125D-01,.112152099609375D+00, & -.5725014209747314D+00,.6074042001273483D+01, & -.1100171402692467D+03,.3038090510922384D+04, & -.1188384262567832D+06,.6252951493434797D+07, & -.4259392165047669D+09,.3646840080706556D+11, & -.3833534661393944D+13,.4854014686852901D+15/ DATA B/ .732421875D-01,-.2271080017089844D+00, & .1727727502584457D+01,-.2438052969955606D+02, & .5513358961220206D+03,-.1825775547429318D+05, & .8328593040162893D+06,-.5006958953198893D+08, & .3836255180230433D+10,-.3649010818849833D+12, & .4218971570284096D+14,-.5827244631566907D+16/ DATA A1/.1171875D+00,-.144195556640625D+00, & .6765925884246826D+00,-.6883914268109947D+01, & .1215978918765359D+03,-.3302272294480852D+04, & .1276412726461746D+06,-.6656367718817688D+07, & .4502786003050393D+09,-.3833857520742790D+11, & .4011838599133198D+13,-.5060568503314727D+15/ DATA B1/-.1025390625D+00,.2775764465332031D+00, & -.1993531733751297D+01,.2724882731126854D+02, & -.6038440767050702D+03,.1971837591223663D+05, & -.8902978767070678D+06,.5310411010968522D+08, & -.4043620325107754D+10,.3827011346598605D+12, & -.4406481417852278D+14,.6065091351222699D+16/ K0=12 IF (A0.GE.35.0) K0=10 IF (A0.GE.50.0) K0=8 CT1=Z1-0.25D0*PI CP0=(1.0D0,0.0D0) DO 50 K=1,K0 50 CP0=CP0+A(K)*Z1**(-2*K) CQ0=-0.125D0/Z1 DO 55 K=1,K0 55 CQ0=CQ0+B(K)*Z1**(-2*K-1) CU=CDSQRT(RP2/Z1) CBJ0=CU*(CP0*CDCOS(CT1)-CQ0*CDSIN(CT1)) CBY0=CU*(CP0*CDSIN(CT1)+CQ0*CDCOS(CT1)) CT2=Z1-0.75D0*PI CP1=(1.0D0,0.0D0) DO 60 K=1,K0 60 CP1=CP1+A1(K)*Z1**(-2*K) CQ1=0.375D0/Z1 DO 65 K=1,K0 65 CQ1=CQ1+B1(K)*Z1**(-2*K-1) CBJ1=CU*(CP1*CDCOS(CT2)-CQ1*CDSIN(CT2)) CBY1=CU*(CP1*CDSIN(CT2)+CQ1*CDCOS(CT2)) ENDIF IF (REAL(Z).LT.0.0) THEN IF (DIMAG(Z).LT.0.0) CBY0=CBY0-2.0D0*CI*CBJ0 IF (DIMAG(Z).GT.0.0) CBY0=CBY0+2.0D0*CI*CBJ0 IF (DIMAG(Z).LT.0.0) CBY1=-(CBY1-2.0D0*CI*CBJ1) IF (DIMAG(Z).GT.0.0) CBY1=-(CBY1+2.0D0*CI*CBJ1) CBJ1=-CBJ1 ENDIF CDJ0=-CBJ1 CDJ1=CBJ0-1.0D0/Z*CBJ1 CDY0=-CBY1 CDY1=CBY0-1.0D0/Z*CBY1 RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcjynb.for000077500000000000000000000251531321604176500261160ustar00rootroot00000000000000 PROGRAM MCJYNB C C ================================================================ C Purpose: This program computes Bessel functions Jn(z), Yn(z) C and their derivatives for a complex argument using C subroutine CJYNB C Input : z --- Complex argument of Jn(z) and Yn(z) C n --- Order of Jn(z) and Yn(z) C ( n = 0,1,úúú, n ó 250 ) C Output: CBJ(n) --- Jn(z) C CDJ(n) --- Jn'(z) C CBY(n) --- Yn(z) C CDY(n) --- Yn'(z) C Eaxmple: z = 4.0 + i 2.0 C C n Re[Jn(z)] Im[Jn(z)] Re[Jn'(z)] Im[Jn'(z)] C ------------------------------------------------------------------- C 0 -.13787022D+01 .39054236D+00 .50735255D+00 .12263041D+01 C 1 -.50735255D+00 -.12263041D+01 -.11546013D+01 .58506793D+00 C 2 .93050039D+00 -.77959350D+00 -.72363400D+00 -.72836666D+00 C 3 .93991546D+00 .23042918D+00 .29742236D+00 -.63587637D+00 C 4 .33565567D+00 .49215925D+00 .47452722D+00 -.29035945D-01 C 5 -.91389835D-02 .28850107D+00 .20054412D+00 .19908868D+00 C C n Re[Yn(z)] Im[Yn(z)] Re[Yn'(z)] Im[Yn'(z)] C -------------------------------------------------------------------- C 0 -.38145893D+00 -.13291649D+01 -.12793101D+01 .51220420D+00 C 1 .12793101D+01 -.51220420D+00 -.58610052D+00 -.10987930D+01 C 2 .79074211D+00 .86842120D+00 .78932897D+00 -.70142425D+00 C 3 -.29934789D+00 .89064431D+00 .70315755D+00 .24423024D+00 C 4 -.61557299D+00 .37996071D+00 .41126221D-01 .34044655D+00 C 5 -.38160033D+00 .20975121D+00 -.33884827D+00 -.20590670D-01 C C z = 20.0 + i 10.0 , Nmax = 5 C C n Re[Jn(z)] Im[Jn(z)] Re[Jn'(z)] Im[Jn'(z)] C -------------------------------------------------------------------- C 0 .15460268D+04 -.10391216D+04 -.10601232D+04 -.15098284D+04 C 1 .10601232D+04 .15098284D+04 .14734253D+04 -.10783122D+04 C 2 -.14008238D+04 .11175029D+04 .11274890D+04 .13643952D+04 C 3 -.11948548D+04 -.12189620D+04 -.11843035D+04 .11920871D+04 C 4 .96778325D+03 -.12666712D+04 -.12483664D+04 -.93887194D+03 C 5 .13018781D+04 .65878188D+03 .64152944D+03 -.12682398D+04 C C n Re[Yn(z)] Im[Yn(z)] Re[Yn'(z)] Im[Yn'(z)] C -------------------------------------------------------------------- C 0 .10391216D+04 .15460268D+04 .15098284D+04 -.10601232D+04 C 1 -.15098284D+04 .10601232D+04 .10783122D+04 .14734253D+04 C 2 -.11175029D+04 -.14008238D+04 -.13643952D+04 .11274890D+04 C 3 .12189620D+04 -.11948548D+04 -.11920871D+04 -.11843035D+04 C 4 .12666712D+04 .96778324D+03 .93887194D+03 -.12483664D+04 C 5 -.65878189D+03 .13018781D+04 .12682398D+04 .64152944D+03 C ================================================================ C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) COMMON CBJ(0:250),CDJ(0:250),CBY(0:250),CDY(0:250) WRITE(*,*)' Please enter n, x,y (z=x+iy) ' READ(*,*)N,X,Y Z=CMPLX(X,Y) WRITE(*,40)X,Y,N IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL CJYNB(N,Z,NM,CBJ,CDJ,CBY,CDY) WRITE(*,*) WRITE(*,*)' n Re[Jn(z)] Im[Jn(z)]', & ' Re[Jn''(z)] Im[Jn''(z)]' WRITE(*,*)' -------------------------------------', & '-------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,30)K,CBJ(K),CDJ(K) WRITE(*,*) WRITE(*,*)' n Re[Yn(z)] Im[Yn(z)]', & ' Re[Yn''(z)] Im[Yn''(z)]' WRITE(*,*)' -------------------------------------', & '-------------------------------' DO 20 K=0,NM,NS 20 WRITE(*,30)K,CBY(K),CDY(K) 30 FORMAT(1X,I4,4D16.8) 40 FORMAT(3X,3Hz =,F5.1,' + i ',F5.1,' ,',6X,6HNmax =,I3) END SUBROUTINE CJYNB(N,Z,NM,CBJ,CDJ,CBY,CDY) C C ======================================================= C Purpose: Compute Bessel functions Jn(z), Yn(z) and C their derivatives for a complex argument C Input : z --- Complex argument of Jn(z) and Yn(z) C n --- Order of Jn(z) and Yn(z) C Output: CBJ(n) --- Jn(z) C CDJ(n) --- Jn'(z) C CBY(n) --- Yn(z) C CDY(n) --- Yn'(z) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 to calculate the starting C point for backward recurrence C ======================================================= C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBJ(0:N),CDJ(0:N),CBY(0:N),CDY(0:N), & A(4),B(4),A1(4),B1(4) EL=0.5772156649015329D0 PI=3.141592653589793D0 R2P=.63661977236758D0 Y0=DABS(DIMAG(Z)) A0=CDABS(Z) NM=N IF (A0.LT.1.0D-100) THEN DO 10 K=0,N CBJ(K)=(0.0D0,0.0D0) CDJ(K)=(0.0D0,0.0D0) CBY(K)=-(1.0D+300,0.0D0) 10 CDY(K)=(1.0D+300,0.0D0) CBJ(0)=(1.0D0,0.0D0) CDJ(1)=(0.5D0,0.0D0) RETURN ENDIF IF (A0.LE.300.D0.OR.N.GT.INT(0.25*A0)) THEN IF (N.EQ.0) NM=1 M=MSTA1(A0,200) IF (M.LT.NM) THEN NM=M ELSE M=MSTA2(A0,NM,15) ENDIF CBS=(0.0D0,0.0D0) CSU=(0.0D0,0.0D0) CSV=(0.0D0,0.0D0) CF2=(0.0D0,0.0D0) CF1=(1.0D-100,0.0D0) DO 15 K=M,0,-1 CF=2.0D0*(K+1.0D0)/Z*CF1-CF2 IF (K.LE.NM) CBJ(K)=CF IF (K.EQ.2*INT(K/2).AND.K.NE.0) THEN IF (Y0.LE.1.0D0) THEN CBS=CBS+2.0D0*CF ELSE CBS=CBS+(-1)**(K/2)*2.0D0*CF ENDIF CSU=CSU+(-1)**(K/2)*CF/K ELSE IF (K.GT.1) THEN CSV=CSV+(-1)**(K/2)*K/(K*K-1.0D0)*CF ENDIF CF2=CF1 15 CF1=CF IF (Y0.LE.1.0D0) THEN CS0=CBS+CF ELSE CS0=(CBS+CF)/CDCOS(Z) ENDIF DO 20 K=0,NM 20 CBJ(K)=CBJ(K)/CS0 CE=CDLOG(Z/2.0D0)+EL CBY(0)=R2P*(CE*CBJ(0)-4.0D0*CSU/CS0) CBY(1)=R2P*(-CBJ(0)/Z+(CE-1.0D0)*CBJ(1)-4.0D0*CSV/CS0) ELSE DATA A/-.7031250000000000D-01,.1121520996093750D+00, & -.5725014209747314D+00,.6074042001273483D+01/ DATA B/ .7324218750000000D-01,-.2271080017089844D+00, & .1727727502584457D+01,-.2438052969955606D+02/ DATA A1/.1171875000000000D+00,-.1441955566406250D+00, & .6765925884246826D+00,-.6883914268109947D+01/ DATA B1/-.1025390625000000D+00,.2775764465332031D+00, & -.1993531733751297D+01,.2724882731126854D+02/ CT1=Z-0.25D0*PI CP0=(1.0D0,0.0D0) DO 25 K=1,4 25 CP0=CP0+A(K)*Z**(-2*K) CQ0=-0.125D0/Z DO 30 K=1,4 30 CQ0=CQ0+B(K)*Z**(-2*K-1) CU=CDSQRT(R2P/Z) CBJ0=CU*(CP0*CDCOS(CT1)-CQ0*CDSIN(CT1)) CBY0=CU*(CP0*CDSIN(CT1)+CQ0*CDCOS(CT1)) CBJ(0)=CBJ0 CBY(0)=CBY0 CT2=Z-0.75D0*PI CP1=(1.0D0,0.0D0) DO 35 K=1,4 35 CP1=CP1+A1(K)*Z**(-2*K) CQ1=0.375D0/Z DO 40 K=1,4 40 CQ1=CQ1+B1(K)*Z**(-2*K-1) CBJ1=CU*(CP1*CDCOS(CT2)-CQ1*CDSIN(CT2)) CBY1=CU*(CP1*CDSIN(CT2)+CQ1*CDCOS(CT2)) CBJ(1)=CBJ1 CBY(1)=CBY1 DO 45 K=2,NM CBJK=2.0D0*(K-1.0D0)/Z*CBJ1-CBJ0 CBJ(K)=CBJK CBJ0=CBJ1 45 CBJ1=CBJK ENDIF CDJ(0)=-CBJ(1) DO 50 K=1,NM 50 CDJ(K)=CBJ(K-1)-K/Z*CBJ(K) IF (CDABS(CBJ(0)).GT.1.0D0) THEN CBY(1)=(CBJ(1)*CBY(0)-2.0D0/(PI*Z))/CBJ(0) ENDIF DO 55 K=2,NM IF (CDABS(CBJ(K-1)).GE.CDABS(CBJ(K-2))) THEN CYY=(CBJ(K)*CBY(K-1)-2.0D0/(PI*Z))/CBJ(K-1) ELSE CYY=(CBJ(K)*CBY(K-2)-4.0D0*(K-1.0D0)/(PI*Z*Z))/CBJ(K-2) ENDIF CBY(K)=CYY 55 CONTINUE CDY(0)=-CBY(1) DO 60 K=1,NM 60 CDY(K)=CBY(K-1)-K/Z*CBY(K) RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcjyva.for000077500000000000000000000351651321604176500261310ustar00rootroot00000000000000 PROGRAM MCJYVA C C =============================================================== C Purpose: This program computes Bessel functions Jv(z), Yv(z), C and their derivatives for a complex argument using C subroutine CJYVA C Input : z --- Complex argument C v --- Order of Jv(z) and Yv(z) C ( v = n+v0, 0 ó n ó 250, 0 ó v0 < 1 ) C Output: CBJ(n) --- Jn+v0(z) C CDJ(n) --- Jn+v0'(z) C CBY(n) --- Yn+v0(z) C CDY(n) --- Yn+v0'(z) C Example: C v = n +v0, v0 = 1/3, z = 4.0 + i 2.0 C C n Re[Jv(z)] Im[Jv(z)] Re[Jv'(z)] Im[Jv'(z)] C ------------------------------------------------------------------ C 0 -.13829878D+01 -.30855145D+00 -.18503756D+00 .13103689D+01 C 1 .82553327D-01 -.12848394D+01 -.12336901D+01 .45079506D-01 C 2 .10843924D+01 -.39871046D+00 -.33046401D+00 -.84574964D+00 C 3 .74348135D+00 .40665987D+00 .45318486D+00 -.42198992D+00 C 4 .17802266D+00 .44526939D+00 .39624497D+00 .97902890D-01 C 5 -.49008598D-01 .21085409D+00 .11784299D+00 .19422044D+00 C C n Re[Yv(z)] Im[Yv(z)] Re[Yv'(z)] Im[Yv'(z)] C ------------------------------------------------------------------ C 0 .34099851D+00 -.13440666D+01 -.13544477D+01 -.15470699D+00 C 1 .13323787D+01 .53735934D-01 -.21467271D-01 -.11807457D+01 C 2 .38393305D+00 .10174248D+01 .91581083D+00 -.33147794D+00 C 3 -.49924295D+00 .71669181D+00 .47786442D+00 .37321597D+00 C 4 -.57179578D+00 .27099289D+00 -.12111686D+00 .23405313D+00 C 5 -.25700924D+00 .24858555D+00 -.43023156D+00 -.13123662D+00 C =============================================================== C IMPLICIT DOUBLE PRECISION (V,X,Y) IMPLICIT COMPLEX*16 (C,Z) COMMON CBJ(0:251),CDJ(0:251),CBY(0:251),CDY(0:251) WRITE(*,*)' Please enter v, x and y ( z=x+iy )' READ(*,*)V,X,Y Z=CMPLX(X,Y) N=INT(V) V0=V-N WRITE(*,25)V0,X,Y IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL CJYVA(V,Z,VM,CBJ,CDJ,CBY,CDY) NM=INT(VM) WRITE(*,*) WRITE(*,*)' n Re[Jv(z)] Im[Jv(z)]', & ' Re[Jv''(z)] Im[Jv''(z)]' WRITE(*,*)' ----------------------------------', & '-----------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20) K,CBJ(K),CDJ(K) WRITE(*,*) WRITE(*,*)' n Re[Yv(z)] Im[Yv(z)]', & ' Re[Yv''(z)] Im[Yv''(z)]' WRITE(*,*)' ----------------------------------', & '-----------------------------------' DO 15 K=0,NM,NS 15 WRITE(*,20) K,CBY(K),CDY(K) 20 FORMAT(1X,I3,2X,4D16.8) 25 FORMAT(8X,'v = n+v0',', v0 =',F5.2,', z =',F7.2,' +',F7.2,'i') END SUBROUTINE CJYVA(V,Z,VM,CBJ,CDJ,CBY,CDY) C C =========================================================== C Purpose: Compute Bessel functions Jv(z), Yv(z) and their C derivatives for a complex argument C Input : z --- Complex argument C v --- Order of Jv(z) and Yv(z) C ( v = n+v0, n = 0,1,2,..., 0 ó v0 < 1 ) C Output: CBJ(n) --- Jn+v0(z) C CDJ(n) --- Jn+v0'(z) C CBY(n) --- Yn+v0(z) C CDY(n) --- Yn+v0'(z) C VM --- Highest order computed C Routines called: C (1) GAMMA for computing the gamma function C (2) MSTA1 and MSTA2 for computing the starting C point for backward recurrence C =========================================================== C IMPLICIT DOUBLE PRECISION (A,B,G,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBJ(0:*),CDJ(0:*),CBY(0:*),CDY(0:*) PI=3.141592653589793D0 RP2=.63661977236758D0 CI=(0.0D0,1.0D0) A0=CDABS(Z) Z1=Z Z2=Z*Z N=INT(V) V0=V-N PV0=PI*V0 PV1=PI*(1.0D0+V0) IF (A0.LT.1.0D-100) THEN DO 10 K=0,N CBJ(K)=(0.0D0,0.0D0) CDJ(K)=(0.0D0,0.0D0) CBY(K)=-(1.0D+300,0.0D0) 10 CDY(K)=(1.0D+300,0.0D0) IF (V0.EQ.0.0) THEN CBJ(0)=(1.0D0,0.0D0) CDJ(1)=(0.5D0,0.0D0) ELSE CDJ(0)=(1.0D+300,0.0D0) ENDIF VM=V RETURN ENDIF IF (REAL(Z).LT.0.0) Z1=-Z IF (A0.LE.12.0) THEN DO 25 L=0,1 VL=V0+L CJVL=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 15 K=1,40 CR=-0.25D0*CR*Z2/(K*(K+VL)) CJVL=CJVL+CR IF (CDABS(CR).LT.CDABS(CJVL)*1.0D-15) GO TO 20 15 CONTINUE 20 VG=1.0D0+VL CALL GAMMA(VG,GA) CA=(0.5D0*Z1)**VL/GA IF (L.EQ.0) CJV0=CJVL*CA IF (L.EQ.1) CJV1=CJVL*CA 25 CONTINUE ELSE K0=11 IF (A0.GE.35.0) K0=10 IF (A0.GE.50.0) K0=8 DO 40 J=0,1 VV=4.0D0*(J+V0)*(J+V0) CPZ=(1.0D0,0.0D0) CRP=(1.0D0,0.0D0) DO 30 K=1,K0 CRP=-0.78125D-2*CRP*(VV-(4.0*K-3.0)**2.0)*(VV- & (4.0*K-1.0)**2.0)/(K*(2.0*K-1.0)*Z2) 30 CPZ=CPZ+CRP CQZ=(1.0D0,0.0D0) CRQ=(1.0D0,0.0D0) DO 35 K=1,K0 CRQ=-0.78125D-2*CRQ*(VV-(4.0*K-1.0)**2.0)*(VV- & (4.0*K+1.0)**2.0)/(K*(2.0*K+1.0)*Z2) 35 CQZ=CQZ+CRQ CQZ=0.125D0*(VV-1.0)*CQZ/Z1 ZK=Z1-(0.5D0*(J+V0)+0.25D0)*PI CA0=CDSQRT(RP2/Z1) CCK=CDCOS(ZK) CSK=CDSIN(ZK) IF (J.EQ.0) THEN CJV0=CA0*(CPZ*CCK-CQZ*CSK) CYV0=CA0*(CPZ*CSK+CQZ*CCK) ELSE IF (J.EQ.1) THEN CJV1=CA0*(CPZ*CCK-CQZ*CSK) CYV1=CA0*(CPZ*CSK+CQZ*CCK) ENDIF 40 CONTINUE ENDIF IF (A0.LE.12.0) THEN IF (V0.NE.0.0) THEN DO 55 L=0,1 VL=V0+L CJVL=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 45 K=1,40 CR=-0.25D0*CR*Z2/(K*(K-VL)) CJVL=CJVL+CR IF (CDABS(CR).LT.CDABS(CJVL)*1.0D-15) GO TO 50 45 CONTINUE 50 VG=1.0D0-VL CALL GAMMA(VG,GB) CB=(2.0D0/Z1)**VL/GB IF (L.EQ.0) CJU0=CJVL*CB IF (L.EQ.1) CJU1=CJVL*CB 55 CONTINUE CYV0=(CJV0*DCOS(PV0)-CJU0)/DSIN(PV0) CYV1=(CJV1*DCOS(PV1)-CJU1)/DSIN(PV1) ELSE CEC=CDLOG(Z1/2.0D0)+.5772156649015329D0 CS0=(0.0D0,0.0D0) W0=0.0D0 CR0=(1.0D0,0.0D0) DO 60 K=1,30 W0=W0+1.0D0/K CR0=-0.25D0*CR0/(K*K)*Z2 60 CS0=CS0+CR0*W0 CYV0=RP2*(CEC*CJV0-CS0) CS1=(1.0D0,0.0D0) W1=0.0D0 CR1=(1.0D0,0.0D0) DO 65 K=1,30 W1=W1+1.0D0/K CR1=-0.25D0*CR1/(K*(K+1))*Z2 65 CS1=CS1+CR1*(2.0D0*W1+1.0D0/(K+1.0D0)) CYV1=RP2*(CEC*CJV1-1.0D0/Z1-0.25D0*Z1*CS1) ENDIF ENDIF IF (REAL(Z).LT.0.0D0) THEN CFAC0=CDEXP(PV0*CI) CFAC1=CDEXP(PV1*CI) IF (DIMAG(Z).LT.0.0D0) THEN CYV0=CFAC0*CYV0-2.0D0*CI*DCOS(PV0)*CJV0 CYV1=CFAC1*CYV1-2.0D0*CI*DCOS(PV1)*CJV1 CJV0=CJV0/CFAC0 CJV1=CJV1/CFAC1 ELSE IF (DIMAG(Z).GT.0.0D0) THEN CYV0=CYV0/CFAC0+2.0D0*CI*DCOS(PV0)*CJV0 CYV1=CYV1/CFAC1+2.0D0*CI*DCOS(PV1)*CJV1 CJV0=CFAC0*CJV0 CJV1=CFAC1*CJV1 ENDIF ENDIF CBJ(0)=CJV0 CBJ(1)=CJV1 IF (N.GE.2.AND.N.LE.INT(0.25*A0)) THEN CF0=CJV0 CF1=CJV1 DO 70 K=2,N CF=2.0D0*(K+V0-1.0D0)/Z*CF1-CF0 CBJ(K)=CF CF0=CF1 70 CF1=CF ELSE IF (N.GE.2) THEN M=MSTA1(A0,200) IF (M.LT.N) THEN N=M ELSE M=MSTA2(A0,N,15) ENDIF CF2=(0.0D0,0.0D0) CF1=(1.0D-100,0.0D0) DO 75 K=M,0,-1 CF=2.0D0*(V0+K+1.0D0)/Z*CF1-CF2 IF (K.LE.N) CBJ(K)=CF CF2=CF1 75 CF1=CF IF (CDABS(CJV0).GT.CDABS(CJV1)) CS=CJV0/CF IF (CDABS(CJV0).LE.CDABS(CJV1)) CS=CJV1/CF2 DO 80 K=0,N 80 CBJ(K)=CS*CBJ(K) ENDIF CDJ(0)=V0/Z*CBJ(0)-CBJ(1) DO 85 K=1,N 85 CDJ(K)=-(K+V0)/Z*CBJ(K)+CBJ(K-1) CBY(0)=CYV0 CBY(1)=CYV1 YA0=CDABS(CYV0) LB=0 CG0=CYV0 CG1=CYV1 DO 90 K=2,N CYK=2.0D0*(V0+K-1.0D0)/Z*CG1-CG0 IF (CDABS(CYK).GT.1.0D+290) GO TO 90 YAK=CDABS(CYK) YA1=CDABS(CG0) IF (YAK.LT.YA0.AND.YAK.LT.YA1) LB=K CBY(K)=CYK CG0=CG1 CG1=CYK 90 CONTINUE IF (LB.LE.4.OR.DIMAG(Z).EQ.0.0D0) GO TO 125 95 IF (LB.EQ.LB0) GO TO 125 CH2=(1.0D0,0.0D0) CH1=(0.0D0,0.0D0) LB0=LB DO 100 K=LB,1,-1 CH0=2.0D0*(K+V0)/Z*CH1-CH2 CH2=CH1 100 CH1=CH0 CP12=CH0 CP22=CH2 CH2=(0.0D0,0.0D0) CH1=(1.0D0,0.0D0) DO 105 K=LB,1,-1 CH0=2.0D0*(K+V0)/Z*CH1-CH2 CH2=CH1 105 CH1=CH0 CP11=CH0 CP21=CH2 IF (LB.EQ.N) CBJ(LB+1)=2.0D0*(LB+V0)/Z*CBJ(LB)-CBJ(LB-1) IF (CDABS(CBJ(0)).GT.CDABS(CBJ(1))) THEN CBY(LB+1)=(CBJ(LB+1)*CYV0-2.0D0*CP11/(PI*Z))/CBJ(0) CBY(LB)=(CBJ(LB)*CYV0+2.0D0*CP12/(PI*Z))/CBJ(0) ELSE CBY(LB+1)=(CBJ(LB+1)*CYV1-2.0D0*CP21/(PI*Z))/CBJ(1) CBY(LB)=(CBJ(LB)*CYV1+2.0D0*CP22/(PI*Z))/CBJ(1) ENDIF CYL2=CBY(LB+1) CYL1=CBY(LB) DO 110 K=LB-1,0,-1 CYLK=2.0D0*(K+V0+1.0D0)/Z*CYL1-CYL2 CBY(K)=CYLK CYL2=CYL1 110 CYL1=CYLK CYL1=CBY(LB) CYL2=CBY(LB+1) DO 115 K=LB+1,N-1 CYLK=2.0D0*(K+V0)/Z*CYL2-CYL1 CBY(K+1)=CYLK CYL1=CYL2 115 CYL2=CYLK DO 120 K=2,N WA=CDABS(CBY(K)) IF (WA.LT.CDABS(CBY(K-1))) LB=K 120 CONTINUE GO TO 95 125 CDY(0)=V0/Z*CBY(0)-CBY(1) DO 130 K=1,N 130 CDY(K)=CBY(K-1)-(K+V0)/Z*CBY(K) VM=N+V0 RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcjyvb.for000077500000000000000000000272501321604176500261260ustar00rootroot00000000000000 PROGRAM MCJYVB C C ============================================================= C Purpose: This program computes Bessel functions Jv(z), Yv(z), C and their derivatives for a complex argument using C subroutine CJYVB C Input : z --- Complex argument C v --- Order of Jv(z) and Yv(z) C ( v = n+v0, 0 ó n ó 250, 0 ó v0 < 1 ) C Output: CBJ(n) --- Jn+v0(z) C CDJ(n) --- Jn+v0'(z) C CBY(n) --- Yn+v0(z) C CDY(n) --- Yn+v0'(z) C Example: C v = n +v0, v0 = 1/3, z = 4.0 + i 2.0 C C n Re[Jv(z)] Im[Jv(z)] Re[Jv'(z)] Im[Jv'(z)] C ------------------------------------------------------------------- C 0 -.13829878D+01 -.30855145D+00 -.18503756D+00 .13103689D+01 C 1 .82553327D-01 -.12848394D+01 -.12336901D+01 .45079506D-01 C 2 .10843924D+01 -.39871046D+00 -.33046401D+00 -.84574964D+00 C 3 .74348135D+00 .40665987D+00 .45318486D+00 -.42198992D+00 C 4 .17802266D+00 .44526939D+00 .39624497D+00 .97902890D-01 C 5 -.49008598D-01 .21085409D+00 .11784299D+00 .19422044D+00 C C n Re[Yv(z)] Im[Yv(z)] Re[Yv'(z)] Im[Yv'(z)] C ------------------------------------------------------------------- C 0 .34099851D+00 -.13440666D+01 -.13544477D+01 -.15470699D+00 C 1 .13323787D+01 .53735934D-01 -.21467271D-01 -.11807457D+01 C 2 .38393305D+00 .10174248D+01 .91581083D+00 -.33147794D+00 C 3 -.49924295D+00 .71669181D+00 .47786442D+00 .37321597D+00 C 4 -.57179578D+00 .27099289D+00 -.12111686D+00 .23405313D+00 C 5 -.25700924D+00 .24858555D+00 -.43023156D+00 -.13123662D+00 C ============================================================= C IMPLICIT DOUBLE PRECISION (V,X,Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBJ(0:250),CDJ(0:250),CBY(0:250),CDY(0:250) WRITE(*,*)' Please enter v, x and y ( z=x+iy )' READ(*,*)V,X,Y Z=CMPLX(X,Y) N=INT(V) V0=V-N WRITE(*,25)V0,X,Y IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL CJYVB(V,Z,VM,CBJ,CDJ,CBY,CDY) NM=INT(VM) WRITE(*,*) WRITE(*,*)' n Re[Jv(z)] Im[Jv(z)]', & ' Re[Jv''(z)] Im[Jv''(z)]' WRITE(*,*)' ----------------------------------', & '-----------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20) K,CBJ(K),CDJ(K) WRITE(*,*) WRITE(*,*)' n Re[Yv(z)] Im[Yv(z)]', & ' Re[Yv''(z)] Im[Yv''(z)]' WRITE(*,*)' ----------------------------------', & '-----------------------------------' DO 15 K=0,NM,NS 15 WRITE(*,20) K,CBY(K),CDY(K) 20 FORMAT(1X,I3,2X,4D16.8) 25 FORMAT(8X,'v = n+v0',', v0 =',F5.2,', z =',F7.2,' +',F7.2,'i') END SUBROUTINE CJYVB(V,Z,VM,CBJ,CDJ,CBY,CDY) C C =========================================================== C Purpose: Compute Bessel functions Jv(z), Yv(z) and their C derivatives for a complex argument C Input : z --- Complex argument C v --- Order of Jv(z) and Yv(z) C ( v = n+v0, n = 0,1,2,..., 0 ó v0 < 1 ) C Output: CBJ(n) --- Jn+v0(z) C CDJ(n) --- Jn+v0'(z) C CBY(n) --- Yn+v0(z) C CDY(n) --- Yn+v0'(z) C VM --- Highest order computed C Routines called: C (1) GAMMA for computing the gamma function C (2) MSTA1 and MSTA2 for computing the starting C point for backward recurrence C =========================================================== C IMPLICIT DOUBLE PRECISION (A,B,G,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CBJ(0:*),CDJ(0:*),CBY(0:*),CDY(0:*) PI=3.141592653589793D0 RP2=.63661977236758D0 CI=(0.0D0,1.0D0) A0=CDABS(Z) Z1=Z Z2=Z*Z N=INT(V) V0=V-N PV0=PI*V0 IF (A0.LT.1.0D-100) THEN DO 10 K=0,N CBJ(K)=(0.0D0,0.0D0) CDJ(K)=(0.0D0,0.0D0) CBY(K)=-(1.0D+300,0.0D0) 10 CDY(K)=(1.0D+300,0.0D0) IF (V0.EQ.0.0) THEN CBJ(0)=(1.0D0,0.0D0) CDJ(1)=(0.5D0,0.0D0) ELSE CDJ(0)=(1.0D+300,0.0D0) ENDIF VM=V RETURN ENDIF IF (REAL(Z).LT.0.0D0) Z1=-Z IF (A0.LE.12.0) THEN CJV0=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 15 K=1,40 CR=-0.25D0*CR*Z2/(K*(K+V0)) CJV0=CJV0+CR IF (CDABS(CR).LT.CDABS(CJV0)*1.0D-15) GO TO 20 15 CONTINUE 20 VG=1.0D0+V0 CALL GAMMA(VG,GA) CA=(0.5D0*Z1)**V0/GA CJV0=CJV0*CA ELSE K0=11 IF (A0.GE.35.0) K0=10 IF (A0.GE.50.0) K0=8 VV=4.0D0*V0*V0 CPZ=(1.0D0,0.0D0) CRP=(1.0D0,0.0D0) DO 25 K=1,K0 CRP=-0.78125D-2*CRP*(VV-(4.0*K-3.0)**2.0)*(VV- & (4.0*K-1.0)**2.0)/(K*(2.0*K-1.0)*Z2) 25 CPZ=CPZ+CRP CQZ=(1.0D0,0.0D0) CRQ=(1.0D0,0.0D0) DO 30 K=1,K0 CRQ=-0.78125D-2*CRQ*(VV-(4.0*K-1.0)**2.0)*(VV- & (4.0*K+1.0)**2.0)/(K*(2.0*K+1.0)*Z2) 30 CQZ=CQZ+CRQ CQZ=0.125D0*(VV-1.0)*CQZ/Z1 ZK=Z1-(0.5D0*V0+0.25D0)*PI CA0=CDSQRT(RP2/Z1) CCK=CDCOS(ZK) CSK=CDSIN(ZK) CJV0=CA0*(CPZ*CCK-CQZ*CSK) CYV0=CA0*(CPZ*CSK+CQZ*CCK) ENDIF IF (A0.LE.12.0) THEN IF (V0.NE.0.0) THEN CJVN=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 35 K=1,40 CR=-0.25D0*CR*Z2/(K*(K-V0)) CJVN=CJVN+CR IF (CDABS(CR).LT.CDABS(CJVN)*1.0D-15) GO TO 40 35 CONTINUE 40 VG=1.0D0-V0 CALL GAMMA(VG,GB) CB=(2.0D0/Z1)**V0/GB CJU0=CJVN*CB CYV0=(CJV0*DCOS(PV0)-CJU0)/DSIN(PV0) ELSE CEC=CDLOG(Z1/2.0D0)+.5772156649015329D0 CS0=(0.0D0,0.0D0) W0=0.0D0 CR0=(1.0D0,0.0D0) DO 45 K=1,30 W0=W0+1.0D0/K CR0=-0.25D0*CR0/(K*K)*Z2 45 CS0=CS0+CR0*W0 CYV0=RP2*(CEC*CJV0-CS0) ENDIF ENDIF IF (N.EQ.0) N=1 M=MSTA1(A0,200) IF (M.LT.N) THEN N=M ELSE M=MSTA2(A0,N,15) ENDIF CF2=(0.0D0,0.0D0) CF1=(1.0D-100,0.0D0) DO 50 K=M,0,-1 CF=2.0D0*(V0+K+1.0D0)/Z1*CF1-CF2 IF (K.LE.N) CBJ(K)=CF CF2=CF1 50 CF1=CF CS=CJV0/CF DO 55 K=0,N 55 CBJ(K)=CS*CBJ(K) IF (REAL(Z).LT.0.0D0) THEN CFAC0=CDEXP(PV0*CI) IF (DIMAG(Z).LT.0.0D0) THEN CYV0=CFAC0*CYV0-2.0D0*CI*DCOS(PV0)*CJV0 ELSE IF (DIMAG(Z).GT.0.0D0) THEN CYV0=CYV0/CFAC0+2.0D0*CI*DCOS(PV0)*CJV0 ENDIF DO 60 K=0,N IF (DIMAG(Z).LT.0.0D0) THEN CBJ(K)=CDEXP(-PI*(K+V0)*CI)*CBJ(K) ELSE IF (DIMAG(Z).GT.0.0D0) THEN CBJ(K)=CDEXP(PI*(K+V0)*CI)*CBJ(K) ENDIF 60 CONTINUE Z1=Z1 ENDIF CBY(0)=CYV0 DO 65 K=1,N CYY=(CBJ(K)*CBY(K-1)-2.0D0/(PI*Z))/CBJ(K-1) CBY(K)=CYY 65 CONTINUE CDJ(0)=V0/Z*CBJ(0)-CBJ(1) DO 70 K=1,N 70 CDJ(K)=-(K+V0)/Z*CBJ(K)+CBJ(K-1) CDY(0)=V0/Z*CBY(0)-CBY(1) DO 75 K=1,N 75 CDY(K)=CBY(K-1)-(K+V0)/Z*CBY(K) VM=N+V0 RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mclpmn.for000077500000000000000000000107701321604176500261210ustar00rootroot00000000000000 PROGRAM MCLPMN C C ============================================================ C Purpose: This program computes the associated Legendre C functions Pmn(z) and their derivatives Pmn'(z) for C a complex argument using subroutine CLPMN C Input : x --- Real part of z C y --- Imaginary part of z C m --- Order of Pmn(z), m = 0,1,2,...,n C n --- Degree of Pmn(z), n = 0,1,2,...,N C Output: CPM(m,n) --- Pmn(z) C CPD(m,n) --- Pmn'(z) C Examples: C n = 5, x = 0.5, y = 0.2 C C m Re[Pmn(z)] Im[Pmn(z)] Re[Pmn'(z)] Im[Pmn'(z)] C ------------------------------------------------------------- C 0 .252594D+00 -.530293D+00 -.347606D+01 -.194250D+01 C 1 .333071D+01 .135206D+01 .117643D+02 -.144329D+02 C 2 -.102769D+02 .125759D+02 .765713D+02 .598500D+02 C 3 -.572879D+02 -.522744D+02 -.343414D+03 .147389D+03 C 4 .335711D+03 -.389151D+02 -.226328D+03 -.737100D+03 C 5 -.461125D+03 .329122D+03 .187180D+04 .160494D+02 C C n = 5, x = 2.5, y = 1.0 C C m Re[Pmn(z)] Im[Pmn(z)] Re[Pmn'(z)] Im[Pmn'(z)] C ------------------------------------------------------------- C 0 -.429395D+03 .900336D+03 -.350391D+02 .193594D+04 C 1 -.216303D+04 .446358D+04 -.208935D+03 .964685D+04 C 2 -.883477D+04 .174005D+05 -.123703D+04 .381938D+05 C 3 -.273211D+05 .499684D+05 -.568080D+04 .112614D+06 C 4 -.565523D+05 .938503D+05 -.167147D+05 .219713D+06 C 5 -.584268D+05 .863328D+05 -.233002D+05 .212595D+06 C ============================================================ C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CPM(0:40,0:40),CPD(0:40,0:40) WRITE(*,*)' Please enter m, n, x and y ' READ(*,*) M,N,X,Y WRITE(*,30) M,N,X,Y CALL CLPMN(40,M,N,X,Y,CPM,CPD) WRITE(*,*)' m n Re[Pmn(z)] Im[Pmn(z)] ', & 'Re[Pmn''(z)] Im[Pmn''(z)]' WRITE(*,*)' -----------------------------------', & '-------------------------------' DO 10 J=0,N 10 WRITE(*,20)M,J,CPM(M,J),CPD(M,J) 20 FORMAT(1X,2I4,1X,2D14.6,1X,2D14.6) 30 FORMAT(1X,'m =',I2,', ','n =',I2,', ','x =',F5.1, & ', ','y =',F5.1) END SUBROUTINE CLPMN(MM,M,N,X,Y,CPM,CPD) C C ========================================================= C Purpose: Compute the associated Legendre functions Pmn(z) C and their derivatives Pmn'(z) for a complex C argument C Input : x --- Real part of z C y --- Imaginary part of z C m --- Order of Pmn(z), m = 0,1,2,...,n C n --- Degree of Pmn(z), n = 0,1,2,...,N C mm --- Physical dimension of CPM and CPD C Output: CPM(m,n) --- Pmn(z) C CPD(m,n) --- Pmn'(z) C ========================================================= C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CPM(0:MM,0:N),CPD(0:MM,0:N) Z=CMPLX(X,Y) DO 10 I=0,N DO 10 J=0,M CPM(J,I)=(0.0D0,0.0D0) 10 CPD(J,I)=(0.0D0,0.0D0) CPM(0,0)=(1.0D0,0.0D0) IF (DABS(X).EQ.1.0D0.AND.Y.EQ.0.0D0) THEN DO 15 I=1,N CPM(0,I)=X**I 15 CPD(0,I)=0.5D0*I*(I+1)*X**(I+1) DO 20 J=1,N DO 20 I=1,M IF (I.EQ.1) THEN CPD(I,J)=(1.0D+300,0.0D0) ELSE IF (I.EQ.2) THEN CPD(I,J)=-0.25D0*(J+2)*(J+1)*J*(J-1)*X**(J+1) ENDIF 20 CONTINUE RETURN ENDIF LS=1 IF (CDABS(Z).GT.1.0D0) LS=-1 ZQ=CDSQRT(LS*(1.0D0-Z*Z)) ZS=LS*(1.0D0-Z*Z) DO 25 I=1,M 25 CPM(I,I)=-LS*(2.0D0*I-1.0D0)*ZQ*CPM(I-1,I-1) DO 30 I=0,M 30 CPM(I,I+1)=(2.0D0*I+1.0D0)*Z*CPM(I,I) DO 35 I=0,M DO 35 J=I+2,N CPM(I,J)=((2.0D0*J-1.0D0)*Z*CPM(I,J-1)-(I+J- & 1.0D0)*CPM(I,J-2))/(J-I) 35 CONTINUE CPD(0,0)=(0.0D0,0.0D0) DO 40 J=1,N 40 CPD(0,J)=LS*J*(CPM(0,J-1)-Z*CPM(0,J))/ZS DO 45 I=1,M DO 45 J=I,N CPD(I,J)=LS*I*Z*CPM(I,J)/ZS+(J+I)*(J-I+1.0D0) & /ZQ*CPM(I-1,J) 45 CONTINUE RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mclpn.for000077500000000000000000000054221321604176500257420ustar00rootroot00000000000000 PROGRAM MCLPN C C ========================================================== C Purpose: This program computes the Legendre polynomials C Pn(z) and Pn'(z) for a complex argument using C subroutine CLPN C Input : x --- Real part of z C y --- Imaginary part of z C n --- Degree of Pn(z), n = 0,1,...,N C Output: CPN(n) --- Pn(z) C CPD(n) --- Pn'(z) C Example: z = 3.0 +2.0 i C C n Re[Pn(z)] Im[Pn(z)] Re[Pn'(z)] Im[Pn'(z)] C ----------------------------------------------------------- C 0 .100000D+01 .000000D+00 .000000D+00 .000000D+00 C 1 .300000D+01 .200000D+01 .100000D+01 .000000D+00 C 2 .700000D+01 .180000D+02 .900000D+01 .600000D+01 C 3 -.270000D+02 .112000D+03 .360000D+02 .900000D+02 C 4 -.539000D+03 .480000D+03 -.180000D+03 .790000D+03 C 5 -.461700D+04 .562000D+03 -.481500D+04 .441000D+04 C ========================================================== C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX *16 (C,Z) DIMENSION CPN(0:100),CPD(0:100) WRITE(*,*)' Please enter Nmax, x and y (z=x+iy)' READ(*,*)N,X,Y WRITE(*,30)X,Y WRITE(*,*) CALL CLPN(N,X,Y,CPN,CPD) WRITE(*,*)' n Re[Pn(z)] Im[Pn(z)] Re[Pn''(z)]', & ' Im[Pn''(z)]' WRITE(*,*)' ---------------------------------------------', & '--------------' DO 10 K=0,N 10 WRITE(*,20)K,CPN(K),CPD(K) 20 FORMAT(1X,I3,4D14.6) 30 FORMAT(3X,'x =',F5.1,', ','y =',F5.1) END SUBROUTINE CLPN(N,X,Y,CPN,CPD) C C ================================================== C Purpose: Compute Legendre polynomials Pn(z) and C their derivatives Pn'(z) for a complex C argument C Input : x --- Real part of z C y --- Imaginary part of z C n --- Degree of Pn(z), n = 0,1,2,... C Output: CPN(n) --- Pn(z) C CPD(n) --- Pn'(z) C ================================================== C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX *16 (C,Z) DIMENSION CPN(0:N),CPD(0:N) Z=CMPLX(X,Y) CPN(0)=(1.0D0,0.0D0) CPN(1)=Z CPD(0)=(0.0D0,0.0D0) CPD(1)=(1.0D0,0.0D0) CP0=(1.0D0,0.0D0) CP1=Z DO 10 K=2,N CPF=(2.0D0*K-1.0D0)/K*Z*CP1-(K-1.0D0)/K*CP0 CPN(K)=CPF IF (DABS(X).EQ.1.0D0.AND.Y.EQ.0.0D0) THEN CPD(K)=0.5D0*X**(K+1)*K*(K+1.0D0) ELSE CPD(K)=K*(CP1-Z*CPF)/(1.0D0-Z*Z) ENDIF CP0=CP1 10 CP1=CPF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mclqmn.for000077500000000000000000000133441321604176500261220ustar00rootroot00000000000000 PROGRAM MCLQMN C C ============================================================ C Purpose: This program computes the associated Legendre C functions Qmn(z) and their derivatives Qmn'(z) for C a complex argument using subroutine CLQMN C Definition: Qmn(z)=(-1)**m*(1-z*z)**(m/2)*dm/dzm[Qn(z)] C Q0(z)=1/2*LOG[(1+z)/(1-z)] ( for |z|<1 ) C Qmn(z)=(z*z-1)**(m/2)*dm/dzm[Qn(z)] C Q0(z)=1/2*LOG[(z+1)/(z-1)] ( for |z|>1 ) C Input : x --- Real part of z C y --- Imaginary part of z C m --- Order of Qmn(z) ( m = 0,1,2,úúú ) C n --- Degree of Qmn(z) ( n = 0,1,2,úúú ) C Output: CQM(m,n) --- Qmn(z) C CQD(m,n) --- Qmn'(z) C Examples: C n = 5, x = 0.5, y = 0.2 C C m Re[Qmn(z)] Im[Qmn(z)] Re[Qmn'(z)] Im[Qmn'(z)] C ------------------------------------------------------------- C 0 .987156D+00 .354345D+00 .324023D+01 -.447297D+01 C 1 -.240328D+01 .436861D+01 .281158D+02 .171437D+02 C 2 -.245853D+02 -.138072D+02 -.106283D+03 .913792D+02 C 3 .102723D+03 -.651233D+02 -.362578D+03 -.429802D+03 C 4 .155510D+03 .357712D+03 .196975D+04 -.287414D+02 C 5 -.167357D+04 -.680954D+03 -.193093D+04 -.925757D+03 C C n = 5, x = 2.5, y = 1.0 C C m Re[Qmn(z)] Im[Qmn(z)] Re[Qmn'(z)] Im[Qmn'(z)] C ------------------------------------------------------------- C 0 -.274023D-04 -.227141D-04 .809834D-04 .210884D-04 C 1 .165620D-03 .136108D-03 -.489095D-03 -.124400D-03 C 2 -.118481D-02 -.948832D-03 .349090D-02 .825057D-03 C 3 .982179D-02 .753264D-02 -.288271D-01 -.596384D-02 C 4 -.927915D-01 -.669521D-01 .270840D+00 .451376D-01 C 5 .985601D+00 .656737D+00 -.285567D+01 -.332533D+00 C ============================================================ C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CQM(0:40,0:40),CQD(0:40,0:40) WRITE(*,*)' Please enter m, n, x and y ' READ(*,*) M,N,X,Y WRITE(*,30)M,N,X,Y CALL CLQMN(40,M,N,X,Y,CQM,CQD) WRITE(*,*)' m n Re[Qmn(z)] Im[Qmn(z)] ', & 'Re[Qmn''(z)] Im[Qmn''(z)]' WRITE(*,*)' -----------------------------------', & '------------------------------' DO 10 J=0,N 10 WRITE(*,20)M,J,CQM(M,J),CQD(M,J) 20 FORMAT(1X,2I4,2D14.6,1X,2D14.6) 30 FORMAT(1X,'m =',I2,', ','n =',I2,', ','x =',F4.1, & ', ','y =',F4.1) END SUBROUTINE CLQMN(MM,M,N,X,Y,CQM,CQD) C C ======================================================= C Purpose: Compute the associated Legendre functions of C the second kind, Qmn(z) and Qmn'(z), for a C complex argument C Input : x --- Real part of z C y --- Imaginary part of z C m --- Order of Qmn(z) ( m = 0,1,2,úúú ) C n --- Degree of Qmn(z) ( n = 0,1,2,úúú ) C mm --- Physical dimension of CQM and CQD C Output: CQM(m,n) --- Qmn(z) C CQD(m,n) --- Qmn'(z) C ======================================================= C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CQM(0:MM,0:N),CQD(0:MM,0:N) Z=CMPLX(X,Y) IF (DABS(X).EQ.1.0D0.AND.Y.EQ.0.0D0) THEN DO 10 I=0,M DO 10 J=0,N CQM(I,J)=(1.0D+300,0.0D0) CQD(I,J)=(1.0D+300,0.0D0) 10 CONTINUE RETURN ENDIF XC=CDABS(Z) IF (DIMAG(Z).EQ.0.0D0.OR.XC.LT.1.0D0) LS=1 IF (XC.GT.1.0D0) LS=-1 ZQ=CDSQRT(LS*(1.0D0-Z*Z)) ZS=LS*(1.0D0-Z*Z) CQ0=0.5D0*CDLOG(LS*(1.0D0+Z)/(1.0D0-Z)) IF (XC.LT.1.0001D0) THEN CQM(0,0)=CQ0 CQM(0,1)=Z*CQ0-1.0D0 CQM(1,0)=-1.0D0/ZQ CQM(1,1)=-ZQ*(CQ0+Z/(1.0D0-Z*Z)) DO 15 I=0,1 DO 15 J=2,N CQM(I,J)=((2.0D0*J-1.0D0)*Z*CQM(I,J-1) & -(J+I-1.0D0)*CQM(I,J-2))/(J-I) 15 CONTINUE DO 20 J=0,N DO 20 I=2,M CQM(I,J)=-2.0D0*(I-1.0D0)*Z/ZQ*CQM(I-1,J)-LS* & (J+I-1.0D0)*(J-I+2.0D0)*CQM(I-2,J) 20 CONTINUE ELSE IF (XC.GT.1.1) THEN KM=40+M+N ELSE KM=(40+M+N)*INT(-1.0-1.8*LOG(XC-1.0)) ENDIF CQF2=(0.0D0,0.0D0) CQF1=(1.0D0,0.0D0) DO 25 K=KM,0,-1 CQF0=((2*K+3.0D0)*Z*CQF1-(K+2.0D0)*CQF2)/(K+1.0D0) IF (K.LE.N) CQM(0,K)=CQF0 CQF2=CQF1 25 CQF1=CQF0 DO 30 K=0,N 30 CQM(0,K)=CQ0*CQM(0,K)/CQF0 CQF2=0.0D0 CQF1=1.0D0 DO 35 K=KM,0,-1 CQF0=((2*K+3.0D0)*Z*CQF1-(K+1.0D0)*CQF2)/(K+2.0D0) IF (K.LE.N) CQM(1,K)=CQF0 CQF2=CQF1 35 CQF1=CQF0 CQ10=-1.0D0/ZQ DO 40 K=0,N 40 CQM(1,K)=CQ10*CQM(1,K)/CQF0 DO 45 J=0,N CQ0=CQM(0,J) CQ1=CQM(1,J) DO 45 I=0,M-2 CQF=-2.0D0*(I+1)*Z/ZQ*CQ1+(J-I)*(J+I+1.0D0)*CQ0 CQM(I+2,J)=CQF CQ0=CQ1 CQ1=CQF 45 CONTINUE ENDIF CQD(0,0)=LS/ZS DO 50 J=1,N 50 CQD(0,J)=LS*J*(CQM(0,J-1)-Z*CQM(0,J))/ZS DO 55 J=0,N DO 55 I=1,M CQD(I,J)=LS*I*Z/ZS*CQM(I,J)+(I+J)*(J-I+1.0D0) & /ZQ*CQM(I-1,J) 55 CONTINUE RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mclqn.for000077500000000000000000000077521321604176500257530ustar00rootroot00000000000000 PROGRAM MCLQN C C ========================================================== C Purpose: This program computes the Legendre polynomials C Qn(z) and Qn'(z) for a complex argument using C subroutine CLQN C Input : x --- Real part of z C y --- Imaginary part of z C n --- Degree of Qn(z), n = 0,1,... C Output: CQN(n) --- Qn(z) C CQD(n) --- Qn'(z) C Examples: C C z = 0.5 + 0.5 i C n Re[Qn(z)] Im[Qn(z)] Re[Qn'(z)] Im[Qn'(z)] C ----------------------------------------------------------- C 0 .402359D+00 .553574D+00 .800000D+00 .400000D+00 C 1 -.107561D+01 .477967D+00 .602359D+00 .115357D+01 C 2 -.136636D+01 -.725018D+00 -.242682D+01 .183390D+01 C 3 .182619D+00 -.206146D+01 -.622944D+01 -.247151D+01 C 4 .298834D+01 -.110022D+01 -.114849D+01 -.125963D+02 C 5 .353361D+01 .334847D+01 .206656D+02 -.123735D+02 C C z = 3.0 + 2.0 i C n Re[Qn(z)] Im[Qn(z)] Re[Qn'(z)] Im[Qn'(z)] C ----------------------------------------------------------- C 0 .229073D+00 -.160875D+00 -.250000D-01 .750000D-01 C 1 .896860D-02 -.244805D-01 .407268D-02 .141247D-01 C 2 -.736230D-03 -.281865D-02 .190581D-02 .155860D-02 C 3 -.264727D-03 -.227023D-03 .391535D-03 .314880D-04 C 4 -.430648D-04 -.443187D-05 .527190D-04 -.305592D-04 C 5 -.481362D-05 .265297D-05 .395108D-05 -.839883D-05 C ========================================================== C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CQN(0:100),CQD(0:100) WRITE(*,*)' Please enter Nmax, x and y (z=x+iy)' READ(*,*)N,X,Y WRITE(*,30)X,Y WRITE(*,*) CALL CLQN(N,X,Y,CQN,CQD) WRITE(*,*)' n Re[Qn(z)] Im[Qn(z)] Re[Qn''(z)]', & ' Im[Qn''(z)]' WRITE(*,*)' ---------------------------------------------', & '--------------' DO 10 K=0,N 10 WRITE(*,20)K,CQN(K),CQD(K) 20 FORMAT(1X,I3,4D14.6) 30 FORMAT(3X,'x =',F5.1,', ','y =',F5.1) END SUBROUTINE CLQN(N,X,Y,CQN,CQD) C C ================================================== C Purpose: Compute the Legendre functions Qn(z) and C their derivatives Qn'(z) for a complex C argument C Input : x --- Real part of z C y --- Imaginary part of z C n --- Degree of Qn(z), n = 0,1,2,... C Output: CQN(n) --- Qn(z) C CQD(n) --- Qn'(z) C ================================================== C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CQN(0:N),CQD(0:N) Z=CMPLX(X,Y) IF (Z.EQ.1.0D0) THEN DO 10 K=0,N CQN(K)=(1.0D+300,0.0D0) 10 CQD(K)=(1.0D+300,0.0D0) RETURN ENDIF LS=1 IF (CDABS(Z).GT.1.0D0) LS=-1 CQ0=0.5D0*CDLOG(LS*(1.0D0+Z)/(1.0D0-Z)) CQ1=Z*CQ0-1.0D0 CQN(0)=CQ0 CQN(1)=CQ1 IF (CDABS(Z).LT.1.0001D0) THEN CQF0=CQ0 CQF1=CQ1 DO 15 K=2,N CQF2=((2.0D0*K-1.0D0)*Z*CQF1-(K-1.0D0)*CQF0)/K CQN(K)=CQF2 CQF0=CQF1 15 CQF1=CQF2 ELSE IF (CDABS(Z).GT.1.1D0) THEN KM=40+N ELSE KM=(40+N)*INT(-1.0-1.8*LOG(CDABS(Z-1.0))) ENDIF CQF2=0.0D0 CQF1=1.0D0 DO 20 K=KM,0,-1 CQF0=((2*K+3.0D0)*Z*CQF1-(K+2.0D0)*CQF2)/(K+1.0D0) IF (K.LE.N) CQN(K)=CQF0 CQF2=CQF1 20 CQF1=CQF0 DO 25 K=0,N 25 CQN(K)=CQN(K)*CQ0/CQF0 ENDIF CQD(0)=(CQN(1)-Z*CQN(0))/(Z*Z-1.0D0) DO 30 K=1,N 30 CQD(K)=(K*Z*CQN(K)-K*CQN(K-1))/(Z*Z-1.0D0) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcomelp.for000077500000000000000000000042771321604176500262740ustar00rootroot00000000000000 PROGRAM MCOMELP C C =================================================== C Purpose: This program computes complete elliptic C integrals K(k) and E(k) using subroutine C COMELP C Input : K --- Modulus k ( 0 ó k ó 1 ) C Output : CK --- K(k) C CE --- E(k) C Example: C k K(k) E(K) C --------------------------------- C .00 1.570796 1.570796 C .25 1.596242 1.545957 C .50 1.685750 1.467462 C .75 1.910990 1.318472 C 1.00 ì 1.000000 C =================================================== C DOUBLE PRECISION HK,CK,CE WRITE(*,*)'Please enter the modulus k ' READ(*,*) HK WRITE(*,*)' k K(k) E(K)' WRITE(*,*)' ---------------------------------' CALL COMELP(HK,CK,CE) IF (HK.NE.1.0) WRITE(*,10) HK,CK,CE IF (HK.EQ.1.0) WRITE(*,20) HK,CE 10 FORMAT(2X,F5.2,2F14.6) 20 FORMAT(2X,F5.2,7X,'ì',6X,F14.6) END SUBROUTINE COMELP(HK,CK,CE) C C ================================================== C Purpose: Compute complete elliptic integrals K(k) C and E(k) C Input : K --- Modulus k ( 0 ó k ó 1 ) C Output : CK --- K(k) C CE --- E(k) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PK=1.0D0-HK*HK IF (HK.EQ.1.0) THEN CK=1.0D+300 CE=1.0D0 ELSE AK=(((.01451196212D0*PK+.03742563713D0)*PK & +.03590092383D0)*PK+.09666344259D0)*PK+ & 1.38629436112D0 BK=(((.00441787012D0*PK+.03328355346D0)*PK+ & .06880248576D0)*PK+.12498593597D0)*PK+.5D0 CK=AK-BK*DLOG(PK) AE=(((.01736506451D0*PK+.04757383546D0)*PK+ & .0626060122D0)*PK+.44325141463D0)*PK+1.0D0 BE=(((.00526449639D0*PK+.04069697526D0)*PK+ & .09200180037D0)*PK+.2499836831D0)*PK CE=AE-BE*DLOG(PK) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcpbdn.for000077500000000000000000000151061321604176500260740ustar00rootroot00000000000000 PROGRAM MCPBDN C C ============================================================= C Purpose: This program computes parabolic cylinder functions C Dn(z) for an integer order and a complex argument C using subroutine CPBDN C Input : x --- Real part of z C y --- Imaginary part of z C n --- Order of Dn(z) C Output: CPB(|n|) --- Dn(z) C CPD(|n|) --- Dn'(z) C Example: C z = 5.0+ 5.0 i C C n Re[Dn(z)] Im[Dn(z)] Re[Dn'(z)] Im[Dn'(z)] C ----------------------------------------------------------------- C 0 .99779828D+00 .66321897D-01 -.23286910D+01 -.26603004D+01 C 1 .46573819D+01 .53206009D+01 .26558457D+01 -.24878635D+02 C 2 -.43138931D+01 .49823592D+02 .14465848D+03 -.10313305D+03 C 3 -.28000219D+03 .21690729D+03 .12293320D+04 .30720802D+03 C 4 -.24716057D+04 -.46494526D+03 .38966424D+04 .82090067D+04 C -1 .10813809D+00 -.90921592D-01 -.50014908D+00 -.23280660D-01 C -2 .24998820D-02 -.19760577D-01 -.52486940D-01 .47769856D-01 C -3 -.15821033D-02 -.23090595D-02 -.68249161D-03 .10032670D-01 C -4 -.37829961D-03 -.10158757D-03 .89032322D-03 .11093416D-02 C ============================================================= C IMPLICIT DOUBLE PRECISION (X,Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CPB(0:100),CPD(0:100) WRITE(*,*)'Please enter n, x and y ' READ(*,*)N,X,Y WRITE(*,20)N,X,Y Z=CMPLX(X,Y) N0=ABS(N) CALL CPBDN(N,Z,CPB,CPD) WRITE(*,*) IF (N.GE.0) THEN WRITE(*,*)' n Re[Dn(z)] Im[Dn(z)] ', & 'Re[Dn''(z)] Im[Dn''(z)]' ELSE WRITE(*,*)' -n Re[Dn(z)] Im[Dn(z)] ', & 'Re[Dn''(z)] Im[Dn''(z)]' ENDIF WRITE(*,*)'-------------------------------------------', & '-------------------------' DO 5 I=0,N0 5 WRITE(*,10)I,CPB(I),CPD(I) 10 FORMAT(1X,I3,4D16.8) 20 FORMAT(1X,'N =',I3,', z =x+iy :',F6.2,'+',F6.2,' i') END SUBROUTINE CPBDN(N,Z,CPB,CPD) C C ================================================== C Purpose: Compute the parabolic cylinder functions C Dn(z) and Dn'(z) for a complex argument C Input: z --- Complex argument of Dn(z) C n --- Order of Dn(z) ( n=0,ñ1,ñ2,úúú ) C Output: CPB(|n|) --- Dn(z) C CPD(|n|) --- Dn'(z) C Routines called: C (1) CPDSA for computing Dn(z) for a small |z| C (2) CPDLA for computing Dn(z) for a large |z| C ================================================== C IMPLICIT DOUBLE PRECISION (A-B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION CPB(0:*),CPD(0:*) PI=3.141592653589793D0 X=REAL(Z) A0=CDABS(Z) C0=(0.0D0,0.0D0) CA0=CDEXP(-0.25D0*Z*Z) IF (N.GE.0) THEN CF0=CA0 CF1=Z*CA0 CPB(0)=CF0 CPB(1)=CF1 DO 10 K=2,N CF=Z*CF1-(K-1.0D0)*CF0 CPB(K)=CF CF0=CF1 10 CF1=CF ELSE N0=-N IF (X.LE.0.0.OR.CDABS(Z).EQ.0.0) THEN CF0=CA0 CPB(0)=CF0 Z1=-Z IF (A0.LE.7.0) THEN CALL CPDSA(-1,Z1,CF1) ELSE CALL CPDLA(-1,Z1,CF1) ENDIF CF1=DSQRT(2.0D0*PI)/CA0-CF1 CPB(1)=CF1 DO 15 K=2,N0 CF=(-Z*CF1+CF0)/(K-1.0D0) CPB(K)=CF CF0=CF1 15 CF1=CF ELSE IF (A0.LE.3.0) THEN CALL CPDSA(-N0,Z,CFA) CPB(N0)=CFA N1=N0+1 CALL CPDSA(-N1,Z,CFB) CPB(N1)=CFB NM1=N0-1 DO 20 K=NM1,0,-1 CF=Z*CFA+(K+1.0D0)*CFB CPB(K)=CF CFB=CFA 20 CFA=CF ELSE M=100+ABS(N) CFA=C0 CFB=(1.0D-30,0.0D0) DO 25 K=M,0,-1 CF=Z*CFB+(K+1.0D0)*CFA IF (K.LE.N0) CPB(K)=CF CFA=CFB 25 CFB=CF CS0=CA0/CF DO 30 K=0,N0 30 CPB(K)=CS0*CPB(K) ENDIF ENDIF ENDIF CPD(0)=-0.5D0*Z*CPB(0) IF (N.GE.0) THEN DO 35 K=1,N 35 CPD(K)=-0.5D0*Z*CPB(K)+K*CPB(K-1) ELSE DO 40 K=1,N0 40 CPD(K)=0.5D0*Z*CPB(K)-CPB(K-1) ENDIF RETURN END SUBROUTINE CPDSA(N,Z,CDN) C C =========================================================== C Purpose: Compute complex parabolic cylinder function Dn(z) C for small argument C Input: z --- complex argument of D(z) C n --- Order of D(z) (n = 0,-1,-2,úúú) C Output: CDN --- Dn(z) C Routine called: GAIH for computing â(x), x=n/2 (n=1,2,...) C =========================================================== C IMPLICIT DOUBLE PRECISION (A-B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) EPS=1.0D-15 PI=3.141592653589793D0 SQ2=DSQRT(2.0D0) CA0=CDEXP(-.25D0*Z*Z) VA0=0.5D0*(1.0D0-N) IF (N.EQ.0.0) THEN CDN=CA0 ELSE IF (CDABS(Z).EQ.0.0) THEN IF (VA0.LE.0.0.AND.VA0.EQ.INT(VA0)) THEN CDN=0.0D0 ELSE CALL GAIH(VA0,GA0) PD=DSQRT(PI)/(2.0D0**(-.5D0*N)*GA0) CDN=CMPLX(PD,0.0D0) ENDIF ELSE XN=-N CALL GAIH(XN,G1) CB0=2.0D0**(-0.5D0*N-1.0D0)*CA0/G1 VT=-.5D0*N CALL GAIH(VT,G0) CDN=CMPLX(G0,0.0D0) CR=(1.0D0,0.0D0) DO 10 M=1,250 VM=.5D0*(M-N) CALL GAIH(VM,GM) CR=-CR*SQ2*Z/M CDW=GM*CR CDN=CDN+CDW IF (CDABS(CDW).LT.CDABS(CDN)*EPS) GO TO 20 10 CONTINUE 20 CDN=CB0*CDN ENDIF ENDIF RETURN END SUBROUTINE CPDLA(N,Z,CDN) C C =========================================================== C Purpose: Compute complex parabolic cylinder function Dn(z) C for large argument C Input: z --- Complex argument of Dn(z) C n --- Order of Dn(z) (n = 0,ñ1,ñ2,úúú) C Output: CDN --- Dn(z) C =========================================================== C IMPLICIT DOUBLE PRECISION (A-B,D-H,O-Y) IMPLICIT COMPLEX*16 (C,Z) CB0=Z**N*CDEXP(-.25D0*Z*Z) CR=(1.0D0,0.0D0) CDN=(1.0D0,0.0D0) DO 10 K=1,16 CR=-0.5D0*CR*(2.0*K-N-1.0)*(2.0*K-N-2.0)/(K*Z*Z) CDN=CDN+CR IF (CDABS(CR).LT.CDABS(CDN)*1.0D-12) GO TO 15 10 CONTINUE 15 CDN=CB0*CDN RETURN END SUBROUTINE GAIH(X,GA) C C ===================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x), x = n/2, n=1,2,úúú C Output: GA --- â(x) C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 IF (X.EQ.INT(X).AND.X.GT.0.0) THEN GA=1.0D0 M1=INT(X-1.0) DO 10 K=2,M1 10 GA=GA*K ELSE IF (X+.5D0.EQ.INT(X+.5D0).AND.X.GT.0.0) THEN M=INT(X) GA=DSQRT(PI) DO 15 K=1,M 15 GA=0.5D0*GA*(2.0D0*K-1.0D0) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcpsi.for000077500000000000000000000064011321604176500257420ustar00rootroot00000000000000 PROGRAM MCPSI C C ========================================================= C Purpose: This program computes the psi function psi(z) C for a complex argument using subroutine CPSI C Input : x --- Real part of z C y --- Imaginary part of z C Output: PSR --- Real part of psi(z) C PSI --- Imaginary part of psi(z) C Examples: C x y Re[psi(z)] Im[psi(z)] C ------------------------------------------- C 3.0 2.0 1.16459152 .67080728 C 3.0 -2.0 1.16459152 -.67080728 C -3.0 2.0 1.39536075 2.62465344 C -3.0 -2.0 1.39536075 -2.62465344 C ========================================================= C DOUBLE PRECISION X,Y,PSR,PSI WRITE(*,*)'Please enter x and y ( z=x+iy)' READ(*,*)X,Y WRITE(*,20)X,Y WRITE(*,*) WRITE(*,*)' x y Re[Psi(z)] Im[Psi(z)]' WRITE(*,*)' ----------------------------------------------' CALL CPSI(X,Y,PSR,PSI) WRITE(*,10)X,Y,PSR,PSI 10 FORMAT(1X,F5.1,3X,F5.1,2X,2E16.8) 20 FORMAT(1X,2Hx=,F6.2,6X,2Hy=,F6.2) END SUBROUTINE CPSI(X,Y,PSR,PSI) C C ============================================= C Purpose: Compute the psi function for a C complex argument C Input : x --- Real part of z C y --- Imaginary part of z C Output: PSR --- Real part of psi(z) C PSI --- Imaginary part of psi(z) C ============================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(8) DATA A/-.8333333333333D-01,.83333333333333333D-02, & -.39682539682539683D-02,.41666666666666667D-02, & -.75757575757575758D-02,.21092796092796093D-01, & -.83333333333333333D-01,.4432598039215686D0/ PI=3.141592653589793D0 IF (Y.EQ.0.0D0.AND.X.EQ.INT(X).AND.X.LE.0.0D0) THEN PSR=1.0D+300 PSI=0.0D0 ELSE IF (X.LT.0.0D0) THEN X1=X Y1=Y X=-X Y=-Y ENDIF X0=X IF (X.LT.8.0D0) THEN N=8-INT(X) X0=X+N ENDIF IF (X0.EQ.0.0D0.AND.Y.NE.0.0D0) TH=0.5D0*PI IF (X0.NE.0.0D0) TH=DATAN(Y/X0) Z2=X0*X0+Y*Y Z0=DSQRT(Z2) PSR=DLOG(Z0)-0.5D0*X0/Z2 PSI=TH+0.5D0*Y/Z2 DO 10 K=1,8 PSR=PSR+A(K)*Z2**(-K)*DCOS(2.0D0*K*TH) 10 PSI=PSI-A(K)*Z2**(-K)*DSIN(2.0D0*K*TH) IF (X.LT.8.0D0) THEN RR=0.0D0 RI=0.0D0 DO 20 K=1,N RR=RR+(X0-K)/((X0-K)**2.0D0+Y*Y) 20 RI=RI+Y/((X0-K)**2.0D0+Y*Y) PSR=PSR-RR PSI=PSI+RI ENDIF IF (X1.LT.0.0D0) THEN TN=DTAN(PI*X) TM=DTANH(PI*Y) CT2=TN*TN+TM*TM PSR=PSR+X/(X*X+Y*Y)+PI*(TN-TN*TM*TM)/CT2 PSI=PSI-Y/(X*X+Y*Y)-PI*TM*(1.0D0+TN*TN)/CT2 X=X1 Y=Y1 ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcsphik.for000077500000000000000000000162731321604176500262750ustar00rootroot00000000000000 PROGRAM MCSPHIK C C ============================================================= C Purpose: This program computes the modified spherical Bessel C functions and their derivatives for a complex C argument using subroutine CSPHIK C Input : z --- Complex argument C n --- Order of in(z) & kn(z) ( 0 ó n ó 250 ) C Output: CSI(n) --- in(z) C CDI(n) --- in'(z) C CSK(n) --- kn(z) C CDK(n) --- kn'(z) C Example: z =4.0+i 2.0 C C n Re[in(z)] Im[in(z)] Re[in'(z)] Im[in'(z)] C --------------------------------------------------------------- C 0 .2118080D+00 .6101922D+01 -.4439356D+00 .4900150D+01 C 1 -.4439356D+00 .4900150D+01 -.5906477D+00 .4053075D+01 C 2 -.9918756D+00 .3028652D+01 -.7574058D+00 .2785396D+01 C 3 -.9663859D+00 .1375561D+01 -.7689911D+00 .1541649D+01 C 4 -.6018277D+00 .4263967D+00 -.5777565D+00 .6482500D+00 C 5 -.2668530D+00 .6640148D-01 -.3214450D+00 .1866032D+00 C C n Re[kn(z)] Im[kn(z)] Re[kn'(z)] Im[kn'(z)] C --------------------------------------------------------------- C 0 -.5010582D-02 -.4034862D-02 .6416184D-02 .4340777D-02 C 1 -.6416184D-02 -.4340777D-02 .8445211D-02 .4487936D-02 C 2 -.1016253D-01 -.4714473D-02 .1392804D-01 .4120703D-02 C 3 -.1893595D-01 -.3973987D-02 .2690088D-01 .3192843D-03 C 4 -.3945464D-01 .2977107D-02 .5690203D-01 -.1873044D-01 C 5 -.8727490D-01 .3689398D-01 .1220481D+00 -.9961483D-01 C ============================================================= C IMPLICIT COMPLEX*16 (C,Z) DOUBLE PRECISION X,Y DIMENSION CSI(0:250),CDI(0:250),CSK(0:250),CDK(0:250) WRITE(*,*)'Please enter n,x,y (z=x+iy) ' READ(*,*)N,X,Y WRITE(*,30)N,X,Y Z=CMPLX(X,Y) IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)'Please enter order step Ns ' READ(*,*)NS ENDIF CALL CSPHIK(N,Z,NM,CSI,CDI,CSK,CDK) WRITE(*,*) WRITE(*,*)' n Re[in(z)] Im[in(z)]', & ' Re[in''(z)] Im[in''(z)]' WRITE(*,*)'--------------------------------------------', & '----------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20)K,CSI(K),CDI(K) WRITE(*,*) WRITE(*,*)' n Re[kn(z)] Im[kn(z)]', & ' Re[kn''(z)] Im[kn''(z)]' WRITE(*,*)'--------------------------------------------', & '----------------------------' DO 15 K=0,NM,NS 15 WRITE(*,20)K,CSK(K),CDK(K) 20 FORMAT(1X,I3,4D17.8) 30 FORMAT(3X,'Nmaz =',I3,', ','z = ',F8.1,'+ i',F8.1) END SUBROUTINE CSPHIK(N,Z,NM,CSI,CDI,CSK,CDK) C C ======================================================= C Purpose: Compute modified spherical Bessel functions C and their derivatives for a complex argument C Input : z --- Complex argument C n --- Order of in(z) & kn(z) ( n = 0,1,2,... ) C Output: CSI(n) --- in(z) C CDI(n) --- in'(z) C CSK(n) --- kn(z) C CDK(n) --- kn'(z) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 for computing the starting C point for backward recurrence C ======================================================= C IMPLICIT COMPLEX*16 (C,Z) DOUBLE PRECISION A0,PI DIMENSION CSI(0:N),CDI(0:N),CSK(0:N),CDK(0:N) PI=3.141592653589793D0 A0=CDABS(Z) NM=N IF (A0.LT.1.0D-60) THEN DO 10 K=0,N CSI(K)=0.0D0 CDI(K)=0.0D0 CSK(K)=1.0D+300 10 CDK(K)=-1.0D+300 CSI(0)=1.0D0 CDI(1)=0.3333333333333333D0 RETURN ENDIF CI=CMPLX(0.0D0,1.0D0) CSINH=CDSIN(CI*Z)/CI CCOSH=CDCOS(CI*Z) CSI0=CSINH/Z CSI1=(-CSINH/Z+CCOSH)/Z CSI(0)=CSI0 CSI(1)=CSI1 IF (N.GE.2) THEN M=MSTA1(A0,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(A0,N,15) ENDIF CF0=0.0D0 CF1=1.0D0-100 DO 15 K=M,0,-1 CF=(2.0D0*K+3.0D0)*CF1/Z+CF0 IF (K.LE.NM) CSI(K)=CF CF0=CF1 15 CF1=CF IF (CDABS(CSI0).GT.CDABS(CSI1)) CS=CSI0/CF IF (CDABS(CSI0).LE.CDABS(CSI1)) CS=CSI1/CF0 DO 20 K=0,NM 20 CSI(K)=CS*CSI(K) ENDIF CDI(0)=CSI(1) DO 25 K=1,NM 25 CDI(K)=CSI(K-1)-(K+1.0D0)*CSI(K)/Z CSK(0)=0.5D0*PI/Z*CDEXP(-Z) CSK(1)=CSK(0)*(1.0D0+1.0D0/Z) DO 30 K=2,NM IF (CDABS(CSI(K-1)).GT.CDABS(CSI(K-2))) THEN CSK(K)=(0.5D0*PI/(Z*Z)-CSI(K)*CSK(K-1))/CSI(K-1) ELSE CSK(K)=(CSI(K)*CSK(K-2)+(K-0.5D0)*PI/Z**3)/CSI(K-2) ENDIF 30 CONTINUE CDK(0)=-CSK(1) DO 35 K=1,NM 35 CDK(K)=-CSK(K-1)-(K+1.0D0)*CSK(K)/Z RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcsphjy.for000077500000000000000000000163401321604176500263070ustar00rootroot00000000000000 PROGRAM MCSPHJY C C ================================================================ C Purpose: This program computes the spherical Bessel functions C jn(z), yn(z), and their derivatives for a complex C argument using subroutine CSPHJY C Input : z --- Complex argument C n --- Order of jn(z) & yn(z) ( 0 ó n ó 250 ) C Output: CSJ(n) --- jn(z) C CDJ(n) --- jn'(z) C CSY(n) --- yn(z) C CDY(n) --- yn'(z) C Example: z = 4.0+i 2.0 C C n Re[jn(z)] Im[jn(z)] Re[jn'(z)] Im[jn'(z)] C -------------------------------------------------------------------- C 0 -.80651523D+00 -.18941093D+00 -.37101203D-01 .75210758D+00 C 1 .37101203D-01 -.75210758D+00 -.67093420D+00 .11885235D+00 C 2 .60314368D+00 -.27298399D+00 -.24288981D+00 -.40737409D+00 C 3 .42955048D+00 .17755176D+00 .18848259D+00 -.24320520D+00 C 4 .12251323D+00 .22087111D+00 .19660170D+00 .17937264D-01 C 5 -.10242676D-01 .10975433D+00 .68951842D-01 .83020305D-01 C C n Re[yn(z)] Im[yn(z)] Re[yn'(z)] Im[yn'(z)] C -------------------------------------------------------------------- C 0 .21734534D+00 -.79487692D+00 -.77049661D+00 -.87010064D-02 C 1 .77049661D+00 .87010064D-02 -.92593503D-01 -.64425800D+00 C 2 .24756293D+00 .56894854D+00 .45127429D+00 -.25839924D+00 C 3 -.23845941D+00 .43646607D+00 .26374403D+00 .12439192D+00 C 4 -.27587985D+00 .20902555D+00 -.67092335D-01 .89500599D-01 C 5 -.70001327D-01 .18807178D+00 -.30472133D+00 -.58661384D-01 C ================================================================ C IMPLICIT COMPLEX*16 (C,Z) DOUBLE PRECISION X,Y DIMENSION CSJ(0:250),CDJ(0:250),CSY(0:250),CDY(0:250) WRITE(*,*)'Please enter n,x,y (z=x+iy) ' READ(*,*)N,X,Y WRITE(*,30)N,X,Y Z=CMPLX(X,Y) IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)'Please enter order step Ns ' READ(*,*)NS ENDIF CALL CSPHJY(N,Z,NM,CSJ,CDJ,CSY,CDY) WRITE(*,*) WRITE(*,*)' n Re[jn(z)] Im[jn(z)]', & ' Re[jn''(z)] Im[jn''(z)]' WRITE(*,*)'--------------------------------------------', & '----------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20)K,CSJ(K),CDJ(K) WRITE(*,*) WRITE(*,*)' n Re[yn(z)] Im[yn(z)]', & ' Re[yn''(z)] Im[yn''(z)]' WRITE(*,*)'--------------------------------------------', & '----------------------------' DO 15 K=0,NM,NS 15 WRITE(*,20)K,CSY(K),CDY(K) 20 FORMAT(1X,I3,4D17.8) 30 FORMAT(3X,6HNmaz =,I3,', ','z = ',F8.1,'+ i',F8.1) END SUBROUTINE CSPHJY(N,Z,NM,CSJ,CDJ,CSY,CDY) C C ========================================================== C Purpose: Compute spherical Bessel functions jn(z) & yn(z) C and their derivatives for a complex argument C Input : z --- Complex argument C n --- Order of jn(z) & yn(z) ( n = 0,1,2,... ) C Output: CSJ(n) --- jn(z) C CDJ(n) --- jn'(z) C CSY(n) --- yn(z) C CDY(n) --- yn'(z) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 for computing the starting C point for backward recurrence C ========================================================== C IMPLICIT COMPLEX*16 (C,Z) DOUBLE PRECISION A0 DIMENSION CSJ(0:N),CDJ(0:N),CSY(0:N),CDY(0:N) A0=CDABS(Z) NM=N IF (A0.LT.1.0D-60) THEN DO 10 K=0,N CSJ(K)=0.0D0 CDJ(K)=0.0D0 CSY(K)=-1.0D+300 10 CDY(K)=1.0D+300 CSJ(0)=(1.0D0,0.0D0) CDJ(1)=(.333333333333333D0,0.0D0) RETURN ENDIF CSJ(0)=CDSIN(Z)/Z CSJ(1)=(CSJ(0)-CDCOS(Z))/Z IF (N.GE.2) THEN CSA=CSJ(0) CSB=CSJ(1) M=MSTA1(A0,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(A0,N,15) ENDIF CF0=0.0D0 CF1=1.0D0-100 DO 15 K=M,0,-1 CF=(2.0D0*K+3.0D0)*CF1/Z-CF0 IF (K.LE.NM) CSJ(K)=CF CF0=CF1 15 CF1=CF IF (CDABS(CSA).GT.CDABS(CSB)) CS=CSA/CF IF (CDABS(CSA).LE.CDABS(CSB)) CS=CSB/CF0 DO 20 K=0,NM 20 CSJ(K)=CS*CSJ(K) ENDIF CDJ(0)=(CDCOS(Z)-CDSIN(Z)/Z)/Z DO 25 K=1,NM 25 CDJ(K)=CSJ(K-1)-(K+1.0D0)*CSJ(K)/Z CSY(0)=-CDCOS(Z)/Z CSY(1)=(CSY(0)-CDSIN(Z))/Z CDY(0)=(CDSIN(Z)+CDCOS(Z)/Z)/Z CDY(1)=(2.0D0*CDY(0)-CDCOS(Z))/Z DO 30 K=2,NM IF (CDABS(CSJ(K-1)).GT.CDABS(CSJ(K-2))) THEN CSY(K)=(CSJ(K)*CSY(K-1)-1.0D0/(Z*Z))/CSJ(K-1) ELSE CSY(K)=(CSJ(K)*CSY(K-2)-(2.0D0*K-1.0D0)/Z**3)/CSJ(K-2) ENDIF 30 CONTINUE DO 35 K=2,NM 35 CDY(K)=CSY(K-1)-(K+1.0D0)*CSY(K)/Z RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcva1.for000077500000000000000000000156141321604176500256440ustar00rootroot00000000000000 PROGRAM MCVA1 C C ============================================================ C Purpose: This program computes a sequence of characteristic C values of Mathieu functions using subroutine CVA1 C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,...) C KD=2 for cem(x,q) ( m = 1,3,5,...) C KD=3 for sem(x,q) ( m = 1,3,5,...) C KD=4 for sem(x,q) ( m = 2,4,6,...) C Output: CV(I) --- Characteristic values; I = 1,2,3,... C For KD=1, CV(1), CV(2), CV(3),..., correspond to C the characteristic values of cem for m = 0,2,4,... C For KD=2, CV(1), CV(2), CV(3),..., correspond to C the characteristic values of cem for m = 1,3,5,... C For KD=3, CV(1), CV(2), CV(3),..., correspond to C the characteristic values of sem for m = 1,3,5,... C For KD=4, CV(1), CV(2), CV(3),..., correspond to C the characteristic values of sem for m = 0,2,4,... C C Example: Mmax = 12, q = 25.00 C C Characteristic values of Mathieu functions C C m a b C ------------------------------------------ C 0 -40.256779547 C 1 -21.314899691 -40.256778985 C 2 -3.522164727 -21.314860622 C 3 12.964079444 -3.520941527 C 4 27.805240581 12.986489953 C 5 40.050190986 28.062765899 C 6 48.975786716 41.801071292 C 7 57.534689001 55.002957151 C 8 69.524065166 69.057988351 C 9 85.076999882 85.023356505 C 10 103.230204804 103.225680042 C 11 123.643012376 123.642713667 C 12 146.207690643 146.207674647 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION CV1(200),CV2(200),CVE(200),CVS(200) WRITE(*,*)'Please enter Mmax,q =?' READ(*,*)MMAX,Q WRITE(*,25)MMAX,Q WRITE(*,*) CALL CVA1(1,MMAX,Q,CV1) CALL CVA1(2,MMAX,Q,CV2) DO 10 J=1,MMAX/2+1 CVE(2*J-1)=CV1(J) 10 CVE(2*J)=CV2(J) CALL CVA1(3,MMAX,Q,CV1) CALL CVA1(4,MMAX,Q,CV2) DO 15 J=1,MMAX/2+1 CVS(2*J)=CV1(J) 15 CVS(2*J+1)=CV2(J) WRITE(*,35) WRITE(*,*) WRITE(*,*)' m a b' WRITE(*,*)'------------------------------------------' DO 20 J=0,MMAX IF (J.EQ.0) WRITE(*,30)J,CVE(J+1) IF (J.NE.0) WRITE(*,30)J,CVE(J+1),CVS(J+1) 20 CONTINUE 25 FORMAT(3X,6HMmax =,I3,', ',3Hq =,F6.2) 30 FORMAT(1X,I3,2F19.9) 35 FORMAT(1X,'Characteristic values of Mathieu functions') END SUBROUTINE CVA1(KD,M,Q,CV) C C ============================================================ C Purpose: Compute a sequence of characteristic values of C Mathieu functions C Input : M --- Maximum order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,úúú ) C KD=2 for cem(x,q) ( m = 1,3,5,úúú ) C KD=3 for sem(x,q) ( m = 1,3,5,úúú ) C KD=4 for sem(x,q) ( m = 2,4,6,úúú ) C Output: CV(I) --- Characteristic values; I = 1,2,3,... C For KD=1, CV(1), CV(2), CV(3),..., correspond to C the characteristic values of cem for m = 0,2,4,... C For KD=2, CV(1), CV(2), CV(3),..., correspond to C the characteristic values of cem for m = 1,3,5,... C For KD=3, CV(1), CV(2), CV(3),..., correspond to C the characteristic values of sem for m = 1,3,5,... C For KD=4, CV(1), CV(2), CV(3),..., correspond to C the characteristic values of sem for m = 0,2,4,... C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(200),H(200),D(500),E(500),F(500),CV(200) EPS=1.0D-14 ICM=INT(M/2)+1 IF (KD.EQ.4) ICM=M/2 IF (Q.EQ.0.0D0) THEN IF (KD.EQ.1) THEN DO 10 IC=1,ICM 10 CV(IC)=4.0D0*(IC-1.0D0)**2 ELSE IF (KD.NE.4) THEN DO 15 IC=1,ICM 15 CV(IC)=(2.0D0*IC-1.0D0)**2 ELSE DO 20 IC=1,ICM 20 CV(IC)=4.0D0*IC*IC ENDIF ELSE NM=INT(10+1.5*M+0.5*Q) E(1)=0.0D0 F(1)=0.0D0 IF (KD.EQ.1) THEN D(1)=0.0D0 DO 25 I=2,NM D(I)=4.0D0*(I-1.0D0)**2 E(I)=Q 25 F(I)=Q*Q E(2)=DSQRT(2.0D0)*Q F(2)=2.0D0*Q*Q ELSE IF (KD.NE.4) THEN D(1)=1.0D0+(-1)**KD*Q DO 30 I=2,NM D(I)=(2.0D0*I-1.0D0)**2 E(I)=Q 30 F(I)=Q*Q ELSE D(1)=4.0D0 DO 35 I=2,NM D(I)=4.0D0*I*I E(I)=Q 35 F(I)=Q*Q ENDIF XA=D(NM)+DABS(E(NM)) XB=D(NM)-DABS(E(NM)) NM1=NM-1 DO 40 I=1,NM1 T=DABS(E(I))+DABS(E(I+1)) T1=D(I)+T IF (XA.LT.T1) XA=T1 T1=D(I)-T IF (T1.LT.XB) XB=T1 40 CONTINUE DO 45 I=1,ICM G(I)=XA 45 H(I)=XB DO 75 K=1,ICM DO 50 K1=K,ICM IF (G(K1).LT.G(K)) THEN G(K)=G(K1) GO TO 55 ENDIF 50 CONTINUE 55 IF (K.NE.1.AND.H(K).LT.H(K-1)) H(K)=H(K-1) 60 X1=(G(K)+H(K))/2.0D0 CV(K)=X1 IF (DABS((G(K)-H(K))/X1).LT.EPS) GO TO 70 J=0 S=1.0D0 DO 65 I=1,NM IF (S.EQ.0.0D0) S=S+1.0D-30 T=F(I)/S S=D(I)-T-X1 IF (S.LT.0.0) J=J+1 65 CONTINUE IF (J.LT.K) THEN H(K)=X1 ELSE G(K)=X1 IF (J.GE.ICM) THEN G(ICM)=X1 ELSE IF (H(J+1).LT.X1) H(J+1)=X1 IF (X1.LT.G(J)) G(J)=X1 ENDIF ENDIF GO TO 60 70 CV(K)=X1 75 CONTINUE ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcva2.for000077500000000000000000000377161321604176500256540ustar00rootroot00000000000000 PROGRAM MCVA2 C C ============================================================= C Purpose: This program calculates a specific characteristic C value of Mathieu functions using subroutine CVA2 C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,...) C KD=2 for cem(x,q) ( m = 1,3,5,...) C KD=3 for sem(x,q) ( m = 1,3,5,...) C KD=4 for sem(x,q) ( m = 2,4,6,...) C Output: A --- Characteristic value C Example: q = 25.0, m = 0,1,2,...,12 C C Characteristic values of Mathieu functions C C m a b C ------------------------------------------ C 0 -40.256779547 C 1 -21.314899691 -40.256778985 C 2 -3.522164727 -21.314860622 C 3 12.964079444 -3.520941527 C 4 27.805240581 12.986489953 C 5 40.050190986 28.062765899 C 6 48.975786716 41.801071292 C 7 57.534689001 55.002957151 C 8 69.524065166 69.057988351 C 9 85.076999882 85.023356505 C 10 103.230204804 103.225680042 C 11 123.643012376 123.642713667 C 12 146.207690643 146.207674647 C ============================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter KD, m and q ' READ(*,*)KD,M,Q CALL CVA2(KD,M,Q,A) IF (KD.LE.2) THEN WRITE(*,20) ELSE WRITE(*,30) ENDIF WRITE(*,*) WRITE(*,*)' m a (or b)' WRITE(*,*)'------------------------' WRITE(*,10)M,A 10 FORMAT(1X,I3,F18.8) 20 FORMAT(1X,'Characteristic value of even Mathieu function, a') 30 FORMAT(1X,'Characteristic value of odd Mathieu function, b') END SUBROUTINE CVA2(KD,M,Q,A) C C ====================================================== C Purpose: Calculate a specific characteristic value of C Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,...) C KD=2 for cem(x,q) ( m = 1,3,5,...) C KD=3 for sem(x,q) ( m = 1,3,5,...) C KD=4 for sem(x,q) ( m = 2,4,6,...) C Output: A --- Characteristic value C Routines called: C (1) REFINE for finding accurate characteristic C value using an iteration method C (2) CV0 for finding initial characteristic C values using polynomial approximation C (3) CVQM for computing initial characteristic C values for q ó 3*m C (3) CVQL for computing initial characteristic C values for q ò m*m C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (M.LE.12.OR.Q.LE.3.0*M.OR.Q.GT.M*M) THEN CALL CV0(KD,M,Q,A) IF (Q.NE.0.0D0) CALL REFINE(KD,M,Q,A,1) ELSE NDIV=10 DELTA=(M-3.0)*M/NDIV IF ((Q-3.0*M).LE.(M*M-Q)) THEN 5 NN=INT((Q-3.0*M)/DELTA)+1 DELTA=(Q-3.0*M)/NN Q1=2.0*M CALL CVQM(M,Q1,A1) Q2=3.0*M CALL CVQM(M,Q2,A2) QQ=3.0*M DO 10 I=1,NN QQ=QQ+DELTA A=(A1*Q2-A2*Q1+(A2-A1)*QQ)/(Q2-Q1) IFLAG=1 IF (I.EQ.NN) IFLAG=-1 CALL REFINE(KD,M,QQ,A,IFLAG) Q1=Q2 Q2=QQ A1=A2 A2=A 10 CONTINUE IF (IFLAG.EQ.-10) THEN NDIV=NDIV*2 DELTA=(M-3.0)*M/NDIV GO TO 5 ENDIF ELSE 15 NN=INT((M*M-Q)/DELTA)+1 DELTA=(M*M-Q)/NN Q1=M*(M-1.0) CALL CVQL(KD,M,Q1,A1) Q2=M*M CALL CVQL(KD,M,Q2,A2) QQ=M*M DO 20 I=1,NN QQ=QQ-DELTA A=(A1*Q2-A2*Q1+(A2-A1)*QQ)/(Q2-Q1) IFLAG=1 IF (I.EQ.NN) IFLAG=-1 CALL REFINE(KD,M,QQ,A,IFLAG) Q1=Q2 Q2=QQ A1=A2 A2=A 20 CONTINUE IF (IFLAG.EQ.-10) THEN NDIV=NDIV*2 DELTA=(M-3.0)*M/NDIV GO TO 15 ENDIF ENDIF ENDIF RETURN END SUBROUTINE REFINE(KD,M,Q,A,IFLAG) C C ===================================================== C Purpose: calculate the accurate characteristic value C by the secant method C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C A --- Initial characteristic value C Output: A --- Refineed characteristic value C Routine called: CVF for computing the value of F for C characteristic equation C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) EPS=1.0D-14 MJ=10+M CA=A DELTA=0.0D0 X0=A CALL CVF(KD,M,Q,X0,MJ,F0) X1=1.002*A CALL CVF(KD,M,Q,X1,MJ,F1) 5 DO 10 IT=1,100 MJ=MJ+1 X=X1-(X1-X0)/(1.0D0-F0/F1) CALL CVF(KD,M,Q,X,MJ,F) IF (ABS(1.0-X1/X).LT.EPS.OR.F.EQ.0.0) GO TO 15 X0=X1 F0=F1 X1=X 10 F1=F 15 A=X IF (DELTA.GT.0.05) THEN A=CA IF (IFLAG.LT.0) THEN IFLAG=-10 ENDIF RETURN ENDIF IF (ABS((A-CA)/CA).GT.0.05) THEN X0=CA DELTA=DELTA+0.005D0 CALL CVF(KD,M,Q,X0,MJ,F0) X1=(1.0D0+DELTA)*CA CALL CVF(KD,M,Q,X1,MJ,F1) GO TO 5 ENDIF RETURN END SUBROUTINE CVF(KD,M,Q,A,MJ,F) C C ====================================================== C Purpose: Compute the value of F for characteristic C equation of Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C A --- Characteristic value C Output: F --- Value of F for characteristic equation C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) B=A IC=INT(M/2) L=0 L0=0 J0=2 JF=IC IF (KD.EQ.1) L0=2 IF (KD.EQ.1) J0=3 IF (KD.EQ.2.OR.KD.EQ.3) L=1 IF (KD.EQ.4) JF=IC-1 T1=0.0D0 DO 10 J=MJ,IC+1,-1 10 T1=-Q*Q/((2.0D0*J+L)**2-B+T1) IF (M.LE.2) THEN T2=0.0D0 IF (KD.EQ.1.AND.M.EQ.0) T1=T1+T1 IF (KD.EQ.1.AND.M.EQ.2) T1=-2.0*Q*Q/(4.0-B+T1)-4.0 IF (KD.EQ.2.AND.M.EQ.1) T1=T1+Q IF (KD.EQ.3.AND.M.EQ.1) T1=T1-Q ELSE IF (KD.EQ.1) T0=4.0D0-B+2.0D0*Q*Q/B IF (KD.EQ.2) T0=1.0D0-B+Q IF (KD.EQ.3) T0=1.0D0-B-Q IF (KD.EQ.4) T0=4.0D0-B T2=-Q*Q/T0 DO 15 J=J0,JF 15 T2=-Q*Q/((2.0D0*J-L-L0)**2-B+T2) ENDIF F=(2.0D0*IC+L)**2+T1+T2-B RETURN END SUBROUTINE CV0(KD,M,Q,A0) C C ===================================================== C Purpose: Compute the initial characteristic value of C Mathieu functions for m ó 12 or q ó 300 or C q ò m*m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Characteristic value C Routines called: C (1) CVQM for computing initial characteristic C value for q ó 3*m C (2) CVQL for computing initial characteristic C value for q ò m*m C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) Q2=Q*Q IF (M.EQ.0) THEN IF (Q.LE.1.0) THEN A0=(((.0036392*Q2-.0125868)*Q2+.0546875)*Q2-.5)*Q2 ELSE IF (Q.LE.10.0) THEN A0=((3.999267D-3*Q-9.638957D-2)*Q-.88297)*Q & +.5542818 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.1) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=(((-6.51E-4*Q-.015625)*Q-.125)*Q+1.0)*Q+1.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=(((-6.51E-4*Q+.015625)*Q-.125)*Q-1.0)*Q+1.0 ELSE IF (Q.LE.10.0.AND. KD.EQ.2) THEN A0=(((-4.94603D-4*Q+1.92917D-2)*Q-.3089229) & *Q+1.33372)*Q+.811752 ELSE IF (Q.LE.10.0.AND.KD.EQ.3) THEN A0=((1.971096D-3*Q-5.482465D-2)*Q-1.152218) & *Q+1.10427 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.2) THEN IF (Q.LE.1.0.AND.KD.EQ.1) THEN A0=(((-.0036391*Q2+.0125888)*Q2-.0551939)*Q2 & +.416667)*Q2+4.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.4) THEN A0=(.0003617*Q2-.0833333)*Q2+4.0 ELSE IF (Q.LE.15.AND.KD.EQ.1) THEN A0=(((3.200972D-4*Q-8.667445D-3)*Q & -1.829032D-4)*Q+.9919999)*Q+3.3290504 ELSE IF (Q.LE.10.0.AND.KD.EQ.4) THEN A0=((2.38446D-3*Q-.08725329)*Q-4.732542D-3) & *Q+4.00909 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.3) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=((6.348E-4*Q+.015625)*Q+.0625)*Q2+9.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=((6.348E-4*Q-.015625)*Q+.0625)*Q2+9.0 ELSE IF (Q.LE.20.0.AND.KD.EQ.2) THEN A0=(((3.035731D-4*Q-1.453021D-2)*Q & +.19069602)*Q-.1039356)*Q+8.9449274 ELSE IF (Q.LE.15.0.AND.KD.EQ.3) THEN A0=((9.369364D-5*Q-.03569325)*Q+.2689874)*Q & +8.771735 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.4) THEN IF (Q.LE.1.0.AND.KD.EQ.1) THEN A0=((-2.1E-6*Q2+5.012E-4)*Q2+.0333333)*Q2+16.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.4) THEN A0=((3.7E-6*Q2-3.669E-4)*Q2+.0333333)*Q2+16.0 ELSE IF (Q.LE.25.0.AND.KD.EQ.1) THEN A0=(((1.076676D-4*Q-7.9684875D-3)*Q & +.17344854)*Q-.5924058)*Q+16.620847 ELSE IF (Q.LE.20.0.AND.KD.EQ.4) THEN A0=((-7.08719D-4*Q+3.8216144D-3)*Q & +.1907493)*Q+15.744 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.5) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=((6.8E-6*Q+1.42E-5)*Q2+.0208333)*Q2+25.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=((-6.8E-6*Q+1.42E-5)*Q2+.0208333)*Q2+25.0 ELSE IF (Q.LE.35.0.AND.KD.EQ.2) THEN A0=(((2.238231D-5*Q-2.983416D-3)*Q & +.10706975)*Q-.600205)*Q+25.93515 ELSE IF (Q.LE.25.0.AND.KD.EQ.3) THEN A0=((-7.425364D-4*Q+2.18225D-2)*Q & +4.16399D-2)*Q+24.897 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.6) THEN IF (Q.LE.1.0) THEN A0=(.4D-6*Q2+.0142857)*Q2+36.0 ELSE IF (Q.LE.40.0.AND.KD.EQ.1) THEN A0=(((-1.66846D-5*Q+4.80263D-4)*Q & +2.53998D-2)*Q-.181233)*Q+36.423 ELSE IF (Q.LE.35.0.AND.KD.EQ.4) THEN A0=((-4.57146D-4*Q+2.16609D-2)*Q-2.349616D-2)*Q & +35.99251 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.7) THEN IF (Q.LE.10.0) THEN CALL CVQM(M,Q,A0) ELSE IF (Q.LE.50.0.AND.KD.EQ.2) THEN A0=(((-1.411114D-5*Q+9.730514D-4)*Q & -3.097887D-3)*Q+3.533597D-2)*Q+49.0547 ELSE IF (Q.LE.40.0.AND.KD.EQ.3) THEN A0=((-3.043872D-4*Q+2.05511D-2)*Q & -9.16292D-2)*Q+49.19035 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.GE.8) THEN IF (Q.LE.3.*M) THEN CALL CVQM(M,Q,A0) ELSE IF (Q.GT.M*M) THEN CALL CVQL(KD,M,Q,A0) ELSE IF (M.EQ.8.AND.KD.EQ.1) THEN A0=(((8.634308D-6*Q-2.100289D-3)*Q+.169072)*Q & -4.64336)*Q+109.4211 ELSE IF (M.EQ.8.AND.KD.EQ.4) THEN A0=((-6.7842D-5*Q+2.2057D-3)*Q+.48296)*Q+56.59 ELSE IF (M.EQ.9.AND.KD.EQ.2) THEN A0=(((2.906435D-6*Q-1.019893D-3)*Q+.1101965)*Q & -3.821851)*Q+127.6098 ELSE IF (M.EQ.9.AND.KD.EQ.3) THEN A0=((-9.577289D-5*Q+.01043839)*Q+.06588934)*Q & +78.0198 ELSE IF (M.EQ.10.AND.KD.EQ.1) THEN A0=(((5.44927D-7*Q-3.926119D-4)*Q+.0612099)*Q & -2.600805)*Q+138.1923 ELSE IF (M.EQ.10.AND.KD.EQ.4) THEN A0=((-7.660143D-5*Q+.01132506)*Q-.09746023)*Q & +99.29494 ELSE IF (M.EQ.11.AND.KD.EQ.2) THEN A0=(((-5.67615D-7*Q+7.152722D-6)*Q+.01920291)*Q & -1.081583)*Q+140.88 ELSE IF (M.EQ.11.AND.KD.EQ.3) THEN A0=((-6.310551D-5*Q+.0119247)*Q-.2681195)*Q & +123.667 ELSE IF (M.EQ.12.AND.KD.EQ.1) THEN A0=(((-2.38351D-7*Q-2.90139D-5)*Q+.02023088)*Q & -1.289)*Q+171.2723 ELSE IF (M.EQ.12.AND.KD.EQ.4) THEN A0=(((3.08902D-7*Q-1.577869D-4)*Q+.0247911)*Q & -1.05454)*Q+161.471 ENDIF ENDIF ENDIF RETURN END SUBROUTINE CVQL(KD,M,Q,A0) C C ======================================================== C Purpose: Compute the characteristic value of Mathieu C functions for q ò 3m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Initial characteristic value C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (KD.EQ.1.OR.KD.EQ.2) W=2.0D0*M+1.0D0 IF (KD.EQ.3.OR.KD.EQ.4) W=2.0D0*M-1.0D0 W2=W*W W3=W*W2 W4=W2*W2 W6=W2*W4 D1=5.0+34.0/W2+9.0/W4 D2=(33.0+410.0/W2+405.0/W4)/W D3=(63.0+1260.0/W2+2943.0/W4+486.0/W6)/W2 D4=(527.0+15617.0/W2+69001.0/W4+41607.0/W6)/W3 C1=128.0 P2=Q/W4 P1=DSQRT(P2) CV1=-2.0*Q+2.0*W*DSQRT(Q)-(W2+1.0)/8.0 CV2=(W+3.0/W)+D1/(32.0*P1)+D2/(8.0*C1*P2) CV2=CV2+D3/(64.0*C1*P1*P2)+D4/(16.0*C1*C1*P2*P2) A0=CV1-CV2/(C1*P1) RETURN END SUBROUTINE CVQM(M,Q,A0) C C ===================================================== C Purpose: Compute the characteristic value of Mathieu C functions for q ó m*m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Initial characteristic value C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) HM1=.5*Q/(M*M-1.0) HM3=.25*HM1**3/(M*M-4.0) HM5=HM1*HM3*Q/((M*M-1.0)*(M*M-9.0)) A0=M*M+Q*(HM1+(5.0*M*M+7.0)*HM3 & +(9.0*M**4+58.0*M*M+29.0)*HM5) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mcyzo.for000077500000000000000000000264521321604176500260000ustar00rootroot00000000000000 PROGRAM MCYZO C C =========================================================== C Purpose : This program evaluates the complex zeros of C Y0(z), Y0'(z), Y1(z) and Y1'(z), and their C associated values at the zeros using the C modified Newton's iteration method C Input: NT --- Total number of roots/zeros C KF --- Function choice code C KF=0 for Y0(z) & Y1(z0) C KF=1 for Y1(z) & Y0(z1) C KF=2 for Y1'(z) & Y1(z1') C KC --- Choice code C KC=0 for complex roots C KC=1 for real roots C Output: ZO(L) --- L-th zero of Y0(z) or Y1(z) or Y1'(z) C ZV(L) --- Value of Y0'(z) or Y1'(z) or Y1(z) C at the L-th zero C Examples: NT = 5 C C No. z0, Zeros of Y0(z) Y1(z0) C ----------------------------------------------------------------- C 1 -2.403016632 + i .5398823130 .1007476893 - i .8819677101 C 2 -5.519876702 + i .5471800106 -.0292464182 + i .5871695027 C 3 -8.653672403 + i .5484120673 .0149080637 - i .4694587524 C 4 -11.791512030 + i .5488191184 -.0093736817 + i .4023045429 C 5 -14.930906564 + i .5490008289 .0065788031 - i .3575673214 C C No. z1, Zeros of Y1(z) Y0(z1) C ----------------------------------------------------------------- C 1 -.502743273 + i .7862437145 -.4595276847 + i1.3171019361 C 2 -3.833535193 + i .5623565382 .0483019087 - i .6925128842 C 3 -7.015903683 + i .5533930459 -.0201269494 + i .5186425332 C 4 -10.173573834 + i .5512733877 .0116140017 - i .4320329636 C 5 -13.323739307 + i .5504585830 -.0077719300 + i .3779698048 C C No. z1', Zeros of Y1'(z) Y1(z1') C ---------------------------------------------------------------- C 1 .576785129 + i .9039847922 -.7634970879 + i .5892448647 C 2 -1.940477342 - i .7211859189 .1620640057 + i .9520278864 C 3 -5.333478617 - i .5672196368 -.0317940081 - i .5968536736 C 4 -8.536768577 - i .5560607040 .0154177166 + i .4726011652 C 5 -11.706175219 - i .5528590607 -.0095443768 - i .4037533396 C ============================================================ C IMPLICIT COMPLEX *16 (Z) DIMENSION ZO(50),ZV(50) WRITE(*,*)'Please Enter NT, KF and KC' WRITE(*,*)' NT --- Total number of the roots' WRITE(*,*)' KF --- Function choice code' WRITE(*,*)' KF=0 for Y0(z) & Y1(z0)' WRITE(*,*)' KF=1 for Y1(z) & Y0(z1)' WRITE(*,*)' KF=2 for Y1''(z) & Y1(z1'')' WRITE(*,*)' KC --- Choice code' WRITE(*,*)' KC=0 for complex roots' WRITE(*,*)' KC=1 for real roots' READ(*,*)NT,KF,KC WRITE(*,20)NT,KF,KC WRITE(*,*) WRITE(*,15) CALL CYZO(NT,KF,KC,ZO,ZV) WRITE(*,*) IF (KF.EQ.0) THEN WRITE(*,*)' No. z0, Zeros of Y0(z)', & ' Y1(z0)' ELSE IF (KF.EQ.1) THEN WRITE(*,*)' No. z1, Zeros of Y1(z)', & ' Y0(z1)' ELSE IF (KF.EQ.2) THEN WRITE(*,*)' No. z1'', Zeros of Y1''(z)', & ' Y1(z1'')' ENDIF WRITE(*,*)'--------------------------------------', & '----------------------------' DO 10 I=1,NT 10 WRITE(*,25)I,ZO(I),ZV(I) 15 FORMAT(20X,'***** Please Wait ! *****') 20 FORMAT(2X,'NT=',I3,', ','KF=',I3,', ','KC=',I3) 25 FORMAT(1X,I3,2X,F15.9,3F15.10) END SUBROUTINE CYZO(NT,KF,KC,ZO,ZV) C C =========================================================== C Purpose : Compute the complex zeros of Y0(z), Y1(z) and C Y1'(z), and their associated values at the zeros C using the modified Newton's iteration method C Input: NT --- Total number of zeros/roots C KF --- Function choice code C KF=0 for Y0(z) & Y1(z0) C KF=1 for Y1(z) & Y0(z1) C KF=2 for Y1'(z) & Y1(z1') C KC --- Choice code C KC=0 for complex roots C KC=1 for real roots C Output: ZO(L) --- L-th zero of Y0(z) or Y1(z) or Y1'(z) C ZV(L) --- Value of Y0'(z) or Y1'(z) or Y1(z) C at the L-th zero C Routine called: CY01 for computing Y0(z) and Y1(z), and C their derivatives C =========================================================== IMPLICIT DOUBLE PRECISION (H,O-Y) IMPLICIT COMPLEX*16 (C,Z) DIMENSION ZO(NT),ZV(NT) IF (KC.EQ.0) THEN X=-2.4D0 Y=0.54D0 H=3.14 ELSE IF (KC.EQ.1) THEN X=0.89 Y=0.0 H=-3.14 ENDIF IF (KF.EQ.1) X=-0.503 IF (KF.EQ.2) X=0.577 ZERO=CMPLX(X,Y) Z=ZERO DO 35 NR=1,NT 10 IF (NR.NE.1) Z=ZO(NR-1)-H IT=0 15 IT=IT+1 CALL CY01(KF,Z,ZF,ZD) ZP=(1.0D0,0.0D0) DO 20 I=1,NR-1 20 ZP=ZP*(Z-ZO(I)) ZFD=ZF/ZP ZQ=(0.0D0,0.0D0) DO 30 I=1,NR-1 ZW=(1.0D0,0.0D0) DO 25 J=1,NR-1 IF (J.EQ.I) GO TO 25 ZW=ZW*(Z-ZO(J)) 25 CONTINUE ZQ=ZQ+ZW 30 CONTINUE ZGD=(ZD-ZQ*ZFD)/ZP Z=Z-ZFD/ZGD W0=W W=CDABS(Z) IF (IT.LE.50.AND.DABS((W-W0)/W).GT.1.0D-12) GO TO 15 ZO(NR)=Z 35 CONTINUE DO 40 I=1,NT Z=ZO(I) IF (KF.EQ.0.OR.KF.EQ.2) THEN CALL CY01(1,Z,ZF,ZD) ZV(I)=ZF ELSE IF (KF.EQ.1) THEN CALL CY01(0,Z,ZF,ZD) ZV(I)=ZF ENDIF 40 CONTINUE RETURN END SUBROUTINE CY01(KF,Z,ZF,ZD) C C =========================================================== C Purpose: Compute complex Bessel functions Y0(z), Y1(z) C and their derivatives C Input : z --- Complex argument of Yn(z) ( n=0,1 ) C KF --- Function choice code C KF=0 for ZF=Y0(z) and ZD=Y0'(z) C KF=1 for ZF=Y1(z) and ZD=Y1'(z) C KF=2 for ZF=Y1'(z) and ZD=Y1''(z) C Output: ZF --- Y0(z) or Y1(z) or Y1'(z) C ZD --- Y0'(z) or Y1'(z) or Y1''(z) C =========================================================== C IMPLICIT DOUBLE PRECISION (A,B,E,P,R,W) IMPLICIT COMPLEX*16 (C,Z) DIMENSION A(12),B(12),A1(12),B1(12) PI=3.141592653589793D0 EL=0.5772156649015329D0 RP2=2.0D0/PI CI=(0.0D0,1.0D0) A0=CDABS(Z) Z2=Z*Z Z1=Z IF (A0.EQ.0.0D0) THEN CBJ0=(1.0D0,0.0D0) CBJ1=(0.0D0,0.0D0) CBY0=-(1.0D300,0.0D0) CBY1=-(1.0D300,0.0D0) CDY0=(1.0D300,0.0D0) CDY1=(1.0D300,0.0D0) GO TO 70 ENDIF IF (REAL(Z).LT.0.0) Z1=-Z IF (A0.LE.12.0) THEN CBJ0=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 10 K=1,40 CR=-0.25D0*CR*Z2/(K*K) CBJ0=CBJ0+CR IF (CDABS(CR).LT.CDABS(CBJ0)*1.0D-15) GO TO 15 10 CONTINUE 15 CBJ1=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 20 K=1,40 CR=-0.25D0*CR*Z2/(K*(K+1.0D0)) CBJ1=CBJ1+CR IF (CDABS(CR).LT.CDABS(CBJ1)*1.0D-15) GO TO 25 20 CONTINUE 25 CBJ1=0.5D0*Z1*CBJ1 W0=0.0D0 CR=(1.0D0,0.0D0) CS=(0.0D0,0.0D0) DO 30 K=1,40 W0=W0+1.0D0/K CR=-0.25D0*CR/(K*K)*Z2 CP=CR*W0 CS=CS+CP IF (CDABS(CP).LT.CDABS(CS)*1.0D-15) GO TO 35 30 CONTINUE 35 CBY0=RP2*(CDLOG(Z1/2.0D0)+EL)*CBJ0-RP2*CS W1=0.0D0 CR=(1.0D0,0.0D0) CS=(1.0D0,0.0D0) DO 40 K=1,40 W1=W1+1.0D0/K CR=-0.25D0*CR/(K*(K+1))*Z2 CP=CR*(2.0D0*W1+1.0D0/(K+1.0D0)) CS=CS+CP IF (CDABS(CP).LT.CDABS(CS)*1.0D-15) GO TO 45 40 CONTINUE 45 CBY1=RP2*((CDLOG(Z1/2.0D0)+EL)*CBJ1-1.0D0/Z1-.25D0*Z1*CS) ELSE DATA A/-.703125D-01,.112152099609375D+00, & -.5725014209747314D+00,.6074042001273483D+01, & -.1100171402692467D+03,.3038090510922384D+04, & -.1188384262567832D+06,.6252951493434797D+07, & -.4259392165047669D+09,.3646840080706556D+11, & -.3833534661393944D+13,.4854014686852901D+15/ DATA B/ .732421875D-01,-.2271080017089844D+00, & .1727727502584457D+01,-.2438052969955606D+02, & .5513358961220206D+03,-.1825775547429318D+05, & .8328593040162893D+06,-.5006958953198893D+08, & .3836255180230433D+10,-.3649010818849833D+12, & .4218971570284096D+14,-.5827244631566907D+16/ DATA A1/.1171875D+00,-.144195556640625D+00, & .6765925884246826D+00,-.6883914268109947D+01, & .1215978918765359D+03,-.3302272294480852D+04, & .1276412726461746D+06,-.6656367718817688D+07, & .4502786003050393D+09,-.3833857520742790D+11, & .4011838599133198D+13,-.5060568503314727D+15/ DATA B1/-.1025390625D+00,.2775764465332031D+00, & -.1993531733751297D+01,.2724882731126854D+02, & -.6038440767050702D+03,.1971837591223663D+05, & -.8902978767070678D+06,.5310411010968522D+08, & -.4043620325107754D+10,.3827011346598605D+12, & -.4406481417852278D+14,.6065091351222699D+16/ K0=12 IF (A0.GE.35.0) K0=10 IF (A0.GE.50.0) K0=8 CT1=Z1-.25D0*PI CP0=(1.0D0,0.0D0) DO 50 K=1,K0 50 CP0=CP0+A(K)*Z1**(-2*K) CQ0=-0.125D0/Z1 DO 55 K=1,K0 55 CQ0=CQ0+B(K)*Z1**(-2*K-1) CU=CDSQRT(RP2/Z1) CBJ0=CU*(CP0*CDCOS(CT1)-CQ0*CDSIN(CT1)) CBY0=CU*(CP0*CDSIN(CT1)+CQ0*CDCOS(CT1)) CT2=Z1-.75D0*PI CP1=(1.0D0,0.0D0) DO 60 K=1,K0 60 CP1=CP1+A1(K)*Z1**(-2*K) CQ1=0.375D0/Z1 DO 65 K=1,K0 65 CQ1=CQ1+B1(K)*Z1**(-2*K-1) CBJ1=CU*(CP1*CDCOS(CT2)-CQ1*CDSIN(CT2)) CBY1=CU*(CP1*CDSIN(CT2)+CQ1*CDCOS(CT2)) ENDIF IF (REAL(Z).LT.0.0) THEN IF (DIMAG(Z).LT.0.0) CBY0=CBY0-2.0D0*CI*CBJ0 IF (DIMAG(Z).GT.0.0) CBY0=CBY0+2.0D0*CI*CBJ0 IF (DIMAG(Z).LT.0.0) CBY1=-(CBY1-2.0D0*CI*CBJ1) IF (DIMAG(Z).GT.0.0) CBY1=-(CBY1+2.0D0*CI*CBJ1) CBJ1=-CBJ1 ENDIF CDY0=-CBY1 CDY1=CBY0-1.0D0/Z*CBY1 70 IF (KF.EQ.0) THEN ZF=CBY0 ZD=CDY0 ELSE IF (KF.EQ.1) THEN ZF=CBY1 ZD=CDY1 ELSE IF (KF.EQ.2) THEN ZF=CDY1 ZD=-CDY1/Z-(1.0D0-1.0D0/(Z*Z))*CBY1 ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/me1xa.for000077500000000000000000000033451321604176500256460ustar00rootroot00000000000000 PROGRAM ME1XA C C ========================================================= C Purpose: This program computes the exponential integral C E1(x) using subroutine E1XA C Input : x --- Argument of E1(x) ( x > 0 ) C Output: E1 --- E1(x) C Example: C x E1(x) C ---------------------- C 0.0 .1000000+301 C 1.0 .2193839E+00 C 2.0 .4890051E-01 C 3.0 .1304838E-01 C 4.0 .3779352E-02 C 5.0 .1148296E-02 C ========================================================= C DOUBLE PRECISION E1,X WRITE(*,*)'Please enter x ' READ(*,*) X WRITE(*,*)' x E1(x)' WRITE(*,*)' ----------------------' CALL E1XA(X,E1) WRITE(*,10)X,E1 10 FORMAT(1X,F5.1,E17.7) END SUBROUTINE E1XA(X,E1) C C ============================================ C Purpose: Compute exponential integral E1(x) C Input : x --- Argument of E1(x) C Output: E1 --- E1(x) ( x > 0 ) C ============================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (X.EQ.0.0) THEN E1=1.0D+300 ELSE IF (X.LE.1.0) THEN E1=-DLOG(X)+((((1.07857D-3*X-9.76004D-3)*X+5.519968D-2)*X & -0.24991055D0)*X+0.99999193D0)*X-0.57721566D0 ELSE ES1=(((X+8.5733287401D0)*X+18.059016973D0)*X & +8.6347608925D0)*X+0.2677737343D0 ES2=(((X+9.5733223454D0)*X+25.6329561486D0)*X & +21.0996530827D0)*X+3.9584969228D0 E1=DEXP(-X)/X*ES1/ES2 ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/me1xb.for000077500000000000000000000035101321604176500256410ustar00rootroot00000000000000 PROGRAM ME1XB C C ========================================================= C Purpose: This program computes the exponential integral C E1(x) using subroutine E1XB C Input : x --- Argument of E1(x) ( x > 0 ) C Output: E1 --- E1(x) C Example: C x E1(x) C ------------------------- C 0.0 .1000000000+301 C 1.0 .2193839344E+00 C 2.0 .4890051071E-01 C 3.0 .1304838109E-01 C 4.0 .3779352410E-02 C 5.0 .1148295591E-02 C ========================================================= C DOUBLE PRECISION E1,X WRITE(*,*)'Please enter x ' READ(*,*) X WRITE(*,*)' x E1(x)' WRITE(*,*)' -------------------------' CALL E1XB(X,E1) WRITE(*,10)X,E1 10 FORMAT(1X,F5.1,E20.10) END SUBROUTINE E1XB(X,E1) C C ============================================ C Purpose: Compute exponential integral E1(x) C Input : x --- Argument of E1(x) C Output: E1 --- E1(x) ( x > 0 ) C ============================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (X.EQ.0.0) THEN E1=1.0D+300 ELSE IF (X.LE.1.0) THEN E1=1.0D0 R=1.0D0 DO 10 K=1,25 R=-R*K*X/(K+1.0D0)**2 E1=E1+R IF (DABS(R).LE.DABS(E1)*1.0D-15) GO TO 15 10 CONTINUE 15 GA=0.5772156649015328D0 E1=-GA-DLOG(X)+X*E1 ELSE M=20+INT(80.0/X) T0=0.0D0 DO 20 K=M,1,-1 T0=K/(1.0D0+K/(X+T0)) 20 CONTINUE T=1.0D0/(X+T0) E1=DEXP(-X)*T ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/me1z.for000077500000000000000000000047161321604176500255120ustar00rootroot00000000000000 PROGRAM ME1Z C C ========================================================= C Purpose: This program computes the complex exponential C integral E1(z) using subroutine E1Z C Example: C z Re[E1(z)] Im[E1(z)] C ----------------------------------------------- C 3.0 2.0 -.90959209D-02 -.69001793D-02 C 3.0 -2.0 -.90959209D-02 .69001793D-02 C -3.0 2.0 -.28074891D+01 .59603353D+01 C -3.0 -2.0 -.28074891D+01 -.59603353D+01 C 25.0 10.0 -.29302080D-12 .40391222D-12 C 25.0 -10.0 -.29302080D-12 -.40391222D-12 C -25.0 10.0 .27279957D+10 -.49430610D+09 C -25.0 -10.0 .27279957D+10 .49430610D+09 C ========================================================= C IMPLICIT COMPLEX*16 (C,Z) IMPLICIT DOUBLE PRECISION (D-H,O-Y) WRITE(*,*)'Please enter x and y ( z =x+iy ) ' READ(*,*)X,Y Z=CMPLX(X,Y) CALL E1Z(Z,CE1) WRITE(*,*) WRITE(*,*)' z Re[E1(z)] Im[E1(z)]' WRITE(*,*)' -----------------------------------------------' WRITE(*,10)X,Y,CE1 10 FORMAT(1X,F5.1,2X,F5.1,1X,2D17.8) END SUBROUTINE E1Z(Z,CE1) C C ==================================================== C Purpose: Compute complex exponential integral E1(z) C Input : z --- Argument of E1(z) C Output: CE1 --- E1(z) C ==================================================== C IMPLICIT COMPLEX*16 (C,Z) IMPLICIT DOUBLE PRECISION (D-H,O-Y) PI=3.141592653589793D0 EL=0.5772156649015328D0 X=REAL(Z) A0=CDABS(Z) IF (A0.EQ.0.0D0) THEN CE1=(1.0D+300,0.0D0) ELSE IF (A0.LE.10.0.OR.X.LT.0.0.AND.A0.LT.20.0) THEN CE1=(1.0D0,0.0D0) CR=(1.0D0,0.0D0) DO 10 K=1,150 CR=-CR*K*Z/(K+1.0D0)**2 CE1=CE1+CR IF (CDABS(CR).LE.CDABS(CE1)*1.0D-15) GO TO 15 10 CONTINUE 15 CE1=-EL-CDLOG(Z)+Z*CE1 ELSE CT0=(0.0D0,0.0D0) DO 20 K=120,1,-1 CT0=K/(1.0D0+K/(Z+CT0)) 20 CONTINUE CT=1.0D0/(Z+CT0) CE1=CDEXP(-Z)*CT IF (X.LE.0.0.AND.DIMAG(Z).EQ.0.0) CE1=CE1-PI*(0.0D0,1.0D0) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/meix.for000077500000000000000000000032641321604176500255750ustar00rootroot00000000000000 PROGRAM MEIX C C ========================================================= C Purpose: This program computes the exponential integral C Ei(x) using subroutine EIX C Example: C x Ei(x) C ----------------------- C 0 -.10000000+301 C 1 .18951178E+01 C 2 .49542344E+01 C 3 .99338326E+01 C 4 .19630874E+02 C 5 .40185275E+02 C ========================================================= C DOUBLE PRECISION EI,X WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*) WRITE(*,*)' x Ei(x)' WRITE(*,*)'------------------------' CALL EIX(X,EI) WRITE(*,10)X,EI 10 FORMAT(1X,F5.1,E18.8) END SUBROUTINE EIX(X,EI) C C ============================================ C Purpose: Compute exponential integral Ei(x) C Input : x --- Argument of Ei(x) C Output: EI --- Ei(x) ( x > 0 ) C ============================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (X.EQ.0.0) THEN EI=-1.0D+300 ELSE IF (X.LE.40.0) THEN EI=1.0D0 R=1.0D0 DO 15 K=1,100 R=R*K*X/(K+1.0D0)**2 EI=EI+R IF (DABS(R/EI).LE.1.0D-15) GO TO 20 15 CONTINUE 20 GA=0.5772156649015328D0 EI=GA+DLOG(X)+X*EI ELSE EI=1.0D0 R=1.0D0 DO 25 K=1,20 R=R*K/X 25 EI=EI+R EI=DEXP(X)/X*EI ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/melit.for000077500000000000000000000055311321604176500257440ustar00rootroot00000000000000 PROGRAM MELIT C C ========================================================== C Purpose: This program computes complete and incomplete C elliptic integrals F(k,phi) and E(k,phi) using C subroutine ELIT C Input : HK --- Modulus k ( 0 ó k ó 1 ) C Phi --- Argument ( in degrees ) C Output : FE --- F(k,phi) C EE --- E(k,phi) C Example: C k = .5 C C phi F(k,phi) E(k,phi) C ----------------------------------- C 0 .00000000 .00000000 C 15 .26254249 .26106005 C 30 .52942863 .51788193 C 45 .80436610 .76719599 C 60 1.08955067 1.00755556 C 75 1.38457455 1.23988858 C 90 1.68575035 1.46746221 C ========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter k and phi (in degs.) ' READ(*,*)HK,PHI WRITE(*,*) WRITE(*,*)' phi F(k,phi) E(k,phi)' WRITE(*,*)' -----------------------------------' CALL ELIT(HK,PHI,FE,EE) WRITE(*,10)PHI,FE,EE 10 FORMAT(1X,I4,2F15.8) END SUBROUTINE ELIT(HK,PHI,FE,EE) C C ================================================== C Purpose: Compute complete and incomplete elliptic C integrals F(k,phi) and E(k,phi) C Input : HK --- Modulus k ( 0 ó k ó 1 ) C Phi --- Argument ( in degrees ) C Output : FE --- F(k,phi) C EE --- E(k,phi) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) G=0.0D0 PI=3.14159265358979D0 A0=1.0D0 B0=DSQRT(1.0D0-HK*HK) D0=(PI/180.0D0)*PHI R=HK*HK IF (HK.EQ.1.0D0.AND.PHI.EQ.90.0D0) THEN FE=1.0D+300 EE=1.0D0 ELSE IF (HK.EQ.1.0D0) THEN FE=DLOG((1.0D0+DSIN(D0))/DCOS(D0)) EE=DSIN(D0) ELSE FAC=1.0D0 DO 10 N=1,40 A=(A0+B0)/2.0D0 B=DSQRT(A0*B0) C=(A0-B0)/2.0D0 FAC=2.0D0*FAC R=R+FAC*C*C IF (PHI.NE.90.0D0) THEN D=D0+DATAN((B0/A0)*DTAN(D0)) G=G+C*DSIN(D) D0=D+PI*INT(D/PI+.5D0) ENDIF A0=A B0=B IF (C.LT.1.0D-7) GO TO 15 10 CONTINUE 15 CK=PI/(2.0D0*A) CE=PI*(2.0D0-R)/(4.0D0*A) IF (PHI.EQ.90.0D0) THEN FE=CK EE=CE ELSE FE=D/(FAC*A) EE=FE*CE/CK+G ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/melit3.for000077500000000000000000000047721321604176500260350ustar00rootroot00000000000000 PROGRAM MELIT3 C C ========================================================== C Purpose: This program computes the elliptic integral of C the third kind using subroutine ELIT3 C Input : Phi --- Argument ( in degrees ) C k --- Modulus ( 0 ó k ó 1 ) C c --- Parameter ( 0 ó c ó 1 ) C Output: EL3 ÄÄÄ Value of the elliptic integral of the C third kind C ========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter phi, k and c ' READ(*,*)PHI,HK,C CALL ELIT3(PHI,HK,C,EL3) WRITE(*,10)EL3 10 FORMAT(1X,'EL3=',F12.8) END SUBROUTINE ELIT3(PHI,HK,C,EL3) C C ========================================================= C Purpose: Compute the elliptic integral of the third kind C using Gauss-Legendre quadrature C Input : Phi --- Argument ( in degrees ) C k --- Modulus ( 0 ó k ó 1.0 ) C c --- Parameter ( 0 ó c ó 1.0 ) C Output: EL3 --- Value of the elliptic integral of the C third kind C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION T(10),W(10) LOGICAL LB1,LB2 DATA T/.9931285991850949,.9639719272779138, & .9122344282513259,.8391169718222188, & .7463319064601508,.6360536807265150, & .5108670019508271,.3737060887154195, & .2277858511416451,.7652652113349734D-1/ DATA W/.1761400713915212D-1,.4060142980038694D-1, & .6267204833410907D-1,.8327674157670475D-1, & .1019301198172404,.1181945319615184, & .1316886384491766,.1420961093183820, & .1491729864726037,.1527533871307258/ LB1=HK.EQ.1.0D0.AND.DABS(PHI-90.0).LE.1.0D-8 LB2=C.EQ.1.0D0.AND.DABS(PHI-90.0).LE.1.0D-8 IF (LB1.OR.LB2) THEN EL3=1.0D+300 RETURN ENDIF C1=0.87266462599716D-2*PHI C2=C1 EL3=0.0D0 DO 10 I=1,10 C0=C2*T(I) T1=C1+C0 T2=C1-C0 F1=1.0D0/((1.0D0-C*DSIN(T1)*DSIN(T1))* & DSQRT(1.0D0-HK*HK*DSIN(T1)*DSIN(T1))) F2=1.0D0/((1.0D0-C*DSIN(T2)*DSIN(T2))* & DSQRT(1.0D0-HK*HK*DSIN(T2)*DSIN(T2))) 10 EL3=EL3+W(I)*(F1+F2) EL3=C1*EL3 RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/menxa.for000077500000000000000000000050011321604176500257320ustar00rootroot00000000000000 PROGRAM MENXA C C ========================================================= C Purpose: This program computes the exponential integral C En(x) using subroutine ENXA C Example: x = 10.0 C n En(x) C ---------------------- C 0 .45399930D-05 C 1 .41569689D-05 C 2 .38302405D-05 C 3 .35487626D-05 C 4 .33041014D-05 C 5 .30897289D-05 C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EN(0:100) WRITE(*,*)'Please enter n and x ' READ(*,*)N,X WRITE(*,20)N,X WRITE(*,*) WRITE(*,*)' n En(x)' WRITE(*,*)' ----------------------' CALL ENXA(N,X,EN) DO 10 K=0,N WRITE(*,30)K,EN(K) 10 CONTINUE 20 FORMAT(5X,I3,', ','x=',F5.1) 30 FORMAT(2X,I3,D18.8) END SUBROUTINE ENXA(N,X,EN) C C ============================================ C Purpose: Compute exponential integral En(x) C Input : x --- Argument of En(x) ( x ó 20 ) C n --- Order of En(x) C Output: EN(n) --- En(x) C Routine called: E1XB for computing E1(x) C ============================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EN(0:N) EN(0)=DEXP(-X)/X CALL E1XB(X,E1) EN(1)=E1 DO 10 K=2,N EK=(DEXP(-X)-X*E1)/(K-1.0D0) EN(K)=EK 10 E1=EK RETURN END SUBROUTINE E1XB(X,E1) C C ============================================ C Purpose: Compute exponential integral E1(x) C Input : x --- Argument of E1(x) C Output: E1 --- E1(x) C ============================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (X.EQ.0.0) THEN E1=1.0D+300 ELSE IF (X.LE.1.0) THEN E1=1.0D0 R=1.0D0 DO 10 K=1,25 R=-R*K*X/(K+1.0D0)**2 E1=E1+R IF (DABS(R).LE.DABS(E1)*1.0D-15) GO TO 15 10 CONTINUE 15 GA=0.5772156649015328D0 E1=-GA-DLOG(X)+X*E1 ELSE M=20+INT(80.0/X) T0=0.0D0 DO 20 K=M,1,-1 T0=K/(1.0D0+K/(X+T0)) 20 CONTINUE T=1.0D0/(X+T0) E1=DEXP(-X)*T ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/menxb.for000077500000000000000000000047441321604176500257500ustar00rootroot00000000000000 PROGRAM MENXB C C ========================================================= C Purpose: This program computes the exponential integral C En(x) using subroutine ENXB C Example: x = 10.0 C n En(x) C ---------------------- C 0 .45399930D-05 C 1 .41569689D-05 C 2 .38302405D-05 C 3 .35487626D-05 C 4 .33041014D-05 C 5 .30897289D-05 C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EN(0:100) WRITE(*,*)'Please enter n and x ' READ(*,*)N,X WRITE(*,20)N,X WRITE(*,*) WRITE(*,*)' n En(x)' WRITE(*,*)' ----------------------' CALL ENXB(N,X,EN) DO 10 K=0,N WRITE(*,30)K,EN(K) 10 CONTINUE 20 FORMAT(5X,I3,', ','x=',F5.1) 30 FORMAT(2X,I3,D18.8) END SUBROUTINE ENXB(N,X,EN) C C =============================================== C Purpose: Compute exponential integral En(x) C Input : x --- Argument of En(x) C n --- Order of En(x) (n = 0,1,2,...) C Output: EN(n) --- En(x) C =============================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EN(0:N) IF (X.EQ.0.0) THEN EN(0)=1.0D+300 EN(1)=1.0D+300 DO 10 K=2,N 10 EN(K)=1.0D0/(K-1.0) RETURN ELSE IF (X.LE.1.0) THEN EN(0)=DEXP(-X)/X DO 40 L=1,N RP=1.0D0 DO 15 J=1,L-1 15 RP=-RP*X/J PS=-0.5772156649015328D0 DO 20 M=1,L-1 20 PS=PS+1.0D0/M ENS=RP*(-DLOG(X)+PS) S=0.0D0 DO 30 M=0,20 IF (M.EQ.L-1) GO TO 30 R=1.0D0 DO 25 J=1,M 25 R=-R*X/J S=S+R/(M-L+1.0D0) IF (DABS(S-S0).LT.DABS(S)*1.0D-15) GO TO 35 S0=S 30 CONTINUE 35 EN(L)=ENS-S 40 CONTINUE ELSE EN(0)=DEXP(-X)/X M=15+INT(100.0/X) DO 50 L=1,N T0=0.0D0 DO 45 K=M,1,-1 45 T0=(L+K-1.0D0)/(1.0D0+K/(X+T0)) T=1.0D0/(X+T0) 50 EN(L)=DEXP(-X)*T ENDIF END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/merror.for000077500000000000000000000034301321604176500261340ustar00rootroot00000000000000 PROGRAM MERROR C C =================================================== C Purpose: This program computes the error function C erf(x) using subroutine ERROR C Input: x --- Argument of erf(x) C Output: ERR --- erf(x) C Example: C x erf(x) C --------------------- C 1.0 .84270079 C 2.0 .99532227 C 3.0 .99997791 C 4.0 .99999998 C 5.0 1.00000000 C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x erf(x)' WRITE(*,*)'---------------------' CALL ERROR(X,ER) WRITE(*,10)X,ER 10 FORMAT(1X,F5.2,F15.8) END SUBROUTINE ERROR(X,ERR) C C ========================================= C Purpose: Compute error function erf(x) C Input: x --- Argument of erf(x) C Output: ERR --- erf(x) C ========================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) EPS=1.0D-15 PI=3.141592653589793D0 X2=X*X IF (DABS(X).LT.3.5D0) THEN ER=1.0D0 R=1.0D0 DO 10 K=1,50 R=R*X2/(K+0.5D0) ER=ER+R IF (DABS(R).LE.DABS(ER)*EPS) GO TO 15 10 CONTINUE 15 C0=2.0D0/DSQRT(PI)*X*DEXP(-X2) ERR=C0*ER ELSE ER=1.0D0 R=1.0D0 DO 20 K=1,12 R=-R*(K-0.5D0)/X2 20 ER=ER+R C0=DEXP(-X2)/(DABS(X)*DSQRT(PI)) ERR=1.0D0-C0*ER IF (X.LT.0.0) ERR=-ERR ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/meulera.for000077500000000000000000000030601321604176500262570ustar00rootroot00000000000000 PROGRAM MEULERA C C ========================================================== C Purpose: This program computes Euler number En using C subroutine EULERA C Example: Compute Euler number En for n = 0,2,...,10 C Computed results: C C n En C -------------------------- C 0 .100000000000D+01 C 2 -.100000000000D+01 C 4 .500000000000D+01 C 6 -.610000000000D+02 C 8 .138500000000D+04 C 10 -.505210000000D+05 C ========================================================== C DOUBLE PRECISION E DIMENSION E(0:200) WRITE(*,*)' Please enter Nmax ' READ(*,*)N CALL EULERA(N,E) WRITE(*,*)' n En' WRITE(*,*)' --------------------------' DO 10 K=0,N,2 10 WRITE(*,20)K,E(K) 20 FORMAT(2X,I3,D22.12) END SUBROUTINE EULERA(N,EN) C C ====================================== C Purpose: Compute Euler number En C Input : n --- Serial number C Output: EN(n) --- En C ====================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EN(0:N) EN(0)=1.0D0 DO 30 M=1,N/2 S=1.0D0 DO 20 K=1,M-1 R=1.0D0 DO 10 J=1,2*K 10 R=R*(2.0D0*M-2.0D0*K+J)/J 20 S=S+R*EN(2*K) 30 EN(2*M)=-S RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/meulerb.for000077500000000000000000000033311321604176500262610ustar00rootroot00000000000000 PROGRAM MEULERB C C ========================================================== C Purpose: This program computes Euler number En using C subroutine EULERB C Example: Compute Euler number En for n = 0,2,...,10 C Computed results: C C n En C -------------------------- C 0 .100000000000D+01 C 2 -.100000000000D+01 C 4 .500000000000D+01 C 6 -.610000000000D+02 C 8 .138500000000D+04 C 10 -.505210000000D+05 C ========================================================== C DOUBLE PRECISION E DIMENSION E(0:200) WRITE(*,*)' Please enter Nmax ' READ(*,*)N CALL EULERB(N,E) WRITE(*,*)' n En' WRITE(*,*)' --------------------------' DO 10 K=0,N,2 10 WRITE(*,20)K,E(K) 20 FORMAT(2X,I3,D22.12) END SUBROUTINE EULERB(N,EN) C C ====================================== C Purpose: Compute Euler number En C Input : n --- Serial number C Output: EN(n) --- En C ====================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EN(0:N) HPI=2.0D0/3.141592653589793D0 EN(0)=1.0D0 EN(2)=-1.0D0 R1=-4.0D0*HPI**3 DO 20 M=4,N,2 R1=-R1*(M-1)*M*HPI*HPI R2=1.0D0 ISGN=1.0D0 DO 10 K=3,1000,2 ISGN=-ISGN S=(1.0D0/K)**(M+1) R2=R2+ISGN*S IF (S.LT.1.0D-15) GOTO 20 10 CONTINUE 20 EN(M)=R1*R2 RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mfcoef.for000077500000000000000000000554001321604176500260710ustar00rootroot00000000000000 PROGRAM MFCOEF C C ========================================================= C Purpose: This program computes the expansion coefficients C for Mathieu and modified Mathieu functions using C subroutine FCOEF C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,...) C KD=2 for cem(x,q) ( m = 1,3,5,...) C KD=3 for sem(x,q) ( m = 1,3,5,...) C KD=4 for sem(x,q) ( m = 2,4,6,...) C A --- Characteristic value of Mathieu C functions for given m and q C Output: FC(k) --- Expansion coefficients of Mathieu C functions ( k= 1,2,...,KM ) C FC(1),FC(2),FC(3),... correspond to C A0,A2,A4,... for KD=1 case, A1,A3, C A5,... for KD=2 case, B1,B3,B5,... C for KD=3 case and B2,B4,B6,... for C KD=4 case C Example: Compute the first 12 expansion coefficients of C even and odd Mathieu functions for given C m = 10 And q= 5.0 C Expansion coefficients of Mathieu functions C C n Amn(q) Bmn(q) C ---------------------------------------- C 0 .16788542D-05 C 2 .33619515D-04 .33444320D-04 C 4 .64298667D-03 .64297621D-03 C 6 .10784807D-01 .10784806D-01 C 8 .13767512D+00 .13767512D+00 C 10 .98395564D+00 .98395564D+00 C 12 -.11280678D+00 -.11280678D+00 C 14 .58929627D-02 .58929627D-02 C 16 -.18916571D-03 -.18916571D-03 C 18 .42264064D-05 .42264064D-05 C 20 -.70485101D-07 -.70485101D-07 C 22 .91820256D-09 .91820256D-09 C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION FC(251),FB(251) WRITE(*,*)'Please enter m and q ' READ(*,*) M,Q WRITE(*,30)M,Q WRITE(*,*) IF (M.EQ.2*INT(M/2)) THEN KI=1 KF=4 KS=3 ELSE IF (M.NE.2*INT(M/2)) THEN KI=2 KF=3 KS=1 ENDIF DO 20 KD=KI,KF,KS CALL CVA2(KD,M,Q,A) CALL FCOEF(KD,M,Q,A,FC) IF (KD.EQ.KI) THEN DO 10 L=1,M/2+8 FB(L)=FC(L) 10 CONTINUE ENDIF 20 CONTINUE WRITE(*,40) WRITE(*,*) WRITE(*,45) WRITE(*,*)'----------------------------------------' DO 25 L=1,M/2+8 IF (M.EQ.2*INT(M/2)) THEN IF (M.EQ.0) WRITE(*,35)2*L-2,FB(L) IF (M.GT.0.AND.L.EQ.1) WRITE(*,35)2*L-2,FB(L) IF (M.GT.0.AND.L.NE.1) WRITE(*,35)2*L-2,FB(L),FC(L-1) ELSE WRITE(*,35)2*L-1,FB(L),FC(L) ENDIF 25 CONTINUE 30 FORMAT(1X,2Hm=,I3,', ',2Hq=,F6.2) 35 FORMAT(1X,I3,2D18.8) 40 FORMAT(1X,'Expansion coefficients of Mathieu functions') 45 FORMAT(1X,' n Amn(q) ',' Bmn(q)') END SUBROUTINE FCOEF(KD,M,Q,A,FC) C C ===================================================== C Purpose: Compute expansion coefficients for Mathieu C functions and modified Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,...) C KD=2 for cem(x,q) ( m = 1,3,5,...) C KD=3 for sem(x,q) ( m = 1,3,5,...) C KD=4 for sem(x,q) ( m = 2,4,6,...) C A --- Characteristic value of Mathieu C functions for given m and q C Output: FC(k) --- Expansion coefficients of Mathieu C functions ( k= 1,2,...,KM ) C FC(1),FC(2),FC(3),... correspond to C A0,A2,A4,... for KD=1 case, A1,A3, C A5,... for KD=2 case, B1,B3,B5,... C for KD=3 case and B2,B4,B6,... for C KD=4 case C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION FC(251) IF (Q.LE.1.0D0) THEN QM=7.5+56.1*SQRT(Q)-134.7*Q+90.7*SQRT(Q)*Q ELSE QM=17.0+3.1*SQRT(Q)-.126*Q+.0037*SQRT(Q)*Q ENDIF KM=INT(QM+0.5*M) IF (Q.EQ.0.0D0) THEN DO 10 K=1,KM 10 FC(K)=0.0D0 IF (KD.EQ.1) THEN FC((M+2)/2)=1.0D0 IF (M.EQ.0) FC(1)=1.0D0/DSQRT(2.0D0) ELSE IF (KD.EQ.4) THEN FC(M/2)=1.0D0 ELSE FC((M+1)/2)=1.0D0 ENDIF RETURN ENDIF KB=0 S=0.0D0 F=1.0D-100 U=0.0D0 FC(KM)=0.0D0 IF (KD.EQ.1) THEN DO 25 K=KM,3,-1 V=U U=F F=(A-4.0D0*K*K)*U/Q-V IF (DABS(F).LT.DABS(FC(K+1))) THEN KB=K FC(1)=1.0D-100 SP=0.0D0 F3=FC(K+1) FC(2)=A/Q*FC(1) FC(3)=(A-4.0D0)*FC(2)/Q-2.0D0*FC(1) U=FC(2) F1=FC(3) DO 15 I=3,KB V=U U=F1 F1=(A-4.0D0*(I-1.0D0)**2)*U/Q-V FC(I+1)=F1 IF (I.EQ.KB) F2=F1 IF (I.NE.KB) SP=SP+F1*F1 15 CONTINUE SP=SP+2.0D0*FC(1)**2+FC(2)**2+FC(3)**2 SS=S+SP*(F3/F2)**2 S0=DSQRT(1.0D0/SS) DO 20 J=1,KM IF (J.LE.KB+1) THEN FC(J)=S0*FC(J)*F3/F2 ELSE FC(J)=S0*FC(J) ENDIF 20 CONTINUE GO TO 85 ELSE FC(K)=F S=S+F*F ENDIF 25 CONTINUE FC(2)=Q*FC(3)/(A-4.0D0-2.0D0*Q*Q/A) FC(1)=Q/A*FC(2) S=S+2.0D0*FC(1)**2+FC(2)**2 S0=DSQRT(1.0D0/S) DO 30 K=1,KM 30 FC(K)=S0*FC(K) ELSE IF (KD.EQ.2.OR.KD.EQ.3) THEN DO 35 K=KM,3,-1 V=U U=F F=(A-(2.0D0*K-1)**2)*U/Q-V IF (DABS(F).GE.DABS(FC(K))) THEN FC(K-1)=F S=S+F*F ELSE KB=K F3=FC(K) GO TO 45 ENDIF 35 CONTINUE FC(1)=Q/(A-1.0D0-(-1)**KD*Q)*FC(2) S=S+FC(1)*FC(1) S0=DSQRT(1.0D0/S) DO 40 K=1,KM 40 FC(K)=S0*FC(K) GO TO 85 45 FC(1)=1.0D-100 FC(2)=(A-1.0D0-(-1)**KD*Q)/Q*FC(1) SP=0.0D0 U=FC(1) F1=FC(2) DO 50 I=2,KB-1 V=U U=F1 F1=(A-(2.0D0*I-1.0D0)**2)*U/Q-V IF (I.NE.KB-1) THEN FC(I+1)=F1 SP=SP+F1*F1 ELSE F2=F1 ENDIF 50 CONTINUE SP=SP+FC(1)**2+FC(2)**2 SS=S+SP*(F3/F2)**2 S0=1.0D0/DSQRT(SS) DO 55 J=1,KM IF (J.LT.KB) FC(J)=S0*FC(J)*F3/F2 IF (J.GE.KB) FC(J)=S0*FC(J) 55 CONTINUE ELSE IF (KD.EQ.4) THEN DO 60 K=KM,3,-1 V=U U=F F=(A-4.0D0*K*K)*U/Q-V IF (DABS(F).GE.DABS(FC(K))) THEN FC(K-1)=F S=S+F*F ELSE KB=K F3=FC(K) GO TO 70 ENDIF 60 CONTINUE FC(1)=Q/(A-4.0D0)*FC(2) S=S+FC(1)*FC(1) S0=DSQRT(1.0D0/S) DO 65 K=1,KM 65 FC(K)=S0*FC(K) GO TO 85 70 FC(1)=1.0D-100 FC(2)=(A-4.0D0)/Q*FC(1) SP=0.0D0 U=FC(1) F1=FC(2) DO 75 I=2,KB-1 V=U U=F1 F1=(A-4.0D0*I*I)*U/Q-V IF (I.NE.KB-1) THEN FC(I+1)=F1 SP=SP+F1*F1 ELSE F2=F1 ENDIF 75 CONTINUE SP=SP+FC(1)**2+FC(2)**2 SS=S+SP*(F3/F2)**2 S0=1.0D0/DSQRT(SS) DO 80 J=1,KM IF (J.LT.KB) FC(J)=S0*FC(J)*F3/F2 IF (J.GE.KB) FC(J)=S0*FC(J) 80 CONTINUE ENDIF 85 IF (FC(1).LT.0.0D0) THEN DO 90 J=1,KM 90 FC(J)=-FC(J) ENDIF RETURN END SUBROUTINE CVA2(KD,M,Q,A) C C ====================================================== C Purpose: Calculate a specific characteristic value of C Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,...) C KD=2 for cem(x,q) ( m = 1,3,5,...) C KD=3 for sem(x,q) ( m = 1,3,5,...) C KD=4 for sem(x,q) ( m = 2,4,6,...) C Output: A --- Characteristic value C Routines called: C (1) REFINE for finding accurate characteristic C values using an iteration method C (2) CV0 for finding initial characteristic C values using polynomial approximation C (3) CVQM for computing initial characteristic C values for q ó 3*m C (3) CVQL for computing initial characteristic C values for q ò m*m C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (M.LE.12.OR.Q.LE.3.0*M.OR.Q.GT.M*M) THEN CALL CV0(KD,M,Q,A) IF (Q.NE.0.0D0) CALL REFINE(KD,M,Q,A,1) ELSE NDIV=10 DELTA=(M-3.0)*M/NDIV IF ((Q-3.0*M).LE.(M*M-Q)) THEN 5 NN=INT((Q-3.0*M)/DELTA)+1 DELTA=(Q-3.0*M)/NN Q1=2.0*M CALL CVQM(M,Q1,A1) Q2=3.0*M CALL CVQM(M,Q2,A2) QQ=3.0*M DO 10 I=1,NN QQ=QQ+DELTA A=(A1*Q2-A2*Q1+(A2-A1)*QQ)/(Q2-Q1) IFLAG=1 IF (I.EQ.NN) IFLAG=-1 CALL REFINE(KD,M,QQ,A,IFLAG) Q1=Q2 Q2=QQ A1=A2 A2=A 10 CONTINUE IF (IFLAG.EQ.-10) THEN NDIV=NDIV*2 DELTA=(M-3.0)*M/NDIV GO TO 5 ENDIF ELSE 15 NN=INT((M*M-Q)/DELTA)+1 DELTA=(M*M-Q)/NN Q1=M*(M-1.0) CALL CVQL(KD,M,Q1,A1) Q2=M*M CALL CVQL(KD,M,Q2,A2) QQ=M*M DO 20 I=1,NN QQ=QQ-DELTA A=(A1*Q2-A2*Q1+(A2-A1)*QQ)/(Q2-Q1) IFLAG=1 IF (I.EQ.NN) IFLAG=-1 CALL REFINE(KD,M,QQ,A,IFLAG) Q1=Q2 Q2=QQ A1=A2 A2=A 20 CONTINUE IF (IFLAG.EQ.-10) THEN NDIV=NDIV*2 DELTA=(M-3.0)*M/NDIV GO TO 15 ENDIF ENDIF ENDIF RETURN END SUBROUTINE REFINE(KD,M,Q,A,IFLAG) C C ===================================================== C Purpose: calculate the accurate characteristic value C by the secant method C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C A --- Initial characteristic value C Output: A --- Refineed characteristic value C Routine called: CVF for computing the value of F for C characteristic equation C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) EPS=1.0D-14 MJ=10+M CA=A DELTA=0.0D0 X0=A CALL CVF(KD,M,Q,X0,MJ,F0) X1=1.002*A CALL CVF(KD,M,Q,X1,MJ,F1) 5 DO 10 IT=1,100 MJ=MJ+1 X=X1-(X1-X0)/(1.0D0-F0/F1) CALL CVF(KD,M,Q,X,MJ,F) IF (ABS(1.0-X1/X).LT.EPS.OR.F.EQ.0.0) GO TO 15 X0=X1 F0=F1 X1=X 10 F1=F 15 A=X IF (DELTA.GT.0.05) THEN A=CA IF (IFLAG.LT.0) THEN IFLAG=-10 ENDIF RETURN ENDIF IF (ABS((A-CA)/CA).GT.0.05) THEN X0=CA DELTA=DELTA+0.005D0 CALL CVF(KD,M,Q,X0,MJ,F0) X1=(1.0D0+DELTA)*CA CALL CVF(KD,M,Q,X1,MJ,F1) GO TO 5 ENDIF RETURN END SUBROUTINE CVF(KD,M,Q,A,MJ,F) C C ====================================================== C Purpose: Compute the value of F for characteristic C equation of Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C A --- Characteristic value C Output: F --- Value of F for characteristic equation C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) B=A IC=INT(M/2) L=0 L0=0 J0=2 JF=IC IF (KD.EQ.1) L0=2 IF (KD.EQ.1) J0=3 IF (KD.EQ.2.OR.KD.EQ.3) L=1 IF (KD.EQ.4) JF=IC-1 T1=0.0D0 DO 10 J=MJ,IC+1,-1 10 T1=-Q*Q/((2.0D0*J+L)**2-B+T1) IF (M.LE.2) THEN T2=0.0D0 IF (KD.EQ.1.AND.M.EQ.0) T1=T1+T1 IF (KD.EQ.1.AND.M.EQ.2) T1=-2.0*Q*Q/(4.0-B+T1)-4.0 IF (KD.EQ.2.AND.M.EQ.1) T1=T1+Q IF (KD.EQ.3.AND.M.EQ.1) T1=T1-Q ELSE IF (KD.EQ.1) T0=4.0D0-B+2.0D0*Q*Q/B IF (KD.EQ.2) T0=1.0D0-B+Q IF (KD.EQ.3) T0=1.0D0-B-Q IF (KD.EQ.4) T0=4.0D0-B T2=-Q*Q/T0 DO 15 J=J0,JF 15 T2=-Q*Q/((2.0D0*J-L-L0)**2-B+T2) ENDIF F=(2.0D0*IC+L)**2+T1+T2-B RETURN END SUBROUTINE CV0(KD,M,Q,A0) C C ===================================================== C Purpose: Compute the initial characteristic value of C Mathieu functions for m ó 12 or q ó 300 or C q ò m*m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Characteristic value C Routines called: C (1) CVQM for computing initial characteristic C value for q ó 3*m C (2) CVQL for computing initial characteristic C value for q ò m*m C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) Q2=Q*Q IF (M.EQ.0) THEN IF (Q.LE.1.0) THEN A0=(((.0036392*Q2-.0125868)*Q2+.0546875)*Q2-.5)*Q2 ELSE IF (Q.LE.10.0) THEN A0=((3.999267D-3*Q-9.638957D-2)*Q-.88297)*Q & +.5542818 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.1) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=(((-6.51E-4*Q-.015625)*Q-.125)*Q+1.0)*Q+1.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=(((-6.51E-4*Q+.015625)*Q-.125)*Q-1.0)*Q+1.0 ELSE IF (Q.LE.10.0.AND. KD.EQ.2) THEN A0=(((-4.94603D-4*Q+1.92917D-2)*Q-.3089229) & *Q+1.33372)*Q+.811752 ELSE IF (Q.LE.10.0.AND.KD.EQ.3) THEN A0=((1.971096D-3*Q-5.482465D-2)*Q-1.152218) & *Q+1.10427 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.2) THEN IF (Q.LE.1.0.AND.KD.EQ.1) THEN A0=(((-.0036391*Q2+.0125888)*Q2-.0551939)*Q2 & +.416667)*Q2+4.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.4) THEN A0=(.0003617*Q2-.0833333)*Q2+4.0 ELSE IF (Q.LE.15.AND.KD.EQ.1) THEN A0=(((3.200972D-4*Q-8.667445D-3)*Q & -1.829032D-4)*Q+.9919999)*Q+3.3290504 ELSE IF (Q.LE.10.0.AND.KD.EQ.4) THEN A0=((2.38446D-3*Q-.08725329)*Q-4.732542D-3) & *Q+4.00909 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.3) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=((6.348E-4*Q+.015625)*Q+.0625)*Q2+9.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=((6.348E-4*Q-.015625)*Q+.0625)*Q2+9.0 ELSE IF (Q.LE.20.0.AND.KD.EQ.2) THEN A0=(((3.035731D-4*Q-1.453021D-2)*Q & +.19069602)*Q-.1039356)*Q+8.9449274 ELSE IF (Q.LE.15.0.AND.KD.EQ.3) THEN A0=((9.369364D-5*Q-.03569325)*Q+.2689874)*Q & +8.771735 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.4) THEN IF (Q.LE.1.0.AND.KD.EQ.1) THEN A0=((-2.1E-6*Q2+5.012E-4)*Q2+.0333333)*Q2+16.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.4) THEN A0=((3.7E-6*Q2-3.669E-4)*Q2+.0333333)*Q2+16.0 ELSE IF (Q.LE.25.0.AND.KD.EQ.1) THEN A0=(((1.076676D-4*Q-7.9684875D-3)*Q & +.17344854)*Q-.5924058)*Q+16.620847 ELSE IF (Q.LE.20.0.AND.KD.EQ.4) THEN A0=((-7.08719D-4*Q+3.8216144D-3)*Q & +.1907493)*Q+15.744 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.5) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=((6.8E-6*Q+1.42E-5)*Q2+.0208333)*Q2+25.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=((-6.8E-6*Q+1.42E-5)*Q2+.0208333)*Q2+25.0 ELSE IF (Q.LE.35.0.AND.KD.EQ.2) THEN A0=(((2.238231D-5*Q-2.983416D-3)*Q & +.10706975)*Q-.600205)*Q+25.93515 ELSE IF (Q.LE.25.0.AND.KD.EQ.3) THEN A0=((-7.425364D-4*Q+2.18225D-2)*Q & +4.16399D-2)*Q+24.897 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.6) THEN IF (Q.LE.1.0) THEN A0=(.4D-6*Q2+.0142857)*Q2+36.0 ELSE IF (Q.LE.40.0.AND.KD.EQ.1) THEN A0=(((-1.66846D-5*Q+4.80263D-4)*Q & +2.53998D-2)*Q-.181233)*Q+36.423 ELSE IF (Q.LE.35.0.AND.KD.EQ.4) THEN A0=((-4.57146D-4*Q+2.16609D-2)*Q-2.349616D-2)*Q & +35.99251 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.7) THEN IF (Q.LE.10.0) THEN CALL CVQM(M,Q,A0) ELSE IF (Q.LE.50.0.AND.KD.EQ.2) THEN A0=(((-1.411114D-5*Q+9.730514D-4)*Q & -3.097887D-3)*Q+3.533597D-2)*Q+49.0547 ELSE IF (Q.LE.40.0.AND.KD.EQ.3) THEN A0=((-3.043872D-4*Q+2.05511D-2)*Q & -9.16292D-2)*Q+49.19035 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.GE.8) THEN IF (Q.LE.3.*M) THEN CALL CVQM(M,Q,A0) ELSE IF (Q.GT.M*M) THEN CALL CVQL(KD,M,Q,A0) ELSE IF (M.EQ.8.AND.KD.EQ.1) THEN A0=(((8.634308D-6*Q-2.100289D-3)*Q+.169072)*Q & -4.64336)*Q+109.4211 ELSE IF (M.EQ.8.AND.KD.EQ.4) THEN A0=((-6.7842D-5*Q+2.2057D-3)*Q+.48296)*Q+56.59 ELSE IF (M.EQ.9.AND.KD.EQ.2) THEN A0=(((2.906435D-6*Q-1.019893D-3)*Q+.1101965)*Q & -3.821851)*Q+127.6098 ELSE IF (M.EQ.9.AND.KD.EQ.3) THEN A0=((-9.577289D-5*Q+.01043839)*Q+.06588934)*Q & +78.0198 ELSE IF (M.EQ.10.AND.KD.EQ.1) THEN A0=(((5.44927D-7*Q-3.926119D-4)*Q+.0612099)*Q & -2.600805)*Q+138.1923 ELSE IF (M.EQ.10.AND.KD.EQ.4) THEN A0=((-7.660143D-5*Q+.01132506)*Q-.09746023)*Q & +99.29494 ELSE IF (M.EQ.11.AND.KD.EQ.2) THEN A0=(((-5.67615D-7*Q+7.152722D-6)*Q+.01920291)*Q & -1.081583)*Q+140.88 ELSE IF (M.EQ.11.AND.KD.EQ.3) THEN A0=((-6.310551D-5*Q+.0119247)*Q-.2681195)*Q & +123.667 ELSE IF (M.EQ.12.AND.KD.EQ.1) THEN A0=(((-2.38351D-7*Q-2.90139D-5)*Q+.02023088)*Q & -1.289)*Q+171.2723 ELSE IF (M.EQ.12.AND.KD.EQ.4) THEN A0=(((3.08902D-7*Q-1.577869D-4)*Q+.0247911)*Q & -1.05454)*Q+161.471 ENDIF ENDIF ENDIF RETURN END SUBROUTINE CVQL(KD,M,Q,A0) C C ======================================================== C Purpose: Compute the characteristic value of Mathieu C functions for q ò 3m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Initial characteristic value C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (KD.EQ.1.OR.KD.EQ.2) W=2.0D0*M+1.0D0 IF (KD.EQ.3.OR.KD.EQ.4) W=2.0D0*M-1.0D0 W2=W*W W3=W*W2 W4=W2*W2 W6=W2*W4 D1=5.0+34.0/W2+9.0/W4 D2=(33.0+410.0/W2+405.0/W4)/W D3=(63.0+1260.0/W2+2943.0/W4+486.0/W6)/W2 D4=(527.0+15617.0/W2+69001.0/W4+41607.0/W6)/W3 C1=128.0 P2=Q/W4 P1=DSQRT(P2) CV1=-2.0*Q+2.0*W*DSQRT(Q)-(W2+1.0)/8.0 CV2=(W+3.0/W)+D1/(32.0*P1)+D2/(8.0*C1*P2) CV2=CV2+D3/(64.0*C1*P1*P2)+D4/(16.0*C1*C1*P2*P2) A0=CV1-CV2/(C1*P1) RETURN END SUBROUTINE CVQM(M,Q,A0) C C ===================================================== C Purpose: Compute the characteristic value of Mathieu C functions for q ó m*m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Initial characteristic value C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) HM1=.5*Q/(M*M-1.0) HM3=.25*HM1**3/(M*M-4.0) HM5=HM1*HM3*Q/((M*M-1.0)*(M*M-9.0)) A0=M*M+Q*(HM1+(5.0*M*M+7.0)*HM3 & +(9.0*M**4+58.0*M*M+29.0)*HM5) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mfcs.for000077500000000000000000000062301321604176500255570ustar00rootroot00000000000000 PROGRAM MFCS C C ======================================================= C Purpose: This program computes the Fresnel integrals C C(x) and S(x) using subroutine FCS C Input : x --- Argument of C(x) and S(x) C Output: C --- C(x) C S --- S(x) C Example: C x C(x) S(x) C ----------------------------------- C 0.0 .00000000 .00000000 C 0.5 .49234423 .06473243 C 1.0 .77989340 .43825915 C 1.5 .44526118 .69750496 C 2.0 .48825341 .34341568 C 2.5 .45741301 .61918176 C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*) X WRITE(*,*)' x C(x) S(x)' WRITE(*,*)' -----------------------------------' CALL FCS(X,C,S) WRITE(*,10)X,C,S 10 FORMAT(1X,F5.1,2F15.8) END SUBROUTINE FCS(X,C,S) C C ================================================= C Purpose: Compute Fresnel integrals C(x) and S(x) C Input : x --- Argument of C(x) and S(x) C Output: C --- C(x) C S --- S(x) C ================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) EPS=1.0D-15 PI=3.141592653589793D0 XA=DABS(X) PX=PI*XA T=.5D0*PX*XA T2=T*T IF (XA.EQ.0.0) THEN C=0.0D0 S=0.0D0 ELSE IF (XA.LT.2.5D0) THEN R=XA C=R DO 10 K=1,50 R=-.5D0*R*(4.0D0*K-3.0D0)/K/(2.0D0*K-1.0D0) & /(4.0D0*K+1.0D0)*T2 C=C+R IF (DABS(R).LT.DABS(C)*EPS) GO TO 15 10 CONTINUE 15 S=XA*T/3.0D0 R=S DO 20 K=1,50 R=-.5D0*R*(4.0D0*K-1.0D0)/K/(2.0D0*K+1.0D0) & /(4.0D0*K+3.0D0)*T2 S=S+R IF (DABS(R).LT.DABS(S)*EPS) GO TO 40 20 CONTINUE ELSE IF (XA.LT.4.5D0) THEN M=INT(42.0+1.75*T) SU=0.0D0 C=0.0D0 S=0.0D0 F1=0.0D0 F0=1.0D-100 DO 25 K=M,0,-1 F=(2.0D0*K+3.0D0)*F0/T-F1 IF (K.EQ.INT(K/2)*2) THEN C=C+F ELSE S=S+F ENDIF SU=SU+(2.0D0*K+1.0D0)*F*F F1=F0 25 F0=F Q=DSQRT(SU) C=C*XA/Q S=S*XA/Q ELSE R=1.0D0 F=1.0D0 DO 30 K=1,20 R=-.25D0*R*(4.0D0*K-1.0D0)*(4.0D0*K-3.0D0)/T2 30 F=F+R R=1.0D0/(PX*XA) G=R DO 35 K=1,12 R=-.25D0*R*(4.0D0*K+1.0D0)*(4.0D0*K-1.0D0)/T2 35 G=G+R T0=T-INT(T/(2.0D0*PI))*2.0D0*PI C=.5D0+(F*DSIN(T0)-G*DCOS(T0))/PX S=.5D0-(F*DCOS(T0)+G*DSIN(T0))/PX ENDIF 40 IF (X.LT.0.0D0) THEN C=-C S=-S ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mfcszo.for000077500000000000000000000161341321604176500261340ustar00rootroot00000000000000 PROGRAM MFCSZO C C =========================================================== C Purpose : This program computes the complex zeros of the C Fresnel integral C(z) or S(z) using subroutine C FCSZO C Input : KF --- Function code C KF=1 for C(z) or KF=2 for S(z) C NT --- Total number of zeros C Output: ZO(L) --- L-th zero of C(z) or S(z) C Example: NT=10 C C n Complex zeros of C(z) Complex zeros of S(z) C ------------------------------------------------------------ C 1 1.7436675 + i .30573506 2.0092570 + i .28854790 C 2 2.6514596 + i .25290396 2.8334772 + i .24428524 C 3 3.3203593 + i .22395346 3.4675331 + i .21849268 C 4 3.8757345 + i .20474747 4.0025782 + i .20085103 C 5 4.3610635 + i .19066973 4.4741893 + i .18768859 C 6 4.7976077 + i .17970801 4.9006784 + i .17732036 C 7 5.1976532 + i .17081930 5.2929467 + i .16884418 C 8 5.5690602 + i .16339854 5.6581068 + i .16172492 C 9 5.9172173 + i .15706585 6.0011034 + i .15562108 C 10 6.2460098 + i .15156826 6.3255396 + i .15030246 C =========================================================== C IMPLICIT DOUBLE PRECISION (E,P,W) IMPLICIT COMPLEX *16 (C,Z) DIMENSION ZO(100) WRITE(*,*)'Please Enter KF and NT ' READ(*,*)KF,NT WRITE(*,20)KF,NT WRITE(*,*)' ***** Please Wait ! *****' CALL FCSZO(KF,NT,ZO) WRITE(*,*) IF (KF.EQ.1) WRITE(*,*)' n Complex zeros of C(z)' IF (KF.EQ.2) WRITE(*,*)' n Complex zeros of S(z)' WRITE(*,*)'-----------------------------------' DO 10 I=1,NT 10 WRITE(*,30) I,ZO(I) 20 FORMAT(2X,'KF=',I2,', ','NT=',I3) 30 FORMAT(1X,I3,F13.8,2X,2H+i,F13.8) END SUBROUTINE FCSZO(KF,NT,ZO) C C =============================================================== C Purpose: Compute the complex zeros of Fresnel integral C(z) C or S(z) using modified Newton's iteration method C Input : KF --- Function code C KF=1 for C(z) or KF=2 for S(z) C NT --- Total number of zeros C Output: ZO(L) --- L-th zero of C(z) or S(z) C Routines called: C (1) CFC for computing Fresnel integral C(z) C (2) CFS for computing Fresnel integral S(z) C ============================================================== C IMPLICIT DOUBLE PRECISION (E,P,W) IMPLICIT COMPLEX *16 (C,Z) DIMENSION ZO(NT) PI=3.141592653589793D0 DO 35 NR=1,NT IF (KF.EQ.1) PSQ=DSQRT(4.0D0*NR-1.0D0) IF (KF.EQ.2) PSQ=2.0D0*NR**(0.5) PX=PSQ-DLOG(PI*PSQ)/(PI*PI*PSQ**3.0) PY=DLOG(PI*PSQ)/(PI*PSQ) Z=CMPLX(PX,PY) IF (KF.EQ.2) THEN IF (NR.EQ.2) Z=(2.8334,0.2443) IF (NR.EQ.3) Z=(3.4674,0.2185) IF (NR.EQ.4) Z=(4.0025,0.2008) ENDIF IT=0 15 IT=IT+1 IF (KF.EQ.1) CALL CFC(Z,ZF,ZD) IF (KF.EQ.2) CALL CFS(Z,ZF,ZD) ZP=(1.0D0,0.0D0) DO 20 I=1,NR-1 20 ZP=ZP*(Z-ZO(I)) ZFD=ZF/ZP ZQ=(0.0D0,0.0D0) DO 30 I=1,NR-1 ZW=(1.0D0,0.0D0) DO 25 J=1,NR-1 IF (J.EQ.I) GO TO 25 ZW=ZW*(Z-ZO(J)) 25 CONTINUE 30 ZQ=ZQ+ZW ZGD=(ZD-ZQ*ZFD)/ZP Z=Z-ZFD/ZGD W0=W W=CDABS(Z) IF (IT.LE.50.AND.DABS((W-W0)/W).GT.1.0D-12) GO TO 15 35 ZO(NR)=Z RETURN END SUBROUTINE CFC(Z,ZF,ZD) C C ========================================================= C Purpose: Compute complex Fresnel integral C(z) and C'(z) C Input : z --- Argument of C(z) C Output: ZF --- C(z) C ZD --- C'(z) C ========================================================= C IMPLICIT DOUBLE PRECISION (E,P,W) IMPLICIT COMPLEX *16 (C,S,Z) EPS=1.0D-14 PI=3.141592653589793D0 W0=CDABS(Z) ZP=0.5D0*PI*Z*Z ZP2=ZP*ZP Z0=(0.0D0,0.0D0) IF (Z.EQ.Z0) THEN C=Z0 ELSE IF (W0.LE.2.5) THEN CR=Z C=CR DO 10 K=1,80 CR=-.5D0*CR*(4.0D0*K-3.0D0)/K/(2.0D0*K-1.0D0) & /(4.0D0*K+1.0D0)*ZP2 C=C+CR WA=CDABS(C) IF (DABS((WA-WA0)/WA).LT.EPS.AND.K.GT.10) GO TO 30 10 WA0=WA ELSE IF (W0.GT.2.5.AND.W0.LT.4.5) THEN M=85 C=Z0 CF1=Z0 CF0=(1.0D-100,0.0D0) DO 15 K=M,0,-1 CF=(2.0D0*K+3.0D0)*CF0/ZP-CF1 IF (K.EQ.INT(K/2)*2) C=C+CF CF1=CF0 15 CF0=CF C=CDSQRT(2.0D0/(PI*ZP))*CDSIN(ZP)/CF*C ELSE CR=(1.0D0,0.0D0) CF=(1.0D0,0.0D0) DO 20 K=1,20 CR=-.25D0*CR*(4.0D0*K-1.0D0)*(4.0D0*K-3.0D0)/ZP2 20 CF=CF+CR CR=1.0D0/(PI*Z*Z) CG=CR DO 25 K=1,12 CR=-.25D0*CR*(4.0D0*K+1.0D0)*(4.0D0*K-1.0D0)/ZP2 25 CG=CG+CR C=.5D0+(CF*CDSIN(ZP)-CG*CDCOS(ZP))/(PI*Z) ENDIF 30 ZF=C ZD=CDCOS(0.5*PI*Z*Z) RETURN END SUBROUTINE CFS(Z,ZF,ZD) C C ========================================================= C Purpose: Compute complex Fresnel Integral S(z) and S'(z) C Input : z --- Argument of S(z) C Output: ZF --- S(z) C ZD --- S'(z) C ========================================================= C IMPLICIT DOUBLE PRECISION (E,P,W) IMPLICIT COMPLEX *16 (C,S,Z) EPS=1.0D-14 PI=3.141592653589793D0 W0=CDABS(Z) ZP=0.5D0*PI*Z*Z ZP2=ZP*ZP Z0=(0.0D0,0.0D0) IF (Z.EQ.Z0) THEN S=Z0 ELSE IF (W0.LE.2.5) THEN S=Z*ZP/3.0D0 CR=S DO 10 K=1,80 CR=-.5D0*CR*(4.0D0*K-1.0D0)/K/(2.0D0*K+1.0D0) & /(4.0D0*K+3.0D0)*ZP2 S=S+CR WB=CDABS(S) IF (DABS(WB-WB0).LT.EPS.AND.K.GT.10) GO TO 30 10 WB0=WB ELSE IF (W0.GT.2.5.AND.W0.LT.4.5) THEN M=85 S=Z0 CF1=Z0 CF0=(1.0D-100,0.0D0) DO 15 K=M,0,-1 CF=(2.0D0*K+3.0D0)*CF0/ZP-CF1 IF (K.NE.INT(K/2)*2) S=S+CF CF1=CF0 15 CF0=CF S=CDSQRT(2.0D0/(PI*ZP))*CDSIN(ZP)/CF*S ELSE CR=(1.0D0,0.0D0) CF=(1.0D0,0.0D0) DO 20 K=1,20 CR=-.25D0*CR*(4.0D0*K-1.0D0)*(4.0D0*K-3.0D0)/ZP2 20 CF=CF+CR CR=1.0D0/(PI*Z*Z) CG=CR DO 25 K=1,12 CR=-.25D0*CR*(4.0D0*K+1.0D0)*(4.0D0*K-1.0D0)/ZP2 25 CG=CG+CR S=.5D0-(CF*CDCOS(ZP)+CG*CDSIN(ZP))/(PI*Z) ENDIF 30 ZF=S ZD=CDSIN(0.5*PI*Z*Z) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mffk.for000077500000000000000000000150631321604176500255560ustar00rootroot00000000000000 PROGRAM MFFK C C ============================================================== C Purpose: This program computes the modified Fresnel integrals C Fñ(x) and Kñ(x) using subroutine FFK C Input : x --- Argument of Fñ(x) and Kñ(x) C KS --- Sign code C KS=0 for calculating F+(x) and K+(x) C KS=1 for calculating F_(x) and K_(x) C Output: FR --- Re[Fñ(x)] C FI --- Im[Fñ(x)] C FM --- |Fñ(x)| C FA --- Arg[Fñ(x)] (Degs.) C GR --- Re[Kñ(x)] C GI --- Im[Kñ(x)] C GM --- |Kñ(x)| C GA --- Arg[Kñ(x)] (Degs.) C Example: C C x Re[Fñ(x)] ñIm[Fñ(x)] Mod[Fñ(x)] ñArg[Fñ(x)] C ---------------------------------------------------------- C 0.0 .62665707 .62665707 .88622693 45.000000 C 2.0 .16519561 -.17811942 .24293233 -47.155835 C 4.0 .03219674 -.12047678 .12470479 -75.037684 C 6.0 .08245304 -.01180212 .08329342 -8.145843 C 8.0 -.05729996 .02493542 .06249048 156.482601 C 10.0 .02553188 .04298617 .04999688 59.291561 C C x Re[Kñ(x)] ñIm[Kñ(x)] Mod[Kñ(x)] ñArg[Kñ(x)] C ---------------------------------------------------------- C 0.0 .50000000 .00000000 .50000000 0.000000 C 2.0 .10702394 .08562295 .13705989 38.661047 C 4.0 .05126306 .04818949 .07035714 43.229843 C 6.0 .03368650 .03276566 .04699328 44.206095 C 8.0 .02512396 .02473472 .03525648 44.552712 C 10.0 .02004532 .01984592 .02820772 44.713609 C =============================================================== C IMPLICIT DOUBLE PRECISION (F,G,X) WRITE(*,*)'Please enter x' READ(*,*) X WRITE(*,*) WRITE(*,*)' x Re[Fñ(x)] ñIm[Fñ(x)] ', & 'Mod[Fñ(x)] ñArg[Fñ(x)]' WRITE(*,*)' ---------------------------------------', & '-----------------------' CALL FFK(0,X,FR,FI,FM,FA,GR,GI,GM,GA) WRITE(*,10)X,FR,FI,FM,FA WRITE(*,*) WRITE(*,*)' x Re[Kñ(x)] ñIm[Kñ(x)] ', & 'Mod[Kñ(x)] ñArg[Kñ(x)]' WRITE(*,*)' ---------------------------------------', & '-----------------------' WRITE(*,10)X,GR,GI,GM,GA 10 FORMAT(1X,F5.1,3F14.8,F14.6) END SUBROUTINE FFK(KS,X,FR,FI,FM,FA,GR,GI,GM,GA) C C ======================================================= C Purpose: Compute modified Fresnel integrals Fñ(x) C and Kñ(x) C Input : x --- Argument of Fñ(x) and Kñ(x) C KS --- Sign code C KS=0 for calculating F+(x) and K+(x) C KS=1 for calculating F_(x) and K_(x) C Output: FR --- Re[Fñ(x)] C FI --- Im[Fñ(x)] C FM --- |Fñ(x)| C FA --- Arg[Fñ(x)] (Degs.) C GR --- Re[Kñ(x)] C GI --- Im[Kñ(x)] C GM --- |Kñ(x)| C GA --- Arg[Kñ(x)] (Degs.) C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) SRD= 57.29577951308233D0 EPS=1.0D-15 PI=3.141592653589793D0 PP2=1.2533141373155D0 P2P=.7978845608028654D0 XA=DABS(X) X2=X*X X4=X2*X2 IF (X.EQ.0.0D0) THEN FR=.5D0*DSQRT(0.5D0*PI) FI=(-1)**KS*FR FM=DSQRT(0.25D0*PI) FA=(-1)**KS*45.0D0 GR=.5D0 GI=0.0D0 GM=.5D0 GA=0.0D0 ELSE IF (XA.LE.2.5D0) THEN XR=P2P*XA C1=XR DO 10 K=1,50 XR=-.5D0*XR*(4.0D0*K-3.0D0)/K/(2.0D0*K-1.0D0) & /(4.0D0*K+1.0D0)*X4 C1=C1+XR IF (DABS(XR/C1).LT.EPS) GO TO 15 10 CONTINUE 15 S1=P2P*XA*XA*XA/3.0D0 XR=S1 DO 20 K=1,50 XR=-.5D0*XR*(4.0D0*K-1.0D0)/K/(2.0D0*K+1.0D0) & /(4.0D0*K+3.0D0)*X4 S1=S1+XR IF (DABS(XR/S1).LT.EPS) GO TO 40 20 CONTINUE ELSE IF (XA.LT.5.5D0) THEN M=INT(42+1.75*X2) XSU=0.0D0 XC=0.0D0 XS=0.0D0 XF1=0.0D0 XF0=1D-100 DO 25 K=M,0,-1 XF=(2.0D0*K+3.0D0)*XF0/X2-XF1 IF (K.EQ.2*INT(K/2)) THEN XC=XC+XF ELSE XS=XS+XF ENDIF XSU=XSU+(2.0D0*K+1.0D0)*XF*XF XF1=XF0 25 XF0=XF XQ=DSQRT(XSU) XW=P2P*XA/XQ C1=XC*XW S1=XS*XW ELSE XR=1.0D0 XF=1.0D0 DO 30 K=1,12 XR=-.25D0*XR*(4.0D0*K-1.0D0)*(4.0D0*K-3.0D0)/X4 30 XF=XF+XR XR=1.0D0/(2.0D0*XA*XA) XG=XR DO 35 K=1,12 XR=-.25D0*XR*(4.0D0*K+1.0D0)*(4.0D0*K-1.0D0)/X4 35 XG=XG+XR C1=.5D0+(XF*DSIN(X2)-XG*DCOS(X2))/DSQRT(2.0D0*PI)/XA S1=.5D0-(XF*DCOS(X2)+XG*DSIN(X2))/DSQRT(2.0D0*PI)/XA ENDIF 40 FR=PP2*(.5D0-C1) FI0=PP2*(.5D0-S1) FI=(-1)**KS*FI0 FM=DSQRT(FR*FR+FI*FI) IF (FR.GE.0.0) THEN FA=SRD*DATAN(FI/FR) ELSE IF (FI.GT.0.0) THEN FA=SRD*(DATAN(FI/FR)+PI) ELSE IF (FI.LT.0.0) THEN FA=SRD*(DATAN(FI/FR)-PI) ENDIF XP=X*X+PI/4.0D0 CS=DCOS(XP) SS=DSIN(XP) XQ2=1.0D0/DSQRT(PI) GR=XQ2*(FR*CS+FI0*SS) GI=(-1)**KS*XQ2*(FI0*CS-FR*SS) GM=DSQRT(GR*GR+GI*GI) IF (GR.GE.0.0) THEN GA=SRD*DATAN(GI/GR) ELSE IF (GI.GT.0.0) THEN GA=SRD*(DATAN(GI/GR)+PI) ELSE IF (GI.LT.0.0) THEN GA=SRD*(DATAN(GI/GR)-PI) ENDIF IF (X.LT.0.0D0) THEN FR=PP2-FR FI=(-1)**KS*PP2-FI FM=DSQRT(FR*FR+FI*FI) FA=SRD*DATAN(FI/FR) GR=DCOS(X*X)-GR GI=-(-1)**KS*DSIN(X*X)-GI GM=DSQRT(GR*GR+GI*GI) GA=SRD*DATAN(GI/GR) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mgamma.for000077500000000000000000000053631321604176500260740ustar00rootroot00000000000000 PROGRAM MGAMMA C C ==================================================== C Purpose: This program computes the gamma function C â(x) using subroutine GAMMA C Examples: C x â(x) C ---------------------------- C 1/3 2.678938534708 C 0.5 1.772453850906 C -0.5 -3.544907701811 C -1.5 2.363271801207 C 5.0 24.000000000000 C ==================================================== C DOUBLE PRECISION A,X,GA DIMENSION A(5) DATA A/.333333333333333333D0,0.5D0,-0.5D0,-1.5,5.0D0/ WRITE(*,*)' x â(x)' WRITE(*,*)' ----------------------------' DO 10 K=1,5 X=A(K) CALL GAMMA(X,GA) 10 WRITE(*,20)X,GA WRITE(*,*) 'Please enter x:' READ(*,*) X CALL GAMMA(X,GA) WRITE(*,20)X,GA 20 FORMAT(1X,F8.4,E20.12) END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute the gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú ) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mherzo.for000077500000000000000000000060321321604176500261330ustar00rootroot00000000000000 PROGRAM MHERZO C C =========================================================== C Purpose : This program computes the zeros of Hermite C polynomial Ln(x) in the interval [-ì,ì] and the C corresponding weighting coefficients for Gauss- C Hermite integration using subroutine HERZO C Input : n --- Order of the Hermite polynomial C X(n) --- Zeros of the Hermite polynomial C W(n) --- Corresponding weighting coefficients C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION X(100),W(100) WRITE(*,*)'Please enter the order of Hn(x), n ' READ(*,*)N WRITE(*,20)N CALL HERZO(N,X,W) WRITE(*,*)' Nodes and weights for Gauss-Hermite integration' WRITE(*,*) WRITE(*,*)' i xi Wi' WRITE(*,*)' -----------------------------------------', & '------------' DO 10 J=1,N 10 WRITE(*,30)J,X(J),W(J) 20 FORMAT(1X,'n =',I3) 30 FORMAT(1X,I3,3X,D22.13,3X,D22.13) END SUBROUTINE HERZO(N,X,W) C C ======================================================== C Purpose : Compute the zeros of Hermite polynomial Ln(x) C in the interval [-ì,ì], and the corresponding C weighting coefficients for Gauss-Hermite C integration C Input : n --- Order of the Hermite polynomial C X(n) --- Zeros of the Hermite polynomial C W(n) --- Corresponding weighting coefficients C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION X(N),W(N) HN=1.0D0/N ZL=-1.1611D0+1.46D0*N**0.5 DO 40 NR=1,N/2 IF (NR.EQ.1) Z=ZL IF (NR.NE.1) Z=Z-HN*(N/2+1-NR) IT=0 10 IT=IT+1 Z0=Z F0=1.0D0 F1=2.0D0*Z DO 15 K=2,N HF=2.0D0*Z*F1-2.0D0*(K-1.0D0)*F0 HD=2.0D0*K*F1 F0=F1 15 F1=HF P=1.0D0 DO 20 I=1,NR-1 20 P=P*(Z-X(I)) FD=HF/P Q=0.0D0 DO 30 I=1,NR-1 WP=1.0D0 DO 25 J=1,NR-1 IF (J.EQ.I) GO TO 25 WP=WP*(Z-X(J)) 25 CONTINUE 30 Q=Q+WP GD=(HD-Q*FD)/P Z=Z-FD/GD IF (IT.LE.40.AND.DABS((Z-Z0)/Z).GT.1.0D-15) GO TO 10 X(NR)=Z X(N+1-NR)=-Z R=1.0D0 DO 35 K=1,N 35 R=2.0D0*R*K W(NR)=3.544907701811D0*R/(HD*HD) 40 W(N+1-NR)=W(NR) IF (N.NE.2*INT(N/2)) THEN R1=1.0D0 R2=1.0D0 DO 45 J=1,N R1=2.0D0*R1*J IF (J.GE.(N+1)/2) R2=R2*J 45 CONTINUE W(N/2+1)=0.88622692545276D0*R1/(R2*R2) X(N/2+1)=0.0D0 ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mhygfx.for000077500000000000000000000262211321604176500261330ustar00rootroot00000000000000 PROGRAM MHYGFX C C ============================================================ C Purpose: This program computes the hypergeometric function C F(a,b,c,x) using subroutine HYGFX C Input : a --- Parameter C b --- Parameter C c --- Parameter, c <> 0,-1,-2,... C x --- Argument ( x ó 1 ) C Output: HF --- F(a,b,c,x) C Example: C b = 3.30, c = 6.70 C a F(a,b,c,.25) F(a,b,c,.55) F(a,b,c,.85) C ------------------------------------------------------ C -2.5 .72356129D+00 .46961432D+00 .29106096D+00 C -0.5 .93610145D+00 .85187390D+00 .75543187D+00 C 0.5 .10689695D+01 .11795358D+01 .13510497D+01 C 2.5 .14051563D+01 .23999063D+01 .57381566D+01 C C a = 3.30, b = 6.70 C c F(a,b,c,.25) F(a,b,c,.55) F(a,b,c,.85) C ------------------------------------------------------ C -5.5 .15090670D+05 .10170778D+11 .58682088D+19 C -0.5 -.21631479D+04 -.30854772D+07 -.10217370D+13 C 0.5 .26451677D+03 .11967860D+06 .92370648D+10 C 4.5 .41946916D+01 .58092729D+02 .20396914D+05 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter a,b,c and x ' READ(*,*)A,B,C,X CALL HYGFX(A,B,C,X,HF) WRITE(*,10)A,B,C,X WRITE(*,20)HF 10 FORMAT(1X,'a =',F5.2,', ','b =',F5.2,', ','c =',F5.2, & ', ','x =',F5.2) 20 FORMAT(1X,'F(a,b,c,x)=',D16.8) END SUBROUTINE HYGFX(A,B,C,X,HF) C C ==================================================== C Purpose: Compute hypergeometric function F(a,b,c,x) C Input : a --- Parameter C b --- Parameter C c --- Parameter, c <> 0,-1,-2,... C x --- Argument ( x < 1 ) C Output: HF --- F(a,b,c,x) C Routines called: C (1) GAMMA for computing gamma function C (2) PSI for computing psi function C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) LOGICAL L0,L1,L2,L3,L4,L5 PI=3.141592653589793D0 EL=.5772156649015329D0 L0=C.EQ.INT(C).AND.C.LT.0.0 L1=1.0D0-X.LT.1.0D-15.AND.C-A-B.LE.0.0 L2=A.EQ.INT(A).AND.A.LT.0.0 L3=B.EQ.INT(B).AND.B.LT.0.0 L4=C-A.EQ.INT(C-A).AND.C-A.LE.0.0 L5=C-B.EQ.INT(C-B).AND.C-B.LE.0.0 IF (L0.OR.L1) THEN WRITE(*,*)'The hypergeometric series is divergent' RETURN ENDIF EPS=1.0D-15 IF (X.GT.0.95) EPS=1.0D-8 IF (X.EQ.0.0.OR.A.EQ.0.0.OR.B.EQ.0.0) THEN HF=1.0D0 RETURN ELSE IF (1.0D0-X.EQ.EPS.AND.C-A-B.GT.0.0) THEN CALL GAMMA(C,GC) CALL GAMMA(C-A-B,GCAB) CALL GAMMA(C-A,GCA) CALL GAMMA(C-B,GCB) HF=GC*GCAB/(GCA*GCB) RETURN ELSE IF (1.0D0+X.LE.EPS.AND.DABS(C-A+B-1.0).LE.EPS) THEN G0=DSQRT(PI)*2.0D0**(-A) CALL GAMMA(C,G1) CALL GAMMA(1.0D0+A/2.0-B,G2) CALL GAMMA(0.5D0+0.5*A,G3) HF=G0*G1/(G2*G3) RETURN ELSE IF (L2.OR.L3) THEN IF (L2) NM=INT(ABS(A)) IF (L3) NM=INT(ABS(B)) HF=1.0D0 R=1.0D0 DO 10 K=1,NM R=R*(A+K-1.0D0)*(B+K-1.0D0)/(K*(C+K-1.0D0))*X 10 HF=HF+R RETURN ELSE IF (L4.OR.L5) THEN IF (L4) NM=INT(ABS(C-A)) IF (L5) NM=INT(ABS(C-B)) HF=1.0D0 R=1.0D0 DO 15 K=1,NM R=R*(C-A+K-1.0D0)*(C-B+K-1.0D0)/(K*(C+K-1.0D0))*X 15 HF=HF+R HF=(1.0D0-X)**(C-A-B)*HF RETURN ENDIF AA=A BB=B X1=X IF (X.LT.0.0D0) THEN X=X/(X-1.0D0) IF (C.GT.A.AND.B.LT.A.AND.B.GT.0.0) THEN A=BB B=AA ENDIF B=C-B ENDIF IF (X.GE.0.75D0) THEN GM=0.0D0 IF (DABS(C-A-B-INT(C-A-B)).LT.1.0D-15) THEN M=INT(C-A-B) CALL GAMMA(A,GA) CALL GAMMA(B,GB) CALL GAMMA(C,GC) CALL GAMMA(A+M,GAM) CALL GAMMA(B+M,GBM) CALL PSI(A,PA) CALL PSI(B,PB) IF (M.NE.0) GM=1.0D0 DO 30 J=1,ABS(M)-1 30 GM=GM*J RM=1.0D0 DO 35 J=1,ABS(M) 35 RM=RM*J F0=1.0D0 R0=1.0D0 R1=1.0D0 SP0=0.D0 SP=0.0D0 IF (M.GE.0) THEN C0=GM*GC/(GAM*GBM) C1=-GC*(X-1.0D0)**M/(GA*GB*RM) DO 40 K=1,M-1 R0=R0*(A+K-1.0D0)*(B+K-1.0)/(K*(K-M))*(1.0-X) 40 F0=F0+R0 DO 45 K=1,M 45 SP0=SP0+1.0D0/(A+K-1.0)+1.0/(B+K-1.0)-1.0/K F1=PA+PB+SP0+2.0D0*EL+DLOG(1.0D0-X) DO 55 K=1,250 SP=SP+(1.0D0-A)/(K*(A+K-1.0))+(1.0-B)/(K*(B+K-1.0)) SM=0.0D0 DO 50 J=1,M 50 SM=SM+(1.0D0-A)/((J+K)*(A+J+K-1.0))+1.0/ & (B+J+K-1.0) RP=PA+PB+2.0D0*EL+SP+SM+DLOG(1.0D0-X) R1=R1*(A+M+K-1.0D0)*(B+M+K-1.0)/(K*(M+K))*(1.0-X) F1=F1+R1*RP IF (DABS(F1-HW).LT.DABS(F1)*EPS) GO TO 60 55 HW=F1 60 HF=F0*C0+F1*C1 ELSE IF (M.LT.0) THEN M=-M C0=GM*GC/(GA*GB*(1.0D0-X)**M) C1=-(-1)**M*GC/(GAM*GBM*RM) DO 65 K=1,M-1 R0=R0*(A-M+K-1.0D0)*(B-M+K-1.0)/(K*(K-M))*(1.0-X) 65 F0=F0+R0 DO 70 K=1,M 70 SP0=SP0+1.0D0/K F1=PA+PB-SP0+2.0D0*EL+DLOG(1.0D0-X) DO 80 K=1,250 SP=SP+(1.0D0-A)/(K*(A+K-1.0))+(1.0-B)/(K*(B+K-1.0)) SM=0.0D0 DO 75 J=1,M 75 SM=SM+1.0D0/(J+K) RP=PA+PB+2.0D0*EL+SP-SM+DLOG(1.0D0-X) R1=R1*(A+K-1.0D0)*(B+K-1.0)/(K*(M+K))*(1.0-X) F1=F1+R1*RP IF (DABS(F1-HW).LT.DABS(F1)*EPS) GO TO 85 80 HW=F1 85 HF=F0*C0+F1*C1 ENDIF ELSE CALL GAMMA(A,GA) CALL GAMMA(B,GB) CALL GAMMA(C,GC) CALL GAMMA(C-A,GCA) CALL GAMMA(C-B,GCB) CALL GAMMA(C-A-B,GCAB) CALL GAMMA(A+B-C,GABC) C0=GC*GCAB/(GCA*GCB) C1=GC*GABC/(GA*GB)*(1.0D0-X)**(C-A-B) HF=0.0D0 R0=C0 R1=C1 DO 90 K=1,250 R0=R0*(A+K-1.0D0)*(B+K-1.0)/(K*(A+B-C+K))*(1.0-X) R1=R1*(C-A+K-1.0D0)*(C-B+K-1.0)/(K*(C-A-B+K)) & *(1.0-X) HF=HF+R0+R1 IF (DABS(HF-HW).LT.DABS(HF)*EPS) GO TO 95 90 HW=HF 95 HF=HF+C0+C1 ENDIF ELSE A0=1.0D0 IF (C.GT.A.AND.C.LT.2.0D0*A.AND. & C.GT.B.AND.C.LT.2.0D0*B) THEN A0=(1.0D0-X)**(C-A-B) A=C-A B=C-B ENDIF HF=1.0D0 R=1.0D0 DO 100 K=1,250 R=R*(A+K-1.0D0)*(B+K-1.0D0)/(K*(C+K-1.0D0))*X HF=HF+R IF (DABS(HF-HW).LE.DABS(HF)*EPS) GO TO 105 100 HW=HF 105 HF=A0*HF ENDIF IF (X1.LT.0.0D0) THEN X=X1 C0=1.0D0/(1.0D0-X)**AA HF=C0*HF ENDIF A=AA B=BB IF (K.GT.120) WRITE(*,115) 115 FORMAT(1X,'Warning! You should check the accuracy') RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END SUBROUTINE PSI(X,PS) C C ====================================== C Purpose: Compute Psi function C Input : x --- Argument of psi(x) C Output: PS --- psi(x) C ====================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) XA=DABS(X) PI=3.141592653589793D0 EL=.5772156649015329D0 S=0.0D0 IF (X.EQ.INT(X).AND.X.LE.0.0) THEN PS=1.0D+300 RETURN ELSE IF (XA.EQ.INT(XA)) THEN N=XA DO 10 K=1 ,N-1 10 S=S+1.0D0/K PS=-EL+S ELSE IF (XA+.5.EQ.INT(XA+.5)) THEN N=XA-.5 DO 20 K=1,N 20 S=S+1.0/(2.0D0*K-1.0D0) PS=-EL+2.0D0*S-1.386294361119891D0 ELSE IF (XA.LT.10.0) THEN N=10-INT(XA) DO 30 K=0,N-1 30 S=S+1.0D0/(XA+K) XA=XA+N ENDIF X2=1.0D0/(XA*XA) A1=-.8333333333333D-01 A2=.83333333333333333D-02 A3=-.39682539682539683D-02 A4=.41666666666666667D-02 A5=-.75757575757575758D-02 A6=.21092796092796093D-01 A7=-.83333333333333333D-01 A8=.4432598039215686D0 PS=DLOG(XA)-.5D0/XA+X2*(((((((A8*X2+A7)*X2+ & A6)*X2+A5)*X2+A4)*X2+A3)*X2+A2)*X2+A1) PS=PS-S ENDIF IF (X.LT.0.0) PS=PS-PI*DCOS(PI*X)/DSIN(PI*X)-1.0D0/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mhygfz.for000077500000000000000000000370121321604176500261350ustar00rootroot00000000000000 PROGRAM MHYGFZ C C ============================================================ C Purpose: This program computes hypergeometric function for C a complex argument, F(a,b,c,z), using subroutine C HYGFZ C Input : a --- Parameter C b --- Parameter C c --- Parameter, c <> 0,-1,-2,... C x --- Real part of complex argument z C y --- Imaginary part of complex argument z C ( z = x+iy ) C Output: ZHF --- F(a,b,c,z) C Examples: C a b c z = x+ iy F(a,b,c,z) C -------------------------------------------------------------- C 3.2 1.8 6.7 1.0+0.0 i .54689992D+01+.00000000D+00 i C 3.2 -1.8 6.7 1.0+0.0 i .33750635D+00+.00000000D+00 i C -5.0 3.3 6.7 5.2+4.8 i .11682745D+03+.60389104D+03 i C 3.3 -6.0 3.7 5.2-4.8 i .17620425D+05+.38293812D+05 i C -7.0 3.3 -3.7 5.2-4.8 i -.11772779D+11-.14382286D+11 i C 4.3 -8.0 -3.7 5.2+4.8 i .13161188D+13-.10129870D+12 i C 3.3 5.8 6.7 0.2+0.1 i .17330557D+01+.63401030D+00 i C 3.5 -2.4 6.7 0.2+0.5 i .64762241D+00-.52110507D+00 i C 3.3 4.3 6.7 0.8+0.3 i -.14830086D+01+.83744258D+01 i C 7.0 5.0 4.1 3.0-1.0 i -.40376095D-02-.29566326D-02 i C 5.0 7.0 4.1 3.0-1.0 i -.40376095D-02-.29566326D-02 i C 3.5 1.2 9.7 0.6+0.9 i .10343044D+01+.54473814D+00 i C 2.1 5.4 9.7 0.5+0.7 i .68850442D+00+.12274187D+01 i C 8.7 3.2 6.7 0.5+0.7 i -.90046505D+00-.11198900D+01 i C 8.7 2.7 6.7 0.6+0.9 i -.46083890D+00-.54575701D+00 i C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Y) IMPLICIT COMPLEX *16 (Z) WRITE(*,*)'Please enter a,b,c,x and y ' READ(*,*)A,B,C,X,Y Z=CMPLX(X,Y) CALL HYGFZ(A,B,C,Z,ZHF) WRITE(*,*) WRITE(*,*)' a b c x y', & ' Re[F] Im[F]' WRITE(*,*)' --------------------------------', & '-----------------------------------' WRITE(*,10)A,B,C,X,Y,ZHF 10 FORMAT(1X,5F7.1,2X,2D16.8) END SUBROUTINE HYGFZ(A,B,C,Z,ZHF) C C ====================================================== C Purpose: Compute the hypergeometric function for a C complex argument, F(a,b,c,z) C Input : a --- Parameter C b --- Parameter C c --- Parameter, c <> 0,-1,-2,... C z --- Complex argument C Output: ZHF --- F(a,b,c,z) C Routines called: C (1) GAMMA for computing gamma function C (2) PSI for computing psi function C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Y) IMPLICIT COMPLEX *16 (Z) LOGICAL L0,L1,L2,L3,L4,L5,L6 X=REAL(Z) Y=DIMAG(Z) EPS=1.0D-15 L0=C.EQ.INT(C).AND.C.LT.0.0D0 L1=DABS(1.0D0-X).LT.EPS.AND.Y.EQ.0.0D0.AND.C-A-B.LE.0.0D0 L2=CDABS(Z+1.0D0).LT.EPS.AND.DABS(C-A+B-1.0D0).LT.EPS L3=A.EQ.INT(A).AND.A.LT.0.0D0 L4=B.EQ.INT(B).AND.B.LT.0.0D0 L5=C-A.EQ.INT(C-A).AND.C-A.LE.0.0D0 L6=C-B.EQ.INT(C-B).AND.C-B.LE.0.0D0 AA=A BB=B A0=CDABS(Z) IF (A0.GT.0.95D0) EPS=1.0D-8 PI=3.141592653589793D0 EL=.5772156649015329D0 IF (L0.OR.L1) THEN WRITE(*,*)'The hypergeometric series is divergent' RETURN ENDIF IF (A0.EQ.0.0D0.OR.A.EQ.0.0D0.OR.B.EQ.0.0D0) THEN ZHF=(1.0D0,0.0D0) ELSE IF (Z.EQ.1.0D0.AND.C-A-B.GT.0.0D0) THEN CALL GAMMA(C,GC) CALL GAMMA(C-A-B,GCAB) CALL GAMMA(C-A,GCA) CALL GAMMA(C-B,GCB) ZHF=GC*GCAB/(GCA*GCB) ELSE IF (L2) THEN G0=DSQRT(PI)*2.0D0**(-A) CALL GAMMA(C,G1) CALL GAMMA(1.0D0+A/2.0D0-B,G2) CALL GAMMA(0.5D0+0.5D0*A,G3) ZHF=G0*G1/(G2*G3) ELSE IF (L3.OR.L4) THEN IF (L3) NM=INT(ABS(A)) IF (L4) NM=INT(ABS(B)) ZHF=(1.0D0,0.0D0) ZR=(1.0D0,0.0D0) DO 10 K=1,NM ZR=ZR*(A+K-1.0D0)*(B+K-1.0D0)/(K*(C+K-1.0D0))*Z 10 ZHF=ZHF+ZR ELSE IF (L5.OR.L6) THEN IF (L5) NM=INT(ABS(C-A)) IF (L6) NM=INT(ABS(C-B)) ZHF=(1.0D0,0.0D0) ZR=(1.0D0,0.0D0) DO 15 K=1,NM ZR=ZR*(C-A+K-1.0D0)*(C-B+K-1.0D0)/(K*(C+K-1.0D0))*Z 15 ZHF=ZHF+ZR ZHF=(1.0D0-Z)**(C-A-B)*ZHF ELSE IF (A0.LE.1.0D0) THEN IF (X.LT.0.0D0) THEN Z1=Z/(Z-1.0D0) IF (C.GT.A.AND.B.LT.A.AND.B.GT.0.0) THEN A=BB B=AA ENDIF ZC0=1.0D0/((1.0D0-Z)**A) ZHF=(1.0D0,0.0D0) ZR0=(1.0D0,0.0D0) DO 20 K=1,500 ZR0=ZR0*(A+K-1.0D0)*(C-B+K-1.0D0)/(K*(C+K-1.0D0))*Z1 ZHF=ZHF+ZR0 IF (CDABS(ZHF-ZW).LT.CDABS(ZHF)*EPS) GO TO 25 20 ZW=ZHF 25 ZHF=ZC0*ZHF ELSE IF (A0.GE.0.90D0) THEN GM=0.0D0 MCAB=INT(C-A-B+EPS*DSIGN(1.0D0,C-A-B)) IF (DABS(C-A-B-MCAB).LT.EPS) THEN M=INT(C-A-B) CALL GAMMA(A,GA) CALL GAMMA(B,GB) CALL GAMMA(C,GC) CALL GAMMA(A+M,GAM) CALL GAMMA(B+M,GBM) CALL PSI(A,PA) CALL PSI(B,PB) IF (M.NE.0) GM=1.0D0 DO 30 J=1,ABS(M)-1 30 GM=GM*J RM=1.0D0 DO 35 J=1,ABS(M) 35 RM=RM*J ZF0=(1.0D0,0.0D0) ZR0=(1.0D0,0.0D0) ZR1=(1.0D0,0.0D0) SP0=0.D0 SP=0.0D0 IF (M.GE.0) THEN ZC0=GM*GC/(GAM*GBM) ZC1=-GC*(Z-1.0D0)**M/(GA*GB*RM) DO 40 K=1,M-1 ZR0=ZR0*(A+K-1.D0)*(B+K-1.D0)/(K*(K-M))*(1.D0-Z) 40 ZF0=ZF0+ZR0 DO 45 K=1,M 45 SP0=SP0+1.0D0/(A+K-1.0D0)+1.0/(B+K-1.0D0)-1.D0/K ZF1=PA+PB+SP0+2.0D0*EL+CDLOG(1.0D0-Z) DO 55 K=1,500 SP=SP+(1.0D0-A)/(K*(A+K-1.0D0))+(1.0D0-B)/ & (K*(B+K-1.0D0)) SM=0.0D0 DO 50 J=1,M SM=SM+(1.0D0-A)/((J+K)*(A+J+K-1.0D0)) & +1.0D0/(B+J+K-1.0D0) 50 CONTINUE ZP=PA+PB+2.0D0*EL+SP+SM+CDLOG(1.0D0-Z) ZR1=ZR1*(A+M+K-1.0D0)*(B+M+K-1.0D0)/(K*(M+K)) & *(1.0D0-Z) ZF1=ZF1+ZR1*ZP IF (CDABS(ZF1-ZW).LT.CDABS(ZF1)*EPS) GO TO 60 55 ZW=ZF1 60 ZHF=ZF0*ZC0+ZF1*ZC1 ELSE IF (M.LT.0) THEN M=-M ZC0=GM*GC/(GA*GB*(1.0D0-Z)**M) ZC1=-(-1)**M*GC/(GAM*GBM*RM) DO 65 K=1,M-1 ZR0=ZR0*(A-M+K-1.0D0)*(B-M+K-1.0D0)/(K*(K-M)) & *(1.0D0-Z) 65 ZF0=ZF0+ZR0 DO 70 K=1,M 70 SP0=SP0+1.0D0/K ZF1=PA+PB-SP0+2.0D0*EL+CDLOG(1.0D0-Z) DO 80 K=1,500 SP=SP+(1.0D0-A)/(K*(A+K-1.0D0))+(1.0D0-B)/(K* & (B+K-1.0D0)) SM=0.0D0 DO 75 J=1,M 75 SM=SM+1.0D0/(J+K) ZP=PA+PB+2.0D0*EL+SP-SM+CDLOG(1.0D0-Z) ZR1=ZR1*(A+K-1.D0)*(B+K-1.D0)/(K*(M+K))*(1.D0-Z) ZF1=ZF1+ZR1*ZP IF (CDABS(ZF1-ZW).LT.CDABS(ZF1)*EPS) GO TO 85 80 ZW=ZF1 85 ZHF=ZF0*ZC0+ZF1*ZC1 ENDIF ELSE CALL GAMMA(A,GA) CALL GAMMA(B,GB) CALL GAMMA(C,GC) CALL GAMMA(C-A,GCA) CALL GAMMA(C-B,GCB) CALL GAMMA(C-A-B,GCAB) CALL GAMMA(A+B-C,GABC) ZC0=GC*GCAB/(GCA*GCB) ZC1=GC*GABC/(GA*GB)*(1.0D0-Z)**(C-A-B) ZHF=(0.0D0,0.0D0) ZR0=ZC0 ZR1=ZC1 DO 90 K=1,500 ZR0=ZR0*(A+K-1.D0)*(B+K-1.D0)/(K*(A+B-C+K))*(1.D0-Z) ZR1=ZR1*(C-A+K-1.0D0)*(C-B+K-1.0D0)/(K*(C-A-B+K)) & *(1.0D0-Z) ZHF=ZHF+ZR0+ZR1 IF (CDABS(ZHF-ZW).LT.CDABS(ZHF)*EPS) GO TO 95 90 ZW=ZHF 95 ZHF=ZHF+ZC0+ZC1 ENDIF ELSE Z00=(1.0D0,0.0D0) IF (C-A.LT.A.AND.C-B.LT.B) THEN Z00=(1.0D0-Z)**(C-A-B) A=C-A B=C-B ENDIF ZHF=(1.0D0,0.D0) ZR=(1.0D0,0.0D0) DO 100 K=1,1500 ZR=ZR*(A+K-1.0D0)*(B+K-1.0D0)/(K*(C+K-1.0D0))*Z ZHF=ZHF+ZR IF (CDABS(ZHF-ZW).LE.CDABS(ZHF)*EPS) GO TO 105 100 ZW=ZHF 105 ZHF=Z00*ZHF ENDIF ELSE IF (A0.GT.1.0D0) THEN MAB=INT(A-B+EPS*DSIGN(1.0D0,A-B)) IF (DABS(A-B-MAB).LT.EPS.AND.A0.LE.1.1D0) B=B+EPS IF (DABS(A-B-MAB).GT.EPS) THEN CALL GAMMA(A,GA) CALL GAMMA(B,GB) CALL GAMMA(C,GC) CALL GAMMA(A-B,GAB) CALL GAMMA(B-A,GBA) CALL GAMMA(C-A,GCA) CALL GAMMA(C-B,GCB) ZC0=GC*GBA/(GCA*GB*(-Z)**A) ZC1=GC*GAB/(GCB*GA*(-Z)**B) ZR0=ZC0 ZR1=ZC1 ZHF=(0.0D0,0.0D0) DO 110 K=1,500 ZR0=ZR0*(A+K-1.0D0)*(A-C+K)/((A-B+K)*K*Z) ZR1=ZR1*(B+K-1.0D0)*(B-C+K)/((B-A+K)*K*Z) ZHF=ZHF+ZR0+ZR1 IF (CDABS((ZHF-ZW)/ZHF).LE.EPS) GO TO 115 110 ZW=ZHF 115 ZHF=ZHF+ZC0+ZC1 ELSE IF (A-B.LT.0.0D0) THEN A=BB B=AA ENDIF CA=C-A CB=C-B NCA=INT(CA+EPS*DSIGN(1.0D0,CA)) NCB=INT(CB+EPS*DSIGN(1.0D0,CB)) IF (DABS(CA-NCA).LT.EPS.OR.DABS(CB-NCB).LT.EPS) C=C+EPS CALL GAMMA(A,GA) CALL GAMMA(C,GC) CALL GAMMA(C-B,GCB) CALL PSI(A,PA) CALL PSI(C-A,PCA) CALL PSI(A-C,PAC) MAB=INT(A-B+EPS) ZC0=GC/(GA*(-Z)**B) CALL GAMMA(A-B,GM) ZF0=GM/GCB*ZC0 ZR=ZC0 DO 120 K=1,MAB-1 ZR=ZR*(B+K-1.0D0)/(K*Z) T0=A-B-K CALL GAMMA(T0,G0) CALL GAMMA(C-B-K,GCBK) 120 ZF0=ZF0+ZR*G0/GCBK IF (MAB.EQ.0) ZF0=(0.0D0,0.0D0) ZC1=GC/(GA*GCB*(-Z)**A) SP=-2.0D0*EL-PA-PCA DO 125 J=1,MAB 125 SP=SP+1.0D0/J ZP0=SP+CDLOG(-Z) SQ=1.0D0 DO 130 J=1,MAB 130 SQ=SQ*(B+J-1.0D0)*(B-C+J)/J ZF1=(SQ*ZP0)*ZC1 ZR=ZC1 RK1=1.0D0 SJ1=0.0D0 DO 145 K=1,10000 ZR=ZR/Z RK1=RK1*(B+K-1.0D0)*(B-C+K)/(K*K) RK2=RK1 DO 135 J=K+1,K+MAB 135 RK2=RK2*(B+J-1.0D0)*(B-C+J)/J SJ1=SJ1+(A-1.0D0)/(K*(A+K-1.0D0))+(A-C-1.0D0)/ & (K*(A-C+K-1.0D0)) SJ2=SJ1 DO 140 J=K+1,K+MAB 140 SJ2=SJ2+1.0D0/J ZP=-2.0D0*EL-PA-PAC+SJ2-1.0D0/(K+A-C) & -PI/DTAN(PI*(K+A-C))+CDLOG(-Z) ZF1=ZF1+RK2*ZR*ZP WS=CDABS(ZF1) IF (DABS((WS-W0)/WS).LT.EPS) GO TO 150 145 W0=WS 150 ZHF=ZF0+ZF1 ENDIF ENDIF 155 A=AA B=BB IF (K.GT.150) WRITE(*,160) 160 FORMAT(1X,'Warning! You should check the accuracy') RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END SUBROUTINE PSI(X,PS) C C ====================================== C Purpose: Compute Psi function C Input : x --- Argument of psi(x) C Output: PS --- psi(x) C ====================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) XA=DABS(X) PI=3.141592653589793D0 EL=.5772156649015329D0 S=0.0D0 IF (X.EQ.INT(X).AND.X.LE.0.0) THEN PS=1.0D+300 RETURN ELSE IF (XA.EQ.INT(XA)) THEN N=XA DO 10 K=1 ,N-1 10 S=S+1.0D0/K PS=-EL+S ELSE IF (XA+.5.EQ.INT(XA+.5)) THEN N=XA-.5 DO 20 K=1,N 20 S=S+1.0/(2.0D0*K-1.0D0) PS=-EL+2.0D0*S-1.386294361119891D0 ELSE IF (XA.LT.10.0) THEN N=10-INT(XA) DO 30 K=0,N-1 30 S=S+1.0D0/(XA+K) XA=XA+N ENDIF X2=1.0D0/(XA*XA) A1=-.8333333333333D-01 A2=.83333333333333333D-02 A3=-.39682539682539683D-02 A4=.41666666666666667D-02 A5=-.75757575757575758D-02 A6=.21092796092796093D-01 A7=-.83333333333333333D-01 A8=.4432598039215686D0 PS=DLOG(XA)-.5D0/XA+X2*(((((((A8*X2+A7)*X2+ & A6)*X2+A5)*X2+A4)*X2+A3)*X2+A2)*X2+A1) PS=PS-S ENDIF IF (X.LT.0.0) PS=PS-PI*DCOS(PI*X)/DSIN(PI*X)-1.0D0/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mik01a.for000077500000000000000000000133531321604176500257150ustar00rootroot00000000000000 PROGRAM MIK01A C C ============================================================= C Purpose: This program computes the modified Bessel functions C I0(x), I1(x), K0(x), K1(x), and their derivatives C using subroutine IK01A C Input : x --- Argument ( x ò 0 ) C Output: BI0 --- I0(x) C DI0 --- I0'(x) C BI1 --- I1(x) C DI1 --- I1'(x) C BK0 --- K0(x) C DK0 --- K0'(x) C BK1 --- K1(x) C DK1 --- K1'(x) C Example: C C x I0(x) I0'(x) I1(x) I1'(x) C ------------------------------------------------------------- C 1.0 .1266066D+01 .5651591D+00 .5651591D+00 .7009068D+00 C 10.0 .2815717D+04 .2670988D+04 .2670988D+04 .2548618D+04 C 20.0 .4355828D+08 .4245497D+08 .4245497D+08 .4143553D+08 C 30.0 .7816723D+12 .7685320D+12 .7685320D+12 .7560546D+12 C 40.0 .1489477D+17 .1470740D+17 .1470740D+17 .1452709D+17 C 50.0 .2932554D+21 .2903079D+21 .2903079D+21 .2874492D+21 C C x K0(x) K0'(x) K1(x) K1'(x) C ------------------------------------------------------------- C 1.0 .4210244D+00 -.6019072D+00 .6019072D+00 -.1022932D+01 C 10.0 .1778006D-04 -.1864877D-04 .1864877D-04 -.1964494D-04 C 20.0 .5741238D-09 -.5883058D-09 .5883058D-09 -.6035391D-09 C 30.0 .2132477D-13 -.2167732D-13 .2167732D-13 -.2204735D-13 C 40.0 .8392861D-18 -.8497132D-18 .8497132D-18 -.8605289D-18 C 50.0 .3410168D-22 -.3444102D-22 .3444102D-22 -.3479050D-22 C ============================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,10)X WRITE(*,*)' x I0(x) I0''(x) I1(x)', & ' I1''(x)' WRITE(*,*)'-------------------------------------------', & '----------------------' CALL IK01A(X,BI0,DI0,BI1,DI1,BK0,DK0,BK1,DK1) WRITE(*,20)X,BI0,DI0,BI1,DI1 WRITE(*,*) WRITE(*,*)' x K0(x) K0''(x) K1(x)', & ' K1''(x)' WRITE(*,*)'-------------------------------------------', & '----------------------' WRITE(*,20)X,BK0,DK0,BK1,DK1 10 FORMAT(3x 'x =',F5.1) 20 FORMAT(1X,F4.1,4D15.7) END SUBROUTINE IK01A(X,BI0,DI0,BI1,DI1,BK0,DK0,BK1,DK1) C C ========================================================= C Purpose: Compute modified Bessel functions I0(x), I1(1), C K0(x) and K1(x), and their derivatives C Input : x --- Argument ( x ò 0 ) C Output: BI0 --- I0(x) C DI0 --- I0'(x) C BI1 --- I1(x) C DI1 --- I1'(x) C BK0 --- K0(x) C DK0 --- K0'(x) C BK1 --- K1(x) C DK1 --- K1'(x) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(12),B(12),A1(8) PI=3.141592653589793D0 EL=0.5772156649015329D0 X2=X*X IF (X.EQ.0.0D0) THEN BI0=1.0D0 BI1=0.0D0 BK0=1.0D+300 BK1=1.0D+300 DI0=0.0D0 DI1=0.5D0 DK0=-1.0D+300 DK1=-1.0D+300 RETURN ELSE IF (X.LE.18.0D0) THEN BI0=1.0D0 R=1.0D0 DO 15 K=1,50 R=0.25D0*R*X2/(K*K) BI0=BI0+R IF (DABS(R/BI0).LT.1.0D-15) GO TO 20 15 CONTINUE 20 BI1=1.0D0 R=1.0D0 DO 25 K=1,50 R=0.25D0*R*X2/(K*(K+1)) BI1=BI1+R IF (DABS(R/BI1).LT.1.0D-15) GO TO 30 25 CONTINUE 30 BI1=0.5D0*X*BI1 ELSE DATA A/0.125D0,7.03125D-2, & 7.32421875D-2,1.1215209960938D-1, & 2.2710800170898D-1,5.7250142097473D-1, & 1.7277275025845D0,6.0740420012735D0, & 2.4380529699556D01,1.1001714026925D02, & 5.5133589612202D02,3.0380905109224D03/ DATA B/-0.375D0,-1.171875D-1, & -1.025390625D-1,-1.4419555664063D-1, & -2.7757644653320D-1,-6.7659258842468D-1, & -1.9935317337513D0,-6.8839142681099D0, & -2.7248827311269D01,-1.2159789187654D02, & -6.0384407670507D02,-3.3022722944809D03/ K0=12 IF (X.GE.35.0) K0=9 IF (X.GE.50.0) K0=7 CA=DEXP(X)/DSQRT(2.0D0*PI*X) BI0=1.0D0 XR=1.0D0/X DO 35 K=1,K0 35 BI0=BI0+A(K)*XR**K BI0=CA*BI0 BI1=1.0D0 DO 40 K=1,K0 40 BI1=BI1+B(K)*XR**K BI1=CA*BI1 ENDIF IF (X.LE.9.0D0) THEN CT=-(DLOG(X/2.0D0)+EL) BK0=0.0D0 W0=0.0D0 R=1.0D0 DO 65 K=1,50 W0=W0+1.0D0/K R=0.25D0*R/(K*K)*X2 BK0=BK0+R*(W0+CT) IF (DABS((BK0-WW)/BK0).LT.1.0D-15) GO TO 70 65 WW=BK0 70 BK0=BK0+CT ELSE DATA A1/0.125D0,0.2109375D0, & 1.0986328125D0,1.1775970458984D01, & 2.1461706161499D02,5.9511522710323D03, & 2.3347645606175D05,1.2312234987631D07/ CB=0.5D0/X XR2=1.0D0/X2 BK0=1.0D0 DO 75 K=1,8 75 BK0=BK0+A1(K)*XR2**K BK0=CB*BK0/BI0 ENDIF BK1=(1.0D0/X-BI1*BK0)/BI0 DI0=BI1 DI1=BI0-BI1/X DK0=-BK1 DK1=-BK0-BK1/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mik01b.for000077500000000000000000000121271321604176500257140ustar00rootroot00000000000000 PROGRAM MIK01B C C ============================================================= C Purpose: This program computes the modified Bessel functions C I0(x), I1(x), K0(x), K1(x), and their derivatives C using subroutine IK01B C Input : x --- Argument ( x ò 0 ) C Output: BI0 --- I0(x) C DI0 --- I0'(x) C BI1 --- I1(x) C DI1 --- I1'(x) C BK0 --- K0(x) C DK0 --- K0'(x) C BK1 --- K1(x) C DK1 --- K1'(x) C Example: C C x I0(x) I0'(x) I1(x) I1'(x) C ------------------------------------------------------------- C 1.0 .126607D+01 .565159D+00 .565159D+00 .700907D+00 C 10.0 .281572D+04 .267099D+04 .267099D+04 .254862D+04 C 20.0 .435583D+08 .424550D+08 .424550D+08 .414355D+08 C 30.0 .781672D+12 .768532D+12 .768532D+12 .756055D+12 C 40.0 .148948D+17 .147074D+17 .147074D+17 .145271D+17 C 50.0 .293255D+21 .290308D+21 .290308D+21 .287449D+21 C C x K0(x) K0'(x) K1(x) K1'(x) C ------------------------------------------------------------- C 1.0 .421024D+00 -.601907D+00 .601907D+00 -.102293D+01 C 10.0 .177801D-04 -.186488D-04 .186488D-04 -.196449D-04 C 20.0 .574124D-09 -.588306D-09 .588306D-09 -.603539D-09 C 30.0 .213248D-13 -.216773D-13 .216773D-13 -.220474D-13 C 40.0 .839286D-18 -.849713D-18 .849713D-18 -.860529D-18 C 50.0 .341017D-22 -.344410D-22 .344410D-22 -.347905D-22 C ============================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,10)X WRITE(*,*)' x I0(x) I0''(x) I1(x)', & ' I1''(x)' WRITE(*,*)'-------------------------------------------', & '----------------------' CALL IK01B(X,BI0,DI0,BI1,DI1,BK0,DK0,BK1,DK1) WRITE(*,20)X,BI0,DI0,BI1,DI1 WRITE(*,*) WRITE(*,*)' x K0(x) K0''(x) K1(x)', & ' K1''(x)' WRITE(*,*)'-------------------------------------------', & '----------------------' WRITE(*,20)X,BK0,DK0,BK1,DK1 10 FORMAT(3x 'x =',F5.1) 20 FORMAT(1X,F4.1,4D15.7) END SUBROUTINE IK01B(X,BI0,DI0,BI1,DI1,BK0,DK0,BK1,DK1) C C ========================================================= C Purpose: Compute modified Bessel functions I0(x), I1(1), C K0(x) and K1(x), and their derivatives C Input : x --- Argument ( x ò 0 ) C Output: BI0 --- I0(x) C DI0 --- I0'(x) C BI1 --- I1(x) C DI1 --- I1'(x) C BK0 --- K0(x) C DK0 --- K0'(x) C BK1 --- K1(x) C DK1 --- K1'(x) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (X.EQ.0.0D0) THEN BI0=1.0D0 BI1=0.0D0 BK0=1.0D+300 BK1=1.0D+300 DI0=0.0D0 DI1=0.5D0 DK0=-1.0D+300 DK1=-1.0D+300 RETURN ELSE IF (X.LE.3.75D0) THEN T=X/3.75D0 T2=T*T BI0=(((((.0045813D0*T2+.0360768D0)*T2+.2659732D0) & *T2+1.2067492D0)*T2+3.0899424D0)*T2 & +3.5156229D0)*T2+1.0D0 BI1=X*((((((.00032411D0*T2+.00301532D0)*T2 & +.02658733D0)*T2+.15084934D0)*T2+.51498869D0) & *T2+.87890594D0)*T2+.5D0) ELSE T=3.75D0/X BI0=((((((((.00392377D0*T-.01647633D0)*T & +.02635537D0)*T-.02057706D0)*T+.916281D-2)*T & -.157565D-2)*T+.225319D-2)*T+.01328592D0)*T & +.39894228D0)*DEXP(X)/DSQRT(X) BI1=((((((((-.420059D-2*T+.01787654D0)*T & -.02895312D0)*T+.02282967D0)*T-.01031555D0)*T & +.163801D-2)*T-.00362018D0)*T-.03988024D0)*T & +.39894228D0)*DEXP(X)/DSQRT(X) ENDIF IF (X.LE.2.0D0) THEN T=X/2.0D0 T2=T*T BK0=(((((.0000074D0*T2+.0001075D0)*T2+.00262698D0) & *T2+.0348859D0)*T2+.23069756D0)*T2+.4227842D0) & *T2-.57721566D0-BI0*DLOG(T) BK1=((((((-.00004686D0*T2-.00110404D0)*T2 & -.01919402D0)*T2-.18156897D0)*T2-.67278579D0) & *T2+.15443144D0)*T2+1.0D0)/X+BI1*DLOG(T) ELSE T=2.0D0/X T2=T*T BK0=((((((.00053208D0*T-.0025154D0)*T+.00587872D0) & *T-.01062446D0)*T+.02189568D0)*T-.07832358D0) & *T+1.25331414D0)*DEXP(-X)/DSQRT(X) BK1=((((((-.00068245D0*T+.00325614D0)*T & -.00780353D0)*T+.01504268D0)*T-.0365562D0)*T+ & .23498619D0)*T+1.25331414D0)*DEXP(-X)/DSQRT(X) ENDIF DI0=BI1 DI1=BI0-BI1/X DK0=-BK1 DK1=-BK0-BK1/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mikna.for000077500000000000000000000226341321604176500257340ustar00rootroot00000000000000 PROGRAM MIKNA C C ============================================================= C Purpose: This program computes modified Bessel functions C In(x) and Kn(x), and their derivatives using C subroutine IKNA C Input: x --- Argument of In(x) and Kn(x) ( x ò 0 ) C n --- Order of In(x) and Kn(x) C ( n = 0,1,úúú, n ó 250 ) C Output: BI(n) --- In(x) C DI(n) --- In'(x) C BK(n) --- Kn(x) C DK(n) --- Kn'(x) C Example: Nmax = 5, x = 10.0 C C n In(x) In'(x) Kn(x) Kn'(x) C --------------------------------------------------------------- C 0 .2815717D+04 .2670988D+04 .1778006D-04 -.1864877D-04 C 1 .2670988D+04 .2548618D+04 .1864877D-04 -.1964494D-04 C 2 .2281519D+04 .2214685D+04 .2150982D-04 -.2295074D-04 C 3 .1758381D+04 .1754005D+04 .2725270D-04 -.2968563D-04 C 4 .1226491D+04 .1267785D+04 .3786144D-04 -.4239728D-04 C 5 .7771883D+03 .8378964D+03 .5754185D-04 -.6663236D-04 C ============================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BI(0:250),DI(0:250),BK(0:250),DK(0:250) WRITE(*,*)' Please enter n, x ' READ(*,*)N,X WRITE(*,25)N,X WRITE(*,*) IF (N.LE.10) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL IKNA(N,X,NM,BI,DI,BK,DK) WRITE(*,*)' n In(x) In''(x) ', & ' Kn(x) Kn''(x) ' WRITE(*,*)' -------------------------------', & '--------------------------------' DO 10 K=0,NM,NS WRITE(*,20)K,BI(K),DI(K),BK(K),DK(K) 10 CONTINUE 20 FORMAT(1X,I3,4D15.7) 25 FORMAT(3X,6HNmax =,I3,', ',3Hx =,F5.1) END SUBROUTINE IKNA(N,X,NM,BI,DI,BK,DK) C C ======================================================== C Purpose: Compute modified Bessel functions In(x) and C Kn(x), and their derivatives C Input: x --- Argument of In(x) and Kn(x) ( x ò 0 ) C n --- Order of In(x) and Kn(x) C Output: BI(n) --- In(x) C DI(n) --- In'(x) C BK(n) --- Kn(x) C DK(n) --- Kn'(x) C NM --- Highest order computed C Routines called: C (1) IK01A for computing I0(x),I1(x),K0(x) & K1(x) C (2) MSTA1 and MSTA2 for computing the starting C point for backward recurrence C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BI(0:N),DI(0:N),BK(0:N),DK(0:N) NM=N IF (X.LE.1.0D-100) THEN DO 10 K=0,N BI(K)=0.0D0 DI(K)=0.0D0 BK(K)=1.0D+300 10 DK(K)=-1.0D+300 BI(0)=1.0D0 DI(1)=0.5D0 RETURN ENDIF CALL IK01A(X,BI0,DI0,BI1,DI1,BK0,DK0,BK1,DK1) BI(0)=BI0 BI(1)=BI1 BK(0)=BK0 BK(1)=BK1 DI(0)=DI0 DI(1)=DI1 DK(0)=DK0 DK(1)=DK1 IF (N.LE.1) RETURN IF (X.GT.40.0.AND.N.LT.INT(0.25*X)) THEN H0=BI0 H1=BI1 DO 15 K=2,N H=-2.0D0*(K-1.0D0)/X*H1+H0 BI(K)=H H0=H1 15 H1=H ELSE M=MSTA1(X,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(X,N,15) ENDIF F0=0.0D0 F1=1.0D-100 DO 20 K=M,0,-1 F=2.0D0*(K+1.0D0)*F1/X+F0 IF (K.LE.NM) BI(K)=F F0=F1 20 F1=F S0=BI0/F DO 25 K=0,NM 25 BI(K)=S0*BI(K) ENDIF G0=BK0 G1=BK1 DO 30 K=2,NM G=2.0D0*(K-1.0D0)/X*G1+G0 BK(K)=G G0=G1 30 G1=G DO 40 K=2,NM DI(K)=BI(K-1)-K/X*BI(K) 40 DK(K)=-BK(K-1)-K/X*BK(K) RETURN END SUBROUTINE IK01A(X,BI0,DI0,BI1,DI1,BK0,DK0,BK1,DK1) C C ========================================================= C Purpose: Compute modified Bessel functions I0(x), I1(1), C K0(x) and K1(x), and their derivatives C Input : x --- Argument ( x ò 0 ) C Output: BI0 --- I0(x) C DI0 --- I0'(x) C BI1 --- I1(x) C DI1 --- I1'(x) C BK0 --- K0(x) C DK0 --- K0'(x) C BK1 --- K1(x) C DK1 --- K1'(x) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(12),B(12),A1(8) PI=3.141592653589793D0 EL=0.5772156649015329D0 X2=X*X IF (X.EQ.0.0D0) THEN BI0=1.0D0 BI1=0.0D0 BK0=1.0D+300 BK1=1.0D+300 DI0=0.0D0 DI1=0.5D0 DK0=-1.0D+300 DK1=-1.0D+300 RETURN ELSE IF (X.LE.18.0) THEN BI0=1.0D0 R=1.0D0 DO 15 K=1,50 R=0.25D0*R*X2/(K*K) BI0=BI0+R IF (DABS(R/BI0).LT.1.0D-15) GO TO 20 15 CONTINUE 20 BI1=1.0D0 R=1.0D0 DO 25 K=1,50 R=0.25D0*R*X2/(K*(K+1)) BI1=BI1+R IF (DABS(R/BI1).LT.1.0D-15) GO TO 30 25 CONTINUE 30 BI1=0.5D0*X*BI1 ELSE DATA A/0.125D0,7.03125D-2, & 7.32421875D-2,1.1215209960938D-1, & 2.2710800170898D-1,5.7250142097473D-1, & 1.7277275025845D0,6.0740420012735D0, & 2.4380529699556D01,1.1001714026925D02, & 5.5133589612202D02,3.0380905109224D03/ DATA B/-0.375D0,-1.171875D-1, & -1.025390625D-1,-1.4419555664063D-1, & -2.7757644653320D-1,-6.7659258842468D-1, & -1.9935317337513D0,-6.8839142681099D0, & -2.7248827311269D01,-1.2159789187654D02, & -6.0384407670507D02,-3.3022722944809D03/ K0=12 IF (X.GE.35.0) K0=9 IF (X.GE.50.0) K0=7 CA=DEXP(X)/DSQRT(2.0D0*PI*X) BI0=1.0D0 XR=1.0D0/X DO 35 K=1,K0 35 BI0=BI0+A(K)*XR**K BI0=CA*BI0 BI1=1.0D0 DO 40 K=1,K0 40 BI1=BI1+B(K)*XR**K BI1=CA*BI1 ENDIF IF (X.LE.9.0D0) THEN CT=-(DLOG(X/2.0D0)+EL) BK0=0.0D0 W0=0.0D0 R=1.0D0 DO 65 K=1,50 W0=W0+1.0D0/K R=0.25D0*R/(K*K)*X2 BK0=BK0+R*(W0+CT) IF (DABS((BK0-WW)/BK0).LT.1.0D-15) GO TO 70 65 WW=BK0 70 BK0=BK0+CT ELSE DATA A1/0.125D0,0.2109375D0, & 1.0986328125D0,1.1775970458984D01, & 2.1461706161499D02,5.9511522710323D03, & 2.3347645606175D05,1.2312234987631D07/ CB=0.5D0/X XR2=1.0D0/X2 BK0=1.0D0 DO 75 K=1,8 75 BK0=BK0+A1(K)*XR2**K BK0=CB*BK0/BI0 ENDIF BK1=(1.0D0/X-BI1*BK0)/BI0 DI0=BI1 DI1=BI0-BI1/X DK0=-BK1 DK1=-BK0-BK1/X RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/miknb.for000077500000000000000000000146651321604176500257420ustar00rootroot00000000000000 PROGRAM MIKNB C C ============================================================= C Purpose: This program computes modified Bessel functions C In(x) and Kn(x), and their derivatives using C subroutine IKNB C Input: x --- Argument of In(x) and Kn(x) ( 0 ó x ó 700 ) C n --- Order of In(x) and Kn(x) C ( n = 0,1,..., n ó 250 ) C Output: BI(n) --- In(x) C DI(n) --- In'(x) C BK(n) --- Kn(x) C DK(n) --- Kn'(x) C Example: Nmax = 5, x = 10.0 C C n In(x) In'(x) Kn(x) Kn'(x) C --------------------------------------------------------------- C 0 .2815717D+04 .2670988D+04 .1778006D-04 -.1864877D-04 C 1 .2670988D+04 .2548618D+04 .1864877D-04 -.1964494D-04 C 2 .2281519D+04 .2214685D+04 .2150982D-04 -.2295074D-04 C 3 .1758381D+04 .1754005D+04 .2725270D-04 -.2968563D-04 C 4 .1226491D+04 .1267785D+04 .3786144D-04 -.4239728D-04 C 5 .7771883D+03 .8378964D+03 .5754185D-04 -.6663236D-04 C ============================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BI(0:250),DI(0:250),BK(0:250),DK(0:250) WRITE(*,*)' Please enter n, x ' READ(*,*)N,X WRITE(*,25)N,X WRITE(*,*) IF (N.LE.10) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL IKNB(N,X,NM,BI,DI,BK,DK) WRITE(*,*)' n In(x) In''(x) ', & ' Kn(x) Kn''(x) ' WRITE(*,*)' -------------------------------', & '--------------------------------' DO 10 K=0,NM,NS WRITE(*,20)K,BI(K),DI(K),BK(K),DK(K) 10 CONTINUE 20 FORMAT(1X,I3,4D15.7) 25 FORMAT(3X,6HNmax =,I3,', ',3Hx =,F5.1) END SUBROUTINE IKNB(N,X,NM,BI,DI,BK,DK) C C ============================================================ C Purpose: Compute modified Bessel functions In(x) and Kn(x), C and their derivatives C Input: x --- Argument of In(x) and Kn(x) ( 0 ó x ó 700 ) C n --- Order of In(x) and Kn(x) C Output: BI(n) --- In(x) C DI(n) --- In'(x) C BK(n) --- Kn(x) C DK(n) --- Kn'(x) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 for computing the starting point C for backward recurrence C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BI(0:N),DI(0:N),BK(0:N),DK(0:N) PI=3.141592653589793D0 EL=0.5772156649015329D0 NM=N IF (X.LE.1.0D-100) THEN DO 10 K=0,N BI(K)=0.0D0 DI(K)=0.0D0 BK(K)=1.0D+300 10 DK(K)=-1.0D+300 BI(0)=1.0D0 DI(1)=0.5D0 RETURN ENDIF IF (N.EQ.0) NM=1 M=MSTA1(X,200) IF (M.LT.NM) THEN NM=M ELSE M=MSTA2(X,NM,15) ENDIF BS=0.0D0 SK0=0.0D0 F0=0.0D0 F1=1.0D-100 DO 15 K=M,0,-1 F=2.0D0*(K+1.0D0)/X*F1+F0 IF (K.LE.NM) BI(K)=F IF (K.NE.0.AND.K.EQ.2*INT(K/2)) SK0=SK0+4.0D0*F/K BS=BS+2.0D0*F F0=F1 15 F1=F S0=DEXP(X)/(BS-F) DO 20 K=0,NM 20 BI(K)=S0*BI(K) IF (X.LE.8.0D0) THEN BK(0)=-(DLOG(0.5D0*X)+EL)*BI(0)+S0*SK0 BK(1)=(1.0D0/X-BI(1)*BK(0))/BI(0) ELSE A0=DSQRT(PI/(2.0D0*X))*DEXP(-X) K0=16 IF (X.GE.25.0) K0=10 IF (X.GE.80.0) K0=8 IF (X.GE.200.0) K0=6 DO 30 L=0,1 BKL=1.0D0 VT=4.0D0*L R=1.0D0 DO 25 K=1,K0 R=0.125D0*R*(VT-(2.0*K-1.0)**2)/(K*X) 25 BKL=BKL+R BK(L)=A0*BKL 30 CONTINUE ENDIF G0=BK(0) G1=BK(1) DO 35 K=2,NM G=2.0D0*(K-1.0D0)/X*G1+G0 BK(K)=G G0=G1 35 G1=G DI(0)=BI(1) DK(0)=-BK(1) DO 40 K=1,NM DI(K)=BI(K-1)-K/X*BI(K) 40 DK(K)=-BK(K-1)-K/X*BK(K) RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mikv.for000077500000000000000000000234571321604176500256070ustar00rootroot00000000000000 PROGRAM MIKV C C ============================================================ C Purpose: This program computes modified Bessel functions C Iv(x) and Kv(x) with an arbitrary order, and C their derivatives using subroutine IKV C Input : x --- Argument ( x ò 0 ) C v --- Order of Iv(x) and Kv(x) C ( v = n+v0, 0 ó n ó 250 , 0 ó v0 < 1 ) C Output: BI(n) --- In+v0(x) C DI(n) --- In+v0'(x) C BK(n) --- Kn+v0(x) C DK(n) --- Kn+v0'(x) C Example: v = n+v0, v0 = .25, x = 10.0 C C n Iv(x) Iv'(x) Kv(x) Kv'(x) C ---------------------------------------------------------------- C 0 .28064359D+04 .26631677D+04 .17833184D-04 -.18709581D-04 C 1 .25930068D+04 .24823101D+04 .19155411D-04 -.20227611D-04 C 2 .21581842D+04 .21074153D+04 .22622037D-04 -.24245369D-04 C 3 .16218239D+04 .16310915D+04 .29335327D-04 -.32156018D-04 C 4 .11039987D+04 .11526244D+04 .41690000D-04 -.47053577D-04 C 5 .68342498D+03 .74520058D+03 .64771827D-04 -.75695209D-04 C ============================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) COMMON BI(0:250),DI(0:250),BK(0:250),DK(0:250) WRITE(*,*)' Please enter v, x ' READ(*,*)V,X N=INT(V) V0=V-N WRITE(*,30)V0,X IF (N.LE.10) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL IKV(V,X,VM,BI,DI,BK,DK) NM=INT(VM) WRITE(*,*) WRITE(*,*)' n Iv(x) Iv''(x) ', & 'Kv(x) Kv''(x)' WRITE(*,*)' -------------------------------------', & '--------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20) K,BI(K),DI(K),BK(K),DK(K) 20 FORMAT(2X,I4,1X,4D16.8) 30 FORMAT(8X,'v = n+v0',', ','v0 =',F7.5,', ','x =',F5.1) END SUBROUTINE IKV(V,X,VM,BI,DI,BK,DK) C C ======================================================= C Purpose: Compute modified Bessel functions Iv(x) and C Kv(x), and their derivatives C Input : x --- Argument ( x ò 0 ) C v --- Order of Iv(x) and Kv(x) C ( v = n+v0, n = 0,1,2,..., 0 ó v0 < 1 ) C Output: BI(n) --- In+v0(x) C DI(n) --- In+v0'(x) C BK(n) --- Kn+v0(x) C DK(n) --- Kn+v0'(x) C VM --- Highest order computed C Routines called: C (1) GAMMA for computing the gamma function C (2) MSTA1 and MSTA2 to compute the starting C point for backward recurrence C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BI(0:*),DI(0:*),BK(0:*),DK(0:*) PI=3.141592653589793D0 X2=X*X N=INT(V) V0=V-N IF (N.EQ.0) N=1 IF (X.LT.1.0D-100) THEN DO 10 K=0,N BI(K)=0.0D0 DI(K)=0.0D0 BK(K)=-1.0D+300 10 DK(K)=1.0D+300 IF (V.EQ.0.0) THEN BI(0)=1.0D0 DI(1)=0.5D0 ENDIF VM=V RETURN ENDIF PIV=PI*V0 VT=4.0D0*V0*V0 IF (V0.EQ.0.0D0) THEN A1=1.0D0 ELSE V0P=1.0D0+V0 CALL GAMMA(V0P,GAP) A1=(0.5D0*X)**V0/GAP ENDIF K0=14 IF (X.GE.35.0) K0=10 IF (X.GE.50.0) K0=8 IF (X.LE.18.0) THEN BI0=1.0D0 R=1.0D0 DO 15 K=1,30 R=0.25D0*R*X2/(K*(K+V0)) BI0=BI0+R IF (DABS(R/BI0).LT.1.0D-15) GO TO 20 15 CONTINUE 20 BI0=BI0*A1 ELSE CA=DEXP(X)/DSQRT(2.0D0*PI*X) SUM=1.0D0 R=1.0D0 DO 25 K=1,K0 R=-0.125D0*R*(VT-(2.0D0*K-1.0D0)**2.0)/(K*X) 25 SUM=SUM+R BI0=CA*SUM ENDIF M=MSTA1(X,200) IF (M.LT.N) THEN N=M ELSE M=MSTA2(X,N,15) ENDIF F2=0.0D0 F1=1.0D-100 DO 30 K=M,0,-1 F=2.0D0*(V0+K+1.0D0)/X*F1+F2 IF (K.LE.N) BI(K)=F F2=F1 30 F1=F CS=BI0/F DO 35 K=0,N 35 BI(K)=CS*BI(K) DI(0)=V0/X*BI(0)+BI(1) DO 40 K=1,N 40 DI(K)=-(K+V0)/X*BI(K)+BI(K-1) IF (X.LE.9.0D0) THEN IF (V0.EQ.0.0D0) THEN CT=-DLOG(0.5D0*X)-0.5772156649015329D0 CS=0.0D0 W0=0.0D0 R=1.0D0 DO 45 K=1,50 W0=W0+1.0D0/K R=0.25D0*R/(K*K)*X2 CS=CS+R*(W0+CT) WA=DABS(CS) IF (DABS((WA-WW)/WA).LT.1.0D-15) GO TO 50 45 WW=WA 50 BK0=CT+CS ELSE V0N=1.0D0-V0 CALL GAMMA(V0N,GAN) A2=1.0D0/(GAN*(0.5D0*X)**V0) A1=(0.5D0*X)**V0/GAP SUM=A2-A1 R1=1.0D0 R2=1.0D0 DO 55 K=1,120 R1=0.25D0*R1*X2/(K*(K-V0)) R2=0.25D0*R2*X2/(K*(K+V0)) SUM=SUM+A2*R1-A1*R2 WA=DABS(SUM) IF (DABS((WA-WW)/WA).LT.1.0D-15) GO TO 60 55 WW=WA 60 BK0=0.5D0*PI*SUM/DSIN(PIV) ENDIF ELSE CB=DEXP(-X)*DSQRT(0.5D0*PI/X) SUM=1.0D0 R=1.0D0 DO 65 K=1,K0 R=0.125D0*R*(VT-(2.0*K-1.0)**2.0)/(K*X) 65 SUM=SUM+R BK0=CB*SUM ENDIF BK1=(1.0D0/X-BI(1)*BK0)/BI(0) BK(0)=BK0 BK(1)=BK1 DO 70 K=2,N BK2=2.0D0*(V0+K-1.0D0)/X*BK1+BK0 BK(K)=BK2 BK0=BK1 70 BK1=BK2 DK(0)=V0/X*BK(0)-BK(1) DO 80 K=1,N 80 DK(K)=-(K+V0)/X*BK(K)-BK(K-1) VM=N+V0 RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mincob.for000077500000000000000000000110441321604176500260750ustar00rootroot00000000000000 PROGRAM MINCOB C C ========================================================= C Purpose: This program computes the incomplete beta C function Ix(a,b) using subroutine INCOB C Input : a --- Parameter C b --- Parameter C x --- Argument ( 0 ó x ó 1 ) C Output: BIX --- Ix(a,b) C Example: C a b x Ix(a,b) C ----------------------------------- C 1.0 3.0 .25 .57812500 C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter a, b and x ( 0 ó x ó 1 )' READ(*,*)A,B,X WRITE(*,*) WRITE(*,*)' a b x Ix(a,b)' WRITE(*,*)' -----------------------------------' CALL INCOB(A,B,X,BIX) WRITE(*,10)A,B,X,BIX 10 FORMAT(1X,F5.1,3X,F5.1,3X,F5.2,F14.8) END SUBROUTINE INCOB(A,B,X,BIX) C C ======================================================== C Purpose: Compute the incomplete beta function Ix(a,b) C Input : a --- Parameter C b --- Parameter C x --- Argument ( 0 ó x ó 1 ) C Output: BIX --- Ix(a,b) C Routine called: BETA for computing beta function B(p,q) C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DK(51),FK(51) S0=(A+1.0D0)/(A+B+2.0D0) CALL BETA(A,B,BT) IF (X.LE.S0) THEN DO 10 K=1,20 10 DK(2*K)=K*(B-K)*X/(A+2.0D0*K-1.0D0)/(A+2.0D0*K) DO 15 K=0,20 15 DK(2*K+1)=-(A+K)*(A+B+K)*X/(A+2.D0*K)/(A+2.0*K+1.0) T1=0.0D0 DO 20 K=20,1,-1 20 T1=DK(K)/(1.0D0+T1) TA=1.0D0/(1.0D0+T1) BIX=X**A*(1.0D0-X)**B/(A*BT)*TA ELSE DO 25 K=1,20 25 FK(2*K)=K*(A-K)*(1.0D0-X)/(B+2.*K-1.0)/(B+2.0*K) DO 30 K=0,20 30 FK(2*K+1)=-(B+K)*(A+B+K)*(1.D0-X)/ & (B+2.D0*K)/(B+2.D0*K+1.D0) T2=0.0D0 DO 35 K=20,1,-1 35 T2=FK(K)/(1.0D0+T2) TB=1.0D0/(1.0D0+T2) BIX=1.0D0-X**A*(1.0D0-X)**B/(B*BT)*TB ENDIF RETURN END SUBROUTINE BETA(P,Q,BT) C C ========================================== C Purpose: Compute the beta function B(p,q) C Input : p --- Parameter ( p > 0 ) C q --- Parameter ( q > 0 ) C Output: BT --- B(p,q) C Routine called: GAMMA for computing â(x) C ========================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) CALL GAMMA(P,GP) CALL GAMMA(Q,GQ) PPQ=P+Q CALL GAMMA(PPQ,GPQ) BT=GP*GQ/GPQ RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mincog.for000077500000000000000000000102441321604176500261030ustar00rootroot00000000000000 PROGRAM MINCOG C C ========================================================== C Purpose: This program computes the incomplete gamma C function r(a,x), â(a,x) and P(a,x) using C subroutine INCOG C Input : a --- Parameter C x --- Argument C Output: GIN --- r(a,x) C GIM --- â(a,x) C GIP --- P(a,x) C Example: C a x r(a,x) â(a,x) P(a,x) C ------------------------------------------------------- C 3.0 5.0 .17506960D+01 .24930404D+00 .87534798D+00 C =========================================================== C DOUBLE PRECISION A,X,GIN,GIM,GIP WRITE(*,*)'Plese enter a and x' READ(*,*)A,X WRITE(*,*) WRITE(*,*)' a x r(a,x) â(a,x) P(a,x)' WRITE(*,*)' --------------------------------------------', & '------------' CALL INCOG(A,X,GIN,GIM,GIP) WRITE(*,10)A,X,GIN,GIM,GIP 10 FORMAT(1X,F5.1,1X,F5.1,3D15.8) END SUBROUTINE INCOG(A,X,GIN,GIM,GIP) C C =================================================== C Purpose: Compute the incomplete gamma function C r(a,x), â(a,x) and P(a,x) C Input : a --- Parameter ( a ó 170 ) C x --- Argument C Output: GIN --- r(a,x) C GIM --- â(a,x) C GIP --- P(a,x) C Routine called: GAMMA for computing â(x) C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) XAM=-X+A*DLOG(X) IF (XAM.GT.700.0.OR.A.GT.170.0) THEN WRITE(*,*)'a and/or x too large' STOP ENDIF IF (X.EQ.0.0) THEN GIN=0.0 CALL GAMMA(A,GA) GIM=GA GIP=0.0 ELSE IF (X.LE.1.0+A) THEN S=1.0D0/A R=S DO 10 K=1,60 R=R*X/(A+K) S=S+R IF (DABS(R/S).LT.1.0D-15) GO TO 15 10 CONTINUE 15 GIN=DEXP(XAM)*S CALL GAMMA(A,GA) GIP=GIN/GA GIM=GA-GIN ELSE IF (X.GT.1.0+A) THEN T0=0.0D0 DO 20 K=60,1,-1 T0=(K-A)/(1.0D0+K/(X+T0)) 20 CONTINUE GIM=DEXP(XAM)/(X+T0) CALL GAMMA(A,GA) GIN=GA-GIM GIP=1.0D0-GIM/GA ENDIF END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mitairy.for000077500000000000000000000116311321604176500263060ustar00rootroot00000000000000 PROGRAM MITAIRY C C =========================================================== C Purpose: This program computes the integrals of Airy C functions using subroutine ITAIRY C Input : x --- Upper limit of the integral C Output : APT --- Integration of Ai(t) from 0 and x C BPT --- Integration of Bi(t) from 0 and x C ANT --- Integration of Ai(-t) from 0 and x C BNT --- Integration of Bi(-t) from 0 and x C Example: C C x Ai(t)dt Bi(t)dt Ai(-t)dt Bi(-t)dt C ---------------------------------------------------------- C 5 .33328759 .32147832D+03 .71788220 .15873094 C 10 .33333333 .14780980D+09 .76569840 .01504043 C 15 .33333333 .49673090D+16 .68358063 .07202621 C 20 .33333333 .47447423D+25 .71173925 -.03906173 C 25 .33333333 .78920820D+35 .70489539 .03293190 C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,20) WRITE(*,30) CALL ITAIRY(X,APT,BPT,ANT,BNT) WRITE(*,10)X,APT,BPT,ANT,BNT 10 FORMAT(1X,F5.1,F14.8,2X,D15.8,2F14.8) 20 FORMAT(3X,'x',8X,'Ai(t)dt',7X,'Bi(t)dt',9X, & 'Ai(-t)dt',6X,'Bi(-t)dt') 30 FORMAT(2X,'----------------------------------', & '------------------------------') END SUBROUTINE ITAIRY(X,APT,BPT,ANT,BNT) C C ====================================================== C Purpose: Compute the integrals of Airy fnctions with C respect to t from 0 and x ( x ò 0 ) C Input : x --- Upper limit of the integral C Output : APT --- Integration of Ai(t) from 0 and x C BPT --- Integration of Bi(t) from 0 and x C ANT --- Integration of Ai(-t) from 0 and x C BNT --- Integration of Bi(-t) from 0 and x C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(16) EPS=1.0D-15 PI=3.141592653589793D0 C1=.355028053887817D0 C2=.258819403792807D0 SR3=1.732050807568877D0 IF (X.EQ.0.0D0) THEN APT=0.0D0 BPT=0.0D0 ANT=0.0D0 BNT=0.0D0 ELSE IF (DABS(X).LE.9.25D0) THEN DO 30 L=0,1 X=(-1)**L*X FX=X R=X DO 10 K=1,40 R=R*(3.0*K-2.0D0)/(3.0*K+1.0D0)*X/(3.0*K) & *X/(3.0*K-1.0D0)*X FX=FX+R IF (DABS(R).LT.DABS(FX)*EPS) GO TO 15 10 CONTINUE 15 GX=.5D0*X*X R=GX DO 20 K=1,40 R=R*(3.0*K-1.0D0)/(3.0*K+2.0D0)*X/(3.0*K) & *X/(3.0*K+1.0D0)*X GX=GX+R IF (DABS(R).LT.DABS(GX)*EPS) GO TO 25 20 CONTINUE 25 ANT=C1*FX-C2*GX BNT=SR3*(C1*FX+C2*GX) IF (L.EQ.0) THEN APT=ANT BPT=BNT ELSE ANT=-ANT BNT=-BNT X=-X ENDIF 30 CONTINUE ELSE DATA A/.569444444444444D0,.891300154320988D0, & .226624344493027D+01,.798950124766861D+01, & .360688546785343D+02,.198670292131169D+03, & .129223456582211D+04,.969483869669600D+04, & .824184704952483D+05,.783031092490225D+06, & .822210493622814D+07,.945557399360556D+08, & .118195595640730D+10,.159564653040121D+11, & .231369166433050D+12,.358622522796969D+13/ Q2=1.414213562373095D0 Q0=.3333333333333333D0 Q1=.6666666666666667D0 XE=X*DSQRT(X)/1.5D0 XP6=1.0D0/DSQRT(6.0D0*PI*XE) SU1=1.0D0 R=1.0D0 XR1=1.0D0/XE DO 35 K=1,16 R=-R*XR1 35 SU1=SU1+A(K)*R SU2=1.0D0 R=1.0D0 DO 40 K=1,16 R=R*XR1 40 SU2=SU2+A(K)*R APT=Q0-DEXP(-XE)*XP6*SU1 BPT=2.0D0*DEXP(XE)*XP6*SU2 SU3=1.0D0 R=1.0D0 XR2=1.0D0/(XE*XE) DO 45 K=1,8 R=-R*XR2 45 SU3=SU3+A(2*K)*R SU4=A(1)*XR1 R=XR1 DO 50 K=1,7 R=-R*XR2 50 SU4=SU4+A(2*K+1)*R SU5=SU3+SU4 SU6=SU3-SU4 ANT=Q1-Q2*XP6*(SU5*DCOS(XE)-SU6*DSIN(XE)) BNT=Q2*XP6*(SU5*DSIN(XE)+SU6*DCOS(XE)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mitika.for000077500000000000000000000064061321604176500261120ustar00rootroot00000000000000 PROGRAM MITIKA C C ============================================================ C Purpose: This program evaluates the integral of modified C Bessel functions I0(t) and K0(t) with respect to t C from 0 to x using subroutine ITIKA C Input : x --- Upper limit of the integral ( x ò 0 ) C Output: TI --- Integration of I0(t) from 0 to x C TK --- Integration of K0(t) from 0 to x C Example: C x I0(t)dt K0(t)dt C -------------------------------------- C 5.0 .31848668D+02 1.56738739 C 10.0 .29930445D+04 1.57077931 C 15.0 .35262048D+06 1.57079623 C 20.0 .44758593D+08 1.57079633 C 25.0 .58991731D+10 1.57079633 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x I0(t)dt K0(t)dt' WRITE(*,*)' --------------------------------------' CALL ITIKA(X,TI,TK) WRITE(*,10)X,TI,TK 10 FORMAT(1X,F5.1,D17.8,F15.8) END SUBROUTINE ITIKA(X,TI,TK) C C ======================================================= C Purpose: Integrate modified Bessel functions I0(t) and C K0(t) with respect to t from 0 to x C Input : x --- Upper limit of the integral ( x ò 0 ) C Output: TI --- Integration of I0(t) from 0 to x C TK --- Integration of K0(t) from 0 to x C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(10) PI=3.141592653589793D0 EL=.5772156649015329D0 DATA A/.625D0,1.0078125D0, & 2.5927734375D0,9.1868591308594D0, & 4.1567974090576D+1,2.2919635891914D+2, & 1.491504060477D+3,1.1192354495579D+4, & 9.515939374212D+4,9.0412425769041D+5/ IF (X.EQ.0.0D0) THEN TI=0.0D0 TK=0.0D0 RETURN ELSE IF (X.LT.20.0D0) THEN X2=X*X TI=1.0D0 R=1.0D0 DO 10 K=1,50 R=.25D0*R*(2*K-1.0D0)/(2*K+1.0D0)/(K*K)*X2 TI=TI+R IF (DABS(R/TI).LT.1.0D-12) GO TO 15 10 CONTINUE 15 TI=TI*X ELSE TI=1.0D0 R=1.0D0 DO 20 K=1,10 R=R/X 20 TI=TI+A(K)*R RC1=1.0D0/DSQRT(2.0D0*PI*X) TI=RC1*DEXP(X)*TI ENDIF IF (X.LT.12.0D0) THEN E0=EL+DLOG(X/2.0D0) B1=1.0D0-E0 B2=0.0D0 RS=0.0D0 R=1.0D0 DO 25 K=1,50 R=.25D0*R*(2*K-1.0D0)/(2*K+1.0D0)/(K*K)*X2 B1=B1+R*(1.0D0/(2*K+1)-E0) RS=RS+1.0D0/K B2=B2+R*RS TK=B1+B2 IF (DABS((TK-TW)/TK).LT.1.0D-12) GO TO 30 25 TW=TK 30 TK=TK*X ELSE TK=1.0D0 R=1.0D0 DO 35 K=1,10 R=-R/X 35 TK=TK+A(K)*R RC2=DSQRT(PI/(2.0D0*X)) TK=PI/2.0D0-RC2*TK*DEXP(-X) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mitikb.for000077500000000000000000000067541321604176500261210ustar00rootroot00000000000000 PROGRAM MITIKB C C ============================================================ C Purpose: This program evaluates the integral of modified C Bessel functions I0(t) and K0(t) with respect to t C from 0 to x using subroutine ITIKB C Input : x --- Upper limit of the integral ( x ò 0 ) C Output: TI --- Integration of I0(t) from 0 to x C TK --- Integration of K0(t) from 0 to x C Example: C x I0(t)dt K0(t)dt C ------------------------------------- C 5.0 .318487D+02 1.567387 C 10.0 .299305D+04 1.570779 C 15.0 .352619D+06 1.570796 C 20.0 .447586D+08 1.570796 C 25.0 .589919D+10 1.570796 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x I0(t)dt K0(t)dt' WRITE(*,*)'--------------------------------------' CALL ITIKB(X,TI,TK) WRITE(*,10)X,TI,TK 10 FORMAT(1X,F5.1,D16.6,F15.6) END SUBROUTINE ITIKB(X,TI,TK) C C ======================================================= C Purpose: Integrate Bessel functions I0(t) and K0(t) C with respect to t from 0 to x C Input : x --- Upper limit of the integral ( x ò 0 ) C Output: TI --- Integration of I0(t) from 0 to x C TK --- Integration of K0(t) from 0 to x C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 IF (X.EQ.0.0D0) THEN TI=0.0D0 ELSE IF (X.LT.5.0D0) THEN T1=X/5.0D0 T=T1*T1 TI=((((((((.59434D-3*T+.4500642D-2)*T & +.044686921D0)*T+.300704878D0)*T+1.471860153D0) & *T+4.844024624D0)*T+9.765629849D0)*T & +10.416666367D0)*T+5.0D0)*T1 ELSE IF (X.GE.5.0.AND.X.LE.8.0D0) THEN T=5.0D0/X TI=(((-.015166D0*T-.0202292D0)*T+.1294122D0)*T & -.0302912D0)*T+.4161224D0 TI=TI*DEXP(X)/DSQRT(X) ELSE T=8.0D0/X TI=(((((-.0073995D0*T+.017744D0)*T-.0114858D0)*T & +.55956D-2)*T+.59191D-2)*T+.0311734D0)*T & +.3989423D0 TI=TI*DEXP(X)/DSQRT(X) ENDIF IF (X.EQ.0.0D0) THEN TK=0.0D0 ELSE IF (X.LE.2.0D0) THEN T1=X/2.0D0 T=T1*T1 TK=((((((.116D-5*T+.2069D-4)*T+.62664D-3)*T & +.01110118D0)*T+.11227902D0)*T+.50407836D0)*T & +.84556868D0)*T1 TK=TK-DLOG(X/2.0D0)*TI ELSE IF (X.GT.2.0.AND.X.LE.4.0D0) THEN T=2.0D0/X TK=(((.0160395D0*T-.0781715D0)*T+.185984D0)*T & -.3584641D0)*T+1.2494934D0 TK=PI/2.0D0-TK*DEXP(-X)/DSQRT(X) ELSE IF (X.GT.4.0.AND.X.LE.7.0D0) THEN T=4.0D0/X TK=(((((.37128D-2*T-.0158449D0)*T+.0320504D0)*T & -.0481455D0)*T+.0787284D0)*T-.1958273D0)*T & +1.2533141D0 TK=PI/2.0D0-TK*DEXP(-X)/DSQRT(X) ELSE T=7.0D0/X TK=(((((.33934D-3*T-.163271D-2)*T+.417454D-2)*T & -.933944D-2)*T+.02576646D0)*T-.11190289D0)*T & +1.25331414D0 TK=PI/2.0D0-TK*DEXP(-X)/DSQRT(X) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mitjya.for000077500000000000000000000063561321604176500261350ustar00rootroot00000000000000 PROGRAM MITJYA C C =========================================================== C Purpose: This program evaluates the integral of Bessel C functions J0(t) and Y0(t) with respect to t C from 0 to x using subroutine ITJYA C Input : x --- Upper limit of the integral ( x ò 0 ) C Output: TJ --- Integration of J0(t) from 0 to x C TY --- Integration of Y0(t) from 0 to x C Example: C x J0(t)dt Y0(t)dt C --------------------------------------- C 5.0 .71531192 .19971938 C 10.0 1.06701130 .24129032 C 15.0 1.20516194 .00745772 C 20.0 1.05837882 -.16821598 C 25.0 .87101492 -.09360793 C 30.0 .88424909 .08822971 C =========================================================== C DOUBLE PRECISION X,TJ,TY WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x J0(t)dt Y0(t)dt' WRITE(*,*)'---------------------------------------' CALL ITJYA(X,TJ,TY) WRITE(*,10)X,TJ,TY 10 FORMAT(1X,F5.1,2F16.8) END SUBROUTINE ITJYA(X,TJ,TY) C C ========================================================== C Purpose: Integrate Bessel functions J0(t) & Y0(t) with C respect to t from 0 to x C Input : x --- Upper limit of the integral ( x ò 0 ) C Output: TJ --- Integration of J0(t) from 0 to x C TY --- Integration of Y0(t) from 0 to x C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(18) PI=3.141592653589793D0 EL=.5772156649015329D0 EPS=1.0D-12 IF (X.EQ.0.0D0) THEN TJ=0.0D0 TY=0.0D0 ELSE IF (X.LE.20.0D0) THEN X2=X*X TJ=X R=X DO 10 K=1,60 R=-.25D0*R*(2*K-1.0D0)/(2*K+1.0D0)/(K*K)*X2 TJ=TJ+R IF (DABS(R).LT.DABS(TJ)*EPS) GO TO 15 10 CONTINUE 15 TY1=(EL+DLOG(X/2.0D0))*TJ RS=0.0D0 TY2=1.0D0 R=1.0D0 DO 20 K=1,60 R=-.25D0*R*(2*K-1.0D0)/(2*K+1.0D0)/(K*K)*X2 RS=RS+1.0D0/K R2=R*(RS+1.0D0/(2.0D0*K+1.0D0)) TY2=TY2+R2 IF (DABS(R2).LT.DABS(TY2)*EPS) GO TO 25 20 CONTINUE 25 TY=(TY1-X*TY2)*2.0D0/PI ELSE A0=1.0D0 A1=5.0D0/8.0D0 A(1)=A1 DO 30 K=1,16 AF=((1.5D0*(K+.5D0)*(K+5.0D0/6.0D0)*A1-.5D0 & *(K+.5D0)*(K+.5D0)*(K-.5D0)*A0))/(K+1.0D0) A(K+1)=AF A0=A1 30 A1=AF BF=1.0D0 R=1.0D0 DO 35 K=1,8 R=-R/(X*X) 35 BF=BF+A(2*K)*R BG=A(1)/X R=1.0D0/X DO 40 K=1,8 R=-R/(X*X) 40 BG=BG+A(2*K+1)*R XP=X+.25D0*PI RC=DSQRT(2.0D0/(PI*X)) TJ=1.0D0-RC*(BF*DCOS(XP)+BG*DSIN(XP)) TY=RC*(BG*DCOS(XP)-BF*DSIN(XP)) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mitjyb.for000077500000000000000000000065751321604176500261410ustar00rootroot00000000000000 PROGRAM MITJYB C C =========================================================== C Purpose: This program evaluates the integral of Bessel C functions J0(t) and Y0(t) with respect to t C from 0 to x using subroutine ITJYB C Input : x --- Upper limit of the integral ( x ò 0 ) C Output: TJ --- Integration of J0(t) from 0 to x C TY --- Integration of Y0(t) from 0 to x C Example: C x J0(t)dt Y0(t)dt C --------------------------------------- C 5.0 .71531192 .19971938 C 10.0 1.06701130 .24129032 C 15.0 1.20516194 .00745772 C 20.0 1.05837882 -.16821598 C 25.0 .87101492 -.09360793 C 30.0 .88424909 .08822971 C =========================================================== C DOUBLE PRECISION X,TJ,TY WRITE(*,*)'Pleas enter x ' READ(*,*)X WRITE(*,*)' x J0(t)dt Y0(t)dt' WRITE(*,*)'---------------------------------------' CALL ITJYB(X,TJ,TY) WRITE(*,10)X,TJ,TY 10 FORMAT(1X,F5.1,2F16.8) END SUBROUTINE ITJYB(X,TJ,TY) C C ======================================================= C Purpose: Integrate Bessel functions J0(t) and Y0(t) C with respect to t from 0 to x ( x ò 0 ) C Input : x --- Upper limit of the integral C Output: TJ --- Integration of J0(t) from 0 to x C TY --- Integration of Y0(t) from 0 to x C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 IF (X.EQ.0.0D0) THEN TJ=0.0D0 TY=0.0D0 ELSE IF (X.LE.4.0D0) THEN X1=X/4.0D0 T=X1*X1 TJ=(((((((-.133718D-3*T+.2362211D-2)*T & -.025791036D0)*T+.197492634D0)*T-1.015860606D0) & *T+3.199997842D0)*T-5.333333161D0)*T+4.0D0)*X1 TY=((((((((.13351D-4*T-.235002D-3)*T+.3034322D-2)* & T-.029600855D0)*T+.203380298D0)*T-.904755062D0) & *T+2.287317974D0)*T-2.567250468D0)*T & +1.076611469D0)*X1 TY=2.0D0/PI*DLOG(X/2.0D0)*TJ-TY ELSE IF (X.LE.8.0D0) THEN XT=X-.25D0*PI T=16.0D0/(X*X) F0=((((((.1496119D-2*T-.739083D-2)*T+.016236617D0) & *T-.022007499D0)*T+.023644978D0) & *T-.031280848D0)*T+.124611058D0)*4.0D0/X G0=(((((.1076103D-2*T-.5434851D-2)*T+.01242264D0) & *T-.018255209)*T+.023664841D0)*T-.049635633D0) & *T+.79784879D0 TJ=1.0D0-(F0*DCOS(XT)-G0*DSIN(XT))/DSQRT(X) TY=-(F0*DSIN(XT)+G0*DCOS(XT))/DSQRT(X) ELSE T=64.0D0/(X*X) XT=X-.25D0*PI F0=(((((((-.268482D-4*T+.1270039D-3)*T & -.2755037D-3)*T+.3992825D-3)*T-.5366169D-3)*T & +.10089872D-2)*T-.40403539D-2)*T+.0623347304D0) & *8.0D0/X G0=((((((-.226238D-4*T+.1107299D-3)*T-.2543955D-3) & *T+.4100676D-3)*T-.6740148D-3)*T+.17870944D-2) & *T-.01256424405D0)*T+.79788456D0 TJ=1.0D0-(F0*DCOS(XT)-G0*DSIN(XT))/DSQRT(X) TY=-(F0*DSIN(XT)+G0*DCOS(XT))/DSQRT(X) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mitsh0.for000077500000000000000000000054701321604176500260400ustar00rootroot00000000000000 PROGRAM MITSH0 C C ==================================================== C Purpose: This program evaluates the integral of C Struve function H0(t) with respect to t C from 0 and x using subroutine ITSH0 C Input : x --- Upper limit ( x ò 0 ) C Output: TH0 --- Integration of H0(t) from 0 and x C Example: C x H0(t)dt C ---------------------- C 0.0 .0000000 C 5.0 2.0442437 C 10.0 2.5189577 C 15.0 2.5415824 C 20.0 2.5484517 C 30.0 3.0625848 C 40.0 3.1484123 C 50.0 3.2445168 C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x H0(t)dt' WRITE(*,*)'----------------------Ä' CALL ITSH0(X,TH0) WRITE(*,10)X,TH0 10 FORMAT(1X,F5.1,E16.7) END SUBROUTINE ITSH0(X,TH0) C C =================================================== C Purpose: Evaluate the integral of Struve function C H0(t) with respect to t from 0 and x C Input : x --- Upper limit ( x ò 0 ) C Output: TH0 --- Integration of H0(t) from 0 and x C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(25) PI=3.141592653589793D0 R=1.0D0 IF (X.LE.30.0) THEN S=0.5D0 DO 10 K=1,100 RD=1.0D0 IF (K.EQ.1) RD=0.5D0 R=-R*RD*K/(K+1.0D0)*(X/(2.0D0*K+1.0D0))**2 S=S+R IF (DABS(R).LT.DABS(S)*1.0D-12) GO TO 15 10 CONTINUE 15 TH0=2.0D0/PI*X*X*S ELSE S=1.0D0 DO 20 K=1,12 R=-R*K/(K+1.0D0)*((2.0D0*K+1.0D0)/X)**2 S=S+R IF (DABS(R).LT.DABS(S)*1.0D-12) GO TO 25 20 CONTINUE 25 EL=.57721566490153D0 S0=S/(PI*X*X)+2.0D0/PI*(DLOG(2.0D0*X)+EL) A0=1.0D0 A1=5.0D0/8.0D0 A(1)=A1 DO 30 K=1,20 AF=((1.5D0*(K+.5D0)*(K+5.0D0/6.0D0)*A1-.5D0 & *(K+.5D0)*(K+.5D0)*(K-.5D0)*A0))/(K+1.0D0) A(K+1)=AF A0=A1 30 A1=AF BF=1.0D0 R=1.0D0 DO 35 K=1,10 R=-R/(X*X) 35 BF=BF+A(2*K)*R BG=A(1)/X R=1.0D0/X DO 40 K=1,10 R=-R/(X*X) 40 BG=BG+A(2*K+1)*R XP=X+.25D0*PI TY=DSQRT(2.0D0/(PI*X))*(BG*DCOS(XP)-BF*DSIN(XP)) TH0=TY+S0 ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mitsl0.for000077500000000000000000000052471321604176500260460ustar00rootroot00000000000000 PROGRAM MITSL0 C C =========================================================== C Purpose: This program evaluates the integral of modified C Struve function L0(t) with respect to t from 0 C to x using subroutine ITSL0 C Input : x --- Upper limit ( x ò 0 ) C Output: TL0 --- Integration of L0(t) from 0 to x C Example: C x L0(t)dt C ----------------------- C 0.0 .0000000D+00 C 5.0 .3003079D+02 C 10.0 .2990773D+04 C 15.0 .3526179D+06 C 20.0 .4475860D+08 C 30.0 .7955389D+12 C 40.0 .1508972D+17 C 50.0 .2962966D+21 C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x L0(t)dt' WRITE(*,*)'-----------------------' CALL ITSL0(X,TL0) WRITE(*,10)X,TL0 10 FORMAT(1X,F5.1,D16.7) END SUBROUTINE ITSL0(X,TL0) C C =========================================================== C Purpose: Evaluate the integral of modified Struve function C L0(t) with respect to t from 0 to x C Input : x --- Upper limit ( x ò 0 ) C Output: TL0 --- Integration of L0(t) from 0 to x C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(18) PI=3.141592653589793D0 R=1.0D0 IF (X.LE.20.0) THEN S=0.5D0 DO 10 K=1,100 RD=1.0D0 IF (K.EQ.1) RD=0.5D0 R=R*RD*K/(K+1.0D0)*(X/(2.0D0*K+1.0D0))**2 S=S+R IF (DABS(R/S).LT.1.0D-12) GO TO 15 10 CONTINUE 15 TL0=2.0D0/PI*X*X*S ELSE S=1.0D0 DO 20 K=1,10 R=R*K/(K+1.0D0)*((2.0D0*K+1.0D0)/X)**2 S=S+R IF (DABS(R/S).LT.1.0D-12) GO TO 25 20 CONTINUE 25 EL=.57721566490153D0 S0=-S/(PI*X*X)+2.0D0/PI*(DLOG(2.0D0*X)+EL) A0=1.0D0 A1=5.0D0/8.0D0 A(1)=A1 DO 30 K=1,10 AF=((1.5D0*(K+.50D0)*(K+5.0D0/6.0D0)*A1-.5D0* & (K+.5D0)**2*(K-.5D0)*A0))/(K+1.0D0) A(K+1)=AF A0=A1 30 A1=AF TI=1.0D0 R=1.0D0 DO 35 K=1,11 R=R/X 35 TI=TI+A(K)*R TL0=TI/DSQRT(2*PI*X)*DEXP(X)+S0 ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mitth0.for000077500000000000000000000046671321604176500260500ustar00rootroot00000000000000 PROGRAM MITTH0 C C =========================================================== C Purpose: This program evaluates the integral of H0(t)/t C with respect to t from x to infinity using C subroutine ITTH0 C Input : x --- Lower limit ( x ò 0 ) C Output: TTH --- Integration of H0(t)/t from x to infinity C Example: C x H0(t)/t dt C ----------------------- C 0.0 1.57079633 C 5.0 .07954575 C 10.0 .04047175 C 15.0 .04276558 C 20.0 .04030796 C 30.0 .01815256 C 40.0 .01621331 C 50.0 .01378661 C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*) ' x H0(t)/t dt' WRITE(*,*)'-----------------------' CALL ITTH0(X,TTH) WRITE(*,10)X,TTH 10 FORMAT(1X,F5.1,1X,E16.8) END SUBROUTINE ITTH0(X,TTH) C C =========================================================== C Purpose: Evaluate the integral H0(t)/t with respect to t C from x to infinity C Input : x --- Lower limit ( x ò 0 ) C Output: TTH --- Integration of H0(t)/t from x to infinity C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 S=1.0D0 R=1.0D0 IF (X.LT.24.5D0) THEN DO 10 K=1,60 R=-R*X*X*(2.0*K-1.0D0)/(2.0*K+1.0D0)**3 S=S+R IF (DABS(R).LT.DABS(S)*1.0D-12) GO TO 15 10 CONTINUE 15 TTH=PI/2.0D0-2.0D0/PI*X*S ELSE DO 20 K=1,10 R=-R*(2.0*K-1.0D0)**3/((2.0*K+1.0D0)*X*X) S=S+R IF (DABS(R).LT.DABS(S)*1.0D-12) GO TO 25 20 CONTINUE 25 TTH=2.0D0/(PI*X)*S T=8.0D0/X XT=X+.25D0*PI F0=(((((.18118D-2*T-.91909D-2)*T+.017033D0)*T & -.9394D-3)*T-.051445D0)*T-.11D-5)*T+.7978846D0 G0=(((((-.23731D-2*T+.59842D-2)*T+.24437D-2)*T & -.0233178D0)*T+.595D-4)*T+.1620695D0)*T TTY=(F0*DSIN(XT)-G0*DCOS(XT))/(DSQRT(X)*X) TTH=TTH+TTY ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mittika.for000077500000000000000000000064311321604176500262740ustar00rootroot00000000000000 PROGRAM MITTIKA C C ============================================================ C Purpose: This program computes the integral of [I0(t)-1]/t C with respect to t from 0 to x and K0(t)/t with C respect to t from x to ì using subroutine ITTIKA C Input : x --- Variable in the limits ( x ò 0 ) C Output: TTI --- Integration of [I0(t)-1]/t from 0 to x C TTK --- Integration of K0(t)/t from x to ì C Example: C x [1-I0(t)]/tdt K0(t)/tdt C --------------------------------------- C 5.0 .71047763D+01 .58635626D-03 C 10.0 .34081537D+03 .15629282D-05 C 15.0 .25437619D+05 .59837472D-08 C 20.0 .23673661D+07 .26790545D-10 C 25.0 .24652751D+09 .13100706D-12 C ============================================================ C DOUBLE PRECISION X,TTI,TTK WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x [1-I0(t)]/tdt K0(t)/tdt' WRITE(*,*)'---------------------------------------' CALL ITTIKA(X,TTI,TTK) WRITE(*,10)X,TTI,TTK 10 FORMAT(1X,F5.1,2D16.8) END SUBROUTINE ITTIKA(X,TTI,TTK) C C ========================================================= C Purpose: Integrate [I0(t)-1]/t with respect to t from 0 C to x, and K0(t)/t with respect to t from x to ì C Input : x --- Variable in the limits ( x ò 0 ) C Output: TTI --- Integration of [I0(t)-1]/t from 0 to x C TTK --- Integration of K0(t)/t from x to ì C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION C(8) PI=3.141592653589793D0 EL=.5772156649015329D0 DATA C/1.625D0,4.1328125D0, & 1.45380859375D+1,6.553353881835D+1, & 3.6066157150269D+2,2.3448727161884D+3, & 1.7588273098916D+4,1.4950639538279D+5/ IF (X.EQ.0.0D0) THEN TTI=0.0D0 TTK=1.0D+300 RETURN ENDIF IF (X.LT.40.0D0) THEN TTI=1.0D0 R=1.0D0 DO 10 K=2,50 R=.25D0*R*(K-1.0D0)/(K*K*K)*X*X TTI=TTI+R IF (DABS(R/TTI).LT.1.0D-12) GO TO 15 10 CONTINUE 15 TTI=TTI*.125D0*X*X ELSE TTI=1.0D0 R=1.0D0 DO 20 K=1,8 R=R/X 20 TTI=TTI+C(K)*R RC=X*DSQRT(2.0D0*PI*X) TTI=TTI*DEXP(X)/RC ENDIF IF (X.LE.12.0D0) THEN E0=(.5D0*DLOG(X/2.0D0)+EL)*DLOG(X/2.0D0) & +PI*PI/24.0D0+.5D0*EL*EL B1=1.5D0-(EL+DLOG(X/2.0D0)) RS=1.0D0 R=1.0D0 DO 25 K=2,50 R=.25D0*R*(K-1.0D0)/(K*K*K)*X*X RS=RS+1.0D0/K R2=R*(RS+1.0D0/(2.0D0*K)-(EL+DLOG(X/2.0D0))) B1=B1+R2 IF (DABS(R2/B1).LT.1.0D-12) GO TO 30 25 CONTINUE 30 TTK=E0-.125D0*X*X*B1 ELSE TTK=1.0D0 R=1.0D0 DO 35 K=1,8 R=-R/X 35 TTK=TTK+C(K)*R RC=X*DSQRT(2.0D0/PI*X) TTK=TTK*DEXP(-X)/RC ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mittikb.for000077500000000000000000000062471321604176500263020ustar00rootroot00000000000000 PROGRAM MITTIKB C C ============================================================ C Purpose: This program computes the integral of [I0(t)-1]/t C with respect to t from 0 to x and K0(t)/t with C respect to t from x to ì using subroutine ITTIKB C Input : x --- Upper limit of the integral C Output: TTI --- Integration of [I0(t)-1]/t from 0 to x C TTK --- Integration of K0(t)/t from x to ì C Example: C x [1-I0(t)]/tdt K0(t)/tdt C --------------------------------------- C 5.0 .710478D+01 .586361D-03 C 10.0 .340811D+03 .156293D-05 C 15.0 .254373D+05 .598363D-08 C 20.0 .236735D+07 .267906D-10 C 25.0 .246534D+09 .131007D-12 C ============================================================ C DOUBLE PRECISION X,TTI,TTK WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x [1-I0(t)]/tdt K0(t)/tdt' WRITE(*,*)'---------------------------------------' CALL ITTIKB(X,TTI,TTK) WRITE(*,10)X,TTI,TTK 10 FORMAT(1X,F5.1,2D16.6) END SUBROUTINE ITTIKB(X,TTI,TTK) C C ========================================================= C Purpose: Integrate [I0(t)-1]/t with respect to t from 0 C to x, and K0(t)/t with respect to t from x to ì C Input : x --- Variable in the limits ( x ò 0 ) C Output: TTI --- Integration of [I0(t)-1]/t from 0 to x C TTK --- Integration of K0(t)/t from x to ì C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 EL=.5772156649015329D0 IF (X.EQ.0.0D0) THEN TTI=0.0D0 ELSE IF (X.LE.5.0D0) THEN X1=X/5.0D0 T=X1*X1 TTI=(((((((.1263D-3*T+.96442D-3)*T+.968217D-2)*T & +.06615507D0)*T+.33116853D0)*T+1.13027241D0) & *T+2.44140746D0)*T+3.12499991D0)*T ELSE T=5.0D0/X TTI=(((((((((2.1945464D0*T-3.5195009D0)*T & -11.9094395D0)*T+40.394734D0)*T-48.0524115D0) & *T+28.1221478D0)*T-8.6556013D0)*T+1.4780044D0) & *T-.0493843D0)*T+.1332055D0)*T+.3989314D0 TTI=TTI*DEXP(X)/(DSQRT(X)*X) ENDIF IF (X.EQ.0.0D0) THEN TTK=1.0D+300 ELSE IF (X.LE.2.0D0) THEN T1=X/2.0D0 T=T1*T1 TTK=(((((.77D-6*T+.1544D-4)*T+.48077D-3)*T & +.925821D-2)*T+.10937537D0)*T+.74999993D0)*T E0=EL+DLOG(X/2.0D0) TTK=PI*PI/24.0D0+E0*(.5D0*E0+TTI)-TTK ELSE IF (X.LE.4.0D0) THEN T=2.0D0/X TTK=(((.06084D0*T-.280367D0)*T+.590944D0)*T & -.850013D0)*T+1.234684D0 TTK=TTK*DEXP(-X)/(DSQRT(X)*X) ELSE T=4.0D0/X TTK=(((((.02724D0*T-.1110396D0)*T+.2060126D0)*T & -.2621446D0)*T+.3219184D0)*T-.5091339D0)*T & +1.2533141D0 TTK=TTK*DEXP(-X)/(DSQRT(X)*X) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mittjya.for000077500000000000000000000100641321604176500263100ustar00rootroot00000000000000 PROGRAM MITTJYA C C =========================================================== C Purpose: This program computes the integral of [1-J0(t)]/t C with respect to t from 0 to x and Y0(t)/t with C respect to t from x to ì using subroutine ITTJYA C Input : x --- Variable in the limits ( x ò 0 ) C Output: TTJ --- Integration of [1-J0(t)]/t from 0 to x C TTY --- Integration of Y0(t)/t from x to ì C Example: C x [1-J0(t)]/tdt Y0(t)/tdt C ------------------------------------------- C 5.0 .15403472D+01 -.46322055D-01 C 10.0 .21778664D+01 -.22987934D-01 C 15.0 .25785507D+01 .38573574D-03 C 20.0 .28773106D+01 .85031527D-02 C 25.0 .31082313D+01 .35263393D-02 C =========================================================== C DOUBLE PRECISION X,TTJ,TTY WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x [1-J0(t)]/tdt Y0(t)/tdt' WRITE(*,*)'-------------------------------------------' CALL ITTJYA(X,TTJ,TTY) WRITE(*,10)X,TTJ,TTY 10 FORMAT(1X,F5.1,2D18.8) END SUBROUTINE ITTJYA(X,TTJ,TTY) C C ========================================================= C Purpose: Integrate [1-J0(t)]/t with respect to t from 0 C to x, and Y0(t)/t with respect to t from x to ì C Input : x --- Variable in the limits ( x ò 0 ) C Output: TTJ --- Integration of [1-J0(t)]/t from 0 to x C TTY --- Integration of Y0(t)/t from x to ì C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 EL=.5772156649015329D0 IF (X.EQ.0.0D0) THEN TTJ=0.0D0 TTY=-1.0D+300 ELSE IF (X.LE.20.0D0) THEN TTJ=1.0D0 R=1.0D0 DO 10 K=2,100 R=-.25D0*R*(K-1.0D0)/(K*K*K)*X*X TTJ=TTJ+R IF (DABS(R).LT.DABS(TTJ)*1.0D-12) GO TO 15 10 CONTINUE 15 TTJ=TTJ*.125D0*X*X E0=.5D0*(PI*PI/6.0D0-EL*EL)-(.5D0*DLOG(X/2.0D0)+EL) & *DLOG(X/2.0D0) B1=EL+DLOG(X/2.0D0)-1.5D0 RS=1.0D0 R=-1.0D0 DO 20 K=2,100 R=-.25D0*R*(K-1.0D0)/(K*K*K)*X*X RS=RS+1.0D0/K R2=R*(RS+1.0D0/(2.0D0*K)-(EL+DLOG(X/2.0D0))) B1=B1+R2 IF (DABS(R2).LT.DABS(B1)*1.0D-12) GO TO 25 20 CONTINUE 25 TTY=2.0D0/PI*(E0+.125D0*X*X*B1) ELSE A0=DSQRT(2.0D0/(PI*X)) DO 50 L=0,1 VT=4.0D0*L*L PX=1.0D0 R=1.0D0 DO 30 K=1,14 R=-.0078125D0*R*(VT-(4.0D0*K-3.0D0)**2) & /(X*K)*(VT-(4.0D0*K-1.0D0)**2) & /((2.0D0*K-1.0D0)*X) PX=PX+R IF (DABS(R).LT.DABS(PX)*1.0D-12) GO TO 35 30 CONTINUE 35 QX=1.0D0 R=1.0D0 DO 40 K=1,14 R=-.0078125D0*R*(VT-(4.0D0*K-1.0D0)**2) & /(X*K)*(VT-(4.0D0*K+1.0D0)**2) & /(2.0D0*K+1.0D0)/X QX=QX+R IF (DABS(R).LT.DABS(QX)*1.0D-12) GO TO 45 40 CONTINUE 45 QX=.125D0*(VT-1.0D0)/X*QX XK=X-(.25D0+.5D0*L)*PI BJ1=A0*(PX*DCOS(XK)-QX*DSIN(XK)) BY1=A0*(PX*DSIN(XK)+QX*DCOS(XK)) IF (L.EQ.0) THEN BJ0=BJ1 BY0=BY1 ENDIF 50 CONTINUE T=2.0D0/X G0=1.0D0 R0=1.0D0 DO 55 K=1,10 R0=-K*K*T*T*R0 55 G0=G0+R0 G1=1.0D0 R1=1.0D0 DO 60 K=1,10 R1=-K*(K+1.0D0)*T*T*R1 60 G1=G1+R1 TTJ=2.0D0*G1*BJ0/(X*X)-G0*BJ1/X+EL+DLOG(X/2.0D0) TTY=2.0D0*G1*BY0/(X*X)-G0*BY1/X ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mittjyb.for000077500000000000000000000065611321604176500263200ustar00rootroot00000000000000 PROGRAM MITTJYB C C =========================================================== C Purpose: This program computes the integral of [1-J0(t)]/t C with respect to t from 0 to x and Y0(t)/t with C respect to t from x to ì using subroutine ITTJYB C Input : x --- Variable in the limits ( x ò 0 ) C Output: TTJ --- Integration of [1-J0(t)]/t from 0 to x C TTY --- Integration of Y0(t)/t from x to ì C Example: C x [1-J0(t)]/tdt Y0(t)/tdt C ---------------------------------------- C 5.0 .1540347D+01 -.4632208D-01 C 10.0 .2177866D+01 -.2298791D-01 C 15.0 .2578551D+01 .3857453D-03 C 20.0 .2877311D+01 .8503154D-02 C 25.0 .3108231D+01 .3526339D-02 C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x [1-J0(t)]/tdt Y0(t)/tdt' WRITE(*,*)'----------------------------------------' CALL ITTJYB(X,TTJ,TTY) WRITE(*,10)X,TTJ,TTY 10 FORMAT(1X,F5.1,2D17.7) END SUBROUTINE ITTJYB(X,TTJ,TTY) C C ========================================================== C Purpose: Integrate [1-J0(t)]/t with respect to t from 0 C to x, and Y0(t)/t with respect to t from x to ì C Input : x --- Variable in the limits ( x ò 0 ) C Output: TTJ --- Integration of [1-J0(t)]/t from 0 to x C TTY --- Integration of Y0(t)/t from x to ì C ========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 EL=.5772156649015329D0 IF (X.EQ.0.0D0) THEN TTJ=0.0D0 TTY=-1.0D+300 ELSE IF (X.LE.4.0D0) THEN X1=X/4.0D0 T=X1*X1 TTJ=((((((.35817D-4*T-.639765D-3)*T+.7092535D-2)*T & -.055544803D0)*T+.296292677D0)*T-.999999326D0) & *T+1.999999936D0)*T TTY=(((((((-.3546D-5*T+.76217D-4)*T-.1059499D-2)*T & +.010787555D0)*T-.07810271D0)*T+.377255736D0) & *T-1.114084491D0)*T+1.909859297D0)*T E0=EL+DLOG(X/2.0D0) TTY=PI/6.0D0+E0/PI*(2.0D0*TTJ-E0)-TTY ELSE IF (X.LE.8.0D0) THEN XT=X+.25D0*PI T1=4.0D0/X T=T1*T1 F0=(((((.0145369D0*T-.0666297D0)*T+.1341551D0)*T & -.1647797D0)*T+.1608874D0)*T-.2021547D0)*T & +.7977506D0 G0=((((((.0160672D0*T-.0759339D0)*T+.1576116D0)*T & -.1960154D0)*T+.1797457D0)*T-.1702778D0)*T & +.3235819D0)*T1 TTJ=(F0*DCOS(XT)+G0*DSIN(XT))/(DSQRT(X)*X) TTJ=TTJ+EL+DLOG(X/2.0D0) TTY=(F0*DSIN(XT)-G0*DCOS(XT))/(DSQRT(X)*X) ELSE T=8.0D0/X XT=X+.25D0*PI F0=(((((.18118D-2*T-.91909D-2)*T+.017033D0)*T & -.9394D-3)*T-.051445D0)*T-.11D-5)*T+.7978846D0 G0=(((((-.23731D-2*T+.59842D-2)*T+.24437D-2)*T & -.0233178D0)*T+.595D-4)*T+.1620695D0)*T TTJ=(F0*DCOS(XT)+G0*DSIN(XT))/(DSQRT(X)*X) & +EL+DLOG(X/2.0D0) TTY=(F0*DSIN(XT)-G0*DCOS(XT))/(DSQRT(X)*X) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mjdzo.for000077500000000000000000000167051321604176500257620ustar00rootroot00000000000000 PROGRAM MJDZO C C ============================================================= C Purpose: This program computes the zeros of Bessel functions C Jn(x) and Jn'(x), and arranges them in the order C of their values C Input : NT --- Number of total zeros ( NT ó 1200 ) C Output: ZO(L) --- Value of the L-th zero of Jn(x) and C Jn'(x) C N(L) --- n, order of Jn(x) or Jn'(x) associated C with the L-th zero C M(L) --- m, serial number of the zeros of Jn(x) C or Jn'(x) associated with the L-th zero C ( L is the serial number of all the C zeros of Jn(x) and Jn'(x) ) C P(L) --- TM or TE, a code for designating the C zeros of Jn(x) or Jn'(x) C In the waveguide applications, the zeros C of Jn(x) correspond to TM modes and those C of Jn'(x) correspond to TE modes. C ============================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) CHARACTER P(1400)*4 DIMENSION N(1400),M(1400),ZO(1400) WRITE(*,*)'NT=?' READ(*,*)NT WRITE(*,60)NT WRITE(*,70) CALL JDZO(NT,N,M,P,ZO) WRITE(*,*) KS=NT/101+1 DO 55 K0=1,KS WRITE(*,*)' Table Zeros of Bessel', & ' functions Jn(x) and Jn''(x)' WRITE(*,*) WRITE(*,*)' ----------------------------------', & '----------------------------------' DO 50 K=1,50 J1=100*(K0-1)+K+1 J2=J1+50 IF (J1.LE.NT+1.AND.J2.LE.NT+1) THEN WRITE(*,65)J1-1,P(J1),N(J1),M(J1),ZO(J1), & J2-1,P(J2),N(J2),M(J2),ZO(J2) ELSE IF (J1.LE.NT+1.AND.J2.GT.NT+1) THEN WRITE(*,65)J1-1,P(J1),N(J1),M(J1),ZO(J1) ENDIF 50 CONTINUE WRITE(*,*)' ----------------------------------', & '----------------------------------' WRITE(*,75) 55 CONTINUE 60 FORMAT(1X,'Total number of the zeros:',I5) 65 FORMAT(1X,I4,3X,A2,I4,2H -,I2,F14.8,3X,1H|,2X,I4, & 3X,A2,I4,2H -,I2,F14.8) 70 FORMAT(15X,'*** Please wait ! The program is running ***') 75 FORMAT(/) END SUBROUTINE JDZO(NT,N,M,P,ZO) C C =========================================================== C Purpose: Compute the zeros of Bessel functions Jn(x) and C Jn'(x), and arrange them in the order of their C magnitudes C Input : NT --- Number of total zeros ( NT ó 1200 ) C Output: ZO(L) --- Value of the L-th zero of Jn(x) C and Jn'(x) C N(L) --- n, order of Jn(x) or Jn'(x) associated C with the L-th zero C M(L) --- m, serial number of the zeros of Jn(x) C or Jn'(x) associated with the L-th zero C ( L is the serial number of all the C zeros of Jn(x) and Jn'(x) ) C P(L) --- TM or TE, a code for designating the C zeros of Jn(x) or Jn'(x). C In the waveguide applications, the zeros C of Jn(x) correspond to TM modes and C those of Jn'(x) correspond to TE modes C Routine called: BJNDD for computing Jn(x), Jn'(x) and C Jn''(x) C ============================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) CHARACTER P(1400)*4,P1(70)*4 DIMENSION N(1400),M(1400),ZO(1400),N1(70),M1(70), & ZOC(70),BJ(101),DJ(101),FJ(101) IF (NT.LT.600) THEN XM=-1.0+2.248485*NT**0.5-.0159382*NT+3.208775E-4 & *NT**1.5 NM=INT(14.5+.05875*NT) MM=INT(.02*NT)+6 ELSE XM=5.0+1.445389*NT**.5+.01889876*NT-2.147763E-4 & *NT**1.5 NM=INT(27.8+.0327*NT) MM=INT(.01088*NT)+10 ENDIF L0=0 DO 45 I=1,NM X1=.407658+.4795504*(I-1)**.5+.983618*(I-1) X2=1.99535+.8333883*(I-1)**.5+.984584*(I-1) L1=0 DO 30 J=1,MM IF (I.EQ.1.AND.J.EQ.1) GO TO 15 X=X1 10 CALL BJNDD(I,X,BJ,DJ,FJ) X0=X X=X-DJ(I)/FJ(I) IF (X1.GT.XM) GO TO 20 IF (DABS(X-X0).GT.1.0D-10) GO TO 10 15 L1=L1+1 N1(L1)=I-1 M1(L1)=J IF (I.EQ.1) M1(L1)=J-1 P1(L1)='TE' ZOC(L1)=X IF (I.LE.15) THEN X1=X+3.057+.0122*(I-1)+(1.555+.41575*(I-1))/(J+1)**2 ELSE X1=X+2.918+.01924*(I-1)+(6.26+.13205*(I-1))/(J+1)**2 ENDIF 20 X=X2 25 CALL BJNDD(I,X,BJ,DJ,FJ) X0=X X=X-BJ(I)/DJ(I) IF (X.GT.XM) GO TO 30 IF (DABS(X-X0).GT.1.0D-10) GO TO 25 L1=L1+1 N1(L1)=I-1 M1(L1)=J P1(L1)='TM' ZOC(L1)=X IF (I.LE.15) THEN X2=X+3.11+.0138*(I-1)+(.04832+.2804*(I-1))/(J+1)**2 ELSE X2=X+3.001+.0105*(I-1)+(11.52+.48525*(I-1))/(J+3)**2 ENDIF 30 CONTINUE L=L0+L1 L2=L 35 IF (L0.EQ.0) THEN DO 40 K=1,L ZO(K)=ZOC(K) N(K)=N1(K) M(K)=M1(K) 40 P(K)=P1(K) L1=0 ELSE IF (L0.NE.0) THEN IF (ZO(L0).GE.ZOC(L1)) THEN ZO(L0+L1)=ZO(L0) N(L0+L1)=N(L0) M(L0+L1)=M(L0) P(L0+L1)=P(L0) L0=L0-1 ELSE ZO(L0+L1)=ZOC(L1) N(L0+L1)=N1(L1) M(L0+L1)=M1(L1) P(L0+L1)=P1(L1) L1=L1-1 ENDIF ENDIF IF (L1.NE.0) GO TO 35 45 L0=L2 RETURN END SUBROUTINE BJNDD(N,X,BJ,DJ,FJ) C C ===================================================== C Purpose: Compute Bessel functions Jn(x) and their C first and second derivatives ( n= 0,1,úúú ) C Input: x --- Argument of Jn(x) ( x ò 0 ) C n --- Order of Jn(x) C Output: BJ(n+1) --- Jn(x) C DJ(n+1) --- Jn'(x) C FJ(n+1) --- Jn"(x) C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BJ(101),DJ(101),FJ(101) DO 10 NT=1,900 MT=INT(0.5*LOG10(6.28*NT)-NT*LOG10(1.36*DABS(X)/NT)) IF (MT.GT.20) GO TO 15 10 CONTINUE 15 M=NT BS=0.0D0 F0=0.0D0 F1=1.0D-35 DO 20 K=M,0,-1 F=2.0D0*(K+1.0D0)*F1/X-F0 IF (K.LE.N) BJ(K+1)=F IF (K.EQ.2*INT(K/2)) BS=BS+2.0D0*F F0=F1 20 F1=F DO 25 K=0,N 25 BJ(K+1)=BJ(K+1)/(BS-F) DJ(1)=-BJ(2) FJ(1)=-1.0D0*BJ(1)-DJ(1)/X DO 30 K=1,N DJ(K+1)=BJ(K)-K*BJ(K+1)/X 30 FJ(K+1)=(K*K/(X*X)-1.0D0)*BJ(K+1)-DJ(K+1)/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mjelp.for000077500000000000000000000052261321604176500257420ustar00rootroot00000000000000 PROGRAM MJELP C C ============================================================ C Purpose: This program computes Jacobian elliptic functions C sn u, cn u and dn u using subroutine JELP C Input : u --- Argument of Jacobian elliptic fuctions C Hk --- Modulus k ( 0 ó k ó 1 ) C Output : ESN --- sn u C ECN --- cn u C EDN --- dn u C EPH --- phi ( in degrees ) C Example: C k = .5, ( K(k) = 1.68575035 ), and u = u0*K C C u0 phi sn u cn u dn u C ---------------------------------------------------- C 0.0 .0000 .0000000 1.0000000 1.0000000 C 0.5 47.0586 .7320508 .6812500 .9306049 C 1.0 90.0000 1.0000000 .0000000 .8660254 C 1.5 132.9414 .7320508 -.6812500 .9306049 C 2.0 180.0000 .0000000 -1.0000000 1.0000000 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter k and u ' READ(*,*)HK,U WRITE(*,*) WRITE(*,*)' k u phi sn u', & ' cn u dn u' WRITE(*,*)' -------------------------------------', & '---------------------------' CALL JELP(U,HK,ESN,ECN,EDN,EPH) WRITE(*,10)HK,U,EPH,ESN,ECN,EDN 10 FORMAT(1X,F5.3,F12.7,2X,F9.5,3F12.7) END SUBROUTINE JELP(U,HK,ESN,ECN,EDN,EPH) C C ======================================================== C Purpose: Compute Jacobian elliptic functions sn u, cn u C and dn u C Input : u --- Argument of Jacobian elliptic fuctions C Hk --- Modulus k ( 0 ó k ó 1 ) C Output : ESN --- sn u C ECN --- cn u C EDN --- dn u C EPH --- phi ( in degrees ) C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION R(40) PI=3.14159265358979D0 A0=1.0D0 B0=DSQRT(1.0D0-HK*HK) DO 10 N=1,40 A=(A0+B0)/2.0D0 B=DSQRT(A0*B0) C=(A0-B0)/2.0D0 R(N)=C/A IF (C.LT.1.0D-7) GO TO 15 A0=A 10 B0=B 15 DN=2.0D0**N*A*U DO 20 J=N,1,-1 T=R(J)*DSIN(DN) SA=DATAN(T/DSQRT(DABS(1.0D0-T*T))) D=.5D0*(DN+SA) 20 DN=D EPH=D*180.0D0/PI ESN=DSIN(D) ECN=DCOS(D) EDN=DSQRT(1.0D0-HK*HK*ESN*ESN) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mjy01a.for000077500000000000000000000157201321604176500257340ustar00rootroot00000000000000 PROGRAM MJY01A C C ========================================================= C Purpose: This program computes the Bessel functions C Jn(x) and Yn(x) ( n=0,1 ) and their derivatives C using subroutine JY01A C Input : x --- Argument of Jn(x) & Yn(x) ( x ò 0 ) C Output: BJ0 --- J0(x) C DJ0 --- J0'(x) C BJ1 --- J1(x) C DJ1 --- J1'(x) C BY0 --- Y0(x) C DY0 --- Y0'(x) C BY1 --- Y1(x) C DY1 --- Y1'(x) C Example: C C x J0(x) J0'(x) J1(x) J1'(x) C --------------------------------------------------------- C 1 .76519769 -.44005059 .44005059 .32514710 C 5 -.17759677 .32757914 -.32757914 -.11208094 C 10 -.24593576 -.04347275 .04347275 -.25028304 C 20 .16702466 -.06683312 .06683312 .16368301 C 30 -.08636798 .11875106 -.11875106 -.08240961 C 40 .00736689 -.12603832 .12603832 .00421593 C 50 .05581233 .09751183 -.09751183 .05776256 C C x Y0(x) Y0'(x) Y1(x) Y1'(x) C --------------------------------------------------------- C 1 .08825696 .78121282 -.78121282 .86946979 C 5 -.30851763 -.14786314 .14786314 -.33809025 C 10 .05567117 -.24901542 .24901542 .03076962 C 20 .06264060 .16551161 -.16551161 .07091618 C 30 -.11729573 -.08442557 .08442557 -.12010992 C 40 .12593642 .00579351 -.00579351 .12608125 C 50 -.09806500 .05679567 -.05679567 -.09692908 C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x' READ(*,*)X WRITE(*,20)X WRITE(*,*)' x J0(x) J0''(x) J1(x)', & ' J1''(x)' WRITE(*,*)'------------------------------------------', & '----------------------------' CALL JY01A(X,BJ0,DJ0,BJ1,DJ1,BY0,DY0,BY1,DY1) WRITE(*,10)X,BJ0,DJ0,BJ1,DJ1 WRITE(*,*) WRITE(*,*)' x Y0(x) Y0''(x) Y1(x)', & ' Y1''(x)' WRITE(*,*)'------------------------------------------', & '----------------------------' WRITE(*,10)X,BY0,DY0,BY1,DY1 10 FORMAT(1X,F5.1,4E16.8) 20 FORMAT(3X,'x =',F5.1) END SUBROUTINE JY01A(X,BJ0,DJ0,BJ1,DJ1,BY0,DY0,BY1,DY1) C C ======================================================= C Purpose: Compute Bessel functions J0(x), J1(x), Y0(x), C Y1(x), and their derivatives C Input : x --- Argument of Jn(x) & Yn(x) ( x ò 0 ) C Output: BJ0 --- J0(x) C DJ0 --- J0'(x) C BJ1 --- J1(x) C DJ1 --- J1'(x) C BY0 --- Y0(x) C DY0 --- Y0'(x) C BY1 --- Y1(x) C DY1 --- Y1'(x) C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(12),B(12),A1(12),B1(12) PI=3.141592653589793D0 RP2=0.63661977236758D0 X2=X*X IF (X.EQ.0.0D0) THEN BJ0=1.0D0 BJ1=0.0D0 DJ0=0.0D0 DJ1=0.5D0 BY0=-1.0D+300 BY1=-1.0D+300 DY0=1.0D+300 DY1=1.0D+300 RETURN ENDIF IF (X.LE.12.0D0) THEN BJ0=1.0D0 R=1.0D0 DO 5 K=1,30 R=-0.25D0*R*X2/(K*K) BJ0=BJ0+R IF (DABS(R).LT.DABS(BJ0)*1.0D-15) GO TO 10 5 CONTINUE 10 BJ1=1.0D0 R=1.0D0 DO 15 K=1,30 R=-0.25D0*R*X2/(K*(K+1.0D0)) BJ1=BJ1+R IF (DABS(R).LT.DABS(BJ1)*1.0D-15) GO TO 20 15 CONTINUE 20 BJ1=0.5D0*X*BJ1 EC=DLOG(X/2.0D0)+0.5772156649015329D0 CS0=0.0D0 W0=0.0D0 R0=1.0D0 DO 25 K=1,30 W0=W0+1.0D0/K R0=-0.25D0*R0/(K*K)*X2 R=R0*W0 CS0=CS0+R IF (DABS(R).LT.DABS(CS0)*1.0D-15) GO TO 30 25 CONTINUE 30 BY0=RP2*(EC*BJ0-CS0) CS1=1.0D0 W1=0.0D0 R1=1.0D0 DO 35 K=1,30 W1=W1+1.0D0/K R1=-0.25D0*R1/(K*(K+1))*X2 R=R1*(2.0D0*W1+1.0D0/(K+1.0D0)) CS1=CS1+R IF (DABS(R).LT.DABS(CS1)*1.0D-15) GO TO 40 35 CONTINUE 40 BY1=RP2*(EC*BJ1-1.0D0/X-0.25D0*X*CS1) ELSE DATA A/-.7031250000000000D-01,.1121520996093750D+00, & -.5725014209747314D+00,.6074042001273483D+01, & -.1100171402692467D+03,.3038090510922384D+04, & -.1188384262567832D+06,.6252951493434797D+07, & -.4259392165047669D+09,.3646840080706556D+11, & -.3833534661393944D+13,.4854014686852901D+15/ DATA B/ .7324218750000000D-01,-.2271080017089844D+00, & .1727727502584457D+01,-.2438052969955606D+02, & .5513358961220206D+03,-.1825775547429318D+05, & .8328593040162893D+06,-.5006958953198893D+08, & .3836255180230433D+10,-.3649010818849833D+12, & .4218971570284096D+14,-.5827244631566907D+16/ DATA A1/.1171875000000000D+00,-.1441955566406250D+00, & .6765925884246826D+00,-.6883914268109947D+01, & .1215978918765359D+03,-.3302272294480852D+04, & .1276412726461746D+06,-.6656367718817688D+07, & .4502786003050393D+09,-.3833857520742790D+11, & .4011838599133198D+13,-.5060568503314727D+15/ DATA B1/-.1025390625000000D+00,.2775764465332031D+00, & -.1993531733751297D+01,.2724882731126854D+02, & -.6038440767050702D+03,.1971837591223663D+05, & -.8902978767070678D+06,.5310411010968522D+08, & -.4043620325107754D+10,.3827011346598605D+12, & -.4406481417852278D+14,.6065091351222699D+16/ K0=12 IF (X.GE.35.0) K0=10 IF (X.GE.50.0) K0=8 T1=X-0.25D0*PI P0=1.0D0 Q0=-0.125D0/X DO 45 K=1,K0 P0=P0+A(K)*X**(-2*K) 45 Q0=Q0+B(K)*X**(-2*K-1) CU=DSQRT(RP2/X) BJ0=CU*(P0*DCOS(T1)-Q0*DSIN(T1)) BY0=CU*(P0*DSIN(T1)+Q0*DCOS(T1)) T2=X-0.75D0*PI P1=1.0D0 Q1=0.375D0/X DO 50 K=1,K0 P1=P1+A1(K)*X**(-2*K) 50 Q1=Q1+B1(K)*X**(-2*K-1) CU=DSQRT(RP2/X) BJ1=CU*(P1*DCOS(T2)-Q1*DSIN(T2)) BY1=CU*(P1*DSIN(T2)+Q1*DCOS(T2)) ENDIF DJ0=-BJ1 DJ1=BJ0-BJ1/X DY0=-BY1 DY1=BY0-BY1/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mjy01b.for000077500000000000000000000125731321604176500257400ustar00rootroot00000000000000 PROGRAM MJY01B C C ========================================================= C Purpose: This program computes Bessel functions Jn(x) C and Yn(x) ( n=0,1 ) and their derivatives C using subroutine JY01B C Input : x --- Argument of Jn(x) & Yn(x) ( x ò 0 ) C Output: BJ0 --- J0(x) C DJ0 --- J0'(x) C BJ1 --- J1(x) C DJ1 --- J1'(x) C BY0 --- Y0(x) C DY0 --- Y0'(x) C BY1 --- Y1(x) C DY1 --- Y1'(x) C Example: C C x J0(x) J0'(x) J1(x) J1'(x) C --------------------------------------------------------- C 1 .76519769 -.44005059 .44005059 .32514710 C 5 -.17759677 .32757914 -.32757914 -.11208094 C 10 -.24593576 -.04347275 .04347275 -.25028304 C 20 .16702466 -.06683312 .06683312 .16368301 C 30 -.08636798 .11875106 -.11875106 -.08240961 C 40 .00736689 -.12603832 .12603832 .00421593 C 50 .05581233 .09751183 -.09751183 .05776256 C C x Y0(x) Y0'(x) Y1(x) Y1'(x) C --------------------------------------------------------- C 1 .08825696 .78121282 -.78121282 .86946979 C 5 -.30851763 -.14786314 .14786314 -.33809025 C 10 .05567117 -.24901542 .24901542 .03076962 C 20 .06264060 .16551161 -.16551161 .07091618 C 30 -.11729573 -.08442557 .08442557 -.12010992 C 40 .12593642 .00579351 -.00579351 .12608125 C 50 -.09806500 .05679567 -.05679567 -.09692908 C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x' READ(*,*)X WRITE(*,20)X WRITE(*,*)' x J0(x) J0''(x) J1(x)', & ' J1''(x)' WRITE(*,*)'------------------------------------------', & '----------------------------' CALL JY01B(X,BJ0,DJ0,BJ1,DJ1,BY0,DY0,BY1,DY1) WRITE(*,10)X,BJ0,DJ0,BJ1,DJ1 WRITE(*,*) WRITE(*,*)' x Y0(x) Y0''(x) Y1(x)', & ' Y1''(x)' WRITE(*,*)'------------------------------------------', & '----------------------------' WRITE(*,10)X,BY0,DY0,BY1,DY1 10 FORMAT(1X,F5.1,4E16.8) 20 FORMAT(3X,'x =',F5.1) END SUBROUTINE JY01B(X,BJ0,DJ0,BJ1,DJ1,BY0,DY0,BY1,DY1) C C ======================================================= C Purpose: Compute Bessel functions J0(x), J1(x), Y0(x), C Y1(x), and their derivatives C Input : x --- Argument of Jn(x) & Yn(x) ( x ò 0 ) C Output: BJ0 --- J0(x) C DJ0 --- J0'(x) C BJ1 --- J1(x) C DJ1 --- J1'(x) C BY0 --- Y0(x) C DY0 --- Y0'(x) C BY1 --- Y1(x) C DY1 --- Y1'(x) C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 IF (X.EQ.0.0D0) THEN BJ0=1.0D0 BJ1=0.0D0 DJ0=0.0D0 DJ1=0.5D0 BY0=-1.0D+300 BY1=-1.0D+300 DY0=1.0D+300 DY1=1.0D+300 RETURN ELSE IF (X.LE.4.0D0) THEN T=X/4.0D0 T2=T*T BJ0=((((((-.5014415D-3*T2+.76771853D-2)*T2 & -.0709253492D0)*T2+.4443584263D0)*T2 & -1.7777560599D0)*T2+3.9999973021D0) & *T2-3.9999998721D0)*T2+1.0D0 BJ1=T*(((((((-.1289769D-3*T2+.22069155D-2) & *T2-.0236616773D0)*T2+.1777582922D0)*T2 & -.8888839649D0)*T2+2.6666660544D0)*T2 & -3.9999999710D0)*T2+1.9999999998D0) BY0=(((((((-.567433D-4*T2+.859977D-3)*T2 & -.94855882D-2)*T2+.0772975809D0)*T2 & -.4261737419D0)*T2+1.4216421221D0)*T2 & -2.3498519931D0)*T2+1.0766115157)*T2 & +.3674669052D0 BY0=2.0D0/PI*DLOG(X/2.0D0)*BJ0+BY0 BY1=((((((((.6535773D-3*T2-.0108175626D0)*T2 & +.107657606D0)*T2-.7268945577D0)*T2 & +3.1261399273D0)*T2-7.3980241381D0)*T2 & +6.8529236342D0)*T2+.3932562018D0)*T2 & -.6366197726D0)/X BY1=2.0D0/PI*DLOG(X/2.0D0)*BJ1+BY1 ELSE T=4.0D0/X T2=T*T A0=DSQRT(2.0D0/(PI*X)) P0=((((-.9285D-5*T2+.43506D-4)*T2-.122226D-3)*T2 & +.434725D-3)*T2-.4394275D-2)*T2+.999999997D0 Q0=T*(((((.8099D-5*T2-.35614D-4)*T2+.85844D-4)*T2 & -.218024D-3)*T2+.1144106D-2)*T2-.031249995D0) TA0=X-.25D0*PI BJ0=A0*(P0*DCOS(TA0)-Q0*DSIN(TA0)) BY0=A0*(P0*DSIN(TA0)+Q0*DCOS(TA0)) P1=((((.10632D-4*T2-.50363D-4)*T2+.145575D-3)*T2 & -.559487D-3)*T2+.7323931D-2)*T2+1.000000004D0 Q1=T*(((((-.9173D-5*T2+.40658D-4)*T2-.99941D-4)*T2 & +.266891D-3)*T2-.1601836D-2)*T2+.093749994D0) TA1=X-.75D0*PI BJ1=A0*(P1*DCOS(TA1)-Q1*DSIN(TA1)) BY1=A0*(P1*DSIN(TA1)+Q1*DCOS(TA1)) ENDIF DJ0=-BJ1 DJ1=BJ0-BJ1/X DY0=-BY1 DY1=BY0-BY1/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mjyna.for000077500000000000000000000223051321604176500257460ustar00rootroot00000000000000 PROGRAM MJYNA C C ==================================================== C Purpose: This program computes Bessel functions C Jn(x) and Yn(x), and their derivatives C using subroutine JYNA C Input : x --- Argument of Jn(x) & Yn(x) ( x ò 0 ) C n --- Order of Jn(x) & Yn(x) C ( n = 0,1,2,úúú, n ó 250 ) C Output: BJ(n) --- Jn(x) C DJ(n) --- Jn'(x) C BY(n) --- Yn(x) C DY(n) --- Yn'(x) C Example: C x = 10.0 C C n Jn(x) Jn'(x) C ------------------------------------- C 0 -.2459358D+00 -.4347275D-01 C 10 .2074861D+00 .8436958D-01 C 20 .1151337D-04 .2011954D-04 C 30 .1551096D-11 .4396479D-11 C C n Yn(x) Yn'(x) C ------------------------------------- C 0 .5567117D-01 -.2490154D+00 C 10 -.3598142D+00 .1605149D+00 C 20 -.1597484D+04 .2737803D+04 C 30 -.7256142D+10 .2047617D+11 C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BJ(0:250),BY(0:250),DJ(0:250),DY(0:250) WRITE(*,*)' Please enter n, x' READ(*,*)N,X WRITE(*,30)N,X IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF WRITE(*,*) CALL JYNA(N,X,NM,BJ,DJ,BY,DY) WRITE(*,*)' n Jn(x) Jn''(x)' WRITE(*,*)'--------------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,40)K,BJ(K),DJ(K) WRITE(*,*) WRITE(*,*)' n Yn(x) Yn''(x)' WRITE(*,*)'--------------------------------------' DO 20 K=0,NM,NS 20 WRITE(*,40)K,BY(K),DY(K) 30 FORMAT(3X,6HNmax =,I3,', ',3Hx =,F6.1) 40 FORMAT(1X,I3,1X,2D16.7) END SUBROUTINE JYNA(N,X,NM,BJ,DJ,BY,DY) C C ========================================================== C Purpose: Compute Bessel functions Jn(x) & Yn(x) and C their derivatives C Input : x --- Argument of Jn(x) & Yn(x) ( x ò 0 ) C n --- Order of Jn(x) & Yn(x) C Output: BJ(n) --- Jn(x) C DJ(n) --- Jn'(x) C BY(n) --- Yn(x) C DY(n) --- Yn'(x) C NM --- Highest order computed C Routines called: C (1) JY01B to calculate J0(x), J1(x), Y0(x) & Y1(x) C (2) MSTA1 and MSTA2 to calculate the starting C point for backward recurrence C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BJ(0:N),BY(0:N),DJ(0:N),DY(0:N) NM=N IF (X.LT.1.0D-100) THEN DO 10 K=0,N BJ(K)=0.0D0 DJ(K)=0.0D0 BY(K)=-1.0D+300 10 DY(K)=1.0D+300 BJ(0)=1.0D0 DJ(1)=0.5D0 RETURN ENDIF CALL JY01B(X,BJ0,DJ0,BJ1,DJ1,BY0,DY0,BY1,DY1) BJ(0)=BJ0 BJ(1)=BJ1 BY(0)=BY0 BY(1)=BY1 DJ(0)=DJ0 DJ(1)=DJ1 DY(0)=DY0 DY(1)=DY1 IF (N.LE.1) RETURN IF (N.LT.INT(0.9*X)) THEN DO 20 K=2,N BJK=2.0D0*(K-1.0D0)/X*BJ1-BJ0 BJ(K)=BJK BJ0=BJ1 20 BJ1=BJK ELSE M=MSTA1(X,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(X,N,15) ENDIF F2=0.0D0 F1=1.0D-100 DO 30 K=M,0,-1 F=2.0D0*(K+1.0D0)/X*F1-F2 IF (K.LE.NM) BJ(K)=F F2=F1 30 F1=F IF (DABS(BJ0).GT.DABS(BJ1)) THEN CS=BJ0/F ELSE CS=BJ1/F2 ENDIF DO 40 K=0,NM 40 BJ(K)=CS*BJ(K) ENDIF DO 50 K=2,NM 50 DJ(K)=BJ(K-1)-K/X*BJ(K) F0=BY(0) F1=BY(1) DO 60 K=2,NM F=2.0D0*(K-1.0D0)/X*F1-F0 BY(K)=F F0=F1 60 F1=F DO 70 K=2,NM 70 DY(K)=BY(K-1)-K*BY(K)/X RETURN END SUBROUTINE JY01B(X,BJ0,DJ0,BJ1,DJ1,BY0,DY0,BY1,DY1) C C ======================================================= C Purpose: Compute Bessel functions J0(x), J1(x), Y0(x), C Y1(x), and their derivatives C Input : x --- Argument of Jn(x) & Yn(x) ( x ò 0 ) C Output: BJ0 --- J0(x) C DJ0 --- J0'(x) C BJ1 --- J1(x) C DJ1 --- J1'(x) C BY0 --- Y0(x) C DY0 --- Y0'(x) C BY1 --- Y1(x) C DY1 --- Y1'(x) C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 IF (X.EQ.0.0D0) THEN BJ0=1.0D0 BJ1=0.0D0 DJ0=0.0D0 DJ1=0.5D0 BY0=-1.0D+300 BY1=-1.0D+300 DY0=1.0D+300 DY1=1.0D+300 RETURN ELSE IF (X.LE.4.0D0) THEN T=X/4.0D0 T2=T*T BJ0=((((((-.5014415D-3*T2+.76771853D-2)*T2 & -.0709253492D0)*T2+.4443584263D0)*T2 & -1.7777560599D0)*T2+3.9999973021D0) & *T2-3.9999998721D0)*T2+1.0D0 BJ1=T*(((((((-.1289769D-3*T2+.22069155D-2) & *T2-.0236616773D0)*T2+.1777582922D0)*T2 & -.8888839649D0)*T2+2.6666660544D0)*T2 & -3.9999999710D0)*T2+1.9999999998D0) BY0=(((((((-.567433D-4*T2+.859977D-3)*T2 & -.94855882D-2)*T2+.0772975809D0)*T2 & -.4261737419D0)*T2+1.4216421221D0)*T2 & -2.3498519931D0)*T2+1.0766115157)*T2 & +.3674669052D0 BY0=2.0D0/PI*DLOG(X/2.0D0)*BJ0+BY0 BY1=((((((((.6535773D-3*T2-.0108175626D0)*T2 & +.107657606D0)*T2-.7268945577D0)*T2 & +3.1261399273D0)*T2-7.3980241381D0)*T2 & +6.8529236342D0)*T2+.3932562018D0)*T2 & -.6366197726D0)/X BY1=2.0D0/PI*DLOG(X/2.0D0)*BJ1+BY1 ELSE T=4.0D0/X T2=T*T A0=DSQRT(2.0D0/(PI*X)) P0=((((-.9285D-5*T2+.43506D-4)*T2-.122226D-3)*T2 & +.434725D-3)*T2-.4394275D-2)*T2+.999999997D0 Q0=T*(((((.8099D-5*T2-.35614D-4)*T2+.85844D-4)*T2 & -.218024D-3)*T2+.1144106D-2)*T2-.031249995D0) TA0=X-.25D0*PI BJ0=A0*(P0*DCOS(TA0)-Q0*DSIN(TA0)) BY0=A0*(P0*DSIN(TA0)+Q0*DCOS(TA0)) P1=((((.10632D-4*T2-.50363D-4)*T2+.145575D-3)*T2 & -.559487D-3)*T2+.7323931D-2)*T2+1.000000004D0 Q1=T*(((((-.9173D-5*T2+.40658D-4)*T2-.99941D-4)*T2 & +.266891D-3)*T2-.1601836D-2)*T2+.093749994D0) TA1=X-.75D0*PI BJ1=A0*(P1*DCOS(TA1)-Q1*DSIN(TA1)) BY1=A0*(P1*DSIN(TA1)+Q1*DCOS(TA1)) ENDIF DJ0=-BJ1 DJ1=BJ0-BJ1/X DY0=-BY1 DY1=BY0-BY1/X RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mjynb.for000077500000000000000000000152271321604176500257540ustar00rootroot00000000000000 PROGRAM MJYNB C C ==================================================== C Purpose: This program computes Bessel functions C Jn(x) and Yn(x), and their derivatives C using subroutine JYNB C Input : x --- Argument of Jn(x) & Yn(x) ( x ò 0 ) C n --- Order of Jn(x) & Yn(x) C ( n = 0,1,2,úúú, n ó 250 ) C Output: BJ(n) --- Jn(x) C DJ(n) --- Jn'(x) C BY(n) --- Yn(x) C DY(n) --- Yn'(x) C Example: C x = 10.0 C C n Jn(x) Jn'(x) C ------------------------------------- C 0 -.2459358D+00 -.4347275D-01 C 10 .2074861D+00 .8436958D-01 C 20 .1151337D-04 .2011954D-04 C 30 .1551096D-11 .4396479D-11 C C n Yn(x) Yn'(x) C ------------------------------------- C 0 .5567117D-01 -.2490154D+00 C 10 -.3598142D+00 .1605149D+00 C 20 -.1597484D+04 .2737803D+04 C 30 -.7256142D+10 .2047617D+11 C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BJ(0:250),BY(0:250),DJ(0:250),DY(0:250) WRITE(*,*)' Please enter n, x' READ(*,*)N,X WRITE(*,30)N,X IF (N.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF WRITE(*,*) CALL JYNB(N,X,NM,BJ,DJ,BY,DY) WRITE(*,*)' n Jn(x) Jn''(x)' WRITE(*,*)'--------------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,40)K,BJ(K),DJ(K) WRITE(*,*) WRITE(*,*)' n Yn(x) Yn''(x)' WRITE(*,*)'--------------------------------------' DO 20 K=0,NM,NS 20 WRITE(*,40)K,BY(K),DY(K) 30 FORMAT(3X,6HNmax =,I3,', ',3Hx =,F6.1) 40 FORMAT(1X,I3,1X,2D16.7) END SUBROUTINE JYNB(N,X,NM,BJ,DJ,BY,DY) C C ===================================================== C Purpose: Compute Bessel functions Jn(x), Yn(x) and C their derivatives C Input : x --- Argument of Jn(x) and Yn(x) ( x ò 0 ) C n --- Order of Jn(x) and Yn(x) C Output: BJ(n) --- Jn(x) C DJ(n) --- Jn'(x) C BY(n) --- Yn(x) C DY(n) --- Yn'(x) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 to calculate the starting C point for backward recurrence C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BJ(0:N),DJ(0:N),BY(0:N),DY(0:N), & A(4),B(4),A1(4),B1(4) PI=3.141592653589793D0 R2P=.63661977236758D0 NM=N IF (X.LT.1.0D-100) THEN DO 10 K=0,N BJ(K)=0.0D0 DJ(K)=0.0D0 BY(K)=-1.0D+300 10 DY(K)=1.0D+300 BJ(0)=1.0D0 DJ(1)=0.5D0 RETURN ENDIF IF (X.LE.300.0.OR.N.GT.INT(0.9*X)) THEN IF (N.EQ.0) NM=1 M=MSTA1(X,200) IF (M.LT.NM) THEN NM=M ELSE M=MSTA2(X,NM,15) ENDIF BS=0.0D0 SU=0.0D0 SV=0.0D0 F2=0.0D0 F1=1.0D-100 DO 15 K=M,0,-1 F=2.0D0*(K+1.0D0)/X*F1-F2 IF (K.LE.NM) BJ(K)=F IF (K.EQ.2*INT(K/2).AND.K.NE.0) THEN BS=BS+2.0D0*F SU=SU+(-1)**(K/2)*F/K ELSE IF (K.GT.1) THEN SV=SV+(-1)**(K/2)*K/(K*K-1.0)*F ENDIF F2=F1 15 F1=F S0=BS+F DO 20 K=0,NM 20 BJ(K)=BJ(K)/S0 EC=DLOG(X/2.0D0)+0.5772156649015329D0 BY0=R2P*(EC*BJ(0)-4.0D0*SU/S0) BY(0)=BY0 BY1=R2P*((EC-1.0D0)*BJ(1)-BJ(0)/X-4.0D0*SV/S0) BY(1)=BY1 ELSE DATA A/-.7031250000000000D-01,.1121520996093750D+00, & -.5725014209747314D+00,.6074042001273483D+01/ DATA B/ .7324218750000000D-01,-.2271080017089844D+00, & .1727727502584457D+01,-.2438052969955606D+02/ DATA A1/.1171875000000000D+00,-.1441955566406250D+00, & .6765925884246826D+00,-.6883914268109947D+01/ DATA B1/-.1025390625000000D+00,.2775764465332031D+00, & -.1993531733751297D+01,.2724882731126854D+02/ T1=X-0.25D0*PI P0=1.0D0 Q0=-0.125D0/X DO 25 K=1,4 P0=P0+A(K)*X**(-2*K) 25 Q0=Q0+B(K)*X**(-2*K-1) CU=DSQRT(R2P/X) BJ0=CU*(P0*DCOS(T1)-Q0*DSIN(T1)) BY0=CU*(P0*DSIN(T1)+Q0*DCOS(T1)) BJ(0)=BJ0 BY(0)=BY0 T2=X-0.75D0*PI P1=1.0D0 Q1=0.375D0/X DO 30 K=1,4 P1=P1+A1(K)*X**(-2*K) 30 Q1=Q1+B1(K)*X**(-2*K-1) BJ1=CU*(P1*DCOS(T2)-Q1*DSIN(T2)) BY1=CU*(P1*DSIN(T2)+Q1*DCOS(T2)) BJ(1)=BJ1 BY(1)=BY1 DO 35 K=2,NM BJK=2.0D0*(K-1.0D0)/X*BJ1-BJ0 BJ(K)=BJK BJ0=BJ1 35 BJ1=BJK ENDIF DJ(0)=-BJ(1) DO 40 K=1,NM 40 DJ(K)=BJ(K-1)-K/X*BJ(K) DO 45 K=2,NM BYK=2.0D0*(K-1.0D0)*BY1/X-BY0 BY(K)=BYK BY0=BY1 45 BY1=BYK DY(0)=-BY(1) DO 50 K=1,NM 50 DY(K)=BY(K-1)-K*BY(K)/X RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mjyv.for000077500000000000000000000263761321604176500256310ustar00rootroot00000000000000 PROGRAM MJYV C C ============================================================ C Purpose: This program computes Bessel functions Jv(x) and C Yv(x) and their derivatives using subroutine JYV C Input : x --- Argument of Jv(x) and Yv(x) C v --- Order of Jv(x) and Yv(x) C ( v = n+v0, 0 ó n ó 250, 0 ó v0 < 1 ) C Output: BJ(n) --- Jn+v0(x) C DJ(n) --- Jn+v0'(x) C BY(n) --- Yn+v0(x) C DY(n) --- Yn+v0'(x) C Example: Compute Jv(x) and Yv(x) and their derivatives C for v = 0.25(1.0)5.25 and x = 10.0 C Computation results: C C v = 5.25, x = 10.00 C C v Jv(x) Jv'(x) Yv(x) Yv'(x) C ------------------------------------------------------------ C .25 -.20639379 -.13476340 .14493044 -.21381777 C 1.25 .12960355 -.22259423 .21744103 .11775031 C 2.25 .23879467 .07587475 -.09057018 .23781932 C 3.25 -.02214595 .24599211 -.25819761 -.00665596 C 4.25 -.25318954 .08545961 -.07725827 -.22536285 C 5.25 -.19306516 -.15183033 .19252809 -.17833551 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) COMMON BJ(0:250),DJ(0:250),BY(0:250),DY(0:250) WRITE(*,*)' Please enter v, x ' READ(*,*)V,X WRITE(*,20)V,X IF (V.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL JYV(V,X,VM,BJ,DJ,BY,DY) NM=INT(VM) V0=VM-NM WRITE(*,*) WRITE(*,*)' v Jv(x) Jv''(x)', & ' Yv(x) Yv''(x)' WRITE(*,*)' ---------------------------------------------', & '------------------------' DO 10 K=0,NM,NS VK=K+V0 10 WRITE(*,15)VK,BJ(K),DJ(K),BY(K),DY(K) 15 FORMAT(1X,F6.2,4D16.8) 20 FORMAT(8X,3Hv =,F6.2,', ',3Hx =,F6.2) END SUBROUTINE JYV(V,X,VM,BJ,DJ,BY,DY) C C ======================================================= C Purpose: Compute Bessel functions Jv(x) and Yv(x) C and their derivatives C Input : x --- Argument of Jv(x) and Yv(x) C v --- Order of Jv(x) and Yv(x) C ( v = n+v0, 0 ó v0 < 1, n = 0,1,2,... ) C Output: BJ(n) --- Jn+v0(x) C DJ(n) --- Jn+v0'(x) C BY(n) --- Yn+v0(x) C DY(n) --- Yn+v0'(x) C VM --- Highest order computed C Routines called: C (1) GAMMA for computing gamma function C (2) MSTA1 and MSTA2 for computing the starting C point for backward recurrence C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BJ(0:*),DJ(0:*),BY(0:*),DY(0:*) EL=.5772156649015329D0 PI=3.141592653589793D0 RP2=.63661977236758D0 X2=X*X N=INT(V) V0=V-N IF (X.LT.1.0D-100) THEN DO 10 K=0,N BJ(K)=0.0D0 DJ(K)=0.0D0 BY(K)=-1.0D+300 10 DY(K)=1.0D+300 IF (V0.EQ.0.0) THEN BJ(0)=1.0D0 DJ(1)=0.5D0 ELSE DJ(0)=1.0D+300 ENDIF VM=V RETURN ENDIF IF (X.LE.12.0) THEN DO 25 L=0,1 VL=V0+L BJVL=1.0D0 R=1.0D0 DO 15 K=1,40 R=-0.25D0*R*X2/(K*(K+VL)) BJVL=BJVL+R IF (DABS(R).LT.DABS(BJVL)*1.0D-15) GO TO 20 15 CONTINUE 20 VG=1.0D0+VL CALL GAMMA(VG,GA) A=(0.5D0*X)**VL/GA IF (L.EQ.0) BJV0=BJVL*A IF (L.EQ.1) BJV1=BJVL*A 25 CONTINUE ELSE K0=11 IF (X.GE.35.0) K0=10 IF (X.GE.50.0) K0=8 DO 40 J=0,1 VV=4.0D0*(J+V0)*(J+V0) PX=1.0D0 RP=1.0D0 DO 30 K=1,K0 RP=-0.78125D-2*RP*(VV-(4.0*K-3.0)**2.0)*(VV- & (4.0*K-1.0)**2.0)/(K*(2.0*K-1.0)*X2) 30 PX=PX+RP QX=1.0D0 RQ=1.0D0 DO 35 K=1,K0 RQ=-0.78125D-2*RQ*(VV-(4.0*K-1.0)**2.0)*(VV- & (4.0*K+1.0)**2.0)/(K*(2.0*K+1.0)*X2) 35 QX=QX+RQ QX=0.125D0*(VV-1.0)*QX/X XK=X-(0.5D0*(J+V0)+0.25D0)*PI A0=DSQRT(RP2/X) CK=DCOS(XK) SK=DSIN(XK) IF (J.EQ.0) THEN BJV0=A0*(PX*CK-QX*SK) BYV0=A0*(PX*SK+QX*CK) ELSE IF (J.EQ.1) THEN BJV1=A0*(PX*CK-QX*SK) BYV1=A0*(PX*SK+QX*CK) ENDIF 40 CONTINUE ENDIF BJ(0)=BJV0 BJ(1)=BJV1 DJ(0)=V0/X*BJ(0)-BJ(1) DJ(1)=-(1.0D0+V0)/X*BJ(1)+BJ(0) IF (N.GE.2.AND.N.LE.INT(0.9*X)) THEN F0=BJV0 F1=BJV1 DO 45 K=2,N F=2.0D0*(K+V0-1.0D0)/X*F1-F0 BJ(K)=F F0=F1 45 F1=F ELSE IF (N.GE.2) THEN M=MSTA1(X,200) IF (M.LT.N) THEN N=M ELSE M=MSTA2(X,N,15) ENDIF F2=0.0D0 F1=1.0D-100 DO 50 K=M,0,-1 F=2.0D0*(V0+K+1.0D0)/X*F1-F2 IF (K.LE.N) BJ(K)=F F2=F1 50 F1=F IF (DABS(BJV0).GT.DABS(BJV1)) THEN CS=BJV0/F ELSE CS=BJV1/F2 ENDIF DO 55 K=0,N 55 BJ(K)=CS*BJ(K) ENDIF DO 60 K=2,N 60 DJ(K)=-(K+V0)/X*BJ(K)+BJ(K-1) IF (X.LE.12.0D0) THEN IF (V0.NE.0.0) THEN DO 75 L=0,1 VL=V0+L BJVL=1.0D0 R=1.0D0 DO 65 K=1,40 R=-0.25D0*R*X2/(K*(K-VL)) BJVL=BJVL+R IF (DABS(R).LT.DABS(BJVL)*1.0D-15) GO TO 70 65 CONTINUE 70 VG=1.0D0-VL CALL GAMMA(VG,GB) B=(2.0D0/X)**VL/GB IF (L.EQ.0) BJU0=BJVL*B IF (L.EQ.1) BJU1=BJVL*B 75 CONTINUE PV0=PI*V0 PV1=PI*(1.0D0+V0) BYV0=(BJV0*DCOS(PV0)-BJU0)/DSIN(PV0) BYV1=(BJV1*DCOS(PV1)-BJU1)/DSIN(PV1) ELSE EC=DLOG(X/2.0D0)+EL CS0=0.0D0 W0=0.0D0 R0=1.0D0 DO 80 K=1,30 W0=W0+1.0D0/K R0=-0.25D0*R0/(K*K)*X2 80 CS0=CS0+R0*W0 BYV0=RP2*(EC*BJV0-CS0) CS1=1.0D0 W1=0.0D0 R1=1.0D0 DO 85 K=1,30 W1=W1+1.0D0/K R1=-0.25D0*R1/(K*(K+1))*X2 85 CS1=CS1+R1*(2.0D0*W1+1.0D0/(K+1.0D0)) BYV1=RP2*(EC*BJV1-1.0D0/X-0.25D0*X*CS1) ENDIF ENDIF BY(0)=BYV0 BY(1)=BYV1 DO 90 K=2,N BYVK=2.0D0*(V0+K-1.0D0)/X*BYV1-BYV0 BY(K)=BYVK BYV0=BYV1 90 BYV1=BYVK DY(0)=V0/X*BY(0)-BY(1) DO 95 K=1,N 95 DY(K)=-(K+V0)/X*BY(K)+BY(K-1) VM=N+V0 RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mjyzo.for000077500000000000000000000141501321604176500257770ustar00rootroot00000000000000 PROGRAM MJYZO C C ========================================================== C Purpose: This program computes the zeros of Bessel C functions Jn(x), Yn(x), and their derivatives C using subroutine JYZO C Input : n --- Order of Bessel functions ( n ó 100 ) C NT --- Number of zeros C Output: RJ0(m) --- m-th zero of Jn(x), m=1,2,...,NT C RJ1(m) --- m-th zero of Jn'(x), m=1,2,...,NT C RY0(m) --- m-th zero of Yn(x), m=1,2,...,NT C RY1(m) --- m-th zero of Yn'(x), m=1,2,...,NT C Example: n = 1, NT =5 C C Zeros of Bessel funcions Jn(x), Yn(x) and their derivatives C ( n = 1 ) C m jnm j'nm ynm y'nm C ----------------------------------------------------------- C 1 3.8317060 1.8411838 2.1971413 3.6830229 C 2 7.0155867 5.3314428 5.4296810 6.9415000 C 3 10.1734681 8.5363164 8.5960059 10.1234047 C 4 13.3236919 11.7060049 11.7491548 13.2857582 C 5 16.4706301 14.8635886 14.8974421 16.4400580 C ========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION RJ0(101),RJ1(101),RY0(101),RY1(101) WRITE(*,*)'Please enter n and NT ' READ(*,*)N,NT WRITE(*,*) CALL JYZO(N,NT,RJ0,RJ1,RY0,RY1) WRITE(*,30) WRITE(*,40)N WRITE(*,*)' m jnm j''nm ynm', & ' y''nm' WRITE(*,*)' ----------------------------------------', & '-------------------' DO 10 M=1,NT 10 WRITE(*,50)M,RJ0(M),RJ1(M),RY0(M),RY1(M) 30 FORMAT(2X,'Zeros of Bessel funcions Jn(x), Yn(x)', & ' and their derivatives') 40 FORMAT(30X,'( n =',I2,' )') 50 FORMAT(1X,I3,4F14.7) END SUBROUTINE JYZO(N,NT,RJ0,RJ1,RY0,RY1) C C ====================================================== C Purpose: Compute the zeros of Bessel functions Jn(x), C Yn(x), and their derivatives C Input : n --- Order of Bessel functions ( n ó 101 ) C NT --- Number of zeros (roots) C Output: RJ0(L) --- L-th zero of Jn(x), L=1,2,...,NT C RJ1(L) --- L-th zero of Jn'(x), L=1,2,...,NT C RY0(L) --- L-th zero of Yn(x), L=1,2,...,NT C RY1(L) --- L-th zero of Yn'(x), L=1,2,...,NT C Routine called: JYNDD for computing Jn(x), Yn(x), and C their first and second derivatives C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION RJ0(NT),RJ1(NT),RY0(NT),RY1(NT) IF (N.LE.20) THEN X=2.82141+1.15859*N ELSE X=N+1.85576*N**0.33333+1.03315/N**0.33333 ENDIF L=0 10 X0=X CALL JYNDD(N,X,BJN,DJN,FJN,BYN,DYN,FYN) X=X-BJN/DJN IF (DABS(X-X0).GT.1.0D-9) GO TO 10 L=L+1 RJ0(L)=X X=X+3.1416+(0.0972+0.0679*N-0.000354*N**2)/L IF (L.LT.NT) GO TO 10 IF (N.LE.20) THEN X=0.961587+1.07703*N ELSE X=N+0.80861*N**0.33333+0.07249/N**0.33333 ENDIF IF (N.EQ.0) X=3.8317 L=0 15 X0=X CALL JYNDD(N,X,BJN,DJN,FJN,BYN,DYN,FYN) X=X-DJN/FJN IF (DABS(X-X0).GT.1.0D-9) GO TO 15 L=L+1 RJ1(L)=X X=X+3.1416+(0.4955+0.0915*N-0.000435*N**2)/L IF (L.LT.NT) GO TO 15 IF (N.LE.20) THEN X=1.19477+1.08933*N ELSE X=N+0.93158*N**0.33333+0.26035/N**0.33333 ENDIF L=0 20 X0=X CALL JYNDD(N,X,BJN,DJN,FJN,BYN,DYN,FYN) X=X-BYN/DYN IF (DABS(X-X0).GT.1.0D-9) GO TO 20 L=L+1 RY0(L)=X X=X+3.1416+(0.312+0.0852*N-0.000403*N**2)/L IF (L.LT.NT) GO TO 20 IF (N.LE.20) THEN X=2.67257+1.16099*N ELSE X=N+1.8211*N**0.33333+0.94001/N**0.33333 ENDIF L=0 25 X0=X CALL JYNDD(N,X,BJN,DJN,FJN,BYN,DYN,FYN) X=X-DYN/FYN IF (DABS(X-X0).GT.1.0D-9) GO TO 25 L=L+1 RY1(L)=X X=X+3.1416+(0.197+0.0643*N-0.000286*N**2)/L IF (L.LT.NT) GO TO 25 RETURN END SUBROUTINE JYNDD(N,X,BJN,DJN,FJN,BYN,DYN,FYN) C C =========================================================== C Purpose: Compute Bessel functions Jn(x) and Yn(x), and C their first and second derivatives C Input: x --- Argument of Jn(x) and Yn(x) ( x > 0 ) C n --- Order of Jn(x) and Yn(x) C Output: BJN --- Jn(x) C DJN --- Jn'(x) C FJN --- Jn"(x) C BYN --- Yn(x) C DYN --- Yn'(x) C FYN --- Yn"(x) C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BJ(102),BY(102) DO 10 NT=1,900 MT=INT(0.5*LOG10(6.28*NT)-NT*LOG10(1.36*DABS(X)/NT)) IF (MT.GT.20) GO TO 15 10 CONTINUE 15 M=NT BS=0.0D0 F0=0.0D0 F1=1.0D-35 SU=0.0D0 DO 20 K=M,0,-1 F=2.0D0*(K+1.0D0)*F1/X-F0 IF (K.LE.N+1) BJ(K+1)=F IF (K.EQ.2*INT(K/2)) THEN BS=BS+2.0D0*F IF (K.NE.0) SU=SU+(-1)**(K/2)*F/K ENDIF F0=F1 20 F1=F DO 25 K=0,N+1 25 BJ(K+1)=BJ(K+1)/(BS-F) BJN=BJ(N+1) EC=0.5772156649015329D0 E0=0.3183098861837907D0 S1=2.0D0*E0*(DLOG(X/2.0D0)+EC)*BJ(1) F0=S1-8.0D0*E0*SU/(BS-F) F1=(BJ(2)*F0-2.0D0*E0/X)/BJ(1) BY(1)=F0 BY(2)=F1 DO 30 K=2,N+1 F=2.0D0*(K-1.0D0)*F1/X-F0 BY(K+1)=F F0=F1 30 F1=F BYN=BY(N+1) DJN=-BJ(N+2)+N*BJ(N+1)/X DYN=-BY(N+2)+N*BY(N+1)/X FJN=(N*N/(X*X)-1.0D0)*BJN-DJN/X FYN=(N*N/(X*X)-1.0D0)*BYN-DYN/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mklvna.for000077500000000000000000000163161321604176500261250ustar00rootroot00000000000000 PROGRAM MKLVNA C C ======================================================= C Purpose: This program computes Kelvin functions ber x, C bei x, ker x and kei x, and their derivatives C using subroutine KLVNA C Input : x --- Argument of Kelvin functions C Output: BER --- ber x C BEI --- bei x C GER --- ker x C GEI --- kei x C DER --- ber'x C DEI --- bei'x C HER --- ker'x C HEI --- kei'x C Example: C C x ber x bei x ker x kei x C ----------------------------------------------------------------- C 0 .1000000D+01 0 ì -.7853982D+00 C 5 -.6230082D+01 .1160344D+00 -.1151173D-01 .1118759D-01 C 10 .1388405D+03 .5637046D+02 .1294663D-03 -.3075246D-03 C 15 -.2967255D+04 -.2952708D+04 -.1514347D-07 .7962894D-05 C 20 .4748937D+05 .1147752D+06 -.7715233D-07 -.1858942D-06 C C x ber'x bei'x ker'x kei'x C ----------------------------------------------------------------- C 0 0 0 - ì 0 C 5 -.3845339D+01 -.4354141D+01 .1719340D-01 -.8199865D-03 C 10 .5119526D+02 .1353093D+03 -.3155969D-03 .1409138D-03 C 15 .9105533D+02 -.4087755D+04 .5644678D-05 -.5882223D-05 C 20 -.4880320D+05 .1118550D+06 -.7501859D-07 .1906243D-06 C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X CALL KLVNA(X,BER,BEI,GER,GEI,DER,DEI,HER,HEI) WRITE(*,*)' x ber x bei x', & ' ker x kei x' WRITE(*,*)'--------------------------------', & '--------------------------------------' WRITE(*,10)X,BER,BEI,GER,GEI WRITE(*,*) WRITE(*,*)' x ber''x bei''x', & ' ker''x kei''x' WRITE(*,*)'--------------------------------', & '--------------------------------------' WRITE(*,10)X,DER,DEI,HER,HEI 10 FORMAT(1X,F5.1,4D16.8) END SUBROUTINE KLVNA(X,BER,BEI,GER,GEI,DER,DEI,HER,HEI) C C ====================================================== C Purpose: Compute Kelvin functions ber x, bei x, ker x C and kei x, and their derivatives ( x > 0 ) C Input : x --- Argument of Kelvin functions C Output: BER --- ber x C BEI --- bei x C GER --- ker x C GEI --- kei x C DER --- ber'x C DEI --- bei'x C HER --- ker'x C HEI --- kei'x C ================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 EL=.5772156649015329D0 EPS=1.0D-15 IF (X.EQ.0.0D0) THEN BER=1.0D0 BEI=0.0D0 GER=1.0D+300 GEI=-0.25D0*PI DER=0.0D0 DEI=0.0D0 HER=-1.0D+300 HEI=0.0D0 RETURN ENDIF X2=0.25D0*X*X X4=X2*X2 IF (DABS(X).LT.10.0D0) THEN BER=1.0D0 R=1.0D0 DO 10 M=1,60 R=-0.25D0*R/(M*M)/(2.0D0*M-1.0D0)**2*X4 BER=BER+R IF (DABS(R).LT.DABS(BER)*EPS) GO TO 15 10 CONTINUE 15 BEI=X2 R=X2 DO 20 M=1,60 R=-0.25D0*R/(M*M)/(2.0D0*M+1.0D0)**2*X4 BEI=BEI+R IF (DABS(R).LT.DABS(BEI)*EPS) GO TO 25 20 CONTINUE 25 GER=-(DLOG(X/2.0D0)+EL)*BER+0.25D0*PI*BEI R=1.0D0 GS=0.0D0 DO 30 M=1,60 R=-0.25D0*R/(M*M)/(2.0D0*M-1.0D0)**2*X4 GS=GS+1.0D0/(2.0D0*M-1.0D0)+1.0D0/(2.0D0*M) GER=GER+R*GS IF (DABS(R*GS).LT.DABS(GER)*EPS) GO TO 35 30 CONTINUE 35 GEI=X2-(DLOG(X/2.0D0)+EL)*BEI-0.25D0*PI*BER R=X2 GS=1.0D0 DO 40 M=1,60 R=-0.25D0*R/(M*M)/(2.0D0*M+1.0D0)**2*X4 GS=GS+1.0D0/(2.0D0*M)+1.0D0/(2.0D0*M+1.0D0) GEI=GEI+R*GS IF (DABS(R*GS).LT.DABS(GEI)*EPS) GO TO 45 40 CONTINUE 45 DER=-0.25D0*X*X2 R=DER DO 50 M=1,60 R=-0.25D0*R/M/(M+1.0D0)/(2.0D0*M+1.0D0)**2*X4 DER=DER+R IF (DABS(R).LT.DABS(DER)*EPS) GO TO 55 50 CONTINUE 55 DEI=0.5D0*X R=DEI DO 60 M=1,60 R=-0.25D0*R/(M*M)/(2.D0*M-1.D0)/(2.D0*M+1.D0)*X4 DEI=DEI+R IF (DABS(R).LT.DABS(DEI)*EPS) GO TO 65 60 CONTINUE 65 R=-0.25D0*X*X2 GS=1.5D0 HER=1.5D0*R-BER/X-(DLOG(X/2.D0)+EL)*DER+0.25*PI*DEI DO 70 M=1,60 R=-0.25D0*R/M/(M+1.0D0)/(2.0D0*M+1.0D0)**2*X4 GS=GS+1.0D0/(2*M+1.0D0)+1.0D0/(2*M+2.0D0) HER=HER+R*GS IF (DABS(R*GS).LT.DABS(HER)*EPS) GO TO 75 70 CONTINUE 75 R=0.5D0*X GS=1.0D0 HEI=0.5D0*X-BEI/X-(DLOG(X/2.D0)+EL)*DEI-0.25*PI*DER DO 80 M=1,60 R=-0.25D0*R/(M*M)/(2*M-1.0D0)/(2*M+1.0D0)*X4 GS=GS+1.0D0/(2.0D0*M)+1.0D0/(2*M+1.0D0) HEI=HEI+R*GS IF (DABS(R*GS).LT.DABS(HEI)*EPS) RETURN 80 CONTINUE ELSE PP0=1.0D0 PN0=1.0D0 QP0=0.0D0 QN0=0.0D0 R0=1.0D0 KM=18 IF (DABS(X).GE.40.0) KM=10 FAC=1.0D0 DO 85 K=1,KM FAC=-FAC XT=0.25D0*K*PI-INT(0.125D0*K)*2.0D0*PI CS=COS(XT) SS=SIN(XT) R0=0.125D0*R0*(2.0D0*K-1.0D0)**2/K/X RC=R0*CS RS=R0*SS PP0=PP0+RC PN0=PN0+FAC*RC QP0=QP0+RS 85 QN0=QN0+FAC*RS XD=X/DSQRT(2.0D0) XE1=DEXP(XD) XE2=DEXP(-XD) XC1=1.D0/DSQRT(2.0D0*PI*X) XC2=DSQRT(.5D0*PI/X) CP0=DCOS(XD+0.125D0*PI) CN0=DCOS(XD-0.125D0*PI) SP0=DSIN(XD+0.125D0*PI) SN0=DSIN(XD-0.125D0*PI) GER=XC2*XE2*(PN0*CP0-QN0*SP0) GEI=XC2*XE2*(-PN0*SP0-QN0*CP0) BER=XC1*XE1*(PP0*CN0+QP0*SN0)-GEI/PI BEI=XC1*XE1*(PP0*SN0-QP0*CN0)+GER/PI PP1=1.0D0 PN1=1.0D0 QP1=0.0D0 QN1=0.0D0 R1=1.0D0 FAC=1.0D0 DO 90 K=1,KM FAC=-FAC XT=0.25D0*K*PI-INT(0.125D0*K)*2.0D0*PI CS=DCOS(XT) SS=DSIN(XT) R1=0.125D0*R1*(4.D0-(2.0D0*K-1.0D0)**2)/K/X RC=R1*CS RS=R1*SS PP1=PP1+FAC*RC PN1=PN1+RC QP1=QP1+FAC*RS QN1=QN1+RS 90 CONTINUE HER=XC2*XE2*(-PN1*CN0+QN1*SN0) HEI=XC2*XE2*(PN1*SN0+QN1*CN0) DER=XC1*XE1*(PP1*CP0+QP1*SP0)-HEI/PI DEI=XC1*XE1*(PP1*SP0-QP1*CP0)+HER/PI ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mklvnb.for000077500000000000000000000141041321604176500261170ustar00rootroot00000000000000 PROGRAM MKLVNB C C ======================================================== C Purpose: This program computes Kelvin functions ber x, C bei x, ker x and kei x, and their derivatives C using subroutine KLVNB C Input : x --- Argument of Kelvin functions C Output: BER --- ber x C BEI --- bei x C GER --- ker x C GEI --- kei x C DER --- ber'x C DEI --- bei'x C HER --- ker'x C HEI --- kei'x C Example: C x ber x bei x ker x kei x C ------------------------------------------------------------- C 0 .100000D+01 .000000D+00 ì -.785398D+00 C 5 -.623008D+01 .116034D+00 -.115117D-01 .111876D-01 C 10 .138840D+03 .563705D+02 .129466D-03 -.307525D-03 C 15 -.296725D+04 -.295271D+04 -.151433D-07 .796289D-05 C 20 .474894D+05 .114775D+06 -.771523D-07 -.185894D-06 C C x ber'x bei'x ker'x kei'x C ------------------------------------------------------------- C 0 .000000D+00 .000000D+00 - ì .000000D+00 C 5 -.384534D+01 -.435414D+01 .171934D-01 -.819979D-03 C 10 .511952D+02 .135309D+03 -.315597D-03 .140914D-03 C 15 .910555D+02 -.408776D+04 .564468D-05 -.588222D-05 C 20 -.488032D+05 .111855D+06 -.750186D-07 .190624D-06 C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x ber x bei x', & ' ker x kei x' WRITE(*,*)'--------------------------------', & '--------------------------------------' CALL KLVNB(X,BER,BEI,GER,GEI,DER,DEI,HER,HEI) WRITE(*,10)X,BER,BEI,GER,GEI WRITE(*,*) WRITE(*,*)' x ber''x bei''x', & ' ker''x kei''x' WRITE(*,*)'--------------------------------', & '--------------------------------------' WRITE(*,10)X,DER,DEI,HER,HEI 10 FORMAT(1X,F5.1,4D16.6) END SUBROUTINE KLVNB(X,BER,BEI,GER,GEI,DER,DEI,HER,HEI) C C ====================================================== C Purpose: Compute Kelvin functions ber x, bei x, ker x C and kei x, and their derivatives ( x > 0 ) C Input : x --- Argument of Kelvin functions C Output: BER --- ber x C BEI --- bei x C GER --- ker x C GEI --- kei x C DER --- ber'x C DEI --- bei'x C HER --- ker'x C HEI --- kei'x C ================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 IF (X.EQ.0.0D0) THEN BER=1.0D0 BEI=0.0D0 GER=1.0D+300 GEI=-.25D0*PI DER=0.0D0 DEI=0.0D0 HER=-1.0D+300 HEI=0.0D0 ELSE IF (X.LT.8.0D0) THEN T=X/8.0D0 T2=T*T U=T2*T2 BER=((((((-.901D-5*U+.122552D-2)*U-.08349609D0)*U & +2.64191397D0)*U-32.36345652D0)*U & +113.77777774D0)*U-64.0D0)*U+1.0D0 BEI=T*T*((((((.11346D-3*U-.01103667D0)*U & +.52185615D0)*U-10.56765779D0)*U & +72.81777742D0)*U-113.77777774D0)*U+16.0D0) GER=((((((-.2458D-4*U+.309699D-2)*U-.19636347D0) & *U+5.65539121D0)*U-60.60977451D0)*U+ & 171.36272133D0)*U-59.05819744D0)*U-.57721566D0 GER=GER-DLOG(.5D0*X)*BER+.25D0*PI*BEI GEI=T2*((((((.29532D-3*U-.02695875D0)*U & +1.17509064D0)*U-21.30060904D0)*U & +124.2356965D0)*U-142.91827687D0)*U & +6.76454936D0) GEI=GEI-DLOG(.5D0*X)*BEI-.25D0*PI*BER DER=X*T2*((((((-.394D-5*U+.45957D-3)*U & -.02609253D0)*U+.66047849D0)*U-6.0681481D0)*U & +14.22222222D0)*U-4.0D0) DEI=X*((((((.4609D-4*U-.379386D-2)*U+.14677204D0) & *U-2.31167514D0)*U+11.37777772D0)*U & -10.66666666D0)*U+.5D0) HER=X*T2*((((((-.1075D-4*U+.116137D-2)*U & -.06136358D0)*U+1.4138478D0)*U-11.36433272D0) & *U+21.42034017D0)*U-3.69113734D0) HER=HER-DLOG(.5D0*X)*DER-BER/X+.25D0*PI*DEI HEI=X*((((((.11997D-3*U-.926707D-2)*U & +.33049424D0)*U-4.65950823D0)*U+19.41182758D0) & *U-13.39858846D0)*U+.21139217D0) HEI=HEI-DLOG(.5D0*X)*DEI-BEI/X-.25D0*PI*DER ELSE T=8.0D0/X DO 10 L=1,2 V=(-1)**L*T TPR=((((.6D-6*V-.34D-5)*V-.252D-4)*V-.906D-4) & *V*V+.0110486D0)*V TPI=((((.19D-5*V+.51D-5)*V*V-.901D-4)*V & -.9765D-3)*V-.0110485D0)*V-.3926991D0 IF (L.EQ.1) THEN TNR=TPR TNI=TPI ENDIF 10 CONTINUE YD=X/DSQRT(2.0D0) YE1=DEXP(YD+TPR) YE2=DEXP(-YD+TNR) YC1=1.0D0/DSQRT(2.0D0*PI*X) YC2=DSQRT(PI/(2.0D0*X)) CSP=DCOS(YD+TPI) SSP=DSIN(YD+TPI) CSN=DCOS(-YD+TNI) SSN=DSIN(-YD+TNI) GER=YC2*YE2*CSN GEI=YC2*YE2*SSN FXR=YC1*YE1*CSP FXI=YC1*YE1*SSP BER=FXR-GEI/PI BEI=FXI+GER/PI DO 15 L=1,2 V=(-1)**L*T PPR=(((((.16D-5*V+.117D-4)*V+.346D-4)*V+.5D-6) & *V-.13813D-2)*V-.0625001D0)*V+.7071068D0 PPI=(((((-.32D-5*V-.24D-5)*V+.338D-4)*V+ & .2452D-3)*V+.13811D-2)*V-.1D-6)*V+.7071068D0 IF (L.EQ.1) THEN PNR=PPR PNI=PPI ENDIF 15 CONTINUE HER=GEI*PNI-GER*PNR HEI=-(GEI*PNR+GER*PNI) DER=FXR*PPR-FXI*PPI-HEI/PI DEI=FXI*PPR+FXR*PPI+HER/PI ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mklvnzo.for000077500000000000000000000230331321604176500263270ustar00rootroot00000000000000 PROGRAM MKLVNZO C C ============================================================== C Purpose: This program computes the first NT zeros of Kelvin C functions and their derivatives using subroutine C KLVNZO C Input : NT --- Total number of zeros C Example: NT = 5 C C Zeros of Kelvin functions ber x, bei x, ker x and kei x C C m ber x bei x ker x kei x C --------------------------------------------------------------- C 1 2.84891782 5.02622395 1.71854296 3.91466761 C 2 7.23882945 9.45540630 6.12727913 8.34422506 C 3 11.67396355 13.89348785 10.56294271 12.78255715 C 4 16.11356383 18.33398346 15.00268812 17.22314372 C 5 20.55463158 22.77543929 19.44381663 21.66464214 C C Zeros of Kelvin Functions ber'x, bei'x, ker'x and kei'x C C m ber'x bei'x ker'x kei'x C --------------------------------------------------------------- C 1 6.03871081 3.77267330 2.66583979 4.93181194 C 2 10.51364251 8.28098785 7.17212212 9.40405458 C 3 14.96844542 12.74214752 11.63218639 13.85826916 C 4 19.41757493 17.19343175 16.08312025 18.30717294 C 5 23.86430432 21.64114394 20.53067845 22.75379258 C ============================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION R1(50),R2(50),R3(50),R4(50),R5(50),R6(50), & R7(50),R8(50) WRITE(*,35) WRITE(*,*)'Please enter NT ' READ(*,*)NT WRITE(*,25) WRITE(*,*) WRITE(*,*)' m ber x bei x ker x', & ' kei x' WRITE(*,*)' ------------------------------------------------', & '---------------' CALL KLVNZO(NT,1,R1) CALL KLVNZO(NT,2,R2) CALL KLVNZO(NT,3,R3) CALL KLVNZO(NT,4,R4) DO 10 L=1,NT 10 WRITE(*,20)L,R1(L),R2(L),R3(L),R4(L) CALL KLVNZO(NT,5,R5) CALL KLVNZO(NT,6,R6) CALL KLVNZO(NT,7,R7) CALL KLVNZO(NT,8,R8) WRITE(*,*) WRITE(*,30) WRITE(*,*) WRITE(*,*)' m ber''x bei''x ker''x', & ' kei''x' WRITE(*,*)' ------------------------------------------------', & '---------------' DO 15 L=1,NT 15 WRITE(*,20)L,R5(L),R6(L),R7(L),R8(L) CLOSE (01) 20 FORMAT(1X,I3,1X,F14.8,1X,F14.8,1X,F14.8,1X,F14.8) 25 FORMAT(4X,'Zeros of Kelvin functions ber x, bei x,' & ,' ker x and kei x') 30 FORMAT(4X,'Zeros of Kelvin functions ber''x, bei''x,' & ,' ker''x and kei''x') 35 FORMAT(1X,'NT is the number of the zeros') END SUBROUTINE KLVNZO(NT,KD,ZO) C C ==================================================== C Purpose: Compute the zeros of Kelvin functions C Input : NT --- Total number of zeros C KD --- Function code C KD=1 to 8 for ber x, bei x, ker x, kei x, C ber'x, bei'x, ker'x and kei'x, C respectively. C Output: ZO(M) --- the M-th zero of Kelvin function C for code KD C Routine called: C KLVNA for computing Kelvin functions and C their derivatives C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION ZO(NT),RT0(8) RT0(1)=2.84891 RT0(2)=5.02622 RT0(3)=1.71854 RT0(4)=3.91467 RT0(5)=6.03871 RT0(6)=3.77268 RT0(7)=2.66584 RT0(8)=4.93181 RT=RT0(KD) DO 15 M=1,NT 10 CALL KLVNA(RT,BER,BEI,GER,GEI,DER,DEI,HER,HEI) IF (KD.EQ.1) THEN RT=RT-BER/DER ELSE IF (KD.EQ.2) THEN RT=RT-BEI/DEI ELSE IF (KD.EQ.3) THEN RT=RT-GER/HER ELSE IF (KD.EQ.4) THEN RT=RT-GEI/HEI ELSE IF (KD.EQ.5) THEN DDR=-BEI-DER/RT RT=RT-DER/DDR ELSE IF (KD.EQ.6) THEN DDI=BER-DEI/RT RT=RT-DEI/DDI ELSE IF (KD.EQ.7) THEN GDR=-GEI-HER/RT RT=RT-HER/GDR ELSE GDI=GER-HEI/RT RT=RT-HEI/GDI ENDIF IF (DABS(RT-RT0(KD)).GT.5.0D-10) THEN RT0(KD)=RT GO TO 10 ENDIF ZO(M)=RT 15 RT=RT+4.44D0 RETURN END SUBROUTINE KLVNA(X,BER,BEI,GER,GEI,DER,DEI,HER,HEI) C C ====================================================== C Purpose: Compute Kelvin functions ber x, bei x, ker x C and kei x, and their derivatives ( x > 0 ) C Input : x --- Argument of Kelvin functions C Output: BER --- ber x C BEI --- bei x C GER --- ker x C GEI --- kei x C DER --- ber'x C DEI --- bei'x C HER --- ker'x C HEI --- kei'x C ================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 EL=.5772156649015329D0 EPS=1.0D-15 IF (X.EQ.0.0D0) THEN BER=1.0D0 BEI=0.0D0 GER=1.0D+300 GEI=-.25D0*PI DER=0.0D0 DEI=0.0D0 HER=-1.0D+300 HEI=0.0D0 RETURN ENDIF X2=.25D0*X*X X4=X2*X2 IF (DABS(X).LT.10.0D0) THEN BER=1.0D0 R=1.0D0 DO 10 M=1,60 R=-.25D0*R/(M*M)/(2.0D0*M-1.0D0)**2*X4 BER=BER+R IF (DABS(R/BER).LT.EPS) GO TO 15 10 CONTINUE 15 BEI=X2 R=X2 DO 20 M=1,60 R=-.25D0*R/(M*M)/(2.0D0*M+1.0D0)**2*X4 BEI=BEI+R IF (DABS(R/BEI).LT.EPS) GO TO 25 20 CONTINUE 25 GER=-(DLOG(X/2.0D0)+EL)*BER+.25D0*PI*BEI R=1.0D0 GS=0.0D0 DO 30 M=1,60 R=-.25D0*R/(M*M)/(2.0D0*M-1.0D0)**2*X4 GS=GS+1.0D0/(2.0D0*M-1.0D0)+1.0D0/(2.0D0*M) GER=GER+R*GS IF (DABS(R*GS/GER).LT.EPS) GO TO 35 30 CONTINUE 35 GEI=X2-(DLOG(X/2.0D0)+EL)*BEI-.25D0*PI*BER R=X2 GS=1.0D0 DO 40 M=1,60 R=-.25D0*R/(M*M)/(2.0D0*M+1.0D0)**2*X4 GS=GS+1.0D0/(2.0D0*M)+1.0D0/(2.0D0*M+1.0D0) GEI=GEI+R*GS IF (DABS(R*GS/GEI).LT.EPS) GO TO 45 40 CONTINUE 45 DER=-.25D0*X*X2 R=DER DO 50 M=1,60 R=-.25D0*R/M/(M+1.0D0)/(2.0D0*M+1.0D0)**2*X4 DER=DER+R IF (DABS(R/DER).LT.EPS) GO TO 55 50 CONTINUE 55 DEI=.5D0*X R=DEI DO 60 M=1,60 R=-.25D0*R/(M*M)/(2.D0*M-1.D0)/(2.D0*M+1.D0)*X4 DEI=DEI+R IF (DABS(R/DEI).LT.EPS) GO TO 65 60 CONTINUE 65 R=-.25D0*X*X2 GS=1.5D0 HER=1.5D0*R-BER/X-(DLOG(X/2.D0)+EL)*DER+.25*PI*DEI DO 70 M=1,60 R=-.25D0*R/M/(M+1.0D0)/(2.0D0*M+1.0D0)**2*X4 GS=GS+1.0D0/(2*M+1.0D0)+1.0D0/(2*M+2.0D0) HER=HER+R*GS IF (DABS(R*GS/HER).LT.EPS) GO TO 75 70 CONTINUE 75 R=.5D0*X GS=1.0D0 HEI=.5D0*X-BEI/X-(DLOG(X/2.D0)+EL)*DEI-.25*PI*DER DO 80 M=1,60 R=-.25D0*R/(M*M)/(2*M-1.0D0)/(2*M+1.0D0)*X4 GS=GS+1.0D0/(2.0D0*M)+1.0D0/(2*M+1.0D0) HEI=HEI+R*GS IF (DABS(R*GS/HEI).LT.EPS) RETURN 80 CONTINUE ELSE PP0=1.0D0 PN0=1.0D0 QP0=0.0D0 QN0=0.0D0 R0=1.0D0 KM=18 IF (DABS(X).GE.40.0) KM=10 FAC=1.0D0 DO 85 K=1,KM FAC=-FAC XT=.25D0*K*PI-INT(.125D0*K)*2.0D0*PI CS=COS(XT) SS=SIN(XT) R0=.125D0*R0*(2.0D0*K-1.0D0)**2/K/X RC=R0*CS RS=R0*SS PP0=PP0+RC PN0=PN0+FAC*RC QP0=QP0+RS 85 QN0=QN0+FAC*RS XD=X/DSQRT(2.0D0) XE1=DEXP(XD) XE2=DEXP(-XD) XC1=1.D0/DSQRT(2.0D0*PI*X) XC2=DSQRT(.5D0*PI/X) CP0=DCOS(XD+.125D0*PI) CN0=DCOS(XD-.125D0*PI) SP0=DSIN(XD+.125D0*PI) SN0=DSIN(XD-.125D0*PI) GER=XC2*XE2*(PN0*CP0-QN0*SP0) GEI=XC2*XE2*(-PN0*SP0-QN0*CP0) BER=XC1*XE1*(PP0*CN0+QP0*SN0)-GEI/PI BEI=XC1*XE1*(PP0*SN0-QP0*CN0)+GER/PI PP1=1.0D0 PN1=1.0D0 QP1=0.0D0 QN1=0.0D0 R1=1.0D0 FAC=1.0D0 DO 90 K=1,KM FAC=-FAC XT=.25D0*K*PI-INT(.125D0*K)*2.0D0*PI CS=DCOS(XT) SS=DSIN(XT) R1=.125D0*R1*(4.D0-(2.0D0*K-1.0D0)**2)/K/X RC=R1*CS RS=R1*SS PP1=PP1+FAC*RC PN1=PN1+RC QP1=QP1+FAC*RS QN1=QN1+RS 90 CONTINUE HER=XC2*XE2*(-PN1*CN0+QN1*SN0) HEI=XC2*XE2*(PN1*SN0+QN1*CN0) DER=XC1*XE1*(PP1*CP0+QP1*SP0)-HEI/PI DEI=XC1*XE1*(PP1*SP0-QP1*CP0)+HER/PI ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlagzo.for000077500000000000000000000052311321604176500261200ustar00rootroot00000000000000 PROGRAM MLAGZO C C =========================================================== C Purpose : This program computes the zeros of Laguerre C polynomial Ln(x) in the interval [0,ì] and the C corresponding weighting coefficients for Gauss- C Laguerre integration using subroutine LAGZO C Input : n --- Order of the Laguerre polynomial C X(n) --- Zeros of the Laguerre polynomial C W(n) --- Corresponding weighting coefficients C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION X(100),W(100) WRITE(*,*)'Please enter the order of Ln(x), n ' READ(*,*)N WRITE(*,20)N CALL LAGZO(N,X,W) WRITE(*,*)' Nodes and weights for Gauss-Lagurre integration' WRITE(*,*) WRITE(*,*)' i xi Wi' WRITE(*,*)' -----------------------------------------', & '------------' DO 10 J=1,N 10 WRITE(*,30)J,X(J),W(J) 20 FORMAT(1X,'n =',I3) 30 FORMAT(1X,I3,3X,D22.13,3X,D22.13) END SUBROUTINE LAGZO(N,X,W) C C ========================================================= C Purpose : Compute the zeros of Laguerre polynomial Ln(x) C in the interval [0,ì], and the corresponding C weighting coefficients for Gauss-Laguerre C integration C Input : n --- Order of the Laguerre polynomial C X(n) --- Zeros of the Laguerre polynomial C W(n) --- Corresponding weighting coefficients C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION X(N),W(N) HN=1.0D0/N DO 35 NR=1,N IF (NR.EQ.1) Z=HN IF (NR.GT.1) Z=X(NR-1)+HN*NR**1.27 IT=0 10 IT=IT+1 Z0=Z P=1.0D0 DO 15 I=1,NR-1 15 P=P*(Z-X(I)) F0=1.0D0 F1=1.0D0-Z DO 20 K=2,N PF=((2.0D0*K-1.0D0-Z)*F1-(K-1.0D0)*F0)/K PD=K/Z*(PF-F1) F0=F1 20 F1=PF FD=PF/P Q=0.0D0 DO 30 I=1,NR-1 WP=1.0D0 DO 25 J=1,NR-1 IF (J.EQ.I) GO TO 25 WP=WP*(Z-X(J)) 25 CONTINUE Q=Q+WP 30 CONTINUE GD=(PD-Q*FD)/P Z=Z-FD/GD IF (IT.LE.40.AND.DABS((Z-Z0)/Z).GT.1.0D-15) GO TO 10 X(NR)=Z W(NR)=1.0D0/(Z*PD*PD) 35 CONTINUE RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlamn.for000077500000000000000000000134771321604176500257460ustar00rootroot00000000000000 PROGRAM MLAMN C C ==================================================== C Purpose: This program computes the lambda functions C and their derivatives using subroutine C LAMN C Input: x --- Argument of lambda function C n --- Order of lambda function C ( n = 0,1,..., n ó 250 ) C Output: BL(n) --- Lambda function of order n C DL(n) --- Derivative of lambda function C Example: Nmax = 5, x = 10.00 C C n lambda(x) lambda'(x) C --------------------------------------- C 0 -.24593576D+00 -.43472746D-01 C 1 .86945492D-02 -.50926063D-01 C 2 .20370425D-01 -.46703503D-02 C 3 .28022102D-02 .10540929D-01 C 4 -.84327431D-02 .89879627D-02 C 5 -.89879627D-02 .55521954D-03 C ==================================================== IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BL(0:250),DL(0:250) WRITE(*,*)' Please enter n,x = ?' READ(*,*)N,X WRITE(*,15)N,X IF (N.LE.10) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF CALL LAMN(N,X,NM,BL,DL) WRITE(*,*) WRITE(*,*) ' n lambda(x) lambda''(x)' WRITE(*,*)' ---------------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20)K,BL(K),DL(K) 15 FORMAT(1X,3HN =,I4,6X,3Hx =,F8.2) 20 FORMAT(1X,I3,2D18.8) END SUBROUTINE LAMN(N,X,NM,BL,DL) C C ========================================================= C Purpose: Compute lambda functions and their derivatives C Input: x --- Argument of lambda function C n --- Order of lambda function C Output: BL(n) --- Lambda function of order n C DL(n) --- Derivative of lambda function C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 for computing the start C point for backward recurrence C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BL(0:N),DL(0:N) NM=N IF (DABS(X).LT.1.0D-100) THEN DO 10 K=0,N BL(K)=0.0D0 10 DL(K)=0.0D0 BL(0)=1.0D0 DL(1)=0.5D0 RETURN ENDIF IF (X.LE.12.0D0) THEN X2=X*X DO 25 K=0,N BK=1.0D0 R=1.0D0 DO 15 I=1,50 R=-0.25D0*R*X2/(I*(I+K)) BK=BK+R IF (DABS(R).LT.DABS(BK)*1.0D-15) GO TO 20 15 CONTINUE 20 BL(K)=BK 25 IF (K.GE.1) DL(K-1)=-0.5D0*X/K*BK UK=1.0D0 R=1.0D0 DO 30 I=1,50 R=-0.25D0*R*X2/(I*(I+N+1.0D0)) UK=UK+R IF (DABS(R).LT.DABS(UK)*1.0D-15) GO TO 35 30 CONTINUE 35 DL(N)=-0.5D0*X/(N+1.0D0)*UK RETURN ENDIF IF (N.EQ.0) NM=1 M=MSTA1(X,200) IF (M.LT.NM) THEN NM=M ELSE M=MSTA2(X,NM,15) ENDIF BS=0.0D0 F0=0.0D0 F1=1.0D-100 DO 40 K=M,0,-1 F=2.0D0*(K+1.0D0)*F1/X-F0 IF (K.LE.NM) BL(K)=F IF (K.EQ.2*INT(K/2)) BS=BS+2.0D0*F F0=F1 40 F1=F BG=BS-F DO 45 K=0,NM 45 BL(K)=BL(K)/BG R0=1.0D0 DO 50 K=1,NM R0=2.0D0*R0*K/X 50 BL(K)=R0*BL(K) DL(0)=-0.5D0*X*BL(1) DO 55 K=1,NM 55 DL(K)=2.0D0*K/X*(BL(K-1)-BL(K)) RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlamv.for000077500000000000000000000171031321604176500257440ustar00rootroot00000000000000 PROGRAM MLAMV C C ======================================================= C Purpose: This program computes the lambda functions C for an arbitrary order, and their derivative C using subroutine LAMV C Input : x --- Argument of lambda function C v --- Order of lambda function C ( v = n+v0, 0 ó n ó 250, 0 ó v0 < 1 ) C Output: VL(n) --- Lambda function of order n+v0 C DL(n) --- Derivative of lambda function C Example: x = 10.0 C C v Lambda(x) Lambda'(x) C ------------------------------------------ C 0.25 -.12510515D+00 -.78558916D-01 C 0.50 -.54402111D-01 -.78466942D-01 C 0.75 -.13657787D-01 -.66234027D-01 C 1.00 .86945492D-02 -.50926063D-01 C 1.25 .19639729D-01 -.36186221D-01 C 1.50 .23540083D-01 -.23382658D-01 C 1.75 .23181910D-01 -.12893894D-01 C 2.00 .20370425D-01 -.46703503D-02 C 2.25 .16283799D-01 .15101684D-02 C 2.50 .11691329D-01 .59243767D-02 C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION VL(0:250),DL(0:250) WRITE(*,*)' Please enter v and x ' READ(*,*)V,X WRITE(*,20)V,X IF (V.LE.8) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF WRITE(*,*) WRITE(*,*) ' v Lambda(x) Lambda''(x)' WRITE(*,*)'-------------------------------------------' CALL LAMV(V,X,VM,VL,DL) NM=INT(VM) V0=VM-NM DO 10 K=0,NM,NS VK=K+V0 10 WRITE(*,15)VK,VL(K),DL(K) 15 FORMAT(1X,F6.2,2D18.8) 20 FORMAT(1X,'v =',F6.2,' ','x =',F8.2) END SUBROUTINE LAMV(V,X,VM,VL,DL) C C ========================================================= C Purpose: Compute lambda function with arbitrary order v, C and their derivative C Input : x --- Argument of lambda function C v --- Order of lambda function C Output: VL(n) --- Lambda function of order n+v0 C DL(n) --- Derivative of lambda function C VM --- Highest order computed C Routines called: C (1) MSTA1 and MSTA2 for computing the starting C point for backward recurrence C (2) GAM0 for computing gamma function (|x| ó 1) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION VL(0:*),DL(0:*) PI=3.141592653589793D0 RP2=0.63661977236758D0 X=DABS(X) X2=X*X N=INT(V) V0=V-N VM=V IF (X.LE.12.0D0) THEN DO 25 K=0,N VK=V0+K BK=1.0D0 R=1.0D0 DO 10 I=1,50 R=-0.25D0*R*X2/(I*(I+VK)) BK=BK+R IF (DABS(R).LT.DABS(BK)*1.0D-15) GO TO 15 10 CONTINUE 15 VL(K)=BK UK=1.0D0 R=1.0D0 DO 20 I=1,50 R=-0.25D0*R*X2/(I*(I+VK+1.0D0)) UK=UK+R IF (DABS(R).LT.DABS(UK)*1.0D-15) GO TO 25 20 CONTINUE 25 DL(K)=-0.5D0*X/(VK+1.0D0)*UK RETURN ENDIF K0=11 IF (X.GE.35.0D0) K0=10 IF (X.GE.50.0D0) K0=8 DO 40 J=0,1 VV=4.0D0*(J+V0)*(J+V0) PX=1.0D0 RP=1.0D0 DO 30 K=1,K0 RP=-0.78125D-2*RP*(VV-(4.0*K-3.0)**2.0)*(VV- & (4.0*K-1.0)**2.0)/(K*(2.0*K-1.0)*X2) 30 PX=PX+RP QX=1.0D0 RQ=1.0D0 DO 35 K=1,K0 RQ=-0.78125D-2*RQ*(VV-(4.0*K-1.0)**2.0)*(VV- & (4.0*K+1.0)**2.0)/(K*(2.0*K+1.0)*X2) 35 QX=QX+RQ QX=0.125D0*(VV-1.0D0)*QX/X XK=X-(0.5D0*(J+V0)+0.25D0)*PI A0=DSQRT(RP2/X) CK=DCOS(XK) SK=DSIN(XK) IF (J.EQ.0) BJV0=A0*(PX*CK-QX*SK) IF (J.EQ.1) BJV1=A0*(PX*CK-QX*SK) 40 CONTINUE IF (V0.EQ.0.0D0) THEN GA=1.0D0 ELSE CALL GAM0(V0,GA) GA=V0*GA ENDIF FAC=(2.0D0/X)**V0*GA VL(0)=BJV0 DL(0)=-BJV1+V0/X*BJV0 VL(1)=BJV1 DL(1)=BJV0-(1.0D0+V0)/X*BJV1 R0=2.0D0*(1.0D0+V0)/X IF (N.LE.1) THEN VL(0)=FAC*VL(0) DL(0)=FAC*DL(0)-V0/X*VL(0) VL(1)=FAC*R0*VL(1) DL(1)=FAC*R0*DL(1)-(1.0D0+V0)/X*VL(1) RETURN ENDIF IF (N.GE.2.AND.N.LE.INT(0.9*X)) THEN F0=BJV0 F1=BJV1 DO 45 K=2,N F=2.0D0*(K+V0-1.0D0)/X*F1-F0 F0=F1 F1=F 45 VL(K)=F ELSE IF (N.GE.2) THEN M=MSTA1(X,200) IF (M.LT.N) THEN N=M ELSE M=MSTA2(X,N,15) ENDIF F2=0.0D0 F1=1.0D-100 DO 50 K=M,0,-1 F=2.0D0*(V0+K+1.0D0)/X*F1-F2 IF (K.LE.N) VL(K)=F F2=F1 50 F1=F IF (DABS(BJV0).GT.DABS(BJV1)) CS=BJV0/F IF (DABS(BJV0).LE.DABS(BJV1)) CS=BJV1/F2 DO 55 K=0,N 55 VL(K)=CS*VL(K) ENDIF VL(0)=FAC*VL(0) DO 65 J=1,N RC=FAC*R0 VL(J)=RC*VL(J) DL(J-1)=-0.5D0*X/(J+V0)*VL(J) 65 R0=2.0D0*(J+V0+1)/X*R0 DL(N)=2.0D0*(V0+N)*(VL(N-1)-VL(N))/X VM=N+V0 RETURN END SUBROUTINE GAM0 (X,GA) C C ================================================ C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) ( |x| ó 1 ) C Output: GA --- â(x) C ================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(25) DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0, -.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14/ GR=(25) DO 20 K=24,1,-1 20 GR=GR*X+G(K) GA=1.0D0/(GR*X) RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlegzo.for000077500000000000000000000052231321604176500261250ustar00rootroot00000000000000 PROGRAM MLEGZO C C ============================================================ C Purpose : This program computes the zeros of Legendre C polynomial Pn(x) in the interval [-1,1] and the C corresponding weighting coefficients for Gauss- C Legendre integration using subroutine LEGZO C Input : n --- Order of the Legendre polynomial C Output: X(n) --- Zeros of the Legendre polynomial C W(n) --- Corresponding weighting coefficients C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION X(120),W(120) WRITE(*,*)'Please enter the order of Pn(x), n ' READ(*,*)N WRITE(*,15)N CALL LEGZO(N,X,W) WRITE(*,*)' Nodes and weights for Gauss-Legendre integration' WRITE(*,*) WRITE(*,*)' i xi Wi' WRITE(*,*)' ------------------------------------------------' DO 10 I=1,N 10 WRITE(*,20)I,X(I),W(I) 15 FORMAT(1X,'n =',I3) 20 FORMAT(1X,I3,1X,F22.13,D22.13) END SUBROUTINE LEGZO(N,X,W) C C ========================================================= C Purpose : Compute the zeros of Legendre polynomial Pn(x) C in the interval [-1,1], and the corresponding C weighting coefficients for Gauss-Legendre C integration C Input : n --- Order of the Legendre polynomial C Output: X(n) --- Zeros of the Legendre polynomial C W(n) --- Corresponding weighting coefficients C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION X(N),W(N) N0=(N+1)/2 DO 45 NR=1,N0 Z=DCOS(3.1415926D0*(NR-0.25D0)/N) 10 Z0=Z P=1.0D0 DO 15 I=1,NR-1 15 P=P*(Z-X(I)) F0=1.0D0 IF (NR.EQ.N0.AND.N.NE.2*INT(N/2)) Z=0.0D0 F1=Z DO 20 K=2,N PF=(2.0D0-1.0D0/K)*Z*F1-(1.0D0-1.0D0/K)*F0 PD=K*(F1-Z*PF)/(1.0D0-Z*Z) F0=F1 20 F1=PF IF (Z.EQ.0.0) GO TO 40 FD=PF/P Q=0.0D0 DO 35 I=1,NR-1 WP=1.0D0 DO 30 J=1,NR-1 IF (J.NE.I) WP=WP*(Z-X(J)) 30 CONTINUE 35 Q=Q+WP GD=(PD-Q*FD)/P Z=Z-FD/GD IF (DABS(Z-Z0).GT.DABS(Z)*1.0D-15) GO TO 10 40 X(NR)=Z X(N+1-NR)=-Z W(NR)=2.0D0/((1.0D0-Z*Z)*PD*PD) 45 W(N+1-NR)=W(NR) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlgama.for000077500000000000000000000044071321604176500260710ustar00rootroot00000000000000 PROGRAM MLGAMA C C =================================================== C Purpose: This program computes the gamma function C â(x) for x > 0 using subroutine LGAMA C Examples: C x â(x) C ------------------------- C 0.5 .1772453851D+01 C 2.5 .1329340388D+01 C 5.0 .2400000000D+02 C 7.5 .1871254306D+04 C 10.0 .3628800000D+06 C =================================================== C IMPLICIT DOUBLE PRECISION (G,X) WRITE(*,*)' x â(x)' WRITE(*,*)' -------------------------' DO 10 L=0,20,5 X=0.5D0*L IF (L.EQ.0) X=0.5 CALL LGAMA(1,X,GL) WRITE(*,20)X,GL 10 CONTINUE WRITE(*,*) 'Please enter x:' READ(*,*) X CALL LGAMA(1,X,GL) WRITE(*,20)X,GL 20 FORMAT(1X,F5.1,D20.10) END SUBROUTINE LGAMA(KF,X,GL) C C ================================================== C Purpose: Compute gamma function â(x) or ln[â(x)] C Input: x --- Argument of â(x) ( x > 0 ) C KF --- Function code C KF=1 for â(x); KF=0 for ln[â(x)] C Output: GL --- â(x) or ln[â(x)] C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(10) DATA A/8.333333333333333D-02,-2.777777777777778D-03, & 7.936507936507937D-04,-5.952380952380952D-04, & 8.417508417508418D-04,-1.917526917526918D-03, & 6.410256410256410D-03,-2.955065359477124D-02, & 1.796443723688307D-01,-1.39243221690590D+00/ X0=X IF (X.EQ.1.0.OR.X.EQ.2.0) THEN GL=0.0D0 GO TO 20 ELSE IF (X.LE.7.0) THEN N=INT(7-X) X0=X+N ENDIF X2=1.0D0/(X0*X0) XP=6.283185307179586477D0 GL0=A(10) DO 10 K=9,1,-1 10 GL0=GL0*X2+A(K) GL=GL0/X0+0.5D0*DLOG(XP)+(X0-.5D0)*DLOG(X0)-X0 IF (X.LE.7.0) THEN DO 15 K=1,N GL=GL-DLOG(X0-1.0D0) 15 X0=X0-1.0D0 ENDIF 20 IF (KF.EQ.1) GL=DEXP(GL) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlpmn.for000077500000000000000000000074601321604176500257600ustar00rootroot00000000000000 PROGRAM MLPMN C C ========================================================== C Purpose: This program computes the associated Legendre C functions Pmn(x) and their derivatives Pmn'(x) C using subroutine LPMN C Input : x --- Argument of Pmn(x) C m --- Order of Pmn(x), m = 0,1,2,...,n C n --- Degree of Pmn(x), n = 0,1,2,...,N C Output: PM(m,n) --- Pmn(x) C PD(m,n) --- Pmn'(x) C Example: x = 0.50 C Pmn(x): C m\n 1 2 3 4 C -------------------------------------------------------- C 0 .500000 -.125000 -.437500 -.289063 C 1 -.866025 -1.299038 -.324760 1.353165 C 2 .000000 2.250000 5.625000 4.218750 C 3 .000000 .000000 -9.742786 -34.099750 C 4 .000000 .000000 .000000 59.062500 C C Pmn'(x): C m\n 1 2 3 4 C -------------------------------------------------------- C 0 1.000000 1.500000 .375000 -1.562500 C 1 .577350 -1.732051 -6.278684 -5.773503 C 2 .000000 -3.000000 3.750000 33.750000 C 3 .000000 .000000 19.485572 .000000 C 4 .000000 .000000 .000000 -157.500000 C ========================================================== C IMPLICIT DOUBLE PRECISION (P,X) DIMENSION PM(0:100,0:100),PD(0:100,0:100) WRITE(*,*)' Please enter m, n and x' READ(*,*) M,N,X WRITE(*,*) WRITE(*,*)' m n x Pmn(x) Pmn''(x)' WRITE(*,*)' ---------------------------------------------------' CALL LPMN(100,M,N,X,PM,PD) DO 15 J=0,N WRITE(*,10)M,J,X,PM(M,J),PD(M,J) 15 CONTINUE 10 FORMAT(1X,I3,3X,I3,3X,F5.1,2E17.8) END SUBROUTINE LPMN(MM,M,N,X,PM,PD) C C ===================================================== C Purpose: Compute the associated Legendre functions C Pmn(x) and their derivatives Pmn'(x) C Input : x --- Argument of Pmn(x) C m --- Order of Pmn(x), m = 0,1,2,...,n C n --- Degree of Pmn(x), n = 0,1,2,...,N C mm --- Physical dimension of PM and PD C Output: PM(m,n) --- Pmn(x) C PD(m,n) --- Pmn'(x) C ===================================================== C IMPLICIT DOUBLE PRECISION (P,X) DIMENSION PM(0:MM,0:N),PD(0:MM,0:N) DO 10 I=0,N DO 10 J=0,M PM(J,I)=0.0D0 10 PD(J,I)=0.0D0 PM(0,0)=1.0D0 IF (DABS(X).EQ.1.0D0) THEN DO 15 I=1,N PM(0,I)=X**I 15 PD(0,I)=0.5D0*I*(I+1.0D0)*X**(I+1) DO 20 J=1,N DO 20 I=1,M IF (I.EQ.1) THEN PD(I,J)=1.0D+300 ELSE IF (I.EQ.2) THEN PD(I,J)=-0.25D0*(J+2)*(J+1)*J*(J-1)*X**(J+1) ENDIF 20 CONTINUE RETURN ENDIF LS=1 IF (DABS(X).GT.1.0D0) LS=-1 XQ=DSQRT(LS*(1.0D0-X*X)) XS=LS*(1.0D0-X*X) DO 30 I=1,M 30 PM(I,I)=-LS*(2.0D0*I-1.0D0)*XQ*PM(I-1,I-1) DO 35 I=0,M 35 PM(I,I+1)=(2.0D0*I+1.0D0)*X*PM(I,I) DO 40 I=0,M DO 40 J=I+2,N PM(I,J)=((2.0D0*J-1.0D0)*X*PM(I,J-1)- & (I+J-1.0D0)*PM(I,J-2))/(J-I) 40 CONTINUE PD(0,0)=0.0D0 DO 45 J=1,N 45 PD(0,J)=LS*J*(PM(0,J-1)-X*PM(0,J))/XS DO 50 I=1,M DO 50 J=I,N PD(I,J)=LS*I*X*PM(I,J)/XS+(J+I) & *(J-I+1.0D0)/XQ*PM(I-1,J) 50 CONTINUE RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlpmns.for000077500000000000000000000073761321604176500261510ustar00rootroot00000000000000 PROGRAM MLPMNS C C ======================================================== C Purpose: This program computes the associated Legendre C functions Pmn(x) and their derivatives Pmn'(x) C for a given order using subroutine LPMNS C Input : x --- Argument of Pmn(x) C m --- Order of Pmn(x), m = 0,1,2,...,n C n --- Degree of Pmn(x), n = 0,1,2,...,N C Output: PM(n) --- Pmn(x) C PD(n) --- Pmn'(x) C Examples: C m = 1, N = 5, x = .5 C n Pmn(x) Pmn'(x) C ------------------------------------- C 0 .00000000D+00 .00000000D+00 C 1 .86602540D+00 -.57735027D+00 C 2 .12990381D+01 .17320508D+01 C 3 .32475953D+00 .62786842D+01 C 4 -.13531647D+01 .57735027D+01 C 5 -.19282597D+01 -.43977853D+01 C C m = 2, N = 6, x = 2.5 C n Pmn(x) Pmn'(x) C ------------------------------------- C 0 .00000000D+00 .00000000D+00 C 1 .00000000D+00 .00000000D+00 C 2 .15750000D+02 .15000000D+02 C 3 .19687500D+03 .26625000D+03 C 4 .16832813D+04 .29812500D+04 C 5 .12230859D+05 .26876719D+05 C 6 .81141416D+05 .21319512D+06 C ======================================================= C IMPLICIT DOUBLE PRECISION (P,X,Y) DIMENSION PM(0:200),PD(0:200) WRITE(*,*)'Please enter m, N, and x ' READ(*,*)M,N,X WRITE(*,30)M,N,X CALL LPMNS(M,N,X,PM,PD) WRITE(*,*) WRITE(*,*)' n Pmn(x) Pmn''(x) ' WRITE(*,*)' -------------------------------------' DO 10 J=0,N WRITE(*,20)J,PM(J),PD(J) 10 CONTINUE 20 FORMAT(1X,I3,2D17.8) 30 FORMAT(1X,'m =',I2,', ','n =',I2,', ','x =',F5.1) END SUBROUTINE LPMNS(M,N,X,PM,PD) C C ======================================================== C Purpose: Compute associated Legendre functions Pmn(x) C and Pmn'(x) for a given order C Input : x --- Argument of Pmn(x) C m --- Order of Pmn(x), m = 0,1,2,...,n C n --- Degree of Pmn(x), n = 0,1,2,...,N C Output: PM(n) --- Pmn(x) C PD(n) --- Pmn'(x) C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION PM(0:N),PD(0:N) DO 10 K=0,N PM(K)=0.0D0 10 PD(K)=0.0D0 IF (DABS(X).EQ.1.0D0) THEN DO 15 K=0,N IF (M.EQ.0) THEN PM(K)=1.0D0 PD(K)=0.5D0*K*(K+1.0) IF (X.LT.0.0) THEN PM(K)=(-1)**K*PM(K) PD(K)=(-1)**(K+1)*PD(K) ENDIF ELSE IF (M.EQ.1) THEN PD(K)=1.0D+300 ELSE IF (M.EQ.2) THEN PD(K)=-0.25D0*(K+2.0)*(K+1.0)*K*(K-1.0) IF (X.LT.0.0) PD(K)=(-1)**(K+1)*PD(K) ENDIF 15 CONTINUE RETURN ENDIF X0=DABS(1.0D0-X*X) PM0=1.0D0 PMK=PM0 DO 20 K=1,M PMK=(2.0D0*K-1.0D0)*DSQRT(X0)*PM0 20 PM0=PMK PM1=(2.0D0*M+1.0D0)*X*PM0 PM(M)=PMK PM(M+1)=PM1 DO 25 K=M+2,N PM2=((2.0D0*K-1.0D0)*X*PM1-(K+M-1.0D0)*PMK)/(K-M) PM(K)=PM2 PMK=PM1 25 PM1=PM2 PD(0)=((1.0D0-M)*PM(1)-X*PM(0))/(X*X-1.0) DO 30 K=1,N 30 PD(K)=(K*X*PM(K)-(K+M)*PM(K-1))/(X*X-1.0D0) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlpmv.for000077500000000000000000000133441321604176500257660ustar00rootroot00000000000000 PROGRAM MLPMV C C ========================================================= C Purpose: This program computes the associated Legendre C function Pmv(x) with an integer order and an C arbitrary nonnegative degree using subroutine C LPMV C Input : x --- Argument of Pm(x) ( -1 ó x ó 1 ) C m --- Order of Pmv(x) C v --- Degree of Pmv(x) C Output: PMV --- Pmv(x) C Example: m = 4, x = 0.5 C v Pmv(x) C ----------------------- C 1.5 .46218726 C 1.6 .48103143 C 1.7 .45031429 C 1.8 .36216902 C 1.9 .21206446 C 2.0 .00000000 C 2.5 -1.51996235 C ========================================================= C IMPLICIT DOUBLE PRECISION (P,V,X) WRITE(*,*)'Please enter m,v,x = ?' READ(*,*) M,V,X WRITE(*,20)M,X WRITE(*,*) WRITE(*,*)' v Pmv(x)' WRITE(*,*)' -----------------------' CALL LPMV(V,M,X,PMV) WRITE(*,10)V,PMV 10 FORMAT(3X,F5.1,E16.8) 20 FORMAT(3X,'m =',I2,', ','x =',F6.2) END SUBROUTINE LPMV(V,M,X,PMV) C C ======================================================= C Purpose: Compute the associated Legendre function C Pmv(x) with an integer order and an arbitrary C nonnegative degree v C Input : x --- Argument of Pm(x) ( -1 ó x ó 1 ) C m --- Order of Pmv(x) C v --- Degree of Pmv(x) C Output: PMV --- Pmv(x) C Routine called: PSI for computing Psi function C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 EL=.5772156649015329D0 EPS=1.0D-14 NV=INT(V) V0=V-NV IF (X.EQ.-1.0D0.AND.V.NE.NV) THEN IF (M.EQ.0) PMV=-1.0D+300 IF (M.NE.0) PMV=1.0D+300 RETURN ENDIF C0=1.0D0 IF (M.NE.0) THEN RG=V*(V+M) DO 10 J=1,M-1 10 RG=RG*(V*V-J*J) XQ=DSQRT(1.0D0-X*X) R0=1.0D0 DO 15 J=1,M 15 R0=.5D0*R0*XQ/J C0=R0*RG ENDIF IF (V0.EQ.0.0D0) THEN PMV=1.0D0 R=1.0D0 DO 20 K=1,NV-M R=0.5D0*R*(-NV+M+K-1.0D0)*(NV+M+K)/(K*(K+M)) & *(1.0D0+X) 20 PMV=PMV+R PMV=(-1)**NV*C0*PMV ELSE IF (X.GE.-0.35D0) THEN PMV=1.0D0 R=1.0D0 DO 25 K=1,100 R=0.5D0*R*(-V+M+K-1.0D0)*(V+M+K)/(K*(M+K))*(1.0D0-X) PMV=PMV+R IF (K.GT.12.AND.DABS(R/PMV).LT.EPS) GO TO 30 25 CONTINUE 30 PMV=(-1)**M*C0*PMV ELSE VS=DSIN(V*PI)/PI PV0=0.0D0 IF (M.NE.0) THEN QR=DSQRT((1.0D0-X)/(1.0D0+X)) R2=1.0D0 DO 35 J=1,M 35 R2=R2*QR*J S0=1.0D0 R1=1.0D0 DO 40 K=1,M-1 R1=0.5D0*R1*(-V+K-1)*(V+K)/(K*(K-M))*(1.0D0+X) 40 S0=S0+R1 PV0=-VS*R2/M*S0 ENDIF CALL PSI(V,PSV) PA=2.0D0*(PSV+EL)+PI/DTAN(PI*V)+1.0D0/V S1=0.0D0 DO 45 J=1,M 45 S1=S1+(J*J+V*V)/(J*(J*J-V*V)) PMV=PA+S1-1.0D0/(M-V)+DLOG(0.5D0*(1.0D0+X)) R=1.0D0 DO 60 K=1,100 R=0.5D0*R*(-V+M+K-1.0D0)*(V+M+K)/(K*(K+M))*(1.0D0+X) S=0.0D0 DO 50 J=1,M 50 S=S+((K+J)**2+V*V)/((K+J)*((K+J)**2-V*V)) S2=0.0D0 DO 55 J=1,K 55 S2=S2+1.0D0/(J*(J*J-V*V)) PSS=PA+S+2.0D0*V*V*S2-1.0D0/(M+K-V) & +DLOG(0.5D0*(1.0D0+X)) R2=PSS*R PMV=PMV+R2 IF (DABS(R2/PMV).LT.EPS) GO TO 65 60 CONTINUE 65 PMV=PV0+PMV*VS*C0 ENDIF ENDIF RETURN END SUBROUTINE PSI(X,PS) C C ====================================== C Purpose: Compute psi function C Input : x --- Argument of psi(x) C Output: PS --- psi(x) C ====================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) XA=DABS(X) PI=3.141592653589793D0 EL=.5772156649015329D0 S=0.0D0 IF (X.EQ.INT(X).AND.X.LE.0.0) THEN PS=1.0D+300 RETURN ELSE IF (XA.EQ.INT(XA)) THEN N=XA DO 10 K=1 ,N-1 10 S=S+1.0D0/K PS=-EL+S ELSE IF (XA+0.5.EQ.INT(XA+0.5)) THEN N=XA-.5 DO 20 K=1,N 20 S=S+1.0/(2.0D0*K-1.0D0) PS=-EL+2.0D0*S-1.386294361119891D0 ELSE IF (XA.LT.10.0) THEN N=10-INT(XA) DO 30 K=0,N-1 30 S=S+1.0D0/(XA+K) XA=XA+N ENDIF X2=1.0D0/(XA*XA) A1=-.8333333333333D-01 A2=.83333333333333333D-02 A3=-.39682539682539683D-02 A4=.41666666666666667D-02 A5=-.75757575757575758D-02 A6=.21092796092796093D-01 A7=-.83333333333333333D-01 A8=.4432598039215686D0 PS=DLOG(XA)-.5D0/XA+X2*(((((((A8*X2+A7)*X2+ & A6)*X2+A5)*X2+A4)*X2+A3)*X2+A2)*X2+A1) PS=PS-S ENDIF IF (X.LT.0.0) PS=PS-PI*DCOS(PI*X)/DSIN(PI*X)-1.0D0/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlpn.for000077500000000000000000000043721321604176500256020ustar00rootroot00000000000000 PROGRAM MLPN C C ======================================================== C Purpose: This program computes the Legendre polynomials C Pn(x) and their derivatives Pn'(x) using C subroutine LPN C Input : x --- Argument of Pn(x) C n --- Degree of Pn(x) ( n = 0,1,...) C Output: PN(n) --- Pn(x) C PD(n) --- Pn'(x) C Example: x = 0.5 C n Pn(x) Pn'(x) C --------------------------------------- C 0 1.00000000 .00000000 C 1 .50000000 1.00000000 C 2 -.12500000 1.50000000 C 3 -.43750000 .37500000 C 4 -.28906250 -1.56250000 C 5 .08984375 -2.22656250 C ======================================================== C DOUBLE PRECISION PN,PD,X DIMENSION PN(0:100),PD(0:100) WRITE(*,*)' Please enter Nmax and x ' READ(*,*)N,X WRITE(*,30)X WRITE(*,*) CALL LPN(N,X,PN,PD) WRITE(*,*)' n Pn(x) Pn''(x)' WRITE(*,*)'---------------------------------------' DO 10 K=0,N 10 WRITE(*,20)K,PN(K),PD(K) 20 FORMAT(1X,I3,2E17.8) 30 FORMAT(3X,'x =',F5.1) END SUBROUTINE LPN(N,X,PN,PD) C C =============================================== C Purpose: Compute Legendre polynomials Pn(x) C and their derivatives Pn'(x) C Input : x --- Argument of Pn(x) C n --- Degree of Pn(x) ( n = 0,1,...) C Output: PN(n) --- Pn(x) C PD(n) --- Pn'(x) C =============================================== C IMPLICIT DOUBLE PRECISION (P,X) DIMENSION PN(0:N),PD(0:N) PN(0)=1.0D0 PN(1)=X PD(0)=0.0D0 PD(1)=1.0D0 P0=1.0D0 P1=X DO 10 K=2,N PF=(2.0D0*K-1.0D0)/K*X*P1-(K-1.0D0)/K*P0 PN(K)=PF IF (DABS(X).EQ.1.0D0) THEN PD(K)=0.5D0*X**(K+1)*K*(K+1.0D0) ELSE PD(K)=K*(P1-X*PF)/(1.0D0-X*X) ENDIF P0=P1 10 P1=PF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlpni.for000077500000000000000000000054411321604176500257510ustar00rootroot00000000000000 PROGRAM MLPNI C C ======================================================== C Purpose: This program computes the Legendre polynomials C Pn(x), Pn'(x) and the integral of Pn(t) from 0 C to x using subroutine LPNI C Input : x --- Argument of Pn(x) C n --- Degree of Pn(x) ( n = 0,1,... ) C Output: PN(n) --- Pn(x) C PD(n) --- Pn'(x) C PL(n) --- Integral of Pn(t) from 0 to x C Example: x = 0.50 C n Pn(x) Pn'(x) Pn(t)dt C --------------------------------------------- C 0 1.00000000 .00000000 .50000000 C 1 .50000000 1.00000000 .12500000 C 2 -.12500000 1.50000000 -.18750000 C 3 -.43750000 .37500000 -.14843750 C 4 -.28906250 -1.56250000 .05859375 C 5 .08984375 -2.22656250 .11816406 C ======================================================== C DOUBLE PRECISION PN,PD,PL,X DIMENSION PN(0:100),PD(0:100),PL(0:100) WRITE(*,*)' Please enter Nmax and x' READ(*,*)N,X WRITE(*,30)X WRITE(*,*) WRITE(*,*)' n Pn(x) Pn''(x) Pn(t)dt' WRITE(*,*)' ---------------------------------------------------' CALL LPNI(N,X,PN,PD,PL) DO 10 K=0,N 10 WRITE(*,20)K,PN(K),PD(K),PL(K) 20 FORMAT(1X,I3,3E16.8) 30 FORMAT(3X,'x =',F5.2) END SUBROUTINE LPNI(N,X,PN,PD,PL) C C ===================================================== C Purpose: Compute Legendre polynomials Pn(x), Pn'(x) C and the integral of Pn(t) from 0 to x C Input : x --- Argument of Pn(x) C n --- Degree of Pn(x) ( n = 0,1,... ) C Output: PN(n) --- Pn(x) C PD(n) --- Pn'(x) C PL(n) --- Integral of Pn(t) from 0 to x C ===================================================== C IMPLICIT DOUBLE PRECISION (P,R,X) DIMENSION PN(0:N),PD(0:N),PL(0:N) PN(0)=1.0D0 PN(1)=X PD(0)=0.0D0 PD(1)=1.0D0 PL(0)=X PL(1)=0.5D0*X*X P0=1.0D0 P1=X DO 15 K=2,N PF=(2.0D0*K-1.0D0)/K*X*P1-(K-1.0D0)/K*P0 PN(K)=PF IF (DABS(X).EQ.1.0D0) THEN PD(K)=0.5D0*X**(K+1)*K*(K+1.0D0) ELSE PD(K)=K*(P1-X*PF)/(1.0D0-X*X) ENDIF PL(K)=(X*PN(K)-PN(K-1))/(K+1.0D0) P0=P1 P1=PF IF (K.EQ.2*INT(K/2)) GO TO 15 R=1.0D0/(K+1.0D0) N1=(K-1)/2 DO 10 J=1,N1 10 R=(0.5D0/J-1.0D0)*R PL(K)=PL(K)+R 15 CONTINUE RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlqmn.for000077500000000000000000000134521321604176500257570ustar00rootroot00000000000000 PROGRAM MLQMN C C =============================================================== C Purpose: This program computes the associated Legendre C functions Qmn(x) and their derivatives Qmn'(x) using C subroutine LQMN C Input : x --- Argument of Qmn(x) C m --- Order of Qmn(x) ( m = 0,1,2,úúú ) C n --- Degree of Qmn(x) ( n = 0,1,2,úúú ) C Output: QM(m,n) --- Qmn(x) C QD(m,n) --- Qmn'(x) C Examples: C C Qmn(x): x = 0.5 C n\m 0 1 2 3 4 C --------------------------------------------------------------- C 0 .549306 -1.154701 1.333333 -5.388603 26.666667 C 1 -.725347 -1.053063 2.666667 -6.158403 32.000000 C 2 -.818663 .729806 4.069272 -12.316806 42.666667 C 3 -.198655 2.491853 -.493486 -23.778868 85.333333 C 4 .440175 1.934087 -11.036781 -9.325204 186.818394 C C Qmn'(x): x = 0.5 C n\m 0 1 2 3 4 C --------------------------------------------------------------- C 0 1.333333 -.769800 4.444444 -20.014809 145.777778 C 1 1.215973 -2.377159 3.555556 -24.633611 156.444444 C 2 -.842707 -5.185328 8.796526 -24.633611 199.111111 C 3 -2.877344 -1.091406 28.115454 -50.976710 227.555556 C 4 -2.233291 11.454786 25.483527 -197.068892 412.039838 C C Qmn(x): x = 2.0 C n\m 0 1 2 3 4 C --------------------------------------------------------------- C 0 .549306 -.577350 1.333333 -5.003702 26.666667 C 1 .098612 -.203274 .666667 -3.079201 18.666667 C 2 .021184 -.064946 .277089 -1.539601 10.666667 C 3 .004871 -.019817 .104220 -.679543 5.333333 C 4 .001161 -.005887 .036816 -.276005 2.427640 C C Qmn'(x): x = 2.0 C n\m 0 1 2 3 4 C --------------------------------------------------------------- C 0 -.333333 .384900 -1.111111 5.388603 -36.444444 C 1 -.117361 .249384 -.888889 4.618802 -32.000000 C 2 -.037496 .116680 -.519437 3.079201 -23.111111 C 3 -.011442 .046960 -.253375 1.720114 -14.222222 C 4 -.003399 .017331 -.110263 .849589 -7.748516 C =============================================================== C IMPLICIT DOUBLE PRECISION (Q,X) DIMENSION QM(0:100,0:100),QD(0:100,0:100) WRITE(*,*)' Please enter m, n and x' READ(*,*) M,N,X WRITE(*,*) WRITE(*,*)' m n x Qmn(x) Qmn''(x)' WRITE(*,*)' ---------------------------------------------------' CALL LQMN(100,M,N,X,QM,QD) DO 15 J=0,N WRITE(*,10)M,J,X,QM(M,J),QD(M,J) 15 CONTINUE 10 FORMAT(1X,I3,3X,I3,3X,F5.1,2D17.8) END SUBROUTINE LQMN(MM,M,N,X,QM,QD) C C ========================================================== C Purpose: Compute the associated Legendre functions of the C second kind, Qmn(x) and Qmn'(x) C Input : x --- Argument of Qmn(x) C m --- Order of Qmn(x) ( m = 0,1,2,úúú ) C n --- Degree of Qmn(x) ( n = 0,1,2,úúú ) C mm --- Physical dimension of QM and QD C Output: QM(m,n) --- Qmn(x) C QD(m,n) --- Qmn'(x) C ========================================================== C IMPLICIT DOUBLE PRECISION (Q,X) DIMENSION QM(0:MM,0:N),QD(0:MM,0:N) IF (DABS(X).EQ.1.0D0) THEN DO 10 I=0,M DO 10 J=0,N QM(I,J)=1.0D+300 QD(I,J)=1.0D+300 10 CONTINUE RETURN ENDIF LS=1 IF (DABS(X).GT.1.0D0) LS=-1 XS=LS*(1.0D0-X*X) XQ=DSQRT(XS) Q0=0.5D0*DLOG(DABS((X+1.0D0)/(X-1.0D0))) IF (DABS(X).LT.1.0001D0) THEN QM(0,0)=Q0 QM(0,1)=X*Q0-1.0D0 QM(1,0)=-1.0D0/XQ QM(1,1)=-XQ*(Q0+X/(1.0D0-X*X)) DO 15 I=0,1 DO 15 J=2,N QM(I,J)=((2.0D0*J-1.0D0)*X*QM(I,J-1) & -(J+I-1.0D0)*QM(I,J-2))/(J-I) 15 CONTINUE DO 20 J=0,N DO 20 I=2,M QM(I,J)=-2.0D0*(I-1.0D0)*X/XQ*QM(I-1,J)-LS* & (J+I-1.0D0)*(J-I+2.0D0)*QM(I-2,J) 20 CONTINUE ELSE IF (DABS(X).GT.1.1D0) THEN KM=40+M+N ELSE KM=(40+M+N)*INT(-1.0-1.8*LOG(X-1.0)) ENDIF QF2=0.0D0 QF1=1.0D0 DO 25 K=KM,0,-1 QF0=((2*K+3.0D0)*X*QF1-(K+2.0D0)*QF2)/(K+1.0D0) IF (K.LE.N) QM(0,K)=QF0 QF2=QF1 25 QF1=QF0 DO 30 K=0,N 30 QM(0,K)=Q0*QM(0,K)/QF0 QF2=0.0D0 QF1=1.0D0 DO 35 K=KM,0,-1 QF0=((2*K+3.0D0)*X*QF1-(K+1.0D0)*QF2)/(K+2.0D0) IF (K.LE.N) QM(1,K)=QF0 QF2=QF1 35 QF1=QF0 Q10=-1.0D0/XQ DO 40 K=0,N 40 QM(1,K)=Q10*QM(1,K)/QF0 DO 45 J=0,N Q0=QM(0,J) Q1=QM(1,J) DO 45 I=0,M-2 QF=-2.0D0*(I+1)*X/XQ*Q1+(J-I)*(J+I+1.0D0)*Q0 QM(I+2,J)=QF Q0=Q1 Q1=QF 45 CONTINUE ENDIF QD(0,0)=LS/XS DO 50 J=1,N 50 QD(0,J)=LS*J*(QM(0,J-1)-X*QM(0,J))/XS DO 55 J=0,N DO 55 I=1,M QD(I,J)=LS*I*X/XS*QM(I,J)+(I+J)*(J-I+1.0D0)/XQ*QM(I-1,J) 55 CONTINUE RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlqmns.for000077500000000000000000000124341321604176500261410ustar00rootroot00000000000000 PROGRAM MLQMNS C C ========================================================= C Purpose: This program computes the associated Legendre C functions Qmn(x) and their derivatives Qmn'(x) C for a given order using subroutine LQMNS C Input : x --- Argument of Qmn(x) C m --- Order of Qmn(x), m = 0,1,2,... C n --- Degree of Qmn(x), n = 0,1,2,... C Output: QM(n) --- Qmn(x) C QD(n) --- Qmn'(x) C Examples: C m = 1, N = 5, x = .5 C n Qmn(x) Qmn'(x) C ------------------------------------- C 0 .11547005D+01 .76980036D+00 C 1 .10530633D+01 .23771592D+01 C 2 -.72980606D+00 .51853281D+01 C 3 -.24918526D+01 .10914062D+01 C 4 -.19340866D+01 -.11454786D+02 C 5 .93896830D+00 -.18602587D+02 C C m = 2, N = 5, x = 2.5 C n Qmn(x) Qmn'(x) C ------------------------------------- C 0 .95238095D+00 -.52607710D+00 C 1 .38095238D+00 -.36281179D+00 C 2 .12485160D+00 -.17134314D+00 C 3 .36835513D-01 -.66284127D-01 C 4 .10181730D-01 -.22703958D-01 C 5 .26919481D-02 -.71662396D-02 C ========================================================= C IMPLICIT DOUBLE PRECISION (Q,X,Y) DIMENSION QM(0:200),QD(0:200) WRITE(*,*)'Please enter m, N, and x ' READ(*,*)M,N,X WRITE(*,30)M,N,X CALL LQMNS(M,N,X,QM,QD) WRITE(*,*) WRITE(*,*)' n Qmn(x) Qmn''(x)' WRITE(*,*)' -------------------------------------' DO 10 J=0,N WRITE(*,20)J,QM(J),QD(J) 10 CONTINUE 20 FORMAT(1X,I3,2D17.8) 30 FORMAT(1X,'m =',I2,', ','n =',I2,', ','x =',F5.1) END SUBROUTINE LQMNS(M,N,X,QM,QD) C C ======================================================== C Purpose: Compute associated Legendre functions Qmn(x) C and Qmn'(x) for a given order C Input : x --- Argument of Qmn(x) C m --- Order of Qmn(x), m = 0,1,2,... C n --- Degree of Qmn(x), n = 0,1,2,... C Output: QM(n) --- Qmn(x) C QD(n) --- Qmn'(x) C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION QM(0:N),QD(0:N) DO 10 K=0,N QM(K)=0.0D0 10 QD(K)=0.0D0 IF (DABS(X).EQ.1.0D0) THEN DO 15 K=0,N QM(K)=1.0D+300 15 QD(K)=1.0D+300 RETURN ENDIF LS=1 IF (DABS(X).GT.1.0D0) LS=-1 XQ=DSQRT(LS*(1.0D0-X*X)) Q0=0.5D0*DLOG(DABS((X+1.0)/(X-1.0))) Q00=Q0 Q10=-1.0D0/XQ Q01=X*Q0-1.0D0 Q11=-LS*XQ*(Q0+X/(1.0D0-X*X)) QF0=Q00 QF1=Q10 DO 20 K=2,M QM0=-2.0D0*(K-1.0)/XQ*X*QF1-LS*(K-1.0)*(2.0-K)*QF0 QF0=QF1 20 QF1=QM0 IF (M.EQ.0) QM0=Q00 IF (M.EQ.1) QM0=Q10 QM(0)=QM0 IF (DABS(X).LT.1.0001D0) THEN IF (M.EQ.0.AND.N.GT.0) THEN QF0=Q00 QF1=Q01 DO 25 K=2,N QF2=((2.0*K-1.0D0)*X*QF1-(K-1.0)*QF0)/K QM(K)=QF2 QF0=QF1 25 QF1=QF2 ENDIF QG0=Q01 QG1=Q11 DO 30 K=2,M QM1=-2.0D0*(K-1.0)/XQ*X*QG1-LS*K*(3.0-K)*QG0 QG0=QG1 30 QG1=QM1 IF (M.EQ.0) QM1=Q01 IF (M.EQ.1) QM1=Q11 QM(1)=QM1 IF (M.EQ.1.AND.N.GT.1) THEN QH0=Q10 QH1=Q11 DO 35 K=2,N QH2=((2.0*K-1.0D0)*X*QH1-K*QH0)/(K-1.0) QM(K)=QH2 QH0=QH1 35 QH1=QH2 ELSE IF (M.GE.2) THEN QG0=Q00 QG1=Q01 QH0=Q10 QH1=Q11 DO 45 L=2,N Q0L=((2.0D0*L-1.0D0)*X*QG1-(L-1.0D0)*QG0)/L Q1L=((2.0*L-1.0D0)*X*QH1-L*QH0)/(L-1.0D0) QF0=Q0L QF1=Q1L DO 40 K=2,M QMK=-2.0D0*(K-1.0)/XQ*X*QF1-LS*(K+L-1.0)* & (L+2.0-K)*QF0 QF0=QF1 40 QF1=QMK QM(L)=QMK QG0=QG1 QG1=Q0L QH0=QH1 45 QH1=Q1L ENDIF ELSE IF (DABS(X).GT.1.1) THEN KM=40+M+N ELSE KM=(40+M+N)*INT(-1.0-1.8*LOG(X-1.0)) ENDIF QF2=0.0D0 QF1=1.0D0 DO 50 K=KM,0,-1 QF0=((2.0*K+3.0D0)*X*QF1-(K+2.0-M)*QF2)/(K+M+1.0) IF (K.LE.N) QM(K)=QF0 QF2=QF1 50 QF1=QF0 DO 55 K=0,N 55 QM(K)=QM(K)*QM0/QF0 ENDIF IF (DABS(X).LT.1.0D0) THEN DO 60 K=0,N 60 QM(K)=(-1)**M*QM(K) ENDIF QD(0)=((1.0D0-M)*QM(1)-X*QM(0))/(X*X-1.0) DO 65 K=1,N 65 QD(K)=(K*X*QM(K)-(K+M)*QM(K-1))/(X*X-1.0) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlqna.for000077500000000000000000000045721321604176500257460ustar00rootroot00000000000000 PROGRAM MLQNA C C ====================================================== C Purpose: This program computes the Legendre functions C Qn(x) and Qn'(x) using subroutine LQNA C Input : x --- Argument of Qn(x) ( -1 ó x ó 1 ) C n --- Degree of Qn(x) ( n = 0,1,úúú ) C Output: QN(n) --- Qn(x) C QD(n) --- Qn'(x) C Example: x = 0.50 C n Qn(x) Qn'(x) C --------------------------------- C 0 .54930614 1.33333333 C 1 -.72534693 1.21597281 C 2 -.81866327 -.84270745 C 3 -.19865477 -2.87734353 C 4 .44017453 -2.23329085 C 5 .55508089 1.08422720 C ====================================================== C DOUBLE PRECISION QN,QD,X DIMENSION QN(0:100),QD(0:100) WRITE(*,*)' Please enter Nmax and x' READ(*,*)N,X WRITE(*,30) X WRITE(*,*) CALL LQNA(N,X,QN,QD) WRITE(*,*)' n Qn(x) Qn''(x)' WRITE(*,*)' ---------------------------------' DO 10 K=0,N 10 WRITE(*,20)K,QN(K),QD(K) 20 FORMAT(1X,I3,2F15.8) 30 FORMAT(3X,'x =',F5.2) END SUBROUTINE LQNA(N,X,QN,QD) C C ===================================================== C Purpose: Compute Legendre functions Qn(x) and Qn'(x) C Input : x --- Argument of Qn(x) ( -1 ó x ó 1 ) C n --- Degree of Qn(x) ( n = 0,1,2,úúú ) C Output: QN(n) --- Qn(x) C QD(n) --- Qn'(x) C ( 1.0D+300 stands for infinity ) C ===================================================== C IMPLICIT DOUBLE PRECISION (Q,X) DIMENSION QN(0:N),QD(0:N) IF (DABS(X).EQ.1.0D0) THEN DO 10 K=0,N QN(K)=1.0D+300 QD(K)=-1.0D+300 10 CONTINUE ELSE IF (DABS(X).LT.1.0D0) THEN Q0=0.5D0*DLOG((1.0D0+X)/(1.0D0-X)) Q1=X*Q0-1.0D0 QN(0)=Q0 QN(1)=Q1 QD(0)=1.0D0/(1.0D0-X*X) QD(1)=QN(0)+X*QD(0) DO 15 K=2,N QF=((2*K-1)*X*Q1-(K-1)*Q0)/K QN(K)=QF QD(K)=(QN(K-1)-X*QF)*K/(1.0D0-X*X) Q0=Q1 15 Q1=QF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mlqnb.for000077500000000000000000000071631321604176500257460ustar00rootroot00000000000000 PROGRAM MLQNB C C =============================================================== C Purpose: This program computes the Legendre functions Qn(x) C and Qn'(x) using subroutine LQNB C Input : x --- Argument of Qn(x) C n --- Degree of Qn(x) ( n = 0,1,úúú) C Output: QN(n) --- Qn(x) C QD(n) --- Qn'(x) C Examples: x1 = 0.50, x2 = 2.50 C C n Qn(x1) Qn'(x1) Qn(x2) Qn'(x2) C ---------------------------------------------------------------- C 0 .54930614 1.33333333 .42364893D+00 -.19047619D+00 C 1 -.72534693 1.21597281 .59122325D-01 -.52541546D-01 C 2 -.81866327 -.84270745 .98842555D-02 -.13109214D-01 C 3 -.19865477 -2.87734353 .17695141D-02 -.31202687D-02 C 4 .44017453 -2.23329085 .32843271D-03 -.72261513D-03 C 5 .55508089 1.08422720 .62335892D-04 -.16437427D-03 C =============================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION QN(0:100),QD(0:100) WRITE(*,*)'Please enter Nmax and x ' READ(*,*)N,X WRITE(*,40)X WRITE(*,*) WRITE(*,*)' n Qn(x) Qn''(x)' WRITE(*,*)'--------------------------------------' CALL LQNB(N,X,QN,QD) DO 10 K=0,N IF (X.LE.1.0) THEN WRITE(*,20)K,QN(K),QD(K) ELSE WRITE(*,30)K,QN(K),QD(K) ENDIF 10 CONTINUE 20 FORMAT(1X,I3,2F17.8) 30 FORMAT(1X,I3,2D17.8) 40 FORMAT(3X,'x =',F5.2) END SUBROUTINE LQNB(N,X,QN,QD) C C ==================================================== C Purpose: Compute Legendre functions Qn(x) & Qn'(x) C Input : x --- Argument of Qn(x) C n --- Degree of Qn(x) ( n = 0,1,2,úúú) C Output: QN(n) --- Qn(x) C QD(n) --- Qn'(x) C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION QN(0:N),QD(0:N) EPS=1.0D-14 IF (DABS(X).EQ.1.0D0) THEN DO 10 K=0,N QN(K)=1.0D+300 10 QD(K)=1.0D+300 RETURN ENDIF IF (X.LE.1.021D0) THEN X2=DABS((1.0D0+X)/(1.0D0-X)) Q0=0.5D0*DLOG(X2) Q1=X*Q0-1.0D0 QN(0)=Q0 QN(1)=Q1 QD(0)=1.0D0/(1.0D0-X*X) QD(1)=QN(0)+X*QD(0) DO 15 K=2,N QF=((2.0D0*K-1.0D0)*X*Q1-(K-1.0D0)*Q0)/K QN(K)=QF QD(K)=(QN(K-1)-X*QF)*K/(1.0D0-X*X) Q0=Q1 15 Q1=QF ELSE QC2=1.0D0/X DO 20 J=1,N QC2=QC2*J/((2.0*J+1.0D0)*X) IF (J.EQ.N-1) QC1=QC2 20 CONTINUE DO 35 L=0,1 NL=N+L QF=1.0D0 QR=1.0D0 DO 25 K=1,500 QR=QR*(0.5D0*NL+K-1.0D0)*(0.5D0*(NL-1)+K) & /((NL+K-0.5D0)*K*X*X) QF=QF+QR IF (DABS(QR/QF).LT.EPS) GO TO 30 25 CONTINUE 30 IF (L.EQ.0) THEN QN(N-1)=QF*QC1 ELSE QN(N)=QF*QC2 ENDIF 35 CONTINUE QF2=QN(N) QF1=QN(N-1) DO 40 K=N,2,-1 QF0=((2*K-1.0D0)*X*QF1-K*QF2)/(K-1.0D0) QN(K-2)=QF0 QF2=QF1 40 QF1=QF0 QD(0)=1.0D0/(1.0D0-X*X) DO 45 K=1,N 45 QD(K)=K*(QN(K-1)-X*QN(K))/(1.0D0-X*X) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mmtu0.for000077500000000000000000000573011321604176500256760ustar00rootroot00000000000000 PROGRAM MMTU0 C C ============================================================ C Purpose: This program computes Mathieu functions cem(x,q), C sem(x,q) and their derivatives using subroutine C MTU0 ( q ò 0 ) C Input : KF --- Function code C KF=1 for computing cem(x,q) and cem'(x,q) C KF=2 for computing sem(x,q) and sem'(x,q) C m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C x --- Argument of Mathieu functions (in degrees) C Output: CSF --- cem(x,q) or sem(x,q) C CSD --- cem'x,q) or sem'x,q) C Example: x = 40 C m q cem(x,q) cem'(x,q) sem(x,q) sem'(x,q) C -------------------------------------------------------- C 0 5.0 .3025683 .9470247 C 1 5.0 .7669652 1.2873097 .2988052 .9606824 C 2 5.0 .9102723 -.3463855 .7549264 1.4743128 C 5 5.0 -.9810931 -.6328576 .1694850 -4.8676455 C 0 25.0 .0515371 .3823737 C 1 25.0 .2074402 1.2646301 .0515365 .3823777 C 2 25.0 -.5297051 -2.4292679 .2074275 1.2646996 C 5 25.0 .7507159 -3.9047012 1.1881232 .3258081 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter KF, m, q and x (in degrees)' READ(*,*)KF,M,Q,X WRITE(*,10)KF,M,Q,X WRITE(*,*) IF (KF.EQ.1) WRITE(*,*)' x(degs.) cem(x,q) cem''(x,q)' IF (KF.EQ.2) WRITE(*,*)' x(degs.) sem(x,q) sem''(x,q)' WRITE(*,*)' --------------------------------------' CALL MTU0(KF,M,Q,X,CSF,CSD) WRITE(*,20)X,CSF,CSD 10 FORMAT(1X,4HKF =,I2,', ',3Hm =,I2,', ', & 3Hq =,F5.1,', ',3Hx =,F5.1) 20 FORMAT(2X,F5.1,2F16.9) END SUBROUTINE MTU0(KF,M,Q,X,CSF,CSD) C C =============================================================== C Purpose: Compute Mathieu functions cem(x,q) and sem(x,q) C and their derivatives ( q ò 0 ) C Input : KF --- Function code C KF=1 for computing cem(x,q) and cem'(x,q) C KF=2 for computing sem(x,q) and sem'(x,q) C m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C x --- Argument of Mathieu functions (in degrees) C Output: CSF --- cem(x,q) or sem(x,q) C CSD --- cem'x,q) or sem'x,q) C Routines called: C (1) CVA2 for computing the characteristic values C (2) FCOEF for computing the expansion coefficients C =============================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION FG(251) EPS=1.0D-14 IF (KF.EQ.1.AND.M.EQ.2*INT(M/2)) KD=1 IF (KF.EQ.1.AND.M.NE.2*INT(M/2)) KD=2 IF (KF.EQ.2.AND.M.NE.2*INT(M/2)) KD=3 IF (KF.EQ.2.AND.M.EQ.2*INT(M/2)) KD=4 CALL CVA2(KD,M,Q,A) IF (Q.LE.1.0D0) THEN QM=7.5+56.1*SQRT(Q)-134.7*Q+90.7*SQRT(Q)*Q ELSE QM=17.0+3.1*SQRT(Q)-.126*Q+.0037*SQRT(Q)*Q ENDIF KM=INT(QM+0.5*M) CALL FCOEF(KD,M,Q,A,FG) IC=INT(M/2)+1 RD=1.74532925199433D-2 XR=X*RD CSF=0.0D0 DO 10 K=1,KM IF (KD.EQ.1) THEN CSF=CSF+FG(K)*DCOS((2*K-2)*XR) ELSE IF (KD.EQ.2) THEN CSF=CSF+FG(K)*DCOS((2*K-1)*XR) ELSE IF (KD.EQ.3) THEN CSF=CSF+FG(K)*DSIN((2*K-1)*XR) ELSE IF (KD.EQ.4) THEN CSF=CSF+FG(K)*DSIN(2*K*XR) ENDIF IF (K.GE.IC.AND.DABS(FG(K)).LT.DABS(CSF)*EPS) GO TO 15 10 CONTINUE 15 CSD=0.0D0 DO 20 K=1,KM IF (KD.EQ.1) THEN CSD=CSD-(2*K-2)*FG(K)*DSIN((2*K-2)*XR) ELSE IF (KD.EQ.2) THEN CSD=CSD-(2*K-1)*FG(K)*DSIN((2*K-1)*XR) ELSE IF (KD.EQ.3) THEN CSD=CSD+(2*K-1)*FG(K)*DCOS((2*K-1)*XR) ELSE IF (KD.EQ.4) THEN CSD=CSD+2.0D0*K*FG(K)*DCOS(2*K*XR) ENDIF IF (K.GE.IC.AND.DABS(FG(K)).LT.DABS(CSD)*EPS) GO TO 25 20 CONTINUE 25 RETURN END SUBROUTINE FCOEF(KD,M,Q,A,FC) C C ===================================================== C Purpose: Compute expansion coefficients for Mathieu C functions and modified Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,...) C KD=2 for cem(x,q) ( m = 1,3,5,...) C KD=3 for sem(x,q) ( m = 1,3,5,...) C KD=4 for sem(x,q) ( m = 2,4,6,...) C A --- Characteristic value of Mathieu C functions for given m and q C Output: FC(k) --- Expansion coefficients of Mathieu C functions ( k= 1,2,...,KM ) C FC(1),FC(2),FC(3),... correspond to C A0,A2,A4,... for KD=1 case, A1,A3, C A5,... for KD=2 case, B1,B3,B5,... C for KD=3 case and B2,B4,B6,... for C KD=4 case C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION FC(251) IF (Q.LE.1.0D0) THEN QM=7.5+56.1*SQRT(Q)-134.7*Q+90.7*SQRT(Q)*Q ELSE QM=17.0+3.1*SQRT(Q)-.126*Q+.0037*SQRT(Q)*Q ENDIF KM=INT(QM+0.5*M) IF (Q.EQ.0.0D0) THEN DO 10 K=1,KM 10 FC(K)=0.0D0 IF (KD.EQ.1) THEN FC((M+2)/2)=1.0D0 IF (M.EQ.0) FC(1)=1.0D0/DSQRT(2.0D0) ELSE IF (KD.EQ.4) THEN FC(M/2)=1.0D0 ELSE FC((M+1)/2)=1.0D0 ENDIF RETURN ENDIF KB=0 S=0.0D0 F=1.0D-100 U=0.0D0 FC(KM)=0.0D0 IF (KD.EQ.1) THEN DO 25 K=KM,3,-1 V=U U=F F=(A-4.0D0*K*K)*U/Q-V IF (DABS(F).LT.DABS(FC(K+1))) THEN KB=K FC(1)=1.0D-100 SP=0.0D0 F3=FC(K+1) FC(2)=A/Q*FC(1) FC(3)=(A-4.0D0)*FC(2)/Q-2.0D0*FC(1) U=FC(2) F1=FC(3) DO 15 I=3,KB V=U U=F1 F1=(A-4.0D0*(I-1.0D0)**2)*U/Q-V FC(I+1)=F1 IF (I.EQ.KB) F2=F1 IF (I.NE.KB) SP=SP+F1*F1 15 CONTINUE SP=SP+2.0D0*FC(1)**2+FC(2)**2+FC(3)**2 SS=S+SP*(F3/F2)**2 S0=DSQRT(1.0D0/SS) DO 20 J=1,KM IF (J.LE.KB+1) THEN FC(J)=S0*FC(J)*F3/F2 ELSE FC(J)=S0*FC(J) ENDIF 20 CONTINUE GO TO 85 ELSE FC(K)=F S=S+F*F ENDIF 25 CONTINUE FC(2)=Q*FC(3)/(A-4.0D0-2.0D0*Q*Q/A) FC(1)=Q/A*FC(2) S=S+2.0D0*FC(1)**2+FC(2)**2 S0=DSQRT(1.0D0/S) DO 30 K=1,KM 30 FC(K)=S0*FC(K) ELSE IF (KD.EQ.2.OR.KD.EQ.3) THEN DO 35 K=KM,3,-1 V=U U=F F=(A-(2.0D0*K-1)**2)*U/Q-V IF (DABS(F).GE.DABS(FC(K))) THEN FC(K-1)=F S=S+F*F ELSE KB=K F3=FC(K) GO TO 45 ENDIF 35 CONTINUE FC(1)=Q/(A-1.0D0-(-1)**KD*Q)*FC(2) S=S+FC(1)*FC(1) S0=DSQRT(1.0D0/S) DO 40 K=1,KM 40 FC(K)=S0*FC(K) GO TO 85 45 FC(1)=1.0D-100 FC(2)=(A-1.0D0-(-1)**KD*Q)/Q*FC(1) SP=0.0D0 U=FC(1) F1=FC(2) DO 50 I=2,KB-1 V=U U=F1 F1=(A-(2.0D0*I-1.0D0)**2)*U/Q-V IF (I.NE.KB-1) THEN FC(I+1)=F1 SP=SP+F1*F1 ELSE F2=F1 ENDIF 50 CONTINUE SP=SP+FC(1)**2+FC(2)**2 SS=S+SP*(F3/F2)**2 S0=1.0D0/DSQRT(SS) DO 55 J=1,KM IF (J.LT.KB) FC(J)=S0*FC(J)*F3/F2 IF (J.GE.KB) FC(J)=S0*FC(J) 55 CONTINUE ELSE IF (KD.EQ.4) THEN DO 60 K=KM,3,-1 V=U U=F F=(A-4.0D0*K*K)*U/Q-V IF (DABS(F).GE.DABS(FC(K))) THEN FC(K-1)=F S=S+F*F ELSE KB=K F3=FC(K) GO TO 70 ENDIF 60 CONTINUE FC(1)=Q/(A-4.0D0)*FC(2) S=S+FC(1)*FC(1) S0=DSQRT(1.0D0/S) DO 65 K=1,KM 65 FC(K)=S0*FC(K) GO TO 85 70 FC(1)=1.0D-100 FC(2)=(A-4.0D0)/Q*FC(1) SP=0.0D0 U=FC(1) F1=FC(2) DO 75 I=2,KB-1 V=U U=F1 F1=(A-4.0D0*I*I)*U/Q-V IF (I.NE.KB-1) THEN FC(I+1)=F1 SP=SP+F1*F1 ELSE F2=F1 ENDIF 75 CONTINUE SP=SP+FC(1)**2+FC(2)**2 SS=S+SP*(F3/F2)**2 S0=1.0D0/DSQRT(SS) DO 80 J=1,KM IF (J.LT.KB) FC(J)=S0*FC(J)*F3/F2 IF (J.GE.KB) FC(J)=S0*FC(J) 80 CONTINUE ENDIF 85 IF (FC(1).LT.0.0D0) THEN DO 90 J=1,KM 90 FC(J)=-FC(J) ENDIF RETURN END SUBROUTINE CVA2(KD,M,Q,A) C C ====================================================== C Purpose: Calculate a specific characteristic value of C Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,...) C KD=2 for cem(x,q) ( m = 1,3,5,...) C KD=3 for sem(x,q) ( m = 1,3,5,...) C KD=4 for sem(x,q) ( m = 2,4,6,...) C Output: A --- Characteristic value C Routines called: C (1) REFINE for finding accurate characteristic C values using an iteration method C (2) CV0 for finding initial characteristic C values using polynomial approximation C (3) CVQM for computing initial characteristic C values for q ó 3*m C (3) CVQL for computing initial characteristic C values for q ò m*m C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (M.LE.12.OR.Q.LE.3.0*M.OR.Q.GT.M*M) THEN CALL CV0(KD,M,Q,A) IF (Q.NE.0.0D0) CALL REFINE(KD,M,Q,A,1) ELSE NDIV=10 DELTA=(M-3.0)*M/NDIV IF ((Q-3.0*M).LE.(M*M-Q)) THEN 5 NN=INT((Q-3.0*M)/DELTA)+1 DELTA=(Q-3.0*M)/NN Q1=2.0*M CALL CVQM(M,Q1,A1) Q2=3.0*M CALL CVQM(M,Q2,A2) QQ=3.0*M DO 10 I=1,NN QQ=QQ+DELTA A=(A1*Q2-A2*Q1+(A2-A1)*QQ)/(Q2-Q1) IFLAG=1 IF (I.EQ.NN) IFLAG=-1 CALL REFINE(KD,M,QQ,A,IFLAG) Q1=Q2 Q2=QQ A1=A2 A2=A 10 CONTINUE IF (IFLAG.EQ.-10) THEN NDIV=NDIV*2 DELTA=(M-3.0)*M/NDIV GO TO 5 ENDIF ELSE 15 NN=INT((M*M-Q)/DELTA)+1 DELTA=(M*M-Q)/NN Q1=M*(M-1.0) CALL CVQL(KD,M,Q1,A1) Q2=M*M CALL CVQL(KD,M,Q2,A2) QQ=M*M DO 20 I=1,NN QQ=QQ-DELTA A=(A1*Q2-A2*Q1+(A2-A1)*QQ)/(Q2-Q1) IFLAG=1 IF (I.EQ.NN) IFLAG=-1 CALL REFINE(KD,M,QQ,A,IFLAG) Q1=Q2 Q2=QQ A1=A2 A2=A 20 CONTINUE IF (IFLAG.EQ.-10) THEN NDIV=NDIV*2 DELTA=(M-3.0)*M/NDIV GO TO 15 ENDIF ENDIF ENDIF RETURN END SUBROUTINE REFINE(KD,M,Q,A,IFLAG) C C ===================================================== C Purpose: calculate the accurate characteristic value C by the secant method C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C A --- Initial characteristic value C Output: A --- Refineed characteristic value C Routine called: CVF for computing the value of F for C characteristic equation C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) EPS=1.0D-14 MJ=10+M CA=A DELTA=0.0D0 X0=A CALL CVF(KD,M,Q,X0,MJ,F0) X1=1.002*A CALL CVF(KD,M,Q,X1,MJ,F1) 5 DO 10 IT=1,100 MJ=MJ+1 X=X1-(X1-X0)/(1.0D0-F0/F1) CALL CVF(KD,M,Q,X,MJ,F) IF (ABS(1.0-X1/X).LT.EPS.OR.F.EQ.0.0) GO TO 15 X0=X1 F0=F1 X1=X 10 F1=F 15 A=X IF (DELTA.GT.0.05) THEN A=CA IF (IFLAG.LT.0) THEN IFLAG=-10 ENDIF RETURN ENDIF IF (ABS((A-CA)/CA).GT.0.05) THEN X0=CA DELTA=DELTA+0.005D0 CALL CVF(KD,M,Q,X0,MJ,F0) X1=(1.0D0+DELTA)*CA CALL CVF(KD,M,Q,X1,MJ,F1) GO TO 5 ENDIF RETURN END SUBROUTINE CVF(KD,M,Q,A,MJ,F) C C ====================================================== C Purpose: Compute the value of F for characteristic C equation of Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C A --- Characteristic value C Output: F --- Value of F for characteristic equation C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) B=A IC=INT(M/2) L=0 L0=0 J0=2 JF=IC IF (KD.EQ.1) L0=2 IF (KD.EQ.1) J0=3 IF (KD.EQ.2.OR.KD.EQ.3) L=1 IF (KD.EQ.4) JF=IC-1 T1=0.0D0 DO 10 J=MJ,IC+1,-1 10 T1=-Q*Q/((2.0D0*J+L)**2-B+T1) IF (M.LE.2) THEN T2=0.0D0 IF (KD.EQ.1.AND.M.EQ.0) T1=T1+T1 IF (KD.EQ.1.AND.M.EQ.2) T1=-2.0*Q*Q/(4.0-B+T1)-4.0 IF (KD.EQ.2.AND.M.EQ.1) T1=T1+Q IF (KD.EQ.3.AND.M.EQ.1) T1=T1-Q ELSE IF (KD.EQ.1) T0=4.0D0-B+2.0D0*Q*Q/B IF (KD.EQ.2) T0=1.0D0-B+Q IF (KD.EQ.3) T0=1.0D0-B-Q IF (KD.EQ.4) T0=4.0D0-B T2=-Q*Q/T0 DO 15 J=J0,JF 15 T2=-Q*Q/((2.0D0*J-L-L0)**2-B+T2) ENDIF F=(2.0D0*IC+L)**2+T1+T2-B RETURN END SUBROUTINE CV0(KD,M,Q,A0) C C ===================================================== C Purpose: Compute the initial characteristic value of C Mathieu functions for m ó 12 or q ó 300 or C q ò m*m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Characteristic value C Routines called: C (1) CVQM for computing initial characteristic C value for q ó 3*m C (2) CVQL for computing initial characteristic C value for q ò m*m C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) Q2=Q*Q IF (M.EQ.0) THEN IF (Q.LE.1.0) THEN A0=(((.0036392*Q2-.0125868)*Q2+.0546875)*Q2-.5)*Q2 ELSE IF (Q.LE.10.0) THEN A0=((3.999267D-3*Q-9.638957D-2)*Q-.88297)*Q & +.5542818 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.1) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=(((-6.51E-4*Q-.015625)*Q-.125)*Q+1.0)*Q+1.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=(((-6.51E-4*Q+.015625)*Q-.125)*Q-1.0)*Q+1.0 ELSE IF (Q.LE.10.0.AND. KD.EQ.2) THEN A0=(((-4.94603D-4*Q+1.92917D-2)*Q-.3089229) & *Q+1.33372)*Q+.811752 ELSE IF (Q.LE.10.0.AND.KD.EQ.3) THEN A0=((1.971096D-3*Q-5.482465D-2)*Q-1.152218) & *Q+1.10427 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.2) THEN IF (Q.LE.1.0.AND.KD.EQ.1) THEN A0=(((-.0036391*Q2+.0125888)*Q2-.0551939)*Q2 & +.416667)*Q2+4.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.4) THEN A0=(.0003617*Q2-.0833333)*Q2+4.0 ELSE IF (Q.LE.15.AND.KD.EQ.1) THEN A0=(((3.200972D-4*Q-8.667445D-3)*Q & -1.829032D-4)*Q+.9919999)*Q+3.3290504 ELSE IF (Q.LE.10.0.AND.KD.EQ.4) THEN A0=((2.38446D-3*Q-.08725329)*Q-4.732542D-3) & *Q+4.00909 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.3) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=((6.348E-4*Q+.015625)*Q+.0625)*Q2+9.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=((6.348E-4*Q-.015625)*Q+.0625)*Q2+9.0 ELSE IF (Q.LE.20.0.AND.KD.EQ.2) THEN A0=(((3.035731D-4*Q-1.453021D-2)*Q & +.19069602)*Q-.1039356)*Q+8.9449274 ELSE IF (Q.LE.15.0.AND.KD.EQ.3) THEN A0=((9.369364D-5*Q-.03569325)*Q+.2689874)*Q & +8.771735 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.4) THEN IF (Q.LE.1.0.AND.KD.EQ.1) THEN A0=((-2.1E-6*Q2+5.012E-4)*Q2+.0333333)*Q2+16.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.4) THEN A0=((3.7E-6*Q2-3.669E-4)*Q2+.0333333)*Q2+16.0 ELSE IF (Q.LE.25.0.AND.KD.EQ.1) THEN A0=(((1.076676D-4*Q-7.9684875D-3)*Q & +.17344854)*Q-.5924058)*Q+16.620847 ELSE IF (Q.LE.20.0.AND.KD.EQ.4) THEN A0=((-7.08719D-4*Q+3.8216144D-3)*Q & +.1907493)*Q+15.744 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.5) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=((6.8E-6*Q+1.42E-5)*Q2+.0208333)*Q2+25.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=((-6.8E-6*Q+1.42E-5)*Q2+.0208333)*Q2+25.0 ELSE IF (Q.LE.35.0.AND.KD.EQ.2) THEN A0=(((2.238231D-5*Q-2.983416D-3)*Q & +.10706975)*Q-.600205)*Q+25.93515 ELSE IF (Q.LE.25.0.AND.KD.EQ.3) THEN A0=((-7.425364D-4*Q+2.18225D-2)*Q & +4.16399D-2)*Q+24.897 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.6) THEN IF (Q.LE.1.0) THEN A0=(.4D-6*Q2+.0142857)*Q2+36.0 ELSE IF (Q.LE.40.0.AND.KD.EQ.1) THEN A0=(((-1.66846D-5*Q+4.80263D-4)*Q & +2.53998D-2)*Q-.181233)*Q+36.423 ELSE IF (Q.LE.35.0.AND.KD.EQ.4) THEN A0=((-4.57146D-4*Q+2.16609D-2)*Q-2.349616D-2)*Q & +35.99251 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.7) THEN IF (Q.LE.10.0) THEN CALL CVQM(M,Q,A0) ELSE IF (Q.LE.50.0.AND.KD.EQ.2) THEN A0=(((-1.411114D-5*Q+9.730514D-4)*Q & -3.097887D-3)*Q+3.533597D-2)*Q+49.0547 ELSE IF (Q.LE.40.0.AND.KD.EQ.3) THEN A0=((-3.043872D-4*Q+2.05511D-2)*Q & -9.16292D-2)*Q+49.19035 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.GE.8) THEN IF (Q.LE.3.*M) THEN CALL CVQM(M,Q,A0) ELSE IF (Q.GT.M*M) THEN CALL CVQL(KD,M,Q,A0) ELSE IF (M.EQ.8.AND.KD.EQ.1) THEN A0=(((8.634308D-6*Q-2.100289D-3)*Q+.169072)*Q & -4.64336)*Q+109.4211 ELSE IF (M.EQ.8.AND.KD.EQ.4) THEN A0=((-6.7842D-5*Q+2.2057D-3)*Q+.48296)*Q+56.59 ELSE IF (M.EQ.9.AND.KD.EQ.2) THEN A0=(((2.906435D-6*Q-1.019893D-3)*Q+.1101965)*Q & -3.821851)*Q+127.6098 ELSE IF (M.EQ.9.AND.KD.EQ.3) THEN A0=((-9.577289D-5*Q+.01043839)*Q+.06588934)*Q & +78.0198 ELSE IF (M.EQ.10.AND.KD.EQ.1) THEN A0=(((5.44927D-7*Q-3.926119D-4)*Q+.0612099)*Q & -2.600805)*Q+138.1923 ELSE IF (M.EQ.10.AND.KD.EQ.4) THEN A0=((-7.660143D-5*Q+.01132506)*Q-.09746023)*Q & +99.29494 ELSE IF (M.EQ.11.AND.KD.EQ.2) THEN A0=(((-5.67615D-7*Q+7.152722D-6)*Q+.01920291)*Q & -1.081583)*Q+140.88 ELSE IF (M.EQ.11.AND.KD.EQ.3) THEN A0=((-6.310551D-5*Q+.0119247)*Q-.2681195)*Q & +123.667 ELSE IF (M.EQ.12.AND.KD.EQ.1) THEN A0=(((-2.38351D-7*Q-2.90139D-5)*Q+.02023088)*Q & -1.289)*Q+171.2723 ELSE IF (M.EQ.12.AND.KD.EQ.4) THEN A0=(((3.08902D-7*Q-1.577869D-4)*Q+.0247911)*Q & -1.05454)*Q+161.471 ENDIF ENDIF ENDIF RETURN END SUBROUTINE CVQL(KD,M,Q,A0) C C ======================================================== C Purpose: Compute the characteristic value of Mathieu C functions for q ò 3m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Initial characteristic value C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (KD.EQ.1.OR.KD.EQ.2) W=2.0D0*M+1.0D0 IF (KD.EQ.3.OR.KD.EQ.4) W=2.0D0*M-1.0D0 W2=W*W W3=W*W2 W4=W2*W2 W6=W2*W4 D1=5.0+34.0/W2+9.0/W4 D2=(33.0+410.0/W2+405.0/W4)/W D3=(63.0+1260.0/W2+2943.0/W4+486.0/W6)/W2 D4=(527.0+15617.0/W2+69001.0/W4+41607.0/W6)/W3 C1=128.0 P2=Q/W4 P1=DSQRT(P2) CV1=-2.0*Q+2.0*W*DSQRT(Q)-(W2+1.0)/8.0 CV2=(W+3.0/W)+D1/(32.0*P1)+D2/(8.0*C1*P2) CV2=CV2+D3/(64.0*C1*P1*P2)+D4/(16.0*C1*C1*P2*P2) A0=CV1-CV2/(C1*P1) RETURN END SUBROUTINE CVQM(M,Q,A0) C C ===================================================== C Purpose: Compute the characteristic value of Mathieu C functions for q ó m*m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Initial characteristic value C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) HM1=.5*Q/(M*M-1.0) HM3=.25*HM1**3/(M*M-4.0) HM5=HM1*HM3*Q/((M*M-1.0)*(M*M-9.0)) A0=M*M+Q*(HM1+(5.0*M*M+7.0)*HM3 & +(9.0*M**4+58.0*M*M+29.0)*HM5) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mmtu12.for000077500000000000000000000665711321604176500257720ustar00rootroot00000000000000 PROGRAM MMTU12 C C =============================================================== C Purpose: This program computes the modified Mathieu functions C of the first and second kinds, Mcm(1)(2)(x,q) and C Msm(1)(2)(x,q), and their derivatives using C subroutine MTU12 C Input: KF --- Function code C KF=1 for computing Mcm(x,q) C KF=2 for computing Msm(x,q) C KC --- Function Code C KC=1 for computing Mcm(1)(x,q) and Mcm(1)'(x,q) C or Msm(1)(x,q) and Msm(1)'(x,q) C KC=2 for computing Mcm(2)(x,q) and Mcm(2)'(x,q) C or Msm(2)(x,q) and Msm(2)'(x,q) C KC=3 for both modified Mathieu functions of the C first and second kinds, and their C derivatives C m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C x --- Argument of Mathieu functions C Output: F1R --- Mcm(1)(x,q) or Msm(1)(x,q) C D1R --- Derivative of Mcm(1)(x,q) or Msm(1)(x,q) C F2R --- Mcm(2)(x,q) or Msm(2)(x,q) C D2R --- Derivative of Mcm(2)(x,q) or Msm(2)(x,q) C =============================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter KF, m, q and x ' READ(*,*)KF,M,Q,X WRITE(*,10)KF,M,Q,X KC=3 CALL MTU12(KF,KC,M,Q,X,F1R,D1R,F2R,D2R) WRITE(*,*) IF (KF.EQ.1) THEN WRITE(*,*)' x Mcm(1)(x,q) Mcm(1)''(x,q)', & ' Mcm(2)(x,q) Mcm(2)''(x,q)' ELSE WRITE(*,*)' x Msm(1)(x,q) Msm(1)''(x,q)', & ' Msm(2)(x,q) Msm(2)''(x,q)' ENDIF WRITE(*,*)' --------------------------------------', & '-------------------------------' WRITE(*,20)X,F1R,D1R,F2R,D2R WRITE(*,*) WRITE(*,30)F1R*D2R-F2R*D1R,.63661977236758D0 WRITE(*,40) 10 FORMAT(1X,4HKF =,I2,', ',3Hm =,I3,', ', & 3Hq =,F5.1,', ',3Hx =,F5.1) 20 FORMAT(1X,F5.1,4D16.8) 30 FORMAT(1X,'WRONSKIAN=',E16.8,3X,'should equal 2/PI=',E16.8) 40 FORMAT(1X,/1X,'Caution: This check is not accurate if it ', & 'involves',/1X,' the subtraction of two ', & 'similar numbers') END SUBROUTINE MTU12(KF,KC,M,Q,X,F1R,D1R,F2R,D2R) C C ============================================================== C Purpose: Compute modified Mathieu functions of the first and C second kinds, Mcm(1)(2)(x,q) and Msm(1)(2)(x,q), C and their derivatives C Input: KF --- Function code C KF=1 for computing Mcm(x,q) C KF=2 for computing Msm(x,q) C KC --- Function Code C KC=1 for computing the first kind C KC=2 for computing the second kind C or Msm(2)(x,q) and Msm(2)'(x,q) C KC=3 for computing both the first C and second kinds C m --- Order of Mathieu functions C q --- Parameter of Mathieu functions ( q ò 0 ) C x --- Argument of Mathieu functions C Output: F1R --- Mcm(1)(x,q) or Msm(1)(x,q) C D1R --- Derivative of Mcm(1)(x,q) or Msm(1)(x,q) C F2R --- Mcm(2)(x,q) or Msm(2)(x,q) C D2R --- Derivative of Mcm(2)(x,q) or Msm(2)(x,q) C Routines called: C (1) CVA2 for computing the characteristic values C (2) FCOEF for computing expansion coefficients C (3) JYNB for computing Jn(x), Yn(x) and their C derivatives C ============================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION FG(251),BJ1(0:251),DJ1(0:251),BJ2(0:251),DJ2(0:251), & BY1(0:251),DY1(0:251),BY2(0:251),DY2(0:251) EPS=1.0D-14 IF (KF.EQ.1.AND.M.EQ.2*INT(M/2)) KD=1 IF (KF.EQ.1.AND.M.NE.2*INT(M/2)) KD=2 IF (KF.EQ.2.AND.M.NE.2*INT(M/2)) KD=3 IF (KF.EQ.2.AND.M.EQ.2*INT(M/2)) KD=4 CALL CVA2(KD,M,Q,A) IF (Q.LE.1.0D0) THEN QM=7.5+56.1*SQRT(Q)-134.7*Q+90.7*SQRT(Q)*Q ELSE QM=17.0+3.1*SQRT(Q)-.126*Q+.0037*SQRT(Q)*Q ENDIF KM=INT(QM+0.5*M) CALL FCOEF(KD,M,Q,A,FG) IC=INT(M/2)+1 IF (KD.EQ.4) IC=M/2 C1=DEXP(-X) C2=DEXP(X) U1=DSQRT(Q)*C1 U2=DSQRT(Q)*C2 CALL JYNB(KM,U1,NM,BJ1,DJ1,BY1,DY1) CALL JYNB(KM,U2,NM,BJ2,DJ2,BY2,DY2) IF (KC.EQ.2) GO TO 50 F1R=0.0D0 DO 30 K=1,KM IF (KD.EQ.1) THEN F1R=F1R+(-1)**(IC+K)*FG(K)*BJ1(K-1)*BJ2(K-1) ELSE IF (KD.EQ.2.OR.KD.EQ.3) THEN F1R=F1R+(-1)**(IC+K)*FG(K)*(BJ1(K-1)*BJ2(K) & +(-1)**KD*BJ1(K)*BJ2(K-1)) ELSE F1R=F1R+(-1)**(IC+K)*FG(K)*(BJ1(K-1)*BJ2(K+1) & -BJ1(K+1)*BJ2(K-1)) ENDIF IF (K.GE.5.AND.DABS(F1R-W1).LT.DABS(F1R)*EPS) GO TO 35 30 W1=F1R 35 F1R=F1R/FG(1) D1R=0.0D0 DO 40 K=1,KM IF (KD.EQ.1) THEN D1R=D1R+(-1)**(IC+K)*FG(K)*(C2*BJ1(K-1)*DJ2(K-1) & -C1*DJ1(K-1)*BJ2(K-1)) ELSE IF (KD.EQ.2.OR.KD.EQ.3) THEN D1R=D1R+(-1)**(IC+K)*FG(K)*(C2*(BJ1(K-1)*DJ2(K) & +(-1)**KD*BJ1(K)*DJ2(K-1))-C1*(DJ1(K-1)*BJ2(K) & +(-1)**KD*DJ1(K)*BJ2(K-1))) ELSE D1R=D1R+(-1)**(IC+K)*FG(K)*(C2*(BJ1(K-1)*DJ2(K+1) & -BJ1(K+1)*DJ2(K-1))-C1*(DJ1(K-1)*BJ2(K+1) & -DJ1(K+1)*BJ2(K-1))) ENDIF IF (K.GE.5.AND.DABS(D1R-W2).LT.DABS(D1R)*EPS) GO TO 45 40 W2=D1R 45 D1R=D1R*DSQRT(Q)/FG(1) IF (KC.EQ.1) RETURN 50 F2R=0.0D0 DO 55 K=1,KM IF (KD.EQ.1) THEN F2R=F2R+(-1)**(IC+K)*FG(K)*BJ1(K-1)*BY2(K-1) ELSE IF (KD.EQ.2.OR.KD.EQ.3) THEN F2R=F2R+(-1)**(IC+K)*FG(K)*(BJ1(K-1)*BY2(K) & +(-1)**KD*BJ1(K)*BY2(K-1)) ELSE F2R=F2R+(-1)**(IC+K)*FG(K)*(BJ1(K-1)*BY2(K+1) & -BJ1(K+1)*BY2(K-1)) ENDIF IF (K.GE.5.AND.DABS(F2R-W1).LT.DABS(F2R)*EPS) GO TO 60 55 W1=F2R 60 F2R=F2R/FG(1) D2R=0.0D0 DO 65 K=1,KM IF (KD.EQ.1) THEN D2R=D2R+(-1)**(IC+K)*FG(K)*(C2*BJ1(K-1)*DY2(K-1) & -C1*DJ1(K-1)*BY2(K-1)) ELSE IF (KD.EQ.2.OR.KD.EQ.3) THEN D2R=D2R+(-1)**(IC+K)*FG(K)*(C2*(BJ1(K-1)*DY2(K) & +(-1)**KD*BJ1(K)*DY2(K-1))-C1*(DJ1(K-1)*BY2(K) & +(-1)**KD*DJ1(K)*BY2(K-1))) ELSE D2R=D2R+(-1)**(IC+K)*FG(K)*(C2*(BJ1(K-1)*DY2(K+1) & -BJ1(K+1)*DY2(K-1))-C1*(DJ1(K-1)*BY2(K+1) & -DJ1(K+1)*BY2(K-1))) ENDIF IF (K.GE.5.AND.DABS(D2R-W2).LT.DABS(D2R)*EPS) GO TO 70 65 W2=D2R 70 D2R=D2R*DSQRT(Q)/FG(1) RETURN END SUBROUTINE FCOEF(KD,M,Q,A,FC) C C ===================================================== C Purpose: Compute expansion coefficients for Mathieu C functions and modified Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,...) C KD=2 for cem(x,q) ( m = 1,3,5,...) C KD=3 for sem(x,q) ( m = 1,3,5,...) C KD=4 for sem(x,q) ( m = 2,4,6,...) C A --- Characteristic value of Mathieu C functions for given m and q C Output: FC(k) --- Expansion coefficients of Mathieu C functions ( k= 1,2,...,KM ) C FC(1),FC(2),FC(3),... correspond to C A0,A2,A4,... for KD=1 case, A1,A3, C A5,... for KD=2 case, B1,B3,B5,... C for KD=3 case and B2,B4,B6,... for C KD=4 case C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION FC(251) IF (Q.LE.1.0D0) THEN QM=7.5+56.1*SQRT(Q)-134.7*Q+90.7*SQRT(Q)*Q ELSE QM=17.0+3.1*SQRT(Q)-.126*Q+.0037*SQRT(Q)*Q ENDIF KM=INT(QM+0.5*M) IF (Q.EQ.0.0D0) THEN DO 10 K=1,KM 10 FC(K)=0.0D0 IF (KD.EQ.1) THEN FC((M+2)/2)=1.0D0 IF (M.EQ.0) FC(1)=1.0D0/DSQRT(2.0D0) ELSE IF (KD.EQ.4) THEN FC(M/2)=1.0D0 ELSE FC((M+1)/2)=1.0D0 ENDIF RETURN ENDIF KB=0 S=0.0D0 F=1.0D-100 U=0.0D0 FC(KM)=0.0D0 IF (KD.EQ.1) THEN DO 25 K=KM,3,-1 V=U U=F F=(A-4.0D0*K*K)*U/Q-V IF (DABS(F).LT.DABS(FC(K+1))) THEN KB=K FC(1)=1.0D-100 SP=0.0D0 F3=FC(K+1) FC(2)=A/Q*FC(1) FC(3)=(A-4.0D0)*FC(2)/Q-2.0D0*FC(1) U=FC(2) F1=FC(3) DO 15 I=3,KB V=U U=F1 F1=(A-4.0D0*(I-1.0D0)**2)*U/Q-V FC(I+1)=F1 IF (I.EQ.KB) F2=F1 IF (I.NE.KB) SP=SP+F1*F1 15 CONTINUE SP=SP+2.0D0*FC(1)**2+FC(2)**2+FC(3)**2 SS=S+SP*(F3/F2)**2 S0=DSQRT(1.0D0/SS) DO 20 J=1,KM IF (J.LE.KB+1) THEN FC(J)=S0*FC(J)*F3/F2 ELSE FC(J)=S0*FC(J) ENDIF 20 CONTINUE GO TO 85 ELSE FC(K)=F S=S+F*F ENDIF 25 CONTINUE FC(2)=Q*FC(3)/(A-4.0D0-2.0D0*Q*Q/A) FC(1)=Q/A*FC(2) S=S+2.0D0*FC(1)**2+FC(2)**2 S0=DSQRT(1.0D0/S) DO 30 K=1,KM 30 FC(K)=S0*FC(K) ELSE IF (KD.EQ.2.OR.KD.EQ.3) THEN DO 35 K=KM,3,-1 V=U U=F F=(A-(2.0D0*K-1)**2)*U/Q-V IF (DABS(F).GE.DABS(FC(K))) THEN FC(K-1)=F S=S+F*F ELSE KB=K F3=FC(K) GO TO 45 ENDIF 35 CONTINUE FC(1)=Q/(A-1.0D0-(-1)**KD*Q)*FC(2) S=S+FC(1)*FC(1) S0=DSQRT(1.0D0/S) DO 40 K=1,KM 40 FC(K)=S0*FC(K) GO TO 85 45 FC(1)=1.0D-100 FC(2)=(A-1.0D0-(-1)**KD*Q)/Q*FC(1) SP=0.0D0 U=FC(1) F1=FC(2) DO 50 I=2,KB-1 V=U U=F1 F1=(A-(2.0D0*I-1.0D0)**2)*U/Q-V IF (I.NE.KB-1) THEN FC(I+1)=F1 SP=SP+F1*F1 ELSE F2=F1 ENDIF 50 CONTINUE SP=SP+FC(1)**2+FC(2)**2 SS=S+SP*(F3/F2)**2 S0=1.0D0/DSQRT(SS) DO 55 J=1,KM IF (J.LT.KB) FC(J)=S0*FC(J)*F3/F2 IF (J.GE.KB) FC(J)=S0*FC(J) 55 CONTINUE ELSE IF (KD.EQ.4) THEN DO 60 K=KM,3,-1 V=U U=F F=(A-4.0D0*K*K)*U/Q-V IF (DABS(F).GE.DABS(FC(K))) THEN FC(K-1)=F S=S+F*F ELSE KB=K F3=FC(K) GO TO 70 ENDIF 60 CONTINUE FC(1)=Q/(A-4.0D0)*FC(2) S=S+FC(1)*FC(1) S0=DSQRT(1.0D0/S) DO 65 K=1,KM 65 FC(K)=S0*FC(K) GO TO 85 70 FC(1)=1.0D-100 FC(2)=(A-4.0D0)/Q*FC(1) SP=0.0D0 U=FC(1) F1=FC(2) DO 75 I=2,KB-1 V=U U=F1 F1=(A-4.0D0*I*I)*U/Q-V IF (I.NE.KB-1) THEN FC(I+1)=F1 SP=SP+F1*F1 ELSE F2=F1 ENDIF 75 CONTINUE SP=SP+FC(1)**2+FC(2)**2 SS=S+SP*(F3/F2)**2 S0=1.0D0/DSQRT(SS) DO 80 J=1,KM IF (J.LT.KB) FC(J)=S0*FC(J)*F3/F2 IF (J.GE.KB) FC(J)=S0*FC(J) 80 CONTINUE ENDIF 85 IF (FC(1).LT.0.0D0) THEN DO 90 J=1,KM 90 FC(J)=-FC(J) ENDIF RETURN END SUBROUTINE CVA2(KD,M,Q,A) C C ====================================================== C Purpose: Calculate a specific characteristic value of C Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C KD --- Case code C KD=1 for cem(x,q) ( m = 0,2,4,...) C KD=2 for cem(x,q) ( m = 1,3,5,...) C KD=3 for sem(x,q) ( m = 1,3,5,...) C KD=4 for sem(x,q) ( m = 2,4,6,...) C Output: A --- Characteristic value C Routines called: C (1) REFINE for finding accurate characteristic C values using an iteration method C (2) CV0 for finding initial characteristic C values using polynomial approximation C (3) CVQM for computing initial characteristic C values for q ó 3*m C (3) CVQL for computing initial characteristic C values for q ò m*m C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (M.LE.12.OR.Q.LE.3.0*M.OR.Q.GT.M*M) THEN CALL CV0(KD,M,Q,A) IF (Q.NE.0.0D0) CALL REFINE(KD,M,Q,A,1) ELSE NDIV=10 DELTA=(M-3.0)*M/NDIV IF ((Q-3.0*M).LE.(M*M-Q)) THEN 5 NN=INT((Q-3.0*M)/DELTA)+1 DELTA=(Q-3.0*M)/NN Q1=2.0*M CALL CVQM(M,Q1,A1) Q2=3.0*M CALL CVQM(M,Q2,A2) QQ=3.0*M DO 10 I=1,NN QQ=QQ+DELTA A=(A1*Q2-A2*Q1+(A2-A1)*QQ)/(Q2-Q1) IFLAG=1 IF (I.EQ.NN) IFLAG=-1 CALL REFINE(KD,M,QQ,A,IFLAG) Q1=Q2 Q2=QQ A1=A2 A2=A 10 CONTINUE IF (IFLAG.EQ.-10) THEN NDIV=NDIV*2 DELTA=(M-3.0)*M/NDIV GO TO 5 ENDIF ELSE 15 NN=INT((M*M-Q)/DELTA)+1 DELTA=(M*M-Q)/NN Q1=M*(M-1.0) CALL CVQL(KD,M,Q1,A1) Q2=M*M CALL CVQL(KD,M,Q2,A2) QQ=M*M DO 20 I=1,NN QQ=QQ-DELTA A=(A1*Q2-A2*Q1+(A2-A1)*QQ)/(Q2-Q1) IFLAG=1 IF (I.EQ.NN) IFLAG=-1 CALL REFINE(KD,M,QQ,A,IFLAG) Q1=Q2 Q2=QQ A1=A2 A2=A 20 CONTINUE IF (IFLAG.EQ.-10) THEN NDIV=NDIV*2 DELTA=(M-3.0)*M/NDIV GO TO 15 ENDIF ENDIF ENDIF RETURN END SUBROUTINE REFINE(KD,M,Q,A,IFLAG) C C ===================================================== C Purpose: calculate the accurate characteristic value C by the secant method C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C A --- Initial characteristic value C Output: A --- Refineed characteristic value C Routine called: CVF for computing the value of F for C characteristic equation C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) EPS=1.0D-14 MJ=10+M CA=A DELTA=0.0D0 X0=A CALL CVF(KD,M,Q,X0,MJ,F0) X1=1.002*A CALL CVF(KD,M,Q,X1,MJ,F1) 5 DO 10 IT=1,100 MJ=MJ+1 X=X1-(X1-X0)/(1.0D0-F0/F1) CALL CVF(KD,M,Q,X,MJ,F) IF (ABS(1.0-X1/X).LT.EPS.OR.F.EQ.0.0) GO TO 15 X0=X1 F0=F1 X1=X 10 F1=F 15 A=X IF (DELTA.GT.0.05) THEN A=CA IF (IFLAG.LT.0) THEN IFLAG=-10 ENDIF RETURN ENDIF IF (ABS((A-CA)/CA).GT.0.05) THEN X0=CA DELTA=DELTA+0.005D0 CALL CVF(KD,M,Q,X0,MJ,F0) X1=(1.0D0+DELTA)*CA CALL CVF(KD,M,Q,X1,MJ,F1) GO TO 5 ENDIF RETURN END SUBROUTINE CVF(KD,M,Q,A,MJ,F) C C ====================================================== C Purpose: Compute the value of F for characteristic C equation of Mathieu functions C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C A --- Characteristic value C Output: F --- Value of F for characteristic equation C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) B=A IC=INT(M/2) L=0 L0=0 J0=2 JF=IC IF (KD.EQ.1) L0=2 IF (KD.EQ.1) J0=3 IF (KD.EQ.2.OR.KD.EQ.3) L=1 IF (KD.EQ.4) JF=IC-1 T1=0.0D0 DO 10 J=MJ,IC+1,-1 10 T1=-Q*Q/((2.0D0*J+L)**2-B+T1) IF (M.LE.2) THEN T2=0.0D0 IF (KD.EQ.1.AND.M.EQ.0) T1=T1+T1 IF (KD.EQ.1.AND.M.EQ.2) T1=-2.0*Q*Q/(4.0-B+T1)-4.0 IF (KD.EQ.2.AND.M.EQ.1) T1=T1+Q IF (KD.EQ.3.AND.M.EQ.1) T1=T1-Q ELSE IF (KD.EQ.1) T0=4.0D0-B+2.0D0*Q*Q/B IF (KD.EQ.2) T0=1.0D0-B+Q IF (KD.EQ.3) T0=1.0D0-B-Q IF (KD.EQ.4) T0=4.0D0-B T2=-Q*Q/T0 DO 15 J=J0,JF 15 T2=-Q*Q/((2.0D0*J-L-L0)**2-B+T2) ENDIF F=(2.0D0*IC+L)**2+T1+T2-B RETURN END SUBROUTINE CV0(KD,M,Q,A0) C C ===================================================== C Purpose: Compute the initial characteristic value of C Mathieu functions for m ó 12 or q ó 300 or C q ò m*m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Characteristic value C Routines called: C (1) CVQM for computing initial characteristic C value for q ó 3*m C (2) CVQL for computing initial characteristic C value for q ò m*m C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) Q2=Q*Q IF (M.EQ.0) THEN IF (Q.LE.1.0) THEN A0=(((.0036392*Q2-.0125868)*Q2+.0546875)*Q2-.5)*Q2 ELSE IF (Q.LE.10.0) THEN A0=((3.999267D-3*Q-9.638957D-2)*Q-.88297)*Q & +.5542818 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.1) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=(((-6.51E-4*Q-.015625)*Q-.125)*Q+1.0)*Q+1.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=(((-6.51E-4*Q+.015625)*Q-.125)*Q-1.0)*Q+1.0 ELSE IF (Q.LE.10.0.AND. KD.EQ.2) THEN A0=(((-4.94603D-4*Q+1.92917D-2)*Q-.3089229) & *Q+1.33372)*Q+.811752 ELSE IF (Q.LE.10.0.AND.KD.EQ.3) THEN A0=((1.971096D-3*Q-5.482465D-2)*Q-1.152218) & *Q+1.10427 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.2) THEN IF (Q.LE.1.0.AND.KD.EQ.1) THEN A0=(((-.0036391*Q2+.0125888)*Q2-.0551939)*Q2 & +.416667)*Q2+4.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.4) THEN A0=(.0003617*Q2-.0833333)*Q2+4.0 ELSE IF (Q.LE.15.AND.KD.EQ.1) THEN A0=(((3.200972D-4*Q-8.667445D-3)*Q & -1.829032D-4)*Q+.9919999)*Q+3.3290504 ELSE IF (Q.LE.10.0.AND.KD.EQ.4) THEN A0=((2.38446D-3*Q-.08725329)*Q-4.732542D-3) & *Q+4.00909 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.3) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=((6.348E-4*Q+.015625)*Q+.0625)*Q2+9.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=((6.348E-4*Q-.015625)*Q+.0625)*Q2+9.0 ELSE IF (Q.LE.20.0.AND.KD.EQ.2) THEN A0=(((3.035731D-4*Q-1.453021D-2)*Q & +.19069602)*Q-.1039356)*Q+8.9449274 ELSE IF (Q.LE.15.0.AND.KD.EQ.3) THEN A0=((9.369364D-5*Q-.03569325)*Q+.2689874)*Q & +8.771735 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.4) THEN IF (Q.LE.1.0.AND.KD.EQ.1) THEN A0=((-2.1E-6*Q2+5.012E-4)*Q2+.0333333)*Q2+16.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.4) THEN A0=((3.7E-6*Q2-3.669E-4)*Q2+.0333333)*Q2+16.0 ELSE IF (Q.LE.25.0.AND.KD.EQ.1) THEN A0=(((1.076676D-4*Q-7.9684875D-3)*Q & +.17344854)*Q-.5924058)*Q+16.620847 ELSE IF (Q.LE.20.0.AND.KD.EQ.4) THEN A0=((-7.08719D-4*Q+3.8216144D-3)*Q & +.1907493)*Q+15.744 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.5) THEN IF (Q.LE.1.0.AND.KD.EQ.2) THEN A0=((6.8E-6*Q+1.42E-5)*Q2+.0208333)*Q2+25.0 ELSE IF (Q.LE.1.0.AND.KD.EQ.3) THEN A0=((-6.8E-6*Q+1.42E-5)*Q2+.0208333)*Q2+25.0 ELSE IF (Q.LE.35.0.AND.KD.EQ.2) THEN A0=(((2.238231D-5*Q-2.983416D-3)*Q & +.10706975)*Q-.600205)*Q+25.93515 ELSE IF (Q.LE.25.0.AND.KD.EQ.3) THEN A0=((-7.425364D-4*Q+2.18225D-2)*Q & +4.16399D-2)*Q+24.897 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.6) THEN IF (Q.LE.1.0) THEN A0=(.4D-6*Q2+.0142857)*Q2+36.0 ELSE IF (Q.LE.40.0.AND.KD.EQ.1) THEN A0=(((-1.66846D-5*Q+4.80263D-4)*Q & +2.53998D-2)*Q-.181233)*Q+36.423 ELSE IF (Q.LE.35.0.AND.KD.EQ.4) THEN A0=((-4.57146D-4*Q+2.16609D-2)*Q-2.349616D-2)*Q & +35.99251 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.EQ.7) THEN IF (Q.LE.10.0) THEN CALL CVQM(M,Q,A0) ELSE IF (Q.LE.50.0.AND.KD.EQ.2) THEN A0=(((-1.411114D-5*Q+9.730514D-4)*Q & -3.097887D-3)*Q+3.533597D-2)*Q+49.0547 ELSE IF (Q.LE.40.0.AND.KD.EQ.3) THEN A0=((-3.043872D-4*Q+2.05511D-2)*Q & -9.16292D-2)*Q+49.19035 ELSE CALL CVQL(KD,M,Q,A0) ENDIF ELSE IF (M.GE.8) THEN IF (Q.LE.3.*M) THEN CALL CVQM(M,Q,A0) ELSE IF (Q.GT.M*M) THEN CALL CVQL(KD,M,Q,A0) ELSE IF (M.EQ.8.AND.KD.EQ.1) THEN A0=(((8.634308D-6*Q-2.100289D-3)*Q+.169072)*Q & -4.64336)*Q+109.4211 ELSE IF (M.EQ.8.AND.KD.EQ.4) THEN A0=((-6.7842D-5*Q+2.2057D-3)*Q+.48296)*Q+56.59 ELSE IF (M.EQ.9.AND.KD.EQ.2) THEN A0=(((2.906435D-6*Q-1.019893D-3)*Q+.1101965)*Q & -3.821851)*Q+127.6098 ELSE IF (M.EQ.9.AND.KD.EQ.3) THEN A0=((-9.577289D-5*Q+.01043839)*Q+.06588934)*Q & +78.0198 ELSE IF (M.EQ.10.AND.KD.EQ.1) THEN A0=(((5.44927D-7*Q-3.926119D-4)*Q+.0612099)*Q & -2.600805)*Q+138.1923 ELSE IF (M.EQ.10.AND.KD.EQ.4) THEN A0=((-7.660143D-5*Q+.01132506)*Q-.09746023)*Q & +99.29494 ELSE IF (M.EQ.11.AND.KD.EQ.2) THEN A0=(((-5.67615D-7*Q+7.152722D-6)*Q+.01920291)*Q & -1.081583)*Q+140.88 ELSE IF (M.EQ.11.AND.KD.EQ.3) THEN A0=((-6.310551D-5*Q+.0119247)*Q-.2681195)*Q & +123.667 ELSE IF (M.EQ.12.AND.KD.EQ.1) THEN A0=(((-2.38351D-7*Q-2.90139D-5)*Q+.02023088)*Q & -1.289)*Q+171.2723 ELSE IF (M.EQ.12.AND.KD.EQ.4) THEN A0=(((3.08902D-7*Q-1.577869D-4)*Q+.0247911)*Q & -1.05454)*Q+161.471 ENDIF ENDIF ENDIF RETURN END SUBROUTINE CVQL(KD,M,Q,A0) C C ======================================================== C Purpose: Compute the characteristic value of Mathieu C functions for q ò 3m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Initial characteristic value C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) IF (KD.EQ.1.OR.KD.EQ.2) W=2.0D0*M+1.0D0 IF (KD.EQ.3.OR.KD.EQ.4) W=2.0D0*M-1.0D0 W2=W*W W3=W*W2 W4=W2*W2 W6=W2*W4 D1=5.0+34.0/W2+9.0/W4 D2=(33.0+410.0/W2+405.0/W4)/W D3=(63.0+1260.0/W2+2943.0/W4+486.0/W6)/W2 D4=(527.0+15617.0/W2+69001.0/W4+41607.0/W6)/W3 C1=128.0 P2=Q/W4 P1=DSQRT(P2) CV1=-2.0*Q+2.0*W*DSQRT(Q)-(W2+1.0)/8.0 CV2=(W+3.0/W)+D1/(32.0*P1)+D2/(8.0*C1*P2) CV2=CV2+D3/(64.0*C1*P1*P2)+D4/(16.0*C1*C1*P2*P2) A0=CV1-CV2/(C1*P1) RETURN END SUBROUTINE CVQM(M,Q,A0) C C ===================================================== C Purpose: Compute the characteristic value of Mathieu C functions for q ó m*m C Input : m --- Order of Mathieu functions C q --- Parameter of Mathieu functions C Output: A0 --- Initial characteristic value C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) HM1=.5*Q/(M*M-1.0) HM3=.25*HM1**3/(M*M-4.0) HM5=HM1*HM3*Q/((M*M-1.0)*(M*M-9.0)) A0=M*M+Q*(HM1+(5.0*M*M+7.0)*HM3 & +(9.0*M**4+58.0*M*M+29.0)*HM5) RETURN END SUBROUTINE JYNB(N,X,NM,BJ,DJ,BY,DY) C C ===================================================== C Purpose: Compute Bessel functions Jn(x), Yn(x) and C their derivatives C Input : x --- Argument of Jn(x) and Yn(x) ( x ò 0 ) C n --- Order of Jn(x) and Yn(x) C Output: BJ(n) --- Jn(x) C DJ(n) --- Jn'(x) C BY(n) --- Yn(x) C DY(n) --- Yn'(x) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 to calculate the starting C point for backward recurrence C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BJ(0:N),DJ(0:N),BY(0:N),DY(0:N), & A(4),B(4),A1(4),B1(4) PI=3.141592653589793D0 R2P=.63661977236758D0 NM=N IF (X.LT.1.0D-100) THEN DO 10 K=0,N BJ(K)=0.0D0 DJ(K)=0.0D0 BY(K)=-1.0D+300 10 DY(K)=1.0D+300 BJ(0)=1.0D0 DJ(1)=0.5D0 RETURN ENDIF IF (X.LE.300.0.OR.N.GT.INT(0.9*X)) THEN IF (N.EQ.0) NM=1 M=MSTA1(X,200) IF (M.LT.NM) THEN NM=M ELSE M=MSTA2(X,NM,15) ENDIF BS=0.0D0 SU=0.0D0 SV=0.0D0 F2=0.0D0 F1=1.0D-100 DO 15 K=M,0,-1 F=2.0D0*(K+1.0D0)/X*F1-F2 IF (K.LE.NM) BJ(K)=F IF (K.EQ.2*INT(K/2).AND.K.NE.0) THEN BS=BS+2.0D0*F SU=SU+(-1)**(K/2)*F/K ELSE IF (K.GT.1) THEN SV=SV+(-1)**(K/2)*K/(K*K-1.0)*F ENDIF F2=F1 15 F1=F S0=BS+F DO 20 K=0,NM 20 BJ(K)=BJ(K)/S0 EC=DLOG(X/2.0D0)+0.5772156649015329D0 BY0=R2P*(EC*BJ(0)-4.0D0*SU/S0) BY(0)=BY0 BY1=R2P*((EC-1.0D0)*BJ(1)-BJ(0)/X-4.0D0*SV/S0) BY(1)=BY1 ELSE DATA A/-.7031250000000000D-01,.1121520996093750D+00, & -.5725014209747314D+00,.6074042001273483D+01/ DATA B/ .7324218750000000D-01,-.2271080017089844D+00, & .1727727502584457D+01,-.2438052969955606D+02/ DATA A1/.1171875000000000D+00,-.1441955566406250D+00, & .6765925884246826D+00,-.6883914268109947D+01/ DATA B1/-.1025390625000000D+00,.2775764465332031D+00, & -.1993531733751297D+01,.2724882731126854D+02/ T1=X-0.25D0*PI P0=1.0D0 Q0=-0.125D0/X DO 25 K=1,4 P0=P0+A(K)*X**(-2*K) 25 Q0=Q0+B(K)*X**(-2*K-1) CU=DSQRT(R2P/X) BJ0=CU*(P0*DCOS(T1)-Q0*DSIN(T1)) BY0=CU*(P0*DSIN(T1)+Q0*DCOS(T1)) BJ(0)=BJ0 BY(0)=BY0 T2=X-0.75D0*PI P1=1.0D0 Q1=0.375D0/X DO 30 K=1,4 P1=P1+A1(K)*X**(-2*K) 30 Q1=Q1+B1(K)*X**(-2*K-1) BJ1=CU*(P1*DCOS(T2)-Q1*DSIN(T2)) BY1=CU*(P1*DSIN(T2)+Q1*DCOS(T2)) BJ(1)=BJ1 BY(1)=BY1 DO 35 K=2,NM BJK=2.0D0*(K-1.0D0)/X*BJ1-BJ0 BJ(K)=BJK BJ0=BJ1 35 BJ1=BJK ENDIF DJ(0)=-BJ(1) DO 40 K=1,NM 40 DJ(K)=BJ(K-1)-K/X*BJ(K) DO 45 K=2,NM BYK=2.0D0*(K-1.0D0)*BY1/X-BY0 BY(K)=BYK BY0=BY1 45 BY1=BYK DY(0)=-BY(1) DO 50 K=1,NM 50 DY(K)=BY(K-1)-K*BY(K)/X RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mothpl.for000077500000000000000000000064311321604176500261350ustar00rootroot00000000000000 PROGRAM MOTHPL C C ========================================================= C Purpose: This program computes orthogonal polynomials: C Tn(x) or Un(x) or Ln(x) or Hn(x), and their C derivatives using subroutine OTHPL C Input : KF --- Function code C KF=1 for Chebyshev polynomial Tn(x) C KF=2 for Chebyshev polynomial Un(x) C KF=3 for Laguerre polynomial Ln(x) C KF=4 for Hermite polynomial Hn(x) C n --- Order of orthogonal polynomials C x --- Argument C Output: PL(n) --- Tn(x) or Un(x) or Ln(x) or Hn(x) C DPL(n)--- Tn'(x) or Un'(x) or Ln'(x) or Hn'(x) C n = 0,1,2,...,N ( N ó 100 ) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION PL(0:100),DPL(0:100) WRITE(*,*)'KF,N,x = ?' READ(*,*)KF,N,X WRITE(*,20)KF,N,X WRITE(*,*) CALL OTHPL(KF,N,X,PL,DPL) IF (KF.EQ.1) WRITE(*,*)' n Tn(x) Tn''(x)' IF (KF.EQ.2) WRITE(*,*)' n Un(x) Un''(x)' IF (KF.EQ.3) WRITE(*,*)' n Ln(x) Ln''(x)' IF (KF.EQ.4) WRITE(*,*)' n Hn(x) Hn''(x)' WRITE(*,*)'-----------------------------------------' DO 10 K=0,N 10 WRITE(*,30)K,PL(K),DPL(K) 20 FORMAT(1X,3HKF=,I3,5X,5HNmax=,I3,5X,2Hx=,F6.3) 30 FORMAT(1X,I3,2D18.8) END SUBROUTINE OTHPL(KF,N,X,PL,DPL) C C ========================================================== C Purpose: Compute orthogonal polynomials: Tn(x) or Un(x), C or Ln(x) or Hn(x), and their derivatives C Input : KF --- Function code C KF=1 for Chebyshev polynomial Tn(x) C KF=2 for Chebyshev polynomial Un(x) C KF=3 for Laguerre polynomial Ln(x) C KF=4 for Hermite polynomial Hn(x) C n --- Order of orthogonal polynomials C x --- Argument of orthogonal polynomials C Output: PL(n) --- Tn(x) or Un(x) or Ln(x) or Hn(x) C DPL(n)--- Tn'(x) or Un'(x) or Ln'(x) or Hn'(x) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION PL(0:N),DPL(0:N) A=2.0D0 B=0.0D0 C=1.0D0 Y0=1.0D0 Y1=2.0D0*X DY0=0.0D0 DY1=2.0D0 PL(0)=1.0D0 PL(1)=2.0D0*X DPL(0)=0.0D0 DPL(1)=2.0D0 IF (KF.EQ.1) THEN Y1=X DY1=1.0D0 PL(1)=X DPL(1)=1.0D0 ELSE IF (KF.EQ.3) THEN Y1=1.0D0-X DY1=-1.0D0 PL(1)=1.0D0-X DPL(1)=-1.0D0 ENDIF DO 10 K=2,N IF (KF.EQ.3) THEN A=-1.0D0/K B=2.0D0+A C=1.0D0+A ELSE IF (KF.EQ.4) THEN C=2.0D0*(K-1.0D0) ENDIF YN=(A*X+B)*Y1-C*Y0 DYN=A*Y1+(A*X+B)*DY1-C*DY0 PL(K)=YN DPL(K)=DYN Y0=Y1 Y1=YN DY0=DY1 10 DY1=DYN RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mpbdv.c000077500000000000000000000322471321604176500254020ustar00rootroot00000000000000/* mpbdv.f -- translated by f2c (version 20090411). You must link the resulting object file with libf2c: on Microsoft Windows system, link with libf2c.lib; on Linux or Unix systems, link with .../path/to/libf2c.a -lm or, if you install libf2c.a in a standard place, with -lf2c -lm -- in that order, at the end of the command line, as in cc *.o -lf2c -lm Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., http://www.netlib.org/f2c/libf2c.zip */ /* GCS: Fortran built-ins */ #include typedef double doublereal; typedef long integer; double d_sign(doublereal *a, doublereal *b) { double x; x = (*a >= 0 ? *a : - *a); return( *b >= 0 ? x : -x); } double pow_dd(doublereal *ap, doublereal *bp) { return(pow(*ap, *bp) ); } #undef abs #define abs(x) ((x) >= 0 ? (x) : -(x)) /* Table of constant values */ static doublereal c_b2 = 1.; static doublereal c_b11 = 2.; /* $$$ PROGRAM MPBDV */ /* $$$C */ /* $$$C ========================================================= */ /* $$$C Purpose: This program computes the parabolic cylinder */ /* $$$C functions Dv(x) and their derivatives using */ /* $$$C subroutine PBDV */ /* $$$C Input: x --- Argument of Dv(x) */ /* $$$C v --- Order of Dv(x) */ /* $$$C Output: DV(na) --- Dn+v0(x) */ /* $$$C DP(na) --- Dn+v0'(x) */ /* $$$C ( na = |n|, n = int(v), v0 = v-n, |v0| < 1 */ /* $$$C n = 0,ñ1,ñ2,úúú, |n| ó 100 ) */ /* $$$C PDF --- Dv(x) */ /* $$$C PDD --- Dv'(x) */ /* $$$C Example: v = 5.5, x =10.0, v0 = 0.5, n = 0,1,...,5 */ /* $$$C */ /* $$$C n+v0 Dv(x) Dv'(x) */ /* $$$C --------------------------------------- */ /* $$$C 0.5 .43971930D-10 -.21767183D-09 */ /* $$$C 1.5 .43753148D-09 -.21216995D-08 */ /* $$$C 2.5 .43093569D-08 -.20452956D-07 */ /* $$$C 3.5 .41999741D-07 -.19491595D-06 */ /* $$$C 4.5 .40491466D-06 -.18355745D-05 */ /* $$$C 5.5 .38601477D-05 -.17073708D-04 */ /* $$$C */ /* $$$C Dv(x)= .38601477D-05, Dv'(x)=-.17073708D-04 */ /* $$$C ========================================================= */ /* $$$C */ /* $$$ IMPLICIT DOUBLE PRECISION (A-H,O-Z) */ /* $$$ DIMENSION DV(0:100),DP(0:100) */ /* $$$ WRITE(*,*)'Please enter v and x ' */ /* $$$ READ(*,*)V,X */ /* $$$ WRITE(*,20)V,X */ /* $$$ NV=INT(V) */ /* $$$ V0=V-NV */ /* $$$ NA=ABS(NV) */ /* $$$ CALL PBDV(V,X,DV,DP,PDF,PDD) */ /* $$$ WRITE(*,*) */ /* $$$ WRITE(*,*)' v Dv(x) Dv''(x)' */ /* $$$ WRITE(*,*)'---------------------------------------' */ /* $$$ DO 10 K=0,NA */ /* $$$ VK=K*ISIGN(1,NV)+V0 */ /* $$$10 WRITE(*,30)VK,DV(K),DP(K) */ /* $$$ WRITE(*,*) */ /* $$$ WRITE(*,40)V,PDF,PDD */ /* $$$20 FORMAT(1X,'v =',F6.2,', ','x =',F6.2) */ /* $$$30 FORMAT(1X,F5.1,2D16.8) */ /* $$$40 FORMAT(1X,'v =',F5.1,', Dv(x)=',D14.8,', Dv''(x)=',D14.8) */ /* $$$ END */ /* Subroutine */ int pbdv_(doublereal *v, doublereal *x, doublereal *dv, doublereal *dp, doublereal *pdf, doublereal *pdd) { /* System generated locals */ integer i__1; /* Builtin functions */ double d_sign(doublereal *, doublereal *), exp(doublereal); /* Local variables */ static doublereal f; static integer k, l, m; static doublereal f0, f1, s0, v0, v1, v2; static integer ja, na; static doublereal ep, pd, xa; static integer nk; static doublereal vh; static integer nv; static doublereal pd0, pd1; extern /* Subroutine */ int dvla_(doublereal *, doublereal *, doublereal * ), dvsa_(doublereal *, doublereal *, doublereal *); /* ==================================================== */ /* Purpose: Compute parabolic cylinder functions Dv(x) */ /* and their derivatives */ /* Input: x --- Argument of Dv(x) */ /* v --- Order of Dv(x) */ /* Output: DV(na) --- Dn+v0(x) */ /* DP(na) --- Dn+v0'(x) */ /* ( na = |n|, v0 = v-n, |v0| < 1, */ /* n = 0,ñ1,ñ2,úúú ) */ /* PDF --- Dv(x) */ /* PDD --- Dv'(x) */ /* Routines called: */ /* (1) DVSA for computing Dv(x) for small |x| */ /* (2) DVLA for computing Dv(x) for large |x| */ /* ==================================================== */ xa = abs(*x); vh = *v; *v += d_sign(&c_b2, v); nv = (integer) (*v); v0 = *v - nv; na = abs(nv); ep = exp(*x * -.25 * *x); if (na >= 1) { ja = 1; } if (*v >= 0.f) { if (v0 == 0.f) { pd0 = ep; pd1 = *x * ep; } else { i__1 = ja; for (l = 0; l <= i__1; ++l) { v1 = v0 + l; if (xa <= 5.8f) { dvsa_(&v1, x, &pd1); } if (xa > 5.8f) { dvla_(&v1, x, &pd1); } if (l == 0) { pd0 = pd1; } /* L10: */ } } dv[0] = pd0; dv[1] = pd1; i__1 = na; for (k = 2; k <= i__1; ++k) { *pdf = *x * pd1 - (k + v0 - 1.) * pd0; dv[k] = *pdf; pd0 = pd1; /* L15: */ pd1 = *pdf; } } else { if (*x <= 0.f) { if (xa <= 5.8) { dvsa_(&v0, x, &pd0); v1 = v0 - 1.; dvsa_(&v1, x, &pd1); } else { dvla_(&v0, x, &pd0); v1 = v0 - 1.; dvla_(&v1, x, &pd1); } dv[0] = pd0; dv[1] = pd1; i__1 = na; for (k = 2; k <= i__1; ++k) { pd = (-(*x) * pd1 + pd0) / (k - 1. - v0); dv[k] = pd; pd0 = pd1; /* L20: */ pd1 = pd; } } else if (*x <= 2.f) { v2 = nv + v0; if (nv == 0) { v2 += -1.; } nk = (integer) (-v2); dvsa_(&v2, x, &f1); v1 = v2 + 1.; dvsa_(&v1, x, &f0); dv[nk] = f1; dv[nk - 1] = f0; for (k = nk - 2; k >= 0; --k) { f = *x * f0 + (k - v0 + 1.) * f1; dv[k] = f; f1 = f0; /* L25: */ f0 = f; } } else { if (xa <= 5.8f) { dvsa_(&v0, x, &pd0); } if (xa > 5.8f) { dvla_(&v0, x, &pd0); } dv[0] = pd0; m = na + 100; f1 = 0.; f0 = 1e-30; for (k = m; k >= 0; --k) { f = *x * f0 + (k - v0 + 1.) * f1; if (k <= na) { dv[k] = f; } f1 = f0; /* L30: */ f0 = f; } s0 = pd0 / f; i__1 = na; for (k = 0; k <= i__1; ++k) { /* L35: */ dv[k] = s0 * dv[k]; } } } i__1 = na - 1; for (k = 0; k <= i__1; ++k) { v1 = abs(v0) + k; if (*v >= 0.) { dp[k] = *x * .5 * dv[k] - dv[k + 1]; } else { dp[k] = *x * -.5 * dv[k] - v1 * dv[k + 1]; } /* L40: */ } *pdf = dv[na - 1]; *pdd = dp[na - 1]; *v = vh; return 0; } /* pbdv_ */ /* Subroutine */ int dvsa_(doublereal *va, doublereal *x, doublereal *pd) { /* System generated locals */ doublereal d__1; /* Builtin functions */ double sqrt(doublereal), exp(doublereal), pow_dd(doublereal *, doublereal *); /* Local variables */ static integer m; static doublereal r__, a0, g0, g1, r1, ep, gm, pi, vm, vt, ga0, va0, sq2, eps; extern /* Subroutine */ int gamma_(doublereal *, doublereal *); /* =================================================== */ /* Purpose: Compute parabolic cylinder function Dv(x) */ /* for small argument */ /* Input: x --- Argument */ /* va --- Order */ /* Output: PD --- Dv(x) */ /* Routine called: GAMMA for computing â(x) */ /* =================================================== */ eps = 1e-15; pi = 3.141592653589793; sq2 = sqrt(2.); ep = exp(*x * -.25 * *x); va0 = (1. - *va) * .5; if (*va == 0.f) { *pd = ep; } else { if (*x == 0.f) { if (va0 <= 0.f && va0 == (doublereal) ((integer) va0)) { *pd = 0.; } else { gamma_(&va0, &ga0); d__1 = *va * -.5; *pd = sqrt(pi) / (pow_dd(&c_b11, &d__1) * ga0); } } else { d__1 = -(*va); gamma_(&d__1, &g1); d__1 = *va * -.5 - 1.; a0 = pow_dd(&c_b11, &d__1) * ep / g1; vt = *va * -.5; gamma_(&vt, &g0); *pd = g0; r__ = 1.; for (m = 1; m <= 250; ++m) { vm = (m - *va) * .5; gamma_(&vm, &gm); r__ = -r__ * sq2 * *x / m; r1 = gm * r__; *pd += r1; if (abs(r1) < abs(*pd) * eps) { goto L15; } /* L10: */ } L15: *pd = a0 * *pd; } } return 0; } /* dvsa_ */ /* Subroutine */ int dvla_(doublereal *va, doublereal *x, doublereal *pd) { /* System generated locals */ doublereal d__1; /* Builtin functions */ double exp(doublereal), pow_dd(doublereal *, doublereal *), cos( doublereal); /* Local variables */ static integer k; static doublereal r__, a0, x1, gl, ep, pi, vl, eps; extern /* Subroutine */ int vvla_(doublereal *, doublereal *, doublereal * ), gamma_(doublereal *, doublereal *); /* ==================================================== */ /* Purpose: Compute parabolic cylinder functions Dv(x) */ /* for large argument */ /* Input: x --- Argument */ /* va --- Order */ /* Output: PD --- Dv(x) */ /* Routines called: */ /* (1) VVLA for computing Vv(x) for large |x| */ /* (2) GAMMA for computing â(x) */ /* ==================================================== */ pi = 3.141592653589793; eps = 1e-12; ep = exp(*x * -.25f * *x); d__1 = abs(*x); a0 = pow_dd(&d__1, va) * ep; r__ = 1.; *pd = 1.; for (k = 1; k <= 16; ++k) { r__ = r__ * -.5 * (k * 2.f - *va - 1.f) * (k * 2.f - *va - 2.f) / (k * *x * *x); *pd += r__; if ((d__1 = r__ / *pd, abs(d__1)) < eps) { goto L15; } /* L10: */ } L15: *pd = a0 * *pd; if (*x < 0.) { x1 = -(*x); vvla_(va, &x1, &vl); d__1 = -(*va); gamma_(&d__1, &gl); *pd = pi * vl / gl + cos(pi * *va) * *pd; } return 0; } /* dvla_ */ /* Subroutine */ int vvla_(doublereal *va, doublereal *x, doublereal *pv) { /* System generated locals */ doublereal d__1, d__2; /* Builtin functions */ double exp(doublereal), sqrt(doublereal), pow_dd(doublereal *, doublereal *), sin(doublereal), cos(doublereal); /* Local variables */ static integer k; static doublereal r__, a0, x1, gl, qe, pi, pdl, dsl, eps; extern /* Subroutine */ int dvla_(doublereal *, doublereal *, doublereal * ), gamma_(doublereal *, doublereal *); /* =================================================== */ /* Purpose: Compute parabolic cylinder function Vv(x) */ /* for large argument */ /* Input: x --- Argument */ /* va --- Order */ /* Output: PV --- Vv(x) */ /* Routines called: */ /* (1) DVLA for computing Dv(x) for large |x| */ /* (2) GAMMA for computing â(x) */ /* =================================================== */ pi = 3.141592653589793; eps = 1e-12; qe = exp(*x * .25f * *x); d__1 = abs(*x); d__2 = -(*va) - 1.; a0 = pow_dd(&d__1, &d__2) * sqrt(2. / pi) * qe; r__ = 1.; *pv = 1.; for (k = 1; k <= 18; ++k) { r__ = r__ * .5 * (k * 2.f + *va - 1.f) * (k * 2.f + *va) / (k * *x * * x); *pv += r__; if ((d__1 = r__ / *pv, abs(d__1)) < eps) { goto L15; } /* L10: */ } L15: *pv = a0 * *pv; if (*x < 0.) { x1 = -(*x); dvla_(va, &x1, &pdl); d__1 = -(*va); gamma_(&d__1, &gl); dsl = sin(pi * *va) * sin(pi * *va); *pv = dsl * gl / pi * pdl - cos(pi * *va) * *pv; } return 0; } /* vvla_ */ /* Subroutine */ int gamma_(doublereal *x, doublereal *ga) { /* Initialized data */ static doublereal g[26] = { 1.,.5772156649015329,-.6558780715202538, -.0420026350340952,.1665386113822915,-.0421977345555443, -.009621971527877,.007218943246663,-.0011651675918591, -2.152416741149e-4,1.280502823882e-4,-2.01348547807e-5, -1.2504934821e-6,1.133027232e-6,-2.056338417e-7,6.116095e-9, 5.0020075e-9,-1.1812746e-9,1.043427e-10,7.7823e-12,-3.6968e-12, 5.1e-13,-2.06e-14,-5.4e-15,1.4e-15,1e-16 }; /* System generated locals */ integer i__1; /* Builtin functions */ double sin(doublereal); /* Local variables */ static integer k, m; static doublereal r__, z__; static integer m1; static doublereal pi, gr; /* ================================================== */ /* Purpose: Compute gamma function â(x) */ /* Input : x --- Argument of â(x) */ /* ( x is not equal to 0,-1,-2,úúú) */ /* Output: GA --- â(x) */ /* ================================================== */ pi = 3.141592653589793; if (*x == (doublereal) ((integer) (*x))) { if (*x > 0.) { *ga = 1.; m1 = (integer) (*x - 1); i__1 = m1; for (k = 2; k <= i__1; ++k) { /* L10: */ *ga *= k; } } else { *ga = 1e300; } } else { if (abs(*x) > 1.) { z__ = abs(*x); m = (integer) z__; r__ = 1.; i__1 = m; for (k = 1; k <= i__1; ++k) { /* L15: */ r__ *= z__ - k; } z__ -= m; } else { z__ = *x; } gr = g[25]; for (k = 25; k >= 1; --k) { /* L20: */ gr = gr * z__ + g[k - 1]; } *ga = 1. / (gr * z__); if (abs(*x) > 1.) { *ga *= r__; if (*x < 0.) { *ga = -pi / (*x * *ga * sin(pi * *x)); } } } return 0; } /* gamma_ */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mpbdv.for000077500000000000000000000245101321604176500257400ustar00rootroot00000000000000c$$$ PROGRAM MPBDV c$$$C c$$$C ========================================================= c$$$C Purpose: This program computes the parabolic cylinder c$$$C functions Dv(x) and their derivatives using c$$$C subroutine PBDV c$$$C Input: x --- Argument of Dv(x) c$$$C v --- Order of Dv(x) c$$$C Output: DV(na) --- Dn+v0(x) c$$$C DP(na) --- Dn+v0'(x) c$$$C ( na = |n|, n = int(v), v0 = v-n, |v0| < 1 c$$$C n = 0,ñ1,ñ2,úúú, |n| ó 100 ) c$$$C PDF --- Dv(x) c$$$C PDD --- Dv'(x) c$$$C Example: v = 5.5, x =10.0, v0 = 0.5, n = 0,1,...,5 c$$$C c$$$C n+v0 Dv(x) Dv'(x) c$$$C --------------------------------------- c$$$C 0.5 .43971930D-10 -.21767183D-09 c$$$C 1.5 .43753148D-09 -.21216995D-08 c$$$C 2.5 .43093569D-08 -.20452956D-07 c$$$C 3.5 .41999741D-07 -.19491595D-06 c$$$C 4.5 .40491466D-06 -.18355745D-05 c$$$C 5.5 .38601477D-05 -.17073708D-04 c$$$C c$$$C Dv(x)= .38601477D-05, Dv'(x)=-.17073708D-04 c$$$C ========================================================= c$$$C c$$$ IMPLICIT DOUBLE PRECISION (A-H,O-Z) c$$$ DIMENSION DV(0:100),DP(0:100) c$$$ WRITE(*,*)'Please enter v and x ' c$$$ READ(*,*)V,X c$$$ WRITE(*,20)V,X c$$$ NV=INT(V) c$$$ V0=V-NV c$$$ NA=ABS(NV) c$$$ CALL PBDV(V,X,DV,DP,PDF,PDD) c$$$ WRITE(*,*) c$$$ WRITE(*,*)' v Dv(x) Dv''(x)' c$$$ WRITE(*,*)'---------------------------------------' c$$$ DO 10 K=0,NA c$$$ VK=K*ISIGN(1,NV)+V0 c$$$10 WRITE(*,30)VK,DV(K),DP(K) c$$$ WRITE(*,*) c$$$ WRITE(*,40)V,PDF,PDD c$$$20 FORMAT(1X,'v =',F6.2,', ','x =',F6.2) c$$$30 FORMAT(1X,F5.1,2D16.8) c$$$40 FORMAT(1X,'v =',F5.1,', Dv(x)=',D14.8,', Dv''(x)=',D14.8) c$$$ END SUBROUTINE PBDV(V,X,DV,DP,PDF,PDD) C C ==================================================== C Purpose: Compute parabolic cylinder functions Dv(x) C and their derivatives C Input: x --- Argument of Dv(x) C v --- Order of Dv(x) C Output: DV(na) --- Dn+v0(x) C DP(na) --- Dn+v0'(x) C ( na = |n|, v0 = v-n, |v0| < 1, C n = 0,ñ1,ñ2,úúú ) C PDF --- Dv(x) C PDD --- Dv'(x) C Routines called: C (1) DVSA for computing Dv(x) for small |x| C (2) DVLA for computing Dv(x) for large |x| C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DV(0:*),DP(0:*) XA=DABS(X) VH=V V=V+DSIGN(1.0D0,V) NV=INT(V) V0=V-NV NA=ABS(NV) EP=DEXP(-.25D0*X*X) IF (NA.GE.1) JA=1 IF (V.GE.0.0) THEN IF (V0.EQ.0.0) THEN PD0=EP PD1=X*EP ELSE DO 10 L=0,JA V1=V0+L IF (XA.LE.5.8) CALL DVSA(V1,X,PD1) IF (XA.GT.5.8) CALL DVLA(V1,X,PD1) IF (L.EQ.0) PD0=PD1 10 CONTINUE ENDIF DV(0)=PD0 DV(1)=PD1 DO 15 K=2,NA PDF=X*PD1-(K+V0-1.0D0)*PD0 DV(K)=PDF PD0=PD1 15 PD1=PDF ELSE IF (X.LE.0.0) THEN IF (XA.LE.5.8D0) THEN CALL DVSA(V0,X,PD0) V1=V0-1.0D0 CALL DVSA(V1,X,PD1) ELSE CALL DVLA(V0,X,PD0) V1=V0-1.0D0 CALL DVLA(V1,X,PD1) ENDIF DV(0)=PD0 DV(1)=PD1 DO 20 K=2,NA PD=(-X*PD1+PD0)/(K-1.0D0-V0) DV(K)=PD PD0=PD1 20 PD1=PD ELSE IF (X.LE.2.0) THEN V2=NV+V0 IF (NV.EQ.0) V2=V2-1.0D0 NK=INT(-V2) CALL DVSA(V2,X,F1) V1=V2+1.0D0 CALL DVSA(V1,X,F0) DV(NK)=F1 DV(NK-1)=F0 DO 25 K=NK-2,0,-1 F=X*F0+(K-V0+1.0D0)*F1 DV(K)=F F1=F0 25 F0=F ELSE IF (XA.LE.5.8) CALL DVSA(V0,X,PD0) IF (XA.GT.5.8) CALL DVLA(V0,X,PD0) DV(0)=PD0 M=100+NA F1=0.0D0 F0=1.0D-30 DO 30 K=M,0,-1 F=X*F0+(K-V0+1.0D0)*F1 IF (K.LE.NA) DV(K)=F F1=F0 30 F0=F S0=PD0/F DO 35 K=0,NA 35 DV(K)=S0*DV(K) ENDIF ENDIF DO 40 K=0,NA-1 V1=ABS(V0)+K IF (V.GE.0.0D0) THEN DP(K)=0.5D0*X*DV(K)-DV(K+1) ELSE DP(K)=-0.5D0*X*DV(K)-V1*DV(K+1) ENDIF 40 CONTINUE PDF=DV(NA-1) PDD=DP(NA-1) V=VH RETURN END SUBROUTINE DVSA(VA,X,PD) C C =================================================== C Purpose: Compute parabolic cylinder function Dv(x) C for small argument C Input: x --- Argument C va --- Order C Output: PD --- Dv(x) C Routine called: GAMMA for computing â(x) C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) EPS=1.0D-15 PI=3.141592653589793D0 SQ2=DSQRT(2.0D0) EP=DEXP(-.25D0*X*X) VA0=0.5D0*(1.0D0-VA) IF (VA.EQ.0.0) THEN PD=EP ELSE IF (X.EQ.0.0) THEN IF (VA0.LE.0.0.AND.VA0.EQ.INT(VA0)) THEN PD=0.0D0 ELSE CALL GAMMA(VA0,GA0) PD=DSQRT(PI)/(2.0D0**(-.5D0*VA)*GA0) ENDIF ELSE CALL GAMMA(-VA,G1) A0=2.0D0**(-0.5D0*VA-1.0D0)*EP/G1 VT=-.5D0*VA CALL GAMMA(VT,G0) PD=G0 R=1.0D0 DO 10 M=1,250 VM=.5D0*(M-VA) CALL GAMMA(VM,GM) R=-R*SQ2*X/M R1=GM*R PD=PD+R1 IF (DABS(R1).LT.DABS(PD)*EPS) GO TO 15 10 CONTINUE 15 PD=A0*PD ENDIF ENDIF RETURN END SUBROUTINE DVLA(VA,X,PD) C C ==================================================== C Purpose: Compute parabolic cylinder functions Dv(x) C for large argument C Input: x --- Argument C va --- Order C Output: PD --- Dv(x) C Routines called: C (1) VVLA for computing Vv(x) for large |x| C (2) GAMMA for computing â(x) C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 EPS=1.0D-12 EP=DEXP(-.25*X*X) A0=DABS(X)**VA*EP R=1.0D0 PD=1.0D0 DO 10 K=1,16 R=-0.5D0*R*(2.0*K-VA-1.0)*(2.0*K-VA-2.0)/(K*X*X) PD=PD+R IF (DABS(R/PD).LT.EPS) GO TO 15 10 CONTINUE 15 PD=A0*PD IF (X.LT.0.0D0) THEN X1=-X CALL VVLA(VA,X1,VL) CALL GAMMA(-VA,GL) PD=PI*VL/GL+DCOS(PI*VA)*PD ENDIF RETURN END SUBROUTINE VVLA(VA,X,PV) C C =================================================== C Purpose: Compute parabolic cylinder function Vv(x) C for large argument C Input: x --- Argument C va --- Order C Output: PV --- Vv(x) C Routines called: C (1) DVLA for computing Dv(x) for large |x| C (2) GAMMA for computing â(x) C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 EPS=1.0D-12 QE=DEXP(0.25*X*X) A0=DABS(X)**(-VA-1.0D0)*DSQRT(2.0D0/PI)*QE R=1.0D0 PV=1.0D0 DO 10 K=1,18 R=0.5D0*R*(2.0*K+VA-1.0)*(2.0*K+VA)/(K*X*X) PV=PV+R IF (DABS(R/PV).LT.EPS) GO TO 15 10 CONTINUE 15 PV=A0*PV IF (X.LT.0.0D0) THEN X1=-X CALL DVLA(VA,X1,PDL) CALL GAMMA(-VA,GL) DSL=DSIN(PI*VA)*DSIN(PI*VA) PV=DSL*GL/PI*PDL-DCOS(PI*VA)*PV ENDIF RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mpbvv.for000077500000000000000000000244771321604176500257760ustar00rootroot00000000000000 PROGRAM MPBVV C C ======================================================== C Purpose: This program computes the parabolic cylinder C functions Vv(x) and Vv'(x) using subroutine C PBVV C Input: x --- Argument of Vv(x) C v --- Order of Vv(x) C Output: VV(na) --- Vv(x) C VP(na) --- Vv'(x) C ( na = |n|, v = n+v0, n = int(v), |v0| < 1 C n = 0,ñ1,ñ2,úúú, |n| ó 100 ) C PVF --- Vv(x) C PVD --- Vv'(x) C Example: v = 5.5, x =10.0, v0 = 0.5, n = 0,1,2,...,5 C C n+v0 Vv(x) Vv'(x) C --------------------------------------- C 0.5 .18522719D+10 .89761157D+10 C 1.5 .19016268D+09 .90145854D+09 C 2.5 .19741946D+08 .91452949D+08 C 3.5 .20733667D+07 .93751130D+07 C 4.5 .22038231D+06 .97145511D+06 C 5.5 .23719356D+05 .10178553D+06 C C Vv(x)= .23719356D+05, Vv'(x)= .10178553D+06 C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION VV(0:100),VP(0:100) WRITE(*,*)'Please enter v and x ' READ(*,*)V,X WRITE(*,20)V,X NV=INT(V) V0=V-NV NA=ABS(NV) CALL PBVV(V,X,VV,VP,PVF,PVD) WRITE(*,*) WRITE(*,*)' v Vv(x) Vv''(x)' WRITE(*,*)'---------------------------------------' DO 10 K=0,NA VK=K*ISIGN(1,NV)+V0 10 WRITE(*,30)VK,VV(K),VP(K) WRITE(*,*) WRITE(*,40)V,PVF,PVD 20 FORMAT(1X,'v =',F6.2,', ','x =',F6.2) 30 FORMAT(1X,F5.1,2D16.8) 40 FORMAT(1X,'v =',F5.1,', Vv(x)=',D14.8,', Vv''(x)=',D14.8) END SUBROUTINE PBVV(V,X,VV,VP,PVF,PVD) C C =================================================== C Purpose: Compute parabolic cylinder functions Vv(x) C and their derivatives C Input: x --- Argument of Vv(x) C v --- Order of Vv(x) C Output: VV(na) --- Vv(x) C VP(na) --- Vv'(x) C ( na = |n|, v = n+v0, |v0| < 1 C n = 0,ñ1,ñ2,úúú ) C PVF --- Vv(x) C PVD --- Vv'(x) C Routines called: C (1) VVSA for computing Vv(x) for small |x| C (2) VVLA for computing Vv(x) for large |x| C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION VV(0:*),VP(0:*) PI=3.141592653589793D0 XA=DABS(X) VH=V V=V+DSIGN(1.0D0,V) NV=INT(V) V0=V-NV NA=ABS(NV) QE=DEXP(0.25D0*X*X) Q2P=DSQRT(2.0D0/PI) IF (NA.GE.1) JA=1 IF (V.LE.0.0) THEN IF (V0.EQ.0.0) THEN IF (XA.LE.7.5) CALL VVSA(V0,X,PV0) IF (XA.GT.7.5) CALL VVLA(V0,X,PV0) F0=Q2P*QE F1=X*F0 VV(0)=PV0 VV(1)=F0 VV(2)=F1 ELSE DO 10 L=0,JA V1=V0-L IF (XA.LE.7.5) CALL VVSA(V1,X,F1) IF (XA.GT.7.5) CALL VVLA(V1,X,F1) IF (L.EQ.0) F0=F1 10 CONTINUE VV(0)=F0 VV(1)=F1 ENDIF KV=2 IF (V0.EQ.0.0) KV=3 DO 15 K=KV,NA F=X*F1+(K-V0-2.0D0)*F0 VV(K)=F F0=F1 15 F1=F ELSE IF (X.GE.0.0.AND.X.LE.7.5D0) THEN V2=V IF (V2.LT.1.0) V2=V2+1.0D0 CALL VVSA(V2,X,F1) V1=V2-1.0D0 KV=INT(V2) CALL VVSA(V1,X,F0) VV(KV)=F1 VV(KV-1)=F0 DO 20 K=KV-2,0,-1 F=X*F0-(K+V0+2.0D0)*F1 IF (K.LE.NA) VV(K)=F F1=F0 20 F0=F ELSE IF (X.GT.7.5D0) THEN CALL VVLA(V0,X,PV0) M=100+ABS(NA) VV(1)=PV0 F1=0.0D0 F0=1.0D-40 DO 25 K=M,0,-1 F=X*F0-(K+V0+2.0D0)*F1 IF (K.LE.NA) VV(K)=F F1=F0 25 F0=F S0=PV0/F DO 30 K=0,NA 30 VV(K)=S0*VV(K) ELSE IF (XA.LE.7.5D0) THEN CALL VVSA(V0,X,F0) V1=V0+1.0 CALL VVSA(V1,X,F1) ELSE CALL VVLA(V0,X,F0) V1=V0+1.0D0 CALL VVLA(V1,X,F1) ENDIF VV(0)=F0 VV(1)=F1 DO 35 K=2,NA F=(X*F1-F0)/(K+V0) VV(K)=F F0=F1 35 F1=F ENDIF ENDIF DO 40 K=0,NA-1 V1=V0+K IF (V.GE.0.0D0) THEN VP(K)=0.5D0*X*VV(K)-(V1+1.0D0)*VV(K+1) ELSE VP(K)=-0.5D0*X*VV(K)+VV(K+1) ENDIF 40 CONTINUE PVF=VV(NA-1) PVD=VP(NA-1) V=VH RETURN END SUBROUTINE VVSA(VA,X,PV) C C =================================================== C Purpose: Compute parabolic cylinder function Vv(x) C for small argument C Input: x --- Argument C va --- Order C Output: PV --- Vv(x) C Routine called : GAMMA for computing â(x) C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) EPS=1.0D-15 PI=3.141592653589793D0 EP=DEXP(-.25D0*X*X) VA0=1.0D0+0.5D0*VA IF (X.EQ.0.0) THEN IF (VA0.LE.0.0.AND.VA0.EQ.INT(VA0).OR.VA.EQ.0.0) THEN PV=0.0D0 ELSE VB0=-0.5D0*VA SV0=DSIN(VA0*PI) CALL GAMMA(VA0,GA0) PV=2.0D0**VB0*SV0/GA0 ENDIF ELSE SQ2=DSQRT(2.0D0) A0=2.0D0**(-.5D0*VA)*EP/(2.0D0*PI) SV=DSIN(-(VA+.5D0)*PI) V1=-.5D0*VA CALL GAMMA(V1,G1) PV=(SV+1.0D0)*G1 R=1.0D0 FAC=1.0D0 DO 10 M=1,250 VM=.5D0*(M-VA) CALL GAMMA(VM,GM) R=R*SQ2*X/M FAC=-FAC GW=FAC*SV+1.0D0 R1=GW*R*GM PV=PV+R1 IF (DABS(R1/PV).LT.EPS.AND.GW.NE.0.0) GO TO 15 10 CONTINUE 15 PV=A0*PV ENDIF RETURN END SUBROUTINE VVLA(VA,X,PV) C C =================================================== C Purpose: Compute parabolic cylinder function Vv(x) C for large argument C Input: x --- Argument C va --- Order C Output: PV --- Vv(x) C Routines called: C (1) DVLA for computing Dv(x) for large |x| C (2) GAMMA for computing â(x) C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 EPS=1.0D-12 QE=DEXP(0.25*X*X) A0=DABS(X)**(-VA-1.0D0)*DSQRT(2.0D0/PI)*QE R=1.0D0 PV=1.0D0 DO 10 K=1,18 R=0.5D0*R*(2.0*K+VA-1.0)*(2.0*K+VA)/(K*X*X) PV=PV+R IF (DABS(R/PV).LT.EPS) GO TO 15 10 CONTINUE 15 PV=A0*PV IF (X.LT.0.0D0) THEN X1=-X CALL DVLA(VA,X1,PDL) CALL GAMMA(-VA,GL) DSL=DSIN(PI*VA)*DSIN(PI*VA) PV=DSL*GL/PI*PDL-DCOS(PI*VA)*PV ENDIF RETURN END SUBROUTINE DVLA(VA,X,PD) C C ==================================================== C Purpose: Compute parabolic cylinder functions Dv(x) C for large argument C Input: x --- Argument C va --- Order C Output: PD --- Dv(x) C Routines called: C (1) VVLA for computing Vv(x) for large |x| C (2) GAMMA for computing â(x) C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 EPS=1.0D-12 EP=DEXP(-.25*X*X) A0=X**VA*EP R=1.0D0 PD=1.0D0 DO 10 K=1,16 R=-0.5D0*R*(2.0*K-VA-1.0)*(2.0*K-VA-2.0)/(K*X*X) PD=PD+R IF (DABS(R/PD).LT.EPS) GO TO 15 10 CONTINUE 15 PD=A0*PD IF (X.LT.0.0D0) THEN X1=-X CALL VVLA(VA,X1,VL) CALL GAMMA(-VA,GL) PD=PI*VL/GL+DCOS(PI*VA)*PD ENDIF RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mpbwa.for000077500000000000000000000147171321604176500257460ustar00rootroot00000000000000 PROGRAM MPBWA C C ============================================================ C Purpose: This program computes the parabolic cylinder C functions W(a,ñx) and their derivatives using C subroutine PBWA C Input : a --- Parameter ( 0 ó |a| ó 5 ) C x --- Argument of W(a,ñx) ( 0 ó |x| ó 5 ) C Output : W1F --- W(a,x) C W1D --- W'(a,x) C W2F --- W(a,-x) C W2D --- W'(a,-x) C Example: x = 5.0 C a W(a,x) W'(a,x) W(a,-x) W'(a,-x) C ---------------------------------------------------- C 0.5 .1871153 .1915744 -.8556585 4.4682493 C 1.5 -.0215853 .0899870 -8.8586002 -9.3971967 C 0.0 .3009549 -.7148233 .6599634 1.7552224 C -0.5 -.1934088 -1.3474400 .6448148 -.6781011 C -1.5 -.5266539 .8219516 -.2822774 -1.4582283 C -5.0 .0893618 -1.8118641 .5386084 .2698553 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter a and x ' READ(*,*)A,X WRITE(*,10)A,X WRITE(*,*) WRITE(*,*)' a W(a,x) W''(a,x)', & ' W(a,-x) W''(a,-x)' WRITE(*,*)' -----------------------------------------', & '----------------------------' CALL PBWA(A,X,W1F,W1D,W2F,W2D) WRITE(*,20)A,W1F,W1D,W2F,W2D 10 FORMAT(1X,'a=',F5.1,3X,'x=',F5.1) 20 FORMAT(1X,F5.1,4D16.8) END SUBROUTINE PBWA(A,X,W1F,W1D,W2F,W2D) C C ====================================================== C Purpose: Compute parabolic cylinder functions W(a,ñx) C and their derivatives C Input : a --- Parameter ( 0 ó |a| ó 5 ) C x --- Argument of W(a,ñx) ( 0 ó |x| ó 5 ) C Output : W1F --- W(a,x) C W1D --- W'(a,x) C W2F --- W(a,-x) C W2D --- W'(a,-x) C Routine called: C CGAMA for computing complex gamma function C ====================================================== C IMPLICIT DOUBLE PRECISION (A,B,D-H,O-Y) IMPLICIT COMPLEX *16 (C,Z) DIMENSION H(100),D(100) EPS=1.0D-15 P0=0.59460355750136D0 IF (A.EQ.0.0D0) THEN G1=3.625609908222D0 G2=1.225416702465D0 ELSE X1=0.25D0 Y1=0.5D0*A CALL CGAMA(X1,Y1,1,UGR,UGI) G1=DSQRT(UGR*UGR+UGI*UGI) X2=0.75D0 CALL CGAMA(X2,Y1,1,VGR,VGI) G2=DSQRT(VGR*VGR+VGI*VGI) ENDIF F1=DSQRT(G1/G2) F2=DSQRT(2.0D0*G2/G1) H0=1.0D0 H1=A H(1)=A DO 10 L1=4,200,2 M=L1/2 HL=A*H1-0.25D0*(L1-2.0D0)*(L1-3.0D0)*H0 H(M)=HL H0=H1 10 H1=HL Y1F=1.0D0 R=1.0D0 DO 15 K=1,100 R=0.5D0*R*X*X/(K*(2.0D0*K-1.0D0)) R1=H(K)*R Y1F=Y1F+R1 IF (DABS(R1/Y1F).LE.EPS.AND.K.GT.30) GO TO 20 15 CONTINUE 20 Y1D=A R=1.0D0 DO 25 K=1,100 R=0.5D0*R*X*X/(K*(2.0D0*K+1.0D0)) R1=H(K+1)*R Y1D=Y1D+R1 IF (DABS(R1/Y1D).LE.EPS.AND.K.GT.30) GO TO 30 25 CONTINUE 30 Y1D=X*Y1D D1=1.0D0 D2=A D(1)=1.0D0 D(2)=A DO 40 L2=5,160,2 M=(L2+1)/2 DL=A*D2-0.25D0*(L2-2.0D0)*(L2-3.0D0)*D1 D(M)=DL D1=D2 40 D2=DL Y2F=1.0D0 R=1.0D0 DO 45 K=1,100 R=0.5D0*R*X*X/(K*(2.0D0*K+1.0D0)) R1=D(K+1)*R Y2F=Y2F+R1 IF (DABS(R1/Y2F).LE.EPS.AND.K.GT.30) GO TO 50 45 CONTINUE 50 Y2F=X*Y2F Y2D=1.0D0 R=1.0D0 DO 55 K=1,100 R=0.5D0*R*X*X/(K*(2.0D0*K-1.0D0)) R1=D(K+1)*R Y2D=Y2D+R1 IF (DABS(R1/Y2D).LE.EPS.AND.K.GT.30) GO TO 60 55 CONTINUE 60 W1F=P0*(F1*Y1F-F2*Y2F) W2F=P0*(F1*Y1F+F2*Y2F) W1D=P0*(F1*Y1D-F2*Y2D) W2D=P0*(F1*Y1D+F2*Y2D) RETURN END SUBROUTINE CGAMA(X,Y,KF,GR,GI) C C ========================================================= C Purpose: Compute complex gamma function â(z) or Ln[â(z)] C Input : x --- Real part of z C y --- Imaginary part of z C KF --- Function code C KF=0 for Ln[â(z)] C KF=1 for â(z) C Output: GR --- Real part of Ln[â(z)] or â(z) C GI --- Imaginary part of Ln[â(z)] or â(z) C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(10) PI=3.141592653589793D0 DATA A/8.333333333333333D-02,-2.777777777777778D-03, & 7.936507936507937D-04,-5.952380952380952D-04, & 8.417508417508418D-04,-1.917526917526918D-03, & 6.410256410256410D-03,-2.955065359477124D-02, & 1.796443723688307D-01,-1.39243221690590D+00/ IF (Y.EQ.0.0D0.AND.X.EQ.INT(X).AND.X.LE.0.0D0) THEN GR=1.0D+300 GI=0.0D0 RETURN ELSE IF (X.LT.0.0D0) THEN X1=X Y1=Y X=-X Y=-Y ENDIF X0=X IF (X.LE.7.0) THEN NA=INT(7-X) X0=X+NA ENDIF Z1=DSQRT(X0*X0+Y*Y) TH=DATAN(Y/X0) GR=(X0-.5D0)*DLOG(Z1)-TH*Y-X0+0.5D0*DLOG(2.0D0*PI) GI=TH*(X0-0.5D0)+Y*DLOG(Z1)-Y DO 10 K=1,10 T=Z1**(1-2*K) GR=GR+A(K)*T*DCOS((2.0D0*K-1.0D0)*TH) 10 GI=GI-A(K)*T*DSIN((2.0D0*K-1.0D0)*TH) IF (X.LE.7.0) THEN GR1=0.0D0 GI1=0.0D0 DO 15 J=0,NA-1 GR1=GR1+.5D0*DLOG((X+J)**2+Y*Y) 15 GI1=GI1+DATAN(Y/(X+J)) GR=GR-GR1 GI=GI-GI1 ENDIF IF (X1.LT.0.0D0) THEN Z1=DSQRT(X*X+Y*Y) TH1=DATAN(Y/X) SR=-DSIN(PI*X)*DCOSH(PI*Y) SI=-DCOS(PI*X)*DSINH(PI*Y) Z2=DSQRT(SR*SR+SI*SI) TH2=DATAN(SI/SR) IF (SR.LT.0.0D0) TH2=PI+TH2 GR=DLOG(PI/(Z1*Z2))-GR GI=-TH1-TH2-GI X=X1 Y=Y1 ENDIF IF (KF.EQ.1) THEN G0=DEXP(GR) GR=G0*DCOS(GI) GI=G0*DSIN(GI) ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mpsi.for000077500000000000000000000046651321604176500256110ustar00rootroot00000000000000 PROGRAM MPSI C C ================================================== C Purpose: This program computes the psi function C using subroutine PSI C Input : x --- Argument of psi(x) C Output: PS --- psi(x) C Examples: C x Psi(x) C ------------------------ C .25 -4.227453533 C .50 -1.963510026 C .75 -1.085860880 C 1.00 -.577215665 C 1.25 -.227453533 C 1.50 .036489974 C 1.75 .247472454 C 2.00 .422784335 C ================================================== C DOUBLE PRECISION X,PS WRITE(*,*)'Please enter x' READ(*,*)X WRITE(*,*)' x Psi(x)' WRITE(*,*)' ------------------------' CALL PSI(X,PS) WRITE(*,10)X,PS 10 FORMAT(1X,F6.2,F18.9) END SUBROUTINE PSI(X,PS) C C ====================================== C Purpose: Compute the psi function C Input : x --- Argument of psi(x) C Output: PS --- psi(x) C ====================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) XA=DABS(X) PI=3.141592653589793D0 EL=.5772156649015329D0 S=0.0D0 IF (X.EQ.INT(X).AND.X.LE.0.0) THEN PS=1.0D+300 RETURN ELSE IF (XA.EQ.INT(XA)) THEN N=XA DO 10 K=1 ,N-1 10 S=S+1.0D0/K PS=-EL+S ELSE IF (XA+.5.EQ.INT(XA+.5)) THEN N=XA-.5 DO 20 K=1,N 20 S=S+1.0/(2.0D0*K-1.0D0) PS=-EL+2.0D0*S-1.386294361119891D0 ELSE IF (XA.LT.10.0) THEN N=10-INT(XA) DO 30 K=0,N-1 30 S=S+1.0D0/(XA+K) XA=XA+N ENDIF X2=1.0D0/(XA*XA) A1=-.8333333333333D-01 A2=.83333333333333333D-02 A3=-.39682539682539683D-02 A4=.41666666666666667D-02 A5=-.75757575757575758D-02 A6=.21092796092796093D-01 A7=-.83333333333333333D-01 A8=.4432598039215686D0 PS=DLOG(XA)-.5D0/XA+X2*(((((((A8*X2+A7)*X2+ & A6)*X2+A5)*X2+A4)*X2+A3)*X2+A2)*X2+A1) PS=PS-S ENDIF IF (X.LT.0.0) PS=PS-PI*DCOS(PI*X)/DSIN(PI*X)-1.0D0/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mrctj.for000077500000000000000000000124061321604176500257500ustar00rootroot00000000000000 PROGRAM MRCTJ C C ======================================================= C Purpose: This program computes the Riccati-Bessel C functions of the first kind, and their C derivatives using subroutine RCTJ C Input: x --- Argument of Riccati-Bessel function C n --- Order of jn(x) ( 0 ó n ó 250 ) C Output: RJ(n) --- xújn(x) C DJ(n) --- [xújn(x)]' C Example: x = 10.0 C n xújn(x) [xújn(x)]' C -------------------------------------------- C 0 -.5440211109D+00 -.8390715291D+00 C 1 .7846694180D+00 -.6224880527D+00 C 2 .7794219363D+00 .6287850307D+00 C 3 -.3949584498D+00 .8979094712D+00 C 4 -.1055892851D+01 .2739869063D-01 C 5 -.5553451162D+00 -.7782202931D+00 C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION RJ(0:250),DJ(0:250) WRITE(*,*)' Please enter n and x ' READ(*,*)N,X WRITE(*,30)N,X IF (N.LE.10) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF WRITE(*,*) CALL RCTJ(N,X,NM,RJ,DJ) WRITE(*,*) WRITE(*,*)' n xújn(x) [xújn(x)]''' WRITE(*,*)'--------------------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20)K,RJ(K),DJ(K) 20 FORMAT(1X,I3,2D20.10) 30 FORMAT(3X,6HNmax =,I3,', ',3Hx =,F7.2) END SUBROUTINE RCTJ(N,X,NM,RJ,DJ) C C ======================================================== C Purpose: Compute Riccati-Bessel functions of the first C kind and their derivatives C Input: x --- Argument of Riccati-Bessel function C n --- Order of jn(x) ( n = 0,1,2,... ) C Output: RJ(n) --- xújn(x) C DJ(n) --- [xújn(x)]' C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 for computing the starting C point for backward recurrence C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION RJ(0:N),DJ(0:N) NM=N IF (DABS(X).LT.1.0D-100) THEN DO 10 K=0,N RJ(K)=0.0D0 10 DJ(K)=0.0D0 DJ(0)=1.0D0 RETURN ENDIF RJ(0)=DSIN(X) RJ(1)=RJ(0)/X-DCOS(X) RJ0=RJ(0) RJ1=RJ(1) IF (N.GE.2) THEN M=MSTA1(X,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(X,N,15) ENDIF F0=0.0D0 F1=1.0D-100 DO 15 K=M,0,-1 F=(2.0D0*K+3.0D0)*F1/X-F0 IF (K.LE.NM) RJ(K)=F F0=F1 15 F1=F IF (DABS(RJ0).GT.DABS(RJ1)) CS=RJ0/F IF (DABS(RJ0).LE.DABS(RJ1)) CS=RJ1/F0 DO 20 K=0,NM 20 RJ(K)=CS*RJ(K) ENDIF DJ(0)=DCOS(X) DO 25 K=1,NM 25 DJ(K)=-K*RJ(K)/X+RJ(K-1) RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mrcty.for000077500000000000000000000054331321604176500257710ustar00rootroot00000000000000 PROGRAM MRCTY C C ======================================================= C Purpose: This program computes the Riccati-Bessel C functions of the second kind and their C derivatives using subroutine RCTY C Input: x --- Argument of Riccati-Bessel function C n --- Order of yn(x) C Output: RY(n) --- xúyn(x) C DY(n) --- [xúyn(x)]' C Example: x = 10.0 C n xúyn(x) [xúyn(x)]' C -------------------------------------------- C 0 .8390715291D+00 -.5440211109D+00 C 1 .6279282638D+00 .7762787027D+00 C 2 -.6506930499D+00 .7580668738D+00 C 3 -.9532747888D+00 -.3647106133D+00 C 4 -.1659930220D-01 -.9466350679D+00 C 5 .9383354168D+00 -.4857670106D+00 C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION RY(0:250),DY(0:250) WRITE(*,*)' Please enter n and x ' READ(*,*)N,X WRITE(*,30)N,X IF (N.LE.10) THEN NS=1 ELSE WRITE(*,*)' Please enter order step Ns' READ(*,*)NS ENDIF WRITE(*,*) CALL RCTY(N,X,NM,RY,DY) WRITE(*,*) WRITE(*,*)' n xúyn(x) [xúyn(x)]''' WRITE(*,*)'--------------------------------------------' DO 10 K=0,NM,NS WRITE(*,20)K,RY(K),DY(K) 10 CONTINUE 20 FORMAT(1X,I3,2D20.10) 30 FORMAT(3X,6HNmax =,I3,', ',3Hx =,F6.2) END SUBROUTINE RCTY(N,X,NM,RY,DY) C C ======================================================== C Purpose: Compute Riccati-Bessel functions of the second C kind and their derivatives C Input: x --- Argument of Riccati-Bessel function C n --- Order of yn(x) C Output: RY(n) --- xúyn(x) C DY(n) --- [xúyn(x)]' C NM --- Highest order computed C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION RY(0:N),DY(0:N) NM=N IF (X.LT.1.0D-60) THEN DO 10 K=0,N RY(K)=-1.0D+300 10 DY(K)=1.0D+300 RY(0)=-1.0D0 DY(0)=0.0D0 RETURN ENDIF RY(0)=-DCOS(X) RY(1)=RY(0)/X-DSIN(X) RF0=RY(0) RF1=RY(1) DO 15 K=2,N RF2=(2.0D0*K-1.0D0)*RF1/X-RF0 IF (DABS(RF2).GT.1.0D+300) GO TO 20 RY(K)=RF2 RF0=RF1 15 RF1=RF2 20 NM=K-1 DY(0)=DSIN(X) DO 25 K=1,NM 25 DY(K)=-K*RY(K)/X+RY(K-1) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mrswfo.for000077500000000000000000000651331321604176500261530ustar00rootroot00000000000000 PROGRAM MRSWFO C C ============================================================= C Purpose: This program computes the radial oblate spheriodal C functions of the first and second kinds, and their C derivatives using subroutine RSWFO C Input : m --- Mode parameter, m = 0,1,2,... C n --- Mode parameter, n = m,m+1,m+2,... C c --- Spheroidal parameter C x --- Argument (x ò 0) C cv --- Characteristic value C KF --- Function code C KF=1 for the first kind C KF=2 for the second kind C KF=3 for both the first and second kinds C Output: R1F --- Radial function of the first kind C R1D --- Derivative of the radial function of C the first kind C R2F --- Radial function of the second kind C R2D --- Derivative of the radial function of C the second kind C Example: C KD=-1, m = 2, n = 3, c = 5.0 and cv = 2.10980581604 C C x R23(1)(-ic,ix) R23(1)'(-ic,ix) R23(2)(-ic,ix) R23(2)'(-ic,ix) C ------------------------------------------------------------------ C 0.0 0.0000000 (-1) 4.9911346 (-1)-4.0071049 (-1) 3.3065682 C 0.5 (-1) 2.0215966 (-1) 1.9559661 (-1)-1.5154835 (-1) 6.4482526 C 1.0 (-1) 1.0526737 (-1)-5.4010624 (-1) 1.3065731 (-1) 2.7958491 C 1.5 (-1)-1.1611246 (-2)-8.9414690 (-2) 3.7405936 (-1)-5.0118500 C 5.0 (-2) 3.6463251 (-2)-8.3283065 (-2) 1.5549615 (-1) 1.7544481 C ============================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EG(200) WRITE(*,*)'Please enter KF' READ(*,*)KF WRITE(*,10)KF WRITE(*,*)'Please enter m, n, c and x ( x ò 0 )' READ(*,*)M,N,C,X CALL SEGV(M,N,C,-1,CV,EG) WRITE(*,20)M,N,C,CV,X WRITE(*,*) CALL RSWFO(M,N,C,X,CV,KF,R1F,R1D,R2F,R2D) WRITE(*,*)' x Rmn(1)(-ic,ix) Rmn''(1)(-ic,ix) ', & ' Rmn(2)(-ic,ix) Rmn''(2)(-ic,ix)' WRITE(*,*)' ---------------------------------------------', & '---------------------------' IF (KF.EQ.1) THEN WRITE(*,30)X,R1F,R1D ELSE IF (KF.EQ.2) THEN WRITE(*,40)X,R2F,R2D ELSE IF (KF.EQ.3) THEN WRITE(*,30)X,R1F,R1D,R2F,R2D ENDIF IF (KF.EQ.3) THEN WRITE(*,50)R1F*R2D-R2F*R1D,1.0D0/(C*(X*X+1.0D0)) WRITE(*,60) ENDIF 10 FORMAT(1X,3HKF=,I3) 20 FORMAT(1X,2Hm=,I2,', ',2Hn=,I2,', ',2Hc=,F5.1, & ', ',4Hcv =,F18.10,', ',2Hx=,F5.2) 30 FORMAT(1X,F5.1,4D17.8) 40 FORMAT(1X,F5.1,34X,4D17.8) 50 FORMAT(1X,/1X,'Wronskian check:',/1X,'Computed value =', & D17.8,5X,'Exact value =',D17.8) 60 FORMAT(1X,/1X,'Caution: This check is not accurate if it ', & 'involves',/1X,' the subtraction of two ', & 'similar numbers') END SUBROUTINE RSWFO(M,N,C,X,CV,KF,R1F,R1D,R2F,R2D) C C ========================================================== C Purpose: Compute oblate radial functions of the first C and second kinds, and their derivatives C Input : m --- Mode parameter, m = 0,1,2,... C n --- Mode parameter, n = m,m+1,m+2,... C c --- Spheroidal parameter C x --- Argument (x ò 0) C cv --- Characteristic value C KF --- Function code C KF=1 for the first kind C KF=2 for the second kind C KF=3 for both the first and second kinds C Output: R1F --- Radial function of the first kind C R1D --- Derivative of the radial function of C the first kind C R2F --- Radial function of the second kind C R2D --- Derivative of the radial function of C the second kind C Routines called: C (1) SDMN for computing expansion coefficients dk C (2) RMN1 for computing prolate or oblate radial C function of the first kind C (3) RMN2L for computing prolate or oblate radial C function of the second kind for a large argument C (4) RMN2SO for computing oblate radial functions of C the second kind for a small argument C ========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DF(200) KD=-1 CALL SDMN(M,N,C,CV,KD,DF) IF (KF.NE.2) THEN CALL RMN1(M,N,C,X,DF,KD,R1F,R1D) ENDIF IF (KF.GT.1) THEN ID=10 IF (X.GT.1.0D-8) THEN CALL RMN2L(M,N,C,X,DF,KD,R2F,R2D,ID) ENDIF IF (ID.GT.-1) THEN CALL RMN2SO(M,N,C,X,CV,DF,KD,R2F,R2D) ENDIF ENDIF RETURN END SUBROUTINE SDMN(M,N,C,CV,KD,DF) C C ===================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions, dk C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C cv --- Characteristic value C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C Output: DF(k) --- Expansion coefficients dk; C DF(1), DF(2), ... correspond to C d0, d2, ... for even n-m and d1, C d3, ... for odd n-m C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(200),D(200),G(200),DF(200) NM=25+INT(0.5*(N-M)+C) IF (C.LT.1.0D-10) THEN DO 5 I=1,NM 5 DF(I)=0D0 DF((N-M)/2+1)=1.0D0 RETURN ENDIF CS=C*C*KD IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 DO 10 I=1,NM+2 IF (IP.EQ.0) K=2*(I-1) IF (IP.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS 10 CONTINUE FS=1.0D0 F1=0.0D0 F0=1.0D-100 KB=0 DF(NM+1)=0.0D0 DO 30 K=NM,1,-1 F=-((D(K+1)-CV)*F0+A(K+1)*F1)/G(K+1) IF (DABS(F).GT.DABS(DF(K+1))) THEN DF(K)=F F1=F0 F0=F IF (DABS(F).GT.1.0D+100) THEN DO 12 K1=K,NM 12 DF(K1)=DF(K1)*1.0D-100 F1=F1*1.0D-100 F0=F0*1.0D-100 ENDIF ELSE KB=K FL=DF(K+1) F1=1.0D-100 F2=-(D(1)-CV)/A(1)*F1 DF(1)=F1 IF (KB.EQ.1) THEN FS=F2 ELSE IF (KB.EQ.2) THEN DF(2)=F2 FS=-((D(2)-CV)*F2+G(2)*F1)/A(2) ELSE DF(2)=F2 DO 20 J=3,KB+1 F=-((D(J-1)-CV)*F2+G(J-1)*F1)/A(J-1) IF (J.LE.KB) DF(J)=F IF (DABS(F).GT.1.0D+100) THEN DO 15 K1=1,J 15 DF(K1)=DF(K1)*1.0D-100 F=F*1.0D-100 F2=F2*1.0D-100 ENDIF F1=F2 20 F2=F FS=F ENDIF GO TO 35 ENDIF 30 CONTINUE 35 SU1=0.0D0 R1=1.0D0 DO 40 J=M+IP+1,2*(M+IP) 40 R1=R1*J SU1=DF(1)*R1 DO 45 K=2,KB R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) 45 SU1=SU1+R1*DF(K) SU2=0.0D0 DO 50 K=KB+1,NM IF (K.NE.1) R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) SU2=SU2+R1*DF(K) IF (DABS(SW-SU2).LT.DABS(SU2)*1.0D-14) GOTO 55 50 SW=SU2 55 R3=1.0D0 DO 60 J=1,(M+N+IP)/2 60 R3=R3*(J+0.5D0*(N+M+IP)) R4=1.0D0 DO 65 J=1,(N-M-IP)/2 65 R4=-4.0D0*R4*J S0=R3/(FL*(SU1/FS)+SU2)/R4 DO 70 K=1,KB 70 DF(K)=FL/FS*S0*DF(K) DO 75 K=KB+1,NM 75 DF(K)=S0*DF(K) RETURN END SUBROUTINE RMN1(M,N,C,X,DF,KD,R1F,R1D) C C ======================================================= C Purpose: Compute prolate and oblate spheroidal radial C functions of the first kind for given m, n, C c and x C Routines called: C (1) SCKB for computing expansion coefficients c2k C (2) SPHJ for computing the spherical Bessel C functions of the first kind C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION CK(200),DF(200),SJ(0:251),DJ(0:251) EPS=1.0D-14 IP=1 NM1=INT((N-M)/2) IF (N-M.EQ.2*NM1) IP=0 NM=25+NM1+INT(C) REG=1.0D0 IF (M+NM.GT.80) REG=1.0D-200 R0=REG DO 10 J=1,2*M+IP 10 R0=R0*J R=R0 SUC=R*DF(1) DO 15 K=2,NM R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) SUC=SUC+R*DF(K) IF (K.GT.NM1.AND.DABS(SUC-SW).LT.DABS(SUC)*EPS) GO TO 20 15 SW=SUC 20 CONTINUE IF (X.EQ.0.0) THEN CALL SCKB(M,N,C,DF,CK) SUM=0.0D0 DO 25 J=1,NM SUM=SUM+CK(J) IF (DABS(SUM-SW1).LT.DABS(SUM)*EPS) GO TO 30 25 SW1=SUM 30 R1=1.0D0 DO 35 J=1,(N+M+IP)/2 35 R1=R1*(J+0.5D0*(N+M+IP)) R2=1.0D0 DO 40 J=1,M 40 R2=2.0D0*C*R2*J R3=1.0D0 DO 45 J=1,(N-M-IP)/2 45 R3=R3*J SA0=(2.0*(M+IP)+1.0)*R1/(2.0**N*C**IP*R2*R3) IF (IP.EQ.0) THEN R1F=SUM/(SA0*SUC)*DF(1)*REG R1D=0.0D0 ELSE IF (IP.EQ.1) THEN R1F=0.0D0 R1D=SUM/(SA0*SUC)*DF(1)*REG ENDIF RETURN ENDIF CX=C*X NM2=2*NM+M CALL SPHJ(NM2,CX,NM2,SJ,DJ) A0=(1.0D0-KD/(X*X))**(0.5D0*M)/SUC R1F=0.0D0 DO 50 K=1,NM L=2*K+M-N-2+IP IF (L.EQ.4*INT(L/4)) LG=1 IF (L.NE.4*INT(L/4)) LG=-1 IF (K.EQ.1) THEN R=R0 ELSE R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) ENDIF NP=M+2*K-2+IP R1F=R1F+LG*R*DF(K)*SJ(NP) IF (K.GT.NM1.AND.DABS(R1F-SW).LT.DABS(R1F)*EPS) GO TO 55 50 SW=R1F 55 R1F=R1F*A0 B0=KD*M/X**3.0D0/(1.0-KD/(X*X))*R1F SUD=0.0D0 DO 60 K=1,NM L=2*K+M-N-2+IP IF (L.EQ.4*INT(L/4)) LG=1 IF (L.NE.4*INT(L/4)) LG=-1 IF (K.EQ.1) THEN R=R0 ELSE R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) ENDIF NP=M+2*K-2+IP SUD=SUD+LG*R*DF(K)*DJ(NP) IF (K.GT.NM1.AND.DABS(SUD-SW).LT.DABS(SUD)*EPS) GO TO 65 60 SW=SUD 65 R1D=B0+A0*C*SUD RETURN END SUBROUTINE SCKB(M,N,C,DF,CK) C C ====================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions, c2k C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C DF(k) --- Expansion coefficients dk C Output: CK(k) --- Expansion coefficients ck; C CK(1), CK(2), ... correspond to C c0, c2, ... C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DF(200),CK(200) IF (C.LE.1.0D-10) C=1.0D-10 NM=25+INT(0.5*(N-M)+C) IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 REG=1.0D0 IF (M+NM.GT.80) REG=1.0D-200 FAC=-0.5D0**M DO 35 K=0,NM-1 FAC=-FAC I1=2*K+IP+1 R=REG DO 10 I=I1,I1+2*M-1 10 R=R*I I2=K+M+IP DO 15 I=I2,I2+K-1 15 R=R*(I+0.5D0) SUM=R*DF(K+1) DO 20 I=K+1,NM D1=2.0D0*I+IP D2=2.0D0*M+D1 D3=I+M+IP-0.5D0 R=R*D2*(D2-1.0D0)*I*(D3+K)/(D1*(D1-1.0D0)*(I-K)*D3) SUM=SUM+R*DF(I+1) IF (DABS(SW-SUM).LT.DABS(SUM)*1.0D-14) GOTO 25 20 SW=SUM 25 R1=REG DO 30 I=2,M+K 30 R1=R1*I 35 CK(K+1)=FAC*SUM/R1 RETURN END SUBROUTINE SPHJ(N,X,NM,SJ,DJ) C C ======================================================= C Purpose: Compute spherical Bessel functions jn(x) and C their derivatives C Input : x --- Argument of jn(x) C n --- Order of jn(x) ( n = 0,1,úúú ) C Output: SJ(n) --- jn(x) C DJ(n) --- jn'(x) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 for computing the starting C point for backward recurrence C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SJ(0:N),DJ(0:N) NM=N IF (DABS(X).EQ.1.0D-100) THEN DO 10 K=0,N SJ(K)=0.0D0 10 DJ(K)=0.0D0 SJ(0)=1.0D0 DJ(1)=.3333333333333333D0 RETURN ENDIF SJ(0)=DSIN(X)/X SJ(1)=(SJ(0)-DCOS(X))/X IF (N.GE.2) THEN SA=SJ(0) SB=SJ(1) M=MSTA1(X,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(X,N,15) ENDIF F0=0.0D0 F1=1.0D0-100 DO 15 K=M,0,-1 F=(2.0D0*K+3.0D0)*F1/X-F0 IF (K.LE.NM) SJ(K)=F F0=F1 15 F1=F IF (DABS(SA).GT.DABS(SB)) CS=SA/F IF (DABS(SA).LE.DABS(SB)) CS=SB/F0 DO 20 K=0,NM 20 SJ(K)=CS*SJ(K) ENDIF DJ(0)=(DCOS(X)-DSIN(X)/X)/X DO 25 K=1,NM 25 DJ(K)=SJ(K-1)-(K+1.0D0)*SJ(K)/X RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END SUBROUTINE RMN2L(M,N,C,X,DF,KD,R2F,R2D,ID) C C ======================================================== C Purpose: Compute prolate and oblate spheroidal radial C functions of the second kind for given m, n, C c and a large cx C Routine called: C SPHY for computing the spherical Bessel C functions of the second kind C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DF(200),SY(0:251),DY(0:251) EPS=1.0D-14 IP=1 NM1=INT((N-M)/2) IF (N-M.EQ.2*NM1) IP=0 NM=25+NM1+INT(C) REG=1.0D0 IF (M+NM.GT.80) REG=1.0D-200 NM2=2*NM+M CX=C*X CALL SPHY(NM2,CX,NM2,SY,DY) R0=REG DO 10 J=1,2*M+IP 10 R0=R0*J R=R0 SUC=R*DF(1) DO 15 K=2,NM R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) SUC=SUC+R*DF(K) IF (K.GT.NM1.AND.DABS(SUC-SW).LT.DABS(SUC)*EPS) GO TO 20 15 SW=SUC 20 A0=(1.0D0-KD/(X*X))**(0.5D0*M)/SUC R2F=0.0 DO 50 K=1,NM L=2*K+M-N-2+IP IF (L.EQ.4*INT(L/4)) LG=1 IF (L.NE.4*INT(L/4)) LG=-1 IF (K.EQ.1) THEN R=R0 ELSE R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) ENDIF NP=M+2*K-2+IP R2F=R2F+LG*R*(DF(K)*SY(NP)) EPS1=DABS(R2F-SW) IF (K.GT.NM1.AND.EPS1.LT.DABS(R2F)*EPS) GO TO 55 50 SW=R2F 55 ID1=INT(LOG10(EPS1/DABS(R2F)+EPS)) R2F=R2F*A0 IF (NP.GE.NM2) THEN ID=10 RETURN ENDIF B0=KD*M/X**3.0D0/(1.0-KD/(X*X))*R2F SUD=0.0D0 DO 60 K=1,NM L=2*K+M-N-2+IP IF (L.EQ.4*INT(L/4)) LG=1 IF (L.NE.4*INT(L/4)) LG=-1 IF (K.EQ.1) THEN R=R0 ELSE R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) ENDIF NP=M+2*K-2+IP SUD=SUD+LG*R*(DF(K)*DY(NP)) EPS2=DABS(SUD-SW) IF (K.GT.NM1.AND.EPS2.LT.DABS(SUD)*EPS) GO TO 65 60 SW=SUD 65 R2D=B0+A0*C*SUD ID2=INT(LOG10(EPS2/DABS(SUD)+EPS)) ID=MAX(ID1,ID2) RETURN END SUBROUTINE SPHY(N,X,NM,SY,DY) C C ====================================================== C Purpose: Compute spherical Bessel functions yn(x) and C their derivatives C Input : x --- Argument of yn(x) ( x ò 0 ) C n --- Order of yn(x) ( n = 0,1,úúú ) C Output: SY(n) --- yn(x) C DY(n) --- yn'(x) C NM --- Highest order computed C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SY(0:N),DY(0:N) NM=N IF (X.LT.1.0D-60) THEN DO 10 K=0,N SY(K)=-1.0D+300 10 DY(K)=1.0D+300 RETURN ENDIF SY(0)=-DCOS(X)/X SY(1)=(SY(0)-DSIN(X))/X F0=SY(0) F1=SY(1) DO 15 K=2,N F=(2.0D0*K-1.0D0)*F1/X-F0 SY(K)=F IF (DABS(F).GE.1.0D+300) GO TO 20 F0=F1 15 F1=F 20 NM=K-1 DY(0)=(DSIN(X)+DCOS(X)/X)/X DO 25 K=1,NM 25 DY(K)=SY(K-1)-(K+1.0D0)*SY(K)/X RETURN END SUBROUTINE RMN2SO(M,N,C,X,CV,DF,KD,R2F,R2D) C C ============================================================= C Purpose: Compute oblate radial functions of the second kind C with a small argument, Rmn(-ic,ix) & Rmn'(-ic,ix) C Routines called: C (1) SCKB for computing the expansion coefficients c2k C (2) KMN for computing the joining factors C (3) QSTAR for computing the factor defined in (15.7.3) C (4) CBK for computing the the expansion coefficient C defined in (15.7.6) C (5) GMN for computing the function defined in (15.7.4) C (6) RMN1 for computing the radial function of the first C kind C ============================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BK(200),CK(200),DF(200),DN(200) IF (DABS(DF(1)).LE.1.0D-280) THEN R2F=1.0D+300 R2D=1.0D+300 RETURN ENDIF EPS=1.0D-14 PI=3.141592653589793D0 NM=25+INT((N-M)/2+C) IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 CALL SCKB(M,N,C,DF,CK) CALL KMN(M,N,C,CV,KD,DF,DN,CK1,CK2) CALL QSTAR(M,N,C,CK,CK1,QS,QT) CALL CBK(M,N,C,CV,QT,CK,BK) IF (X.EQ.0.0D0) THEN SUM=0.0D0 DO 10 J=1,NM SUM=SUM+CK(J) IF (DABS(SUM-SW).LT.DABS(SUM)*EPS) GO TO 15 10 SW=SUM 15 IF (IP.EQ.0) THEN R1F=SUM/CK1 R2F=-0.5D0*PI*QS*R1F R2D=QS*R1F+BK(1) ELSE IF (IP.EQ.1) THEN R1D=SUM/CK1 R2F=BK(1) R2D=-0.5D0*PI*QS*R1D ENDIF RETURN ELSE CALL GMN(M,N,C,X,BK,GF,GD) CALL RMN1(M,N,C,X,DF,KD,R1F,R1D) H0=DATAN(X)-0.5D0*PI R2F=QS*R1F*H0+GF R2D=QS*(R1D*H0+R1F/(1.0D0+X*X))+GD ENDIF RETURN END SUBROUTINE QSTAR(M,N,C,CK,CK1,QS,QT) C C ========================================================= C Purpose: Compute Q*mn(-ic) for oblate radial functions C with a small argument C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION AP(200),CK(200) IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 R=1.0D0/CK(1)**2 AP(1)=R DO 20 I=1,M S=0.0D0 DO 15 L=1,I SK=0.0D0 DO 10 K=0,L 10 SK=SK+CK(K+1)*CK(L-K+1) 15 S=S+SK*AP(I-L+1) 20 AP(I+1)=-R*S QS0=AP(M+1) DO 30 L=1,M R=1.0D0 DO 25 K=1,L 25 R=R*(2.0D0*K+IP)*(2.0D0*K-1.0D0+IP)/(2.0D0*K)**2 30 QS0=QS0+AP(M-L+1)*R QS=(-1)**IP*CK1*(CK1*QS0)/C QT=-2.0D0/CK1*QS RETURN END SUBROUTINE CBK(M,N,C,CV,QT,CK,BK) C C ===================================================== C Purpose: Compute coefficient Bk's for oblate radial C functions with a small argument C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BK(200),CK(200),U(200),V(200),W(200) EPS=1.0D-14 IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 NM=25+INT(0.5*(N-M)+C) U(1)=0.0D0 N2=NM-2 DO 10 J=2,N2 10 U(J)=C*C DO 15 J=1,N2 15 V(J)=(2.0*J-1.0-IP)*(2.0*(J-M)-IP)+M*(M-1.0)-CV DO 20 J=1,NM-1 20 W(J)=(2.0*J-IP)*(2.0*J+1.0-IP) IF (IP.EQ.0) THEN DO 40 K=0,N2-1 S1=0.0D0 I1=K-M+1 DO 30 I=I1,NM IF (I.LT.0) GO TO 30 R1=1.0D0 DO 25 J=1,K 25 R1=R1*(I+M-J)/J S1=S1+CK(I+1)*(2.0*I+M)*R1 IF (DABS(S1-SW).LT.DABS(S1)*EPS) GO TO 35 SW=S1 30 CONTINUE 35 BK(K+1)=QT*S1 40 CONTINUE ELSE IF (IP.EQ.1) THEN DO 60 K=0,N2-1 S1=0.0D0 I1=K-M+1 DO 50 I=I1,NM IF (I.LT.0) GO TO 50 R1=1.0D0 DO 45 J=1,K 45 R1=R1*(I+M-J)/J IF (I.GT.0) S1=S1+CK(I)*(2.0*I+M-1)*R1 S1=S1-CK(I+1)*(2.0*I+M)*R1 IF (DABS(S1-SW).LT.DABS(S1)*EPS) GO TO 55 SW=S1 50 CONTINUE 55 BK(K+1)=QT*S1 60 CONTINUE ENDIF W(1)=W(1)/V(1) BK(1)=BK(1)/V(1) DO 65 K=2,N2 T=V(K)-W(K-1)*U(K) W(K)=W(K)/T 65 BK(K)=(BK(K)-BK(K-1)*U(K))/T DO 70 K=N2-1,1,-1 70 BK(K)=BK(K)-W(K)*BK(K+1) RETURN END SUBROUTINE GMN(M,N,C,X,BK,GF,GD) C C =========================================================== C Purpose: Compute gmn(-ic,ix) and its derivative for oblate C radial functions with a small argument C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION BK(200) EPS=1.0D-14 IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 NM=25+INT(0.5*(N-M)+C) XM=(1.0D0+X*X)**(-0.5D0*M) GF0=0.0D0 DO 10 K=1,NM GF0=GF0+BK(K)*X**(2.0*K-2.0) IF (DABS((GF0-GW)/GF0).LT.EPS.AND.K.GE.10) GO TO 15 10 GW=GF0 15 GF=XM*GF0*X**(1-IP) GD1=-M*X/(1.0D0+X*X)*GF GD0=0.0D0 DO 20 K=1,NM IF (IP.EQ.0) THEN GD0=GD0+(2.0D0*K-1.0)*BK(K)*X**(2.0*K-2.0) ELSE GD0=GD0+2.0D0*K*BK(K+1)*X**(2.0*K-1.0) ENDIF IF (DABS((GD0-GW)/GD0).LT.EPS.AND.K.GE.10) GO TO 25 20 GW=GD0 25 GD=GD1+XM*GD0 RETURN END SUBROUTINE KMN(M,N,C,CV,KD,DF,DN,CK1,CK2) C C =================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions C and joining factors C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION U(200),V(200),W(200),DF(200),DN(200), & TP(200),RK(200) NM=25+INT(0.5*(N-M)+C) NN=NM+M CS=C*C*KD IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 DO 10 I=1,NN+3 IF (IP.EQ.0) K=-2*(I-1) IF (IP.EQ.1) K=-(2*I-3) GK0=2.0D0*M+K GK1=(M+K)*(M+K+1.0D0) GK2=2.0D0*(M+K)-1.0D0 GK3=2.0D0*(M+K)+3.0D0 U(I)=GK0*(GK0-1.0D0)*CS/(GK2*(GK2+2.0D0)) V(I)=GK1-CV+(2.0D0*(GK1-M*M)-1.0D0)*CS/(GK2*GK3) 10 W(I)=(K+1.0D0)*(K+2.0D0)*CS/((GK2+2.0D0)*GK3) DO 20 K=1,M T=V(M+1) DO 15 L=0,M-K-1 15 T=V(M-L)-W(M-L+1)*U(M-L)/T 20 RK(K)=-U(K)/T R=1.0D0 DO 25 K=1,M R=R*RK(K) 25 DN(K)=DF(1)*R TP(NN)=V(NN+1) DO 30 K=NN-1,M+1,-1 TP(K)=V(K+1)-W(K+2)*U(K+1)/TP(K+1) IF (K.GT.M+1) RK(K)=-U(K)/TP(K) 30 CONTINUE IF (M.EQ.0) DNP=DF(1) IF (M.NE.0) DNP=DN(M) DN(M+1)=(-1)**IP*DNP*CS/((2.0*M-1.0)*(2.0*M+1.0-4.0*IP) & *TP(M+1)) DO 35 K=M+2,NN 35 DN(K)=RK(K)*DN(K-1) R1=1.0D0 DO 40 J=1,(N+M+IP)/2 40 R1=R1*(J+0.5D0*(N+M+IP)) NM1=(N-M)/2 R=1.0D0 DO 45 J=1,2*M+IP 45 R=R*J SU0=R*DF(1) DO 50 K=2,NM R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) SU0=SU0+R*DF(K) IF (K.GT.NM1.AND.DABS((SU0-SW)/SU0).LT.1.0D-14) GO TO 55 50 SW=SU0 55 IF (KD.EQ.1) GOTO 70 R2=1.0D0 DO 60 J=1,M 60 R2=2.0D0*C*R2*J R3=1.0D0 DO 65 J=1,(N-M-IP)/2 65 R3=R3*J SA0=(2.0*(M+IP)+1.0)*R1/(2.0**N*C**IP*R2*R3*DF(1)) CK1=SA0*SU0 IF (KD.EQ.-1) RETURN 70 R4=1.0D0 DO 75 J=1,(N-M-IP)/2 75 R4=4.0D0*R4*J R5=1.0D0 DO 80 J=1,M 80 R5=R5*(J+M)/C G0=DN(M) IF (M.EQ.0) G0=DF(1) SB0=(IP+1.0)*C**(IP+1)/(2.0*IP*(M-2.0)+1.0)/(2.0*M-1.0) CK2=(-1)**IP*SB0*R4*R5*G0/R1*SU0 RETURN END SUBROUTINE SEGV(M,N,C,KD,CV,EG) C C ========================================================= C Purpose: Compute the characteristic values of spheroidal C wave functions C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C KD --- Function code C KD=1 for Prolate; KD=-1 for Oblate C Output: CV --- Characteristic value for given m, n and c C EG(L) --- Characteristic value for mode m and n' C ( L = n' - m + 1 ) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION B(100),H(100),D(300),E(300),F(300),CV0(100), & A(300),G(300),EG(200) IF (C.LT.1.0D-10) THEN DO 5 I=1,N 5 EG(I)=(I+M)*(I+M-1.0D0) GO TO 70 ENDIF ICM=(N-M+2)/2 NM=10+INT(0.5*(N-M)+C) CS=C*C*KD DO 60 L=0,1 DO 10 I=1,NM IF (L.EQ.0) K=2*(I-1) IF (L.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1.0D0 DK2=2.0D0*(M+K) D2K=2.0D0*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS 10 G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS DO 15 K=2,NM E(K)=DSQRT(A(K-1)*G(K)) 15 F(K)=E(K)*E(K) F(1)=0.0D0 E(1)=0.0D0 XA=D(NM)+DABS(E(NM)) XB=D(NM)-DABS(E(NM)) NM1=NM-1 DO 20 I=1,NM1 T=DABS(E(I))+DABS(E(I+1)) T1=D(I)+T IF (XA.LT.T1) XA=T1 T1=D(I)-T IF (T1.LT.XB) XB=T1 20 CONTINUE DO 25 I=1,ICM B(I)=XA 25 H(I)=XB DO 55 K=1,ICM DO 30 K1=K,ICM IF (B(K1).LT.B(K)) THEN B(K)=B(K1) GO TO 35 ENDIF 30 CONTINUE 35 IF (K.NE.1.AND.H(K).LT.H(K-1)) H(K)=H(K-1) 40 X1=(B(K)+H(K))/2.0D0 CV0(K)=X1 IF (DABS((B(K)-H(K))/X1).LT.1.0D-14) GO TO 50 J=0 S=1.0D0 DO 45 I=1,NM IF (S.EQ.0.0D0) S=S+1.0D-30 T=F(I)/S S=D(I)-T-X1 IF (S.LT.0.0D0) J=J+1 45 CONTINUE IF (J.LT.K) THEN H(K)=X1 ELSE B(K)=X1 IF (J.GE.ICM) THEN B(ICM)=X1 ELSE IF (H(J+1).LT.X1) H(J+1)=X1 IF (X1.LT.B(J)) B(J)=X1 ENDIF ENDIF GO TO 40 50 CV0(K)=X1 IF (L.EQ.0) EG(2*K-1)=CV0(K) IF (L.EQ.1) EG(2*K)=CV0(K) 55 CONTINUE 60 CONTINUE 70 CV=EG(N-M+1) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mrswfp.for000077500000000000000000000707361321604176500261610ustar00rootroot00000000000000 PROGRAM MRSWFP C C ============================================================== C Purpose: This program computes the radial prolate spheriodal C functions of the first and second kinds, and their C derivatives using subroutine RSWFP C Input : m --- Mode parameter, m = 0,1,2,... C n --- Mode parameter, n = m,m+1,m+2,... C c --- Spheroidal parameter C cv --- Characteristic value C x --- Argument of radial function ( x > 1.0 ) C KF --- Function code C KF=1 for the first kind C KF=2 for the second kind C KF=3 for both the first and second kinds C Output: R1F --- Radial function of the first kind C R1D --- Derivative of the radial function of C the first kind C R2F --- Radial function of the second kind C R2D --- Derivative of the radial function of C the second kind C Example: C KD= 1, m = 2, n = 3, c = 5.0 and cv =19.1359819110 C C x R23(1)(c,x) R23(1)'(c,x) R23(2)(c,x) R23(2)'(c,x) C ------------------------------------------------------------------- C 1.(7).1 (-8) 1.6240735 1.6240735 ( 6)-3.0786785 (14) 3.0786784 C 1.005 (-3) 8.0600009 1.5998506 -6.2737713 ( 3) 1.2299041 C 1.1 (-1) 1.3578875 1.0702727 (-1)-4.3693218 3.5698419 C 1.5 (-1) 1.2002958 (-1)-8.0657929 (-1) 1.2623910 (-1) 4.8469847 C 5.0 (-2) 3.9455888 (-2) 4.2556949 (-2)-1.0099734 (-1) 2.0031280 C ============================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EG(200) WRITE(*,*)'Please enter: KF --- Kind choice code' WRITE(*,*)'KF = ?' READ(*,*)KF WRITE(*,10)KF WRITE(*,*)'Please enter m, n, c and x ( x > 1 )' READ(*,*)M,N,C,X CALL SEGV(M,N,C,1,CV,EG) WRITE(*,20)M,N,C,CV,X WRITE(*,*) CALL RSWFP(M,N,C,X,CV,KF,R1F,R1D,R2F,R2D) WRITE(*,*)' x Rmn(1)(c,x) Rmn''(1)(c,x) ', & 'Rmn(2)(c,x) Rmn''(2)(c,x)' WRITE(*,*)'-----------------------------------------------', & '---------------------------' IF (KF.EQ.1) THEN WRITE(*,30)X,R1F,R1D ELSE IF (KF.EQ.2) THEN WRITE(*,40)X,R2F,R2D ELSE IF (KF.EQ.3) THEN WRITE(*,30)X,R1F,R1D,R2F,R2D ENDIF IF (KF.EQ.3) THEN WRITE(*,50)R1F*R2D-R2F*R1D,1.0D0/(C*(X*X-1.0D0)) WRITE(*,60) ENDIF 10 FORMAT(1X,3HKF=,I3) 20 FORMAT(1X,2Hm=,I2,', ',2Hn=,I2,', ',2Hc=,F5.1, & ', ',4Hcv =,D20.12,', ',2Hx=,F5.2) 30 FORMAT(1X,F5.2,4D17.8) 40 FORMAT(1X,F5.2,34X,4D17.8) 50 FORMAT(1X,/1X,'Wronskian check:',/1X,'Computed value =', & D17.8,5X,'Exact value =',D17.8) 60 FORMAT(1X,/1X,'Caution: This check is not accurate if it ', & 'involves',/1X,' the subtraction of two ', & 'similar numbers') END SUBROUTINE RSWFP(M,N,C,X,CV,KF,R1F,R1D,R2F,R2D) C C ============================================================== C Purpose: Compute prolate spheriodal radial functions of the C first and second kinds, and their derivatives C Input : m --- Mode parameter, m = 0,1,2,... C n --- Mode parameter, n = m,m+1,m+2,... C c --- Spheroidal parameter C x --- Argument of radial function ( x > 1.0 ) C cv --- Characteristic value C KF --- Function code C KF=1 for the first kind C KF=2 for the second kind C KF=3 for both the first and second kinds C Output: R1F --- Radial function of the first kind C R1D --- Derivative of the radial function of C the first kind C R2F --- Radial function of the second kind C R2D --- Derivative of the radial function of C the second kind C Routines called: C (1) SDMN for computing expansion coefficients dk C (2) RMN1 for computing prolate and oblate radial C functions of the first kind C (3) RMN2L for computing prolate and oblate radial C functions of the second kind for a large argument C (4) RMN2SP for computing the prolate radial function C of the second kind for a small argument C ============================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DF(200) KD=1 CALL SDMN(M,N,C,CV,KD,DF) IF (KF.NE.2) THEN CALL RMN1(M,N,C,X,DF,KD,R1F,R1D) ENDIF IF (KF.GT.1) THEN CALL RMN2L(M,N,C,X,DF,KD,R2F,R2D,ID) IF (ID.GT.-8) THEN CALL RMN2SP(M,N,C,X,CV,DF,KD,R2F,R2D) ENDIF ENDIF RETURN END SUBROUTINE SDMN(M,N,C,CV,KD,DF) C C ===================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions, dk C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C cv --- Characteristic value C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C Output: DF(k) --- Expansion coefficients dk; C DF(1), DF(2), ... correspond to C d0, d2, ... for even n-m and d1, C d3, ... for odd n-m C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(200),D(200),G(200),DF(200) NM=25+INT(0.5*(N-M)+C) IF (C.LT.1.0D-10) THEN DO 5 I=1,NM 5 DF(I)=0D0 DF((N-M)/2+1)=1.0D0 RETURN ENDIF CS=C*C*KD IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 DO 10 I=1,NM+2 IF (IP.EQ.0) K=2*(I-1) IF (IP.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS 10 CONTINUE FS=1.0D0 F1=0.0D0 F0=1.0D-100 KB=0 DF(NM+1)=0.0D0 DO 30 K=NM,1,-1 F=-((D(K+1)-CV)*F0+A(K+1)*F1)/G(K+1) IF (DABS(F).GT.DABS(DF(K+1))) THEN DF(K)=F F1=F0 F0=F IF (DABS(F).GT.1.0D+100) THEN DO 12 K1=K,NM 12 DF(K1)=DF(K1)*1.0D-100 F1=F1*1.0D-100 F0=F0*1.0D-100 ENDIF ELSE KB=K FL=DF(K+1) F1=1.0D-100 F2=-(D(1)-CV)/A(1)*F1 DF(1)=F1 IF (KB.EQ.1) THEN FS=F2 ELSE IF (KB.EQ.2) THEN DF(2)=F2 FS=-((D(2)-CV)*F2+G(2)*F1)/A(2) ELSE DF(2)=F2 DO 20 J=3,KB+1 F=-((D(J-1)-CV)*F2+G(J-1)*F1)/A(J-1) IF (J.LE.KB) DF(J)=F IF (DABS(F).GT.1.0D+100) THEN DO 15 K1=1,J 15 DF(K1)=DF(K1)*1.0D-100 F=F*1.0D-100 F2=F2*1.0D-100 ENDIF F1=F2 20 F2=F FS=F ENDIF GO TO 35 ENDIF 30 CONTINUE 35 SU1=0.0D0 R1=1.0D0 DO 40 J=M+IP+1,2*(M+IP) 40 R1=R1*J SU1=DF(1)*R1 DO 45 K=2,KB R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) 45 SU1=SU1+R1*DF(K) SU2=0.0D0 DO 50 K=KB+1,NM IF (K.NE.1) R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) SU2=SU2+R1*DF(K) IF (DABS(SW-SU2).LT.DABS(SU2)*1.0D-14) GOTO 55 50 SW=SU2 55 R3=1.0D0 DO 60 J=1,(M+N+IP)/2 60 R3=R3*(J+0.5D0*(N+M+IP)) R4=1.0D0 DO 65 J=1,(N-M-IP)/2 65 R4=-4.0D0*R4*J S0=R3/(FL*(SU1/FS)+SU2)/R4 DO 70 K=1,KB 70 DF(K)=FL/FS*S0*DF(K) DO 75 K=KB+1,NM 75 DF(K)=S0*DF(K) RETURN END SUBROUTINE RMN1(M,N,C,X,DF,KD,R1F,R1D) C C ======================================================= C Purpose: Compute prolate and oblate spheroidal radial C functions of the first kind for given m, n, C c and x C Routines called: C (1) SCKB for computing expansion coefficients c2k C (2) SPHJ for computing the spherical Bessel C functions of the first kind C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION CK(200),DF(200),SJ(0:251),DJ(0:251) EPS=1.0D-14 IP=1 NM1=INT((N-M)/2) IF (N-M.EQ.2*NM1) IP=0 NM=25+NM1+INT(C) REG=1.0D0 IF (M+NM.GT.80) REG=1.0D-200 R0=REG DO 10 J=1,2*M+IP 10 R0=R0*J R=R0 SUC=R*DF(1) DO 15 K=2,NM R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) SUC=SUC+R*DF(K) IF (K.GT.NM1.AND.DABS(SUC-SW).LT.DABS(SUC)*EPS) GO TO 20 15 SW=SUC 20 CONTINUE IF (X.EQ.0.0) THEN CALL SCKB(M,N,C,DF,CK) SUM=0.0D0 DO 25 J=1,NM SUM=SUM+CK(J) IF (DABS(SUM-SW1).LT.DABS(SUM)*EPS) GO TO 30 25 SW1=SUM 30 R1=1.0D0 DO 35 J=1,(N+M+IP)/2 35 R1=R1*(J+0.5D0*(N+M+IP)) R2=1.0D0 DO 40 J=1,M 40 R2=2.0D0*C*R2*J R3=1.0D0 DO 45 J=1,(N-M-IP)/2 45 R3=R3*J SA0=(2.0*(M+IP)+1.0)*R1/(2.0**N*C**IP*R2*R3) IF (IP.EQ.0) THEN R1F=SUM/(SA0*SUC)*DF(1)*REG R1D=0.0D0 ELSE IF (IP.EQ.1) THEN R1F=0.0D0 R1D=SUM/(SA0*SUC)*DF(1)*REG ENDIF RETURN ENDIF CX=C*X NM2=2*NM+M CALL SPHJ(NM2,CX,NM2,SJ,DJ) A0=(1.0D0-KD/(X*X))**(0.5D0*M)/SUC R1F=0.0D0 DO 50 K=1,NM L=2*K+M-N-2+IP IF (L.EQ.4*INT(L/4)) LG=1 IF (L.NE.4*INT(L/4)) LG=-1 IF (K.EQ.1) THEN R=R0 ELSE R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) ENDIF NP=M+2*K-2+IP R1F=R1F+LG*R*DF(K)*SJ(NP) IF (K.GT.NM1.AND.DABS(R1F-SW).LT.DABS(R1F)*EPS) GO TO 55 50 SW=R1F 55 R1F=R1F*A0 B0=KD*M/X**3.0D0/(1.0-KD/(X*X))*R1F SUD=0.0D0 DO 60 K=1,NM L=2*K+M-N-2+IP IF (L.EQ.4*INT(L/4)) LG=1 IF (L.NE.4*INT(L/4)) LG=-1 IF (K.EQ.1) THEN R=R0 ELSE R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) ENDIF NP=M+2*K-2+IP SUD=SUD+LG*R*DF(K)*DJ(NP) IF (K.GT.NM1.AND.DABS(SUD-SW).LT.DABS(SUD)*EPS) GO TO 65 60 SW=SUD 65 R1D=B0+A0*C*SUD RETURN END SUBROUTINE SCKB(M,N,C,DF,CK) C C ====================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions, c2k C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C DF(k) --- Expansion coefficients dk C Output: CK(k) --- Expansion coefficients ck; C CK(1), CK(2), ... correspond to C c0, c2, ... C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DF(200),CK(200) IF (C.LE.1.0D-10) C=1.0D-10 NM=25+INT(0.5*(N-M)+C) IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 REG=1.0D0 IF (M+NM.GT.80) REG=1.0D-200 FAC=-0.5D0**M DO 35 K=0,NM-1 FAC=-FAC I1=2*K+IP+1 R=REG DO 10 I=I1,I1+2*M-1 10 R=R*I I2=K+M+IP DO 15 I=I2,I2+K-1 15 R=R*(I+0.5D0) SUM=R*DF(K+1) DO 20 I=K+1,NM D1=2.0D0*I+IP D2=2.0D0*M+D1 D3=I+M+IP-0.5D0 R=R*D2*(D2-1.0D0)*I*(D3+K)/(D1*(D1-1.0D0)*(I-K)*D3) SUM=SUM+R*DF(I+1) IF (DABS(SW-SUM).LT.DABS(SUM)*1.0D-14) GOTO 25 20 SW=SUM 25 R1=REG DO 30 I=2,M+K 30 R1=R1*I 35 CK(K+1)=FAC*SUM/R1 RETURN END SUBROUTINE SPHJ(N,X,NM,SJ,DJ) C C ======================================================= C Purpose: Compute spherical Bessel functions jn(x) and C their derivatives C Input : x --- Argument of jn(x) C n --- Order of jn(x) ( n = 0,1,úúú ) C Output: SJ(n) --- jn(x) C DJ(n) --- jn'(x) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 for computing the starting C point for backward recurrence C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SJ(0:N),DJ(0:N) NM=N IF (DABS(X).EQ.1.0D-100) THEN DO 10 K=0,N SJ(K)=0.0D0 10 DJ(K)=0.0D0 SJ(0)=1.0D0 DJ(1)=.3333333333333333D0 RETURN ENDIF SJ(0)=DSIN(X)/X SJ(1)=(SJ(0)-DCOS(X))/X IF (N.GE.2) THEN SA=SJ(0) SB=SJ(1) M=MSTA1(X,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(X,N,15) ENDIF F0=0.0D0 F1=1.0D0-100 DO 15 K=M,0,-1 F=(2.0D0*K+3.0D0)*F1/X-F0 IF (K.LE.NM) SJ(K)=F F0=F1 15 F1=F IF (DABS(SA).GT.DABS(SB)) CS=SA/F IF (DABS(SA).LE.DABS(SB)) CS=SB/F0 DO 20 K=0,NM 20 SJ(K)=CS*SJ(K) ENDIF DJ(0)=(DCOS(X)-DSIN(X)/X)/X DO 25 K=1,NM 25 DJ(K)=SJ(K-1)-(K+1.0D0)*SJ(K)/X RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END SUBROUTINE RMN2L(M,N,C,X,DF,KD,R2F,R2D,ID) C C ======================================================== C Purpose: Compute prolate and oblate spheroidal radial C functions of the second kind for given m, n, C c and a large cx C Routine called: C SPHY for computing the spherical Bessel C functions of the second kind C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DF(200),SY(0:251),DY(0:251) EPS=1.0D-14 IP=1 NM1=INT((N-M)/2) IF (N-M.EQ.2*NM1) IP=0 NM=25+NM1+INT(C) REG=1.0D0 IF (M+NM.GT.80) REG=1.0D-200 NM2=2*NM+M CX=C*X CALL SPHY(NM2,CX,NM2,SY,DY) R0=REG DO 10 J=1,2*M+IP 10 R0=R0*J R=R0 SUC=R*DF(1) DO 15 K=2,NM R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) SUC=SUC+R*DF(K) IF (K.GT.NM1.AND.DABS(SUC-SW).LT.DABS(SUC)*EPS) GO TO 20 15 SW=SUC 20 A0=(1.0D0-KD/(X*X))**(0.5D0*M)/SUC R2F=0.0 DO 50 K=1,NM L=2*K+M-N-2+IP IF (L.EQ.4*INT(L/4)) LG=1 IF (L.NE.4*INT(L/4)) LG=-1 IF (K.EQ.1) THEN R=R0 ELSE R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) ENDIF NP=M+2*K-2+IP R2F=R2F+LG*R*(DF(K)*SY(NP)) EPS1=DABS(R2F-SW) IF (K.GT.NM1.AND.EPS1.LT.DABS(R2F)*EPS) GO TO 55 50 SW=R2F 55 ID1=INT(LOG10(EPS1/DABS(R2F)+EPS)) R2F=R2F*A0 IF (NP.GE.NM2) THEN ID=10 RETURN ENDIF B0=KD*M/X**3.0D0/(1.0-KD/(X*X))*R2F SUD=0.0D0 DO 60 K=1,NM L=2*K+M-N-2+IP IF (L.EQ.4*INT(L/4)) LG=1 IF (L.NE.4*INT(L/4)) LG=-1 IF (K.EQ.1) THEN R=R0 ELSE R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) ENDIF NP=M+2*K-2+IP SUD=SUD+LG*R*(DF(K)*DY(NP)) EPS2=DABS(SUD-SW) IF (K.GT.NM1.AND.EPS2.LT.DABS(SUD)*EPS) GO TO 65 60 SW=SUD 65 R2D=B0+A0*C*SUD ID2=INT(LOG10(EPS2/DABS(SUD)+EPS)) ID=MAX(ID1,ID2) RETURN END SUBROUTINE SPHY(N,X,NM,SY,DY) C C ====================================================== C Purpose: Compute spherical Bessel functions yn(x) and C their derivatives C Input : x --- Argument of yn(x) ( x ò 0 ) C n --- Order of yn(x) ( n = 0,1,úúú ) C Output: SY(n) --- yn(x) C DY(n) --- yn'(x) C NM --- Highest order computed C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SY(0:N),DY(0:N) NM=N IF (X.LT.1.0D-60) THEN DO 10 K=0,N SY(K)=-1.0D+300 10 DY(K)=1.0D+300 RETURN ENDIF SY(0)=-DCOS(X)/X SY(1)=(SY(0)-DSIN(X))/X F0=SY(0) F1=SY(1) DO 15 K=2,N F=(2.0D0*K-1.0D0)*F1/X-F0 SY(K)=F IF (DABS(F).GE.1.0D+300) GO TO 20 F0=F1 15 F1=F 20 NM=K-1 DY(0)=(DSIN(X)+DCOS(X)/X)/X DO 25 K=1,NM 25 DY(K)=SY(K-1)-(K+1.0D0)*SY(K)/X RETURN END SUBROUTINE RMN2SP(M,N,C,X,CV,DF,KD,R2F,R2D) C C ====================================================== C Purpose: Compute prolate spheroidal radial function C of the second kind with a small argument C Routines called: C (1) LPMNS for computing the associated Legendre C functions of the first kind C (2) LQMNS for computing the associated Legendre C functions of the second kind C (3) KMN for computing expansion coefficients C and joining factors C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION PM(0:251),PD(0:251),QM(0:251),QD(0:251), & DN(200),DF(200) IF (DABS(DF(1)).LT.1.0D-280) THEN R2F=1.0D+300 R2D=1.0D+300 RETURN ENDIF EPS=1.0D-14 IP=1 NM1=INT((N-M)/2) IF (N-M.EQ.2*NM1) IP=0 NM=25+NM1+INT(C) NM2=2*NM+M CALL KMN(M,N,C,CV,KD,DF,DN,CK1,CK2) CALL LPMNS(M,NM2,X,PM,PD) CALL LQMNS(M,NM2,X,QM,QD) SU0=0.0D0 DO 10 K=1,NM J=2*K-2+M+IP SU0=SU0+DF(K)*QM(J) IF (K.GT.NM1.AND.DABS(SU0-SW).LT.DABS(SU0)*EPS) GO TO 15 10 SW=SU0 15 SD0=0.0D0 DO 20 K=1,NM J=2*K-2+M+IP SD0=SD0+DF(K)*QD(J) IF (K.GT.NM1.AND.DABS(SD0-SW).LT.DABS(SD0)*EPS) GO TO 25 20 SW=SD0 25 SU1=0.0D0 SD1=0.0D0 DO 30 K=1,M J=M-2*K+IP IF (J.LT.0) J=-J-1 SU1=SU1+DN(K)*QM(J) 30 SD1=SD1+DN(K)*QD(J) GA=((X-1.0D0)/(X+1.0D0))**(0.5D0*M) DO 55 K=1,M J=M-2*K+IP IF (J.GE.0) GO TO 55 IF (J.LT.0) J=-J-1 R1=1.0D0 DO 35 J1=1,J 35 R1=(M+J1)*R1 R2=1.0D0 DO 40 J2=1,M-J-2 40 R2=J2*R2 R3=1.0D0 SF=1.0D0 DO 45 L1=1,J R3=0.5D0*R3*(-J+L1-1.0)*(J+L1)/((M+L1)*L1)*(1.0-X) 45 SF=SF+R3 IF (M-J.GE.2) GB=(M-J-1.0D0)*R2 IF (M-J.LE.1) GB=1.0D0 SPL=R1*GA*GB*SF SU1=SU1+(-1)**(J+M)*DN(K)*SPL SPD1=M/(X*X-1.0D0)*SPL GC=0.5D0*J*(J+1.0)/(M+1.0) SD=1.0D0 R4=1.0D0 DO 50 L1=1,J-1 R4=0.5D0*R4*(-J+L1)*(J+L1+1.0)/((M+L1+1.0)*L1) & *(1.0-X) 50 SD=SD+R4 SPD2=R1*GA*GB*GC*SD SD1=SD1+(-1)**(J+M)*DN(K)*(SPD1+SPD2) 55 CONTINUE SU2=0.0D0 KI=(2*M+1+IP)/2 NM3=NM+KI DO 60 K=KI,NM3 J=2*K-1-M-IP SU2=SU2+DN(K)*PM(J) IF (J.GT.M.AND.DABS(SU2-SW).LT.DABS(SU2)*EPS) GO TO 65 60 SW=SU2 65 SD2=0.0D0 DO 70 K=KI,NM3 J=2*K-1-M-IP SD2=SD2+DN(K)*PD(J) IF (J.GT.M.AND.DABS(SD2-SW).LT.DABS(SD2)*EPS) GO TO 75 70 SW=SD2 75 SUM=SU0+SU1+SU2 SDM=SD0+SD1+SD2 R2F=SUM/CK2 R2D=SDM/CK2 RETURN END SUBROUTINE LPMNS(M,N,X,PM,PD) C C ======================================================== C Purpose: Compute associated Legendre functions Pmn(x) C and Pmn'(x) for a given order C Input : x --- Argument of Pmn(x) C m --- Order of Pmn(x), m = 0,1,2,...,n C n --- Degree of Pmn(x), n = 0,1,2,...,N C Output: PM(n) --- Pmn(x) C PD(n) --- Pmn'(x) C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION PM(0:N),PD(0:N) DO 10 K=0,N PM(K)=0.0D0 10 PD(K)=0.0D0 IF (DABS(X).EQ.1.0D0) THEN DO 15 K=0,N IF (M.EQ.0) THEN PM(K)=1.0D0 PD(K)=0.5D0*K*(K+1.0) IF (X.LT.0.0) THEN PM(K)=(-1)**K*PM(K) PD(K)=(-1)**(K+1)*PD(K) ENDIF ELSE IF (M.EQ.1) THEN PD(K)=1.0D+300 ELSE IF (M.EQ.2) THEN PD(K)=-0.25D0*(K+2.0)*(K+1.0)*K*(K-1.0) IF (X.LT.0.0) PD(K)=(-1)**(K+1)*PD(K) ENDIF 15 CONTINUE RETURN ENDIF X0=DABS(1.0D0-X*X) PM0=1.0D0 PMK=PM0 DO 20 K=1,M PMK=(2.0D0*K-1.0D0)*DSQRT(X0)*PM0 20 PM0=PMK PM1=(2.0D0*M+1.0D0)*X*PM0 PM(M)=PMK PM(M+1)=PM1 DO 25 K=M+2,N PM2=((2.0D0*K-1.0D0)*X*PM1-(K+M-1.0D0)*PMK)/(K-M) PM(K)=PM2 PMK=PM1 25 PM1=PM2 PD(0)=((1.0D0-M)*PM(1)-X*PM(0))/(X*X-1.0) DO 30 K=1,N 30 PD(K)=(K*X*PM(K)-(K+M)*PM(K-1))/(X*X-1.0D0) RETURN END SUBROUTINE LQMNS(M,N,X,QM,QD) C C ======================================================== C Purpose: Compute associated Legendre functions Qmn(x) C and Qmn'(x) for a given order C Input : x --- Argument of Qmn(x) C m --- Order of Qmn(x), m = 0,1,2,... C n --- Degree of Qmn(x), n = 0,1,2,... C Output: QM(n) --- Qmn(x) C QD(n) --- Qmn'(x) C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION QM(0:N),QD(0:N) DO 10 K=0,N QM(K)=0.0D0 10 QD(K)=0.0D0 IF (DABS(X).EQ.1.0D0) THEN DO 15 K=0,N QM(K)=1.0D+300 15 QD(K)=1.0D+300 RETURN ENDIF LS=1 IF (DABS(X).GT.1.0D0) LS=-1 XQ=DSQRT(LS*(1.0D0-X*X)) Q0=0.5D0*DLOG(DABS((X+1.0)/(X-1.0))) Q00=Q0 Q10=-1.0D0/XQ Q01=X*Q0-1.0D0 Q11=-LS*XQ*(Q0+X/(1.0D0-X*X)) QF0=Q00 QF1=Q10 DO 20 K=2,M QM0=-2.0D0*(K-1.0)/XQ*X*QF1-LS*(K-1.0)*(2.0-K)*QF0 QF0=QF1 20 QF1=QM0 IF (M.EQ.0) QM0=Q00 IF (M.EQ.1) QM0=Q10 QM(0)=QM0 IF (DABS(X).LT.1.0001D0) THEN IF (M.EQ.0.AND.N.GT.0) THEN QF0=Q00 QF1=Q01 DO 25 K=2,N QF2=((2.0*K-1.0D0)*X*QF1-(K-1.0)*QF0)/K QM(K)=QF2 QF0=QF1 25 QF1=QF2 ENDIF QG0=Q01 QG1=Q11 DO 30 K=2,M QM1=-2.0D0*(K-1.0)/XQ*X*QG1-LS*K*(3.0-K)*QG0 QG0=QG1 30 QG1=QM1 IF (M.EQ.0) QM1=Q01 IF (M.EQ.1) QM1=Q11 QM(1)=QM1 IF (M.EQ.1.AND.N.GT.1) THEN QH0=Q10 QH1=Q11 DO 35 K=2,N QH2=((2.0*K-1.0D0)*X*QH1-K*QH0)/(K-1.0) QM(K)=QH2 QH0=QH1 35 QH1=QH2 ELSE IF (M.GE.2) THEN QG0=Q00 QG1=Q01 QH0=Q10 QH1=Q11 DO 45 L=2,N Q0L=((2.0D0*L-1.0D0)*X*QG1-(L-1.0D0)*QG0)/L Q1L=((2.0*L-1.0D0)*X*QH1-L*QH0)/(L-1.0D0) QF0=Q0L QF1=Q1L DO 40 K=2,M QMK=-2.0D0*(K-1.0)/XQ*X*QF1-LS*(K+L-1.0)* & (L+2.0-K)*QF0 QF0=QF1 40 QF1=QMK QM(L)=QMK QG0=QG1 QG1=Q0L QH0=QH1 45 QH1=Q1L ENDIF ELSE IF (DABS(X).GT.1.1) THEN KM=40+M+N ELSE KM=(40+M+N)*INT(-1.0-1.8*LOG(X-1.0)) ENDIF QF2=0.0D0 QF1=1.0D0 DO 50 K=KM,0,-1 QF0=((2.0*K+3.0D0)*X*QF1-(K+2.0-M)*QF2)/(K+M+1.0) IF (K.LE.N) QM(K)=QF0 QF2=QF1 50 QF1=QF0 DO 55 K=0,N 55 QM(K)=QM(K)*QM0/QF0 ENDIF IF (DABS(X).LT.1.0D0) THEN DO 60 K=0,N 60 QM(K)=(-1)**M*QM(K) ENDIF QD(0)=((1.0D0-M)*QM(1)-X*QM(0))/(X*X-1.0) DO 65 K=1,N 65 QD(K)=(K*X*QM(K)-(K+M)*QM(K-1))/(X*X-1.0) RETURN END SUBROUTINE KMN(M,N,C,CV,KD,DF,DN,CK1,CK2) C C =================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions C and joining factors C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION U(200),V(200),W(200),DF(200),DN(200), & TP(200),RK(200) NM=25+INT(0.5*(N-M)+C) NN=NM+M CS=C*C*KD IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 DO 10 I=1,NN+3 IF (IP.EQ.0) K=-2*(I-1) IF (IP.EQ.1) K=-(2*I-3) GK0=2.0D0*M+K GK1=(M+K)*(M+K+1.0D0) GK2=2.0D0*(M+K)-1.0D0 GK3=2.0D0*(M+K)+3.0D0 U(I)=GK0*(GK0-1.0D0)*CS/(GK2*(GK2+2.0D0)) V(I)=GK1-CV+(2.0D0*(GK1-M*M)-1.0D0)*CS/(GK2*GK3) 10 W(I)=(K+1.0D0)*(K+2.0D0)*CS/((GK2+2.0D0)*GK3) DO 20 K=1,M T=V(M+1) DO 15 L=0,M-K-1 15 T=V(M-L)-W(M-L+1)*U(M-L)/T 20 RK(K)=-U(K)/T R=1.0D0 DO 25 K=1,M R=R*RK(K) 25 DN(K)=DF(1)*R TP(NN)=V(NN+1) DO 30 K=NN-1,M+1,-1 TP(K)=V(K+1)-W(K+2)*U(K+1)/TP(K+1) IF (K.GT.M+1) RK(K)=-U(K)/TP(K) 30 CONTINUE IF (M.EQ.0) DNP=DF(1) IF (M.NE.0) DNP=DN(M) DN(M+1)=(-1)**IP*DNP*CS/((2.0*M-1.0)*(2.0*M+1.0-4.0*IP) & *TP(M+1)) DO 35 K=M+2,NN 35 DN(K)=RK(K)*DN(K-1) R1=1.0D0 DO 40 J=1,(N+M+IP)/2 40 R1=R1*(J+0.5D0*(N+M+IP)) NM1=(N-M)/2 R=1.0D0 DO 45 J=1,2*M+IP 45 R=R*J SU0=R*DF(1) DO 50 K=2,NM R=R*(M+K-1.0)*(M+K+IP-1.5D0)/(K-1.0D0)/(K+IP-1.5D0) SU0=SU0+R*DF(K) IF (K.GT.NM1.AND.DABS((SU0-SW)/SU0).LT.1.0D-14) GO TO 55 50 SW=SU0 55 IF (KD.EQ.1) GOTO 70 R2=1.0D0 DO 60 J=1,M 60 R2=2.0D0*C*R2*J R3=1.0D0 DO 65 J=1,(N-M-IP)/2 65 R3=R3*J SA0=(2.0*(M+IP)+1.0)*R1/(2.0**N*C**IP*R2*R3*DF(1)) CK1=SA0*SU0 IF (KD.EQ.-1) RETURN 70 R4=1.0D0 DO 75 J=1,(N-M-IP)/2 75 R4=4.0D0*R4*J R5=1.0D0 DO 80 J=1,M 80 R5=R5*(J+M)/C G0=DN(M) IF (M.EQ.0) G0=DF(1) SB0=(IP+1.0)*C**(IP+1)/(2.0*IP*(M-2.0)+1.0)/(2.0*M-1.0) CK2=(-1)**IP*SB0*R4*R5*G0/R1*SU0 RETURN END SUBROUTINE SEGV(M,N,C,KD,CV,EG) C C ========================================================= C Purpose: Compute the characteristic values of spheroidal C wave functions C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C KD --- Function code C KD=1 for Prolate; KD=-1 for Oblate C Output: CV --- Characteristic value for given m, n and c C EG(L) --- Characteristic value for mode m and n' C ( L = n' - m + 1 ) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION B(100),H(100),D(300),E(300),F(300),CV0(100), & A(300),G(300),EG(200) IF (C.LT.1.0D-10) THEN DO 5 I=1,N 5 EG(I)=(I+M)*(I+M-1.0D0) GO TO 70 ENDIF ICM=(N-M+2)/2 NM=10+INT(0.5*(N-M)+C) CS=C*C*KD DO 60 L=0,1 DO 10 I=1,NM IF (L.EQ.0) K=2*(I-1) IF (L.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS 10 G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS DO 15 K=2,NM E(K)=DSQRT(A(K-1)*G(K)) 15 F(K)=E(K)*E(K) F(1)=0.0D0 E(1)=0.0D0 XA=D(NM)+DABS(E(NM)) XB=D(NM)-DABS(E(NM)) NM1=NM-1 DO 20 I=1,NM1 T=DABS(E(I))+DABS(E(I+1)) T1=D(I)+T IF (XA.LT.T1) XA=T1 T1=D(I)-T IF (T1.LT.XB) XB=T1 20 CONTINUE DO 25 I=1,ICM B(I)=XA 25 H(I)=XB DO 55 K=1,ICM DO 30 K1=K,ICM IF (B(K1).LT.B(K)) THEN B(K)=B(K1) GO TO 35 ENDIF 30 CONTINUE 35 IF (K.NE.1.AND.H(K).LT.H(K-1)) H(K)=H(K-1) 40 X1=(B(K)+H(K))/2.0D0 CV0(K)=X1 IF (DABS((B(K)-H(K))/X1).LT.1.0D-14) GO TO 50 J=0 S=1.0D0 DO 45 I=1,NM IF (S.EQ.0.0D0) S=S+1.0D-30 T=F(I)/S S=D(I)-T-X1 IF (S.LT.0.0D0) J=J+1 45 CONTINUE IF (J.LT.K) THEN H(K)=X1 ELSE B(K)=X1 IF (J.GE.ICM) THEN B(ICM)=X1 ELSE IF (H(J+1).LT.X1) H(J+1)=X1 IF (X1.LT.B(J)) B(J)=X1 ENDIF ENDIF GO TO 40 50 CV0(K)=X1 IF (L.EQ.0) EG(2*K-1)=CV0(K) IF (L.EQ.1) EG(2*K)=CV0(K) 55 CONTINUE 60 CONTINUE 70 CV=EG(N-M+1) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mscka.for000077500000000000000000000164101321604176500257260ustar00rootroot00000000000000 PROGRAM MSCKA C C ============================================================ C Purpose: This program computes the expansion coefficients C of the prolate and oblate spheroidal functions, C c2k, using subroutine SCKA C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C cv --- Characteristic value C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C Output: CK(k) --- Expansion coefficients ck; C CK(1), CK(2),... correspond to C c0, c2,... C Example: Compute the first 13 expansion coefficients C2k for C KD= 1, m=2, n=3, c=3.0 and cv=14.8277782138; and C KD=-1, m=2, n=3, c=3.0 and cv=8.80939392077 C C Coefficients of Prolate and oblate functions C C k C2k(c) C2k(-ic) C --------------------------------------------- C 0 .9173213327D+01 .2489664942D+02 C 1 .4718258929D+01 -.1205287032D+02 C 2 .9841212916D+00 .2410564082D+01 C 3 .1151870224D+00 -.2735821590D+00 C 4 .8733916403D-02 .2026057157D-01 C 5 .4663888254D-03 -.1061946315D-02 C 6 .1853910398D-04 .4158091152D-04 C 7 .5708084895D-06 -.1264400411D-05 C 8 .1402786472D-07 .3074963448D-07 C 9 .2817194508D-09 -.6120579463D-09 C 10 .4712094447D-11 .1015900041D-10 C 11 .6667838485D-13 -.1427953361D-12 C 12 .8087995432D-15 .1721924955D-14 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION CK(200),EG(200) WRITE(*,*)'Please KD, m, n and c ' READ(*,*)KD,M,N,C CALL SEGV(M,N,C,KD,CV,EG) WRITE(*,30)KD,M,N,C,CV CALL SCKA(M,N,C,CV,KD,CK) WRITE(*,*) IF (KD.EQ.1) THEN WRITE(*,*)'Coefficients of Prolate function' WRITE(*,*) WRITE(*,*)' k C2k(c)' ELSE WRITE(*,*)'Coefficients of Oblate function' WRITE(*,*) WRITE(*,*)' k C2k(-ic)' ENDIF WRITE(*,*)'----------------------------' NM=25+INT((N-M)/2+C) DO 10 K=1,NM 10 WRITE(*,20)K-1,CK(K) 20 FORMAT(2X,I3,4X,D18.10) 30 FORMAT(1X,3HKD=,I3,', ',2Hm=,I3,', ',2Hn=,I3,', ',2Hc=, & F5.1,', ',4Hcv =,F18.10) END SUBROUTINE SCKA(M,N,C,CV,KD,CK) C C ====================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions, c2k C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C cv --- Characteristic value C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C Output: CK(k) --- Expansion coefficients ck; C CK(1), CK(2),... correspond to C c0, c2,... C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION CK(200) IF (C.LE.1.0D-10) C=1.0D-10 NM=25+INT((N-M)/2+C) CS=C*C*KD IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 FS=1.0D0 F1=0.0D0 F0=1.0D-100 KB=0 CK(NM+1)=0.0D0 DO 15 K=NM,1,-1 F=(((2.0D0*K+M+IP)*(2.0D0*K+M+1.0D0+IP)-CV+CS)*F0 & -4.0D0*(K+1.0D0)*(K+M+1.0D0)*F1)/CS IF (DABS(F).GT.DABS(CK(K+1))) THEN CK(K)=F F1=F0 F0=F IF (DABS(F).GT.1.0D+100) THEN DO 5 K1=NM,K,-1 5 CK(K1)=CK(K1)*1.0D-100 F1=F1*1.0D-100 F0=F0*1.0D-100 ENDIF ELSE KB=K FL=CK(K+1) F1=1.0D0 F2=0.25D0*((M+IP)*(M+IP+1.0)-CV+CS)/(M+1.0)*F1 CK(1)=F1 IF (KB.EQ.1) THEN FS=F2 ELSE IF (KB.EQ.2) THEN CK(2)=F2 FS=0.125D0*(((M+IP+2.0)*(M+IP+3.0)-CV+CS)*F2 & -CS*F1)/(M+2.0) ELSE CK(2)=F2 DO 10 J=3,KB+1 F=0.25D0*(((2.0*J+M+IP-4.0)*(2.0*J+M+IP- & 3.0)-CV+CS)*F2-CS*F1)/((J-1.0)*(J+M-1.0)) IF (J.LE.KB) CK(J)=F F1=F2 10 F2=F FS=F ENDIF GO TO 20 ENDIF 15 CONTINUE 20 SU1=0.0D0 DO 25 K=1,KB 25 SU1=SU1+CK(K) SU2=0.0D0 DO 30 K=KB+1,NM 30 SU2=SU2+CK(K) R1=1.0D0 DO 35 J=1,(N+M+IP)/2 35 R1=R1*(J+0.5D0*(N+M+IP)) R2=1.0D0 DO 40 J=1,(N-M-IP)/2 40 R2=-R2*J IF (KB.EQ.0) THEN S0=R1/(2.0D0**N*R2*SU2) ELSE S0=R1/(2.0D0**N*R2*(FL/FS*SU1+SU2)) ENDIF DO 45 K=1,KB 45 CK(K)=FL/FS*S0*CK(K) DO 50 K=KB+1,NM 50 CK(K)=S0*CK(K) RETURN END SUBROUTINE SEGV(M,N,C,KD,CV,EG) C C ========================================================= C Purpose: Compute the characteristic values of spheroidal C wave functions C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C KD --- Function code C KD=1 for Prolate; KD=-1 for Oblate C Output: CV --- Characteristic value for given m, n and c C EG(L) --- Characteristic value for mode m and n' C ( L = n' - m + 1 ) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION B(100),H(100),D(300),E(300),F(300),CV0(100), & A(300),G(300),EG(200) IF (C.LT.1.0D-10) THEN DO 5 I=1,N 5 EG(I)=(I+M)*(I+M-1.0D0) GO TO 70 ENDIF ICM=(N-M+2)/2 NM=10+INT(0.5*(N-M)+C) CS=C*C*KD DO 60 L=0,1 DO 10 I=1,NM IF (L.EQ.0) K=2*(I-1) IF (L.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS 10 G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS DO 15 K=2,NM E(K)=DSQRT(A(K-1)*G(K)) 15 F(K)=E(K)*E(K) F(1)=0.0D0 E(1)=0.0D0 XA=D(NM)+DABS(E(NM)) XB=D(NM)-DABS(E(NM)) NM1=NM-1 DO 20 I=1,NM1 T=DABS(E(I))+DABS(E(I+1)) T1=D(I)+T IF (XA.LT.T1) XA=T1 T1=D(I)-T IF (T1.LT.XB) XB=T1 20 CONTINUE DO 25 I=1,ICM B(I)=XA 25 H(I)=XB DO 55 K=1,ICM DO 30 K1=K,ICM IF (B(K1).LT.B(K)) THEN B(K)=B(K1) GO TO 35 ENDIF 30 CONTINUE 35 IF (K.NE.1.AND.H(K).LT.H(K-1)) H(K)=H(K-1) 40 X1=(B(K)+H(K))/2.0D0 CV0(K)=X1 IF (DABS((B(K)-H(K))/X1).LT.1.0D-14) GO TO 50 J=0 S=1.0D0 DO 45 I=1,NM IF (S.EQ.0.0D0) S=S+1.0D-30 T=F(I)/S S=D(I)-T-X1 IF (S.LT.0.0D0) J=J+1 45 CONTINUE IF (J.LT.K) THEN H(K)=X1 ELSE B(K)=X1 IF (J.GE.ICM) THEN B(ICM)=X1 ELSE IF (H(J+1).LT.X1) H(J+1)=X1 IF (X1.LT.B(J)) B(J)=X1 ENDIF ENDIF GO TO 40 50 CV0(K)=X1 IF (L.EQ.0) EG(2*K-1)=CV0(K) IF (L.EQ.1) EG(2*K)=CV0(K) 55 CONTINUE 60 CONTINUE 70 CV=EG(N-M+1) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/msckb.for000077500000000000000000000223431321604176500257310ustar00rootroot00000000000000 PROGRAM MSCKB C C ============================================================ C Purpose: This program computes the expansion coefficients C of the prolate and oblate spheroidal functions, C c2k, using subroutine SCKB C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C cv --- Characteristic value C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C Output: CK(k) --- Expansion coefficients ck; C CK(1), CK(2), ... correspond to C c0, c2, ... C Example: Compute the first 13 expansion coefficients C2k for C KD= 1, m=2, n=3, c=3.0 and cv=14.8277782138; and C KD=-1, m=2, n=3, c=3.0 and cv=8.80939392077 C C Coefficients of Prolate and oblate functions C C k C2k(c) C2k(-ic) C --------------------------------------------- C 0 .9173213327D+01 .2489664942D+02 C 1 .4718258929D+01 -.1205287032D+02 C 2 .9841212916D+00 .2410564082D+01 C 3 .1151870224D+00 -.2735821590D+00 C 4 .8733916403D-02 .2026057157D-01 C 5 .4663888254D-03 -.1061946315D-02 C 6 .1853910398D-04 .4158091152D-04 C 7 .5708084895D-06 -.1264400411D-05 C 8 .1402786472D-07 .3074963448D-07 C 9 .2817194508D-09 -.6120579463D-09 C 10 .4712094447D-11 .1015900041D-10 C 11 .6667838485D-13 -.1427953361D-12 C 12 .8087995432D-15 .1721924955D-14 C ============================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION CK(200),DF(200),EG(200) WRITE(*,*)'Please KD, m, n and c ' READ(*,*)KD,M,N,C CALL SEGV(M,N,C,KD,CV,EG) WRITE(*,30)KD,M,N,C,CV CALL SDMN(M,N,C,CV,KD,DF) CALL SCKB(M,N,C,DF,CK) WRITE(*,*) IF (KD.EQ.1) THEN WRITE(*,*)'Coefficients of Prolate function' WRITE(*,*) WRITE(*,*)' k C2k(c)' ELSE WRITE(*,*)'Coefficients of Oblate function' WRITE(*,*) WRITE(*,*)' k C2k(-ic)' ENDIF WRITE(*,*)'----------------------------' NM=25+INT((N-M)/2+C) DO 10 K=1,NM 10 WRITE(*,20)K-1,CK(K) 20 FORMAT(2X,I3,4X,D18.10) 30 FORMAT(1X,3HKD=,I3,', ',2Hm=,I3,', ',2Hn=,I3, & ', ',2Hc=,F5.1,', ',4Hcv =,F18.10) END SUBROUTINE SCKB(M,N,C,DF,CK) C C ====================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions, c2k C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C DF(k) --- Expansion coefficients dk C Output: CK(k) --- Expansion coefficients ck; C CK(1), CK(2), ... correspond to C c0, c2, ... C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DF(200),CK(200) IF (C.LE.1.0D-10) C=1.0D-10 NM=25+INT(0.5*(N-M)+C) IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 FAC=-0.5D0**M REG=1.0D0 IF (M+NM.GT.80) REG=1.0D-200 DO 35 K=0,NM-1 FAC=-FAC I1=2*K+IP+1 R=REG DO 10 I=I1,I1+2*M-1 10 R=R*I I2=K+M+IP DO 15 I=I2,I2+K-1 15 R=R*(I+0.5D0) SUM=R*DF(K+1) DO 20 I=K+1,NM D1=2.0D0*I+IP D2=2.0D0*M+D1 D3=I+M+IP-0.5D0 R=R*D2*(D2-1.0D0)*I*(D3+K)/(D1*(D1-1.0D0)*(I-K)*D3) SUM=SUM+R*DF(I+1) IF (DABS(SW-SUM).LT.DABS(SUM)*1.0D-14) GO TO 25 20 SW=SUM 25 R1=REG DO 30 I=2,M+K 30 R1=R1*I 35 CK(K+1)=FAC*SUM/R1 RETURN END SUBROUTINE SDMN(M,N,C,CV,KD,DF) C C ===================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C cv --- Characteristic value C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C Output: DF(k) --- Expansion coefficients dk; C DF(1), DF(2), ... correspond to C d0, d2, ... for even n-m and d1, C d3, ... for odd n-m C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(200),D(200),G(200),DF(200) NM=25+INT(0.5*(N-M)+C) IF (C.LT.1.0D-10) THEN DO 5 I=1,NM 5 DF(I)=0D0 DF((N-M)/2+1)=1.0D0 RETURN ENDIF CS=C*C*KD IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 DO 10 I=1,NM+2 IF (IP.EQ.0) K=2*(I-1) IF (IP.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS 10 CONTINUE FS=1.0D0 F1=0.0D0 F0=1.0D-100 KB=0 DF(NM+1)=0.0D0 DO 30 K=NM,1,-1 F=-((D(K+1)-CV)*F0+A(K+1)*F1)/G(K+1) IF (DABS(F).GT.DABS(DF(K+1))) THEN DF(K)=F F1=F0 F0=F IF (DABS(F).GT.1.0D+100) THEN DO 12 K1=K,NM 12 DF(K1)=DF(K1)*1.0D-100 F1=F1*1.0D-100 F0=F0*1.0D-100 ENDIF ELSE KB=K FL=DF(K+1) F1=1.0D-100 F2=-(D(1)-CV)/A(1)*F1 DF(1)=F1 IF (KB.EQ.1) THEN FS=F2 ELSE IF (KB.EQ.2) THEN DF(2)=F2 FS=-((D(2)-CV)*F2+G(2)*F1)/A(2) ELSE DF(2)=F2 DO 20 J=3,KB+1 F=-((D(J-1)-CV)*F2+G(J-1)*F1)/A(J-1) IF (J.LE.KB) DF(J)=F IF (DABS(F).GT.1.0D+100) THEN DO 15 K1=1,J 15 DF(K1)=DF(K1)*1.0D-100 F=F*1.0D-100 F2=F2*1.0D-100 ENDIF F1=F2 20 F2=F FS=F ENDIF GO TO 35 ENDIF 30 CONTINUE 35 SU1=0.0D0 R1=1.0D0 DO 40 J=M+IP+1,2*(M+IP) 40 R1=R1*J SU1=DF(1)*R1 DO 45 K=2,KB R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) 45 SU1=SU1+R1*DF(K) SU2=0.0D0 DO 50 K=KB+1,NM IF (K.NE.1) R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) SU2=SU2+R1*DF(K) IF (DABS(SW-SU2).LT.DABS(SU2)*1.0D-14) GOTO 55 50 SW=SU2 55 R3=1.0D0 DO 60 J=1,(M+N+IP)/2 60 R3=R3*(J+0.5D0*(N+M+IP)) R4=1.0D0 DO 65 J=1,(N-M-IP)/2 65 R4=-4.0D0*R4*J S0=R3/(FL*(SU1/FS)+SU2)/R4 DO 70 K=1,KB 70 DF(K)=FL/FS*S0*DF(K) DO 75 K=KB+1,NM 75 DF(K)=S0*DF(K) RETURN END SUBROUTINE SEGV(M,N,C,KD,CV,EG) C C ========================================================= C Purpose: Compute the characteristic values of spheroidal C wave functions C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C KD --- Function code C KD=1 for Prolate; KD=-1 for Oblate C Output: CV --- Characteristic value for given m, n and c C EG(L) --- Characteristic value for mode m and n' C ( L = n' - m + 1 ) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION B(100),H(100),D(300),E(300),F(300),CV0(100), & A(300),G(300),EG(200) IF (C.LT.1.0D-10) THEN DO 5 I=1,N 5 EG(I)=(I+M)*(I+M-1.0D0) GO TO 70 ENDIF ICM=(N-M+2)/2 NM=10+INT(0.5*(N-M)+C) CS=C*C*KD DO 60 L=0,1 DO 10 I=1,NM IF (L.EQ.0) K=2*(I-1) IF (L.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS 10 G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS DO 15 K=2,NM E(K)=DSQRT(A(K-1)*G(K)) 15 F(K)=E(K)*E(K) F(1)=0.0D0 E(1)=0.0D0 XA=D(NM)+DABS(E(NM)) XB=D(NM)-DABS(E(NM)) NM1=NM-1 DO 20 I=1,NM1 T=DABS(E(I))+DABS(E(I+1)) T1=D(I)+T IF (XA.LT.T1) XA=T1 T1=D(I)-T IF (T1.LT.XB) XB=T1 20 CONTINUE DO 25 I=1,ICM B(I)=XA 25 H(I)=XB DO 55 K=1,ICM DO 30 K1=K,ICM IF (B(K1).LT.B(K)) THEN B(K)=B(K1) GO TO 35 ENDIF 30 CONTINUE 35 IF (K.NE.1.AND.H(K).LT.H(K-1)) H(K)=H(K-1) 40 X1=(B(K)+H(K))/2.0D0 CV0(K)=X1 IF (DABS((B(K)-H(K))/X1).LT.1.0D-14) GO TO 50 J=0 S=1.0D0 DO 45 I=1,NM IF (S.EQ.0.0D0) S=S+1.0D-30 T=F(I)/S S=D(I)-T-X1 IF (S.LT.0.0D0) J=J+1 45 CONTINUE IF (J.LT.K) THEN H(K)=X1 ELSE B(K)=X1 IF (J.GE.ICM) THEN B(ICM)=X1 ELSE IF (H(J+1).LT.X1) H(J+1)=X1 IF (X1.LT.B(J)) B(J)=X1 ENDIF ENDIF GO TO 40 50 CV0(K)=X1 IF (L.EQ.0) EG(2*K-1)=CV0(K) IF (L.EQ.1) EG(2*K)=CV0(K) 55 CONTINUE 60 CONTINUE 70 CV=EG(N-M+1) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/msdmn.for000077500000000000000000000177071321604176500257600ustar00rootroot00000000000000 PROGRAM MSDMN C C =========================================================== C Purpose: This program computes the expansion coefficients C of the prolate and oblate spheroidal functions, C dk, using subroutine SDMN C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C cv --- Characteristic value C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C Output: DF(k) --- Expansion coefficients dk; C DF(1), DF(2),... correspond to C d0, d2,... for even n-m and d1, C d3,... for odd n-m C Example: Compute the first 12 expansion coefficients for C KD= 1, m=2, n=2, c=3.0 and cv=7.1511005241; and C KD=-1, m=2, n=2, c=3.0 and cv=4.5264604622 C C Coefficients of Prolate and oblate functions C C r dr(c) dr(-ic) C ------------------------------------------- C 0 .9237882817D+00 .1115434000D+01 C 2 -.2901607696D-01 .4888489020D-01 C 4 .8142246173D-03 .1600845667D-02 C 6 -.1632270292D-04 .3509183384D-04 C 8 .2376699010D-06 .5416293446D-06 C 10 -.2601391701D-08 .6176624069D-08 C 12 .2209142844D-10 .5407431236D-10 C 14 -.1494812074D-12 .3745889118D-12 C 16 .8239302207D-15 .2103624480D-14 C 18 -.3768260778D-17 .9768323113D-17 C 20 .1452384658D-19 .3812753620D-19 C 22 -.4780280430D-22 .1268321726D-21 C =========================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION DF(200),EG(200) WRITE(*,*)'Please enter KD, m, n and c ' READ(*,*)KD,M,N,C CALL SEGV(M,N,C,KD,CV,EG) WRITE(*,30)KD,M,N,C,CV CALL SDMN(M,N,C,CV,KD,DF) WRITE(*,*) IF (KD.EQ.1) THEN WRITE(*,*)'Coefficients of Prolate function' WRITE(*,*) WRITE(*,*)' r dr(c)' ELSE WRITE(*,*)'Coefficients of Oblate function' WRITE(*,*) WRITE(*,*)' r dr(-ic)' ENDIF WRITE(*,*)'----------------------------' NM=25+INT(0.5*(N-M)+C) DO 10 K=1,NM IF (N-M.EQ.2*INT((N-M)/2)) THEN J=2*(K-1) ELSE J=2*K-1 ENDIF 10 WRITE(*,20)J,DF(K) 20 FORMAT(2X,I3,4X,D18.10) 30 FORMAT(1X,3HKD=,I3,', ',2Hm=,I3,', ',2Hn=,I3,', ',2Hc=, & F5.1,', ',4Hcv =,F18.10) END SUBROUTINE SDMN(M,N,C,CV,KD,DF) C C ===================================================== C Purpose: Compute the expansion coefficients of the C prolate and oblate spheroidal functions, dk C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C cv --- Characteristic value C KD --- Function code C KD=1 for prolate; KD=-1 for oblate C Output: DF(k) --- Expansion coefficients dk; C DF(1), DF(2),... correspond to C d0, d2,... for even n-m and d1, C d3,... for odd n-m C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION A(200),D(200),G(200),DF(200) NM=25+INT(0.5*(N-M)+C) IF (C.LT.1.0D-10) THEN DO 5 I=1,NM 5 DF(I)=0D0 DF((N-M)/2+1)=1.0D0 RETURN ENDIF CS=C*C*KD IP=1 IF (N-M.EQ.2*INT((N-M)/2)) IP=0 DO 10 I=1,NM+2 IF (IP.EQ.0) K=2*(I-1) IF (IP.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS 10 CONTINUE FS=1.0D0 F1=0.0D0 F0=1.0D-100 KB=0 DF(NM+1)=0.0D0 DO 30 K=NM,1,-1 F=-((D(K+1)-CV)*F0+A(K+1)*F1)/G(K+1) IF (DABS(F).GT.DABS(DF(K+1))) THEN DF(K)=F F1=F0 F0=F IF (DABS(F).GT.1.0D+100) THEN DO 12 K1=K,NM 12 DF(K1)=DF(K1)*1.0D-100 F1=F1*1.0D-100 F0=F0*1.0D-100 ENDIF ELSE KB=K FL=DF(K+1) F1=1.0D-100 F2=-(D(1)-CV)/A(1)*F1 DF(1)=F1 IF (KB.EQ.1) THEN FS=F2 ELSE IF (KB.EQ.2) THEN DF(2)=F2 FS=-((D(2)-CV)*F2+G(2)*F1)/A(2) ELSE DF(2)=F2 DO 20 J=3,KB+1 F=-((D(J-1)-CV)*F2+G(J-1)*F1)/A(J-1) IF (J.LE.KB) DF(J)=F IF (DABS(F).GT.1.0D+100) THEN DO 15 K1=1,J 15 DF(K1)=DF(K1)*1.0D-100 F=F*1.0D-100 F2=F2*1.0D-100 ENDIF F1=F2 20 F2=F FS=F ENDIF GO TO 35 ENDIF 30 CONTINUE 35 SU1=0.0D0 R1=1.0D0 DO 40 J=M+IP+1,2*(M+IP) 40 R1=R1*J SU1=DF(1)*R1 DO 45 K=2,KB R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) 45 SU1=SU1+R1*DF(K) SU2=0.0D0 DO 50 K=KB+1,NM IF (K.NE.1) R1=-R1*(K+M+IP-1.5D0)/(K-1.0D0) SU2=SU2+R1*DF(K) IF (DABS(SW-SU2).LT.DABS(SU2)*1.0D-14) GOTO 55 50 SW=SU2 55 R3=1.0D0 DO 60 J=1,(M+N+IP)/2 60 R3=R3*(J+0.5D0*(N+M+IP)) R4=1.0D0 DO 65 J=1,(N-M-IP)/2 65 R4=-4.0D0*R4*J S0=R3/(FL*(SU1/FS)+SU2)/R4 DO 70 K=1,KB 70 DF(K)=FL/FS*S0*DF(K) DO 75 K=KB+1,NM 75 DF(K)=S0*DF(K) RETURN END SUBROUTINE SEGV(M,N,C,KD,CV,EG) C C ========================================================= C Purpose: Compute the characteristic values of spheroidal C wave functions C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C KD --- Function code C KD=1 for Prolate; KD=-1 for Oblate C Output: CV --- Characteristic value for given m, n and c C EG(L) --- Characteristic value for mode m and n' C ( L = n' - m + 1 ) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION B(100),H(100),D(300),E(300),F(300),CV0(100), & A(300),G(300),EG(200) IF (C.LT.1.0D-10) THEN DO 5 I=1,N 5 EG(I)=(I+M)*(I+M-1.0D0) GO TO 70 ENDIF ICM=(N-M+2)/2 NM=10+INT(0.5*(N-M)+C) CS=C*C*KD DO 60 L=0,1 DO 10 I=1,NM IF (L.EQ.0) K=2*(I-1) IF (L.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS 10 G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS DO 15 K=2,NM E(K)=DSQRT(A(K-1)*G(K)) 15 F(K)=E(K)*E(K) F(1)=0.0D0 E(1)=0.0D0 XA=D(NM)+DABS(E(NM)) XB=D(NM)-DABS(E(NM)) NM1=NM-1 DO 20 I=1,NM1 T=DABS(E(I))+DABS(E(I+1)) T1=D(I)+T IF (XA.LT.T1) XA=T1 T1=D(I)-T IF (T1.LT.XB) XB=T1 20 CONTINUE DO 25 I=1,ICM B(I)=XA 25 H(I)=XB DO 55 K=1,ICM DO 30 K1=K,ICM IF (B(K1).LT.B(K)) THEN B(K)=B(K1) GO TO 35 ENDIF 30 CONTINUE 35 IF (K.NE.1.AND.H(K).LT.H(K-1)) H(K)=H(K-1) 40 X1=(B(K)+H(K))/2.0D0 CV0(K)=X1 IF (DABS((B(K)-H(K))/X1).LT.1.0D-14) GO TO 50 J=0 S=1.0D0 DO 45 I=1,NM IF (S.EQ.0.0D0) S=S+1.0D-30 T=F(I)/S S=D(I)-T-X1 IF (S.LT.0.0D0) J=J+1 45 CONTINUE IF (J.LT.K) THEN H(K)=X1 ELSE B(K)=X1 IF (J.GE.ICM) THEN B(ICM)=X1 ELSE IF (H(J+1).LT.X1) H(J+1)=X1 IF (X1.LT.B(J)) B(J)=X1 ENDIF ENDIF GO TO 40 50 CV0(K)=X1 IF (L.EQ.0) EG(2*K-1)=CV0(K) IF (L.EQ.1) EG(2*K)=CV0(K) 55 CONTINUE 60 CONTINUE 70 CV=EG(N-M+1) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/msegv.for000077500000000000000000000124661321604176500257600ustar00rootroot00000000000000 PROGRAM MSEGV C C ============================================================ C Purpose: This program computes a sequence of characteristic C values of spheroidal prolate and oblate functions C using subroutine SEGV C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C KD --- Function code C KD=1 for Prolate; KD=-1 for Oblate C Output: CV --- Characteristic value for given m, n and c C EG(L) --- Characteristic value for mode m and n' C ( L = n' - m + 1 ) C Examples: C Prolate: ( KD = 1 , m = 1, n = 5, c = 5.0 ) C C m n c Lambda mn(c) C --------------------------------------- C 1 1 5.0 5.35042230 C 1 2 5.0 14.64295624 C 1 3 5.0 23.39761312 C 1 4 5.0 32.42194359 C 1 5 5.0 42.65818215 C C Oblate: ( KD = -1 , m = 1, n = 5, c = 5.0 ) C C m n c Lambda mn(-ic) C -------------------------------------- C 1 1 5.0 -7.49338828 C 1 2 5.0 -7.12783752 C 1 3 5.0 2.75036721 C 1 4 5.0 8.69495925 C 1 5 5.0 18.43931577 C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION EG(100) WRITE(*,*)'Please enter KD, m, n and c ' READ(*,*)KD,M,N,C WRITE(*,15)KD,M,N,C WRITE(*,*) CALL SEGV(M,N,C,KD,CV,EG) IF (KD.EQ.1) THEN WRITE(*,*)' m n c Lambda mn(c)' ELSE IF (KD.EQ.-1) THEN WRITE(*,*)' m n c Lambda mn(-ic)' ENDIF WRITE(*,*)'---------------------------------------' DO 10 L=1,N-M+1 N1=M+L-1 10 WRITE(*,20)M,N1,C,EG(L) 15 FORMAT(1X,'KD =',I2,', m =',I3,', n =',I3,', c =',F5.1) 20 FORMAT(1X,I3,4X,I3,4X,F5.1,F18.8) END SUBROUTINE SEGV(M,N,C,KD,CV,EG) C C ========================================================= C Purpose: Compute the characteristic values of spheroidal C wave functions C Input : m --- Mode parameter C n --- Mode parameter C c --- Spheroidal parameter C KD --- Function code C KD=1 for Prolate; KD=-1 for Oblate C Output: CV --- Characteristic value for given m, n and c C EG(L) --- Characteristic value for mode m and n' C ( L = n' - m + 1 ) C ========================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION B(100),H(100),D(300),E(300),F(300),CV0(100), & A(300),G(300),EG(200) IF (C.LT.1.0D-10) THEN DO 5 I=1,N 5 EG(I)=(I+M)*(I+M-1.0D0) GO TO 70 ENDIF ICM=(N-M+2)/2 NM=10+INT(0.5*(N-M)+C) CS=C*C*KD DO 60 L=0,1 DO 10 I=1,NM IF (L.EQ.0) K=2*(I-1) IF (L.EQ.1) K=2*I-1 DK0=M+K DK1=M+K+1 DK2=2*(M+K) D2K=2*M+K A(I)=(D2K+2.0)*(D2K+1.0)/((DK2+3.0)*(DK2+5.0))*CS D(I)=DK0*DK1+(2.0*DK0*DK1-2.0*M*M-1.0)/((DK2-1.0) & *(DK2+3.0))*CS 10 G(I)=K*(K-1.0)/((DK2-3.0)*(DK2-1.0))*CS DO 15 K=2,NM E(K)=DSQRT(A(K-1)*G(K)) 15 F(K)=E(K)*E(K) F(1)=0.0D0 E(1)=0.0D0 XA=D(NM)+DABS(E(NM)) XB=D(NM)-DABS(E(NM)) NM1=NM-1 DO 20 I=1,NM1 T=DABS(E(I))+DABS(E(I+1)) T1=D(I)+T IF (XA.LT.T1) XA=T1 T1=D(I)-T IF (T1.LT.XB) XB=T1 20 CONTINUE DO 25 I=1,ICM B(I)=XA 25 H(I)=XB DO 55 K=1,ICM DO 30 K1=K,ICM IF (B(K1).LT.B(K)) THEN B(K)=B(K1) GO TO 35 ENDIF 30 CONTINUE 35 IF (K.NE.1.AND.H(K).LT.H(K-1)) H(K)=H(K-1) 40 X1=(B(K)+H(K))/2.0D0 CV0(K)=X1 IF (DABS((B(K)-H(K))/X1).LT.1.0D-14) GO TO 50 J=0 S=1.0D0 DO 45 I=1,NM IF (S.EQ.0.0D0) S=S+1.0D-30 T=F(I)/S S=D(I)-T-X1 IF (S.LT.0.0D0) J=J+1 45 CONTINUE IF (J.LT.K) THEN H(K)=X1 ELSE B(K)=X1 IF (J.GE.ICM) THEN B(ICM)=X1 ELSE IF (H(J+1).LT.X1) H(J+1)=X1 IF (X1.LT.B(J)) B(J)=X1 ENDIF ENDIF GO TO 40 50 CV0(K)=X1 IF (L.EQ.0) EG(2*K-1)=CV0(K) IF (L.EQ.1) EG(2*K)=CV0(K) 55 CONTINUE 60 CONTINUE 70 CV=EG(N-M+1) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/msphi.for000077500000000000000000000122371321604176500257530ustar00rootroot00000000000000 PROGRAM MSPHI C C ====================================================== C Purpose: This program computes the modified spherical C Bessel functions of the first kind in(x) and C in'(x) using subroutine SPHI C Input : x --- Argument of in(x) C n --- Order of in(x) ( 0 ó n ó 250 ) C Output: SI(n) --- in(x) C DI(n) --- in'(x) C Example: x = 10.0 C n in(x) in'(x) C -------------------------------------------- C 0 .1101323287D+04 .9911909633D+03 C 1 .9911909633D+03 .9030850948D+03 C 2 .8039659985D+03 .7500011637D+03 C 3 .5892079640D+03 .5682828129D+03 C 4 .3915204237D+03 .3934477522D+03 C 5 .2368395827D+03 .2494166741D+03 C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SI(0:250),DI(0:250) WRITE(*,*)'Please enter n and x ' READ(*,*)N,X WRITE(*,30)N,X IF (N.LE.10) THEN NS=1 ELSE WRITE(*,*) 'Please enter order step Ns' READ(*,*) NS ENDIF CALL SPHI(N,X,NM,SI,DI) WRITE(*,*) WRITE(*,*)' n in(x) in''(x)' WRITE(*,*)'--------------------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20)K,SI(K),DI(K) 20 FORMAT(1X,I3,2D20.10) 30 FORMAT(3X,'Nmax =',I3,', ','x =',F6.1) END SUBROUTINE SPHI(N,X,NM,SI,DI) C C ======================================================== C Purpose: Compute modified spherical Bessel functions C of the first kind, in(x) and in'(x) C Input : x --- Argument of in(x) C n --- Order of in(x) ( n = 0,1,2,... ) C Output: SI(n) --- in(x) C DI(n) --- in'(x) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 for computing the starting C point for backward recurrence C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SI(0:N),DI(0:N) NM=N IF (DABS(X).LT.1.0D-100) THEN DO 10 K=0,N SI(K)=0.0D0 10 DI(K)=0.0D0 SI(0)=1.0D0 DI(1)=0.333333333333333D0 RETURN ENDIF SI(0)=DSINH(X)/X SI(1)=-(DSINH(X)/X-DCOSH(X))/X SI0=SI(0) IF (N.GE.2) THEN M=MSTA1(X,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(X,N,15) ENDIF F0=0.0D0 F1=1.0D0-100 DO 15 K=M,0,-1 F=(2.0D0*K+3.0D0)*F1/X+F0 IF (K.LE.NM) SI(K)=F F0=F1 15 F1=F CS=SI0/F DO 20 K=0,NM 20 SI(K)=CS*SI(K) ENDIF DI(0)=SI(1) DO 25 K=1,NM 25 DI(K)=SI(K-1)-(K+1.0D0)/X*SI(K) RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/msphj.for000077500000000000000000000123401321604176500257470ustar00rootroot00000000000000 PROGRAM MSPHJ C C ======================================================= C Purpose: This program computes the spherical Bessel C functions jn(x) and jn'(x) using subroutine C SPHJ C Input : x --- Argument of jn(x) C n --- Order of jn(x) ( n = 0,1,úúú,ó 250 ) C Output: SJ(n) --- jn(x) C DJ(n) --- jn'(x) C Example: x =10.0 C n jn(x) jn(x) C -------------------------------------------- C 0 -.5440211109D-01 -.7846694180D-01 C 1 .7846694180D-01 -.7009549945D-01 C 2 .7794219363D-01 .5508428371D-01 C 3 -.3949584498D-01 .9374053162D-01 C 4 -.1055892851D+00 .1329879757D-01 C 5 -.5553451162D-01 -.7226857814D-01 C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SJ(0:250),DJ(0:250) WRITE(*,*)'Please enter n and x ' READ(*,*)N,X WRITE(*,30)N,X IF (N.LE.10) THEN NS=1 ELSE WRITE(*,*)'Please enter order step Ns' READ(*,*)NS ENDIF CALL SPHJ(N,X,NM,SJ,DJ) WRITE(*,*) WRITE(*,*)' n jn(x) jn''(x)' WRITE(*,*)'--------------------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20)K,SJ(K),DJ(K) 20 FORMAT(1X,I3,2D20.10) 30 FORMAT(3X,6HNmax =,I3,', ',2Hx=,F5.1) END SUBROUTINE SPHJ(N,X,NM,SJ,DJ) C C ======================================================= C Purpose: Compute spherical Bessel functions jn(x) and C their derivatives C Input : x --- Argument of jn(x) C n --- Order of jn(x) ( n = 0,1,úúú ) C Output: SJ(n) --- jn(x) C DJ(n) --- jn'(x) C NM --- Highest order computed C Routines called: C MSTA1 and MSTA2 for computing the starting C point for backward recurrence C ======================================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SJ(0:N),DJ(0:N) NM=N IF (DABS(X).EQ.1.0D-100) THEN DO 10 K=0,N SJ(K)=0.0D0 10 DJ(K)=0.0D0 SJ(0)=1.0D0 DJ(1)=.3333333333333333D0 RETURN ENDIF SJ(0)=DSIN(X)/X SJ(1)=(SJ(0)-DCOS(X))/X IF (N.GE.2) THEN SA=SJ(0) SB=SJ(1) M=MSTA1(X,200) IF (M.LT.N) THEN NM=M ELSE M=MSTA2(X,N,15) ENDIF F0=0.0D0 F1=1.0D0-100 DO 15 K=M,0,-1 F=(2.0D0*K+3.0D0)*F1/X-F0 IF (K.LE.NM) SJ(K)=F F0=F1 15 F1=F IF (DABS(SA).GT.DABS(SB)) CS=SA/F IF (DABS(SA).LE.DABS(SB)) CS=SB/F0 DO 20 K=0,NM 20 SJ(K)=CS*SJ(K) ENDIF DJ(0)=(DCOS(X)-DSIN(X)/X)/X DO 25 K=1,NM 25 DJ(K)=SJ(K-1)-(K+1.0D0)*SJ(K)/X RETURN END INTEGER FUNCTION MSTA1(X,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that the magnitude of C Jn(x) at that point is about 10^(-MP) C Input : x --- Argument of Jn(x) C MP --- Value of magnitude C Output: MSTA1 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) N0=INT(1.1*A0)+1 F0=ENVJ(N0,A0)-MP N1=N0+5 F1=ENVJ(N1,A0)-MP DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-MP IF(ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA1=NN RETURN END INTEGER FUNCTION MSTA2(X,N,MP) C C =================================================== C Purpose: Determine the starting point for backward C recurrence such that all Jn(x) has MP C significant digits C Input : x --- Argument of Jn(x) C n --- Order of Jn(x) C MP --- Significant digit C Output: MSTA2 --- Starting point C =================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) A0=DABS(X) HMP=0.5D0*MP EJN=ENVJ(N,A0) IF (EJN.LE.HMP) THEN OBJ=MP N0=INT(1.1*A0) ELSE OBJ=HMP+EJN N0=N ENDIF F0=ENVJ(N0,A0)-OBJ N1=N0+5 F1=ENVJ(N1,A0)-OBJ DO 10 IT=1,20 NN=N1-(N1-N0)/(1.0D0-F0/F1) F=ENVJ(NN,A0)-OBJ IF (ABS(NN-N1).LT.1) GO TO 20 N0=N1 F0=F1 N1=NN 10 F1=F 20 MSTA2=NN+10 RETURN END REAL*8 FUNCTION ENVJ(N,X) DOUBLE PRECISION X ENVJ=0.5D0*DLOG10(6.28D0*N)-N*DLOG10(1.36D0*X/N) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/msphk.for000077500000000000000000000053401321604176500257520ustar00rootroot00000000000000 PROGRAM MSPHK C C ====================================================== C Purpose: This program computes the modified spherical C Bessel functions kn(x) and kn'(x) using C subroutine SPHK C Input : x --- Argument of kn(x) ( x ò 0 ) C n --- Order of kn(x) ( n ó 250 ) C Output: SK(n) --- kn(x) C DK(n) --- kn'(x) C Example: x= 10.0 C n kn(x) kn'(x) C -------------------------------------------- C 0 .7131404291D-05 -.7844544720D-05 C 1 .7844544720D-05 -.8700313235D-05 C 2 .9484767707D-05 -.1068997503D-04 C 3 .1258692857D-04 -.1451953914D-04 C 4 .1829561771D-04 -.2173473743D-04 C 5 .2905298451D-04 -.3572740841D-04 C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SK(0:250),DK(0:250) WRITE(*,*)'Please enter n and x ' READ(*,*)N,X WRITE(*,30)N,X IF (N.LE.10) THEN NS=1 ELSE WRITE(*,*) 'Please enter order step Ns' READ(*,*) NS ENDIF CALL SPHK(N,X,NM,SK,DK) WRITE(*,*) WRITE(*,*)' n kn(x) kn''(x)' WRITE(*,*)'--------------------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20)K,SK(K),DK(K) 20 FORMAT(1X,I3,2D20.10) 30 FORMAT(3X,'Nmax =',I3,', ','x =',F6.1) END SUBROUTINE SPHK(N,X,NM,SK,DK) C C ===================================================== C Purpose: Compute modified spherical Bessel functions C of the second kind, kn(x) and kn'(x) C Input : x --- Argument of kn(x) ( x ò 0 ) C n --- Order of kn(x) ( n = 0,1,2,... ) C Output: SK(n) --- kn(x) C DK(n) --- kn'(x) C NM --- Highest order computed C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SK(0:N),DK(0:N) PI=3.141592653589793D0 NM=N IF (X.LT.1.0D-60) THEN DO 10 K=0,N SK(K)=1.0D+300 10 DK(K)=-1.0D+300 RETURN ENDIF SK(0)=0.5D0*PI/X*DEXP(-X) SK(1)=SK(0)*(1.0D0+1.0D0/X) F0=SK(0) F1=SK(1) DO 15 K=2,N F=(2.0D0*K-1.0D0)*F1/X+F0 SK(K)=F IF (DABS(F).GT.1.0D+300) GO TO 20 F0=F1 15 F1=F 20 NM=K-1 DK(0)=-SK(1) DO 25 K=1,NM 25 DK(K)=-SK(K-1)-(K+1.0D0)/X*SK(K) RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/msphy.for000077500000000000000000000053131321604176500257700ustar00rootroot00000000000000 PROGRAM MSPHY C C ======================================================== C Purpose: This program computes the spherical Bessel C functions yn(x) and yn'(x) using subroutine C SPHY C Input : x --- Argument of yn(x) ( x ò 0 ) C n --- Order of yn(x) ( n = 0,1,úúú, ó 250 ) C Output: SY(n) --- yn(x) C DY(n) --- yn'(x) C Example: x = 10.0 C n yn(x) yn'(x) C -------------------------------------------- C 0 .8390715291D-01 -.6279282638D-01 C 1 .6279282638D-01 .7134858763D-01 C 2 -.6506930499D-01 .8231361788D-01 C 3 -.9532747888D-01 -.2693831344D-01 C 4 -.1659930220D-02 -.9449751377D-01 C 5 .9383354168D-01 -.5796005523D-01 C ======================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SY(0:250),DY(0:250) WRITE(*,*)'Please enter n and x ' READ(*,*)N,X WRITE(*,30)N,X IF (N.LE.10) THEN NS=1 ELSE WRITE(*,*)'Please enter order step Ns' READ(*,*)NS ENDIF CALL SPHY(N,X,NM,SY,DY) WRITE(*,*) WRITE(*,*)' n yn(x) yn''(x)' WRITE(*,*)'--------------------------------------------' DO 10 K=0,NM,NS 10 WRITE(*,20)K,SY(K),DY(K) 20 FORMAT(1X,I3,2D20.10) 30 FORMAT(3X,6HNmax =,I3,', ',2Hx=,F6.1) END SUBROUTINE SPHY(N,X,NM,SY,DY) C C ====================================================== C Purpose: Compute spherical Bessel functions yn(x) and C their derivatives C Input : x --- Argument of yn(x) ( x ò 0 ) C n --- Order of yn(x) ( n = 0,1,úúú ) C Output: SY(n) --- yn(x) C DY(n) --- yn'(x) C NM --- Highest order computed C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION SY(0:N),DY(0:N) NM=N IF (X.LT.1.0D-60) THEN DO 10 K=0,N SY(K)=-1.0D+300 10 DY(K)=1.0D+300 RETURN ENDIF SY(0)=-DCOS(X)/X SY(1)=(SY(0)-DSIN(X))/X F0=SY(0) F1=SY(1) DO 15 K=2,N F=(2.0D0*K-1.0D0)*F1/X-F0 SY(K)=F IF (DABS(F).GE.1.0D+300) GO TO 20 F0=F1 15 F1=F 20 NM=K-1 DY(0)=(DSIN(X)+DCOS(X)/X)/X DO 25 K=1,NM 25 DY(K)=SY(K-1)-(K+1.0D0)*SY(K)/X RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mstvh0.for000077500000000000000000000043111321604176500260460ustar00rootroot00000000000000 PROGRAM MSTVH0 C C ==================================================== C Purpose: This program computes Struve function C H0(x) using subroutine STVH0 C Input : x --- Argument of H0(x) ( x ò 0 ) C Output: SH0 --- H0(x) C Example: C x H0(x) C ---------------------- C 0.0 .00000000 C 5.0 -.18521682 C 10.0 .11874368 C 15.0 .24772383 C 20.0 .09439370 C 25.0 -.10182519 C ==================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x H0(x)' WRITE(*,*)'----------------------' CALL STVH0(X,SH0) WRITE(*,10)X,SH0 10 FORMAT(1X,F5.1,E16.8) END SUBROUTINE STVH0(X,SH0) C C ============================================= C Purpose: Compute Struve function H0(x) C Input : x --- Argument of H0(x) ( x ò 0 ) C Output: SH0 --- H0(x) C ============================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 S=1.0D0 R=1.0D0 IF (X.LE.20.0D0) THEN A0=2.0*X/PI DO 10 K=1,60 R=-R*X/(2.0D0*K+1.0D0)*X/(2.0D0*K+1.0D0) S=S+R IF (DABS(R).LT.DABS(S)*1.0D-12) GO TO 15 10 CONTINUE 15 SH0=A0*S ELSE KM=INT(.5*(X+1.0)) IF (X.GE.50.0) KM=25 DO 20 K=1,KM R=-R*((2.0D0*K-1.0D0)/X)**2 S=S+R IF (DABS(R).LT.DABS(S)*1.0D-12) GO TO 25 20 CONTINUE 25 T=4.0D0/X T2=T*T P0=((((-.37043D-5*T2+.173565D-4)*T2-.487613D-4) & *T2+.17343D-3)*T2-.1753062D-2)*T2+.3989422793D0 Q0=T*(((((.32312D-5*T2-.142078D-4)*T2+.342468D-4)* & T2-.869791D-4)*T2+.4564324D-3)*T2-.0124669441D0) TA0=X-.25D0*PI BY0=2.0D0/DSQRT(X)*(P0*DSIN(TA0)+Q0*DCOS(TA0)) SH0=2.0D0/(PI*X)*S+BY0 ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mstvh1.for000077500000000000000000000043301321604176500260500ustar00rootroot00000000000000 PROGRAM MSTVH1 C C ===================================================== C Purpose: This program computes Struve function C H1(x) using subroutine STVH1 C Input : x --- Argument of H1(x) ( x ò 0 ) C Output: SH1 --- H1(x) C Example: C x H1(x) C ----------------------- C 0.0 .00000000 C 5.0 .80781195 C 10.0 .89183249 C 15.0 .66048730 C 20.0 .47268818 C 25.0 .53880362 C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x H1(x)' WRITE(*,*)'-----------------------' CALL STVH1(X,SH1) WRITE(*,10)X,SH1 10 FORMAT(1X,F5.1,E16.8) END SUBROUTINE STVH1(X,SH1) C C ============================================= C Purpose: Compute Struve function H1(x) C Input : x --- Argument of H1(x) ( x ò 0 ) C Output: SH1 --- H1(x) C ============================================= C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 R=1.0D0 IF (X.LE.20.0D0) THEN S=0.0D0 A0=-2.0D0/PI DO 10 K=1,60 R=-R*X*X/(4.0D0*K*K-1.0D0) S=S+R IF (DABS(R).LT.DABS(S)*1.0D-12) GO TO 15 10 CONTINUE 15 SH1=A0*S ELSE S=1.0D0 KM=INT(.5*X) IF (X.GT.50.D0) KM=25 DO 20 K=1,KM R=-R*(4.0D0*K*K-1.0D0)/(X*X) S=S+R IF (DABS(R).LT.DABS(S)*1.0D-12) GO TO 25 20 CONTINUE 25 T=4.0D0/X T2=T*T P1=((((.42414D-5*T2-.20092D-4)*T2+.580759D-4)*T2 & -.223203D-3)*T2+.29218256D-2)*T2+.3989422819D0 Q1=T*(((((-.36594D-5*T2+.1622D-4)*T2-.398708D-4)* & T2+.1064741D-3)*T2-.63904D-3)*T2+.0374008364D0) TA1=X-.75D0*PI BY1=2.0D0/DSQRT(X)*(P1*DSIN(TA1)+Q1*DCOS(TA1)) SH1=2.0/PI*(1.0D0+S/(X*X))+BY1 ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mstvhv.for000077500000000000000000000134111321604176500261550ustar00rootroot00000000000000 PROGRAM MSTVHV C C ====================================================== C Purpose: This program computes Struve function Hv(x) C for an arbitrary order using subroutine C STVHV C Input : v --- Order of Hv(x) ( -8.0 ó v ó 12.5 ) C x --- Argument of Hv(x) ( x ò 0 ) C Output: HV --- Hv(x) C Example: x = 10.0 C v Hv(x) C ----------------------- C .5 .46402212D+00 C 1.5 .14452322D+01 C 2.5 .31234632D+01 C 3.5 .53730255D+01 C 4.5 .72083122D+01 C 5.5 .76851132D+01 C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please v and x ' READ(*,*)V,X WRITE(*,30)V,X WRITE(*,*) WRITE(*,*)' v Hv(x)' WRITE(*,*)' -----------------------' CAll STVHV(V,X,HV) WRITE(*,20)V,HV 20 FORMAT(1X,F5.1,D18.8) 30 FORMAT(1X,'v =',F5.1,6X,'x =',F5.1) END SUBROUTINE STVHV(V,X,HV) C C ===================================================== C Purpose: Compute Struve function Hv(x) with an C arbitrary order v C Input : v --- Order of Hv(x) ( -8.0 ó v ó 12.5 ) C x --- Argument of Hv(x) ( x ò 0 ) C Output: HV --- Hv(x) C Routine called: GAMMA to compute the gamma function C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 IF (X.EQ.0.0D0) THEN IF (V.GT.-1.0.OR.INT(V)-V.EQ.0.5D0) THEN HV=0.0D0 ELSE IF (V.LT.-1.0D0) THEN HV=(-1)**(INT(0.5D0-V)-1)*1.0D+300 ELSE IF (V.EQ.-1.0D0) THEN HV=2.0D0/PI ENDIF RETURN ENDIF IF (X.LE.20.0D0) THEN V0=V+1.5D0 CALL GAMMA(V0,GA) S=2.0D0/(DSQRT(PI)*GA) R1=1.0D0 DO 10 K=1,100 VA=K+1.5D0 CALL GAMMA(VA,GA) VB=V+K+1.5D0 CALL GAMMA(VB,GB) R1=-R1*(0.5D0*X)**2 R2=R1/(GA*GB) S=S+R2 IF (DABS(R2).LT.DABS(S)*1.0D-12) GO TO 15 10 CONTINUE 15 HV=(0.5D0*X)**(V+1.0D0)*S ELSE SA=(0.5D0*X)**(V-1.0)/PI V0=V+0.5D0 CALL GAMMA(V0,GA) S=DSQRT(PI)/GA R1=1.0D0 DO 20 K=1,12 VA=K+0.5D0 CALL GAMMA(VA,GA) VB=-K+V+0.5D0 CALL GAMMA(VB,GB) R1=R1/(0.5D0*X)**2 S=S+R1*GA/GB 20 CONTINUE S0=SA*S U=DABS(V) N=INT(U) U0=U-N DO 35 L=0,1 VT=4.0D0*(U0+L)**2 R1=1.0D0 PU1=1.0D0 DO 25 K=1,12 R1=-0.0078125D0*R1*(VT-(4.0*K-3.0D0)**2)* & (VT-(4.0D0*K-1.0)**2)/((2.0D0*K-1.0)*K*X*X) PU1=PU1+R1 25 CONTINUE QU1=1.0D0 R2=1.0D0 DO 30 K=1,12 R2=-0.0078125D0*R2*(VT-(4.0D0*K-1.0)**2)* & (VT-(4.0D0*K+1.0)**2)/((2.0D0*K+1.0)*K*X*X) QU1=QU1+R2 30 CONTINUE QU1=0.125D0*(VT-1.0D0)/X*QU1 IF (L.EQ.0) THEN PU0=PU1 QU0=QU1 ENDIF 35 CONTINUE T0=X-(0.5*U0+0.25D0)*PI T1=X-(0.5*U0+0.75D0)*PI SR=DSQRT(2.0D0/(PI*X)) BY0=SR*(PU0*DSIN(T0)+QU0*DCOS(T0)) BY1=SR*(PU1*DSIN(T1)+QU1*DCOS(T1)) BF0=BY0 BF1=BY1 DO 40 K=2,N BF=2.0D0*(K-1.0+U0)/X*BF1-BF0 BF0=BF1 40 BF1=BF IF (N.EQ.0) BYV=BY0 IF (N.EQ.1) BYV=BY1 IF (N.GT.1) BYV=BF HV=BYV+S0 ENDIF RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mstvl0.for000077500000000000000000000042641321604176500260610ustar00rootroot00000000000000 PROGRAM MSTVL0 C C ===================================================== C Purpose: This program computes modified Struve C function L0(x) using subroutine STVL0 C Input : x --- Argument of L0(x) ( x ò 0 ) C Output: SL0 --- L0(x) C Example: C x L0(x) C ------------------------ C 0.0 .00000000D+00 C 5.0 .27105917D+02 C 10.0 .28156522D+04 C 15.0 .33964933D+06 C 20.0 .43558283D+08 C 30.0 .78167230D+12 C 40.0 .14894775D+17 C 50.0 .29325538D+21 C ===================================================== IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x L0(x)' WRITE(*,*)'-----------------------' CALL STVL0(X,SL0) WRITE(*,10)X,SL0 10 FORMAT(1X,F5.1,D16.8) END SUBROUTINE STVL0(X,SL0) C C ================================================ C Purpose: Compute modified Struve function L0(x) C Input : x --- Argument of L0(x) ( x ò 0 ) C Output: SL0 --- L0(x) C ================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 S=1.0D0 R=1.0D0 IF (X.LE.20.0D0) THEN A0=2.0D0*X/PI DO 10 K=1,60 R=R*(X/(2.0D0*K+1.0D0))**2 S=S+R IF (DABS(R/S).LT.1.0D-12) GO TO 15 10 CONTINUE 15 SL0=A0*S ELSE KM=INT(.5*(X+1.0)) IF (X.GE.50.0) KM=25 DO 20 K=1,KM R=R*((2.0D0*K-1.0D0)/X)**2 S=S+R IF (DABS(R/S).LT.1.0D-12) GO TO 25 20 CONTINUE 25 A1=DEXP(X)/DSQRT(2.0D0*PI*X) R=1.0D0 BI0=1.0D0 DO 30 K=1,16 R=0.125D0*R*(2.0D0*K-1.0D0)**2/(K*X) BI0=BI0+R IF (DABS(R/BI0).LT.1.0D-12) GO TO 35 30 CONTINUE 35 BI0=A1*BI0 SL0=-2.0D0/(PI*X)*S+BI0 ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mstvl1.for000077500000000000000000000043661321604176500260650ustar00rootroot00000000000000 PROGRAM MSTVL1 C C ===================================================== C Purpose: This program computes the modified Struve C function L1(x) using subroutine STVL1 C Input : x --- Argument of L1(x) ( x ò 0 ) C Output: SL1 --- L1(x) C Example: C x L1(x) C ----------------------- C 0.0 .00000000D+00 C 5.0 .23728216D+02 C 10.0 .26703583D+04 C 15.0 .32812429D+06 C 20.0 .42454973D+08 C 30.0 .76853204D+12 C 40.0 .14707396D+17 C 50.0 .29030786D+21 C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter x ' READ(*,*)X WRITE(*,*)' x L1(x)' WRITE(*,*)'-----------------------' CALL STVL1(X,SL1) WRITE(*,10)X,SL1 10 FORMAT(1X,F5.1,D16.8) END SUBROUTINE STVL1(X,SL1) C C ================================================ C Purpose: Compute modified Struve function L1(x) C Input : x --- Argument of L1(x) ( x ò 0 ) C Output: SL1 --- L1(x) C ================================================ C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 R=1.0D0 IF (X.LE.20.0D0) THEN S=0.0D0 DO 10 K=1,60 R=R*X*X/(4.0D0*K*K-1.0D0) S=S+R IF (DABS(R/S).LT.1.0D-12) GO TO 15 10 CONTINUE 15 SL1=2.0D0/PI*S ELSE S=1.0D0 KM=INT(.50*X) IF (X.GT.50) KM=25 DO 20 K=1,KM R=R*(2.0D0*K+3.0D0)*(2.0D0*K+1.0D0)/(X*X) S=S+R IF (DABS(R/S).LT.1.0D-12) GO TO 25 20 CONTINUE 25 SL1=2.0D0/PI*(-1.0D0+1.0D0/(X*X)+3.0D0*S/X**4) A1=DEXP(X)/DSQRT(2.0D0*PI*X) R=1.0D0 BI1=1.0D0 DO 30 K=1,16 R=-0.125D0*R*(4.0D0-(2.0D0*K-1.0D0)**2)/(K*X) BI1=BI1+R IF (DABS(R/BI1).LT.1.0D-12) GO TO 35 30 CONTINUE 35 SL1=SL1+A1*BI1 ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/mstvlv.for000077500000000000000000000123641321604176500261670ustar00rootroot00000000000000 PROGRAM MSTVLV C C ====================================================== C Purpose: This program computes the modified Struve C function Lv(x) for an arbitrary order v C using subroutine STVLV C Input : v --- Order of Lv(x) ( |v| ó 20 ) C x --- Argument of Lv(x) ( x ò 0 ) C Output: SLV --- Lv(x) C Example: x = 10.0 C v Lv(x) C ------------------------ C 0.5 .27785323D+04 C 1.5 .24996698D+04 C 2.5 .20254774D+04 C 3.5 .14816746D+04 C 4.5 .98173460D+03 C 5.5 .59154277D+03 C ===================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) WRITE(*,*)'Please enter v and x ' READ(*,*)V,X WRITE(*,30)V,X WRITE(*,*) WRITE(*,*)' v Lv(x)' WRITE(*,*)' ------------------------' CAll STVLV(V,X,SLV) WRITE(*,20)V,SLV 20 FORMAT(1X,F5.1,D18.8) 30 FORMAT(1X,'v =',F5.1,6X,'x =',F5.1) END SUBROUTINE STVLV(V,X,SLV) C C ====================================================== C Purpose: Compute modified Struve function Lv(x) with C an arbitrary order v C Input : v --- Order of Lv(x) ( |v| ó 20 ) C x --- Argument of Lv(x) ( x ò 0 ) C Output: SLV --- Lv(x) C Routine called: GAMMA to compute the gamma function C ====================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) PI=3.141592653589793D0 IF (X.EQ.0.0D0) THEN IF (V.GT.-1.0.OR.INT(V)-V.EQ.0.5D0) THEN SLV=0.0D0 ELSE IF (V.LT.-1.0D0) THEN SLV=(-1)**(INT(0.5D0-V)-1)*1.0D+300 ELSE IF (V.EQ.-1.0D0) THEN SLV=2.0D0/PI ENDIF RETURN ENDIF IF (X.LE.40.0D0) THEN V0=V+1.5D0 CALL GAMMA(V0,GA) S=2.0D0/(DSQRT(PI)*GA) R1=1.0D0 DO 10 K=1,100 VA=K+1.5D0 CALL GAMMA(VA,GA) VB=V+K+1.5D0 CALL GAMMA(VB,GB) R1=R1*(0.5D0*X)**2 R2=R1/(GA*GB) S=S+R2 IF (DABS(R2/S).LT.1.0D-12) GO TO 15 10 CONTINUE 15 SLV=(0.5D0*X)**(V+1.0D0)*S ELSE SA=-1.0D0/PI*(0.5D0*X)**(V-1.0) V0=V+0.5D0 CALL GAMMA(V0,GA) S=-DSQRT(PI)/GA R1=-1.0D0 DO 20 K=1,12 VA=K+0.5D0 CALL GAMMA(VA,GA) VB=-K+V+0.5D0 CALL GAMMA(VB,GB) R1=-R1/(0.5D0*X)**2 S=S+R1*GA/GB 20 CONTINUE S0=SA*S U=DABS(V) N=INT(U) U0=U-N DO 35 L=0,1 VT=U0+L R=1.0D0 BIV=1.0D0 DO 25 K=1,16 R=-0.125*R*(4.0*VT*VT-(2.0*K-1.0D0)**2)/(K*X) BIV=BIV+R IF (DABS(R/BIV).LT.1.0D-12) GO TO 30 25 CONTINUE 30 IF (L.EQ.0) BIV0=BIV 35 CONTINUE BF0=BIV0 BF1=BIV DO 40 K=2,N BF=-2.0D0*(K-1.0+U0)/X*BF1+BF0 BF0=BF1 40 BF1=BF IF (N.EQ.0) BIV=BIV0 IF (N.GT.1) BIV=BF SLV=DEXP(X)/DSQRT(2.0D0*PI*X)*BIV+S0 ENDIF RETURN END SUBROUTINE GAMMA(X,GA) C C ================================================== C Purpose: Compute gamma function â(x) C Input : x --- Argument of â(x) C ( x is not equal to 0,-1,-2,úúú) C Output: GA --- â(x) C ================================================== C IMPLICIT DOUBLE PRECISION (A-H,O-Z) DIMENSION G(26) PI=3.141592653589793D0 IF (X.EQ.INT(X)) THEN IF (X.GT.0.0D0) THEN GA=1.0D0 M1=X-1 DO 10 K=2,M1 10 GA=GA*K ELSE GA=1.0D+300 ENDIF ELSE IF (DABS(X).GT.1.0D0) THEN Z=DABS(X) M=INT(Z) R=1.0D0 DO 15 K=1,M 15 R=R*(Z-K) Z=Z-M ELSE Z=X ENDIF DATA G/1.0D0,0.5772156649015329D0, & -0.6558780715202538D0, -0.420026350340952D-1, & 0.1665386113822915D0,-.421977345555443D-1, & -.96219715278770D-2, .72189432466630D-2, & -.11651675918591D-2, -.2152416741149D-3, & .1280502823882D-3, -.201348547807D-4, & -.12504934821D-5, .11330272320D-5, & -.2056338417D-6, .61160950D-8, & .50020075D-8, -.11812746D-8, & .1043427D-9, .77823D-11, & -.36968D-11, .51D-12, & -.206D-13, -.54D-14, .14D-14, .1D-15/ GR=G(26) DO 20 K=25,1,-1 20 GR=GR*Z+G(K) GA=1.0D0/(GR*Z) IF (DABS(X).GT.1.0D0) THEN GA=GA*R IF (X.LT.0.0D0) GA=-PI/(X*GA*DSIN(PI*X)) ENDIF ENDIF RETURN END plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/readme000077500000000000000000000417511321604176500253060ustar00rootroot00000000000000 **************************************** * DISK TO ACCOMPANY * * COMPUTATION OF SPECIAL FUNCTIONS * * * * Shanjie Zhang and Jianming Jin * * * * Copyright 1996 by John Wiley & * * Sons, Inc. * * * **************************************** I. INTRODUCTION As stated in the preface of our book "Computation of Special Functions," the purpose of this book is to share with the reader a set of computer programs (130 in total) which we have developed during the past several years for computing a variety of special mathematical functions. For your convenience, we attach to the book this diskette that contains all the computer programs listed or mentioned in the book. In this diskette, we place all the programs under directory SMF\PROGRAMS. In order to illustrate the use of these programs and facilitate your testing of the programs, we wrote a short simple main program for each program so that you can readily test them. All the programs are written in FORTRAN-77 and tested on PCs and workstations. Therefore, they should run on any computer with implementation of the FORTRAN-77 standard. Although we have made a great effort to test these programs, we would not be surprised to find some errors in them. We would appreciate it if you can bring to our attention any errors you find. You can do this by either writing us directly at the location (e-mail: j-jin1@uiuc.edu) or writing to the publisher, whose address appears on the back cover of the book. However, we must note that all these programs are sold "as is," and we cannot guarantee to correct the errors reported by readers on any fixed schedule. All the programs and subroutines contained in this diskette are copyrighted. However, we give permission to the reader who purchases this book to incorporate any of these programs into his or her programs provided that the copyright is acknowledged. Regarding the specifics of the programs, we want to make the following two points. 1) All the programs are written in double precision. Although the use of double precision is necessary for some programs, especially for those based on series expansions, it is not necessary for all programs. For example, the computation of of special functions based on polynomial approximations does not have to use double precision. We chose to write all the programs using double precision in order to avoid possible confusion which may occur in using these programs. If necessary, you can convert the programs into the single precision format easily. However, doing so for some programs may lead to a lower accuracy. 2) In the main programs that calculate a sequence of special functions, we usually set the maximum order or degree to 100 or 250. However, this is not a limit. To compute functions with a higher order or degree, all you need to do is simply set the dimension of proper arrays higher. II. DISCLAIMER OF WARRANTY Although we have made a great effort to test and validate the computer programs, we make no warranties, express or implied, that these programs are free of error, or are consistent with any particular standard of merchantability, or that they will meet your requirements for any particular application. They should not be relied on for solving problems whose incorrect solution could result in injury to a person or loss of property. If you do use the programs in such a manner, it is at your own risk. The authors and publisher disclaim all liability for direct or consequential damages resulting from your use of the programs. III. LIST OF PROGRAMS (Please note that all file names of programs installed from the disk begin with an M, for example, MBERNOA.FOR) BERNOA Evaluate a sequence of Bernoulli numbers (method 1). BERNOB Evaluate a sequence of Bernoulli numbers (method 2). EULERA Evaluate a sequence of Euler numbers (method 1). EULERB Evaluate a sequence of Euler numbers (method 2). ***** OTHPL Evaluate a sequence of orthogonal polynomials and their derivatives, including Chebyshev, Laguerre, and Hermite polynomials. LEGZO Evaluate the nodes and weights for Gauss-Legendre quadrature. LAGZO Evaluate the nodes and weights for Gauss-Laguerre quadrature. HERZO Evaluate the nodes and weights for Gauss-Hermite quadrature. ***** GAMMA Evaluate the gamma function. LGAMA Evaluate the gamma function or the logarithm of the gamma function. CGAMA Evaluate the gamma function with a complex argument. BETA Evaluate the beta function. PSI Evaluate the psi function. CPSI Evaluate the psi function with a complex argument. INCOG Evaluate the incomplete gamma function. INCOB Evaluate the incomplete beta function. ***** LPN Evaluate a sequence of Legendre polynomials and their derivatives with real arguments. CLPN Evaluate a sequence of Legendre polynomials and their derivatives with complex arguments. LPNI Evaluate a sequence of Legendre polynomials, their derivatives, and their integrals. LQNA Evaluate a sequence of Legendre functions of the second kind and their derivatives with restricted real arguments. LQNB Evaluate a sequence of Legendre functions of the second kind and their derivatives with nonrestricted real arguments. CLQN Evaluate a sequence of Legendre functions of the second kind and their derivatives with complex arguments. LPMN Evaluate a sequence of associated Legendre polynomials and their derivatives with real arguments. CLPMN Evaluate a sequence of associated Legendre polynomials and their derivatives with complex arguments. LQMN Evaluate a sequence of associated Legendre functions of the second kind and their derivatives with real arguments. CLQMN Evaluate a sequence of associated Legendre functions of the second kind and their derivatives with complex arguments. LPMV Evaluate associated Legendre functions of the first kind with an integer order and arbitrary non-negative degree. ***** JY01A Evaluate the zeroth- and first-order Bessel functions of the first and second kinds with real arguments using series and asymptotic expansions. JY01B Evaluate the zeroth- and first-order Bessel functions of the first and second kinds with real arguments using polynomial approximations. JYNA Evaluate a sequence of Bessel functions of the first and second kinds and their derivatives with integer orders and real arguments (method 1). JYNB Evaluate a sequence of Bessel functions of the first and second kinds and their derivatives with integer orders and real arguments (method 2). CJY01 Evaluate the zeroth- and first-order Bessel functions of the first and second kinds and their derivatives with complex arguments. CJYNA Evaluate a sequence of Bessel functions of the first and second kinds and their derivatives with integer orders and complex arguments (method 1). CJYNB Evaluate a sequence of Bessel functions of the first and second kinds and their derivatives with integer orders and complex arguments (method 2). JYV Evaluate a sequence of Bessel functions of the first and second kinds and their derivatives with arbitrary real orders and real arguments. CJYVA Evaluate a sequence of Bessel functions of the first and second kinds and their derivatives with arbitrary real orders and complex arguments (method 1). CJYVB Evaluate a sequence of Bessel functions of the first and second kinds and their derivatives with arbitrary real orders and complex arguments (method 2). CJK Evaluate the coefficients for the asymptotic expansion of Bessel functions for large orders. CJYLV Evaluate Bessel functions of the first and second kinds and their derivatives with a large arbitrary real order and complex arguments. JYZO Evaluate the zeros of the Bessel functions of the first and second kinds and their derivatives. JDZO Evaluate the zeros of the Bessel functions of the first kind and their derivatives. CYZO Evaluate the complex zeros of the Bessel functions of the second kind of order zero and one. LAMN Evaluate a sequence of lambda functions with integer orders and their derivatives. LAMV Evaluate a sequence of lambda functions with arbitrary orders and their derivatives. ***** IK01A Evaluate the zeroth- and first-order modified Bessel functions of the first and second kinds with real arguments. IK01B Evaluate the zeroth- and first-order modified Bessel functions of the first and second kinds with real arguments. IKNA Evaluate a sequence of modified Bessel functions of the first and second kinds and their derivatives with integer orders and real arguments (method 1). IKNB Evaluate a sequence of modified Bessel functions of the first and second kinds and their derivatives with integer orders and real arguments (method 2). CIK01 Evaluate the zeroth- and first-order modified Bessel functions of the first and second kinds and their derivatives with complex arguments. CIKNA Evaluate a sequence of modified Bessel functions of the first and second kinds and their derivatives with integer orders and complex arguments (method 1). CIKNB Evaluate a sequence of modified Bessel functions of the first and second kinds and their derivatives with integer orders and complex arguments (method 2). IKV Evaluate a sequence of modified Bessel functions of the first and second kinds and their derivatives with arbitrary real orders and real arguments. CIKVA Evaluate a sequence of modified Bessel functions of the first and second kinds and their derivatives with arbitrary real orders and complex arguments. CIKVB Evaluate a sequence of modified Bessel functions of the first and second kinds and their derivatives with arbitrary real orders and complex arguments. CIKLV Evaluate modified Bessel functions of the first and second kinds and their derivatives with a large arbitrary real order and complex arguments. CH12N Evaluate a sequence of Hankel functions of the first and second kinds and their derivatives with integer orders and complex arguments. ***** ITJYA Evaluate the integral of Bessel functions J0(t) and Y0(t) from 0 to x using series and asymptotic expansions. ITJYB Evaluate the integral of Bessel functions J0(t) and Y0(t) from 0 to x using polynomial approximations. ITTJYA Evaluate the integral of [1-J0(t)]/t from 0 to x and Y0(t)/t from x to infinity using series and asymptotic expansions. ITTJYB Evaluate the integral of [1-J0(t)]/t from 0 to x and Y0(t)/t from x to infinity using polynomial approximations. ITIKA Evaluate the integral of modified Bessel functions I0(t) and K0(t) from 0 to x using series and asymptotic expansions. ITIKB Evaluate the integral of modified Bessel functions I0(t) and K0(t) from 0 to x using polynomial approximations. ITTIKA Evaluate the integral of [1-I0(t)]/t from 0 to x and K0(t) from x to infinity using series and asymptotic expansions. ITTIKB Evaluate the integral of [1-I0(t)]/t from 0 to x and K0(t) from x to infinity using polynomial approximations. **** SPHJ Evaluate a sequence of spherical Bessel functions of the first kind and their derivatives with integer orders and real arguments. SPHY Evaluate a sequence of spherical Bessel functions of the second kind and their derivatives with integer orders and real arguments. CSPHJY Evaluate a sequence of spherical Bessel functions of the first and second kinds and their derivatives with integer orders and complex arguments. RCTJ Evaluate a sequence of Riccati-Bessel functions and their derivatives of the first kind. RCTY Evaluate a sequence of Riccati-Bessel functions and their derivatives of the second kind. SPHI Evaluate a sequence of modified spherical Bessel functions of the first kind and their derivatives with integer orders and real arguments. SPHK Evaluate a sequence of modified spherical Bessel functions of the second kind and their derivatives with integer orders and real arguments. CSPHIK Evaluate a sequence of modified spherical Bessel functions of the first and second kinds and their derivatives with integer orders and complex arguments. ***** KLVNA Evaluate the Kelvin functions and their derivatives using series and asymptotic expansions. KLVNB Evaluate the Kelvin functions and their derivatives using polynomial approximations. KLVNZO Evaluate the zeros of the Kelvin functions and their derivatives. ***** AIRYA Evaluate the Airy functions and their derivatives by means of Bessel functions. AIRYB Evaluate the Airy functions and their derivatives using the series and asymptotic expansions. ITAIRY Evaluate the integral of the Airy functions. AIRYZO Evaluate the zeros of Airy functions and their derivatives. ***** STVH0 Evaluate the zeroth-order Struve function. STVH1 Evaluate the first-order Struve function. STVHV Evaluate the Struve functions with an arbitrary order. ITSH0 Evaluate the integral of Struve function H0(t) from 0 to x. ITTH0 Evaluate the integral of H0(t)/t from x to infinity. STVL0 Evaluate the zeroth-order modified Struve function. STVL1 Evaluate the first-order modified Struve function. STVLV Evaluate the modified Struve function with an arbitrary order. ITSL0 Evaluate the integral of modified Struve function L0(t) from 0 to x. ***** HYGFX Evaluate the hypergeometric function with real arguments. HYGFZ Evaluate the hypergeometric function with complex arguments. ***** CHGM Evaluate the confluent hypergeometric function M(a,b,x) with real arguments. CCHG Evaluate the confluent hypergeometric function M(a,b,z) with complex arguments. CHGU Evaluate the confluent hypergeometric function U(a,b,x) with real arguments. ***** PBDV Evaluate a sequence of parabolic cylinder functions Dv(x) and their derivatives. PBVV Evaluate a sequence of parabolic cylinder functions Vv(x) and their derivatives. PBWA Evaluate parabolic cylinder functions W(a,+/-x) and their derivatives. CPBDN Evaluate a sequence of parabolic cylinder functions Dn(z) and their derivatives for complex arguments. ***** CVA1 Evaluate a sequence of characteristic values for the Mathieu and modified Mathieu functions. CVA2 Evaluate a specific characteristic value for the Mathieu and modified Mathieu functions. FCOEF Evaluate the expansion coefficients for the Mathieu and modified Mathieu functions. MTU0 Evaluate the Mathieu functions and their derivatives. MTU12 Evaluate the modified Mathieu functions of the first and second kinds and their derivatives. ***** SEGV Evaluate a sequence of characteristic values for spheroidal wave functions. SDMN Evaluate the expansion coefficients d_k^mn for spheroidal wave functions. SCKA Evaluate the expansion coefficients c_2k^mn for spheroidal wave functions (method 1). SCKB Evaluate the expansion coefficients c_2k^mn for spheroidal wave functions (method 2). ASWFA Evaluate the angular spheroidal wave functions of the first kind (method 1). ASWFB Evaluate the angular spheroidal wave functions of the first kind (method 2). RSWFP Evaluate the radial prolate spheroidal wave functions of the first and second kinds. RSWFO Evaluate the radial oblate spheroidal wave functions of the first and second kinds. LPMNS Evaluate a sequence of the associated Legendre functions of the first kind and their derivatives with real arguments for a given order. LQMNS Evaluate a sequence of the associated Legendre functions of the second kind and their derivatives with real arguments for a given order. ***** ERROR Evaluate the error function. CERROR Evaluate the error function with a complex argument. ***** FCS Evaluate the Fresnel Integrals. FFK Evaluate the modified Fresnel integrals. CERZO Evaluate the complex zeros of the error function. FCSZO Evaluate the complex zeros of the Fresnel Integrals. ***** CISIA Evaluate the cosine and sine integrals using their series and asymptotic expansions. CISIB Evaluate the cosine and sine integrals using their rational approximations. ***** COMELP Evaluate the complete elliptic integrals of the first and second kinds. ELIT Evaluate the incomplete elliptic integrals of the first and second kinds. ELIT3 Evaluate the complete and incomplete elliptic integrals of the third kind. JELP Evaluate the Jacobian elliptic functions. ***** E1XA Evaluate the exponential integral E1(x) using its polynomial approximations. E1XB Evaluate the exponential integral E1(x) using its series and continued fraction expressions. E1Z Evaluate the exponential integral E1(z) for complex arguments. ENXA Evaluate a sequence of exponential integrals En(x) (method 1). ENXB Evaluate a sequence of exponential integrals En(x) (method 2). EIX Evaluate the exponential integral Ei(x). plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/libs/specfun/readme.plastimatch000066400000000000000000000001461321604176500276040ustar00rootroot00000000000000From the web site: http://jin.ece.uiuc.edu/routines/routines.html Downloaded on: Friday, Jun 18, 2010 plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/000077500000000000000000000000001321604176500223065ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/CMakeLists.txt000077500000000000000000000053351321604176500250570ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## Welcome to the Plastimatch CMakeLists.txt file ##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src) ##----------------------------------------------------------------------------- ## Add subdirectories ##----------------------------------------------------------------------------- if (PLM_CONFIG_DEBIAN_BUILD) set (PLM_CONFIG_DISABLE_FATM ON) set (PLM_CONFIG_DISABLE_MONDOSHOT ON) endif () if (NOT PLM_CONFIG_DISABLE_FATM) add_subdirectory (fatm) endif () # mondoshot requires plastimatch, WIN32, wx, dcmtk, sqlite3 if (WIN32 AND NOT CYGWIN AND wxWidgets_FOUND AND DCMTK_FOUND AND NOT PLM_CONFIG_DISABLE_MONDOSHOT) add_subdirectory (mondoshot) endif () if (NOT PLM_CONFIG_DISABLE_PLASTIMATCH) if (NOT ITK_FOUND OR NOT DCMTK_FOUND) if (PLM_CONFIG_ENABLE_SUPERBUILD) set (proj plastimatch) if(CMAKE_EXTRA_GENERATOR) set(gen "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}") else() set(gen "${CMAKE_GENERATOR}") endif() set (sb_option_list "") foreach (_var ${sb_cmake_vars}) list (APPEND sb_option_list "-D${_var}=${${_var}}") endforeach () set (sb_dependencies devillard inih lbfgs nkidecompress specfun sqlite3) if (NOT ITK_FOUND) list (APPEND sb_dependencies ITK) endif () if (NOT DCMTK_FOUND) list (APPEND sb_dependencies DCMTK) endif () ExternalProject_Add (${proj} DOWNLOAD_COMMAND "" INSTALL_COMMAND "" SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/plastimatch" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/plastimatch" CMAKE_GENERATOR ${gen} CMAKE_ARGS -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} -DCMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_OSX_SYSROOT:PATH=${CMAKE_OSX_SYSROOT} -DITK_DIR:PATH=${ITK_DIR} -DDCMTK_DIR:PATH=${DCMTK_DIR} -DPLASTIMATCH_VERSION_STRING:STRING=${PLASTIMATCH_VERSION_STRING} ${sb_option_list} DEPENDS ${sb_dependencies} ) else () message (STATUS "Plastimatch will not be built (ITK or DCMTK not found; superbuild disabled)") endif () else () add_subdirectory (plastimatch) endif () endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/000077500000000000000000000000001321604176500246175ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/CHANGELOG.TXT000066400000000000000000000270471321604176500265210ustar00rootroot00000000000000Version 1.7.0 (tag v1.7.0) Mon Dec 18 17:38:55 EST 2017 * Remove reg-2-3 and ise from distribution Version 1.6.7 (tag v1.6.7) Mon Dec 18 17:06:14 EST 2017 * Implement automatic download and build of ITK, DCMTK * Prevent in-source builds * Improve library support: DCTMK 3.6.2, ITK 3.20, Windows OpenMP, Qt5, CUDA 8 * DICOM Series UIDs may be specified on command line * Fix a few MABS command file bugs * Allow loading of 2D images * Last version including reg-2-3 and ise Version 1.6.6 (tag v1.6.6) Wed Oct 11 10:54:34 EDT 2017 * Support for multi-metric registration * Support for multi-planar registration * Support image masks in multi-planar registration * Support for dmap registration metric type * Many dose calculation improvements * DICOM RT Ion plan support * Many other bug fixes Version 1.6.5 (tag v1.6.5) Sun Dec 4 18:07:24 EST 2016 * Improved support for DICOM RT ion plan * Better handling study-wide DICOM metadata * Allow use of system dlib library * XiO import has better support for unequal slice spacing * Improvements to registration GUI Version 1.6.4 (tag v1.6.4) Tue Aug 9 18:15:58 EDT 2016 * Convert to new gitlab host * Windows binary fixes * Allow building DLLs without manifests * Re-enable wed code * Fix incorrect CUDA initialization when not being used * Add lbfgsb_mmax option to registration parameter file Version 1.6.3 (build 5341) Wed Jun 29 17:08:12 EDT 2016 * WiX based windows install * Many proton dose enhancements * Many MABS enhancements * Gamma_gui and register_gui programs * DICOM metadata enhancements * Default MI metric for ITK implementations is now Mattes * Vector fields can now be saved as any ITK format * Multi-DRR options can now use any starting angle and can save details file * Dij matrix warping works again * You can now select gpuid in registration command file * Fix image convert failure for when resampling without supplied xform * Fix image resize crash * Fix for loading ITK volumes with non-zero index attributes * Fix DICOM loading RTDOSE with non-identity direction cosines Version 1.6.2 (build 5130) Tue Jul 28 14:38:04 EDT 2015 * New MABS post-processing feature to fill holes and remove islands * Center of gravity pre-alignment for registration and MABS * Fix subtle bug in gamma computation with mask * Fix bug in Hausdorff calculation with single slice images * Fix crash in vf_invert * Build system fixes for non-intel platforms * Remove dependency on bstrlib Version 1.6.1 (build 5068) Wed May 13 13:26:55 EDT 2015 * Remove dependency on patched ITK library * Implement max avg Hausdorff statistic * Workaround for regression test failures on i386 * Remove obsolete libraries: getopt, dbf, FindCUDA Version 1.6.0 (build 5025) Mon Apr 27 15:26:01 EDT 2015 * Registration supports grid search * Registration supports gradient magnitude * Registration landmarks can now appear in stages * Registration improved ROI support * Registration resolutions can now be subsampled by voxel, mm, or percent * Gamma calculation supports local gamma, interp-search, other improvements * New plastimatch filter command for filtering with gabor, gauss, others * Many MABS updates * Many dose calculation improvements * Fix problem rasterizing tilted structures * Several DICOM fixes * Several parallelization improvements * Run registration in worker thread; allow restartable registrations * Many other bug fixes Version 1.5.16 (build 4659) Sun May 18 16:06:34 EDT 2014 * Many mabs updates * Many proton dose calculation updates * Improve handling of DICOM slope/offset on export * DICOM image loading no longer uses ITK when DCMTK is present * DICOM SRO export fixes * Let plastimatch stats use DICOM input * Let plastimatch gamma work without creating output file * Add noise option to plastimatch synth * Add min_its and convergence_tol options to lbfgsb optimizer Version 1.5.15 (build 4523) Sun Dec 15 14:00:47 EST 2013 * Support for DICOM export of spatial registration object * Fix bug in computing statistics with a mask * Fix two debian bugs Version 1.5.14 (build 4503) Sun Nov 24 16:35:22 EST 2013 * Many MABS improvements, especially atlas selection and configuration * Implement per-stage masking capabilities * Add ITK diff, ldd, sym-ldd demons * Add ITK optimizers FRPR and OnePlusOne * Add MI intensity threshold options * Add ITK normalized mutual information * Add plastimatch dmap command * New fast native Danielsson distance map implementation * Many improvements in wed, dew, and proton_dose * Many DICOM improvements * Add capability to load Elekta XVI format * Fix for important gamma calculation bug Version 1.5.13 (build 4289) Mon May 27 12:46:04 EDT 2013 * DICOM interchange using dcmtk now complete * ITK 4 support now complete * The wed command can now generate beam apertures and range compenators * Better support for Kepler architecture GPUs * Many external API improvements * Internal smart pointer support for plastimatch native types * Bug fixes in mutual information * Bug fixes in hausdorff computation Version 1.5.12 (build 4075) Sun Jan 27 09:19:01 EST 2013 * B-spline support for direction cosines * Alpha version of plastimatch library API * Vector field inverter "vf_invert" now officially supported * Add "adjust" command for changing image intensities * Better support for masks in B-spline registration * Better ITK4 and DCMTK support * Add support for loading Elkta/NKI CBCT format images * Beta version of "mabs" command for atlas-based segmentation * Beta version of "wed" command for water-equivalent pathlength computation * Move dice command into plastimatch executable * Move structure set union command into plastimatch executable * Move sift feature detection command into plastimatch executable * Fix potential divide by zero in B-spline registration * Bug fixes in DVH computation * Bug fixes and speed improvements for B-spline warper * Speed improvements for Dice calculation Version 1.5.11 (build 3637) Sat Jun 9 19:58:20 EDT 2012 * Reorganize code into smaller libraries * Mostly complete support for ITK 4 * Improve performance of native B-spline registration * Convert/warp routine can now import "prefix directories" * Add "plastimatch average" command * Add "plastimatch synth-vf" command * Improve thumbnailer so it can auto window/level and export png or tiff * Improve aperture support in proton dose * Proton dose now uses configuration files * Bug fixes to threshbox, gamma analysis * Better (though still incomplete) dcmtk support * Add viscous as standalone program * Add support to specify study UIDs from command line * Upgrade dlib to 17.46 * Fix bug calling demons stage after translation or rigid stage * Fix memory error resizing ITK B-spline transforms Version 1.5.10 (build 3259) Sat Apr 14 19:18:41 EDT 2012 * Embedded lua-based scripting engine * Final version of sift code * Improved direction-cosine support in B-spline registration * Image masking support for B-spline registration * Fix memory error in vector field warper * Incomplete support of dcmtk 3.6 for dicom file i/o * New synthetic image generators: grid, lung Version 1.5.9 (build 3050) Sat Feb 18 10:10:22 EST 2012 * New auto-4D feature introduced to command file * Attempt to fix big-endian build on debian (yet again) Version 1.5.8 (build 3028) Sat Feb 11 22:32:07 EST 2012 * Attempt to fix big-endian build on debian (again) Version 1.5.7 (build 3020) Mon Feb 6 22:21:36 EST 2012 * Add weighted addition to plastimatch add command * Improve compatibility for CUDA 4.X * Fix bug creating directory when writing bspline xform file * Fix floating point rounding issue in writing DICOM dose Version 1.5.6 (build 2984) Wed Jan 25 22:47:55 EST 2012 * Partial fix for B-spline registration problems when direction cosines are not identity * B-spline warper is now multi-threaded * Fix memory error with large image sizes * New slicer plugin for isodose, dose comparison extraction * Fix bug rasterizing more than eight structures * Fix program abort when putting B-spline stage after demons stage * Fix program abort when writing dicom for images without existing metadata * Add vector field to B-spline converter to xf-convert command * Get metadata from referenced CT if there is no other existing metadata * Option feval_max is now respected when using the liblbfgs optimizer with B-splines * Improve portability to big-endian, unsigned char platforms * Add direction cosines option to resample command * Fix bug where dicom output was not written for fill command * Add panel offset option to FDK reconstructor Version 1.5.5 (build 2868) Mon Oct 31 00:35:29 EDT 2011 * Add support for landmark penalty to B-spline registration * First working version of plastimatch autolabel * Add --xor-contours option for converting DICOM-RT structure sets * Implement a primitive synthetic_vf command * Fix bug where demographics weren't loaded when converting Xio dose * Fix bug where Xio dose was not converted due to version mismatch * Fix bug loading pointsets in txt format Version 1.5.4 (build 2832) Mon Oct 10 00:20:35 EDT 2011 * Include reg-2-3 in default build * Add plastimatch probe command * Add landmark_diff program * Add support for numeric implementation of B-spline regularization * Add support for different image resolutions to Dice * Remove automatic parsing of current directory for dicom images * Early support for optimized histogram binning for mutual information * Early support for reading images with irregular slice spacing * Fix bug in converting between image types, where values were being incorrectly clamped * Fix bug in Nocedal optimizer where wrong answer is returned when optimization ends during partial line search * Fix bug where Nocedal optimizer would run out of memory during initialization of large problems * Fix bug where --fixed option was ignored when resampling vector fields * Fix bug in image resampling between stages of multi-resolution registration * Fix bug with mutual information during multi-resolution registration Version 1.5.3 (build 2678) Sun Aug 14 21:56:51 EDT 2011 * Add support for signed char image type * Add output image type to slicer bspline plugin * Add bspline regularization to slicer bspline plugin * Add ss_list (structure set name) file input/output to slicer dicomrt import/export plugins * Fix/workaround problem with b-spline regularization on images with negative voxel spacing * Fix bug where pixel values were wrapped instead of clamped when converting to a pixel type with smaller range of values * Fix bug where img_out_type field was ignored in registration command file * Remove deprecated brook code Version 1.5.2 (build 2621) Sun Jul 24 21:06:48 EDT 2011 * Fix build problem with cuda * Fix regression on loading mha files without direction cosines Version 1.5.1 (build 2617) * Reg-2-3 code for 2D-3D registration * Slicer plugin enhancements: XFORM warper, synthetic images, DVH display * Early prototype of B-spline regularization * Many bug fixes Version 1.5.0 (build 2498) * CUDA-accelerated mutual information for B-splines * Regularized gaussian landmark splines * Replace cone RBF with Wendland RBF * Better handling of image metadata * Many improvements to image conversion and warping Version 1.4.0 (svn only) * Native grid-aligned B-spline registration (MSE: CUDA, OpenMP, MI: CPU) * Native demons registration (Brook, CPU) * Wrappers for some ITK registration transforms: translation, rigid, affine, B-spline, demons * Global thin-plate spline (ITK), local cone RBF (native) * Multistage registration framework * FDK cone-beam reconstruction (CUDA, OpenMP) * DRR generation (CUDA, OpenMP) * Dicom image import/export, DicomRT structure set import/export * XiO image import, XiO structure set import/export * 3D slicer plugins * Mondoshot screen capture program plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/CMakeLists.txt000066400000000000000000000463021321604176500273640ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## Welcome to the Plastimatch CMakeLists.txt file ##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch) cmake_minimum_required (VERSION 2.8.12) ##----------------------------------------------------------------------------- ## CMake include files ##----------------------------------------------------------------------------- set (CMAKE_MODULE_PATH "${PLM_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) include (PlmMacros) ##----------------------------------------------------------------------------- ## Processor and OS characteristics ## 32-bit or 64-bit machine ## Endian-ness ## Machine precision ## Processor type ##----------------------------------------------------------------------------- include (CheckCharSign) include (CheckEpsilon) include (CheckTypeSize) include (TestBigEndian) check_type_size ("unsigned int" CMAKE_SIZEOF_UINT) check_type_size ("unsigned long" CMAKE_SIZEOF_ULONG) check_type_size ("size_t" CMAKE_SIZEOF_SIZE_T) if (NOT APPLE) if (CMAKE_SIZEOF_VOID_P EQUAL 4) set (MACHINE_IS_32_BIT TRUE) set (MACHINE_IS_64_BIT FALSE) message (STATUS "Machine is 32-bit") else () set (MACHINE_IS_32_BIT FALSE) set (MACHINE_IS_64_BIT TRUE) message (STATUS "Machine is 64-bit") endif () endif () test_big_endian (PLM_BIG_ENDIAN) check_epsilon (MACHINE_EPS) check_char_sign (CHAR_SIGN) message (STATUS "Checking host processor: ${CMAKE_HOST_SYSTEM_PROCESSOR}") message (STATUS "Checking target processor: ${CMAKE_SYSTEM_PROCESSOR}") message (STATUS "Checking epsilon: ${MACHINE_EPS}") message (STATUS "Checking sign of char: ${CHAR_SIGN}") include (CheckIncludeFiles) check_include_files ("stdint.h" HAVE_STDINT_H) check_include_files ("sys/stat.h" HAVE_SYS_STAT_H) ##----------------------------------------------------------------------------- ## Figure out if we should use gdcm or dcmtk ##----------------------------------------------------------------------------- if (DCMTK_DIR AND EXISTS "${DCMTK_DIR}/DCMTKConfig.cmake") find_package (DCMTK NO_MODULE) else () find_package (DCMTK_legacy) endif () set (PLM_DCM_USE_DCMTK 0) set (PLM_DCM_USE_GDCM1 0) set (PLM_DCM_USE_GDCM2 0) if (DCMTK_FOUND) set (PLM_DCM_USE_DCMTK 1) elseif (GDCM_VERSION_2) set (PLM_DCM_USE_GDCM2 1) else () set (PLM_DCM_USE_GDCM1 1) endif () ##----------------------------------------------------------------------------- ## Give a warning for obsolete dicom libraries ##----------------------------------------------------------------------------- # If the user only has gdcm 2.x, give a warning if (PLM_DCM_USE_GDCM2) message (WARNING "Plastimatch is being built with GDCM 2.X. DICOM-RT functions are disabled.") elseif (PLM_DCM_USE_GDCM1) message (WARNING "Plastimatch is being built with GDCM 1.X. Certain features of DICOM-RT are disabled.") endif () ##----------------------------------------------------------------------------- ## dlib ##----------------------------------------------------------------------------- if (PLM_PREFER_SYSTEM_DLIB) # Use this version if you want to use the internal cmake find. # The internal version has issue finding the correct BLAS library # for Debian, so we prefer Debian version. # find_package (Dlib) # However, the Debian cmake find is broken. Its breakage can # be worked around by setting dlib_BINARY_DIR. set (dlib_BINARY_DIR 1) find_package (dlib QUIET) endif () set (DLIB_HAVE_LIBRARY FALSE) if (dlib_FOUND) set (DLIB_INCLUDE_DIR ${dlib_INCLUDE_DIR}) set (DLIB_LIBRARIES ${dlib_LIBRARIES}) set (DLIB_FOUND TRUE) if (DLIB_LIBRARIES) set (DLIB_HAVE_LIBRARY TRUE) endif () else () set (DLIB_INCLUDE_DIR "${PLM_SOURCE_DIR}/libs/dlib-19.1") set (DLIB_LIBRARIES "") endif () ##----------------------------------------------------------------------------- ## ransac ##----------------------------------------------------------------------------- set (RANSAC_INCLUDE_DIRS "${PLM_SOURCE_DIR}/libs/ransac" "${PLM_SOURCE_DIR}/libs/ransac/Common") ##----------------------------------------------------------------------------- ## ITK ##----------------------------------------------------------------------------- set (PLM_CONFIG_USE_PATCHED_ITK 0) find_package (ITK REQUIRED) include (HandleITK) ##----------------------------------------------------------------------------- ## Hack for superbuild ##----------------------------------------------------------------------------- link_directories (${PLM_BINARY_DIR}) ##----------------------------------------------------------------------------- ## Libraries ##----------------------------------------------------------------------------- set (PLASTIMATCH_LIBS plmclp # plmscript plmsegment plmregister plmreconstruct plmdose plmutil plmbase plmsys ${ITK_LIBRARIES} devillard nkidecompress # lua ${MATH_LIB} ) if (CUDA_FOUND AND NOT PLM_USE_GPU_PLUGINS) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} plmcuda) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} plmreconstructcuda) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} plmregistercuda) endif () if (DCMTK_FOUND) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} ${DCMTK_LIBRARIES}) endif () if (DLIB_LIBRARIES) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} ${DLIB_LIBRARIES}) endif () if (FFTW_FOUND) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} ${FFTW_LIBRARIES}) endif () if (KAZE_FOUND) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} ${KAZE_LIBRARIES}) endif () if (LIBDL_FOUND) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} dl) endif () if (NLOPT_FOUND) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} ${NLOPT_LIBRARIES}) endif () if (OPENCL_FOUND) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} plmopencl) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} ${OPENCL_LIBRARIES}) endif () if (OPENMP_FOUND) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} ${OPENMP_LIBRARIES}) endif () if (SPECFUN_FOUND) set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} specfun) endif () ### Let QT applications add this themselves #if (QT4_FOUND) # set (PLASTIMATCH_LIBS ${PLASTIMATCH_LIBS} ${QT_LIBRARIES}) #endif () ##----------------------------------------------------------------------------- ## Linker flags ##----------------------------------------------------------------------------- set (PLASTIMATCH_LDFLAGS "${OPENMP_LDFLAGS}") if (PLM_USE_GPU_PLUGINS AND WIN32 AND NOT CYGWIN AND NOT MINGW) set (PLASTIMATCH_LDFLAGS "${PLASTIMATCH_LDFLAGS} /DELAYLOAD:plmregistercuda.dll /DELAYLOAD:plmreconstructcuda.dll") endif () if (PLM_CONFIG_NOMANIFEST AND WIN32) set (PLASTIMATCH_LDFLAGS "${PLASTIMATCH_LDFLAGS} /MANIFEST:NO") endif () ##----------------------------------------------------------------------------- ## Include directories ##----------------------------------------------------------------------------- include_directories (BEFORE ${CMAKE_BINARY_DIR}) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/base) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/cli) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/clp) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/dose) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/cuda) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/opencl) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/qt) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/reconstruct) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/reconstruct/cuda) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/register) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/register/cuda) # GCS 2013-09-11. Disable scripting, because it doesn't yet support # smart pointers for registration. # include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/script) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/segment) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/sys) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/util) include_directories (BEFORE ${CMAKE_CURRENT_BINARY_DIR}) include_directories (AFTER ${ITK_INCLUDE_DIRS}) include_directories (AFTER ${PLM_SOURCE_DIR}/libs/demons_itk_insight) include_directories (AFTER ${PLM_SOURCE_DIR}/libs/demons_itk_insight/DiffeomorphicDemons) include_directories (AFTER ${PLM_SOURCE_DIR}/libs/demons_itk_insight/FastSymmetricForces) include_directories (AFTER ${PLM_SOURCE_DIR}/libs/demons_itk_insight/LOGDomainDemons) include_directories (AFTER ${PLM_SOURCE_DIR}/libs/nSIFT) include_directories (AFTER ${DLIB_INCLUDE_DIR}) include_directories (AFTER ${LIBLBFGS_INCLUDE_DIR}) include_directories (AFTER ${MSINTTYPES_INCLUDE_DIR}) include_directories (AFTER ${RANSAC_INCLUDE_DIRS}) if (${PLM_CONFIG_USE_PATCHED_ITK}) include_directories (AFTER ${CMAKE_SOURCE_DIR}/libs/itk-3.20.0) endif () if (CUDA_FOUND) include_directories (AFTER ${CUDA_INCLUDE_DIRS}) endif () if (DCMTK_FOUND) include_directories (AFTER ${DCMTK_INCLUDE_DIRS}) endif () if (FFTW_FOUND) include_directories (BEFORE ${FFTW_INCLUDE_DIR}) link_directories (${FFTW_DIR}) endif () if (KAZE_FOUND) include_directories (AFTER ${KAZE_INCLUDE_DIR}) endif () if (MATLAB_FOUND) include_directories (AFTER ${MATLAB_INCLUDE_DIRS}) endif () if (NLOPT_FOUND) include_directories (AFTER ${NLOPT_INCLUDE_DIR}) endif () if (OPENCL_FOUND) include_directories (BEFORE ${OPENCL_INCLUDE_DIRS}) endif () if (PANTHEIOS_FOUND) include_directories (AFTER ${STLSOFT_INCLUDE_DIR}) include_directories (AFTER ${PANTHEIOS_INCLUDE_DIR}) endif () #if (QT4_FOUND) # if (QT_QTGUI_FOUND) # include_directories (AFTER ${QT_QTGUI_INCLUDE_DIR}) # endif () # if (QT_QTSQL_FOUND) # include_directories (AFTER ${QT_QTSQL_INCLUDE_DIR}) # endif () #endif () if (RAPIDJSON_FOUND) include_directories (AFTER ${RAPIDJSON_INCLUDE_DIR}) endif () if (SQLITE_FOUND) include_directories (AFTER ${SQLITE_INCLUDE_DIR}) endif () if (LIBYAML_FOUND) include_directories (AFTER ${LIBYAML_INCLUDE_DIR}) endif () ##----------------------------------------------------------------------------- ## CONFIGURE INCLUDE FILES ##----------------------------------------------------------------------------- configure_file (${CMAKE_CURRENT_SOURCE_DIR}/sys/plm_config.h.in ${CMAKE_BINARY_DIR}/plm_config.h) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/sys/plm_version.h.in ${CMAKE_BINARY_DIR}/plm_version.h) ##----------------------------------------------------------------------------- ## Option to generate .clang_complete for hip Vim users using clang_complete ##----------------------------------------------------------------------------- if (PLM_CONFIG_CLANG_COMPLETE) get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES) set (file_clang_complete "${CMAKE_SOURCE_DIR}/src/plastimatch/.clang_complete") foreach (arg ${inc_dirs}) set (inc_args "${inc_args} -I${arg}\n") endforeach () file (WRITE "${file_clang_complete}" "${inc_args}") message (STATUS "Generated ${file_clang_complete}") endif () ##----------------------------------------------------------------------------- ## Do we have prerequisites for viscous code? ##----------------------------------------------------------------------------- set (PLM_BUILD_VISCOUS FALSE) if (NOT PLM_CONFIG_DISABLE_VISCOUS AND CUDA_FOUND AND CUDA_SDK_ROOT_DIR AND THRUST_FOUND) set (PLM_BUILD_VISCOUS TRUE) endif () ## Specify which libraries of plastimatch should be built if (PLM_CONFIG_LIBRARY_BUILD) else () set (PLMLIB_CONFIG_ENABLE_CLI true) set (PLMLIB_CONFIG_ENABLE_CLP true) set (PLMLIB_CONFIG_ENABLE_DOSE true) set (PLMLIB_CONFIG_ENABLE_QT true) set (PLMLIB_CONFIG_ENABLE_RECONSTRUCT true) set (PLMLIB_CONFIG_ENABLE_REGISTER true) # set (PLMLIB_CONFIG_ENABLE_SCRIPT true) set (PLMLIB_CONFIG_ENABLE_SEGMENT true) set (PLMLIB_CONFIG_ENABLE_STANDALONE true) set (PLMLIB_CONFIG_ENABLE_TEST true) endif () if (PLMLIB_CONFIG_ENABLE_REGISTER OR PLMLIB_CONFIG_ENABLE_RECONSTRUCT) set (PLMLIB_CONFIG_ENABLE_CUDA true) set (PLMLIB_CONFIG_ENABLE_OPENCL true) endif () ##----------------------------------------------------------------------------- ## SETUP IMPORTANT LOCATIONS ##----------------------------------------------------------------------------- # Offer the user the choice of overriding the installation directories set (PLM_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") set (PLM_INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") set (PLM_INSTALL_INCLUDE_DIR include/plastimatch CACHE PATH "Installation directory for header files") if (WIN32 AND NOT CYGWIN) set (DEF_INSTALL_CMAKE_DIR CMake) else() set (DEF_INSTALL_CMAKE_DIR lib/cmake/plastimatch) endif() set (PLM_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") mark_as_advanced ( PLM_INSTALL_LIB_DIR PLM_INSTALL_BIN_DIR PLM_INSTALL_INCLUDE_DIR PLM_INSTALL_CMAKE_DIR) ## Specify which include directories are needed when ## compiling code that links to the libraries set (PLASTIMATCH_INCLUDE_DIRECTORIES "") if (NOT PLM_PACKAGE_LEGACY_CMAKE_CONFIG) list (APPEND PLASTIMATCH_INCLUDE_DIRECTORIES $ ) list (APPEND PLASTIMATCH_INCLUDE_DIRECTORIES $ $ $ $ $ $ ) if (PLMLIB_CONFIG_ENABLE_REGISTER) list (APPEND PLASTIMATCH_INCLUDE_DIRECTORIES $ $ ) endif () if (PLMLIB_CONFIG_ENABLE_SEGMENT) list (APPEND PLASTIMATCH_INCLUDE_DIRECTORIES $ ) endif () if (PLMLIB_CONFIG_ENABLE_DOSE) list (APPEND PLASTIMATCH_INCLUDE_DIRECTORIES $ ) endif () endif () # Core add_subdirectory(base) add_subdirectory(sys) add_subdirectory(util) # Optional if (PLMLIB_CONFIG_ENABLE_CLI) add_subdirectory(cli) endif () if (PLMLIB_CONFIG_ENABLE_CLP) add_subdirectory(clp) endif () if (CUDA_FOUND AND PLMLIB_CONFIG_ENABLE_CUDA) add_subdirectory(cuda) endif () if (PLMLIB_CONFIG_ENABLE_DOSE) add_subdirectory(dose) endif () if (OPENCL_FOUND AND PLMLIB_CONFIG_ENABLE_OPENCL) add_subdirectory(opencl) endif () if (QT_FOUND AND PLMLIB_CONFIG_ENABLE_QT) add_subdirectory(qt) endif () if (PLMLIB_CONFIG_ENABLE_RECONSTRUCT) add_subdirectory(reconstruct) endif () if (PLMLIB_CONFIG_ENABLE_REGISTER) add_subdirectory(register) endif () #if (PLMLIB_CONFIG_ENABLE_SCRIPT) # add_subdirectory(script) #endif () if (PLMLIB_CONFIG_ENABLE_SEGMENT) add_subdirectory(segment) endif () if (PLMLIB_CONFIG_ENABLE_STANDALONE) add_subdirectory(standalone) endif () if (PLMLIB_CONFIG_ENABLE_TEST) add_subdirectory(test) endif () # Create a list of targets to be exported. These are used by applications # which link to plastimatch libraries. set (EXPORT_TARGET_LIST plmsys plmbase devillard nkidecompress plmutil) if (PLMLIB_CONFIG_ENABLE_DOSE) set (EXPORT_TARGET_LIST ${EXPORT_TARGET_LIST} specfun plmdose) endif () if (PLMLIB_CONFIG_ENABLE_REGISTER) set (EXPORT_TARGET_LIST ${EXPORT_TARGET_LIST} lbfgs plmregister) endif () if (PLMLIB_CONFIG_ENABLE_RECONSTRUCT) set (EXPORT_TARGET_LIST ${EXPORT_TARGET_LIST} plmreconstruct) endif () if (CUDA_FOUND) if (PLMLIB_CONFIG_ENABLE_REGISTER OR PLMLIB_CONFIG_ENABLE_RECONSTRUCT) set (EXPORT_TARGET_LIST ${EXPORT_TARGET_LIST} plmcuda) endif () if (PLMLIB_CONFIG_ENABLE_REGISTER) set (EXPORT_TARGET_LIST ${EXPORT_TARGET_LIST} plmregistercuda) endif () if (PLMLIB_CONFIG_ENABLE_RECONSTRUCT) set (EXPORT_TARGET_LIST ${EXPORT_TARGET_LIST} plmreconstructcuda) endif () endif () if (OPENCL_FOUND) if (PLMLIB_CONFIG_ENABLE_REGISTER OR PLMLIB_CONFIG_ENABLE_RECONSTRUCT) set (EXPORT_TARGET_LIST ${EXPORT_TARGET_LIST} plmopencl) endif () endif () if (PLMLIB_CONFIG_ENABLE_SEGMENT) set (EXPORT_TARGET_LIST ${EXPORT_TARGET_LIST} plmsegment) endif () #if (PLMLIB_CONFIG_ENABLE_SCRIPT) # set (EXPORT_TARGET_LIST ${EXPORT_TARGET_LIST} lua plmscript) #endif () # Create the configuration files used by client applications if (PLM_PACKAGE_LEGACY_CMAKE_CONFIG) export (TARGETS ${EXPORT_TARGET_LIST} FILE "${CMAKE_BINARY_DIR}/PlastimatchLibraryDepends.cmake") # Help cmake find the PlastimatchConfig.cmake in the build directory if (NOT ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 2.8) export (PACKAGE Plastimatch) endif () # Create PlastimatchBuildTreeSettings.cmake for the use from the build tree file (RELATIVE_PATH CONF_REL_INCLUDE_DIR "${PLM_INSTALL_CMAKE_DIR}" "${PLM_INSTALL_INCLUDE_DIR}") configure_file ( "${PROJECT_SOURCE_DIR}/cmake/PlastimatchConfig-Legacy.cmake.in" "${CMAKE_BINARY_DIR}/PlastimatchConfig.cmake" @ONLY) configure_file ( "${PROJECT_SOURCE_DIR}/cmake/PlastimatchBuildTreeSettings.cmake.in" "${CMAKE_BINARY_DIR}/PlastimatchBuildTreeSettings.cmake" @ONLY) # Install the PlastimatchConfig.cmake file install (FILES "${CMAKE_BINARY_DIR}/PlastimatchConfig.cmake" DESTINATION "${PLM_INSTALL_CMAKE_DIR}" # COMPONENT dev ) # Install the export set for use with the install-tree install (EXPORT PlastimatchLibraryDepends DESTINATION "${PLM_INSTALL_CMAKE_DIR}" # COMPONENT dev ) else (PLM_PACKAGE_LEGACY_CMAKE_CONFIG) ## GCS: This is not working #if (COMMENTOUT) include (CMakePackageConfigHelpers) # Make the version file write_basic_package_version_file ( "${CMAKE_CURRENT_BINARY_DIR}/PlastimatchConfigVersion.cmake" VERSION ${PLASTIMATCH_VERSION_STRING} COMPATIBILITY AnyNewerVersion ) # Make the targets file if (NOT ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 3.0) export (EXPORT PlastimatchLibraryDepends FILE "${CMAKE_BINARY_DIR}/PlastimatchLibraryDepends.cmake" ) endif () # Make the config file configure_file ( "${PROJECT_SOURCE_DIR}/cmake/PlastimatchConfig.cmake.in" "${CMAKE_BINARY_DIR}/PlastimatchConfig.cmake" @ONLY) # Install the files install (EXPORT PlastimatchLibraryDepends DESTINATION "${PLM_INSTALL_CMAKE_DIR}" ) install (FILES "${CMAKE_BINARY_DIR}/PlastimatchConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/PlastimatchConfigVersion.cmake" DESTINATION "${PLM_INSTALL_CMAKE_DIR}" COMPONENT Devel ) #endif (COMMENTOUT) endif (PLM_PACKAGE_LEGACY_CMAKE_CONFIG) ##----------------------------------------------------------------------------- ## DOXYGEN ##----------------------------------------------------------------------------- if (DOXYGEN_FOUND) file (MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/doc") configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) add_custom_target (doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/doc" COMMENT "Generating API documentation with Doxygen" VERBATIM ) endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/COPYRIGHT.TXT000066400000000000000000000017111321604176500265700ustar00rootroot00000000000000Plastimatch is copyrighted software. Copyright (c) 2004-2011 Massachusetts General Hospital All rights reserved You can freely use and distribute plastimatch under a BSD-style license. See LICENSE.TXT for details ------------------------------------------------------------------------ RTOG format routines (exchkeys.h) These routines were developed by John Matthews of the RTOG. They were developed using NCI funding, and are meant to be used by vendors for converting to and from RTOG format. http://itc.wustl.edu/Exchcode.html ------------------------------------------------------------------------ GDCM (gdcm_series_helper_2.cxx gdcm_series_helper_2.h) Starting with gdcm 2.0.11, GDCM, Grassroots DICOM is distributed under the new simplified BSD license, approved by the Open Source Initiative (OSI) * http://www.opensource.org/licenses/bsd-license.php Presumably the new BSD license can be used with the 1.x series as well. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/Doxyfile.in000066400000000000000000002244711321604176500267440ustar00rootroot00000000000000# Doxyfile 1.7.6.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = "plastimatch" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the # same symbol appear multiple times in the code, doxygen keeps a cache of # pre-resolved symbols. If the cache is too small doxygen will become slower. # If the cache is too large, memory is wasted. The cache size is given by this # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES #EXTRACT_ALL = NO EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. #EXTRACT_STATIC = NO EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. #EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. #HIDE_UNDOC_CLASSES = NO HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @CMAKE_CURRENT_SOURCE_DIR@/base @CMAKE_CURRENT_SOURCE_DIR@/sys @CMAKE_CURRENT_SOURCE_DIR@/util # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # style sheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the # mathjax.org site, so you can quickly see the result without installing # MathJax, but it is strongly recommended to install a local copy of MathJax # before deployment. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. #MACRO_EXPANSION = NO MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = \ "PLM_GET(type, name)=const type get_##name (type)" \ "PLM_SET(type, name)=void set_##name (const type&)" \ "PLM_SET(type, name)=void set_##name (const type&)" \ "PLM_GET_SET(type, name)=/*! \brief get_##name */const type get_##name (type);/*! \brief set_##name */void set_##name (const type&)" # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/LICENSE.TXT000066400000000000000000000136561321604176500263150ustar00rootroot00000000000000Plastimatch Software License ("Software License") Version 1.0 This Software License covers downloads from the Plastimatch project ("Plastimatch") maintained by The General Hospital Corporation Inc. ("MGH"). Your downloading, copying, modifying, displaying, distributing or use of any software and/or data from Plastimatch (collectively, the "Software") constitutes acceptance of all of the terms and conditions of this Software License. If you do not agree to such terms and conditions, you have no right to download, copy, modify, display, distribute or use the Software. 1. As used in this Software License, "you" means the individual downloading and/or using, reproducing, modifying, displaying and/or distributing the Software and the institution or entity which employs or is otherwise affiliated with such individual in connection therewith. The MGH hereby grants you, with right to sublicense, with respect to MGH's rights in the software, and data, if any, which is the subject of this Software License (collectively, the "Software"), a royalty-free, non-exclusive license to use, reproduce, make derivative works of, display and distribute the Software, provided that: (a) you accept and adhere to all of the terms and conditions of this Software License; (b) in connection with any copy of or sublicense of all or any portion of the Software, all of the terms and conditions in this Software License shall appear in and shall apply to such copy and such sublicense, including without limitation all source and executable forms and on any user documentation, prefaced with the following words: "All or portions of this licensed product (such portions are the "Software") have been obtained under license from MGH and are subject to the following terms and conditions:" (c) you preserve and maintain all applicable attributions, copyright notices and licenses included in or applicable to the Software; (d) modified versions of the Software must be clearly identified and marked as such, and must not be misrepresented as being the original Software; and (e) you consider making, but are under no obligation to make, the source code of any of your modifications to the Software freely available to others on an open source basis. 2. The license granted under this Software License includes without limitation the right to (i) incorporate the Software into proprietary programs (subject to any restrictions applicable to such programs), (ii) add your own copyright statement to your modifications of the Software, and (iii) provide additional or different license terms and conditions in your sublicenses of modifications of the Software; provided that in each case your use, reproduction or distribution of such modifications otherwise complies with the conditions stated in this Software License. 3. This Software License does not grant any rights with respect to third party software, except those rights that MGH has been authorized by a third party to grant to you, and accordingly you are solely responsible for (i) obtaining any permissions from third parties that you need to use, reproduce, make derivative works of, display and distribute the Software, and (ii) informing your sublicensees, including without limitation your end-users, of their obligations to secure any such required permissions. 4. The Software has been designed for research purposes only and has not been reviewed or approved by the Food and Drug Administration or by any other agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL APPLICATIONS ARE NEITHER RECOMMENDED NOR ADVISED. Any commercialization of the Software is at the sole risk of the party or parties engaged in such commercialization. You further agree to use, reproduce, make derivative works of, display and distribute the Software in compliance with all applicable governmental laws, regulations and orders, including without limitation those relating to export and import control. 5. The Software is provided "AS IS" and neither MGH nor any contributor to the software (each a "Contributor") shall have any obligation to provide maintenance, support, updates, enhancements or modifications thereto. MGH AND ALL CONTRIBUTORS SPECIFICALLY DISCLAIM ALL EXPRESS AND IMPLIED WARRANTIES OF ANY KIND INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL MGH OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY RELATED TO THE SOFTWARE, EVEN IF MGH OR ANY CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM EXTENT NOT PROHIBITED BY LAW OR REGULATION, YOU FURTHER ASSUME ALL LIABILITY FOR YOUR USE, REPRODUCTION, MAKING OF DERIVATIVE WORKS, DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE AND AGREE TO INDEMNIFY AND HOLD HARMLESS MGH AND ALL CONTRIBUTORS FROM AND AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS ARISING THEREFROM. 6. None of the names, logos or trademarks of MGH or any of MGH's affiliates or any of the Contributors, or any funding agency, may be used to endorse or promote products produced in whole or in part by operation of the Software or derived from or based on the Software without specific prior written permission from the applicable party. 7. Any use, reproduction or distribution of the Software which is not in accordance with this Software License shall automatically revoke all rights granted to you under this Software License and render Paragraphs 1 and 2 of this Software License null and void. 8. This Software License does not grant any rights in or to any intellectual property owned by MGH or any Contributor except those rights expressly granted hereunder. plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/000077500000000000000000000000001321604176500255315ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/CMakeLists.txt000077500000000000000000000165061321604176500303040ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_base) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/plmbase_config.h.in ${CMAKE_BINARY_DIR}/plmbase_config.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (AFTER ${NKIDECOMPRESS_INCLUDE_DIR}) ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (PLMBASE_LIBRARY_SRC aperture.cxx aperture.h astroid_dose.cxx astroid_dose.h bspline_interpolate.cxx bspline_interpolate.h bspline_warp.cxx bspline_warp.h bspline_xform.cxx bspline_xform.h bspline_xform_legacy.cxx bspline_xform_legacy.h clamp.h cxt_extract.cxx cxt_extract.h cxt_io.cxx cxt_io.h dicom_probe.cxx dicom_probe.h dicom_util.cxx dicom_util.h dicom.dic # How to make sure this gets installed? direction_cosines.cxx direction_cosines.h direction_matrices.cxx direction_matrices.h exchkeys.cxx float_pair_list.cxx float_pair_list.h gaussian.cxx gaussian.h hnd_io.cxx hnd_io.h hnd_io_p.h interpolate.cxx interpolate.h interpolate_macros.h itkAndConstantToImageFilter.h itkClampCastImageFilter.txx itkClampCastImageFilter.h itk_bbox.cxx itk_bbox.h itk_dicom_load.cxx itk_dicom_load.h itk_dicom_save.cxx itk_dicom_save.h itk_directions.cxx itk_directions.h itk_image.cxx itk_image.h itk_image_accumulate.cxx itk_image_accumulate.h itk_image_cast.cxx itk_image_cast.h itk_image_clone.cxx itk_image_clone.h # itk_image_conv.cxx (broken) itk_image_create.cxx itk_image_create.h itk_image_load.txx itk_image_load.h itk_image_load_char.cxx itk_image_load_double.cxx itk_image_load_float.cxx itk_image_load_int32.cxx itk_image_load_short.cxx itk_image_load_uchar.cxx itk_image_load_uint32.cxx itk_image_load_ushort.cxx itk_image_load_vec.cxx itk_image_origin.cxx itk_image_origin.h itk_image_region.cxx itk_image_region.h itk_image_save.cxx itk_image_save.h itk_image_scale.cxx itk_image_scale.h itk_image_stats.cxx itk_image_stats.h itk_image_type.h itk_metadata.cxx itk_metadata.h itk_point.h itk_pointset.cxx itk_pointset.h itk_resample.cxx itk_resample.h itk_volume_header.cxx itk_volume_header.h itk_warp.cxx itk_warp.h make_string.h mc_dose.cxx mc_dose.h metadata.cxx metadata.h mha_io.cxx mha_io.h nki_io.cxx nki_io.h parameter_parser.cxx parameter_parser.h plm_file_format.cxx plm_file_format.h plm_image.cxx plm_image.h plm_image_p.h plm_image_convert.cxx plm_image_header.cxx plm_image_header.h plm_image_set.cxx plm_image_set.h plm_image_type.cxx plm_image_type.h plm_itk.h plm_uid_prefix.h plm_warp.cxx plm_warp.h pointset.cxx pointset.h pointset_warp.cxx pointset_warp.h proj_image.cxx proj_image.h proj_image_dir.cxx proj_image_dir.h proj_matrix.cxx proj_matrix.h proj_volume.cxx proj_volume.h pwlut.cxx pwlut.h rasterize_slice.cxx rasterize_slice.h rasterizer.cxx rasterizer.h raw_pointset.cxx raw_pointset.h ray_data.h ray_trace_exact.cxx ray_trace_callback.h ray_trace_probe.cxx ray_trace_probe.h ray_trace_uniform.cxx rpl_volume.cxx rpl_volume.h rpl_volume_lut.cxx rpl_volume_lut.h rtds_dcmtk.cxx rtds_gdcm.cxx rt_study.cxx rt_study.h rt_study_p.h rt_study_metadata.cxx rt_study_metadata.h rtog_io.cxx rtss.cxx rtss.h rtss_contour.cxx rtss_contour.h rtss_roi.cxx rtss_roi.h rtplan.cxx rtplan.h rtplan_beam.cxx rtplan_beam.h rtplan_control_pt.cxx rtplan_control_pt.h segmentation.cxx segmentation.h slice_extract.cxx slice_extract.h slice_list.cxx slice_list.h ss_img_extract.cxx ss_img_extract.h ss_list_io.cxx ss_list_io.h threading.h thumbnail.cxx thumbnail.h vf.cxx vf.h vf_convolve.cxx vf_convolve.h vf_jacobian.cxx vf_jacobian.h vf_stats.cxx vf_stats.h volume.cxx volume.h volume_boundary_behavior.h volume_conv.cxx volume_conv.h volume_fill.cxx volume_fill.h volume_gaussian.cxx volume_gaussian.h volume_grad.cxx volume_grad.h volume_header.cxx volume_header.h volume_limit.cxx volume_limit.h volume_macros.h volume_resample.cxx volume_resample.h volume_stats.cxx volume_stats.h xform.cxx xform.h xform_convert.cxx xform_convert.h xform_legacy.cxx xform_legacy.h xform_point.cxx xform_point.h xio_ct.cxx xio_ct.h xio_ct_transform.cxx xio_ct_transform.h xio_demographic.cxx xio_demographic.h xio_dir.cxx xio_dir.h xio_dose.cxx xio_dose.h xio_patient.cxx xio_patient.h xio_plan.cxx xio_plan.h xio_structures.cxx xio_structures.h xio_studyset.cxx xio_studyset.h xpm.cxx xpm.h xpm_p.h ) if (PLM_DCM_USE_GDCM1) set (PLMBASE_LIBRARY_SRC ${PLMBASE_LIBRARY_SRC} gdcm1_dose.cxx gdcm1_dose.h gdcm1_file.cxx gdcm1_file.h gdcm1_rdd.cxx gdcm1_rdd.h gdcm1_rtss.cxx gdcm1_rtss.h gdcm1_series.cxx gdcm1_series.h gdcm1_series_helper_2.cxx gdcm1_series_helper_2.h gdcm1_util.cxx gdcm1_util.h ) endif () if (PLM_DCM_USE_GDCM2) set (PLMBASE_LIBRARY_SRC ${PLMBASE_LIBRARY_SRC} gdcm2_util.cxx gdcm2_util.h ) endif () if (PLM_DCM_USE_DCMTK) set (PLMBASE_LIBRARY_SRC ${PLMBASE_LIBRARY_SRC} dcmtk_config.h dcmtk_file.cxx dcmtk_file.h dcmtk_image.cxx dcmtk_metadata.cxx dcmtk_metadata.h dcmtk_module.cxx dcmtk_module.h dcmtk_rdd.cxx dcmtk_rdd.h dcmtk_rtdose.cxx dcmtk_rtdose.h dcmtk_rtss.cxx dcmtk_rtss.h dcmtk_rtplan.cxx dcmtk_rtplan.h dcmtk_rt_study.cxx dcmtk_rt_study.h dcmtk_rt_study_p.cxx dcmtk_rt_study_p.h dcmtk_series.cxx dcmtk_series.h dcmtk_series_map.h dcmtk_sro.cxx dcmtk_sro.h dcmtk_uid.cxx dcmtk_uid.h dcmtk_util.cxx dcmtk_util.h ) endif () set (PLMBASE_LIBRARY_HEADERS "${CMAKE_BINARY_DIR}/plmbase_config.h" ) foreach (ARG ${PLMBASE_LIBRARY_SRC}) string (REGEX MATCH ".*\\.h$" TMP "${ARG}") if (TMP) list (APPEND PLMBASE_LIBRARY_HEADERS "${TMP}") endif () endforeach () ##----------------------------------------------------------------------------- ## LIBRARY DEPENDENCIES ##----------------------------------------------------------------------------- set (PLMBASE_LIBRARY_DEPENDENCIES ${ITK_LIBRARIES} nkidecompress plmsys ) if (DCMTK_FOUND) set (PLMBASE_LIBRARY_DEPENDENCIES ${PLMBASE_LIBRARY_DEPENDENCIES} ${DCMTK_LIBRARIES}) endif () ##----------------------------------------------------------------------------- ## SPECIAL BUILD RULES: OpenMP & SSE2 ##----------------------------------------------------------------------------- if (OPENMP_FOUND) set (PLMBASE_LIBRARY_LDFLAGS "${OPENMP_LDFLAGS}") set_source_files_properties (bspline_warp.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) set_source_files_properties (volume_conv.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) endif () if (SSE2_FOUND) plm_set_sse2_flags (bspline_warp.cxx) endif () ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- plm_add_library ( plmbase "${PLMBASE_LIBRARY_SRC}" "${PLMBASE_LIBRARY_DEPENDENCIES}" "${PLMBASE_LIBRARY_LDFLAGS}" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "${PLMBASE_LIBRARY_HEADERS}" ) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/aperture.cxx000077500000000000000000000302261321604176500301120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "aperture.h" #include "plm_image.h" class Aperture_private { public: Aperture_private () { distance = 800; dim[0] = 10; dim[1] = 10; center[0] = 4.5; center[1] = 4.5; spacing[0] = 1; spacing[1] = 1; } Aperture_private (const Aperture_private* app) { distance = app->distance; dim[0] = app->dim[0]; dim[1] = app->dim[1]; center[0] = app->center[0]; center[1] = app->center[1]; spacing[0] = app->spacing[0]; spacing[1] = app->spacing[1]; } public: Plm_image::Pointer aperture_image; Plm_image::Pointer range_compensator_image; double distance; plm_long dim[2]; double center[2]; double spacing[2]; }; Aperture::Aperture () { this->d_ptr = new Aperture_private; /* The aperture and the range compensator are inizialized */ this->allocate_aperture_images(); this->vup[0] = 0.0; this->vup[1] = 0.0; this->vup[2] = 1.0; this->pdn[0] = 0.0; this->pdn[1] = 0.0; this->pdn[2] = -1.0; this->prt[0] = 0.0; this->prt[1] = 1.0; this->prt[2] = 0.0; //memset (this->ic, 0, 2*sizeof (double)); memset (this->ic_room, 0, 3*sizeof (double)); memset (this->ul_room, 0, 3*sizeof (double)); memset (this->incr_r, 0, 3*sizeof (double)); memset (this->incr_c, 0, 3*sizeof (double)); } Aperture::Aperture (const Aperture::Pointer& ap) { this->d_ptr = new Aperture_private (ap->d_ptr); /* The aperture and the range compensator are initialized */ this->allocate_aperture_images(); vec3_copy (this->vup, ap->vup); vec3_copy (this->pdn, ap->pdn); vec3_copy (this->prt, ap->prt); vec3_copy (this->ic_room, ap->ic_room); vec3_copy (this->ul_room, ap->ul_room); vec3_copy (this->incr_r, ap->incr_r); vec3_copy (this->incr_c, ap->incr_c); Volume::Pointer ap_tmp = ap->get_aperture_volume(); unsigned char* ap_tmp_img = (unsigned char*) ap_tmp->img; Volume::Pointer rc_tmp = ap->get_range_compensator_volume(); float* rc_tmp_img = (float*) rc_tmp->img; unsigned char* ap_img = (unsigned char*) this->get_aperture_volume()->img; float* rc_img = (float*) this->get_range_compensator_volume()->img; for (int i = 0; i < d_ptr->dim[0] * d_ptr->dim[1]; i++) { ap_img[i] = ap_tmp_img[i]; rc_img[i] = rc_tmp_img[i]; } } Aperture::~Aperture () { delete this->d_ptr; } double Aperture::get_distance () const { return d_ptr->distance; } void Aperture::set_distance (double distance) { d_ptr->distance = distance; } const plm_long* Aperture::get_dim () const { return d_ptr->dim; } plm_long Aperture::get_dim (int dim) const { return d_ptr->dim[dim]; } void Aperture::set_dim (const plm_long* dim) { d_ptr->dim[0] = dim[0]; d_ptr->dim[1] = dim[1]; d_ptr->center[0] = (dim[0]-1) / 2; d_ptr->center[1] = (dim[1]-1) / 2; this->allocate_aperture_images(); } const double* Aperture::get_center () const { return d_ptr->center; } double Aperture::get_center (int dim) const { return d_ptr->center[dim]; } void Aperture::set_center (const float* center) { d_ptr->center[0] = center[0]; d_ptr->center[1] = center[1]; } void Aperture::set_center (const double* center) { d_ptr->center[0] = center[0]; d_ptr->center[1] = center[1]; } void Aperture::set_origin (const float* origin) { /* GCS FIX: This should be saved internally as an origin, then only converted to pixel coordinates as needed */ /* Compute & save as pixel coordinates */ for (int i = 0; i < 2; i++) { d_ptr->center[i] = ((double) -origin[i]) / d_ptr->spacing[i]; } } void Aperture::set_origin (const double* origin) { /* GCS FIX: This should be saved internally as an origin, then only converted to pixel coordinates as needed */ /* Compute & save as pixel coordinates */ for (int i = 0; i < 2; i++) { d_ptr->center[i] = ((double) -origin[i]) / d_ptr->spacing[i]; } } const double* Aperture::get_spacing () const { return d_ptr->spacing; } double Aperture::get_spacing (int dim) const { return d_ptr->spacing[dim]; } void Aperture::set_spacing (const float* spacing) { d_ptr->spacing[0] = spacing[0]; d_ptr->spacing[1] = spacing[1]; } void Aperture::set_spacing (const double* spacing) { d_ptr->spacing[0] = spacing[0]; d_ptr->spacing[1] = spacing[1]; } void Aperture::set_vup (const float* vup) { this->vup[0] = vup[0]; this->vup[1] = vup[1]; this->vup[2] = vup[2]; } void Aperture::allocate_aperture_images () { plm_long dim[3] = { d_ptr->dim[0], d_ptr->dim[1], 1 }; float origin[3] = { 0, 0, 0 }; float spacing[3]; spacing[0] = d_ptr->spacing[0]; spacing[1] = d_ptr->spacing[1]; spacing[2] = 1; Volume *ap_vol = new Volume (dim, origin, spacing, NULL, PT_UCHAR, 1); Volume *rc_vol = new Volume (dim, origin, spacing, NULL, PT_FLOAT, 1); /* Set the volume to values = 0 for range compensator and 1 for aperture */ unsigned char* ap_img = (unsigned char*) ap_vol->img; float* rc_img = (float*) rc_vol->img; for (int i = 0; i < d_ptr->dim[0] * d_ptr->dim[1]; i++) { ap_img[i] = 1; rc_img[i] = 0; } d_ptr->aperture_image = Plm_image::New (ap_vol); d_ptr->range_compensator_image = Plm_image::New (rc_vol); } bool Aperture::have_aperture_image () { return (bool) d_ptr->aperture_image; } Plm_image::Pointer& Aperture::get_aperture_image () { return d_ptr->aperture_image; } Volume::Pointer& Aperture::get_aperture_volume () { return d_ptr->aperture_image->get_volume_uchar (); } Volume* Aperture::get_aperture_vol () { return this->get_aperture_volume().get(); } void Aperture::set_aperture_image (const char *ap_filename) { d_ptr->aperture_image = Plm_image::New (ap_filename); } void Aperture::set_aperture_volume (Volume::Pointer ap) { d_ptr->aperture_image->set_volume(ap); } bool Aperture::have_range_compensator_image () { return (bool) d_ptr->range_compensator_image; } Plm_image::Pointer& Aperture::get_range_compensator_image () { return d_ptr->range_compensator_image; } Volume::Pointer& Aperture::get_range_compensator_volume () { return d_ptr->range_compensator_image->get_volume_float(); } void Aperture::set_range_compensator_image (const char *rc_filename) { d_ptr->range_compensator_image = Plm_image::New (rc_filename); } void Aperture::set_range_compensator_volume (Volume::Pointer rc) { d_ptr->range_compensator_image->set_volume(rc); } void Aperture::apply_smearing_to_aperture (float smearing, float reference_depth) { /* Create a structured element of the right size */ int strel_half_size[2]; int strel_size[2]; strel_half_size[0] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[0])); strel_half_size[1] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[1])); strel_size[0] = 1 + 2 * strel_half_size[0]; strel_size[1] = 1 + 2 * strel_half_size[1]; unsigned char *strel = new unsigned char[strel_size[0]*strel_size[1]]; for (int r = 0; r < strel_size[1]; r++) { float rf = (float) (r - strel_half_size[1]) * d_ptr->spacing[1]; for (int c = 0; c < strel_size[0]; c++) { float cf = (float) (c - strel_half_size[0]) * d_ptr->spacing[0]; int idx = r*strel_size[0] + c; strel[idx] = 0; if ((rf*rf + cf*cf) <= smearing*smearing) { strel[idx] = 1; } } } /* Debugging information */ for (int r = 0; r < strel_size[1]; r++) { for (int c = 0; c < strel_size[0]; c++) { int idx = r*strel_size[0] + c; printf ("%d ", strel[idx]); } printf ("\n"); } /* Apply smear */ Volume::Pointer& ap_vol = this->get_aperture_volume (); unsigned char* ap_img = (unsigned char*) ap_vol->img; Volume::Pointer ap_vol_new = ap_vol->clone (); unsigned char* ap_img_new = (unsigned char*) ap_vol_new->img; for (plm_long ar = 0; ar < d_ptr->dim[1]; ar++) { for (plm_long ac = 0; ac < d_ptr->dim[0]; ac++) { plm_long aidx = ar * d_ptr->dim[0] + ac; unsigned char ap_acc = 0; for (int sr = 0; sr < strel_size[1]; sr++) { int pr = ar + sr - strel_half_size[1]; if (pr < 0 || pr >= d_ptr->dim[1]) { continue; } for (int sc = 0; sc < strel_size[0]; sc++) { int pc = ac + sc - strel_half_size[0]; if (pc < 0 || pc >= d_ptr->dim[0]) { continue; } int sidx = sr * strel_size[0] + sc; if (strel[sidx] == 0) { continue; } int pidx = pr * d_ptr->dim[0] + pc; if (ap_img[pidx]) { ap_acc = 1; } } } ap_img_new[aidx] = ap_acc; } } /* Fixate updated aperture and rc into this object */ d_ptr->aperture_image->set_volume (ap_vol_new); /* Clean up */ delete[] strel; } void Aperture::apply_smearing_to_range_compensator (float smearing, float reference_depth) { /* Create a structured element of the right size */ int strel_half_size[2]; int strel_size[2]; strel_half_size[0] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[0])); strel_half_size[1] = ROUND_INT(smearing * d_ptr->distance / (reference_depth * d_ptr->spacing[1])); strel_size[0] = 1 + 2 * strel_half_size[0]; strel_size[1] = 1 + 2 * strel_half_size[1]; unsigned char *strel = new unsigned char[strel_size[0]*strel_size[1]]; for (int r = 0; r < strel_size[1]; r++) { float rf = (float) (r - strel_half_size[1]) * d_ptr->spacing[1]; for (int c = 0; c < strel_size[0]; c++) { float cf = (float) (c - strel_half_size[0]) * d_ptr->spacing[0]; int idx = r*strel_size[0] + c; strel[idx] = 0; if ((rf*rf + cf*cf) <= smearing*smearing) { strel[idx] = 1; } } } /* Debugging information */ for (int r = 0; r < strel_size[1]; r++) { for (int c = 0; c < strel_size[0]; c++) { int idx = r*strel_size[0] + c; printf ("%d ", strel[idx]); } printf ("\n"); } /* Apply smear */ Volume::Pointer& rc_vol = this->get_range_compensator_volume (); float* rc_img = (float*) rc_vol->img; Volume::Pointer rc_vol_new = rc_vol->clone (); float* rc_img_new = (float*) rc_vol_new->img; for (plm_long ar = 0; ar < d_ptr->dim[1]; ar++) { for (plm_long ac = 0; ac < d_ptr->dim[0]; ac++) { plm_long aidx = ar * d_ptr->dim[0] + ac; float rc_acc = FLT_MAX; for (int sr = 0; sr < strel_size[1]; sr++) { int pr = ar + sr - strel_half_size[1]; if (pr < 0 || pr >= d_ptr->dim[1]) { continue; } for (int sc = 0; sc < strel_size[0]; sc++) { int pc = ac + sc - strel_half_size[0]; if (pc < 0 || pc >= d_ptr->dim[0]) { continue; } int sidx = sr * strel_size[0] + sc; if (strel[sidx] == 0) { continue; } int pidx = pr * d_ptr->dim[0] + pc; if (rc_img[pidx] < rc_acc) { rc_acc = rc_img[pidx]; } } } rc_img_new[aidx] = rc_acc; } } /* Fixate updated aperture and rc into this object */ d_ptr->range_compensator_image->set_volume (rc_vol_new); /* Clean up */ delete[] strel; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/aperture.h000077500000000000000000000105551321604176500275420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _aperture_h_ #define _aperture_h_ #include "plmbase_config.h" #include "plm_image.h" #include "plm_int.h" class Aperture_private; class PLMBASE_API Aperture { public: SMART_POINTER_SUPPORT (Aperture); public: Aperture_private *d_ptr; public: Aperture (); ~Aperture (); Aperture (const Aperture::Pointer&); public: /*! \name Inputs */ ///@{ /*! \brief Get the aperture dimension, in pixels */ const plm_long* get_dim () const; /*! \brief Get the i or j aperture dimension, in pixels */ plm_long get_dim (int dim) const; /*! \brief Set the aperture dimension, in pixels */ void set_dim (const plm_long* dim); /*! \brief Get the aperture center, in pixels */ const double* get_center () const; /*! \brief Get the aperture center in the i or j dimension, in pixels */ double get_center (int dim) const; /*! \brief Set the aperture center, in pixels */ void set_center (const float* center); void set_center (const double* center); /*! \brief Set the aperture origin, in mm */ void set_origin (const float* center); void set_origin (const double* center); /*! \brief Get the aperture offset: the distance from the beam source to closest point on the aperture plane */ double get_distance () const; /*! \brief Get the aperture offset: the distance from the beam source to closest point on the aperture plane */ void set_distance (double distance); /*! \brief Get the aperture spacing: the distance between sampling points in the aperture plane, in mm */ const double* get_spacing () const; /*! \brief Get the aperture spacing in the i or j dimension, in mm */ double get_spacing (int dim) const; /*! \brief Get the aperture spacing: the distance between sampling points in the aperture plane */ void set_spacing (const float* spacing); void set_spacing (const double* spacing); /*! \brief Get the aperture vup vector, which is the vector that orients the top of the aperture in room coordinates */ void set_vup (const float* vup); /*! \brief Allocate aperture and range compensator images */ void allocate_aperture_images (); /*! \brief Test if the aperture has a bitmap image describing shape */ bool have_aperture_image (); /*! \brief Get the aperture image as Plm_image */ Plm_image::Pointer& get_aperture_image (); /*! \brief Get the aperture image as Volume */ Volume::Pointer& get_aperture_volume (); Volume* get_aperture_vol (); /*! \brief Load the aperture image from a file */ void set_aperture_image (const char *ap_filename); /*! \brief Load the aperture volume from a file */ void set_aperture_volume (Volume::Pointer ap); /*! \brief Test if the aperture has a float image describing range compensator thicknesses */ bool have_range_compensator_image (); /*! \brief Get the range_compensator image as Plm_image */ Plm_image::Pointer& get_range_compensator_image (); /*! \brief Get the range_compensator image as Volume */ Volume::Pointer& get_range_compensator_volume (); /*! \brief Load the range_compensator image from a file */ void set_range_compensator_image (const char *rc_filename); /*! \brief Load the range_compensator volume from a file */ void set_range_compensator_volume (Volume::Pointer ap); /*! \brief Expand aperture and smear compensator. The smearing parameters is defined as mm around the target in the beam eye view frame at the target minimal depth. */ void apply_smearing_to_aperture (float smearing, float target_depth); void apply_smearing_to_range_compensator (float smearing, float target_depth); ///@} public: double vup[3]; /* orientation */ double ic_room[3]; /* loc of center (room coords) */ double ul_room[3]; /* loc of upper left corder (room coords) */ double incr_r[3]; /* row increment vector */ double incr_c[3]; /* col increment vector */ double nrm[3]; /* unit vec: normal */ double pdn[3]; /* unit vec: down */ double prt[3]; /* unit vec: right */ double tmp[3]; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/astroid_dose.cxx000066400000000000000000000150471321604176500307430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include "astroid_dose.h" #include "direction_cosines.h" #include "plm_endian.h" #include "plm_image.h" #include "plm_int.h" #include "print_and_exit.h" #include "volume.h" #include "xio_ct.h" #include "xio_ct_transform.h" typedef struct astroid_dose_header Astroid_dose_header; struct astroid_dose_header { plm_long dim[3]; float origin[3]; float spacing[3]; std::string dose_type; }; static void astroid_dose_load_header (Astroid_dose_header *adh, const char *filename) { FILE *fp; int rc; /* Dose cube definition */ double rx; double ry; double rz; double ox; double oy; double oz; int nx; int ny; int nz; /* Element spacing */ double dx; double dy; double dz; /* Origin */ double topx; double topy; double topz; char line1[1024]; char line2[1024]; /* Astroid doesn't include the geometry in the dose export file. Therefore an additional .geometry file will be loaded which should contains a line that defines the geometry with 9 values in XiO coordinates: rx, rz, ry, ox, oz, oy, nx, nz, ny The second line of the geometry file may contain the dose type: PHYSICAL, EFFECTIVE or ERROR Default dose type is EFFECTIVE. If dose type = ERROR, the dose cube should contain signed instead of unsigned integers. */ std::string filename_geometry = std::string(filename) + ".geometry"; fp = fopen (filename_geometry.c_str(), "rb"); if (!fp) { print_and_exit ("Error opening geometry file %s for read\n", filename_geometry.c_str()); } /* Dose grid */ if (fgets (line1, sizeof(line1), fp) == NULL) { print_and_exit ("File error."); } rc = sscanf (line1, "%lf,%lf,%lf,%lf,%lf,%lf,%d,%d,%d", &rx, &rz, &ry, &ox, &oz, &oy, &nx, &nz, &ny); if (rc != 9) { print_and_exit ("Error. Cannot parse dose cube definition: %s\n", line1); } printf ("rx = %lf, ry = %lf, rz = %lf\n", rx, ry, rz); printf ("ox = %lf, oy = %lf, oz = %lf\n", ox, oy, oz); printf ("nx = %d, ny = %d, nz = %d\n", nx, ny, nz); /* Calculate element spacing */ dx = rx / (nx - 1); dy = ry / (ny - 1); dz = rz / (nz - 1); /* Calculate origin */ //topx = ox - (rx / 2); //topy = oy - (ry / 2); //topz = -oz - (rz / 2); topx = ox - rx/2 - dx/4; topy = oy - ry/2; topz = -oz - rz/2 - dz/4; /* Put info into header */ adh->dim[0] = nx; adh->dim[1] = nz; adh->dim[2] = ny; adh->spacing[0] = dx; adh->spacing[1] = dz; adh->spacing[2] = dy; adh->origin[0] = topx; adh->origin[1] = topz; adh->origin[2] = topy; if (fgets(line2, sizeof(line2), fp)) { /* Remove newline if exists */ unsigned int len = strlen(line2); if (line2[len - 1] == '\n') line2[len - 1] = '\0'; adh->dose_type = line2; } else { adh->dose_type = ""; } fclose (fp); } static void astroid_dose_load_cube ( Plm_image *pli, Astroid_dose_header *adh, const char *filename ) { FILE *fp; Volume *v; plm_long i, j, k; size_t rc; v = pli->get_vol (); char* cube_img_read = (char*) v->img; fp = fopen (filename, "rb"); if (!fp) { print_and_exit ("Error opening file %s for read\n", filename); } /* Read dose cube */ rc = fread (cube_img_read, 4, v->dim[0] * v->dim[1] * v->dim[2], fp); if (rc != (size_t) (v->dim[0] * v->dim[1] * v->dim[2])) { perror ("File error: "); print_and_exit ( "Error reading astroid dose cube (%s)\n" " rc = %d, ferror = %d\n", filename, rc, ferror (fp)); } /* Switch big-endian to native */ endian4_big_to_native ((void*) cube_img_read, v->dim[0] * v->dim[1] * v->dim[2]); /* Flip XiO Z axis */ Volume* vflip; vflip = new Volume (v->dim, v->origin, v->spacing, v->direction_cosines, v->pix_type, v->vox_planes); for (k=0;kdim[2];k++) { for (j=0;jdim[1];j++) { for (i=0;idim[0];i++) { memcpy ((float*)vflip->img + volume_index (vflip->dim, i, (vflip->dim[1]-1-j), k), (float*)v->img + volume_index (v->dim, i, j, k), v->pix_size); } } } pli->set_volume (vflip); /* Convert volume to float for more accurate normalization */ pli->convert (PLM_IMG_TYPE_GPUIT_FLOAT); /* Convert from cGy to Gy */ vflip->scale_inplace (0.01); fclose (fp); } static void astroid_dose_create_volume ( Plm_image *pli, Astroid_dose_header *adh ) { Volume *v; if (adh->dose_type != "ERROR") { v = new Volume (adh->dim, adh->origin, adh->spacing, 0, PT_UINT32, 1); } else { v = new Volume (adh->dim, adh->origin, adh->spacing, 0, PT_INT32, 1); std::cout<<"Reading cube as int32"<set_volume (v); printf ("img: %p\n", v->img); printf ("Image dim: %u %u %u\n", (unsigned int) v->dim[0], (unsigned int) v->dim[1], (unsigned int) v->dim[2]); } void astroid_dose_load ( Plm_image *pli, Metadata::Pointer& meta, const char *filename ) { Astroid_dose_header adh; astroid_dose_load_header(&adh, filename); // If metadat not set, dose is usually "EFFECTIVE" (Gy(RBE)) // If it is an "ERROR' type (dose difference) read as int32 instead of uint32 std::cout<<"Metadata " << meta->get_metadata(0x3004, 0x0004) << std::endl; if (meta->get_metadata(0x3004, 0x0004) == ""){ if(adh.dose_type==""){ /* Standard is Gy RBE */ adh.dose_type = "EFFECTIVE"; std::cout<<"setting dose type to effective " << std::endl; } meta->set_metadata(0x3004, 0x0004, adh.dose_type); } else { adh.dose_type = meta->get_metadata(0x3004, 0x0004); } astroid_dose_create_volume(pli, &adh); astroid_dose_load_cube(pli, &adh, filename); } void astroid_dose_apply_transform (Plm_image *pli, Xio_ct_transform *transform) { /* Transform coordinates of Astroid dose cube to DICOM coordinates */ Volume *v; v = pli->get_vol (); /* Set origins */ v->origin[0] = (v->origin[0] * transform->direction_cosines[0]) + transform->x_offset; v->origin[1] = (v->origin[1] * transform->direction_cosines[4]) + transform->y_offset; /* Set direction cosines */ v->set_direction_cosines (transform->direction_cosines); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/astroid_dose.h000066400000000000000000000011331321604176500303570ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _astroid_dose_h_ #define _astroid_dose_h_ #include "plmbase_config.h" #include "metadata.h" class Plm_image; class Xio_ct_transform; PLMBASE_C_API void astroid_dose_load ( Plm_image *plm, Metadata::Pointer& meta, const char *filename ); PLMBASE_C_API void astroid_dose_apply_transform ( Plm_image *plm, Xio_ct_transform *transform ); #endif bspline_interpolate.cxx000066400000000000000000000152761321604176500322530ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #if (OPENMP_FOUND) #include #endif #include "bspline_interpolate.h" #include "bspline_xform.h" #include "direction_cosines.h" #include "interpolate_macros.h" #include "plm_math.h" #include "volume.h" #include "volume_macros.h" void bspline_interp_pix ( float out[3], const Bspline_xform* bxf, plm_long p[3], plm_long qidx ) { int i, j, k, m; plm_long cidx; float* q_lut = &bxf->q_lut[qidx*64]; out[0] = out[1] = out[2] = 0; m = 0; for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cidx = (p[2] + k) * bxf->cdims[1] * bxf->cdims[0] + (p[1] + j) * bxf->cdims[0] + (p[0] + i); cidx = cidx * 3; out[0] += q_lut[m] * bxf->coeff[cidx+0]; out[1] += q_lut[m] * bxf->coeff[cidx+1]; out[2] += q_lut[m] * bxf->coeff[cidx+2]; m ++; } } } } void bspline_interp_pix_b ( float out[3], Bspline_xform* bxf, plm_long pidx, plm_long qidx ) { int i, j, k, m; plm_long cidx; float* q_lut = &bxf->q_lut[qidx*64]; plm_long* c_lut = &bxf->c_lut[pidx*64]; out[0] = out[1] = out[2] = 0; m = 0; for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cidx = 3 * c_lut[m]; out[0] += q_lut[m] * bxf->coeff[cidx+0]; out[1] += q_lut[m] * bxf->coeff[cidx+1]; out[2] += q_lut[m] * bxf->coeff[cidx+2]; m ++; } } } } void bspline_interp_pix_c ( float out[3], Bspline_xform* bxf, plm_long pidx, plm_long *q ) { int i,j,k,m; plm_long cidx; float A,B,C; plm_long* c_lut = &bxf->c_lut[pidx*64]; float* bx_lut = &bxf->bx_lut[q[0]*4]; float* by_lut = &bxf->by_lut[q[1]*4]; float* bz_lut = &bxf->bz_lut[q[2]*4]; out[0] = out[1] = out[2] = 0; m=0; for (k=0; k<4; k++) { C = bz_lut[k]; for (j=0; j<4; j++) { B = by_lut[j] * C; for (i=0; i<4; i++) { A = bx_lut[i] * B; cidx = 3*c_lut[m++]; out[0] += A * bxf->coeff[cidx+0]; out[1] += A * bxf->coeff[cidx+1]; out[2] += A * bxf->coeff[cidx+2]; } } } } void bspline_interpolate_vf (Volume* interp, const Bspline_xform* bxf) { plm_long i, j, k, v; plm_long p[3]; plm_long q[3]; float* out; float* img = (float*) interp->img; plm_long qidx; memset (img, 0, interp->npix*3*sizeof(float)); for (k = 0; k < bxf->roi_dim[2]; k++) { p[2] = k / bxf->vox_per_rgn[2]; q[2] = k % bxf->vox_per_rgn[2]; for (j = 0; j < bxf->roi_dim[1]; j++) { p[1] = j / bxf->vox_per_rgn[1]; q[1] = j % bxf->vox_per_rgn[1]; for (i = 0; i < bxf->roi_dim[0]; i++) { p[0] = i / bxf->vox_per_rgn[0]; q[0] = i % bxf->vox_per_rgn[0]; qidx = volume_index (bxf->vox_per_rgn, q); v = (k+bxf->roi_offset[2]) * interp->dim[0] * interp->dim[1] + (j+bxf->roi_offset[1]) * interp->dim[0] + (i+bxf->roi_offset[0]); out = &img[3*v]; bspline_interp_pix (out, bxf, p, qidx); } } } } /* This function uses the B-Spline coefficients to transform a point. The point need not lie exactly on a voxel, so we do not use the lookup table. */ void bspline_transform_point ( float point_out[3], /* Output coordinate of point */ Bspline_xform* bxf, /* Bspline transform coefficients */ float point_in[3], /* Input coordinate of point */ int linear_interp /* 1 = trilinear, 0 = nearest neighbors */ ) { plm_long d, i, j, k; plm_long p[3]; /* Index of tile */ float q[3]; /* Fractional offset within tile */ float q_mini[3][4]; /* "miniature" q-lut, just for this point */ /* Default value is untransformed point */ for (d = 0; d < 3; d++) { point_out[d] = point_in[d]; } /* Compute tile and offset within tile */ for (d = 0; d < 3; d++) { float img_ijk[3]; /* Voxel coordinate of point_in */ img_ijk[d] = (point_in[d] - bxf->img_origin[d]) / bxf->img_spacing[d]; p[d] = (int) floorf ( (img_ijk[d] - bxf->roi_offset[d]) / bxf->vox_per_rgn[d]); /* If point lies outside of B-spline domain, return point_in */ if (p[d] < 0 || p[d] >= bxf->rdims[d]) { printf ("Unwarped point, outside roi: %f %f %f\n", point_out[0], point_out[1], point_out[2]); return; } q[d] = ((img_ijk[d] - bxf->roi_offset[d]) - p[d] * bxf->vox_per_rgn[d]) / bxf->vox_per_rgn[d]; } #if defined (commentout) printf ("p = [%d, %d, %d], q = [%f, %f, %f]\n", p[0], p[1], p[2], q[0], q[1], q[2]); #endif /* Compute basis function values for this offset */ for (d = 0; d < 3; d++) { float t3 = q[d]*q[d]*q[d]; float t2 = q[d]*q[d]; float t1 = q[d]; q_mini[d][0] = (1.0/6.0) * (- 1.0 * t3 + 3.0 * t2 - 3.0 * t1 + 1.0); q_mini[d][1] = (1.0/6.0) * (+ 3.0 * t3 - 6.0 * t2 + 4.0); q_mini[d][2] = (1.0/6.0) * (- 3.0 * t3 + 3.0 * t2 + 3.0 * t1 + 1.0); q_mini[d][3] = (1.0/6.0) * (+ 1.0 * t3); } /* Compute displacement vector and add to point_out */ #if defined (commentout) printf ("---\n"); #endif for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { float ql; int cidx; cidx = (p[2] + k) * bxf->cdims[1] * bxf->cdims[0] + (p[1] + j) * bxf->cdims[0] + (p[0] + i); cidx = cidx * 3; ql = q_mini[0][i] * q_mini[1][j] * q_mini[2][k]; #if defined (commentout) printf ("(%f) + [%f] + [%f] = ", point_out[0], ql, bxf->coeff[cidx+0]); #endif point_out[0] += ql * bxf->coeff[cidx+0]; point_out[1] += ql * bxf->coeff[cidx+1]; point_out[2] += ql * bxf->coeff[cidx+2]; #if defined (commentout) printf (" = (%f)\n", point_out[0]); #endif } } } } bspline_interpolate.h000066400000000000000000000021621321604176500316660ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_interpolate_h_ #define _bspline_interpolate_h_ #include "plmbase_config.h" #include "plm_int.h" class Bspline_xform; class Volume; PLMBASE_API void bspline_interpolate_vf ( Volume* interp, const Bspline_xform* bxf); PLMBASE_API void bspline_transform_point ( float point_out[3], /* Output coordinate of point */ Bspline_xform* bxf, /* Bspline transform coefficients */ float point_in[3], /* Input coordinate of point */ int linear_interp /* 1 = trilinear, 0 = nearest neighbors */ ); PLMBASE_API void bspline_interp_pix ( float out[3], const Bspline_xform* bxf, plm_long p[3], plm_long qidx ); PLMBASE_API void bspline_interp_pix_b ( float out[3], Bspline_xform* bxf, plm_long pidx, plm_long qidx ); PLMBASE_API void bspline_interp_pix_c ( float out[3], Bspline_xform* bxf, plm_long pidx, plm_long *q ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/bspline_macros.h000066400000000000000000000161631321604176500307110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_macros_h_ #define _bspline_macros_h_ #include "plmbase_config.h" #include "bspline_xform.h" #include "plm_int.h" #include "volume_macros.h" /*************************************************************** * MACROS FOR VOXEL CENTRIC ALGORITHMS * ***************************************************************/ /* ITERATORS */ /* For looping through volume ROI. Here: * roi_ijk - coordinates within ROI * vol_ijk - volume coordinate of ROI point roi_ijk */ #define LOOP_THRU_ROI_X(roi_ijk, vol_ijk, bxf) \ for (roi_ijk[0] = 0, vol_ijk[0] = bxf->roi_offset[0]; roi_ijk[0] < bxf->roi_dim[0]; roi_ijk[0]++, vol_ijk[0]++) #define LOOP_THRU_ROI_Y(roi_ijk, vol_ijk, bxf) \ for (roi_ijk[1] = 0, vol_ijk[1] = bxf->roi_offset[1]; roi_ijk[1] < bxf->roi_dim[1]; roi_ijk[1]++, vol_ijk[1]++) #define LOOP_THRU_ROI_Z(roi_ijk, vol_ijk, bxf) \ for (roi_ijk[2] = 0, vol_ijk[2] = bxf->roi_offset[2]; roi_ijk[2] < bxf->roi_dim[2]; roi_ijk[2]++, vol_ijk[2]++) /* COORDINATE MANIPULATION MACROS */ #define REGION_INDEX_X(ijk, bxf) \ (ijk[0] / bxf->vox_per_rgn[0]) #define REGION_INDEX_Y(ijk, bxf) \ (ijk[1] / bxf->vox_per_rgn[1]) #define REGION_INDEX_Z(ijk, bxf) \ (ijk[2] / bxf->vox_per_rgn[2]) static inline void get_region_index_3 (int p[3], const int ijk[3], const Bspline_xform *bxf) { p[0] = ijk[0] / bxf->vox_per_rgn[0]; p[1] = ijk[1] / bxf->vox_per_rgn[1]; p[2] = ijk[2] / bxf->vox_per_rgn[2]; } static inline void get_region_index_3 (int p[3], int i, int j, int k, const Bspline_xform *bxf) { p[0] = i / bxf->vox_per_rgn[0]; p[1] = j / bxf->vox_per_rgn[1]; p[2] = k / bxf->vox_per_rgn[2]; } static inline plm_long get_region_index (const plm_long ijk[3], const Bspline_xform *bxf) { plm_long p[3]; p[0] = ijk[0] / bxf->vox_per_rgn[0]; p[1] = ijk[1] / bxf->vox_per_rgn[1]; p[2] = ijk[2] / bxf->vox_per_rgn[2]; return volume_index (bxf->rdims, p); } static inline plm_long get_region_index (plm_long i, plm_long j, plm_long k, const Bspline_xform *bxf) { plm_long p[3]; p[0] = i / bxf->vox_per_rgn[0]; p[1] = j / bxf->vox_per_rgn[1]; p[2] = k / bxf->vox_per_rgn[2]; return volume_index (bxf->rdims, p); } #define REGION_OFFSET_X(ijk, bxf) \ (ijk[0] % bxf->vox_per_rgn[0]) #define REGION_OFFSET_Y(ijk, bxf) \ (ijk[1] % bxf->vox_per_rgn[1]) #define REGION_OFFSET_Z(ijk, bxf) \ (ijk[2] % bxf->vox_per_rgn[2]) static inline void get_region_offset (int q[3], const int ijk[3], const Bspline_xform *bxf) { q[0] = ijk[0] % bxf->vox_per_rgn[0]; q[1] = ijk[1] % bxf->vox_per_rgn[1]; q[2] = ijk[2] % bxf->vox_per_rgn[2]; } static inline void get_region_offset (int q[3], int i, int j, int k, const Bspline_xform *bxf) { q[0] = i % bxf->vox_per_rgn[0]; q[1] = j % bxf->vox_per_rgn[1]; q[2] = k % bxf->vox_per_rgn[2]; } static inline plm_long get_region_offset (const plm_long ijk[3], const Bspline_xform *bxf) { plm_long q[3]; q[0] = ijk[0] % bxf->vox_per_rgn[0]; q[1] = ijk[1] % bxf->vox_per_rgn[1]; q[2] = ijk[2] % bxf->vox_per_rgn[2]; return volume_index (bxf->vox_per_rgn, q); } static inline plm_long get_region_offset (plm_long i, plm_long j, plm_long k, const Bspline_xform *bxf) { plm_long q[3]; q[0] = i % bxf->vox_per_rgn[0]; q[1] = j % bxf->vox_per_rgn[1]; q[2] = k % bxf->vox_per_rgn[2]; return volume_index (bxf->vox_per_rgn, q); } #define GET_WORLD_COORD_X_NO_DCOS(ijk_vol, bxf) \ (bxf->img_origin[0] + bxf->img_spacing[0] * ijk_vol[0]) #define GET_WORLD_COORD_Y_NO_DCOS(ijk_vol, bxf) \ (bxf->img_origin[1] + bxf->img_spacing[1] * ijk_vol[1]) #define GET_WORLD_COORD_Z_NO_DCOS(ijk_vol, bxf) \ (bxf->img_origin[2] + bxf->img_spacing[2] * ijk_vol[2]) #define GET_WORLD_COORD_X(ijk_vol, vol, bxf) \ (bxf->img_origin[0] \ + ijk_vol[0]*vol->step[0*3+0] \ + ijk_vol[1]*vol->step[0*3+1] \ + ijk_vol[2]*vol->step[0*3+2]) #define GET_WORLD_COORD_Y(ijk_vol, vol, bxf) \ (bxf->img_origin[1] \ + ijk_vol[0]*vol->step[1*3+0] \ + ijk_vol[1]*vol->step[1*3+1] \ + ijk_vol[2]*vol->step[1*3+2]) #define GET_WORLD_COORD_Z(ijk_vol, vol, bxf) \ (bxf->img_origin[2] \ + ijk_vol[0]*vol->step[2*3+0] \ + ijk_vol[1]*vol->step[2*3+1] \ + ijk_vol[2]*vol->step[2*3+2]) /*************************************************************** * MACROS FOR THE "PARALLEL FRIENDLY" TILE-CENTRIC ALGORITHMS * ***************************************************************/ /* ITERATORS */ /* For linearlly cycling through regions/tiles in the volume */ #define LOOP_THRU_VOL_TILES(idx_tile, bxf) \ for (idx_tile = 0; idx_tile < (bxf->rdims[0] * bxf->rdims[1] * bxf->rdims[2]); idx_tile++) /* For cycling through local coordinates within a tile */ #define LOOP_THRU_TILE_X(ijk_local, bxf) \ for (ijk_local[0]=0; ijk_local[0] < bxf->vox_per_rgn[0]; ijk_local[0]++) #define LOOP_THRU_TILE_Y(ijk_local, bxf) \ for (ijk_local[1]=0; ijk_local[1] < bxf->vox_per_rgn[1]; ijk_local[1]++) #define LOOP_THRU_TILE_Z(ijk_local, bxf) \ for (ijk_local[2]=0; ijk_local[2] < bxf->vox_per_rgn[2]; ijk_local[2]++) /* COORDINATE MANIPULATION MACROS */ /* Get volume coordinates given tile coordinates and local coordinates */ #define GET_VOL_COORDS(ijk_vol, ijk_tile, ijk_local, bxf) \ do { \ ijk_vol[0] = bxf->roi_offset[0] + bxf->vox_per_rgn[0] * ijk_tile[0] + ijk_local[0]; \ ijk_vol[1] = bxf->roi_offset[1] + bxf->vox_per_rgn[1] * ijk_tile[1] + ijk_local[1]; \ ijk_vol[2] = bxf->roi_offset[2] + bxf->vox_per_rgn[2] * ijk_tile[2] + ijk_local[2]; \ } while (0); /* Get real-space coordinates from a set of volume indices */ #define GET_REAL_SPACE_COORDS(xyz_vol, ijk_vol, bxf) \ do { \ xyz_vol[0] = bxf->img_origin[0] + bxf->img_spacing[0] * ijk_vol[0]; \ xyz_vol[1] = bxf->img_origin[1] + bxf->img_spacing[1] * ijk_vol[1]; \ xyz_vol[2] = bxf->img_origin[2] + bxf->img_spacing[2] * ijk_vol[2]; \ } while (0); /* Get real-space coordinates from a set of volume indices */ #if defined (commentout) #define GET_WORLD_COORDS(xyz_vol, ijk_vol, vol, bxf) \ VOXEL_COORDS (xyz_vol, ijk_vol, bxf->img_origin, vol->step) #endif #endif /* _bspline_macros_h_ */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/bspline_warp.cxx000066400000000000000000000206761321604176500307550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #if (OPENMP_FOUND) #include #endif #if (SSE2_FOUND) #include #endif #include "bspline_correspond.h" #include "bspline_interpolate.h" #include "bspline_macros.h" #include "bspline_warp.h" #include "interpolate.h" #include "interpolate_macros.h" #include "plm_math.h" #include "print_and_exit.h" #include "volume_macros.h" #include "volume.h" /* This only warps voxels within the ROI. If you need the whole image, call bspline_xform_extend. */ template void bspline_warp_dcos ( Volume *vout, /* Output image (sized and allocated) */ Volume *vf_out, /* Output vf (sized and allocated, can be null) */ Bspline_xform* bxf, /* Bspline transform coefficients */ Volume *moving, /* Input image */ int linear_interp, /* 1 = trilinear, 0 = nearest neighbors */ T default_val /* Fill in this value outside of image */ ) { T* vout_img = (T*) vout->img; T* m_img = (T*) moving->img; /* A few sanity checks */ if (vout->pix_type != PIX_TYPE) { print_and_exit ("Error: bspline_warp pix type mismatch\n"); return; } for (int d = 0; d < 3; d++) { if (vout->dim[d] != bxf->img_dim[d]) { print_and_exit ("Error: bspline_warp dim mismatch\n"); return; } if (vout->origin[d] != bxf->img_origin[d]) { print_and_exit ("Error: bspline_warp origin mismatch\n"); return; } if (vout->spacing[d] != bxf->img_spacing[d]) { print_and_exit ("Error: bspline_warp pix spacing mismatch\n"); return; } } if (vf_out && vf_out->pix_type != PT_VF_FLOAT_INTERLEAVED) { print_and_exit ("Error: bspline_warp requires interleaved vf\n"); return; } /* Set default */ for (plm_long vidx = 0; vidx < vout->npix; vidx++) { vout_img[vidx] = default_val; } if (vf_out) { memset (vf_out->img, 0, vf_out->pix_size * vf_out->npix); } #pragma omp parallel for LOOP_Z_OMP (k, vout) { plm_long fijk[3]; /* Index within fixed image (vox) */ float fxyz[3]; /* Position within fixed image (mm) */ plm_long p[3]; plm_long q[3]; plm_long pidx, qidx; float dxyz[3]; fijk[2] = k; fxyz[2] = vout->origin[2] + fijk[2] * vout->step[2*3+2]; p[2] = REGION_INDEX_Z (fijk, bxf); q[2] = REGION_OFFSET_Z (fijk, bxf); LOOP_Y (fijk, fxyz, vout) { p[1] = REGION_INDEX_Y (fijk, bxf); q[1] = REGION_OFFSET_Y (fijk, bxf); LOOP_X (fijk, fxyz, vout) { plm_long fv; /* Linear index within fixed image (vox) */ float mxyz[3]; /* Position within moving image (mm) */ float mijk[3]; /* Index within moving image (vox) */ plm_long mijk_f[3]; /* Floor index within moving image (vox) */ plm_long mijk_r[3]; /* Round index within moving image (vox) */ plm_long mvf; /* Floor linear index within moving image */ float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ p[0] = REGION_INDEX_X (fijk, bxf); q[0] = REGION_OFFSET_X (fijk, bxf); /* Get B-spline deformation vector */ pidx = volume_index (bxf->rdims, p); qidx = volume_index (bxf->vox_per_rgn, q); bspline_interp_pix_b (dxyz, bxf, pidx, qidx); /* Compute linear index of fixed image voxel */ fv = volume_index (vout->dim, fijk); /* Assign deformation */ if (vf_out) { float *vf_out_img = (float*) vf_out->img; vf_out_img[3*fv+0] = dxyz[0]; vf_out_img[3*fv+1] = dxyz[1]; vf_out_img[3*fv+2] = dxyz[2]; } /* Compute moving image coordinate of fixed image voxel */ mxyz[2] = fxyz[2] + dxyz[2] - moving->origin[2]; mxyz[1] = fxyz[1] + dxyz[1] - moving->origin[1]; mxyz[0] = fxyz[0] + dxyz[0] - moving->origin[0]; mijk[2] = PROJECT_Z (mxyz, moving->proj); mijk[1] = PROJECT_Y (mxyz, moving->proj); mijk[0] = PROJECT_X (mxyz, moving->proj); if (!moving->is_inside (mijk)) continue; li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); if (linear_interp) { /* Find linear index of "corner voxel" in moving image */ mvf = volume_index (moving->dim, mijk_f); /* Macro is slightly faster than function */ /* Compute moving image intensity using linear interpolation */ T m_val; LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], mvf, m_img, moving); /* Assign warped value to output image */ vout_img[fv] = m_val; } else { /* Find linear index of "nearest voxel" in moving image */ mvf = volume_index (moving->dim, mijk_r); /* Loop through planes */ /* Note: We omit looping through planes when linear interpolation is enabled, with the understanding that this is only used for warping structure sets */ for (int plane = 0; plane < moving->vox_planes; plane++) { /* Get moving image value */ T m_val; m_val = m_img[mvf*moving->vox_planes+plane]; /* Assign to output image */ vout_img[fv*moving->vox_planes+plane] = m_val; } } } } } printf ("bspline_warp complete.\n"); } void bspline_warp ( Volume *vout, /* Output image (sized and allocated) */ Volume *vf_out, /* Output vf (sized and allocated, can be null) */ Bspline_xform* bxf, /* Bspline transform coefficients */ Volume *moving, /* Input image */ int linear_interp, /* 1 = trilinear, 0 = nearest neighbors */ float default_val /* Fill in this value outside of image */ ) { switch (moving->pix_type) { case PT_UCHAR: bspline_warp_dcos ( vout, vf_out, bxf, moving, linear_interp, default_val); break; case PT_SHORT: bspline_warp_dcos ( vout, vf_out, bxf, moving, linear_interp, default_val); break; case PT_UINT16: bspline_warp_dcos ( vout, vf_out, bxf, moving, linear_interp, default_val); break; case PT_UINT32: bspline_warp_dcos ( vout, vf_out, bxf, moving, linear_interp, default_val); break; case PT_FLOAT: bspline_warp_dcos ( vout, vf_out, bxf, moving, linear_interp, default_val); break; case PT_VF_FLOAT_INTERLEAVED: case PT_VF_FLOAT_PLANAR: print_and_exit ("bspline_warp: sorry, this is not supported.\n"); break; case PT_UCHAR_VEC_INTERLEAVED: bspline_warp_dcos ( vout, vf_out, bxf, moving, linear_interp, default_val); break; default: print_and_exit ("bspline_warp: sorry, this is not supported.\n"); break; } } void bspline_warp ( Volume *vout, /* Output image (sized and allocated) */ Volume *vf_out, /* Output vf (sized and allocated, can be null) */ Bspline_xform* bxf, /* Bspline transform coefficients */ const Volume::Pointer& moving, /* Input image */ int linear_interp, /* 1 = trilinear, 0 = nearest neighbors */ float default_val /* Fill in this value outside of image */ ) { bspline_warp (vout, vf_out, bxf, moving.get(), linear_interp, default_val); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/bspline_warp.h000066400000000000000000000024061321604176500303710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_warp_h_ #define _bspline_warp_h_ #include "plmbase_config.h" #include "volume.h" class Bspline_xform; /* This should become obsolete */ PLMBASE_API void bspline_warp ( Volume *vout, /* Output image (already sized and allocated) */ Volume *vf_out, /* Output vf (already sized and allocated, can be null) */ Bspline_xform* bxf, /* Bspline transform coefficients */ Volume *moving, /* Input image */ int linear_interp, /* 1 = trilinear, 0 = nearest neighbors */ float default_val /* Fill in this value outside of image */ ); PLMBASE_API void bspline_warp ( Volume *vout, /* Output image (already sized and allocated) */ Volume *vf_out, /* Output vf (already sized and allocated, can be null) */ Bspline_xform* bxf, /* Bspline transform coefficients */ const Volume::Pointer& moving, /* Input image */ int linear_interp, /* 1 = trilinear, 0 = nearest neighbors */ float default_val /* Fill in this value outside of image */ ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/bspline_xform.cxx000066400000000000000000000520771321604176500311370ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #if (OPENMP_FOUND) #include #endif #include "bspline_interpolate.h" #include "bspline_xform.h" #include "direction_cosines.h" #include "file_util.h" #include "interpolate_macros.h" #include "logfile.h" #include "plm_math.h" #include "print_and_exit.h" #include "string_util.h" #include "volume_header.h" #include "volume_macros.h" Bspline_xform::Bspline_xform () { for (int d = 0; d < 3; d++) { this->img_origin[d] = 0.0f; this->img_spacing[d] = 1.0f; this->img_dim[d] = 0; this->roi_offset[d] = 0; this->roi_dim[d] = 0; this->vox_per_rgn[d] = 30; this->grid_spac[d] = 30.0f; this->rdims[d] = 0; this->cdims[d] = 0; } this->dc.set_identity (); this->num_knots = 0; this->num_coeff = 0; this->coeff = 0; this->lut_type = LUT_ALIGNED; this->cidx_lut = 0; this->c_lut = 0; this->qidx_lut = 0; this->q_lut = 0; this->bx_lut = 0; this->by_lut = 0; this->bz_lut = 0; this->ux_lut = 0; this->uy_lut = 0; this->uz_lut = 0; } Bspline_xform::~Bspline_xform () { if (this->coeff) { free (this->coeff); } if (this->q_lut) { free (this->q_lut); } if (this->c_lut) { free (this->c_lut); } if (this->bx_lut) { free (this->bx_lut); } if (this->by_lut) { free (this->by_lut); } if (this->bz_lut) { free (this->bz_lut); } delete[] ux_lut; delete[] uy_lut; delete[] uz_lut; } static float bspline_basis_eval ( int t_idx, int vox_idx, int vox_per_rgn) { float i = (float)vox_idx / vox_per_rgn; switch(t_idx) { case 0: return (1.0/6.0) * (- 1.0 * i*i*i + 3.0 * i*i - 3.0 * i + 1.0); break; case 1: return (1.0/6.0) * (+ 3.0 * i*i*i - 6.0 * i*i + 4.0); break; case 2: return (1.0/6.0) * (- 3.0 * i*i*i + 3.0 * i*i + 3.0 * i + 1.0); break; case 3: return (1.0/6.0) * (+ 1.0 * i*i*i); break; default: return 0.0; break; } } void Bspline_xform::save (const char* filename) { FILE* fp; make_parent_directories (filename); fp = fopen (filename, "wb"); if (!fp) return; fprintf (fp, "MGH_GPUIT_BSP \n"); fprintf (fp, "img_origin = %f %f %f\n", this->img_origin[0], this->img_origin[1], this->img_origin[2]); fprintf (fp, "img_spacing = %f %f %f\n", this->img_spacing[0], this->img_spacing[1], this->img_spacing[2]); fprintf (fp, "img_dim = %u %u %u\n", (unsigned int) this->img_dim[0], (unsigned int) this->img_dim[1], (unsigned int) this->img_dim[2]); fprintf (fp, "roi_offset = %d %d %d\n", (unsigned int) this->roi_offset[0], (unsigned int) this->roi_offset[1], (unsigned int) this->roi_offset[2]); fprintf (fp, "roi_dim = %d %d %d\n", (unsigned int) this->roi_dim[0], (unsigned int) this->roi_dim[1], (unsigned int) this->roi_dim[2]); fprintf (fp, "vox_per_rgn = %d %d %d\n", (unsigned int) this->vox_per_rgn[0], (unsigned int) this->vox_per_rgn[1], (unsigned int) this->vox_per_rgn[2]); float *direction_cosines = this->dc.get_matrix (); fprintf (fp, "direction_cosines = %f %f %f %f %f %f %f %f %f\n", direction_cosines[0], direction_cosines[1], direction_cosines[2], direction_cosines[3], direction_cosines[4], direction_cosines[5], direction_cosines[6], direction_cosines[7], direction_cosines[8]); /* No need to save grid_spac */ /* This dumps in itk-like planar format */ for (int i = 0; i < 3; i++) { for (int j = 0; j < this->num_coeff / 3; j++) { fprintf (fp, "%.20f\n", this->coeff[j*3 + i]); } } fclose (fp); } Bspline_xform* bspline_xform_load (const char* filename) { int rc; float img_origin[3] = { /* Image origin (in mm) */ 0., 0., 0. }; float img_spacing[3] = { /* Image spacing (in mm) */ 1., 1., 1. }; unsigned int a, b, c; /* For fscanf */ plm_long img_dim[3] = { /* Image size (in vox) */ 0, 0, 0 }; plm_long roi_offset[3] = { /* Position of first vox in ROI (in vox) */ 0, 0, 0 }; plm_long roi_dim[3] = { /* Dimension of ROI (in vox) */ 0, 0, 0 }; plm_long vox_per_rgn[3] = { /* Knot spacing (in vox) */ 0, 0, 0 }; float dc[9] = { /* Direction cosines */ 1., 0., 0., 0., 1., 0., 0., 0., 1. }; std::ifstream ifs (filename); if (!ifs.is_open()) { return 0; } /* Check magic number */ std::string line; getline (ifs, line); if (!string_starts_with (line, "MGH_GPUIT_BSP")) { return 0; } /* Parse header */ while (true) { getline (ifs, line); if (!ifs.good()) { logfile_printf ("Error parsing bspline xform\n"); return 0; } if (line.find('=') == std::string::npos) { /* No "=" found. Better be the first coefficient. */ break; } rc = sscanf (line.c_str(), "img_origin = %f %f %f\n", &img_origin[0], &img_origin[1], &img_origin[2]); if (rc == 3) continue; rc = sscanf (line.c_str(), "img_spacing = %f %f %f\n", &img_spacing[0], &img_spacing[1], &img_spacing[2]); if (rc == 3) continue; rc = sscanf (line.c_str(), "img_dim = %d %d %d\n", &a, &b, &c); if (rc == 3) { img_dim[0] = a; img_dim[1] = b; img_dim[2] = c; continue; } rc = sscanf (line.c_str(), "roi_offset = %d %d %d\n", &a, &b, &c); if (rc == 3) { roi_offset[0] = a; roi_offset[1] = b; roi_offset[2] = c; continue; } rc = sscanf (line.c_str(), "roi_dim = %d %d %d\n", &a, &b, &c); if (rc == 3) { roi_dim[0] = a; roi_dim[1] = b; roi_dim[2] = c; continue; } rc = sscanf (line.c_str(), "vox_per_rgn = %d %d %d\n", &a, &b, &c); if (rc == 3) { vox_per_rgn[0] = a; vox_per_rgn[1] = b; vox_per_rgn[2] = c; continue; } rc = sscanf (line.c_str(), "direction_cosines = %f %f %f %f %f %f %f %f %f\n", &dc[0], &dc[1], &dc[2], &dc[3], &dc[4], &dc[5], &dc[6], &dc[7], &dc[8]); if (rc == 9) continue; logfile_printf ("Error loading bxf file\n%s\n", line.c_str()); return 0; } logfile_printf ("1\n"); /* Allocate memory and build LUTs */ Bspline_xform* bxf = new Bspline_xform; bxf->initialize (img_origin, img_spacing, img_dim, roi_offset, roi_dim, vox_per_rgn, dc); if (bxf->num_coeff < 1) { logfile_printf ("Error loading bxf file, no coefficients\n"); delete bxf; return 0; } /* Load from itk-like planar format */ for (int i = 0; i < 3; i++) { for (int j = 0; j < bxf->num_coeff / 3; j++) { /* The first line is already loaded from before */ if (i != 0 || j != 0) { getline (ifs, line); } if (!ifs.good()) { logfile_printf ("Error parsing bspline xform (idx = %d,%d): %s\n", i, j, filename); delete bxf; return 0; } rc = sscanf (line.c_str(), "%f", &bxf->coeff[j*3 + i]); if (rc != 1) { logfile_printf ("Error parsing bspline xform (idx = %d,%d): %s\n", i, j, filename); delete bxf; return 0; } } } ifs.close(); return bxf; } /* ----------------------------------------------------------------------- Debugging routines ----------------------------------------------------------------------- */ void bspline_xform_dump_coeff (Bspline_xform* bxf, const char* fn) { int i; FILE* fp = fopen (fn,"wb"); for (i = 0; i < bxf->num_coeff; i++) { fprintf (fp, "%20.20f\n", bxf->coeff[i]); } fclose (fp); } void bspline_xform_dump_luts (Bspline_xform* bxf) { plm_long i, j, k, p; int tx, ty, tz; FILE* fp = fopen ("qlut.txt","wb"); /* Dump q_lut */ for (k = 0, p = 0; k < bxf->vox_per_rgn[2]; k++) { for (j = 0; j < bxf->vox_per_rgn[1]; j++) { for (i = 0; i < bxf->vox_per_rgn[0]; i++) { fprintf (fp, "%3d %3d %3d\n", (unsigned int) k, (unsigned int) j, (unsigned int) i); for (tz = 0; tz < 4; tz++) { for (ty = 0; ty < 4; ty++) { for (tx = 0; tx < 4; tx++) { fprintf (fp, " %f", bxf->q_lut[p++]); } } } fprintf (fp, "\n"); } } } fclose (fp); /* Test q_lut */ #if defined (commentout) printf ("Testing q_lut\n"); for (j = 0; j < bxf->vox_per_rgn[2] * bxf->vox_per_rgn[1] * bxf->vox_per_rgn[0]; j++) { float sum = 0.0; for (i = j*64; i < (j+1)*64; i++) { sum += bxf->q_lut[i]; } if (fabs(sum-1.0) > 1.e-7) { printf ("%g ", fabs(sum-1.0)); } } printf ("\n"); #endif fp = fopen ("clut.txt","wb"); p = 0; for (k = 0; k < bxf->rdims[2]; k++) { for (j = 0; j < bxf->rdims[1]; j++) { for (i = 0; i < bxf->rdims[0]; i++) { fprintf (fp, "%3u %3u %3u\n", (unsigned int) k, (unsigned int) j, (unsigned int) i); for (tz = 0; tz < 4; tz++) { for (ty = 0; ty < 4; ty++) { for (tx = 0; tx < 4; tx++) { fprintf (fp, " %u", (unsigned int) bxf->c_lut[p++]); } } } fprintf (fp, "\n"); } } } fclose (fp); } void Bspline_xform::initialize ( float img_origin[3], /* Image origin (in mm) */ float img_spacing[3], /* Image spacing (in mm) */ plm_long img_dim[3], /* Image size (in vox) */ plm_long roi_offset[3], /* Position of first vox in ROI (in vox) */ plm_long roi_dim[3], /* Dimension of ROI (in vox) */ plm_long vox_per_rgn[3], /* Knot spacing (in vox) */ float direction_cosines[9] /* Direction cosines */ ) { plm_long d; plm_long i, j, k, p; plm_long tx, ty, tz; float *A, *B, *C; logfile_printf ("bspline_xform_initialize\n"); this->dc.set (direction_cosines); for (d = 0; d < 3; d++) { /* copy input parameters over */ this->img_origin[d] = img_origin[d]; this->img_spacing[d] = img_spacing[d]; this->img_dim[d] = img_dim[d]; this->roi_offset[d] = roi_offset[d]; this->roi_dim[d] = roi_dim[d]; this->vox_per_rgn[d] = vox_per_rgn[d]; /* grid spacing is in mm */ this->grid_spac[d] = this->vox_per_rgn[d] * fabs (this->img_spacing[d]); /* rdims is the number of regions */ this->rdims[d] = 1 + (this->roi_dim[d] - 1) / this->vox_per_rgn[d]; /* cdims is the number of control points */ this->cdims[d] = 3 + this->rdims[d]; } /* total number of control points & coefficients */ this->num_knots = this->cdims[0] * this->cdims[1] * this->cdims[2]; this->num_coeff = this->cdims[0] * this->cdims[1] * this->cdims[2] * 3; /* Allocate coefficients */ this->coeff = (float*) malloc (sizeof(float) * this->num_coeff); memset (this->coeff, 0, sizeof(float) * this->num_coeff); /* Create q_lut */ this->q_lut = (float*) malloc (sizeof(float) * this->vox_per_rgn[0] * this->vox_per_rgn[1] * this->vox_per_rgn[2] * 64); if (!this->q_lut) { print_and_exit ("Error allocating memory for q_lut\n"); } A = (float*) malloc (sizeof(float) * this->vox_per_rgn[0] * 4); B = (float*) malloc (sizeof(float) * this->vox_per_rgn[1] * 4); C = (float*) malloc (sizeof(float) * this->vox_per_rgn[2] * 4); for (i = 0; i < this->vox_per_rgn[0]; i++) { float ii = ((float) i) / this->vox_per_rgn[0]; float t3 = ii*ii*ii; float t2 = ii*ii; float t1 = ii; A[i*4+0] = (1.0/6.0) * (- 1.0 * t3 + 3.0 * t2 - 3.0 * t1 + 1.0); A[i*4+1] = (1.0/6.0) * (+ 3.0 * t3 - 6.0 * t2 + 4.0); A[i*4+2] = (1.0/6.0) * (- 3.0 * t3 + 3.0 * t2 + 3.0 * t1 + 1.0); A[i*4+3] = (1.0/6.0) * (+ 1.0 * t3); } for (j = 0; j < this->vox_per_rgn[1]; j++) { float jj = ((float) j) / this->vox_per_rgn[1]; float t3 = jj*jj*jj; float t2 = jj*jj; float t1 = jj; B[j*4+0] = (1.0/6.0) * (- 1.0 * t3 + 3.0 * t2 - 3.0 * t1 + 1.0); B[j*4+1] = (1.0/6.0) * (+ 3.0 * t3 - 6.0 * t2 + 4.0); B[j*4+2] = (1.0/6.0) * (- 3.0 * t3 + 3.0 * t2 + 3.0 * t1 + 1.0); B[j*4+3] = (1.0/6.0) * (+ 1.0 * t3); } for (k = 0; k < this->vox_per_rgn[2]; k++) { float kk = ((float) k) / this->vox_per_rgn[2]; float t3 = kk*kk*kk; float t2 = kk*kk; float t1 = kk; C[k*4+0] = (1.0/6.0) * (- 1.0 * t3 + 3.0 * t2 - 3.0 * t1 + 1.0); C[k*4+1] = (1.0/6.0) * (+ 3.0 * t3 - 6.0 * t2 + 4.0); C[k*4+2] = (1.0/6.0) * (- 3.0 * t3 + 3.0 * t2 + 3.0 * t1 + 1.0); C[k*4+3] = (1.0/6.0) * (+ 1.0 * t3); } p = 0; for (k = 0; k < this->vox_per_rgn[2]; k++) { for (j = 0; j < this->vox_per_rgn[1]; j++) { for (i = 0; i < this->vox_per_rgn[0]; i++) { for (tz = 0; tz < 4; tz++) { for (ty = 0; ty < 4; ty++) { for (tx = 0; tx < 4; tx++) { this->q_lut[p++] = A[i*4+tx] * B[j*4+ty] * C[k*4+tz]; } } } } } } free (C); free (B); free (A); /* Create c_lut */ this->c_lut = (plm_long*) malloc (sizeof(plm_long) * this->rdims[0] * this->rdims[1] * this->rdims[2] * 64); p = 0; for (k = 0; k < this->rdims[2]; k++) { for (j = 0; j < this->rdims[1]; j++) { for (i = 0; i < this->rdims[0]; i++) { for (tz = 0; tz < 4; tz++) { for (ty = 0; ty < 4; ty++) { for (tx = 0; tx < 4; tx++) { this->c_lut[p++] = + (k + tz) * this->cdims[0] * this->cdims[1] + (j + ty) * this->cdims[0] + (i + tx); } } } } } } /* Create b_luts */ this->bx_lut = (float*)malloc(4*this->vox_per_rgn[0]*sizeof(float)); this->by_lut = (float*)malloc(4*this->vox_per_rgn[1]*sizeof(float)); this->bz_lut = (float*)malloc(4*this->vox_per_rgn[2]*sizeof(float)); for (int j=0; j<4; j++) { for (int i=0; ivox_per_rgn[0]; i++) { this->bx_lut[i*4+j] = bspline_basis_eval ( j, i, this->vox_per_rgn[0]); } for (int i=0; ivox_per_rgn[1]; i++) { this->by_lut[i*4+j] = bspline_basis_eval ( j, i, this->vox_per_rgn[1]); } for (int i=0; ivox_per_rgn[2]; i++) { this->bz_lut[i*4+j] = bspline_basis_eval ( j, i, this->vox_per_rgn[2]); } } //dump_luts (bxf); logfile_printf ("rdims = (%d,%d,%d)\n", this->rdims[0], this->rdims[1], this->rdims[2]); logfile_printf ("vox_per_rgn = (%d,%d,%d)\n", this->vox_per_rgn[0], this->vox_per_rgn[1], this->vox_per_rgn[2]); logfile_printf ("cdims = (%d %d %d)\n", this->cdims[0], this->cdims[1], this->cdims[2]); } /* ----------------------------------------------------------------------- This extends the bspline grid. Note, that the new roi_offset in the bxf will not be the same as the one requested, because bxf routines implicitly require that the first voxel of the ROI matches the position of the control point. ----------------------------------------------------------------------- */ /* GCS -- Is there an implicit assumption that the roi_origin > 0? */ void bspline_xform_extend ( Bspline_xform* bxf, /* Output: bxf is initialized */ int new_roi_offset[3], /* Position of first vox in ROI (in vox) */ int new_roi_dim[3] /* Dimension of ROI (in vox) */ ) { int d; int roi_offset_diff[3]; int roi_corner_diff[3]; int eb[3]; /* # of control points to "extend before" existing grid */ int ea[3]; /* # of control points to "extend after" existing grid */ int extend_needed = 0; int new_rdims[3]; int new_cdims[3]; plm_long new_num_knots; plm_long new_num_coeff; float* new_coeff; plm_long old_idx; plm_long i, j, k; for (d = 0; d < 3; d++) { roi_offset_diff[d] = new_roi_offset[d] - bxf->roi_offset[d]; roi_corner_diff[d] = (new_roi_offset[d] + new_roi_dim[d]) - (bxf->roi_offset[d] + bxf->roi_offset[d]); if (roi_offset_diff[d] < 0) { eb[d] = (bxf->vox_per_rgn[d] - roi_offset_diff[d] - 1) / bxf->vox_per_rgn[d]; extend_needed = 1; } else { eb[d] = 0; } if (roi_corner_diff[d] > 0) { ea[d] = (bxf->vox_per_rgn[d] + roi_corner_diff[d] - 1) / bxf->vox_per_rgn[d]; extend_needed = 1; } else { ea[d] = 0; } } if (extend_needed) { /* Allocate new memory */ for (d = 0; d < 3; d++) { new_rdims[d] = bxf->rdims[d] + ea[d] + eb[d]; new_cdims[d] = bxf->cdims[d] + ea[d] + eb[d]; } new_num_knots = bxf->cdims[0] * bxf->cdims[1] * bxf->cdims[2]; new_num_coeff = bxf->cdims[0] * bxf->cdims[1] * bxf->cdims[2] * 3; new_coeff = (float*) malloc (sizeof(float) * new_num_coeff); memset (new_coeff, 0, sizeof(float) * new_num_coeff); /* Copy coefficients to new memory */ for (old_idx = 0, k = 0; k < bxf->cdims[2]; k++) { for (j = 0; j < bxf->cdims[1]; j++) { for (i = 0; i < bxf->cdims[0]; i++) { plm_long new_idx = 3 * (((((k + eb[2]) * new_cdims[1]) + (j + eb[1])) * new_cdims[0]) + (i + eb[0])); for (d = 0; d < 3; d++, old_idx++, new_idx++) { new_coeff[new_idx] = bxf->coeff[old_idx]; } } } } /* Free old memory */ free (bxf->coeff); /* Copy over new data into bxf */ for (d = 0; d < 3; d++) { bxf->rdims[d] = new_rdims[d]; bxf->cdims[d] = new_cdims[d]; } bxf->num_knots = new_num_knots; bxf->num_coeff = new_num_coeff; bxf->coeff = new_coeff; /* Special consideration to ROI */ for (d = 0; d < 3; d++) { bxf->roi_offset[d] = bxf->roi_offset[d] - eb[d] * bxf->vox_per_rgn[d]; bxf->roi_dim[d] = new_roi_dim[d] + (new_roi_offset[d] - bxf->roi_offset[d]); } } } void Bspline_xform::fill_coefficients (float val) { int i; for (i = 0; i < this->num_coeff; i++) { this->coeff[i] = val; } } void Bspline_xform::jitter_if_zero () { /* The MI algorithm will get stuck for a set of coefficients all equaling * zero due to the method we use to compute the cost function gradient. * However, it is possible we could be inheriting coefficients from a * prior stage, so we must check for inherited coefficients before * applying an initial offset to the coefficient array. */ for (int i = 0; i < this->num_coeff; i++) { if (this->coeff[i] != 0.0f) { return; } } fill_coefficients (0.01f); } /* Set volume header from B-spline Xform */ void Bspline_xform::get_volume_header (Volume_header *vh) { vh->set (this->img_dim, this->img_origin, this->img_spacing, this->dc.get_matrix()); } void Bspline_xform::log_header () { logfile_printf ("BSPLINE XFORM HEADER\n"); logfile_printf ("vox_per_rgn = %d %d %d\n", this->vox_per_rgn[0], this->vox_per_rgn[1], this->vox_per_rgn[2]); logfile_printf ("roi_offset = %d %d %d\n", this->roi_offset[0], this->roi_offset[1], this->roi_offset[2]); logfile_printf ("roi_dim = %d %d %d\n", this->roi_dim[0], this->roi_dim[1], this->roi_dim[2]); logfile_printf ("img_dc = %s\n", this->dc.get_string().c_str()); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/bspline_xform.h000066400000000000000000000073631321604176500305620ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_xform_h_ #define _bspline_xform_h_ #include "plmbase_config.h" #include "direction_cosines.h" #include "smart_pointer.h" #include "plm_int.h" //TODO: Change type of dc to Direction_cosines* //class Direction_cosines; class Volume; class Volume_header; /*! \brief * The Bspline_xform class encapsulates the B-spline coefficients * used by native registration and warping algorithms. */ class PLMBASE_API Bspline_xform { public: SMART_POINTER_SUPPORT (Bspline_xform); public: Bspline_xform (); ~Bspline_xform (); public: enum Lut_type { LUT_ALIGNED, LUT_UNALIGNED }; public: float img_origin[3]; /* Image origin (in mm) */ float img_spacing[3]; /* Image spacing (in mm) */ plm_long img_dim[3]; /* Image size (in vox) */ Direction_cosines dc; /* Image direction cosines */ plm_long roi_offset[3]; /* Position of first vox in ROI (in vox) */ plm_long roi_dim[3]; /* Dimension of ROI (in vox) */ plm_long vox_per_rgn[3]; /* Knot spacing (in vox) */ float grid_spac[3]; /* Knot spacing (in mm) */ plm_long rdims[3]; /* # of regions in (x,y,z) */ plm_long cdims[3]; /* # of knots in (x,y,z) */ int num_knots; /* Total number of knots (= product(cdims)) */ int num_coeff; /* Total number of coefficents (= product(cdims) * 3) */ float* coeff; /* Coefficients. Vector directions interleaved. */ Lut_type lut_type; /* Which kind of LUT is used */ /* Aligned grid (3D) LUTs */ plm_long* cidx_lut; /* Lookup volume for region number */ plm_long* c_lut; /* Lookup table for control point indices */ plm_long* qidx_lut; /* Lookup volume for region offset */ float* q_lut; /* Lookup table for influence multipliers */ /* Aligned grid (1D) LUTs */ float *bx_lut; /* LUT for influence multiplier in x dir */ float *by_lut; /* LUT for influence multiplier in y dir */ float *bz_lut; /* LUT for influence multiplier in z dir */ /* Unaligned grid (1D) LUTs */ float *ux_lut; /* LUT for influence multiplier in x dir */ float *uy_lut; /* LUT for influence multiplier in y dir */ float *uz_lut; /* LUT for influence multiplier in z dir */ public: void initialize ( float img_origin[3], /* Image origin (in mm) */ float img_spacing[3], /* Image spacing (in mm) */ plm_long img_dim[3], /* Image size (in vox) */ plm_long roi_offset[3], /* Position of first vox in ROI (in vox) */ plm_long roi_dim[3], /* Dimension of ROI (in vox) */ plm_long vox_per_rgn[3], /* Knot spacing (in vox) */ float direction_cosines[9] /* Direction cosines */ ); void save (const char* filename); void fill_coefficients (float val); /*! \brief This function jitters the coefficients if they are all zero. * It is used to prevent local minima artifact when optimizing an MI cost * function for images with the same geometry. */ void jitter_if_zero (); void get_volume_header (Volume_header *vh); void log_header (); }; PLMBASE_C_API Bspline_xform* bspline_xform_load (const char* filename); /* Debugging routines */ PLMBASE_C_API void bspline_xform_dump_coeff (Bspline_xform* bxf, const char* fn); PLMBASE_C_API void bspline_xform_dump_luts (Bspline_xform* bxf); #endif bspline_xform_legacy.cxx000066400000000000000000000073461321604176500324030ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "bspline_xform_legacy.h" #include "logfile.h" Bspline_xform* bspline_xform_legacy_load (const char* filename) { Bspline_xform* bxf; char buf[1024]; FILE* fp; int rc; float img_origin[3]; /* Image origin (in mm) */ float img_spacing[3]; /* Image spacing (in mm) */ unsigned int a, b, c; /* For fscanf */ plm_long img_dim[3]; /* Image size (in vox) */ plm_long roi_offset[3]; /* Position of first vox in ROI (in vox) */ plm_long roi_dim[3]; /* Dimension of ROI (in vox) */ plm_long vox_per_rgn[3]; /* Knot spacing (in vox) */ float dc[9]; /* Direction cosines */ fp = fopen (filename, "r"); if (!fp) return 0; /* Initialize parms */ bxf = new Bspline_xform; /* Skip first line */ if (fgets (buf, 1024, fp) == NULL) { logfile_printf ("File error.\n"); goto free_exit; } /* Read header */ rc = fscanf (fp, "img_origin = %f %f %f\n", &img_origin[0], &img_origin[1], &img_origin[2]); if (rc != 3) { logfile_printf ("Error parsing input xform (img_origin): %s\n", filename); goto free_exit; } rc = fscanf (fp, "img_spacing = %f %f %f\n", &img_spacing[0], &img_spacing[1], &img_spacing[2]); if (rc != 3) { logfile_printf ("Error parsing input xform (img_spacing): %s\n", filename); goto free_exit; } rc = fscanf (fp, "img_dim = %d %d %d\n", &a, &b, &c); if (rc != 3) { logfile_printf ("Error parsing input xform (img_dim): %s\n", filename); goto free_exit; } img_dim[0] = a; img_dim[1] = b; img_dim[2] = c; rc = fscanf (fp, "roi_offset = %d %d %d\n", &a, &b, &c); if (rc != 3) { logfile_printf ("Error parsing input xform (roi_offset): %s\n", filename); goto free_exit; } roi_offset[0] = a; roi_offset[1] = b; roi_offset[2] = c; rc = fscanf (fp, "roi_dim = %d %d %d\n", &a, &b, &c); if (rc != 3) { logfile_printf ("Error parsing input xform (roi_dim): %s\n", filename); goto free_exit; } roi_dim[0] = a; roi_dim[1] = b; roi_dim[2] = c; rc = fscanf (fp, "vox_per_rgn = %d %d %d\n", &a, &b, &c); if (rc != 3) { logfile_printf ("Error parsing input xform (vox_per_rgn): %s\n", filename); goto free_exit; } vox_per_rgn[0] = a; vox_per_rgn[1] = b; vox_per_rgn[2] = c; /* JAS 2012.03.29 : check for direction cosines * we must be careful because older plastimatch xforms do not have this */ rc = fscanf (fp, "direction_cosines = %f %f %f %f %f %f %f %f %f\n", &dc[0], &dc[1], &dc[2], &dc[3], &dc[4], &dc[5], &dc[6], &dc[7], &dc[8]); if (rc != 9) { dc[0] = 1.; dc[3] = 0.; dc[6] = 0.; dc[1] = 0.; dc[4] = 1.; dc[7] = 0.; dc[2] = 0.; dc[5] = 0.; dc[8] = 1.; } /* Allocate memory and build LUTs */ bxf->initialize (img_origin, img_spacing, img_dim, roi_offset, roi_dim, vox_per_rgn, dc); /* This loads from itk-like planar format */ for (int i = 0; i < 3; i++) { for (int j = 0; j < bxf->num_coeff / 3; j++) { rc = fscanf (fp, "%f\n", &bxf->coeff[j*3 + i]); if (rc != 1) { logfile_printf ("Error parsing input xform (idx = %d,%d): %s\n", i, j, filename); goto free_exit; } } } fclose (fp); return bxf; free_exit: fclose (fp); delete bxf; return 0; } bspline_xform_legacy.h000066400000000000000000000006651321604176500320250ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_xform_legacy_h_ #define _bspline_xform_legacy_h_ #include "plmbase_config.h" #include "bspline_xform.h" PLMBASE_API Bspline_xform* bspline_xform_legacy_load (const char* filename); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/clamp.h000066400000000000000000000012151321604176500267750ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _clamp_h_ #define _clamp_h_ #define CLAMP(value, min_value, max_value) \ do { \ if (value < min_value) { \ value = min_value; \ } else if (value > max_value) { \ value = max_value; \ } \ } while (0) #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/cxt_extract.cxx000066400000000000000000000236521321604176500306150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkContourExtractor2DImageFilter.h" #include "itkImage.h" #include "itkImageLinearIteratorWithIndex.h" #include "itkAndConstantToImageFilter.h" #include "itkImageSliceConstIteratorWithIndex.h" #include "cxt_extract.h" #include "itk_image.h" #include "itk_image_origin.h" #include "itk_image_type.h" #include "rtss.h" #include "rtss_contour.h" #include "rtss_roi.h" #include "slice_extract.h" #include "ss_img_extract.h" #include "volume.h" #if defined (commentout) static bool debug_uchar_slice (UCharImage2DType::Pointer uchar_slice) { typedef itk::ImageRegionIterator< UCharImage2DType > IteratorType; IteratorType it1 (uchar_slice, uchar_slice->GetBufferedRegion()); it1.GoToBegin(); while (!it1.IsAtEnd()) { unsigned char p = it1.Get (); if (p != 0) { printf ("Got pixel: %d\n", p); return true; } ++it1; } return false; } static bool debug_uint32_slice (UInt32Image2DType::Pointer slice, uint32_t val) { typedef itk::ImageRegionIterator< UInt32Image2DType > IteratorType; IteratorType it1 (slice, slice->GetBufferedRegion()); it1.GoToBegin(); while (!it1.IsAtEnd()) { uint32_t p = it1.Get (); if (p &= val) { printf ("Got pixel: %d\n", p); return true; } ++it1; } return false; } #endif static void run_marching_squares ( Rtss_roi *curr_structure, const UCharImage2DType::Pointer uchar_slice, unsigned int slice_no, const OriginType& origin, const SpacingType& spacing, const DirectionType& direction ) { typedef itk::ContourExtractor2DImageFilter ContourFilterType; typedef ContourFilterType::VertexType VertexType; /* Run marching squares on the slice */ /* Note: due to an ITK bug, the contour filter cannot be "re-run" with different inputs. Instead we should delete and create a new one for each contour. */ ContourFilterType::Pointer contour_filter = ContourFilterType::New(); contour_filter->SetInput (uchar_slice); contour_filter->SetContourValue (0.5); try { contour_filter->Update(); } catch (itk::ExceptionObject &err) { std::cout << "Exception during marching squares." << std::endl; std::cout << err << std::endl; exit (1); } /* Add marching squares output to cxt. Loop through contours on this slice... */ for (unsigned int i = 0; i < contour_filter->GetNumberOfOutputs(); i++) { ContourFilterType::VertexListConstPointer vertices = contour_filter->GetOutput(i)->GetVertexList(); Rtss_contour *curr_polyline = curr_structure->add_polyline (); curr_polyline->num_vertices = vertices->Size(); curr_polyline->x = (float*) malloc (vertices->Size() * sizeof(float)); curr_polyline->y = (float*) malloc (vertices->Size() * sizeof(float)); curr_polyline->z = (float*) malloc (vertices->Size() * sizeof(float)); curr_polyline->slice_no = slice_no; /* Loop through vertices of this output contour */ for (unsigned int k = 0; k < vertices->Size(); k++) { const VertexType& vertex = vertices->ElementAt (k); curr_polyline->x[k] = origin[0] + direction[0][0] * vertex[0] * spacing[0] + direction[0][1] * vertex[1] * spacing[1] + direction[0][2] * slice_no * spacing[2]; curr_polyline->y[k] = origin[1] + direction[1][0] * vertex[0] * spacing[0] + direction[1][1] * vertex[1] * spacing[1] + direction[1][2] * slice_no * spacing[2]; curr_polyline->z[k] = origin[2] + direction[2][0] * vertex[0] * spacing[0] + direction[2][1] * vertex[1] * spacing[1] + direction[2][2] * slice_no * spacing[2]; } } } /* This function only fills in the polylines. Structure names, id, etc. will be assigned to default values if they are not already set. By default, 32 structures will be searched. If num_structs > 0, only structures with bits between 0 and num_structs-1 will be processed. In the case that we are doing a cxt->mha, then warp, then mha->cxt, the cxt->mha step will mark the bit values in the cxt. In this case, the caller should set check_cxt_bits, so that this function will look at the "bit" field in each cxt structure to see which bit should be processed. */ template void cxt_extract ( Rtss *cxt, T image, int num_structs, bool check_cxt_bits ) { typedef typename T::ObjectType ImageType; typedef itk::ContourExtractor2DImageFilter ContourFilterType; typedef ContourFilterType::VertexType VertexType; typedef itk::ImageSliceConstIteratorWithIndex IteratorType; typedef itk::AndConstantToImageFilter AndFilterType; IteratorType slice_it (image, image->GetLargestPossibleRegion()); typename AndFilterType::Pointer and_filter = AndFilterType::New(); if (num_structs < 0) { num_structs = 32; /* Max 32 structs in 32-bit xormap */ } /* If structure names are unknown, name them, and give them arbitrary id numbers */ for (int j = cxt->num_structures; j < num_structs; j++) { /* Get a free id */ int k = 1; while (cxt->find_structure_by_id (k)) k++; /* Add the structure */ cxt->add_structure ( std::string ("Unknown structure"), std::string(), k); } /* Loop through slices */ int slice_no = 0; slice_it.SetFirstDirection(0); slice_it.SetSecondDirection(1); while (!slice_it.IsAtEnd()) { typename ImageType::IndexType idx; UInt32Image2DType::Pointer uint32_slice; UCharImage2DType::Pointer uchar_slice; /* Make a copy of the current slice */ idx = slice_it.GetIndex(); uint32_slice = slice_extract (image, idx[2]); and_filter->SetInput (uint32_slice); for (int j = 0; j < num_structs; j++) { /* And the current slice with the mask for this structure */ Rtss_roi *curr_structure = cxt->slist[j]; /* Choose the bit value for this structure */ uint32_t val; if (check_cxt_bits) { if (curr_structure->bit == -1) { /* Skip if this structure is not represented in image */ continue; } else { val = (1 << curr_structure->bit); } } else { val = (1 << j); } /* Mask the slice with this bit */ and_filter->SetConstant (val); try { and_filter->Update (); } catch (itk::ExceptionObject &err) { std::cout << "Exception during and operation." << std::endl; std::cout << err << std::endl; exit (1); } uchar_slice = and_filter->GetOutput (); run_marching_squares (curr_structure, uchar_slice, slice_no, itk_image_origin (image), image->GetSpacing(), image->GetDirection()); } slice_it.NextSlice(); slice_no ++; } } template<> void cxt_extract ( Rtss *cxt, UCharVecImageType::Pointer image, int num_structs, bool check_cxt_bits ) { typedef itk::ContourExtractor2DImageFilter ContourFilterType; typedef ContourFilterType::VertexType VertexType; typedef itk::ImageSliceConstIteratorWithIndex IteratorType; typedef itk::AndConstantToImageFilter< UCharImage2DType, unsigned char, UCharImage2DType> AndFilterType; AndFilterType::Pointer and_filter = AndFilterType::New(); if (num_structs < 0) { num_structs = image->GetVectorLength() * 8; } /* If structure names are unknown, name them, and give them arbitrary id numbers */ for (int j = cxt->num_structures; j < num_structs; j++) { /* Get a free id */ int k = 1; while (cxt->find_structure_by_id (k)) k++; /* Add the structure */ cxt->add_structure ( std::string ("Unknown structure"), std::string(), k); } /* Loop through slices */ int num_slices = image->GetLargestPossibleRegion().GetSize(2); unsigned int num_uchar = image->GetVectorLength(); for (int slice_no = 0; slice_no < num_slices; slice_no++) { /* Make a copy of the current slice */ UCharVecImage2DType::Pointer ucharvec_slice = slice_extract (image, slice_no); /* Loop through uchars for this slice */ for (unsigned int uchar_no = 0; uchar_no < num_uchar; uchar_no++) { /* Extract a single uchar slice from uchar_vec slice */ UCharImage2DType::Pointer uchar_slice = ss_img_extract_uchar (ucharvec_slice, uchar_no); and_filter->SetInput (uchar_slice); /* Look for structures which use this uchar */ for (int j = 0; j < num_structs; j++) { Rtss_roi *curr_structure = cxt->slist[j]; int bit; unsigned char mask; /* Choose the bit value for this structure */ if (check_cxt_bits) { bit = curr_structure->bit; } else { bit = j; } /* Make a mask value */ if (bit < (int) (uchar_no*8) || bit > (int) (uchar_no*8+7)) { /* Skip structures not in this uchar */ /* Note: this also skips empty structures, which have a bit value of -1 */ continue; } bit -= uchar_no*8; mask = (1 << bit); /* And the current slice with the mask for this structure */ and_filter->SetConstant (mask); try { and_filter->Update (); } catch (itk::ExceptionObject &err) { std::cout << "Exception during and operation." << std::endl; std::cout << err << std::endl; exit (1); } uchar_slice = and_filter->GetOutput (); run_marching_squares (curr_structure, uchar_slice, slice_no, itk_image_origin (image), image->GetSpacing(), image->GetDirection()); } } } } /* Explicit instantiations */ template PLMBASE_API void cxt_extract (Rtss *cxt, UInt32ImageType::Pointer image, int num_structs, bool check_cxt_bits); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/cxt_extract.h000066400000000000000000000007111321604176500302310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _cxt_extract_h_ #define _cxt_extract_h_ #include "plmbase_config.h" class Rtss; template void cxt_extract ( Rtss *cxt, T image, int num_structs, bool check_cxt_bits ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/cxt_io.cxx000066400000000000000000000241301321604176500275420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "cxt_io.h" #include "file_util.h" #include "metadata.h" #include "plm_math.h" #include "print_and_exit.h" #include "rt_study_metadata.h" #include "rtss.h" #include "rtss_contour.h" #include "rtss_roi.h" #include "string_util.h" #define CXT_BUFLEN 2048 void cxt_load ( Rtss *cxt, /* Output: load into this object */ Rt_study_metadata *rsm, /* Output: load into this object */ const char *cxt_fn /* Input: file to load from */ ) { Rtss_contour* curr_contour; float val_x = 0; float val_y = 0; float val_z = 0; int have_offset = 0; int have_dim = 0; int have_spacing = 0; std::ifstream fp (cxt_fn); if (!fp.is_open()) { print_and_exit ("Could not open contour file for read: %s\n", cxt_fn); } Metadata::Pointer meta = rsm->get_study_metadata (); /* Part 1: Dicom info */ while (1) { std::string tag, val; getline (fp, tag); if (!fp.good()) { fprintf (stderr, "Error. cxt file is not formatted correctly: %s\n", cxt_fn); exit (-1); } size_t loc = tag.find (' '); if (loc != std::string::npos) { val = string_trim (tag.substr (loc + 1)); tag = tag.substr (0, loc); } printf ("%s|%s|\n", tag.c_str(), val.c_str()); if (tag == "ROI_NAMES") { break; } else if (val == "") { continue; } else if (tag == "PATIENT_NAME") { meta->set_metadata (0x0010, 0x0010, val.c_str()); } else if (tag == "PATIENT_ID") { meta->set_metadata (0x0010, 0x0020, val.c_str()); } else if (tag == "PATIENT_SEX") { meta->set_metadata (0x0010, 0x0040, val.c_str()); } else if (tag == "STUDY_ID") { meta->set_metadata (0x0020, 0x0010, val.c_str()); } else if (tag == "CT_STUDY_UID") { rsm->set_study_uid (val.c_str()); } else if (tag == "CT_SERIES_UID") { rsm->set_ct_series_uid (val.c_str()); } else if (tag == "CT_FRAME_OF_REFERENCE_UID") { rsm->set_frame_of_reference_uid (val.c_str()); } else if (tag == "OFFSET") { if (3 == sscanf (val.c_str(), "%f %f %f", &val_x, &val_y, &val_z)) { have_offset = 1; cxt->m_offset[0] = val_x; cxt->m_offset[1] = val_y; cxt->m_offset[2] = val_z; } } else if (tag == "DIMENSION") { int int_x, int_y, int_z; if (3 == sscanf (val.c_str(), "%d %d %d", &int_x, &int_y, &int_z)) { have_dim = 1; cxt->m_dim[0] = int_x; cxt->m_dim[1] = int_y; cxt->m_dim[2] = int_z; } } else if (tag == "SPACING") { if (3 == sscanf (val.c_str(), "%f %f %f", &val_x, &val_y, &val_z)) { have_spacing = 1; cxt->m_spacing[0] = val_x; cxt->m_spacing[1] = val_y; cxt->m_spacing[2] = val_z; } } } if (have_offset && have_dim && have_spacing) { cxt->have_geometry = 1; } /* Part 2: Structures info */ printf ("Starting structure parsing\n"); while (1) { std::string line, color, name; int struct_id; int rc; getline (fp, line); if (!fp.good()) { fprintf (stderr, "Error. cxt file is not formatted correctly: %s\n", cxt_fn); exit (-1); } std::vector tokens = string_split (line, '|'); if (tokens.size() < 3) { /* Normal loop exit */ break; } rc = sscanf (tokens[0].c_str(), "%d", &struct_id); if (rc != 1) { goto not_successful; } color = tokens[1]; name = tokens[2]; cxt->add_structure (name, color, struct_id); } /* Part 3: Contour info */ printf ("Starting contour parsing\n"); while (1) { int rc, k; int num_pt = 0; int struct_id = 0; int slice_idx; Rtss_roi* curr_structure; std::string line; if (!getline (fp, line)) { /* Normal loop exit */ break; } std::vector tokens = string_split (line, '|'); if (tokens.size() == 0) { /* No data on this line; should not happen, but we'll accept this. */ continue; } if (tokens.size() != 6) { goto not_successful; } /* Structure id: required */ rc = sscanf (tokens[0].c_str(), "%d", &struct_id); if (rc != 1) { goto not_successful; } /* Contour thickness: not used */ /* Num vertices: required */ rc = sscanf (tokens[2].c_str(), "%d", &num_pt); if (rc != 1) { goto not_successful; } /* Slice idx: optional */ rc = sscanf (tokens[3].c_str(), "%d", &slice_idx); if (rc != 1) { slice_idx = -1; } /* Slice uid: optional */ std::string slice_uid = tokens[4]; /* Find structure which was created when parsing structure. If there is no header line for this structure, we will will not add the contour into the structure */ curr_structure = cxt->find_structure_by_id (struct_id); if (!curr_structure) { continue; } curr_contour = curr_structure->add_polyline (); curr_contour->num_vertices = num_pt; curr_contour->slice_no = slice_idx; if (slice_uid[0]) { curr_contour->ct_slice_uid = slice_uid; } else { curr_contour->ct_slice_uid = ""; } curr_contour->x = (float*) malloc (num_pt * sizeof(float)); curr_contour->y = (float*) malloc (num_pt * sizeof(float)); curr_contour->z = (float*) malloc (num_pt * sizeof(float)); if (curr_contour->x == 0 || curr_contour->y == 0 || curr_contour->z == 0) { print_and_exit ("Error allocating memory"); } const char *p = tokens[5].c_str(); for (k = 0; k < num_pt; k++) { float x, y, z; int nchar; if (*p == '\\') { p++; } rc = sscanf (p, "%f\\%f\\%f%n", &x, &y, &z, &nchar); if (rc < 3) { goto not_successful; } curr_contour->x[k] = x; curr_contour->y[k] = y; curr_contour->z[k] = z; p += nchar; } slice_idx = 0; num_pt = 0; } return; not_successful: print_and_exit ("Error parsing input file: %s\n", cxt_fn); } void cxt_save ( Rtss *cxt, /* Input: save this object */ const Rt_study_metadata::Pointer& rsm, /* In: save this object */ const char* cxt_fn, /* Input: File to save to */ bool prune_empty /* Input: Should we prune empty structures? */ ) { FILE *fp; /* Prepare output directory */ make_parent_directories (cxt_fn); fp = fopen (cxt_fn, "wb"); if (!fp) { fprintf (stderr, "Could not open contour file for write: %s\n", cxt_fn); exit (-1); } /* Part 1: Dicom info */ Metadata::Pointer meta = rsm->get_study_metadata (); /* GCS FIX: There needs to be a way that tells if these are loaded or some default anonymous value */ if (rsm) { fprintf (fp, "CT_SERIES_UID %s\n", rsm->get_ct_series_uid()); } else { fprintf (fp, "CT_SERIES_UID\n"); } if (rsm) { fprintf (fp, "CT_STUDY_UID %s\n", rsm->get_study_uid()); } else { fprintf (fp, "CT_STUDY_UID\n"); } if (rsm) { fprintf (fp, "CT_FRAME_OF_REFERENCE_UID %s\n", rsm->get_frame_of_reference_uid()); } else { fprintf (fp, "CT_FRAME_OF_REFERENCE_UID\n"); } fprintf (fp, "PATIENT_NAME %s\n", meta->get_metadata (0x0010, 0x0010).c_str()); fprintf (fp, "PATIENT_ID %s\n", meta->get_metadata (0x0010, 0x0020).c_str()); fprintf (fp, "PATIENT_SEX %s\n", meta->get_metadata (0x0010, 0x0040).c_str()); fprintf (fp, "STUDY_ID %s\n", meta->get_metadata (0x0020, 0x0010).c_str()); if (cxt->have_geometry) { fprintf (fp, "OFFSET %g %g %g\n", cxt->m_offset[0], cxt->m_offset[1], cxt->m_offset[2]); fprintf (fp, "DIMENSION %u %u %u\n", (unsigned int) cxt->m_dim[0], (unsigned int) cxt->m_dim[1], (unsigned int) cxt->m_dim[2]); fprintf (fp, "SPACING %g %g %g\n", cxt->m_spacing[0], cxt->m_spacing[1], cxt->m_spacing[2]); } /* Part 2: Structures info */ fprintf (fp, "ROI_NAMES\n"); for (size_t i = 0; i < cxt->num_structures; i++) { Rtss_roi *curr_structure = cxt->slist[i]; if (prune_empty && curr_structure->num_contours <= 0) { continue; } fprintf (fp, "%d|%s|%s\n", curr_structure->id, (curr_structure->color.empty() ? "255\\0\\0" : curr_structure->color.c_str()), curr_structure->name.c_str()); } fprintf (fp, "END_OF_ROI_NAMES\n"); /* Part 3: Contour info */ for (size_t i = 0; i < cxt->num_structures; i++) { Rtss_roi *curr_structure = cxt->slist[i]; if (prune_empty && curr_structure->num_contours <= 0) { continue; } for (size_t j = 0; j < curr_structure->num_contours; j++) { Rtss_contour *curr_polyline = curr_structure->pslist[j]; /* struct_no|contour_thickness|num_points|slice_no|slice_uid|points */ /* I don't think contour thickness is used. */ fprintf (fp, "%d||%d|", curr_structure->id, (int) curr_polyline->num_vertices); /* slice_no and slice_uid are optional */ if (curr_polyline->slice_no >= 0) { fprintf (fp, "%d|", curr_polyline->slice_no); } else { fprintf (fp, "|"); } if (curr_polyline->ct_slice_uid.empty()) { fprintf (fp, "|"); } else { fprintf (fp, "%s|", curr_polyline->ct_slice_uid.c_str()); } for (size_t k = 0; k < curr_polyline->num_vertices; k++) { if (k > 0) { fprintf (fp, "\\"); } fprintf (fp, "%f\\%f\\%f", curr_polyline->x[k], curr_polyline->y[k], curr_polyline->z[k]); } fprintf (fp, "\n"); } } fclose (fp); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/cxt_io.h000066400000000000000000000017411321604176500271720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _cxt_io_h_ #define _cxt_io_h_ #include "plmbase_config.h" #include "rt_study_metadata.h" class Metadata; class Rtss; PLMBASE_API Rtss* cxt_load_ss_list ( Rtss* cxt, const char* xorlist_fn ); PLMBASE_API void cxt_load ( Rtss *cxt, /* Output: load into this object */ Rt_study_metadata *rsm, /* Output: load into this object */ const char *cxt_fn /* Input: file to load from */ ); PLMBASE_API void cxt_save ( Rtss *cxt, /* In: save this object */ const Rt_study_metadata::Pointer& rsm, /* In: save this object */ const char* cxt_fn, /* In: File to save to */ bool prune_empty /* In: Prune empty structures? */ ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_config.h000066400000000000000000000011121321604176500303240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_config_h_ #define _dcmtk_config_h_ #include "plmbase_config.h" /* Debian OS install of DCMTK is broken. This is the workaround. */ #if DCMTK_HAVE_CFUNIX_H #define HAVE_CONFIG_H 1 #endif /* Make sure OS specific configuration is included before other dcmtk headers. */ #include "dcmtk/config/osconfig.h" #endif /* __dcmtk_config_h__ */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_file.cxx000066400000000000000000000147001321604176500303600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_file.h" #include "logfile.h" #include "print_and_exit.h" #include "string_util.h" class Dcmtk_file_private { public: std::string m_fn; DcmFileFormat *m_dfile; Volume_header m_vh; float m_zpos; bool m_valid; public: Dcmtk_file_private () { m_dfile = new DcmFileFormat; m_fn = ""; m_zpos = 0.f; m_valid = false; } ~Dcmtk_file_private () { delete m_dfile; } }; Dcmtk_file::Dcmtk_file () { d_ptr = new Dcmtk_file_private; } Dcmtk_file::Dcmtk_file (const char *fn) { d_ptr = new Dcmtk_file_private; this->load_header (fn); } Dcmtk_file::~Dcmtk_file () { delete d_ptr; } bool Dcmtk_file::is_valid () const { return d_ptr->m_valid; } void Dcmtk_file::debug () const { printf (" %s\n", d_ptr->m_fn.c_str()); d_ptr->m_vh.print (); } DcmDataset* Dcmtk_file::get_dataset (void) const { return d_ptr->m_dfile->getDataset(); } /* Look up DICOM value from tag */ const char* Dcmtk_file::get_cstr (const DcmTagKey& tag_key) const { const char *c = 0; DcmDataset *dset = d_ptr->m_dfile->getDataset(); if (dset->findAndGetString(tag_key, c).good() && c) { return c; } return 0; } bool Dcmtk_file::get_uint8 (const DcmTagKey& tag_key, uint8_t* val) const { return d_ptr->m_dfile->getDataset()->findAndGetUint8 ( tag_key, (*val)).good(); } bool Dcmtk_file::get_uint16 (const DcmTagKey& tag_key, uint16_t* val) const { return d_ptr->m_dfile->getDataset()->findAndGetUint16 ( tag_key, (*val)).good(); } bool Dcmtk_file::get_float (const DcmTagKey& tag_key, float* val) const { return d_ptr->m_dfile->getDataset()->findAndGetFloat32 ( tag_key, (*val)).good(); } bool Dcmtk_file::get_ds_float (const DcmTagKey& tag_key, float* val) const { const char *c = this->get_cstr (tag_key); if (!c) return false; int rc = sscanf (c, "%f", val); if (rc != 1) return false; return true; } bool Dcmtk_file::get_uint8_array (const DcmTagKey& tag_key, const uint8_t** val, unsigned long* count) const { const Uint8* foo; OFCondition rc = d_ptr->m_dfile->getDataset()->findAndGetUint8Array ( tag_key, foo, count, OFFalse); if (val) { *val = foo; } return rc.good(); } bool Dcmtk_file::get_int16_array (const DcmTagKey& tag_key, const int16_t** val, unsigned long* count) const { const Sint16* foo; OFCondition rc = d_ptr->m_dfile->getDataset()->findAndGetSint16Array ( tag_key, foo, count, OFFalse); *val = foo; return rc.good(); } bool Dcmtk_file::get_uint16_array (const DcmTagKey& tag_key, const uint16_t** val, unsigned long* count) const { const Uint16* foo; OFCondition rc = d_ptr->m_dfile->getDataset()->findAndGetUint16Array ( tag_key, foo, count, OFFalse); if (val) { *val = foo; } return rc.good(); } bool Dcmtk_file::get_element (const DcmTagKey& tag_key, DcmElement* val) const { return d_ptr->m_dfile->getDataset()->findAndGetElement(tag_key, val).good(); } bool Dcmtk_file::get_sequence (const DcmTagKey& tag_key, DcmSequenceOfItems*& seq) const { return d_ptr->m_dfile->getDataset()->findAndGetSequence ( tag_key, seq).good(); } const Volume_header* Dcmtk_file::get_volume_header () const { return &d_ptr->m_vh; } const Direction_cosines& Dcmtk_file::get_direction_cosines () const { return d_ptr->m_vh.get_direction_cosines(); } float Dcmtk_file::get_z_position () const { #if defined (commentout) return d_ptr->m_vh.get_origin()[2]; #endif return d_ptr->m_zpos; } void Dcmtk_file::load_header (const char *fn) { /* Save a copy of the filename */ d_ptr->m_fn = fn; /* Open the file */ OFCondition cond = d_ptr->m_dfile->loadFile (fn, EXS_Unknown, EGL_noChange); if (cond.bad()) { /* If it's not a dicom file, loadFile() fails. */ return; } /* Load image header */ DcmDataset *dset = d_ptr->m_dfile->getDataset(); OFCondition ofrc; const char *c; uint16_t rows; uint16_t cols; /* ImagePositionPatient */ float origin[3]; ofrc = dset->findAndGetString (DCM_ImagePositionPatient, c); if (ofrc.good() && c) { int rc = parse_dicom_float3 (origin, c); if (!rc) { d_ptr->m_vh.set_origin (origin); } } /* Rows, Columns */ ofrc = dset->findAndGetUint16 (DCM_Rows, rows); if (ofrc.good()) { ofrc = dset->findAndGetUint16 (DCM_Columns, cols); if (ofrc.good()) { plm_long dim[3]; dim[0] = cols; dim[1] = rows; dim[2] = 1; d_ptr->m_vh.set_dim (dim); } } /* ImageOrientationPatient */ float direction_cosines[9]; ofrc = dset->findAndGetString (DCM_ImageOrientationPatient, c); if (ofrc.good() && c) { int rc = parse_dicom_float6 (direction_cosines, c); if (!rc) { direction_cosines[6] = direction_cosines[1]*direction_cosines[5] - direction_cosines[2]*direction_cosines[4]; direction_cosines[7] = direction_cosines[2]*direction_cosines[3] - direction_cosines[0]*direction_cosines[5]; direction_cosines[8] = direction_cosines[0]*direction_cosines[4] - direction_cosines[1]*direction_cosines[3]; d_ptr->m_vh.set_direction_cosines (direction_cosines); } } /* PixelSpacing */ ofrc = dset->findAndGetString (DCM_PixelSpacing, c); if (ofrc.good() && c) { float dcm_spacing[2]; int rc = parse_dicom_float2 (dcm_spacing, c); if (!rc) { float spacing[3] = { dcm_spacing[1], dcm_spacing[0], 0.0 }; d_ptr->m_vh.set_spacing (spacing); } } /* Compute z position */ d_ptr->m_zpos = + direction_cosines[6] * origin[0] + direction_cosines[7] * origin[1] + direction_cosines[8] * origin[2]; d_ptr->m_valid = true; } bool dcmtk_file_compare_z_position (const Dcmtk_file* f1, const Dcmtk_file* f2) { return f1->get_z_position () < f2->get_z_position (); } bool dcmtk_file_compare_z_position (const Dcmtk_file::Pointer& f1, const Dcmtk_file::Pointer& f2) { return f1->get_z_position () < f2->get_z_position (); } void dcmtk_file_test (const char *fn) { Dcmtk_file df(fn); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_file.h000066400000000000000000000041641321604176500300100ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_file_h_ #define _dcmtk_file_h_ #include "plmbase_config.h" #include "plm_int.h" #include "smart_pointer.h" #include "volume_header.h" class DcmDataset; class DcmElement; class DcmSequenceOfItems; class DcmTagKey; class Dcmtk_file_private; class Dcmtk_file { public: SMART_POINTER_SUPPORT (Dcmtk_file); Dcmtk_file_private *d_ptr; public: Dcmtk_file (); Dcmtk_file (const char *fn); ~Dcmtk_file (); public: bool is_valid () const; void debug () const; DcmDataset* get_dataset (void) const; const char* get_cstr (const DcmTagKey& tag_key) const; bool get_uint8 (const DcmTagKey& tag_key, uint8_t* val) const; bool get_uint16 (const DcmTagKey& tag_key, uint16_t* val) const; bool get_float (const DcmTagKey& tag_key, float* val) const; bool get_ds_float (const DcmTagKey& tag_key, float* val) const; bool get_uint8_array (const DcmTagKey& tag_key, const uint8_t** val, unsigned long* count) const; bool get_uint16_array (const DcmTagKey& tag_key, const uint16_t** val, unsigned long* count) const; bool get_int16_array (const DcmTagKey& tag_key, const int16_t** val, unsigned long* count) const; bool get_uint32_array (const DcmTagKey& tag_key, const uint32_t** val, unsigned long* count) const; bool get_int32_array (const DcmTagKey& tag_key, const int32_t** val, unsigned long* count) const; bool get_element (const DcmTagKey& tag_key, DcmElement* val) const; bool get_sequence (const DcmTagKey& tag_key, DcmSequenceOfItems*& seq) const; const Volume_header* get_volume_header () const; const Direction_cosines& get_direction_cosines () const; float get_z_position () const; void load_header (const char *fn); }; PLMBASE_C_API void dcmtk_series_test (char *dicom_dir); PLMBASE_C_API bool dcmtk_file_compare_z_position ( const Dcmtk_file::Pointer& f1, const Dcmtk_file::Pointer& f2 ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_image.cxx000066400000000000000000000573551321604176500305400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_file.h" #include "dcmtk_metadata.h" #include "dcmtk_module.h" #include "dcmtk_rt_study.h" #include "dcmtk_rt_study_p.h" #include "dcmtk_series.h" #include "dcmtk_slice_data.h" #include "dcmtk_uid.h" #include "file_util.h" #include "logfile.h" #include "rt_study_metadata.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_math.h" #include "plm_uid_prefix.h" #include "plm_version.h" #include "print_and_exit.h" #include "slice_list.h" #include "string_util.h" #include "volume.h" void Dcmtk_rt_study::image_load () { /* Set up outputs */ Plm_image::Pointer pli = Plm_image::New(); d_ptr->img = pli; /* Make abbreviations */ Dcmtk_series *ds_image = d_ptr->ds_image; const Dcmtk_file_list& ds_flist = ds_image->get_flist (); /* Create a container to hold different groups of files */ std::list group_list; /* Arrange files into groups according to direction cosines */ for (Dcmtk_file_list::const_iterator it = ds_flist.begin(); it != ds_flist.end(); ++it) { const Dcmtk_file::Pointer& df = (*it); bool match_found = false; std::list::iterator grit; for (grit = group_list.begin(); grit != group_list.end(); ++grit) { Dcmtk_file_list& flp = *grit; const Dcmtk_file::Pointer& flp_df = flp.front(); if (flp_df->get_direction_cosines() == df->get_direction_cosines()) { /* Add logic to append to flp */ //printf ("Match found. :)\n"); match_found = true; flp.push_back (df); break; } } if (match_found) { continue; } /* Else insert new element into group_list */ group_list.push_back (Dcmtk_file_list()); group_list.back().push_back (df); } /* If multiple groups, emit a warning. Choose the largest group. */ Dcmtk_file_list *flist = &group_list.front (); if (group_list.size() > 1) { lprintf ("Warning, DICOM series with multiple direction cosines\n"); std::list::iterator grit; for (grit = group_list.begin(); grit != group_list.end(); ++grit) { if ((*grit).size() > flist->size()) { flist = &*grit; } } } /* Sort group in Z direction */ flist->sort (dcmtk_file_compare_z_position); /* * GCS FIX: * Remove minimum 2 slices requirement * Check consistency (dim, origin) of images w/in series * Different image types * Refine slice spacing based on entire chunk size */ /* Check for minimum 2 slices */ if (flist->size() < 2) { return; } /* Get first slice */ const Dcmtk_file* df = (*flist->begin()).get(); /* Store UIDs */ if (d_ptr->rt_study_metadata) { d_ptr->rt_study_metadata->set_ct_series_uid ( df->get_cstr (DCM_SeriesInstanceUID)); d_ptr->rt_study_metadata->set_frame_of_reference_uid ( df->get_cstr (DCM_FrameOfReferenceUID)); d_ptr->rt_study_metadata->set_study_uid ( df->get_cstr (DCM_StudyInstanceUID)); d_ptr->rt_study_metadata->set_study_date ( df->get_cstr (DCM_StudyDate)); d_ptr->rt_study_metadata->set_study_time ( df->get_cstr (DCM_StudyTime)); d_ptr->rt_study_metadata->set_study_id ( df->get_cstr (DCM_StudyID)); /* Store remaining metadata */ Metadata::Pointer& study_metadata = d_ptr->rt_study_metadata->get_study_metadata (); dcmtk_copy_into_metadata (study_metadata, df, DCM_PatientName); dcmtk_copy_into_metadata (study_metadata, df, DCM_PatientID); dcmtk_copy_into_metadata (study_metadata, df, DCM_PatientSex); dcmtk_copy_into_metadata (study_metadata, df, DCM_PatientPosition); dcmtk_copy_into_metadata (study_metadata, df, DCM_StudyID); Metadata::Pointer& image_metadata = d_ptr->rt_study_metadata->get_image_metadata (); dcmtk_copy_into_metadata (image_metadata, df, DCM_Modality); dcmtk_copy_into_metadata (image_metadata, df, DCM_InstanceCreationDate); dcmtk_copy_into_metadata (image_metadata, df, DCM_InstanceCreationTime); dcmtk_copy_into_metadata (image_metadata, df, DCM_SeriesDescription); } /* Divine image type */ uint16_t samp_per_pix, bits_alloc, bits_stored, high_bit, pixel_rep; const char* phot_interp; bool rc = df->get_uint16 (DCM_SamplesPerPixel, &samp_per_pix); if (!rc) { return; } phot_interp = df->get_cstr (DCM_PhotometricInterpretation); if (!phot_interp) { return; } rc = df->get_uint16 (DCM_BitsAllocated, &bits_alloc); if (!rc) { return; } rc = df->get_uint16 (DCM_BitsStored, &bits_stored); if (!rc) { return; } rc = df->get_uint16 (DCM_HighBit, &high_bit); if (!rc) { return; } rc = df->get_uint16 (DCM_PixelRepresentation, &pixel_rep); if (!rc) { return; } float rescale_slope, rescale_intercept; rc = df->get_ds_float (DCM_RescaleIntercept, &rescale_intercept); if (!rc) { rescale_intercept = 0; } rc = df->get_ds_float (DCM_RescaleSlope, &rescale_slope); if (!rc) { rescale_slope = 1; } #if defined (commentout) lprintf ("Samp_per_pix: %d\n", (int) samp_per_pix); lprintf ("Phot_interp: %s\n", phot_interp); lprintf ("Bits_alloc: %d\n", (int) bits_alloc); lprintf ("Bits_stored: %d\n", (int) bits_stored); lprintf ("High_bit: %d\n", (int) high_bit); lprintf ("Pixel_rep: %d\n", (int) pixel_rep); lprintf ("S/I = %f/%f\n", rescale_slope, rescale_intercept); #endif /* Some kinds of images we don't know how to deal with. Don't load these. */ if (samp_per_pix != 1) { lprintf ("Sorry, couldn't load image: samp_per_pix\n"); return; } if (strcmp (phot_interp, "MONOCHROME2")) { lprintf ("Sorry, couldn't load image: phot_interp\n"); return; } if (bits_alloc != 16 && bits_alloc != 8) { lprintf ("Sorry, couldn't load image: bits_alloc\n"); return; } if (bits_stored != high_bit + 1) { lprintf ("Sorry, couldn't load image: bits_stored/high_bit\n"); return; } if (pixel_rep != 0 && pixel_rep != 1) { lprintf ("Sorry, couldn't load image: pixel_rep\n"); return; } /* If PLM_CONFIG_VOL_LIST is enabled, the image will be loaded into a PLM_IMG_TYPE_GPUIT_LIST */ #if (PLM_CONFIG_VOL_LIST) /* Get first slice of group */ Dcmtk_file_list::iterator it = flist->begin(); df = it->get(); /* Get next slice in group */ float z_init, z_prev, z_diff, z_last; int slice_no = 0; float best_chunk_z_start = z_init = z_prev = df->get_z_position (); ++it; ++slice_no; df = (*it).get(); z_diff = df->get_z_position() - z_prev; z_last = z_prev = df->get_z_position(); /* We want to find the number and spacing for each chunk within the group. These are used to set the dim and spacing of the volume. */ int this_chunk_start = 0, best_chunk_start = 0; float this_chunk_diff = z_diff, best_chunk_diff = z_diff; int this_chunk_len = 2, best_chunk_len = 2; /* Loop through remaining slices */ while (++it != flist->end()) { ++slice_no; printf ("Slice no: %d\n", slice_no); df = (*it).get(); z_diff = df->get_z_position() - z_prev; z_last = z_prev = df->get_z_position(); if (fabs (this_chunk_diff - z_diff) > 0.11) { /* Start a new chunk if difference in thickness is more than 0.1 millimeter */ this_chunk_start = slice_no - 1; this_chunk_len = 2; this_chunk_diff = z_diff; } else { /* Same thickness, increase size of this chunk */ this_chunk_diff = ((this_chunk_len * this_chunk_diff) + z_diff) / (this_chunk_len + 1); this_chunk_len++; /* Check if this chunk is now the best chunk */ if (this_chunk_len > best_chunk_len) { best_chunk_start = this_chunk_start; best_chunk_len = this_chunk_len; best_chunk_diff = this_chunk_diff; best_chunk_z_start = z_prev - (best_chunk_len-1) * best_chunk_diff; } } } #if defined (commentout) Dcmtk_file_list& flp = *grit; const Dcmtk_file::Pointer dfp = grit->front(); Volume::Pointer vol = Volume::New ( const plm_long dim[3], const float origin[3], const float spacing[3], &dfp->get_direction_cosines(), vh, PT_FLOAT, 1); #endif #else /* NOT VOL_LIST */ /* Get next slice in first chunk */ float z_init, z_prev, z_diff, z_last; int slice_no = 0; float best_chunk_z_start = z_init = z_prev = df->get_z_position (); std::list::const_iterator it = flist->begin(); ++it; ++slice_no; df = (*it).get(); z_diff = df->get_z_position() - z_prev; z_last = z_prev = df->get_z_position(); /* We want to find the largest chunk with equal spacing. This will be used to resample in the case of irregular spacing. */ int this_chunk_start = 0, best_chunk_start = 0; float this_chunk_diff = z_diff, best_chunk_diff = z_diff; size_t this_chunk_len = 2, best_chunk_len = 2; /* Loop through remaining slices */ while (++it != flist->end()) { ++slice_no; df = (*it).get(); z_diff = df->get_z_position() - z_prev; z_last = z_prev = df->get_z_position(); if (fabs (this_chunk_diff - z_diff) > 0.11) { /* Start a new chunk if difference in thickness is more than 0.1 millimeter */ this_chunk_start = slice_no - 1; this_chunk_len = 2; this_chunk_diff = z_diff; } else { /* Same thickness, increase size of this chunk */ this_chunk_diff = ((this_chunk_len * this_chunk_diff) + z_diff) / (this_chunk_len + 1); this_chunk_len++; /* Check if this chunk is now the best chunk */ if (this_chunk_len > best_chunk_len) { best_chunk_start = this_chunk_start; best_chunk_len = this_chunk_len; best_chunk_diff = this_chunk_diff; best_chunk_z_start = z_prev - (best_chunk_len-1) * best_chunk_diff; } } } /* Report information about best chunk */ if (best_chunk_len != flist->size()) { lprintf ("** Warning, inequal slice spacing detected when loading DICOM.\n"); lprintf ("Best chunck:\n Slices %d to %d from (0 to %d)\n" " Z_loc = %f %f\n" " Slice spacing = %f\n", best_chunk_start, best_chunk_start + best_chunk_len - 1, slice_no, best_chunk_z_start, best_chunk_z_start + (best_chunk_len - 1) * best_chunk_diff, best_chunk_diff); } /* Some debugging info */ #if defined (commentout) lprintf ("Slices: "); for (it = flist->begin(); it != flist->end(); ++it) { df = (*it).get(); lprintf ("%f ", df->get_z_position()); } lprintf ("\n"); #endif /* Create a Volume_header to hold the image geometry */ Volume_header vh; plm_long *dim = vh.get_dim(); /* Compute resampled volume header */ int slices_before = ROUND_INT ((best_chunk_z_start - z_init) / best_chunk_diff); int slices_after = ROUND_INT ((z_last - best_chunk_z_start - (best_chunk_len - 1) * best_chunk_diff) / best_chunk_diff); df = (*flist->begin()).get(); vh.clone (df->get_volume_header()); dim[2] = slices_before + best_chunk_len + slices_after; vh.get_origin()[2] = best_chunk_z_start - slices_before * best_chunk_diff; vh.get_spacing()[2] = best_chunk_diff; /* Store image header */ if (d_ptr->rt_study_metadata) { d_ptr->rt_study_metadata->set_image_header (Plm_image_header (vh)); } /* More debugging info */ //vh.print (); /* Still more debugging info */ #if defined (commentout) lprintf ("Resamples slices: "); for (plm_long i = 0; i < dim[2]; i++) { lprintf ("%f ", vh.get_origin()[2] + i * vh.get_spacing()[2]); } lprintf ("\n"); #endif pli->m_type = PLM_IMG_TYPE_GPUIT_FLOAT; pli->m_original_type = PLM_IMG_TYPE_GPUIT_FLOAT; Volume* vol = new Volume (vh, PT_FLOAT, 1); pli->set_volume (vol); float* img = (float*) vol->img; for (plm_long i = 0; i < dim[2]; i++) { /* Find the best slice, using nearest neighbor interpolation */ std::list::const_iterator best_slice_it = flist->begin(); float best_z_dist = FLT_MAX; float z_pos = vh.get_origin()[2] + i * vh.get_spacing()[2]; for (it = flist->begin(); it != flist->end(); ++it) { float this_z_dist = fabs ((*it)->get_z_position() - z_pos); if (this_z_dist < best_z_dist) { best_z_dist = this_z_dist; best_slice_it = it; } } /* Load the slice image data into volume */ df = (*best_slice_it).get(); #if defined (commentout) lprintf ("Loading slice z=%f at location z=%f\n", (*best_slice_it)->get_z_position(), z_pos); #endif /* GCS FIX: This should probably use DicomImage::getOutputData() cf. http://support.dcmtk.org/docs/mod_dcmimage.html */ const uint8_t* pixel_data_8; const uint16_t* pixel_data_16; unsigned long length = 0; rc = 0; if (bits_alloc == 8) { rc = df->get_uint8_array (DCM_PixelData, &pixel_data_8, &length); } else if (bits_alloc == 16) { rc = df->get_uint16_array (DCM_PixelData, &pixel_data_16, &length); } if (!rc) { print_and_exit ("Oops. Error reading pixel data. Punting.\n"); } if (((long) length) != dim[0] * dim[1]) { print_and_exit ("Oops. Dicom image had wrong length " "(%d vs. %d x %d).\n", length, dim[0], dim[1]); } /* Apply slope and offset */ if (bits_alloc == 8) { for (plm_long j = 0; j < (plm_long) length; j++) { img[j] = rescale_slope * (int8_t) pixel_data_8[j] + rescale_intercept; } } else if (bits_alloc == 16) { for (plm_long j = 0; j < (plm_long) length; j++) { img[j] = rescale_slope * (int16_t) pixel_data_16[j] + rescale_intercept; } } img += length; /* Store slice UID */ if (d_ptr->rt_study_metadata) { d_ptr->rt_study_metadata->set_slice_uid (i, df->get_cstr (DCM_SOPInstanceUID)); } } #endif /* NOT VOL_LIST */ if (d_ptr->rt_study_metadata) { d_ptr->rt_study_metadata->set_slice_list_complete (); } } static void dcmtk_save_slice (const Rt_study_metadata::Pointer rsm, Dcmtk_slice_data *dsd) { std::string tmp; DcmFileFormat fileformat; DcmDataset *dataset = fileformat.getDataset(); Metadata::Pointer image_metadata; if (rsm) { image_metadata = rsm->get_image_metadata (); } /* Patient, and General Study modules */ Dcmtk_module::set_patient (dataset, image_metadata); Dcmtk_module::set_general_study (dataset, rsm); /* Get modality */ std::string modality = "CT"; if (image_metadata) { std::string metadata_modality = image_metadata->get_metadata ( DCM_Modality.getGroup(), DCM_Modality.getElement()); if (metadata_modality != "") { modality = metadata_modality; } } /* General Series module */ Dcmtk_module::set_general_series (dataset, image_metadata, modality.c_str()); dataset->putAndInsertString (DCM_SeriesInstanceUID, rsm->get_ct_series_uid()); dataset->putAndInsertString (DCM_SeriesDescription, rsm->get_ct_series_description()); /* Frame of Reference module */ Dcmtk_module::set_frame_of_reference (dataset, rsm); /* XVI 4.5 requires a DCM_PositionReferenceIndicator */ dataset->putAndInsertString (DCM_PositionReferenceIndicator, "SP"); /* General Image module */ tmp = string_format ("%d", dsd->instance_no); dataset->putAndInsertString (DCM_InstanceNumber, tmp.c_str()); if (modality == "CT") { dataset->putAndInsertString (DCM_ImageType, "DERIVED\\SECONDARY\\AXIAL"); } else { dataset->putAndInsertString (DCM_ImageType, "DERIVED\\SECONDARY\\REFORMATTED"); } /* Image Plane module */ tmp = string_format ("%f\\%f", dsd->vol->spacing[1], dsd->vol->spacing[0]); dataset->putAndInsertString (DCM_PixelSpacing, tmp.c_str()); dataset->putAndInsertString (DCM_ImageOrientationPatient, dsd->iop.c_str()); dataset->putAndInsertString (DCM_ImagePositionPatient, dsd->ipp.c_str()); dataset->putAndInsertString (DCM_SliceThickness, dsd->sthk.c_str()); dataset->putAndInsertString (DCM_SliceLocation, dsd->sloc.c_str()); /* Image Pixel module */ dataset->putAndInsertString (DCM_SamplesPerPixel, "1"); dataset->putAndInsertString (DCM_PhotometricInterpretation, "MONOCHROME2"); dataset->putAndInsertUint16 (DCM_Rows, (Uint16) dsd->vol->dim[1]); dataset->putAndInsertUint16 (DCM_Columns, (Uint16) dsd->vol->dim[0]); dataset->putAndInsertString (DCM_BitsAllocated, "16"); dataset->putAndInsertString (DCM_BitsStored, "16"); dataset->putAndInsertString (DCM_HighBit, "15"); dataset->putAndInsertString (DCM_PixelRepresentation, "1"); /* Convert to 16-bit signed int */ for (size_t i = 0; i < dsd->slice_size; i++) { float f = dsd->slice_float[i]; dsd->slice_int16[i] = (int16_t) ((f - dsd->intercept) / dsd->slope); } dataset->putAndInsertUint16Array (DCM_PixelData, (Uint16*) dsd->slice_int16, dsd->slice_size); /* CT Image module */ tmp = string_format ("%f", dsd->intercept); dataset->putAndInsertString (DCM_RescaleIntercept, tmp.c_str()); tmp = string_format ("%f", dsd->slope); dataset->putAndInsertString (DCM_RescaleSlope, tmp.c_str()); dataset->putAndInsertString (DCM_RescaleType, "HU"); dataset->putAndInsertString (DCM_KVP, ""); dataset->putAndInsertString (DCM_AcquisitionNumber, ""); /* VOI LUT module */ if (modality == "CT") { dcmtk_copy_from_metadata (dataset, image_metadata, DCM_WindowCenter, "40"); dcmtk_copy_from_metadata (dataset, image_metadata, DCM_WindowWidth, "400"); } /* SOP Common Module */ if (modality == "MR") { dataset->putAndInsertString ( DCM_SOPClassUID, UID_MRImageStorage); } else if (modality == "PT") { dataset->putAndInsertString ( DCM_SOPClassUID, UID_NuclearMedicineImageStorage); } else if (modality == "US") { dataset->putAndInsertString ( DCM_SOPClassUID, UID_UltrasoundImageStorage); } else { dataset->putAndInsertString ( DCM_SOPClassUID, UID_CTImageStorage); } dataset->putAndInsertString (DCM_SOPInstanceUID, dsd->slice_uid); if (image_metadata->get_metadata (DCM_InstanceCreationDate) != "") { dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, image_metadata->get_metadata(DCM_InstanceCreationDate).c_str()); } else { dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, rsm->get_study_date()); } if (image_metadata->get_metadata (DCM_InstanceCreationTime) != "") { dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, image_metadata->get_metadata(DCM_InstanceCreationTime).c_str()); } else { dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, rsm->get_study_time()); } /* Write the output file */ OFCondition status = fileformat.saveFile (dsd->fn.c_str(), EXS_LittleEndianExplicit); if (status.bad()) { print_and_exit ("Error: cannot write DICOM file (%s)\n", status.text()); } } void Dcmtk_rt_study::save_image ( const char *dicom_dir) { Dcmtk_slice_data dsd; dsd.vol = this->get_image_volume_float(); dsd.slice_size = dsd.vol->dim[0] * dsd.vol->dim[1]; dsd.slice_int16 = new int16_t[dsd.slice_size]; float *dc = dsd.vol->get_direction_matrix(); dsd.iop = string_format ("%f\\%f\\%f\\%f\\%f\\%f", dc[0], dc[3], dc[6], dc[1], dc[4], dc[7]); Plm_image_header pih (dsd.vol.get()); d_ptr->rt_study_metadata->set_image_header (pih); /* Find slope / offset on a per-volume basis */ const Rt_study_metadata::Pointer& rsm = d_ptr->rt_study_metadata; const Metadata::Pointer& image_metadata = rsm->get_image_metadata (); const std::string& meta_intercept = image_metadata->get_metadata (DCM_RescaleIntercept); const std::string& meta_slope = image_metadata->get_metadata (DCM_RescaleSlope); float vol_min = FLT_MAX; float vol_max = - FLT_MAX; float *img = (float*) dsd.vol->img; bool all_integers = true; for (plm_long v = 0; v < dsd.vol->npix; v++) { if (vol_min > img[v]) { vol_min = img[v]; } else if (vol_max < img[v]) { vol_max = img[v]; } if (img[v] != floorf(img[v])) { all_integers = false; } } /* Use a heuristic to determine intercept and offset. The heuristic is designed around the following principles: - prevent underflow when using low-precision DICOM string-encoded floating point numbers - map integers to integers */ if (meta_intercept != "") { int rc = sscanf (meta_intercept.c_str(), "%f", &dsd.intercept); if (rc != 1) { dsd.intercept = floorf (vol_min); } } else { dsd.intercept = floorf (vol_min); } if (meta_slope != "") { int rc = sscanf (meta_slope.c_str(), "%f", &dsd.slope); if (rc != 1) { dsd.slope = 1; } } else if (all_integers) { dsd.slope = 1; } else { float range = vol_max - dsd.intercept; if (range < 1) { range = 1; } dsd.slope = range / (SHRT_MAX - 100); std::string tmp = string_format ("%f", dsd.slope); sscanf (tmp.c_str(), "%f", &dsd.slope); } for (plm_long k = 0; k < dsd.vol->dim[2]; k++) { /* GCS FIX #2: This is possibly correct. Not 100% sure. */ float z_loc = dsd.vol->origin[2] + dc[8] * k * dsd.vol->spacing[2]; dsd.instance_no = k; dsd.sthk = string_format ("%f", dsd.vol->spacing[2]); dsd.sloc = string_format ("%f", z_loc); /* GCS FIX #2: "Ditto" */ dsd.ipp = string_format ("%f\\%f\\%f", dsd.vol->origin[0] + dc[2] * k * dsd.vol->spacing[2], dsd.vol->origin[1] + dc[5] * k * dsd.vol->spacing[2], dsd.vol->origin[2] + dc[8] * k * dsd.vol->spacing[2]); dcmtk_uid (dsd.slice_uid, PLM_UID_PREFIX); dsd.slice_float = &((float*)dsd.vol->img)[k*dsd.slice_size]; /* Format filename and prepare output directory */ if (d_ptr->filenames_with_uid) { dsd.fn = string_format ("%s/image%04d_%s.dcm", dicom_dir, (int) k, dsd.slice_uid); } else { dsd.fn = string_format ("%s/image%04d.dcm", dicom_dir, (int) k); } make_parent_directories (dsd.fn); /* Fix the uid into the metadata */ d_ptr->rt_study_metadata->set_slice_uid (k, dsd.slice_uid); /* Save the file to disk */ dcmtk_save_slice (d_ptr->rt_study_metadata, &dsd); } delete[] dsd.slice_int16; d_ptr->rt_study_metadata->set_slice_list_complete (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_metadata.cxx000066400000000000000000000026631321604176500312260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_file.h" #include "dcmtk_metadata.h" #include "dcmtk_series.h" #include "metadata.h" void dcmtk_copy_from_metadata ( DcmDataset *dataset, const Metadata::Pointer& meta, const DcmTagKey& tagkey, const char* default_value) { if (meta) { const std::string& md = meta->get_metadata ( tagkey.getGroup(), tagkey.getElement()); if (md != "") { dataset->putAndInsertString (tagkey, md.c_str()); return; } } if (default_value) { dataset->putAndInsertString (tagkey, default_value); } } void dcmtk_copy_into_metadata ( Metadata::Pointer& meta, const Dcmtk_file::Pointer& df, const DcmTagKey& tag_key) { dcmtk_copy_into_metadata (meta, df.get(), tag_key); } void dcmtk_copy_into_metadata ( Metadata::Pointer& meta, const Dcmtk_file* df, const DcmTagKey& tag_key) { const char* value = df->get_cstr (tag_key); if (value) { meta->set_metadata ( tag_key.getGroup(), tag_key.getElement(), value); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_metadata.h000066400000000000000000000014721321604176500306500ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_metadata_h_ #define _dcmtk_metadata_h_ #include "plmbase_config.h" #include "dcmtk_file.h" #include "metadata.h" class DcmDataset; class DcmTagKey; class Dcmtk_file; void dcmtk_copy_from_metadata ( DcmDataset *dataset, const Metadata::Pointer& meta, const DcmTagKey& tagkey, const char* default_value); void dcmtk_copy_into_metadata ( Metadata::Pointer& meta, const Dcmtk_file::Pointer& df, const DcmTagKey& tagkey); void dcmtk_copy_into_metadata ( Metadata::Pointer& meta, const Dcmtk_file* df, const DcmTagKey& tagkey); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_module.cxx000066400000000000000000000101701321604176500307230ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_module.h" #include "dcmtk_metadata.h" #include "dicom_util.h" #include "metadata.h" #include "plm_uid_prefix.h" #include "plm_version.h" void Dcmtk_module::set_patient ( DcmDataset *dataset, const Metadata::Pointer& meta) { dcmtk_copy_from_metadata (dataset, meta, DCM_PatientName, ""); dcmtk_copy_from_metadata (dataset, meta, DCM_PatientID, ""); dcmtk_copy_from_metadata (dataset, meta, DCM_PatientBirthDate, ""); dcmtk_copy_from_metadata (dataset, meta, DCM_PatientSex, "O"); } void Dcmtk_module::set_general_study ( DcmDataset *dataset, const Rt_study_metadata::Pointer& rsm) { dataset->putAndInsertString (DCM_StudyInstanceUID, rsm->get_study_uid()); dataset->putAndInsertOFStringArray (DCM_StudyDate, rsm->get_study_date()); dataset->putAndInsertOFStringArray (DCM_StudyTime, rsm->get_study_time()); dataset->putAndInsertString (DCM_ReferringPhysicianName, rsm->get_referring_physician_name()); dcmtk_copy_from_metadata (dataset, rsm->get_study_metadata(), DCM_StudyID, ""); dataset->putAndInsertString (DCM_AccessionNumber,rsm->get_accession_number() ); dataset->putAndInsertString (DCM_StudyDescription,rsm->get_study_description() ); // dcmtk_copy_from_metadata (dataset, rsm->get_study_metadata (), // DCM_StudyDescription, ""); dataset->putAndInsertOFStringArray (DCM_StudyID, rsm->get_study_id()); } void Dcmtk_module::set_general_series ( DcmDataset *dataset, const Metadata::Pointer& meta, const char* modality) { dataset->putAndInsertOFStringArray (DCM_Modality, modality); dataset->putAndInsertString (DCM_SeriesInstanceUID, dicom_uid(PLM_UID_PREFIX).c_str()); dcmtk_copy_from_metadata (dataset, meta, DCM_SeriesNumber, 0); dcmtk_copy_from_metadata (dataset, meta, DCM_SeriesDate, 0); dcmtk_copy_from_metadata (dataset, meta, DCM_SeriesTime, 0); dcmtk_copy_from_metadata (dataset, meta, DCM_SeriesDescription, ""); dcmtk_copy_from_metadata (dataset, meta, DCM_OperatorsName, ""); dcmtk_copy_from_metadata (dataset, meta, DCM_PatientPosition, "HFS"); } void Dcmtk_module::set_frame_of_reference ( DcmDataset *dataset, const Rt_study_metadata::Pointer& rsm) { dataset->putAndInsertString (DCM_FrameOfReferenceUID, rsm->get_frame_of_reference_uid()); } void Dcmtk_module::set_general_equipment (DcmDataset *dataset, const Metadata::Pointer& meta) { dcmtk_copy_from_metadata (dataset, meta, DCM_Manufacturer, "Plastimatch"); //dcmtk_copy_from_metadata (dataset, meta, DCM_InstitutionName, ""); dcmtk_copy_from_metadata (dataset, meta, DCM_StationName, ""); dcmtk_copy_from_metadata (dataset, meta, DCM_ManufacturerModelName, "Plastimatch"); dcmtk_copy_from_metadata (dataset, meta, DCM_DeviceSerialNumber, ""); dcmtk_copy_from_metadata (dataset, meta, DCM_SoftwareVersions, PLASTIMATCH_VERSION_STRING); } void Dcmtk_module::set_rt_series ( DcmDataset *dataset, const Metadata::Pointer& meta, const char* modality) { dataset->putAndInsertOFStringArray (DCM_Modality, modality); /* Series Instance UID, this gets copied from e.g. d_ptr->rt_study_metadata->get_dose_series_uid(), in order to correctly make cross references between series. It is safe to set here, and allow caller to override. */ dataset->putAndInsertString (DCM_SeriesInstanceUID, dicom_uid(PLM_UID_PREFIX).c_str()); dcmtk_copy_from_metadata (dataset, meta, DCM_SeriesNumber, 0); dcmtk_copy_from_metadata (dataset, meta, DCM_SeriesDate, 0); dcmtk_copy_from_metadata (dataset, meta, DCM_SeriesTime, 0); dcmtk_copy_from_metadata (dataset, meta, DCM_SeriesDescription, ""); dcmtk_copy_from_metadata (dataset, meta, DCM_OperatorsName, ""); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_module.h000066400000000000000000000022211321604176500303460ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_module_h_ #define _dcmtk_module_h_ #include "plmbase_config.h" #include #include "rt_study_metadata.h" class DcmDataset; class PLMBASE_API Dcmtk_module { public: /* C.7.1.1 */ static void set_patient (DcmDataset *dataset, const Metadata::Pointer& meta); /* C.7.2.1 */ static void set_general_study (DcmDataset *dataset, const Rt_study_metadata::Pointer& rsm); /* C.7.3.1 */ static void set_general_series (DcmDataset *dataset, const Metadata::Pointer& meta, const char* modality); /* C.7.4.1 */ static void set_frame_of_reference (DcmDataset *dataset, const Rt_study_metadata::Pointer& rsm); /* C.7.5.1 */ static void set_general_equipment (DcmDataset *dataset, const Metadata::Pointer& meta); /* C.8.8.1 */ static void set_rt_series (DcmDataset *dataset, const Metadata::Pointer& meta, const char* modality); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rdd.cxx000066400000000000000000000012161321604176500302100ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "dcmtk_rt_study.h" #include "plm_math.h" #include "plm_uid_prefix.h" #include "rt_study_metadata.h" void dcmtk_load_rdd ( Rt_study_metadata::Pointer rsm, const char *dicom_dir ) { if (!dicom_dir) { return; } Dcmtk_rt_study drs (dicom_dir); drs.set_rt_study_metadata (rsm); drs.parse_directory (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rdd.h000066400000000000000000000006541321604176500276420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_rdd_h_ #define _dcmtk_rdd_h_ #include "plmbase_config.h" #include "rt_study_metadata.h" void dcmtk_load_rdd ( Rt_study_metadata::Pointer rsd, const char *dicom_dir ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rt_study.cxx000066400000000000000000000216041321604176500313170ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_rt_study.h" #include "dcmtk_rt_study_p.h" #include "dcmtk_rtss.h" #include "dcmtk_series.h" #include "dcmtk_slice_data.h" #include "dicom_util.h" #include "file_util.h" #include "logfile.h" #include "path_util.h" #include "plm_image.h" #include "plm_version.h" #include "print_and_exit.h" #include "rt_study_metadata.h" #include "rtss.h" #include "smart_pointer.h" #include "volume.h" Dcmtk_rt_study::Dcmtk_rt_study () { this->d_ptr = new Dcmtk_rt_study_private; /* GCS FIX: Need a way to turn this on via configuration. But for now, just unilaterally disable logging. http://support.dcmtk.org/wiki/dcmtk/howto/logprogram */ OFLog::configure (OFLogger::FATAL_LOG_LEVEL); } Dcmtk_rt_study::Dcmtk_rt_study (const char* dicom_path) { this->d_ptr = new Dcmtk_rt_study_private; /* GCS FIX: Need a way to turn this on via configuration. But for now, just unilaterally disable logging. http://support.dcmtk.org/wiki/dcmtk/howto/logprogram */ OFLog::configure (OFLogger::FATAL_LOG_LEVEL); this->load (dicom_path); } Dcmtk_rt_study::~Dcmtk_rt_study () { delete this->d_ptr; } const char* Dcmtk_rt_study::get_ct_series_uid () const { return d_ptr->ct_series_uid; } const char* Dcmtk_rt_study::get_dose_instance_uid () const { return d_ptr->dose_instance_uid; } const char* Dcmtk_rt_study::get_dose_series_uid () const { return d_ptr->dose_series_uid; } const char* Dcmtk_rt_study::get_frame_of_reference_uid () const { return d_ptr->for_uid; } const char* Dcmtk_rt_study::get_plan_instance_uid () const { return d_ptr->plan_instance_uid; } const char* Dcmtk_rt_study::get_rtss_instance_uid () const { return d_ptr->rtss_instance_uid; } const char* Dcmtk_rt_study::get_rtss_series_uid () const { return d_ptr->rtss_series_uid; } const char* Dcmtk_rt_study::get_study_date () const { return d_ptr->date_string.c_str(); } const char* Dcmtk_rt_study::get_study_time () const { return d_ptr->time_string.c_str(); } const char* Dcmtk_rt_study::get_study_uid () const { return d_ptr->study_uid; } std::vector* Dcmtk_rt_study::get_slice_data () { return d_ptr->slice_data; } Plm_image::Pointer& Dcmtk_rt_study::get_image () { return d_ptr->img; } Volume::Pointer Dcmtk_rt_study::get_image_volume_float () { return d_ptr->img->get_volume_float (); } void Dcmtk_rt_study::set_image (const Plm_image::Pointer& image) { d_ptr->img = image; } Rtss::Pointer& Dcmtk_rt_study::get_rtss () { return d_ptr->rtss; } void Dcmtk_rt_study::set_rtss (const Rtss::Pointer& rtss) { d_ptr->rtss = rtss; } Rtplan::Pointer& Dcmtk_rt_study::get_rtplan() { return d_ptr->rtplan; } void Dcmtk_rt_study::set_rtplan (const Rtplan::Pointer& rtplan) { d_ptr->rtplan = rtplan; } Plm_image::Pointer& Dcmtk_rt_study::get_dose () { return d_ptr->dose; } void Dcmtk_rt_study::set_dose (const Plm_image::Pointer& image) { d_ptr->dose = image; } void Dcmtk_rt_study::set_rt_study_metadata ( const Rt_study_metadata::Pointer& rt_study_metadata) { d_ptr->rt_study_metadata = rt_study_metadata; } void Dcmtk_rt_study::set_filenames_with_uid (bool filenames_with_uid) { d_ptr->filenames_with_uid = filenames_with_uid; } void Dcmtk_rt_study::load (const char *dicom_path) { if (is_directory (dicom_path)) { this->insert_directory (dicom_path); } else { this->insert_file (dicom_path); } this->parse_directory (); } void Dcmtk_rt_study::save (const char *dicom_dir) { if (d_ptr->img) { d_ptr->rt_study_metadata->generate_new_series_uids (); } if (d_ptr->img) { this->save_image (dicom_dir); } if (d_ptr->rtss) { this->save_rtss (dicom_dir); } if (d_ptr->dose) { this->save_dose (dicom_dir); } if (d_ptr->rtplan) { this->save_rtplan (dicom_dir); } } void Dcmtk_rt_study::insert_file (const char* fn) { Dcmtk_file::Pointer df = Dcmtk_file::New (fn); /* Discard non-dicom files */ if (!df->is_valid()) { return; } /* Get the SeriesInstanceUID */ const char *c = NULL; std::string series_uid; c = df->get_cstr (DCM_SeriesInstanceUID); if (c) { series_uid = std::string (c); } else { /* 2014-12-17. Oncentra data missing SeriesInstanceUID? If that happens, make something up. */ series_uid = dicom_uid (); } /* Look for the SeriesInstanceUID in the map */ Dcmtk_series_map::iterator it; it = d_ptr->m_smap.find (series_uid); /* If we didn't find the UID, add a new entry into the map */ if (it == d_ptr->m_smap.end()) { std::pair ret = d_ptr->m_smap.insert (Dcmtk_series_map_pair (series_uid, new Dcmtk_series())); if (ret.second == false) { print_and_exit ( "Error inserting UID %s into dcmtk_series_map.\n", c); } it = ret.first; } /* Add the file to the Dcmtk_series object for this UID */ Dcmtk_series *ds = (*it).second; ds->insert (df); } void Dcmtk_rt_study::insert_directory (const char* dir) { OFBool recurse = OFFalse; OFList input_files; /* On windows, searchDirectoryRecursively doesn't work if the path is like c:/dir/dir; instead it must be c:\dir\dir */ std::string fixed_path = make_windows_slashes (std::string(dir)); OFStandard::searchDirectoryRecursively ( fixed_path.c_str(), input_files, "", "", recurse); OFListIterator(OFString) if_iter = input_files.begin(); OFListIterator(OFString) if_last = input_files.end(); while (if_iter != if_last) { const char *current = (*if_iter++).c_str(); this->insert_file (current); } } void Dcmtk_rt_study::sort_all (void) { Dcmtk_series_map::iterator it; for (it = d_ptr->m_smap.begin(); it != d_ptr->m_smap.end(); ++it) { const std::string& key = (*it).first; Dcmtk_series *ds = (*it).second; UNUSED_VARIABLE (key); ds->sort (); } } void Dcmtk_rt_study::debug (void) const { Dcmtk_series_map::const_iterator it; for (it = d_ptr->m_smap.begin(); it != d_ptr->m_smap.end(); ++it) { const std::string& key = (*it).first; const Dcmtk_series *ds = (*it).second; UNUSED_VARIABLE (key); UNUSED_VARIABLE (ds); ds->debug (); } } Volume * Dcmtk_rt_study::get_volume () { if (!d_ptr->img) { this->parse_directory (); } if (!d_ptr->img) { return 0; } return d_ptr->img->get_vol(); } void Dcmtk_rt_study::parse_directory (void) { Dcmtk_series_map::iterator it; d_ptr->ds_image = 0; d_ptr->ds_rtss = 0; d_ptr->ds_rtdose = 0; d_ptr->ds_rtplan = 0; /* Loop through all series in directory, and find image, ss, dose */ size_t best_image_slices = 0; for (it = d_ptr->m_smap.begin(); it != d_ptr->m_smap.end(); ++it) { const std::string& key = (*it).first; Dcmtk_series *ds = (*it).second; UNUSED_VARIABLE (key); /* Check for rtstruct */ if (!d_ptr->ds_rtss && ds->get_modality() == "RTSTRUCT") { printf ("Found RTSTUCT, UID=%s\n", key.c_str()); d_ptr->ds_rtss = ds; continue; } /* Check for rtdose */ if (!d_ptr->ds_rtdose && ds->get_modality() == "RTDOSE") { printf ("Found RTDOSE, UID=%s\n", key.c_str()); d_ptr->ds_rtdose = ds; continue; } /* Check for rtplan */ if (!d_ptr->ds_rtplan && ds->get_modality() == "RTPLAN") { printf("Found RTPLAN, UID=%s\n", key.c_str()); d_ptr->ds_rtplan = ds; continue; } /* Check for image. An image is anything with a PixelData. Current heuristic: load the image with the most slices (as determined by the number of files) */ bool rc = ds->get_uint16_array (DCM_PixelData, 0, 0); if (rc) { size_t num_slices = ds->get_number_of_files (); if (num_slices > best_image_slices) { best_image_slices = num_slices; d_ptr->ds_image = ds; } continue; } } /* GCS FIX: need additional logic that checks if ss & dose refer to the image. The below logic doesn't do anything. */ std::string referenced_uid = ""; if (d_ptr->ds_rtss) { referenced_uid = d_ptr->ds_rtss->get_referenced_uid (); } /* Load image */ if (d_ptr->ds_image) { d_ptr->ds_image->set_rt_study_metadata (d_ptr->rt_study_metadata); this->image_load (); } /* Load rtss */ if (d_ptr->ds_rtss) { this->rtss_load (); } /* Load dose */ if (d_ptr->ds_rtdose) { this->rtdose_load (); } /* Load plan */ if (d_ptr->ds_rtplan) { this->rtplan_load(); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rt_study.h000066400000000000000000000046001321604176500307410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_rt_study_h_ #define _dcmtk_rt_study_h_ #include "plmbase_config.h" #include #include "itk_image.h" #include "plm_image.h" #include "plm_int.h" #include "rt_study_metadata.h" #include "rtss.h" #include "rtplan.h" #include "volume.h" class Dcmtk_rt_study_private; class Dcmtk_slice_data; class PLMBASE_API Dcmtk_rt_study { public: Dcmtk_rt_study_private *d_ptr; public: Dcmtk_rt_study (); Dcmtk_rt_study (const char* dicom_path); ~Dcmtk_rt_study (); public: void load (const char *dicom_path); void save (const char *dicom_path); public: const char* get_ct_series_uid () const; const char* get_dose_instance_uid () const; const char* get_dose_series_uid () const; const char* get_frame_of_reference_uid () const; const char* get_plan_instance_uid () const; const char* get_rtss_instance_uid () const; const char* get_rtss_series_uid () const; const char* get_study_date () const; const char* get_study_time () const; const char* get_study_description () const; const char* get_study_uid () const; std::vector* get_slice_data(); public: Plm_image::Pointer& get_image (); Volume::Pointer get_image_volume_float (); Volume *get_volume (); void set_image (const Plm_image::Pointer& image); Rtss::Pointer& get_rtss (); void set_rtss (const Rtss::Pointer& rtss); Rtplan::Pointer& get_rtplan(); void set_rtplan (const Rtplan::Pointer& rtplan); Plm_image::Pointer& get_dose (); void set_dose (const Plm_image::Pointer& dose); void set_rt_study_metadata ( const Rt_study_metadata::Pointer& rt_study_metadata); void set_filenames_with_uid (bool filenames_with_uid); public: void save_image (const char *dicom_path); void save_dose (const char *dicom_path); void save_rtss (const char *dicom_path); void save_rtplan(const char *dicom_path); void image_load (); void rtss_load (); void rtdose_load (); void rtplan_load(); void insert_file (const char* fn); void insert_directory (const char* fn); void parse_directory (void); void sort_all (void); void debug (void) const; }; #endif dcmtk_rt_study_p.cxx000066400000000000000000000026251321604176500315610ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_rt_study_p.h" #include "dcmtk_series.h" #include "dcmtk_slice_data.h" #include "dcmtk_uid.h" #include "plm_uid_prefix.h" Dcmtk_rt_study_private::Dcmtk_rt_study_private () { DcmDate::getCurrentDate (date_string); DcmTime::getCurrentTime (time_string); dcmtk_uid (study_uid, PLM_UID_PREFIX); dcmtk_uid (for_uid, PLM_UID_PREFIX); dcmtk_uid (ct_series_uid, PLM_UID_PREFIX); dcmtk_uid (plan_instance_uid, PLM_UID_PREFIX); dcmtk_uid (rtss_instance_uid, PLM_UID_PREFIX); dcmtk_uid (rtss_series_uid, PLM_UID_PREFIX); dcmtk_uid (dose_series_uid, PLM_UID_PREFIX); dcmtk_uid (dose_instance_uid, PLM_UID_PREFIX); slice_data = new std::vector; rt_study_metadata = Rt_study_metadata::New (); filenames_with_uid = true; } Dcmtk_rt_study_private::~Dcmtk_rt_study_private () { /* Delete list of slices */ delete slice_data; /* Delete Dicom_series objects in map */ Dcmtk_series_map::iterator it; for (it = m_smap.begin(); it != m_smap.end(); ++it) { delete (*it).second; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rt_study_p.h000066400000000000000000000026451321604176500312670ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_rt_study_p_h_ #define _dcmtk_rt_study_p_h_ #include "plmbase_config.h" #include "dcmtk_series_map.h" #include "plm_image.h" //#include "plm_image_set.h" #include "rt_study_metadata.h" #include "rtss.h" #include "rtplan.h" class Dcmtk_series; class Dcmtk_slice_data; class Dcmtk_rt_study_private { public: OFString date_string; OFString time_string; char ct_series_uid[100]; char dose_instance_uid[100]; char dose_series_uid[100]; char for_uid[100]; char plan_instance_uid[100]; char rtss_instance_uid[100]; char rtss_series_uid[100]; char study_uid[100]; std::vector* slice_data; /*! The m_smap is used during loading to map filenames to series UIDs */ Dcmtk_series_map m_smap; Dcmtk_series *ds_image; Dcmtk_series *ds_rtdose; Dcmtk_series *ds_rtss; Dcmtk_series *ds_rtplan; Rtss::Pointer rtss; Metadata *rtss_metadata; Rtplan::Pointer rtplan; //Plm_image_set::Pointer img; Plm_image::Pointer img; Plm_image::Pointer dose; Rt_study_metadata::Pointer rt_study_metadata; bool filenames_with_uid; public: Dcmtk_rt_study_private (); ~Dcmtk_rt_study_private (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rtdose.cxx000066400000000000000000000425701321604176500307470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_file.h" #include "dcmtk_metadata.h" #include "dcmtk_module.h" #include "dcmtk_rt_study.h" #include "dcmtk_rt_study_p.h" #include "dcmtk_rtdose.h" #include "dcmtk_series.h" #include "dcmtk_util.h" #include "file_util.h" #include "logfile.h" #include "plm_image.h" #include "plm_math.h" #include "plm_uid_prefix.h" #include "print_and_exit.h" #include "string_util.h" #include "volume.h" #include "volume_stats.h" bool dcmtk_dose_probe (const char *fn) { DcmFileFormat dfile; /* Suppress warning messages */ OFLog::configure(OFLogger::FATAL_LOG_LEVEL); OFCondition ofrc = dfile.loadFile (fn, EXS_Unknown, EGL_noChange); /* Restore error messages -- n.b. dcmtk doesn't have a way to query current setting, so I just set to default */ OFLog::configure(OFLogger::WARN_LOG_LEVEL); if (ofrc.bad()) { return false; } const char *c; DcmDataset *dset = dfile.getDataset(); ofrc = dset->findAndGetString (DCM_Modality, c); if (ofrc.bad() || !c) { return false; } if (strncmp (c, "RTDOSE", strlen("RTDOSE"))) { return false; } else { return true; } } /* This is the tolerance on irregularity of the grid spacing (in mm) */ #define GFOV_SPACING_TOL (1e-1) template void dcmtk_dose_copy (float *img_out, T *img_in, int nvox, float scale) { for (int i = 0; i < nvox; i++) { img_out[i] = img_in[i] * scale; } } void Dcmtk_rt_study::rtdose_load () { int rc; const char *val; uint16_t val_u16; plm_long dim[3]; float ipp[3]; float spacing[3]; float *gfov; /* gfov = GridFrameOffsetVector */ plm_long gfov_len; const char *gfov_str; OFCondition ofrc; /* Modality -- better be RTDOSE */ std::string modality = d_ptr->ds_rtdose->get_modality(); if (modality == "RTDOSE") { printf ("Trying to load rt dose.\n"); } else { print_and_exit ("Oops.\n"); } /* FIX: load metadata such as patient name, etc. */ /* ImagePositionPatient */ val = d_ptr->ds_rtdose->get_cstr (DCM_ImagePositionPatient); if (!val) { print_and_exit ("Couldn't find DCM_ImagePositionPatient in rtdose\n"); } rc = sscanf (val, "%f\\%f\\%f", &ipp[0], &ipp[1], &ipp[2]); if (rc != 3) { print_and_exit ("Error parsing RTDOSE ipp.\n"); } /* ImageOrientationPatient */ float direction_cosines[9] = { 1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 1.f }; val = d_ptr->ds_rtdose->get_cstr (DCM_ImageOrientationPatient); if (val) { int rc = parse_dicom_float6 (direction_cosines, val); if (!rc) { direction_cosines[6] = direction_cosines[1]*direction_cosines[5] - direction_cosines[2]*direction_cosines[4]; direction_cosines[7] = direction_cosines[2]*direction_cosines[3] - direction_cosines[0]*direction_cosines[5]; direction_cosines[8] = direction_cosines[0]*direction_cosines[4] - direction_cosines[1]*direction_cosines[3]; } } /* Rows */ if (!d_ptr->ds_rtdose->get_uint16 (DCM_Rows, &val_u16)) { print_and_exit ("Couldn't find DCM_Rows in rtdose\n"); } dim[1] = val_u16; /* Columns */ if (!d_ptr->ds_rtdose->get_uint16 (DCM_Columns, &val_u16)) { print_and_exit ("Couldn't find DCM_Columns in rtdose\n"); } dim[0] = val_u16; /* PixelSpacing */ val = d_ptr->ds_rtdose->get_cstr (DCM_PixelSpacing); if (!val) { print_and_exit ("Couldn't find DCM_PixelSpacing in rtdose\n"); } rc = sscanf (val, "%g\\%g", &spacing[1], &spacing[0]); if (rc != 2) { print_and_exit ("Error parsing RTDOSE pixel spacing.\n"); } /* GridFrameOffsetVector */ val = d_ptr->ds_rtdose->get_cstr (DCM_GridFrameOffsetVector); if (!val) { print_and_exit ("Couldn't find DCM_GridFrameOffsetVector in rtdose\n"); } gfov = 0; gfov_len = 0; gfov_str = val; while (1) { int len; gfov = (float*) realloc (gfov, (gfov_len + 1) * sizeof(float)); rc = sscanf (gfov_str, "%g%n", &gfov[gfov_len], &len); if (rc != 1) { break; } gfov_len ++; gfov_str += len; if (gfov_str[0] == '\\') { gfov_str ++; } } dim[2] = gfov_len; if (gfov_len == 0) { print_and_exit ("Error parsing RTDOSE gfov.\n"); } /* --- Analyze GridFrameOffsetVector --- */ /* (1) Make sure first element is 0. */ if (gfov[0] != 0.) { if (gfov[0] == ipp[2]) { /* In this case, gfov values are absolute rather than relative positions, but we process the same way. */ } else { /* This is wrong. But Nucletron does it. */ logfile_printf ( "Warning: RTDOSE gfov[0] is neither 0 nor ipp[2].\n" "This violates the DICOM standard. Proceeding anyway...\n"); /* Nucletron seems to work by ignoring absolute origin (???) */ } } /* (2) Handle case where gfov_len == 1 (only one slice). */ if (gfov_len == 1) { spacing[2] = spacing[0]; } /* (3) Check to make sure spacing is regular. */ for (plm_long i = 1; i < gfov_len; i++) { if (i == 1) { spacing[2] = gfov[1] - gfov[0]; } else { float sp = gfov[i] - gfov[i-1]; if (fabs(sp - spacing[2]) > GFOV_SPACING_TOL) { print_and_exit ("Error RTDOSE grid has irregular spacing:" "%f vs %f.\n", sp, spacing[2]); } } } free (gfov); /* DoseGridScaling -- if element doesn't exist, scaling is 1.0 */ float dose_scaling = 1.0; val = d_ptr->ds_rtdose->get_cstr (DCM_DoseGridScaling); if (val) { /* No need to check for success, let scaling be 1.0 if failure */ sscanf (val, "%f", &dose_scaling); } printf ("RTDOSE: dim = %d %d %d\n ipp = %f %f %f\n spc = %f %f %f\n" " dc = %f %f %f %f %f %f\n", (int) dim[0], (int) dim[1], (int) dim[2], ipp[0], ipp[1], ipp[2], spacing[0], spacing[1], spacing[2], direction_cosines[0], direction_cosines[1], direction_cosines[2], direction_cosines[3], direction_cosines[4], direction_cosines[5] ); uint16_t bits_alloc, bits_stored, high_bit, pixel_rep; rc = d_ptr->ds_rtdose->get_uint16 (DCM_BitsAllocated, &bits_alloc); if (!rc) { print_and_exit ("Couldn't find DCM_BitsAllocated in rtdose\n"); } rc = d_ptr->ds_rtdose->get_uint16 (DCM_BitsStored, &bits_stored); if (!rc) { print_and_exit ("Couldn't find DCM_BitsStored in rtdose\n"); } rc = d_ptr->ds_rtdose->get_uint16 (DCM_HighBit, &high_bit); if (!rc) { print_and_exit ("Couldn't find DCM_HighBit in rtdose\n"); } rc = d_ptr->ds_rtdose->get_uint16 (DCM_PixelRepresentation, &pixel_rep); if (!rc) { print_and_exit ("Couldn't find DCM_PixelRepresentation in rtdose\n"); } printf ("Bits_alloc: %d\n", (int) bits_alloc); printf ("Bits_stored: %d\n", (int) bits_stored); printf ("High_bit: %d\n", (int) high_bit); printf ("Pixel_rep: %d\n", (int) pixel_rep); /* Create output dose image */ Plm_image::Pointer dose = Plm_image::New(); this->set_dose (dose); /* Create Volume */ Volume *vol = new Volume (dim, ipp, spacing, direction_cosines, PT_FLOAT, 1); float *img = (float*) vol->img; /* Bind volume to plm_image */ dose->set_volume (vol); /* PixelData */ unsigned long length = 0; if (pixel_rep == 0) { const uint16_t* pixel_data; rc = d_ptr->ds_rtdose->get_uint16_array ( DCM_PixelData, &pixel_data, &length); printf ("rc = %d, length = %lu, npix = %ld\n", rc, length, (long) vol->npix); if (bits_stored == 16) { dcmtk_dose_copy (img, (const uint16_t*) pixel_data, vol->npix, dose_scaling); } else if (bits_stored == 32) { dcmtk_dose_copy (img, (const uint32_t*) pixel_data, vol->npix, dose_scaling); } else { d_ptr->dose.reset(); print_and_exit ("Unknown pixel representation (%d %d)\n", bits_stored, pixel_rep); } } else { const int16_t* pixel_data; rc = d_ptr->ds_rtdose->get_int16_array ( DCM_PixelData, &pixel_data, &length); if (bits_stored == 16) { dcmtk_dose_copy (img, (const int16_t*) pixel_data, vol->npix, dose_scaling); } else if (bits_stored == 32) { dcmtk_dose_copy (img, (const int32_t*) pixel_data, vol->npix, dose_scaling); } else { d_ptr->dose.reset(); print_and_exit ("Unknown pixel representation (%d %d)\n", bits_stored, pixel_rep); } } } void Dcmtk_rt_study::save_dose (const char *dicom_dir) { OFCondition ofc; std::string s; const Rt_study_metadata::Pointer& rsm = d_ptr->rt_study_metadata; if (!rsm) { print_and_exit ("Called Dcmtk_rt_study::save_dose without valid rsm\n"); } const Metadata::Pointer& dose_metadata = rsm->get_dose_metadata (); Volume::Pointer dose_volume = d_ptr->dose->get_volume_float (); /* Prepare dcmtk */ DcmFileFormat fileformat; DcmDataset *dataset = fileformat.getDataset(); DcmItem *dcm_item = 0; /* Patient module, general study module */ Dcmtk_module::set_patient (dataset, rsm->get_study_metadata ()); Dcmtk_module::set_general_study (dataset, rsm); /* RT series module */ Dcmtk_module::set_rt_series (dataset, dose_metadata, "RTDOSE"); dataset->putAndInsertString (DCM_SeriesInstanceUID, d_ptr->rt_study_metadata->get_dose_series_uid()); /* Frame of reference module */ dataset->putAndInsertString (DCM_FrameOfReferenceUID, rsm->get_frame_of_reference_uid()); dataset->putAndInsertString (DCM_PositionReferenceIndicator, ""); /* General equipment module */ Dcmtk_module::set_general_equipment (dataset,dose_metadata); /* SOP common module */ dataset->putAndInsertString (DCM_SOPClassUID, UID_RTDoseStorage); dcmtk_put (dataset, DCM_SOPInstanceUID, d_ptr->rt_study_metadata->get_dose_instance_uid()); dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, d_ptr->rt_study_metadata->get_study_date()); dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, d_ptr->rt_study_metadata->get_study_time()); /* ----------------------------------------------------------------- */ /* Part 1 -- General header */ /* ----------------------------------------------------------------- */ dataset->putAndInsertString (DCM_ImageType, "DERIVED\\SECONDARY\\REFORMATTED"); dataset->putAndInsertOFStringArray(DCM_InstanceCreatorUID, PLM_UID_PREFIX); dataset->putAndInsertString (DCM_ReferringPhysicianName, ""); #if defined (commentout) /* (0008,1110) DCM_ReferencedStudySequence -- probably not needed */ dcm_item = 0; dataset->findOrCreateSequenceItem ( DCM_ReferencedStudySequence, dcm_item, -2); dcm_item->putAndInsertString (DCM_ReferencedSOPClassUID, UID_RETIRED_StudyComponentManagementSOPClass); dcm_item->putAndInsertString (DCM_ReferencedSOPInstanceUID, d_ptr->rt_study_metadata->get_study_uid()); #endif /* (0008,1140) DCM_ReferencedImageSequence -- MIM likes this */ dcm_item = 0; dataset->findOrCreateSequenceItem ( DCM_ReferencedImageSequence, dcm_item, -2); dcm_item->putAndInsertString (DCM_ReferencedSOPClassUID, UID_CTImageStorage); dcm_item->putAndInsertString (DCM_ReferencedSOPInstanceUID, d_ptr->rt_study_metadata->get_ct_series_uid()); dataset->putAndInsertString (DCM_SliceThickness, ""); dcmtk_copy_from_metadata (dataset, dose_metadata, DCM_StudyID, "10001"); dataset->putAndInsertString (DCM_InstanceNumber, "1"); s = string_format ("%g\\%g\\%g", dose_volume->origin[0], dose_volume->origin[1], dose_volume->origin[2]); /* GCS FIX: PatientOrientation */ dataset->putAndInsertString (DCM_PatientOrientation, "L/P"); dataset->putAndInsertString (DCM_ImagePositionPatient, s.c_str()); s = string_format ("%g\\%g\\%g\\%g\\%g\\%g", dose_volume->direction_cosines[0], dose_volume->direction_cosines[3], dose_volume->direction_cosines[6], dose_volume->direction_cosines[1], dose_volume->direction_cosines[4], dose_volume->direction_cosines[7]); dataset->putAndInsertString (DCM_ImageOrientationPatient, s.c_str()); dataset->putAndInsertString (DCM_SamplesPerPixel, "1"); dataset->putAndInsertString (DCM_PhotometricInterpretation, "MONOCHROME2"); s = string_format ("%d", (int) dose_volume->dim[2]); dataset->putAndInsertString (DCM_NumberOfFrames, s.c_str()); /* GCS FIX: Add FrameIncrementPointer */ dataset->putAndInsertString (DCM_FrameIncrementPointer, "(3004,000c)"); dataset->putAndInsertUint16 (DCM_Rows, dose_volume->dim[1]); dataset->putAndInsertUint16 (DCM_Columns, dose_volume->dim[0]); s = string_format ("%g\\%g", dose_volume->spacing[1], dose_volume->spacing[0]); dataset->putAndInsertString (DCM_PixelSpacing, s.c_str()); dataset->putAndInsertString (DCM_BitsAllocated, "32"); dataset->putAndInsertString (DCM_BitsStored, "32"); dataset->putAndInsertString (DCM_HighBit, "31"); if (dose_metadata && dose_metadata->get_metadata(0x3004, 0x0004) == "ERROR") { dataset->putAndInsertString (DCM_PixelRepresentation, "1"); } else { dataset->putAndInsertString (DCM_PixelRepresentation, "0"); } dataset->putAndInsertString (DCM_DoseUnits, "GY"); dcmtk_copy_from_metadata (dataset, dose_metadata, DCM_DoseType, "PHYSICAL"); dataset->putAndInsertString (DCM_DoseSummationType, "PLAN"); s = std::string ("0"); for (int i = 1; i < dose_volume->dim[2]; i++) { s += string_format ("\\%g", dose_volume->direction_cosines[8] * i * dose_volume->spacing[2]); } dataset->putAndInsertString (DCM_GridFrameOffsetVector, s.c_str()); /* GCS FIX: Leave ReferencedRTPlanSequence empty (until I can cross reference) */ /* We need to convert image to uint16_t, but first we need to scale it so that the maximum dose fits in a 16-bit unsigned integer. Compute an appropriate scaling factor based on the maximum dose. */ /* Copy the image so we don't corrupt the original */ Volume::Pointer dose_copy = dose_volume->clone(); /* Find the maximum value in the image */ double min_val, max_val, avg; int non_zero, num_vox; dose_copy->convert (PT_FLOAT); volume_stats (dose_copy, &min_val, &max_val, &avg, &non_zero, &num_vox); /* Find scale factor */ float dose_scale; if (dose_metadata && dose_metadata->get_metadata(0x3004, 0x0004) == "ERROR") { /* Dose error is signed integer */ float dose_scale_min = min_val / INT32_T_MIN * 1.001; float dose_scale_max = max_val / INT32_T_MAX * 1.001; dose_scale = std::max(dose_scale_min, dose_scale_max); } else { /* Dose is unsigned integer */ dose_scale = max_val / UINT32_T_MAX * 1.001; } /* Scale the image and add scale factor to dataset */ dose_copy->scale_inplace (1 / dose_scale); s = string_format ("%g", dose_scale); dataset->putAndInsertString (DCM_DoseGridScaling, s.c_str()); /* (300c,0002) ReferencedRTPlanSequence -- for future expansion */ dcm_item = 0; dataset->findOrCreateSequenceItem ( DCM_ReferencedRTPlanSequence, dcm_item, -2); dcm_item->putAndInsertString (DCM_ReferencedSOPClassUID, UID_RTPlanStorage); dcm_item->putAndInsertString (DCM_ReferencedSOPInstanceUID, d_ptr->rt_study_metadata->get_plan_instance_uid()); /* (300c,0060) DCM_ReferencedStructureSetSequence -- MIM likes this */ dcm_item = 0; dataset->findOrCreateSequenceItem ( DCM_ReferencedStructureSetSequence, dcm_item, -2); dcm_item->putAndInsertString (DCM_ReferencedSOPClassUID, UID_RTStructureSetStorage); dcmtk_put (dcm_item, DCM_ReferencedSOPInstanceUID, d_ptr->rt_study_metadata->get_rtstruct_instance_uid()); /* Convert image bytes to integer, then add to dataset */ if (dose_metadata && dose_metadata->get_metadata(0x3004, 0x0004) == "ERROR") { dose_copy->convert (PT_INT32); dataset->putAndInsertUint16Array (DCM_PixelData, (Uint16*) dose_copy->img, 2*dose_copy->npix); } else { dose_copy->convert (PT_UINT32); dataset->putAndInsertUint16Array (DCM_PixelData, (Uint16*) dose_copy->img, 2*dose_copy->npix); } /* ----------------------------------------------------------------- */ /* Write the output file */ /* ----------------------------------------------------------------- */ std::string filename; if (d_ptr->filenames_with_uid) { filename = string_format ("%s/dose_%s.dcm", dicom_dir, d_ptr->rt_study_metadata->get_dose_series_uid()); } else { filename = string_format ("%s/dose.dcm", dicom_dir); } make_parent_directories (filename); ofc = fileformat.saveFile (filename.c_str(), EXS_LittleEndianExplicit); if (ofc.bad()) { print_and_exit ("Error: cannot write DICOM RTDOSE (%s)\n", ofc.text()); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rtdose.h000066400000000000000000000005631321604176500303700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_rtdose_h_ #define _dcmtk_rtdose_h_ #include "plmbase_config.h" PLMBASE_C_API bool dcmtk_dose_probe (const char *fn); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rtplan.cxx000066400000000000000000000520471321604176500307470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_file.h" #include "dcmtk_metadata.h" #include "dcmtk_module.h" #include "dcmtk_rt_study.h" #include "dcmtk_rt_study_p.h" #include "dcmtk_rtplan.h" #include "dcmtk_series.h" #include "dcmtk_util.h" #include "file_util.h" #include "logfile.h" #include "metadata.h" #include "plm_uid_prefix.h" #include "plm_version.h" #include "print_and_exit.h" #include "rtplan_control_pt.h" #include "rtplan_beam.h" #include "string_util.h" PLMBASE_C_API bool dcmtk_rtplan_probe(const char *rtplan_fn) { DcmFileFormat dfile; /* Suppress warning messages */ OFLog::configure(OFLogger::FATAL_LOG_LEVEL); OFCondition ofrc = dfile.loadFile(rtplan_fn, EXS_Unknown, EGL_noChange); /* Restore error messages -- n.b. dcmtk doesn't have a way to query current setting, so I just set to default */ OFLog::configure(OFLogger::WARN_LOG_LEVEL); if (ofrc.bad()) { return false; } const char *c; DcmDataset *dset = dfile.getDataset(); ofrc = dset->findAndGetString(DCM_Modality, c); if (ofrc.bad() || !c) { return false; } if (strncmp(c, "RTPLAN", strlen("RTPLAN"))) { return false; } else { return true; } } void Dcmtk_rt_study::rtplan_load(void) { Dcmtk_series *ds_rtplan = d_ptr->ds_rtplan; d_ptr->rtplan = Rtplan::New(); /* Modality -- better be RTSTRUCT */ std::string modality = ds_rtplan->get_modality(); if (modality == "RTPLAN") { lprintf("Trying to load rt plan.\n"); } else { print_and_exit("Oops.\n"); } /* FIX: load metadata such as patient name, etc. */ /*const char *val2 = ds_rtplan->get_cstr(DCM_PatientName); const char *val3 = ds_rtplan->get_cstr(DCM_PatientID);*/ /* Load Beam sequence */ DcmSequenceOfItems *seq = 0; bool rc = ds_rtplan->get_sequence(DCM_BeamSequence, seq); if (!rc) { return; } unsigned long iNumOfBeam = seq->card(); for (unsigned long i = 0; i < iNumOfBeam; i++) { Rtplan_beam *curr_beam; OFCondition orc; const char *strVal = 0; long int iVal = 0; int beam_id = 0; std::string strBeamName; DcmItem *item = seq->getItem(i); orc = item->findAndGetLongInt(DCM_BeamNumber, iVal); if (!orc.good()){ continue; } beam_id = iVal; orc = item->findAndGetString(DCM_BeamName, strVal); if (!orc.good()){ continue; } strBeamName = strVal; strVal = 0; curr_beam = d_ptr->rtplan->add_beam(strBeamName, beam_id); DcmSequenceOfItems *cp_seq = 0; orc = item->findAndGetSequence(DCM_ControlPointSequence, cp_seq); unsigned long iNumOfCP = cp_seq->card(); for (unsigned long j = 0; j getItem(j); c_item->findAndGetLongInt(DCM_ControlPointIndex, iVal); //std::string strIsocenter; Rtplan_control_pt* curr_cp = curr_beam->add_control_pt (); /* ContourGeometricType */ orc = c_item->findAndGetString(DCM_IsocenterPosition,strVal); if (!orc.good()){ continue; } float iso_pos[3]; int rc = parse_dicom_float3 (iso_pos, strVal); if (!rc) { curr_cp->set_isocenter (iso_pos); } strVal = 0; /*to be implemented*/ //Get Beam Energy //Get Gantry Angle //Get Collimator openning //GetTable positions //Get MLC positions //Get CumulativeMetersetWeight } if (iNumOfCP > 0){ if (!curr_beam->check_isocenter_identical()){ /* action: isonceter of the control points are not same. */ } } } } void Dcmtk_rt_study::save_rtplan (const char *dicom_dir) { /* Required modules (ref DICOM PS3.3 2016c) Patient General Study RT Series Frame of Reference General Equipment RT General Plan SOP Common */ /* Prepare varibles */ const Rt_study_metadata::Pointer& rsm = d_ptr->rt_study_metadata; const Metadata::Pointer& rtplan_metadata = rsm->get_rtplan_metadata (); std::string s; // Dummy string Rtplan::Pointer& rtplan = d_ptr->rtplan; /* Prepare dcmtk */ OFCondition ofc; DcmFileFormat fileformat; DcmDataset *dataset = fileformat.getDataset(); /* Patient module, general study module, RT series module */ Dcmtk_module::set_patient (dataset, rsm->get_study_metadata ()); Dcmtk_module::set_general_study (dataset, rsm); Dcmtk_module::set_rt_series (dataset, rtplan_metadata, "RTPLAN"); /* Frame of reference module */ dataset->putAndInsertString (DCM_FrameOfReferenceUID, rsm->get_frame_of_reference_uid()); dataset->putAndInsertString (DCM_PositionReferenceIndicator, rsm->get_position_reference_indicator()); /* General equipment module */ Dcmtk_module::set_general_equipment (dataset,rtplan_metadata); /* RT general plan module */ dataset->putAndInsertString (DCM_RTPlanLabel, rtplan->rt_plan_label.c_str()); dataset->putAndInsertString (DCM_RTPlanName, rtplan->rt_plan_name.c_str()); //dataset->putAndInsertString (DCM_RTPlanDescription, "This is only a test"); dataset->putAndInsertString (DCM_RTPlanDate, rtplan->rt_plan_date.c_str()); dataset->putAndInsertString (DCM_RTPlanTime, rtplan->rt_plan_time.c_str()); if (rsm->get_rtstruct_instance_uid() == "") { dataset->putAndInsertString (DCM_RTPlanGeometry, "TREATMENT_DEVICE"); } else { dataset->putAndInsertString (DCM_RTPlanGeometry, "PATIENT"); DcmItem *rsss_item = 0; dataset->findOrCreateSequenceItem ( DCM_ReferencedStructureSetSequence, rsss_item, -2); dcmtk_put (rsss_item, DCM_ReferencedSOPClassUID, UID_RTStructureSetStorage); dcmtk_put (rsss_item, DCM_ReferencedSOPInstanceUID, rsm->get_rtstruct_instance_uid()); } if (rsm->get_dose_instance_uid() != "") { DcmItem *rds_item = 0; dataset->findOrCreateSequenceItem ( DCM_ReferencedDoseSequence, rds_item, -2); dcmtk_put (rds_item, DCM_ReferencedSOPClassUID, UID_RTDoseStorage); dcmtk_put (rds_item, DCM_ReferencedSOPInstanceUID, rsm->get_dose_instance_uid()); } /* SOP common module */ /* GCS TODO: Figure out whether to use Plan or Ion Plan */ // dataset->putAndInsertString (DCM_SOPClassUID, UID_RTPlanStorage); dataset->putAndInsertString (DCM_SOPClassUID, UID_RTIonPlanStorage); dcmtk_put (dataset, DCM_SOPInstanceUID, d_ptr->rt_study_metadata->get_plan_instance_uid()); dataset->putAndInsertString(DCM_InstanceCreationDate, d_ptr->rt_study_metadata->get_study_date()); dataset->putAndInsertString(DCM_InstanceCreationTime, d_ptr->rt_study_metadata->get_study_time()); /* RT prescription module * GCS TODO */ /* RT tolerance tables */ if (rtplan->tolerance_table_label != "") { DcmItem *iots_item = 0; dataset->findOrCreateSequenceItem ( DCM_IonToleranceTableSequence, iots_item, -2); dcmtk_put (iots_item, DCM_ToleranceTableNumber, 0); dcmtk_put (iots_item, DCM_ToleranceTableLabel, rtplan->tolerance_table_label); dcmtk_put (iots_item, DCM_GantryAngleTolerance, rtplan->tolerance_gantry_angle); dcmtk_put (iots_item, DCM_PatientSupportAngleTolerance, rtplan->tolerance_patient_support_angle); dcmtk_put (iots_item, DCM_TableTopVerticalPositionTolerance, rtplan->tolerance_table_top_vertical); dcmtk_put (iots_item, DCM_TableTopLongitudinalPositionTolerance, rtplan->tolerance_table_top_longitudinal); dcmtk_put (iots_item, DCM_TableTopLateralPositionTolerance, rtplan->tolerance_table_top_lateral); dcmtk_put (iots_item, DCM_TableTopPitchAngleTolerance, rtplan->tolerance_table_top_pitch); dcmtk_put (iots_item, DCM_TableTopRollAngleTolerance, rtplan->tolerance_table_top_roll); dcmtk_put (iots_item, DCM_SnoutPositionTolerance, rtplan->tolerance_snout_position); } /* RT patient setup module */ DcmItem *ps_item = 0; dataset->findOrCreateSequenceItem ( DCM_PatientSetupSequence, ps_item, -2); dcmtk_put (ps_item, DCM_PatientSetupNumber, 1); dcmtk_put (ps_item, DCM_PatientPosition, rtplan->patient_position); /* RT fraction scheme module */ DcmItem *fgs_item = 0; dataset->findOrCreateSequenceItem ( DCM_FractionGroupSequence, fgs_item, -2); dcmtk_put (fgs_item, DCM_FractionGroupNumber, 0); dcmtk_put (fgs_item, DCM_NumberOfFractionsPlanned, rtplan->number_of_fractions_planned); dcmtk_put (fgs_item, DCM_NumberOfBeams, rtplan->beamlist.size()); dcmtk_put (fgs_item, DCM_FractionGroupDescription, rtplan->fraction_group_description.c_str()); dcmtk_put (fgs_item, DCM_NumberOfFractionPatternDigitsPerDay, rtplan->number_of_fraction_pattern_digits_per_day.c_str()); dcmtk_put (fgs_item, DCM_RepeatFractionCycleLength, rtplan->repeat_fraction_cycle_length.c_str()); dcmtk_put (fgs_item, DCM_FractionPattern, rtplan->fraction_pattern.c_str()); for (size_t b = 0; b < rtplan->beamlist.size(); b++) { DcmItem *rbs_item = 0; fgs_item->findOrCreateSequenceItem ( DCM_ReferencedBeamSequence, rbs_item, -2); dcmtk_put (rbs_item, DCM_ReferencedBeamNumber, b+1); Rtplan_beam *beam = rtplan->beamlist[b]; dcmtk_put (rbs_item, DCM_BeamMeterset, beam->final_cumulative_meterset_weight); dcmtk_put (rbs_item, DCM_BeamDoseSpecificationPoint, beam->beam_dose_specification_point); dcmtk_put (rbs_item, DCM_BeamDose, beam->beam_dose); } dcmtk_put (fgs_item, DCM_NumberOfBrachyApplicationSetups, 0); /* RT ion beams module */ for (size_t b = 0; b < rtplan->beamlist.size(); b++) { DcmItem *ib_item = 0; dataset->findOrCreateSequenceItem ( DCM_IonBeamSequence, ib_item, -2); s = PLM_to_string (b+1); ib_item->putAndInsertString (DCM_BeamNumber, s.c_str()); Rtplan_beam *beam = rtplan->beamlist[b]; ib_item->putAndInsertString (DCM_BeamName, beam->name.c_str()); ib_item->putAndInsertString (DCM_BeamDescription, beam->description.c_str()); ib_item->putAndInsertString (DCM_BeamType, "STATIC"); ib_item->putAndInsertString (DCM_RadiationType, "PROTON"); ib_item->putAndInsertString (DCM_ScanMode, "MODULATED"); #if defined (commentout) ib_item->putAndInsertString (DCM_ScanMode, "MODULATED_SPEC"); ib_item->putAndInsertString (DCM_ModulatedScanModeType, "STATIONARY"); #endif ib_item->putAndInsertString (DCM_TreatmentMachineName, beam->treatment_machine_name.c_str()); ib_item->putAndInsertString (DCM_Manufacturer, beam->manufacturer.c_str()); ib_item->putAndInsertString (DCM_InstitutionName, beam->institution_name.c_str()); ib_item->putAndInsertString (DCM_InstitutionAddress, beam->institution_address.c_str()); ib_item->putAndInsertString (DCM_InstitutionalDepartmentName, beam->institutional_department_name.c_str()); ib_item->putAndInsertString (DCM_ManufacturerModelName, beam->manufacturer_model_name.c_str()); ib_item->putAndInsertString (DCM_PrimaryDosimeterUnit, "NP"); if (rtplan->tolerance_table_label != "") { dcmtk_put (ib_item, DCM_ReferencedToleranceTableNumber, 0); } if (rtplan->patient_position != "") { dcmtk_put (ib_item, DCM_ReferencedPatientSetupNumber, 1); } ib_item->putAndInsertString (DCM_VirtualSourceAxisDistances, beam->virtual_source_axis_distances.c_str()); ib_item->putAndInsertString (DCM_TreatmentDeliveryType, beam->treatment_delivery_type.c_str()); ib_item->putAndInsertString (DCM_NumberOfWedges, "0"); ib_item->putAndInsertString (DCM_NumberOfCompensators, "0"); ib_item->putAndInsertString (DCM_NumberOfBoli, "0"); ib_item->putAndInsertString (DCM_NumberOfBlocks, "0"); if (rtplan->snout_id != "") { DcmItem *snout_item = 0; ib_item->findOrCreateSequenceItem ( DCM_SnoutSequence, snout_item, -2); snout_item->putAndInsertString (DCM_SnoutID, rtplan->snout_id.c_str()); } if (rtplan->general_accessory_id != "") { DcmItem *ga_item = 0; ib_item->findOrCreateSequenceItem ( DCM_GeneralAccessorySequence, ga_item, -2); ga_item->putAndInsertString (DCM_GeneralAccessoryNumber, "0"); ga_item->putAndInsertString (DCM_GeneralAccessoryID, rtplan->general_accessory_id.c_str()); ga_item->putAndInsertString (DCM_AccessoryCode, rtplan->general_accessory_code.c_str()); } if (rtplan->range_shifter_id != "") { DcmItem *rs_item = 0; ib_item->findOrCreateSequenceItem ( DCM_RangeShifterSequence, rs_item, -2); rs_item->putAndInsertString (DCM_RangeShifterNumber, rtplan->range_shifter_number.c_str()); rs_item->putAndInsertString (DCM_RangeShifterID, rtplan->range_shifter_id.c_str()); rs_item->putAndInsertString (DCM_AccessoryCode, rtplan->range_shifter_code.c_str()); rs_item->putAndInsertString (DCM_RangeShifterType, rtplan->range_shifter_type.c_str()); } if (rtplan->range_modulator_id != "") { DcmItem *rm_item = 0; ib_item->findOrCreateSequenceItem ( DCM_RangeModulatorSequence, rm_item, -2); rm_item->putAndInsertString (DCM_RangeModulatorNumber, "0"); rm_item->putAndInsertString (DCM_RangeModulatorID, rtplan->range_modulator_id.c_str()); rm_item->putAndInsertString (DCM_AccessoryCode, rtplan->range_modulator_code.c_str()); } ib_item->putAndInsertString (DCM_NumberOfRangeShifters, rtplan->number_of_range_shifters.c_str()); ib_item->putAndInsertString (DCM_NumberOfLateralSpreadingDevices,"0"); ib_item->putAndInsertString (DCM_NumberOfRangeModulators, "0"); ib_item->putAndInsertString (DCM_PatientSupportType, "TABLE"); ib_item->putAndInsertString (DCM_PatientSupportID, rtplan->patient_support_id.c_str()); ib_item->putAndInsertString (DCM_PatientSupportAccessoryCode, rtplan->patient_support_accessory_code.c_str()); dcmtk_put (ib_item, DCM_FinalCumulativeMetersetWeight, beam->final_cumulative_meterset_weight); dcmtk_put (ib_item, DCM_NumberOfControlPoints, beam->cplist.size()); for (size_t c = 0; c < beam->cplist.size(); c++) { DcmItem *cp_item = 0; ib_item->findOrCreateSequenceItem ( DCM_IonControlPointSequence, cp_item, -2); s = PLM_to_string (c); cp_item->putAndInsertString (DCM_ControlPointIndex, s.c_str()); Rtplan_control_pt *cp = beam->cplist[c]; s = PLM_to_string (cp->cumulative_meterset_weight); cp_item->putAndInsertString (DCM_CumulativeMetersetWeight, s.c_str()); if (c == 0) { s = PLM_to_string (beam->snout_position); cp_item->putAndInsertString (DCM_SnoutPosition, s.c_str()); s = PLM_to_string (beam->gantry_angle); cp_item->putAndInsertString (DCM_GantryAngle, s.c_str()); cp_item->putAndInsertString (DCM_GantryRotationDirection, beam->gantry_rotation_direction.c_str()); s = PLM_to_string (beam->gantry_pitch_angle); cp_item->putAndInsertString (DCM_GantryPitchAngle, s.c_str()); cp_item->putAndInsertString (DCM_GantryPitchRotationDirection, beam-> gantry_pitch_rotation_direction.c_str()); s = PLM_to_string (beam->beam_limiting_device_angle); cp_item->putAndInsertString (DCM_BeamLimitingDeviceAngle, s.c_str()); cp_item->putAndInsertString (DCM_BeamLimitingDeviceRotationDirection, beam-> beam_limiting_device_rotation_direction.c_str()); s = PLM_to_string (beam->patient_support_angle); cp_item->putAndInsertString (DCM_PatientSupportAngle, s.c_str()); cp_item->putAndInsertString (DCM_PatientSupportRotationDirection, beam-> patient_support_rotation_direction.c_str()); s = PLM_to_string (beam->table_top_vertical_position); cp_item->putAndInsertString (DCM_TableTopVerticalPosition, s.c_str()); s = PLM_to_string (beam->table_top_longitudinal_position); cp_item->putAndInsertString (DCM_TableTopLongitudinalPosition, s.c_str()); s = PLM_to_string (beam->table_top_lateral_position); cp_item->putAndInsertString (DCM_TableTopLateralPosition, s.c_str()); s = PLM_to_string (beam->table_top_pitch_angle); cp_item->putAndInsertString (DCM_TableTopPitchAngle, s.c_str()); cp_item->putAndInsertString (DCM_TableTopPitchRotationDirection, beam-> table_top_pitch_rotation_direction.c_str()); s = PLM_to_string (beam->table_top_roll_angle); cp_item->putAndInsertString (DCM_TableTopRollAngle, s.c_str()); cp_item->putAndInsertString (DCM_TableTopRollRotationDirection, beam-> table_top_roll_rotation_direction.c_str()); s = string_format ("%f\\%f\\%f", beam->isocenter_position[0], beam->isocenter_position[1], beam->isocenter_position[2]); cp_item->putAndInsertString (DCM_IsocenterPosition, s.c_str()); } s = PLM_to_string (cp->nominal_beam_energy); cp_item->putAndInsertString (DCM_NominalBeamEnergy, s.c_str()); s = PLM_to_string (cp->number_of_paintings); cp_item->putAndInsertString (DCM_NumberOfPaintings, s.c_str()); cp_item->putAndInsertString (DCM_ScanSpotTuneID, cp->scan_spot_tune_id.c_str()); s = string_format ("%f\\%f", cp->scanning_spot_size[0], cp->scanning_spot_size[1]); cp_item->putAndInsertString (DCM_ScanningSpotSize, s.c_str()); /* Dcmtk has no putAndInsertFloat32Array, so we must use more primitive methods */ size_t num_spots = cp->scan_spot_position_map.size() / 2; s = PLM_to_string (num_spots); cp_item->putAndInsertString (DCM_NumberOfScanSpotPositions, s.c_str()); if (num_spots != cp->scan_spot_meterset_weights.size()) { lprintf ("Warning, scan spot positions (%d) and weights (%d)" " are mismatched.\n", (int) cp->scan_spot_position_map.size(), (int) cp->scan_spot_meterset_weights.size()); if (cp->scan_spot_meterset_weights.size() < num_spots) { num_spots = cp->scan_spot_meterset_weights.size(); } } DcmFloatingPointSingle *fele; Float32 *f; fele = new DcmFloatingPointSingle (DCM_ScanSpotPositionMap); #if __cplusplus >= 201103L f = cp->scan_spot_position_map.data (); #else f = &cp->scan_spot_position_map[0]; #endif ofc = fele->putFloat32Array (f, 2*num_spots); ofc = cp_item->insert (fele); fele = new DcmFloatingPointSingle (DCM_ScanSpotMetersetWeights); #if __cplusplus >= 201103L f = cp->scan_spot_meterset_weights.data (); #else f = &cp->scan_spot_meterset_weights[0]; #endif ofc = fele->putFloat32Array (f, num_spots); ofc = cp_item->insert (fele); } } /* ----------------------------------------------------------------- */ /* Write the output file */ /* ----------------------------------------------------------------- */ std::string filename; if (d_ptr->filenames_with_uid) { filename = string_format ("%s/rtplan_%s.dcm", dicom_dir, d_ptr->rt_study_metadata->get_dose_series_uid()); } else { filename = string_format ("%s/rtplan.dcm", dicom_dir); } make_parent_directories (filename); ofc = fileformat.saveFile (filename.c_str(), EXS_LittleEndianExplicit); if (ofc.bad()) { print_and_exit ("Error: cannot write DICOM RTPLAN (%s)\n", ofc.text()); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rtplan.h000066400000000000000000000005731321604176500303710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_rtplan_h_ #define _dcmtk_rtplan_h_ #include "plmbase_config.h" PLMBASE_C_API bool dcmtk_rtplan_probe(const char *rtplan_fn); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rtss.cxx000066400000000000000000000443701321604176500304420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_file.h" #include "dcmtk_metadata.h" #include "dcmtk_rt_study.h" #include "dcmtk_rt_study_p.h" #include "dcmtk_series.h" #include "dcmtk_slice_data.h" #include "dcmtk_util.h" #include "file_util.h" #include "logfile.h" #include "metadata.h" #include "plm_uid_prefix.h" #include "plm_version.h" #include "print_and_exit.h" #include "rtss.h" #include "rtss_contour.h" #include "rtss_roi.h" #include "string_util.h" PLMBASE_C_API bool dcmtk_rtss_probe (const char *rtss_fn) { DcmFileFormat dfile; /* Suppress warning messages */ OFLog::configure(OFLogger::FATAL_LOG_LEVEL); OFCondition ofrc = dfile.loadFile (rtss_fn, EXS_Unknown, EGL_noChange); /* Restore error messages -- n.b. dcmtk doesn't have a way to query current setting, so I just set to default */ OFLog::configure(OFLogger::WARN_LOG_LEVEL); if (ofrc.bad()) { return false; } const char *c; DcmDataset *dset = dfile.getDataset(); ofrc = dset->findAndGetString (DCM_Modality, c); if (ofrc.bad() || !c) { return false; } if (strncmp (c, "RTSTRUCT", strlen("RTSTRUCT"))) { return false; } else { return true; } } void Dcmtk_rt_study::rtss_load (void) { Dcmtk_series *ds_rtss = d_ptr->ds_rtss; d_ptr->rtss = Rtss::New(); /* Modality -- better be RTSTRUCT */ std::string modality = ds_rtss->get_modality(); if (modality == "RTSTRUCT") { lprintf ("Trying to load rt structure set.\n"); } else { print_and_exit ("Oops.\n"); } /* FIX: load metadata such as patient name, etc. */ if (d_ptr->rt_study_metadata) { d_ptr->rt_study_metadata->set_rtstruct_instance_uid ( ds_rtss->get_cstr (DCM_SOPInstanceUID)); } /* ReferencedFrameOfReferenceSequence */ DcmSequenceOfItems *seq = 0; bool rc = ds_rtss->get_sequence ( DCM_ReferencedFrameOfReferenceSequence, seq); if (!rc) { lprintf ("Huh? Why no RFOR sequence???\n"); } /* StructureSetROISequence */ seq = 0; rc = ds_rtss->get_sequence (DCM_StructureSetROISequence, seq); if (rc) { for (unsigned long i = 0; i < seq->card(); i++) { int structure_id; OFCondition orc; const char *val = 0; orc = seq->getItem(i)->findAndGetString (DCM_ROINumber, val); if (!orc.good()) { continue; } if (1 != sscanf (val, "%d", &structure_id)) { continue; } val = 0; orc = seq->getItem(i)->findAndGetString (DCM_ROIName, val); lprintf ("Adding structure (%d), %s\n", structure_id, val); d_ptr->rtss->add_structure ( std::string (val), std::string(), structure_id); } } /* ROIContourSequence */ seq = 0; rc = ds_rtss->get_sequence (DCM_ROIContourSequence, seq); if (rc) { for (unsigned long i = 0; i < seq->card(); i++) { Rtss_roi *curr_structure; int structure_id; OFCondition orc; const char *val = 0; DcmItem *item = seq->getItem(i); /* Get ID and color */ orc = item->findAndGetString (DCM_ReferencedROINumber, val); if (!orc.good()) { lprintf ("Error finding DCM_ReferencedROINumber.\n"); continue; } if (1 != sscanf (val, "%d", &structure_id)) { continue; } val = 0; orc = item->findAndGetString (DCM_ROIDisplayColor, val); lprintf ("Structure %d has color %s\n", structure_id, val); /* Look up the structure for this id and set color */ curr_structure = d_ptr->rtss->find_structure_by_id (structure_id); if (!curr_structure) { lprintf ("Couldn't reference structure with id %d\n", structure_id); continue; } curr_structure->set_color (val); /* ContourSequence */ DcmSequenceOfItems *c_seq = 0; orc = item->findAndGetSequence (DCM_ContourSequence, c_seq); if (!orc.good()) { lprintf ("Error finding DCM_ContourSequence.\n"); continue; } for (unsigned long j = 0; j < c_seq->card(); j++) { int i, p, n, contour_data_len; int num_points; const char *contour_geometric_type; const char *contour_data; const char *number_of_contour_points; Rtss_contour *curr_polyline; DcmItem *c_item = c_seq->getItem(j); /* ContourGeometricType */ orc = c_item->findAndGetString (DCM_ContourGeometricType, contour_geometric_type); if (!orc.good()) { lprintf ("Error finding DCM_ContourGeometricType.\n"); continue; } if (strncmp (contour_geometric_type, "CLOSED_PLANAR", strlen("CLOSED_PLANAR"))) { /* Might be "POINT". Do I want to preserve this? */ lprintf ("Skipping geometric type: [%s]\n", contour_geometric_type); continue; } /* NumberOfContourPoints */ orc = c_item->findAndGetString (DCM_NumberOfContourPoints, number_of_contour_points); if (!orc.good()) { lprintf ("Error finding DCM_NumberOfContourPoints.\n"); continue; } if (1 != sscanf (number_of_contour_points, "%d", &num_points)) { lprintf ("Error parsing number_of_contour_points...\n"); continue; } if (num_points <= 0) { /* Polyline with zero points? Skip it. */ continue; } /* ContourData */ orc = c_item->findAndGetString (DCM_ContourData, contour_data); if (!orc.good()) { lprintf ("Error finding DCM_ContourData.\n"); continue; } /* Create a new polyline for this structure */ curr_polyline = curr_structure->add_polyline (); curr_polyline->slice_no = -1; //curr_polyline->ct_slice_uid = ""; curr_polyline->num_vertices = num_points; curr_polyline->x = (float*) malloc (num_points * sizeof(float)); curr_polyline->y = (float*) malloc (num_points * sizeof(float)); curr_polyline->z = (float*) malloc (num_points * sizeof(float)); /* Parse dicom data string */ i = 0; n = 0; contour_data_len = strlen (contour_data); for (p = 0; p < 3 * num_points; p++) { float f; int this_n; /* Skip \\ */ if (n < contour_data_len) { if (contour_data[n] == '\\') { n++; } } /* Parse float value */ if (1 != sscanf (&contour_data[n], "%f%n", &f, &this_n)) { lprintf ("Error parsing data...\n"); break; } n += this_n; /* Put value into polyline */ switch (i) { case 0: curr_polyline->x[p/3] = f; break; case 1: curr_polyline->y[p/3] = f; break; case 2: curr_polyline->z[p/3] = f; break; } i = (i + 1) % 3; } } } } } void Dcmtk_rt_study::save_rtss (const char *dicom_dir) { OFCondition ofc; Rtss::Pointer& rtss = d_ptr->rtss; Metadata::Pointer rtstruct_metadata; if (d_ptr->rt_study_metadata) { rtstruct_metadata = d_ptr->rt_study_metadata->get_rtstruct_metadata (); } /* Prepare structure set with slice uids */ const Slice_list *slice_list = d_ptr->rt_study_metadata->get_slice_list (); rtss->apply_slice_list (slice_list); /* Prepare dcmtk */ DcmFileFormat fileformat; DcmDataset *dataset = fileformat.getDataset(); /* ----------------------------------------------------------------- */ /* Part 1 -- General header */ /* ----------------------------------------------------------------- */ dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, d_ptr->rt_study_metadata->get_study_date()); dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, d_ptr->rt_study_metadata->get_study_time()); dataset->putAndInsertOFStringArray(DCM_InstanceCreatorUID, PLM_UID_PREFIX); dataset->putAndInsertString (DCM_SOPClassUID, UID_RTStructureSetStorage); dcmtk_put (dataset, DCM_SOPInstanceUID, d_ptr->rt_study_metadata->get_rtstruct_instance_uid()); dataset->putAndInsertOFStringArray (DCM_StudyDate, d_ptr->rt_study_metadata->get_study_date()); dataset->putAndInsertOFStringArray (DCM_StudyTime, d_ptr->rt_study_metadata->get_study_time()); dcmtk_copy_from_metadata (dataset, rtstruct_metadata, DCM_StudyDescription, ""); dataset->putAndInsertOFStringArray (DCM_AccessionNumber, ""); dataset->putAndInsertOFStringArray (DCM_Modality, "RTSTRUCT"); dataset->putAndInsertString (DCM_Manufacturer, "Plastimatch"); dataset->putAndInsertString (DCM_InstitutionName, ""); dataset->putAndInsertString (DCM_ReferringPhysicianName, ""); dataset->putAndInsertString (DCM_StationName, ""); dcmtk_copy_from_metadata (dataset, rtstruct_metadata, DCM_SeriesDescription, ""); dataset->putAndInsertString (DCM_ManufacturerModelName, "Plastimatch"); dcmtk_copy_from_metadata (dataset, rtstruct_metadata, DCM_PatientName, ""); dcmtk_copy_from_metadata (dataset, rtstruct_metadata, DCM_PatientID, ""); dataset->putAndInsertString (DCM_PatientBirthDate, ""); dcmtk_copy_from_metadata (dataset, rtstruct_metadata, DCM_PatientSex, "O"); dataset->putAndInsertString (DCM_SoftwareVersions, PLASTIMATCH_VERSION_STRING); #if defined (commentout) /* GCS FIX */ /* PatientPosition */ // gf->InsertValEntry (xxx, 0x0018, 0x5100); #endif dataset->putAndInsertString (DCM_StudyInstanceUID, d_ptr->rt_study_metadata->get_study_uid()); dataset->putAndInsertString (DCM_SeriesInstanceUID, d_ptr->rt_study_metadata->get_rtstruct_series_uid()); dcmtk_copy_from_metadata (dataset, rtstruct_metadata, DCM_StudyID, "10001"); dcmtk_copy_from_metadata (dataset, rtstruct_metadata, DCM_SeriesNumber, "1"); dataset->putAndInsertString (DCM_InstanceNumber, "1"); dataset->putAndInsertString (DCM_StructureSetLabel, "AutoSS"); dataset->putAndInsertString (DCM_StructureSetName, "AutoSS"); dataset->putAndInsertOFStringArray (DCM_StructureSetDate, d_ptr->rt_study_metadata->get_study_date()); dataset->putAndInsertOFStringArray (DCM_StructureSetTime, d_ptr->rt_study_metadata->get_study_time()); /* ----------------------------------------------------------------- */ /* Part 2 -- UID's for CT series */ /* ----------------------------------------------------------------- */ DcmSequenceOfItems *rfor_seq = 0; DcmItem *rfor_item = 0; dataset->findOrCreateSequenceItem ( DCM_ReferencedFrameOfReferenceSequence, rfor_item, -2); rfor_item->putAndInsertString (DCM_FrameOfReferenceUID, d_ptr->rt_study_metadata->get_frame_of_reference_uid()); dataset->findAndGetSequence ( DCM_ReferencedFrameOfReferenceSequence, rfor_seq); DcmItem *rtrstudy_item = 0; rfor_item->findOrCreateSequenceItem ( DCM_RTReferencedStudySequence, rtrstudy_item, -2); rtrstudy_item->putAndInsertString ( DCM_ReferencedSOPClassUID, UID_RETIRED_StudyComponentManagementSOPClass); rtrstudy_item->putAndInsertString ( DCM_ReferencedSOPInstanceUID, d_ptr->rt_study_metadata->get_study_uid()); DcmItem *rtrseries_item = 0; rtrstudy_item->findOrCreateSequenceItem ( DCM_RTReferencedSeriesSequence, rtrseries_item, -2); rtrseries_item->putAndInsertString ( DCM_SeriesInstanceUID, d_ptr->rt_study_metadata->get_ct_series_uid()); for (int k = 0; k < d_ptr->rt_study_metadata->num_slices(); k++) { DcmItem *ci_item = 0; rtrseries_item->findOrCreateSequenceItem ( DCM_ContourImageSequence, ci_item, -2); ci_item->putAndInsertString ( DCM_ReferencedSOPClassUID, UID_CTImageStorage); ci_item->putAndInsertString ( DCM_ReferencedSOPInstanceUID, d_ptr->rt_study_metadata->get_slice_uid (k)); } /* ----------------------------------------------------------------- */ /* Part 3 -- Structure info */ /* ----------------------------------------------------------------- */ for (size_t i = 0; i < rtss->num_structures; i++) { DcmItem *ssroi_item = 0; std::string tmp; dataset->findOrCreateSequenceItem ( DCM_StructureSetROISequence, ssroi_item, -2); tmp = string_format ("%d", rtss->slist[i]->id); ssroi_item->putAndInsertString (DCM_ROINumber, tmp.c_str()); ssroi_item->putAndInsertString (DCM_ReferencedFrameOfReferenceUID, d_ptr->rt_study_metadata->get_frame_of_reference_uid()); ssroi_item->putAndInsertString (DCM_ROIName, rtss->slist[i]->name.c_str()); ssroi_item->putAndInsertString (DCM_ROIGenerationAlgorithm, ""); } /* ----------------------------------------------------------------- */ /* Part 4 -- Contour info */ /* ----------------------------------------------------------------- */ for (size_t i = 0; i < rtss->num_structures; i++) { Rtss_roi *curr_structure = rtss->slist[i]; DcmItem *roic_item = 0; dataset->findOrCreateSequenceItem ( DCM_ROIContourSequence, roic_item, -2); std::string tmp = curr_structure->get_dcm_color_string (); roic_item->putAndInsertString (DCM_ROIDisplayColor, tmp.c_str()); for (size_t j = 0; j < curr_structure->num_contours; j++) { Rtss_contour *curr_contour = curr_structure->pslist[j]; if (curr_contour->num_vertices <= 0) continue; #if defined (commentout) /* GCS 2013-07-02: DICOM standard allows contours without an associated slice UID. Maybe this bug is now fixed in XiO??? */ /* GE -> XiO transfer does not work if contour does not have corresponding slice uid */ if (curr_contour->ct_slice_uid.empty()) { printf ("Warning: Omitting contour (%ld,%ld)\n", (long) i, (long) j); continue; } #endif /* Add item to ContourSequence */ DcmItem *c_item = 0; roic_item->findOrCreateSequenceItem ( DCM_ContourSequence, c_item, -2); /* ContourImageSequence */ if (curr_contour->ct_slice_uid != "") { DcmItem *ci_item = 0; c_item->findOrCreateSequenceItem ( DCM_ContourImageSequence, ci_item, -2); ci_item->putAndInsertString (DCM_ReferencedSOPClassUID, UID_CTImageStorage); ci_item->putAndInsertString (DCM_ReferencedSOPInstanceUID, curr_contour->ct_slice_uid.c_str()); } /* ContourGeometricType */ c_item->putAndInsertString (DCM_ContourGeometricType, "CLOSED_PLANAR"); /* NumberOfContourPoints */ tmp = string_format ("%d", curr_contour->num_vertices); c_item->putAndInsertString (DCM_NumberOfContourPoints, tmp.c_str()); /* ContourData */ tmp = string_format ("%.8g\\%.8g\\%.8g", curr_contour->x[0], curr_contour->y[0], curr_contour->z[0]); for (size_t k = 1; k < curr_contour->num_vertices; k++) { std::string tmp2 = string_format ("\\%.8g\\%.8g\\%.8g", curr_contour->x[k], curr_contour->y[k], curr_contour->z[k]); tmp += tmp2; } c_item->putAndInsertString (DCM_ContourData, tmp.c_str()); } tmp = string_format ("%d", (int) curr_structure->id); roic_item->putAndInsertString (DCM_ReferencedROINumber, tmp.c_str()); } /* ----------------------------------------------------------------- */ /* Part 5 -- More structure info */ /* ----------------------------------------------------------------- */ for (size_t i = 0; i < rtss->num_structures; i++) { Rtss_roi *curr_structure = rtss->slist[i]; std::string tmp; /* RTROIObservationsSequence */ DcmItem *rtroio_item = 0; dataset->findOrCreateSequenceItem ( DCM_RTROIObservationsSequence, rtroio_item, -2); /* ObservationNumber */ tmp = string_format ("%d", (int) curr_structure->id); rtroio_item->putAndInsertString (DCM_ObservationNumber, tmp.c_str()); /* ReferencedROINumber */ rtroio_item->putAndInsertString (DCM_ReferencedROINumber, tmp.c_str()); /* ROIObservationLabel */ if (curr_structure->name.length() <= 16) { rtroio_item->putAndInsertString (DCM_ROIObservationLabel, curr_structure->name.c_str()); } else { /* VR is SH, max length 16 */ std::string tmp_name = curr_structure->name.substr (0, 16); rtroio_item->putAndInsertString (DCM_ROIObservationLabel, tmp_name.c_str()); } /* RTROIInterpretedType */ rtroio_item->putAndInsertString (DCM_RTROIInterpretedType, ""); /* ROIInterpreter */ rtroio_item->putAndInsertString (DCM_ROIInterpreter, ""); } /* ----------------------------------------------------------------- */ /* Write the output file */ /* ----------------------------------------------------------------- */ std::string rtss_fn; if (d_ptr->filenames_with_uid) { rtss_fn = string_format ("%s/rtss_%s.dcm", dicom_dir, d_ptr->rt_study_metadata->get_rtstruct_series_uid()); } else { rtss_fn = string_format ("%s/rtss.dcm", dicom_dir); } make_parent_directories (rtss_fn); ofc = fileformat.saveFile (rtss_fn.c_str(), EXS_LittleEndianExplicit); if (ofc.bad()) { print_and_exit ("Error: cannot write DICOM RTSTRUCT (%s)\n", ofc.text()); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_rtss.h000066400000000000000000000005641321604176500300640ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_rtss_h_ #define _dcmtk_rtss_h_ #include "plmbase_config.h" PLMBASE_C_API bool dcmtk_rtss_probe (const char *rtss_fn); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_series.cxx000066400000000000000000000065161321604176500307410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_file.h" #include "dcmtk_metadata.h" #include "dcmtk_series.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_image_set.h" #include "print_and_exit.h" #include "rt_study_metadata.h" #include "volume.h" class Dcmtk_series_private { public: Dcmtk_file_list m_flist; Rt_study_metadata::Pointer m_drs; public: Dcmtk_series_private () { } ~Dcmtk_series_private () { } }; Dcmtk_series::Dcmtk_series () { d_ptr = new Dcmtk_series_private; } Dcmtk_series::~Dcmtk_series () { delete d_ptr; } const std::list& Dcmtk_series::get_flist () const { return d_ptr->m_flist; } const char* Dcmtk_series::get_cstr (const DcmTagKey& tag_key) const { return d_ptr->m_flist.front()->get_cstr(tag_key); } bool Dcmtk_series::get_int16_array (const DcmTagKey& tag_key, const int16_t** val, unsigned long* count) const { return d_ptr->m_flist.front()->get_int16_array (tag_key, val, count); } bool Dcmtk_series::get_sequence (const DcmTagKey& tag_key, DcmSequenceOfItems*& seq) const { return d_ptr->m_flist.front()->get_sequence (tag_key, seq); } std::string Dcmtk_series::get_string (const DcmTagKey& tag_key) const { const char* c = d_ptr->m_flist.front()->get_cstr(tag_key); if (!c) c = ""; return std::string(c); } bool Dcmtk_series::get_uint16 (const DcmTagKey& tag_key, uint16_t* val) const { return d_ptr->m_flist.front()->get_uint16 (tag_key, val); } bool Dcmtk_series::get_uint16_array (const DcmTagKey& tag_key, const uint16_t** val, unsigned long* count) const { return d_ptr->m_flist.front()->get_uint16_array (tag_key, val, count); } std::string Dcmtk_series::get_modality (void) const { return get_string (DCM_Modality); } std::string Dcmtk_series::get_referenced_uid (void) const { bool rc; if (this->get_modality() != "RTSTRUCT") { return ""; } DcmItem* rfors = 0; rc = d_ptr->m_flist.front()->get_dataset()->findAndGetSequenceItem ( DCM_ReferencedFrameOfReferenceSequence, rfors).good(); if (!rc) { return ""; } lprintf ("Found DCM_ReferencedFrameOfReferenceSequence!\n"); DcmItem* rss = 0; rc = rfors->findAndGetSequenceItem ( DCM_RTReferencedStudySequence, rss).good(); if (!rc) { return ""; } lprintf ("Found DCM_RTReferencedStudySequence!\n"); return ""; } size_t Dcmtk_series::get_number_of_files (void) const { return d_ptr->m_flist.size(); } void Dcmtk_series::insert (Dcmtk_file::Pointer& df) { d_ptr->m_flist.push_back (df); } void Dcmtk_series::sort (void) { d_ptr->m_flist.sort (dcmtk_file_compare_z_position); } void Dcmtk_series::set_rt_study_metadata (Rt_study_metadata::Pointer& drs) { d_ptr->m_drs = drs; } void Dcmtk_series::debug (void) const { std::list::const_iterator it; for (it = d_ptr->m_flist.begin(); it != d_ptr->m_flist.end(); ++it) { const Dcmtk_file::Pointer& df = (*it); df->debug (); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_series.h000077500000000000000000000030771321604176500303700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_series_h_ #define _dcmtk_series_h_ #include "plmbase_config.h" #include #include "dcmtk_file.h" #include "rt_study_metadata.h" #include "plm_image.h" #include "plm_int.h" class DcmTagKey; class Dcmtk_file; class Dcmtk_series_private; class Rt_study_metadata; class Plm_image; typedef std::list Dcmtk_file_list; class PLMBASE_API Dcmtk_series { public: Dcmtk_series (); ~Dcmtk_series (); public: Dcmtk_series_private *d_ptr; public: const std::list& get_flist () const; const char* get_cstr (const DcmTagKey& tag_key) const; bool get_int16_array (const DcmTagKey& tag_key, const int16_t** val, unsigned long* count) const; bool get_sequence (const DcmTagKey& tag_key, DcmSequenceOfItems*& seq) const; std::string get_string (const DcmTagKey& tag_key) const; bool get_uint16 (const DcmTagKey& tag_key, uint16_t* val) const; bool get_uint16_array (const DcmTagKey& tag_key, const uint16_t** val, unsigned long* count) const; std::string get_modality (void) const; std::string get_referenced_uid (void) const; size_t get_number_of_files () const; void insert (Dcmtk_file::Pointer& df); void sort (void); void set_rt_study_metadata (Rt_study_metadata::Pointer& drs); void debug (void) const; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_series_map.h000066400000000000000000000010021321604176500312040ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_series_map_h_ #define _dcmtk_series_map_h_ #include class Dcmtk_series; /*! Map from SeriesInstanceUID to Dcmtk_series */ typedef std::map Dcmtk_series_map; typedef std::pair Dcmtk_series_map_pair; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_slice_data.h000066400000000000000000000013071321604176500311550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_slice_data_h_ #define _dcmtk_slice_data_h_ #include "plmbase_config.h" #include #include "plm_int.h" #include "volume.h" class Dcmtk_slice_data { public: std::string fn; Volume::Pointer vol; size_t slice_size; float *slice_float; int16_t *slice_int16; float intercept; float slope; char slice_uid[100]; std::string ipp; std::string iop; std::string sloc; std::string sthk; int instance_no; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_sro.cxx000066400000000000000000000176141321604176500302530ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "dcmtk_config.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_metadata.h" #include "dcmtk_module.h" #include "dcmtk_sro.h" #include "dicom_util.h" #include "file_util.h" #include "logfile.h" #include "plm_uid_prefix.h" #include "print_and_exit.h" #include "string_util.h" #include "xform.h" void Dcmtk_sro::save ( const Xform::Pointer& xf, const Rt_study_metadata::Pointer& rsm_fixed, const Rt_study_metadata::Pointer& rsm_moving, const std::string& dicom_dir, bool filenames_with_uid) { /* Prepare xform */ Xform xf_aff; xform_to_aff (&xf_aff, xf.get(), 0); AffineTransformType::Pointer itk_aff = xf_aff.get_aff(); /* Prepare dcmtk */ OFCondition ofc; DcmFileFormat fileformat; DcmDataset *dataset = fileformat.getDataset(); if (!rsm_fixed || !rsm_moving) { print_and_exit ("Sorry, anonymous spatial registration objects " "are not yet supported.\n"); } Metadata::Pointer study_meta = rsm_fixed->get_study_metadata (); Metadata::Pointer sro_meta = rsm_fixed->get_sro_metadata (); /* Patient module */ Dcmtk_module::set_patient (dataset, study_meta); /* General Study module */ Dcmtk_module::set_general_study (dataset, rsm_fixed); dataset->putAndInsertOFStringArray (DCM_StudyDate, rsm_moving->get_study_date()); dataset->putAndInsertOFStringArray (DCM_StudyTime, rsm_moving->get_study_time()); /* General Series module */ Dcmtk_module::set_general_series (dataset, sro_meta, "REG"); /* Spatial Registration Series module */ /* (nothing to do) */ /* Frame of Reference module */ Dcmtk_module::set_frame_of_reference (dataset, rsm_fixed); /* General Equipment module */ Dcmtk_module::set_general_equipment (dataset, study_meta); /* Spatial Registration module */ dataset->putAndInsertOFStringArray (DCM_ContentDate, rsm_moving->get_study_date()); dataset->putAndInsertOFStringArray (DCM_ContentTime, rsm_moving->get_study_time()); dataset->putAndInsertString (DCM_InstanceNumber, ""); dataset->putAndInsertString (DCM_ContentLabel, ""); /* fixed image */ DcmItem *reg_item = 0; dataset->findOrCreateSequenceItem ( DCM_RegistrationSequence, reg_item, -2); reg_item->putAndInsertString ( DCM_FrameOfReferenceUID, rsm_fixed->get_frame_of_reference_uid()); DcmItem *mr_item = 0; reg_item->findOrCreateSequenceItem ( DCM_MatrixRegistrationSequence, mr_item, -2); DcmItem *rtc_item = 0; mr_item->findOrCreateSequenceItem ( DCM_RegistrationTypeCodeSequence, rtc_item, -2); rtc_item->putAndInsertString (DCM_CodeValue, "125025"); rtc_item->putAndInsertString (DCM_CodingSchemeDesignator, "DCM"); rtc_item->putAndInsertString (DCM_CodeMeaning, "Visual Alignment"); DcmItem *m_item = 0; mr_item->findOrCreateSequenceItem (DCM_MatrixSequence, m_item, -2); m_item->putAndInsertString (DCM_FrameOfReferenceTransformationMatrix, "1.0\\0.0\\0.0\\0.0\\0.0\\1.0\\0.0\\0.0\\" "0.0\\0.0\\1.0\\0.0\\0.0\\0.0\\0.0\\1.0"); m_item->putAndInsertString (DCM_FrameOfReferenceTransformationMatrixType, "RIGID"); /* moving image */ dataset->findOrCreateSequenceItem ( DCM_RegistrationSequence, reg_item, -2); reg_item->putAndInsertString ( DCM_FrameOfReferenceUID, rsm_moving->get_frame_of_reference_uid()); reg_item->findOrCreateSequenceItem ( DCM_MatrixRegistrationSequence, mr_item, -2); mr_item->findOrCreateSequenceItem ( DCM_RegistrationTypeCodeSequence, rtc_item, -2); rtc_item->putAndInsertString (DCM_CodeValue, "125025"); rtc_item->putAndInsertString (DCM_CodingSchemeDesignator, "DCM"); rtc_item->putAndInsertString (DCM_CodeMeaning, "Visual Alignment"); mr_item->findOrCreateSequenceItem (DCM_MatrixSequence, m_item, -2); std::string matrix_string; const AffineTransformType::MatrixType& itk_aff_mat = itk_aff->GetMatrix (); const AffineTransformType::OutputVectorType& itk_aff_off = itk_aff->GetOffset (); printf ("ITK_AFF_OFF\n%f %f %f\n", itk_aff_off[0], itk_aff_off[1], itk_aff_off[2]); /* Nb. ITK does not easily create an inverse affine transform. Therefore we play with the matrices. */ vnl_matrix_fixed< double, 3, 3 > itk_aff_mat_inv = itk_aff_mat.GetInverse(); matrix_string = string_format ( "%f\\%f\\%f\\%f\\" "%f\\%f\\%f\\%f\\" "%f\\%f\\%f\\%f\\" "0.0\\0.0\\0.0\\1.0", itk_aff_mat_inv[0][0], itk_aff_mat_inv[0][1], itk_aff_mat_inv[0][2], - itk_aff_mat_inv[0][0] * itk_aff_off[0] - itk_aff_mat_inv[0][1] * itk_aff_off[1] - itk_aff_mat_inv[0][2] * itk_aff_off[2], itk_aff_mat_inv[1][0], itk_aff_mat_inv[1][1], itk_aff_mat_inv[1][2], - itk_aff_mat_inv[1][0] * itk_aff_off[0] - itk_aff_mat_inv[1][1] * itk_aff_off[1] - itk_aff_mat_inv[1][2] * itk_aff_off[2], itk_aff_mat_inv[2][0], itk_aff_mat_inv[2][1], itk_aff_mat_inv[2][2], - itk_aff_mat_inv[2][0] * itk_aff_off[0] - itk_aff_mat_inv[2][1] * itk_aff_off[1] - itk_aff_mat_inv[2][2] * itk_aff_off[2] ); m_item->putAndInsertString (DCM_FrameOfReferenceTransformationMatrix, matrix_string.c_str()); m_item->putAndInsertString (DCM_FrameOfReferenceTransformationMatrixType, "RIGID"); printf ("SRO\n%s\n", matrix_string.c_str()); /* Common Instance Reference module */ DcmItem *rss_item = 0; DcmItem *ris_item = 0; /* moving */ dataset->findOrCreateSequenceItem ( DCM_ReferencedSeriesSequence, rss_item, -2); rss_item->findOrCreateSequenceItem ( DCM_ReferencedInstanceSequence, ris_item, -2); ris_item->putAndInsertString (DCM_ReferencedSOPClassUID, UID_CTImageStorage); ris_item->putAndInsertString (DCM_ReferencedSOPInstanceUID, rsm_moving->get_slice_uid (0)); rss_item->putAndInsertString (DCM_SeriesInstanceUID, rsm_moving->get_ct_series_uid ()); /* fixed */ dataset->findOrCreateSequenceItem ( DCM_ReferencedSeriesSequence, rss_item, -2); rss_item->findOrCreateSequenceItem ( DCM_ReferencedInstanceSequence, ris_item, -2); ris_item->putAndInsertString (DCM_ReferencedSOPClassUID, UID_CTImageStorage); ris_item->putAndInsertString (DCM_ReferencedSOPInstanceUID, rsm_fixed->get_slice_uid (0)); rss_item->putAndInsertString (DCM_SeriesInstanceUID, rsm_fixed->get_ct_series_uid ()); /* SOP Common Module */ std::string sro_sop_instance_uid = dicom_uid (PLM_UID_PREFIX); dataset->putAndInsertString (DCM_SOPClassUID, UID_SpatialRegistrationStorage); dataset->putAndInsertString (DCM_SOPInstanceUID, sro_sop_instance_uid.c_str()); /* ----------------------------------------------------------------- * * Write the output file * ----------------------------------------------------------------- */ std::string sro_fn; if (filenames_with_uid) { sro_fn = string_format ("%s/sro_%s.dcm", dicom_dir.c_str(), sro_sop_instance_uid.c_str()); } else { sro_fn = string_format ("%s/sro.dcm", dicom_dir.c_str()); } make_parent_directories (sro_fn); lprintf ("Trying to save SRO: %s\n", sro_fn.c_str()); ofc = fileformat.saveFile (sro_fn.c_str(), EXS_LittleEndianExplicit); if (ofc.bad()) { print_and_exit ( "Error: cannot write DICOM Spatial Registration (%s) (%s)\n", sro_fn.c_str(), ofc.text()); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_sro.h000066400000000000000000000013011321604176500276620ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_sro_h_ #define _dcmtk_sro_h_ #include "plmbase_config.h" #include #include "rt_study_metadata.h" #include "xform.h" class Xform; class PLMBASE_API Dcmtk_sro { public: static void save ( const Xform::Pointer& xf, const Rt_study_metadata::Pointer& rsm_src, /* Fixed image */ const Rt_study_metadata::Pointer& rsm_reg, /* Moving image */ const std::string& dicom_dir, bool filenames_with_uid); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_uid.cxx000066400000000000000000000050671321604176500302300ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #if defined (_WIN32) #include #include #endif #include "dcmtk_config.h" #include "dcmtk/dcmdata/dcuid.h" #include "dcmtk/ofstd/ofstream.h" #include "dcmtk_uid.h" #if defined (_WIN32) static bool gen_random (unsigned char* buf, unsigned long buf_len) { HCRYPTPROV h_cryptprov = NULL; LPTSTR prov_name = NULL; DWORD prov_name_len; BOOL rc; rc = CryptGetDefaultProvider (PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT, NULL, &prov_name_len); if (!rc) { return false; } prov_name = (LPTSTR) LocalAlloc (LMEM_ZEROINIT, prov_name_len); if (!prov_name) { return false; } rc = CryptAcquireContext (&h_cryptprov, NULL, prov_name, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT); if (!rc) { LocalFree (prov_name); return false; } rc = CryptGenRandom (h_cryptprov, buf_len, buf); CryptReleaseContext (h_cryptprov, 0); LocalFree (prov_name); return ((bool) rc); } #else static bool gen_random (unsigned char* buf, unsigned long buf_len) { return false; } #endif /* Unfortunately, the dcmtk uid generator suffers from non-randomness on win32, because process id's are reused. For example, here is the output from win32 dicom_uid using the default generator: C:\gsharp\projects\plastimatch>dicom_uid & dicom_uid & dicom_uid 1.2.276.0.7230010.3.1.4.1599324740.2152.1240860622.1 1.2.276.0.7230010.3.1.4.1599324740.2680.1240860622.1 1.2.276.0.7230010.3.1.4.1599324740.2152.1240860622.1 This routine fixes this problem using the Win32 system cryptographic entropy source (above). */ char* dcmtk_uid (char *uid, const char *uid_root) { int i; unsigned char random_buf[100]; bool rc; int suppress_zeros = 1; dcmGenerateUniqueIdentifier (uid, uid_root); rc = gen_random (random_buf, 100); if (!rc) { return uid; } for (i = strlen (uid_root); i < 63; i++) { switch (uid[i]) { case '.': suppress_zeros = 1; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (suppress_zeros) { uid[i] = '1' + ((((long) uid[i]) + random_buf[i] - '0') % 9); } else { uid[i] = '0' + ((((long) uid[i]) + random_buf[i] - '0') % 10); } suppress_zeros = 0; break; } } return uid; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_uid.h000066400000000000000000000005711321604176500276500ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __dcmtk_uid_h__ #define __dcmtk_uid_h__ #include "plmbase_config.h" PLMBASE_API char* dcmtk_uid (char *uid, const char *uid_root); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_util.cxx000066400000000000000000000027741321604176500304260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "dcmtk_config.h" #include "dcmtk/dcmdata/dctk.h" #include "dcmtk_util.h" #include "print_and_exit.h" #include "string_util.h" void dcmtk_get_date_time ( std::string *current_date, std::string *current_time ) { OFString date_string; OFString time_string; DcmDate::getCurrentDate (date_string); DcmTime::getCurrentTime (time_string); *current_date = date_string.c_str(); *current_time = time_string.c_str(); //*date = "20110101"; //*time = "120000"; } template OFCondition dcmtk_put (DcmItem* item, const DcmTag &tag, T t) { std::string s; s = PLM_to_string (t); return item->putAndInsertString (tag, s.c_str()); } OFCondition dcmtk_put (DcmItem* item, const DcmTag &tag, const std::string& s) { return item->putAndInsertString (tag, s.c_str()); } OFCondition dcmtk_put (DcmItem* item, const DcmTag &tag, const char* s) { return item->putAndInsertString (tag, s); } template PLMBASE_API OFCondition dcmtk_put (DcmItem*, const DcmTag &, int); template PLMBASE_API OFCondition dcmtk_put (DcmItem*, const DcmTag &, size_t); template PLMBASE_API OFCondition dcmtk_put (DcmItem*, const DcmTag &, float); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dcmtk_util.h000066400000000000000000000013431321604176500300420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcmtk_util_h_ #define _dcmtk_util_h_ #include "plmbase_config.h" #include "dcmtk/dcmdata/dcitem.h" #include "dcmtk/dcmdata/dctag.h" #include "dcmtk/ofstd/ofcond.h" PLMBASE_API void dcmtk_get_date_time ( std::string *date, std::string *time ); template PLMBASE_API OFCondition dcmtk_put (DcmItem*, const DcmTag &, T); PLMBASE_API OFCondition dcmtk_put (DcmItem*, const DcmTag &, const std::string&); PLMBASE_API OFCondition dcmtk_put (DcmItem*, const DcmTag &, const char*); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dicom.dic000066400000000000000000007673351321604176500273320ustar00rootroot00000000000000# # Copyright (C) 1994-2005, OFFIS # # This software and supporting documentation were developed by # # Kuratorium OFFIS e.V. # Healthcare Information and Communication Systems # Escherweg 2 # D-26121 Oldenburg, Germany # # THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY # REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR # FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR # ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND # PERFORMANCE OF THE SOFTWARE IS WITH THE USER. # # Module: dcmdata # # Author: Andrew Hewett, Marco Eichelberg # # Purpose: # This is the global DICOM data dictionary for the dcmtk class library. # # Last Update: $Author: meichel $ # Update Date: $Date: 2005/11/15 16:59:25 $ # Source File: $Source: /share/dicom/cvs-depot/dcmtk/dcmdata/libsrc/dicom.dic,v $ # CVS/RCS Revision: $Revision: 1.55 $ # Status: $State: Exp $ # # This dictionary contains # - the complete dictionary from the 2004 DICOM publication # - all final text supplements and CPs as of the last CVS commit date # This includes: # supplements 1-42 (except 16, 21 and 34 which are cancelled), # 44-55 (46 is cancelled), 57-62, 64-73, 75-77, 79-94 # (81 is cancelled), 97, 99-101 and 103-105 as well as the # CP packages 1-33 (final text) # # Each line represents an entry in the data dictionary. Each line # has 5 fields (Tag, VR, Name, VM, Version). Entries need not be # in ascending tag order. # # Entries may override existing entries. # # Each field must be separated by a single tab. The tag values (gggg,eeee) # must be in hexedecimal and must be surrounded by parentheses. Repeating # groups are represented by indicating the range (gggg-gggg,eeee). By default # the repeating notation only represents even numbers. A range where only # odd numbers are valid is represented using the notation (gggg-o-gggg,eeee). # A range can represent both even and odd numbers using the notation # (gggg-u-gggg,eeee). The element part of the tag can also be a range. # # Comments have a '#' at the beginning of the line. # # Tag VR Name VM Version # (0000,0000) UL CommandGroupLength 1 dicom98 (0000,0002) UI AffectedSOPClassUID 1 dicom98 (0000,0003) UI RequestedSOPClassUID 1 dicom98 (0000,0100) US CommandField 1 dicom98 (0000,0110) US MessageID 1 dicom98 (0000,0120) US MessageIDBeingRespondedTo 1 dicom98 (0000,0600) AE MoveDestination 1 dicom98 (0000,0700) US Priority 1 dicom98 (0000,0800) US DataSetType 1 dicom98 (0000,0900) US Status 1 dicom98 (0000,0901) AT OffendingElement 1-n dicom98 (0000,0902) LO ErrorComment 1 dicom98 (0000,0903) US ErrorID 1 dicom98 (0000,1000) UI AffectedSOPInstanceUID 1 dicom98 (0000,1001) UI RequestedSOPInstanceUID 1 dicom98 (0000,1002) US EventTypeID 1 dicom98 (0000,1005) AT AttributeIdentifierList 1-n dicom98 (0000,1008) US ActionTypeID 1 dicom98 (0000,1020) US NumberOfRemainingSuboperations 1 dicom98 (0000,1021) US NumberOfCompletedSuboperations 1 dicom98 (0000,1022) US NumberOfFailedSuboperations 1 dicom98 (0000,1023) US NumberOfWarningSuboperations 1 dicom98 (0000,1030) AE MoveOriginatorApplicationEntityTitle 1 dicom98 (0000,1031) US MoveOriginatorMessageID 1 dicom98 (0002,0000) UL MetaElementGroupLength 1 dicom98 (0002,0001) OB FileMetaInformationVersion 1 dicom98 (0002,0002) UI MediaStorageSOPClassUID 1 dicom98 (0002,0003) UI MediaStorageSOPInstanceUID 1 dicom98 (0002,0010) UI TransferSyntaxUID 1 dicom98 (0002,0012) UI ImplementationClassUID 1 dicom98 (0002,0013) SH ImplementationVersionName 1 dicom98 (0002,0016) AE SourceApplicationEntityTitle 1 dicom98 (0002,0100) UI PrivateInformationCreatorUID 1 dicom98 (0002,0102) OB PrivateInformation 1 dicom98 (0004,0000) UL FileSetGroupLength 1 dicom98 (0004,1130) CS FileSetID 1 dicom98 (0004,1141) CS FileSetDescriptorFileID 1-8 dicom98 (0004,1142) CS SpecificCharacterSetOfFileSetDescriptorFile 1 dicom98 (0004,1200) up OffsetOfTheFirstDirectoryRecordOfTheRootDirectoryEntity 1 dicom98 (0004,1202) up OffsetOfTheLastDirectoryRecordOfTheRootDirectoryEntity 1 dicom98 (0004,1212) US FileSetConsistencyFlag 1 dicom98 (0004,1220) SQ DirectoryRecordSequence 1 dicom98 (0004,1400) up OffsetOfTheNextDirectoryRecord 1 dicom98 (0004,1410) US RecordInUseFlag 1 dicom98 (0004,1420) up OffsetOfReferencedLowerLevelDirectoryEntity 1 dicom98 (0004,1430) CS DirectoryRecordType 1 dicom98 (0004,1432) UI PrivateRecordUID 1 dicom98 (0004,1500) CS ReferencedFileID 1-8 dicom98 (0004,1504) up MRDRDirectoryRecordOffset 1 dicom98 (0004,1510) UI ReferencedSOPClassUIDInFile 1 dicom98 (0004,1511) UI ReferencedSOPInstanceUIDInFile 1 dicom98 (0004,1512) UI ReferencedTransferSyntaxUIDInFile 1 dicom98 (0004,151A) UI ReferencedRelatedGeneralSOPClassUIDInFile 1-n dicom2004 (0004,1600) UL NumberOfReferences 1 dicom98 (0008,0000) UL IdentifyingGroupLength 1 dicom98 # VM of (0008,0005) SpecificCharacterSet was 1 in DICOM93. Changed in DICOM96 (Supplement 9). (0008,0005) CS SpecificCharacterSet 1-n dicom98 (0008,0008) CS ImageType 1-n dicom98 (0008,0012) DA InstanceCreationDate 1 dicom98 (0008,0013) TM InstanceCreationTime 1 dicom98 (0008,0014) UI InstanceCreatorUID 1 dicom98 (0008,0016) UI SOPClassUID 1 dicom98 (0008,0018) UI SOPInstanceUID 1 dicom98 (0008,001A) UI RelatedGeneralSOPClassUID 1-n dicom2004 (0008,001B) UI OriginalSpecializedSOPClassUID 1 dicom2004 (0008,0020) DA StudyDate 1 dicom98 (0008,0021) DA SeriesDate 1 dicom98 (0008,0022) DA AcquisitionDate 1 dicom98 # (0008,0023) ContentDate was named ImageDate before. Changed in dicom2000 (Supplement 30). (0008,0023) DA ContentDate 1 dicom2000 (0008,0024) DA OverlayDate 1 dicom98 (0008,0025) DA CurveDate 1 dicom98 (0008,002A) DT AcquisitionDatetime 1 dicom2000 (0008,0030) TM StudyTime 1 dicom98 (0008,0031) TM SeriesTime 1 dicom98 (0008,0032) TM AcquisitionTime 1 dicom98 # (0008,0033) ContentTime was named ImageTime before. Changed in dicom2000 (Supplement 30). (0008,0033) TM ContentTime 1 dicom2000 (0008,0034) TM OverlayTime 1 dicom98 (0008,0035) TM CurveTime 1 dicom98 (0008,0050) SH AccessionNumber 1 dicom98 (0008,0052) CS QueryRetrieveLevel 1 dicom98 (0008,0054) AE RetrieveAETitle 1-n dicom98 (0008,0056) CS InstanceAvailability 1 dicom2000 (0008,0058) UI FailedSOPInstanceUIDList 1-n dicom98 (0008,0060) CS Modality 1 dicom98 (0008,0061) CS ModalitiesInStudy 1-n dicom98 (0008,0062) UI SOPClassesInStudy 1-n dicom2004 (0008,0064) CS ConversionType 1 dicom98 (0008,0068) CS PresentationIntentType 1 dicom99 (0008,0070) LO Manufacturer 1 dicom98 (0008,0080) LO InstitutionName 1 dicom98 (0008,0081) ST InstitutionAddress 1 dicom98 (0008,0082) SQ InstitutionCodeSequence 1 dicom98 (0008,0090) PN ReferringPhysiciansName 1 dicom98 (0008,0092) ST ReferringPhysiciansAddress 1 dicom98 (0008,0094) SH ReferringPhysiciansTelephoneNumbers 1-n dicom98 (0008,0096) SQ ReferringPhysicianIdentificationSequence 1 dicom2003 (0008,0100) SH CodeValue 1 dicom98 (0008,0102) SH CodingSchemeDesignator 1 dicom98 (0008,0103) SH CodingSchemeVersion 1 dicom99 (0008,0104) LO CodeMeaning 1 dicom98 (0008,0105) CS MappingResource 1 dicom99 (0008,0106) DT ContextGroupVersion 1 dicom99 (0008,0107) DT ContextGroupLocalVersion 1 dicom99 (0008,010B) CS CodeSetExtensionFlag 1 dicom99 # (0008,010C) CodingSchemeUID was named PrivateCodingSchemeCreatorUID before. Changed in dicom2002. (0008,010C) UI CodingSchemeUID 1 dicom99 (0008,010D) UI CodeSetExtensionCreatorUID 1 dicom99 (0008,010F) CS ContextIdentifier 1 dicom99 (0008,0110) SQ CodingSchemeIdentificationSequence 1 dicom2003 (0008,0112) LO CodingSchemeRegistry 1 dicom2003 (0008,0114) ST CodingSchemeExternalID 1 dicom2003 (0008,0115) ST CodingSchemeName 1 dicom2003 (0008,0116) ST ResponsibleOrganization 1 dicom2003 (0008,0201) SH TimezoneOffsetFromUTC 1 dicom2000 (0008,1010) SH StationName 1 dicom98 (0008,1030) LO StudyDescription 1 dicom98 (0008,1032) SQ ProcedureCodeSequence 1 dicom98 (0008,103E) LO SeriesDescription 1 dicom98 (0008,1040) LO InstitutionalDepartmentName 1 dicom98 (0008,1048) PN PhysiciansOfRecord 1-n dicom98 (0008,1049) SQ PhysiciansOfRecordIdentificationSequence 1 dicom2003 (0008,1050) PN PerformingPhysiciansName 1-n dicom98 (0008,1052) SQ PerformingPhysicianIdentificationSequence 1 dicom2003 (0008,1060) PN NameOfPhysiciansReadingStudy 1-n dicom98 (0008,1062) SQ PhysiciansReadingStudyIdentificationSequence 1 dicom2003 (0008,1070) PN OperatorsName 1-n dicom98 (0008,1072) SQ OperatorIdentificationSequence 1 dicom2003 (0008,1080) LO AdmittingDiagnosesDescription 1-n dicom98 # Renamed in CP 239, name was AdmittingDiagnosisCodeSequence before (0008,1084) SQ AdmittingDiagnosesCodeSequence 1 dicom2001 (0008,1090) LO ManufacturersModelName 1 dicom98 (0008,1100) SQ ReferencedResultsSequence 1 dicom98 (0008,1110) SQ ReferencedStudySequence 1 dicom98 # Name of (0008,1111) was ReferencedStudyComponentSequence. Renamed in CP 257. (0008,1111) SQ ReferencedPerformedProcedureStepSequence 1 dicom2003 (0008,1115) SQ ReferencedSeriesSequence 1 dicom98 (0008,1120) SQ ReferencedPatientSequence 1 dicom98 (0008,1125) SQ ReferencedVisitSequence 1 dicom98 (0008,1130) SQ ReferencedOverlaySequence 1 dicom98 (0008,113A) SQ ReferencedWaveformSequence 1 dicom2001 (0008,1140) SQ ReferencedImageSequence 1 dicom98 (0008,1145) SQ ReferencedCurveSequence 1 dicom98 (0008,114A) SQ ReferencedInstanceSequence 1 dicom2001 (0008,114B) SQ ReferencedRealWorldValueMappingInstanceSequence 1 dicom2005 (0008,1150) UI ReferencedSOPClassUID 1 dicom98 (0008,1155) UI ReferencedSOPInstanceUID 1 dicom98 (0008,115A) UI SOPClassesSupported 1-n dicom99 # VM of (0008,1160) ReferencedFrameNumber was 1 in dicom98. Changed in dicom2000 (Supplement 33). (0008,1160) IS ReferencedFrameNumber 1-n dicom2000 (0008,1195) UI TransactionUID 1 dicom98 (0008,1197) US FailureReason 1 dicom98 (0008,1198) SQ FailedSOPSequence 1 dicom98 (0008,1199) SQ ReferencedSOPSequence 1 dicom98 (0008,1200) SQ StudiesContainingOtherReferencedInstancesSequence 1 dicom2004 (0008,1250) SQ RelatedSeriesSequence 1 dicom2004 (0008,2111) ST DerivationDescription 1 dicom98 (0008,2112) SQ SourceImageSequence 1 dicom98 (0008,2120) SH StageName 1 dicom98 (0008,2122) IS StageNumber 1 dicom98 (0008,2124) IS NumberOfStages 1 dicom98 (0008,2127) SH ViewName 1 dicom2001 (0008,2128) IS ViewNumber 1 dicom98 (0008,2129) IS NumberOfEventTimers 1 dicom98 (0008,212A) IS NumberOfViewsInStage 1 dicom98 (0008,2130) DS EventElapsedTimes 1-n dicom98 (0008,2132) LO EventTimerNames 1-n dicom98 (0008,2142) IS StartTrim 1 dicom98 (0008,2143) IS StopTrim 1 dicom98 (0008,2144) IS RecommendedDisplayFrameRate 1 dicom98 (0008,2218) SQ AnatomicRegionSequence 1 dicom98 (0008,2220) SQ AnatomicRegionModifierSequence 1 dicom98 (0008,2228) SQ PrimaryAnatomicStructureSequence 1 dicom98 (0008,2229) SQ AnatomicStructureSpaceOrRegionSequence 1 dicom98 (0008,2230) SQ PrimaryAnatomicStructureModifierSequence 1 dicom98 (0008,2240) SQ TransducerPositionSequence 1 dicom98 (0008,2242) SQ TransducerPositionModifierSequence 1 dicom98 (0008,2244) SQ TransducerOrientationSequence 1 dicom98 (0008,2246) SQ TransducerOrientationModifierSequence 1 dicom98 (0008,3001) SQ AlternateRepresentationSequence 1 dicom2004 (0008,3010) UI IrradiationEventUID 1 dicom2005 (0008,9007) CS FrameType 4 dicom2003 (0008,9092) SQ ReferencedImageEvidenceSequence 1 dicom2003 (0008,9121) SQ ReferencedRawDataSequence 1 dicom2003 (0008,9123) UI CreatorVersionUID 1 dicom2003 (0008,9124) SQ DerivationImageSequence 1 dicom2003 (0008,9154) SQ SourceImageEvidenceSequence 1 dicom2003 (0008,9205) CS PixelPresentation 1 dicom2003 (0008,9206) CS VolumetricProperties 1 dicom2003 (0008,9207) CS VolumeBasedCalculationTechnique 1 dicom2003 (0008,9208) CS ComplexImageComponent 1 dicom2003 (0008,9209) CS AcquisitionContrast 1 dicom2003 (0008,9215) SQ DerivationCodeSequence 1 dicom2003 (0008,9237) SQ ReferencedGrayscalePresentationStateSequence 1 dicom2003 (0008,9410) SQ ReferencedOtherPlaneSequence 1 dicom2005 (0008,9458) SQ FrameDisplaySequence 1 dicom2005 (0008,9459) FL RecommendedDisplayFrameRateInFloat 1 dicom2005 (0008,9460) CS SkipFrameRangeFlag 1 dicom2005 (0010,0000) UL PatientGroupLength 1 dicom98 (0010,0010) PN PatientsName 1 dicom98 (0010,0020) LO PatientID 1 dicom98 (0010,0021) LO IssuerOfPatientID 1 dicom98 (0010,0030) DA PatientsBirthDate 1 dicom98 (0010,0032) TM PatientsBirthTime 1 dicom98 (0010,0040) CS PatientsSex 1 dicom98 (0010,0050) SQ PatientsInsurancePlanCodeSequence 1 dicom98 (0010,0101) SQ PatientsPrimaryLanguageCodeSequence 1 dicom2001 (0010,0102) SQ PatientsPrimaryLanguageCodeModifierSequence 1 dicom2001 (0010,1000) LO OtherPatientIDs 1-n dicom98 (0010,1001) PN OtherPatientNames 1-n dicom98 (0010,1005) PN PatientsBirthName 1 dicom98 (0010,1010) AS PatientsAge 1 dicom98 (0010,1020) DS PatientsSize 1 dicom98 (0010,1030) DS PatientsWeight 1 dicom98 (0010,1040) LO PatientsAddress 1 dicom98 (0010,1060) PN PatientsMothersBirthName 1 dicom98 (0010,1080) LO MilitaryRank 1 dicom98 (0010,1081) LO BranchOfService 1 dicom98 (0010,1090) LO MedicalRecordLocator 1 dicom98 (0010,2000) LO MedicalAlerts 1-n dicom98 (0010,2110) LO ContrastAllergies 1-n dicom98 (0010,2150) LO CountryOfResidence 1 dicom98 (0010,2152) LO RegionOfResidence 1 dicom98 (0010,2154) SH PatientsTelephoneNumbers 1-n dicom98 (0010,2160) SH EthnicGroup 1 dicom98 (0010,2180) SH Occupation 1 dicom98 (0010,21A0) CS SmokingStatus 1 dicom98 (0010,21B0) LT AdditionalPatientHistory 1 dicom98 (0010,21C0) US PregnancyStatus 1 dicom98 (0010,21D0) DA LastMenstrualDate 1 dicom98 (0010,21F0) LO PatientsReligiousPreference 1 dicom98 (0010,4000) LT PatientComments 1 dicom98 (0010,9431) FL ExaminedBodyThickness 1 dicom2005 (0012,0000) UL ClinicalTrialGroupLength 1 dicom2005 (0012,0010) LO ClinicalTrialSponsorName 1 dicom2003 (0012,0020) LO ClinicalTrialProtocolID 1 dicom2003 (0012,0021) LO ClinicalTrialProtocolName 1 dicom2003 (0012,0030) LO ClinicalTrialSiteID 1 dicom2003 (0012,0031) LO ClinicalTrialSiteName 1 dicom2003 (0012,0040) LO ClinicalTrialSubjectID 1 dicom2003 (0012,0042) LO ClinicalTrialSubjectReadingID 1 dicom2003 (0012,0050) LO ClinicalTrialTimePointID 1 dicom2003 (0012,0051) ST ClinicalTrialTimePointDescription 1 dicom2003 (0012,0060) LO ClinicalTrialCoordinatingCenterName 1 dicom2003 (0012,0062) CS PatientIdentifyRemoved 1 dicom2005 (0012,0063) LO DeIdentificationMethod 1-n dicom2005 (0012,0064) SQ DeIdentificationMethodCodeSequence 1 dicom2005 (0018,0000) UL AcquisitionGroupLength 1 dicom98 (0018,0010) LO ContrastBolusAgent 1 dicom98 (0018,0012) SQ ContrastBolusAgentSequence 1 dicom98 (0018,0014) SQ ContrastBolusAdministrationRouteSequence 1 dicom98 (0018,0015) CS BodyPartExamined 1 dicom98 (0018,0020) CS ScanningSequence 1-n dicom98 (0018,0021) CS SequenceVariant 1-n dicom98 (0018,0022) CS ScanOptions 1-n dicom98 (0018,0023) CS MRAcquisitionType 1 dicom98 (0018,0024) SH SequenceName 1 dicom98 (0018,0025) CS AngioFlag 1 dicom98 (0018,0026) SQ InterventionDrugInformationSequence 1 dicom98 (0018,0027) TM InterventionDrugStopTime 1 dicom98 (0018,0028) DS InterventionDrugDose 1 dicom98 (0018,0029) SQ InterventionDrugCodeSequence 1 dicom98 (0018,002A) SQ AdditionalDrugSequence 1 dicom98 # VM of (0018,0031) Radiopharmaceutical was 1-n in DICOM93. Changed in DICOM96 (Supplement 7). (0018,0031) LO Radiopharmaceutical 1 dicom98 (0018,0034) LO InterventionDrugName 1 dicom98 (0018,0035) TM InterventionDrugStartTime 1 dicom98 # was InterventionalTherapySequence prior to CP 159 (0018,0036) SQ InterventionSequence 1 dicom2004 (0018,0038) CS InterventionalStatus 1 dicom98 (0018,003A) ST InterventionDescription 1 dicom2004 (0018,0040) IS CineRate 1 dicom98 (0018,0050) DS SliceThickness 1 dicom98 (0018,0060) DS KVP 1 dicom98 (0018,0070) IS CountsAccumulated 1 dicom98 (0018,0071) CS AcquisitionTerminationCondition 1 dicom98 # was named EffectiveSeriesDuration prior to CP 316 (DICOM 2003) (0018,0072) DS EffectiveDuration 1 dicom98 (0018,0073) CS AcquisitionStartCondition 1 dicom98 (0018,0074) IS AcquisitionStartConditionData 1 dicom98 (0018,0075) IS AcquisitionTerminationConditionData 1 dicom98 (0018,0080) DS RepetitionTime 1 dicom98 (0018,0081) DS EchoTime 1 dicom98 (0018,0082) DS InversionTime 1 dicom98 (0018,0083) DS NumberOfAverages 1 dicom98 (0018,0084) DS ImagingFrequency 1 dicom98 (0018,0085) SH ImagedNucleus 1 dicom98 (0018,0086) IS EchoNumbers 1-n dicom98 (0018,0087) DS MagneticFieldStrength 1 dicom98 (0018,0088) DS SpacingBetweenSlices 1 dicom98 (0018,0089) IS NumberOfPhaseEncodingSteps 1 dicom98 (0018,0090) DS DataCollectionDiameter 1 dicom98 (0018,0091) IS EchoTrainLength 1 dicom98 (0018,0093) DS PercentSampling 1 dicom98 (0018,0094) DS PercentPhaseFieldOfView 1 dicom98 (0018,0095) DS PixelBandwidth 1 dicom98 (0018,1000) LO DeviceSerialNumber 1 dicom98 (0018,1002) UI DeviceUID 1 dicom2005 (0018,1004) LO PlateID 1 dicom98 (0018,1010) LO SecondaryCaptureDeviceID 1 dicom98 (0018,1011) LO HardcopyCreationDeviceID 1 dicom98 (0018,1012) DA DateOfSecondaryCapture 1 dicom98 (0018,1014) TM TimeOfSecondaryCapture 1 dicom98 (0018,1016) LO SecondaryCaptureDeviceManufacturer 1 dicom98 (0018,1017) LO HardcopyDeviceManufacturer 1 dicom98 (0018,1018) LO SecondaryCaptureDeviceManufacturersModelName 1 dicom98 (0018,1019) LO SecondaryCaptureDeviceSoftwareVersions 1-n dicom98 (0018,101A) LO HardcopyDeviceSoftwareVersion 1-n dicom98 (0018,101B) LO HardcopyDeviceManufacturersModelName 1 dicom98 (0018,1020) LO SoftwareVersions 1-n dicom98 (0018,1022) SH VideoImageFormatAcquired 1 dicom98 (0018,1023) LO DigitalImageFormatAcquired 1 dicom98 (0018,1030) LO ProtocolName 1 dicom98 (0018,1040) LO ContrastBolusRoute 1 dicom98 (0018,1041) DS ContrastBolusVolume 1 dicom98 (0018,1042) TM ContrastBolusStartTime 1 dicom98 (0018,1043) TM ContrastBolusStopTime 1 dicom98 (0018,1044) DS ContrastBolusTotalDose 1 dicom98 # VM of (0018,1045) SyringeCounts was 1-n in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1045) IS SyringeCounts 1 dicom98 # name for (0018,1046) was ContrastFlowRates, changed in DICOM 2004 (0018,1046) DS ContrastFlowRate 1-n dicom2004 # name for (0018,1047) was ContrastFlowDurations, changed in DICOM 2004 (0018,1047) DS ContrastFlowDuration 1-n dicom2004 (0018,1048) CS ContrastBolusIngredient 1 dicom98 (0018,1049) DS ContrastBolusIngredientConcentration 1 dicom98 (0018,1050) DS SpatialResolution 1 dicom98 (0018,1060) DS TriggerTime 1 dicom98 (0018,1061) LO TriggerSourceOrType 1 dicom98 (0018,1062) IS NominalInterval 1 dicom98 (0018,1063) DS FrameTime 1 dicom98 (0018,1064) LO FramingType 1 dicom98 (0018,1065) DS FrameTimeVector 1-n dicom98 (0018,1066) DS FrameDelay 1 dicom98 (0018,1067) DS ImageTriggerDelay 1 dicom2000 (0018,1068) DS MultiplexGroupTimeOffset 1 dicom2000 (0018,1069) DS TriggerTimeOffset 1 dicom2000 (0018,106A) CS SynchronizationTrigger 1 dicom2000 (0018,106C) US SynchronizationChannel 2 dicom2000 (0018,106E) UL TriggerSamplePosition 1 dicom2000 # (0018,1070) RadiopharmaceuticalRoute was named RadionucleideRoute VM=1-n in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1070) LO RadiopharmaceuticalRoute 1 dicom98 # (0018,1071) RadiopharmaceuticalVolume was named RadionucleideVolume VM=1-n in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1071) DS RadiopharmaceuticalVolume 1 dicom98 # (0018,1072) RadiopharmaceuticalStartTime was named RadionucleideStartTime VM=1-n in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1072) TM RadiopharmaceuticalStartTime 1 dicom98 # (0018,1073) RadiopharmaceuticalStopTime was named RadionucleideStopTime VM=1-n in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1073) TM RadiopharmaceuticalStopTime 1 dicom98 # (0018,1074) RadionuclideTotalDose was VM=1-n in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1074) DS RadionuclideTotalDose 1 dicom98 (0018,1075) DS RadionuclideHalfLife 1 dicom98 (0018,1076) DS RadionuclidePositronFraction 1 dicom98 (0018,1077) DS RadiopharmaceuticalSpecificActivity 1 dicom98 (0018,1078) DT RadiopharmaceuticalStartDatetime 1 dicom2005 (0018,1079) DT RadiopharmaceuticalStopDatetime 1 dicom2005 (0018,1080) CS BeatRejectionFlag 1 dicom98 (0018,1081) IS LowRRValue 1 dicom98 (0018,1082) IS HighRRValue 1 dicom98 (0018,1083) IS IntervalsAcquired 1 dicom98 (0018,1084) IS IntervalsRejected 1 dicom98 (0018,1085) LO PVCRejection 1 dicom98 (0018,1086) IS SkipBeats 1 dicom98 (0018,1088) IS HeartRate 1 dicom98 (0018,1090) IS CardiacNumberOfImages 1 dicom98 (0018,1094) IS TriggerWindow 1 dicom98 (0018,1100) DS ReconstructionDiameter 1 dicom98 (0018,1110) DS DistanceSourceToDetector 1 dicom98 (0018,1111) DS DistanceSourceToPatient 1 dicom98 (0018,1114) DS EstimatedRadiographicMagnificationFactor 1 dicom98 (0018,1120) DS GantryDetectorTilt 1 dicom98 (0018,1121) DS GantryDetectorSlew 1 dicom98 (0018,1130) DS TableHeight 1 dicom98 (0018,1131) DS TableTraverse 1 dicom98 (0018,1134) CS TableMotion 1 dicom98 (0018,1135) DS TableVerticalIncrement 1-n dicom98 (0018,1136) DS TableLateralIncrement 1-n dicom98 (0018,1137) DS TableLongitudinalIncrement 1-n dicom98 (0018,1138) DS TableAngle 1 dicom98 (0018,113A) CS TableType 1 dicom99 (0018,1140) CS RotationDirection 1 dicom98 (0018,1141) DS AngularPosition 1 dicom98 (0018,1142) DS RadialPosition 1-n dicom98 (0018,1143) DS ScanArc 1 dicom98 (0018,1144) DS AngularStep 1 dicom98 (0018,1145) DS CenterOfRotationOffset 1 dicom98 (0018,1147) CS FieldOfViewShape 1 dicom98 (0018,1149) IS FieldOfViewDimensions 1-2 dicom98 (0018,1150) IS ExposureTime 1 dicom98 (0018,1151) IS XRayTubeCurrent 1 dicom98 (0018,1152) IS Exposure 1 dicom98 (0018,1153) IS ExposureInMicroAs 1 dicom98 (0018,1154) DS AveragePulseWidth 1 dicom98 (0018,1155) CS RadiationSetting 1 dicom98 (0018,1156) CS RectificationType 1 dicom99 (0018,115A) CS RadiationMode 1 dicom98 # Name was ImageAreaDoseProduct. Changed in DICOM 2005 (Supplement 83). (0018,115E) DS ImageAndFluoroscopyAreaDoseProduct 1 dicom2005 (0018,1160) SH FilterType 1 dicom98 (0018,1161) LO TypeOfFilters 1-n dicom98 (0018,1162) DS IntensifierSize 1 dicom98 (0018,1164) DS ImagerPixelSpacing 2 dicom98 # VM changed in CP 228, was 1 before (0018,1166) CS Grid 1-n dicom2001 (0018,1170) IS GeneratorPower 1 dicom98 (0018,1180) SH CollimatorGridName 1 dicom98 (0018,1181) CS CollimatorType 1 dicom98 # VM for (0018,1182) FocalDistance was 1 in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1182) IS FocalDistance 1-2 dicom98 # VM for (0018,1183) XFocusCenter was 1 in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1183) DS XFocusCenter 1-2 dicom98 # VM for (0018,1184) YFocusCenter was 1 in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1184) DS YFocusCenter 1-2 dicom98 (0018,1190) DS FocalSpots 1-n dicom98 (0018,1191) CS AnodeTargetMaterial 1 dicom99 (0018,11A0) DS BodyPartThickness 1 dicom99 (0018,11A2) DS CompressionForce 1 dicom99 (0018,1200) DA DateOfLastCalibration 1-n dicom98 (0018,1201) TM TimeOfLastCalibration 1-n dicom98 (0018,1210) SH ConvolutionKernel 1-n dicom98 (0018,1242) IS ActualFrameDuration 1 dicom98 (0018,1243) IS CountRate 1 dicom98 (0018,1244) US PreferredPlaybackSequencing 1 dicom98 # Name was ReceivingCoil, renamed in Supplement 49 (0018,1250) SH ReceiveCoilName 1 dicom2003 # Name was TransmittingCoil, renamed in Supplement 49 (0018,1251) SH TransmitCoilName 1 dicom2003 (0018,1260) SH PlateType 1 dicom98 (0018,1261) LO PhosphorType 1 dicom98 # VR for (0018,1300) ScanVelocity was IS in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1300) DS ScanVelocity 1 dicom98 (0018,1301) CS WholeBodyTechnique 1-n dicom98 (0018,1302) IS ScanLength 1 dicom98 (0018,1310) US AcquisitionMatrix 4 dicom98 (0018,1312) CS InPlanePhaseEncodingDirection 1 dicom98 (0018,1314) DS FlipAngle 1 dicom98 (0018,1315) CS VariableFlipAngleFlag 1 dicom98 (0018,1316) DS SAR 1 dicom98 (0018,1318) DS dBdt 1 dicom98 (0018,1400) LO AcquisitionDeviceProcessingDescription 1 dicom98 (0018,1401) LO AcquisitionDeviceProcessingCode 1 dicom98 (0018,1402) CS CassetteOrientation 1 dicom98 (0018,1403) CS CassetteSize 1 dicom98 (0018,1404) US ExposuresOnPlate 1 dicom98 (0018,1405) IS RelativeXRayExposure 1 dicom98 # VR of ColumnAngulation was CS in DICOM98. Changed in CP 279. (0018,1450) DS ColumnAngulation 1 dicom2003 (0018,1460) DS TomoLayerHeight 1 dicom98 (0018,1470) DS TomoAngle 1 dicom98 (0018,1480) DS TomoTime 1 dicom98 (0018,1490) CS TomoType 1 dicom99 (0018,1491) CS TomoClass 1 dicom99 (0018,1495) IS NumberOfTomosynthesisSourceImages 1 dicom99 (0018,1500) CS PositionerMotion 1 dicom98 (0018,1508) CS PositionerType 1 dicom99 (0018,1510) DS PositionerPrimaryAngle 1 dicom98 (0018,1511) DS PositionerSecondaryAngle 1 dicom98 (0018,1520) DS PositionerPrimaryAngleIncrement 1-n dicom98 (0018,1521) DS PositionerSecondaryAngleIncrement 1-n dicom98 (0018,1530) DS DetectorPrimaryAngle 1 dicom98 (0018,1531) DS DetectorSecondaryAngle 1 dicom98 # VM for (0018,1600) ShutterShape was 1 in DICOM93. Changed in DICOM96 (Supplement 7). (0018,1600) CS ShutterShape 1-3 dicom98 (0018,1602) IS ShutterLeftVerticalEdge 1 dicom98 (0018,1604) IS ShutterRightVerticalEdge 1 dicom98 (0018,1606) IS ShutterUpperHorizontalEdge 1 dicom98 (0018,1608) IS ShutterLowerHorizontalEdge 1 dicom98 (0018,1610) IS CenterOfCircularShutter 2 dicom98 (0018,1612) IS RadiusOfCircularShutter 1 dicom98 (0018,1620) IS VerticesOfThePolygonalShutter 2-2n dicom98 (0018,1622) US ShutterPresentationValue 1 dicom2000 (0018,1623) US ShutterOverlayGroup 1 dicom2000 (0018,1624) US ShutterPresentationColorCIELabValue 3 dicom2005 (0018,1700) CS CollimatorShape 1-3 dicom98 (0018,1702) IS CollimatorLeftVerticalEdge 1 dicom98 (0018,1704) IS CollimatorRightVerticalEdge 1 dicom98 (0018,1706) IS CollimatorUpperHorizontalEdge 1 dicom98 (0018,1708) IS CollimatorLowerHorizontalEdge 1 dicom98 (0018,1710) IS CenterOfCircularCollimator 2 dicom98 (0018,1712) IS RadiusOfCircularCollimator 1 dicom98 (0018,1720) IS VerticesOfThePolygonalCollimator 2-2n dicom98 (0018,1800) CS AcquisitionTimeSynchronized 1 dicom2000 (0018,1801) SH TimeSource 1 dicom2000 (0018,1802) CS TimeDistributionProtocol 1 dicom2000 (0018,1803) LO NTPSourceAddress 1 dicom2004 (0018,2001) IS PageNumberVector 1-n dicom2001 (0018,2002) SH FrameLabelVector 1-n dicom2001 (0018,2003) DS FramePrimaryAngleVector 1-n dicom2001 (0018,2004) DS FrameSecondaryAngleVector 1-n dicom2001 (0018,2005) DS SliceLocationVector 1-n dicom2001 (0018,2006) SH DisplayWindowLabelVector 1-n dicom2001 (0018,2010) DS NominalScannedPixelSpacing 2 dicom2001 (0018,2020) CS DigitizingDeviceTransportDirection 1 dicom2001 (0018,2030) DS RotationOfScannedFilm 1 dicom2001 (0018,3100) CS IVUSAcquisition 1 dicom2001 (0018,3101) DS IVUSPullbackRate 1 dicom2001 (0018,3102) DS IVUSGatedRate 1 dicom2001 (0018,3103) IS IVUSPullbackStartFrameNumber 1 dicom2001 (0018,3104) IS IVUSPullbackStopFrameNumber 1 dicom2001 (0018,3105) IS LesionNumber 1-n dicom2001 (0018,5000) SH OutputPower 1-n dicom98 (0018,5010) LO TransducerData 3 dicom98 (0018,5012) DS FocusDepth 1 dicom98 (0018,5020) LO ProcessingFunction 1 dicom98 (0018,5021) LO PostprocessingFunction 1 dicom98 (0018,5022) DS MechanicalIndex 1 dicom98 # was ThermalIndex, renamed in CP 320 (dicom2003) (0018,5024) DS BoneThermalIndex 1 dicom98 (0018,5026) DS CranialThermalIndex 1 dicom98 (0018,5027) DS SoftTissueThermalIndex 1 dicom98 (0018,5028) DS SoftTissueFocusThermalIndex 1 dicom98 (0018,5029) DS SoftTissueSurfaceThermalIndex 1 dicom98 (0018,5050) IS DepthOfScanField 1 dicom98 (0018,5100) CS PatientPosition 1 dicom98 (0018,5101) CS ViewPosition 1 dicom98 (0018,5104) SQ ProjectionEponymousNameCodeSequence 1 dicom99 (0018,6000) DS Sensitivity 1 dicom98 (0018,6011) SQ SequenceOfUltrasoundRegions 1 dicom98 (0018,6012) US RegionSpatialFormat 1 dicom98 (0018,6014) US RegionDataType 1 dicom98 (0018,6016) UL RegionFlags 1 dicom98 (0018,6018) UL RegionLocationMinX0 1 dicom98 (0018,601A) UL RegionLocationMinY0 1 dicom98 (0018,601C) UL RegionLocationMaxX1 1 dicom98 (0018,601E) UL RegionLocationMaxY1 1 dicom98 (0018,6020) SL ReferencePixelX0 1 dicom98 (0018,6022) SL ReferencePixelY0 1 dicom98 (0018,6024) US PhysicalUnitsXDirection 1 dicom98 (0018,6026) US PhysicalUnitsYDirection 1 dicom98 (0018,6028) FD ReferencePixelPhysicalValueX 1 dicom98 (0018,602A) FD ReferencePixelPhysicalValueY 1 dicom98 (0018,602C) FD PhysicalDeltaX 1 dicom98 (0018,602E) FD PhysicalDeltaY 1 dicom98 (0018,6030) UL TransducerFrequency 1 dicom98 (0018,6031) CS TransducerType 1 dicom98 (0018,6032) UL PulseRepetitionFrequency 1 dicom98 (0018,6034) FD DopplerCorrectionAngle 1 dicom98 (0018,6036) FD SteeringAngle 1 dicom98 (0018,6039) SL DopplerSampleVolumeXPosition 1 dicom2003 (0018,603B) SL DopplerSampleVolumeYPosition 1 dicom2003 (0018,603D) SL TMLinePositionX0 1 dicom2003 (0018,603F) SL TMLinePositionY0 1 dicom2003 (0018,6041) SL TMLinePositionX1 1 dicom2003 (0018,6043) SL TMLinePositionY1 1 dicom2003 (0018,6044) US PixelComponentOrganization 1 dicom98 (0018,6046) UL PixelComponentMask 1 dicom98 (0018,6048) UL PixelComponentRangeStart 1 dicom98 (0018,604A) UL PixelComponentRangeStop 1 dicom98 (0018,604C) US PixelComponentPhysicalUnits 1 dicom98 (0018,604E) US PixelComponentDataType 1 dicom98 (0018,6050) UL NumberOfTableBreakPoints 1 dicom98 (0018,6052) UL TableOfXBreakPoints 1-n dicom98 (0018,6054) FD TableOfYBreakPoints 1-n dicom98 (0018,6056) UL NumberOfTableEntries 1 dicom98 (0018,6058) UL TableOfPixelValues 1-n dicom98 (0018,605A) FL TableOfParameterValues 1-n dicom98 (0018,6060) FL RWaveTimeVector 1-n dicom2004 (0018,7000) CS DetectorConditionsNominalFlag 1 dicom99 (0018,7001) DS DetectorTemperature 1 dicom99 (0018,7004) CS DetectorType 1 dicom99 (0018,7005) CS DetectorConfiguration 1 dicom99 (0018,7006) LT DetectorDescription 1 dicom99 (0018,7008) LT DetectorMode 1 dicom99 (0018,700A) SH DetectorID 1 dicom99 (0018,700C) DA DateOfLastDetectorCalibration 1 dicom99 (0018,700E) TM TimeOfLastDetectorCalibration 1 dicom99 (0018,7010) IS ExposuresOnDetectorSinceLastCalibration 1 dicom99 (0018,7011) IS ExposuresOnDetectorSinceManufactured 1 dicom99 (0018,7012) DS DetectorTimeSinceLastExposure 1 dicom99 (0018,7014) DS DetectorActiveTime 1 dicom99 (0018,7016) DS DetectorActivationOffsetFromExposure 1 dicom99 (0018,701A) DS DetectorBinning 2 dicom99 (0018,7020) DS DetectorElementPhysicalSize 2 dicom99 (0018,7022) DS DetectorElementSpacing 2 dicom99 (0018,7024) CS DetectorActiveShape 1 dicom99 (0018,7026) DS DetectorActiveDimensions 1-2 dicom99 (0018,7028) DS DetectorActiveOrigin 2 dicom99 (0018,702A) LO DetectorManufacturerName 1 dicom2004 (0018,702B) LO DetectorManufacturersModelName 1 dicom2004 (0018,7030) DS FieldOfViewOrigin 2 dicom99 (0018,7032) DS FieldOfViewRotation 1 dicom99 (0018,7034) CS FieldOfViewHorizontalFlip 1 dicom99 (0018,7040) LT GridAbsorbingMaterial 1 dicom99 (0018,7041) LT GridSpacingMaterial 1 dicom99 (0018,7042) DS GridThickness 1 dicom99 (0018,7044) DS GridPitch 1 dicom99 (0018,7046) IS GridAspectRatio 2 dicom99 (0018,7048) DS GridPeriod 1 dicom99 (0018,704C) DS GridFocalDistance 1 dicom99 # VR of (0018,7050) FilterMaterial was LT 1-n (which is not possible) in dicom99. # Changed in dicom2000 (CP 187). (0018,7050) CS FilterMaterial 1-n dicom2000 (0018,7052) DS FilterThicknessMinimum 1-n dicom99 (0018,7054) DS FilterThicknessMaximum 1-n dicom99 (0018,7060) CS ExposureControlMode 1 dicom99 (0018,7062) LT ExposureControlModeDescription 1 dicom99 (0018,7064) CS ExposureStatus 1 dicom99 (0018,7065) DS PhototimerSetting 1 dicom99 (0018,8150) DS ExposureTimeInMicroS 1 dicom2000 (0018,8151) DS XRayTubeCurrentInMicroA 1 dicom2000 (0018,9004) CS ContentQualification 1 dicom2003 (0018,9005) SH PulseSequenceName 1 dicom2003 (0018,9006) SQ MRImagingModifierSequence 1 dicom2003 (0018,9008) CS EchoPulseSequence 1 dicom2003 (0018,9009) CS InversionRecovery 1 dicom2003 (0018,9010) CS FlowCompensation 1 dicom2003 (0018,9011) CS MultipleSpinEcho 1 dicom2003 (0018,9012) CS MultiPlanarExcitation 1 dicom2003 (0018,9014) CS PhaseContrast 1 dicom2003 (0018,9015) CS TimeOfFlightContrast 1 dicom2003 (0018,9016) CS Spoiling 1 dicom2003 (0018,9017) CS SteadyStatePulseSequence 1 dicom2003 (0018,9018) CS EchoPlanarPulseSequence 1 dicom2003 (0018,9019) FD TagAngleFirstAxis 1 dicom2003 (0018,9020) CS MagnetizationTransfer 1 dicom2003 (0018,9021) CS T2Preparation 1 dicom2003 (0018,9022) CS BloodSignalNulling 1 dicom2003 (0018,9024) CS SaturationRecovery 1 dicom2003 (0018,9025) CS SpectrallySelectedSuppression 1 dicom2003 (0018,9026) CS SpectrallySelectedExcitation 1 dicom2003 (0018,9027) CS SpatialPreSaturation 1 dicom2003 (0018,9028) CS Tagging 1 dicom2003 (0018,9029) CS OversamplingPhase 1 dicom2003 (0018,9030) FD TagSpacingFirstDimension 1 dicom2003 (0018,9032) CS GeometryOfKSpaceTraversal 1 dicom2003 (0018,9033) CS SegmentedKSpaceTraversal 1 dicom2003 (0018,9034) CS RectilinearPhaseEncodeReordering 1 dicom2003 (0018,9035) FD TagThickness 1 dicom2003 (0018,9036) CS PartialFourierDirection 1 dicom2003 (0018,9037) CS CardiacSynchronizationTechnique 1 dicom2003 (0018,9041) LO ReceiveCoilManufacturerName 1 dicom2003 (0018,9042) SQ MRReceiveCoilSequence 1 dicom2003 (0018,9043) CS ReceiveCoilType 1 dicom2003 (0018,9044) CS QuadratureReceiveCoil 1 dicom2003 (0018,9045) SQ MultiCoilDefinitionSequence 1 dicom2003 (0018,9046) LO MultiCoilConfiguration 1 dicom2003 (0018,9047) SH MultiCoilElementName 1 dicom2003 (0018,9048) CS MultiCoilElementUsed 1 dicom2003 (0018,9049) SQ MRTransmitCoilSequence 1 dicom2003 (0018,9050) LO TransmitCoilManufacturerName 1 dicom2003 (0018,9051) CS TransmitCoilType 1 dicom2003 (0018,9052) FD SpectralWidth 1-2 dicom2003 (0018,9053) FD ChemicalShiftReference 1-2 dicom2003 (0018,9054) CS VolumeLocalizationTechnique 1 dicom2003 (0018,9058) US MRAcquisitionFrequencyEncodingSteps 1 dicom2003 (0018,9059) CS Decoupling 1 dicom2003 (0018,9060) CS DecoupledNucleus 1-2 dicom2003 (0018,9061) FD DecouplingFrequency 1-2 dicom2003 (0018,9062) CS DecouplingMethod 1 dicom2003 (0018,9063) FD DecouplingChemicalShiftReference 1-2 dicom2003 (0018,9064) CS KSpaceFiltering 1 dicom2003 (0018,9065) CS TimeDomainFiltering 1-2 dicom2003 (0018,9066) US NumberOfZeroFills 1-2 dicom2003 (0018,9067) CS BaselineCorrection 1 dicom2003 (0018,9069) FD ParallelReductionFactorInPlane 1 dicom2003 (0018,9070) FD CardiacRRIntervalSpecified 1 dicom2003 (0018,9073) FD AcquisitionDuration 1 dicom2003 (0018,9074) DT FrameAcquisitionDatetime 1 dicom2003 (0018,9075) CS DiffusionDirectionality 1 dicom2003 (0018,9076) SQ DiffusionGradientDirectionSequence 1 dicom2003 (0018,9077) CS ParallelAcquisition 1 dicom2003 (0018,9078) CS ParallelAcquisitionTechnique 1 dicom2003 (0018,9079) FD InversionTimes 1-n dicom2003 (0018,9080) ST MetaboliteMapDescription 1 dicom2003 (0018,9081) CS PartialFourier 1 dicom2003 (0018,9082) FD EffectiveEchoTime 1 dicom2003 (0018,9083) SQ MetaboliteMapCodeSequence 1 dicom2004 (0018,9084) SQ ChemicalShiftSequence 1 dicom2003 (0018,9085) CS CardiacSignalSource 1 dicom2003 (0018,9087) FD DiffusionBValue 1 dicom2003 (0018,9089) FD DiffusionGradientOrientation 3 dicom2003 (0018,9090) FD VelocityEncodingDirection 3 dicom2003 (0018,9091) FD VelocityEncodingMinimumValue 1 dicom2003 (0018,9093) US NumberOfKSpaceTrajectories 1 dicom2003 (0018,9094) CS CoverageOfKSpace 1 dicom2003 (0018,9095) UL SpectroscopyAcquisitionPhaseRows 1 dicom2003 (0018,9098) FD TransmitterFrequency 1-2 dicom2003 (0018,9100) CS ResonantNucleus 1-2 dicom2003 (0018,9101) CS FrequencyCorrection 1 dicom2003 (0018,9103) SQ MRSpectroscopyFOVGeometrySequence 1 dicom2003 (0018,9104) FD SlabThickness 1 dicom2003 (0018,9105) FD SlabOrientation 3 dicom2003 (0018,9106) FD MidSlabPosition 3 dicom2003 (0018,9107) SQ MRSpatialSaturationSequence 1 dicom2003 (0018,9112) SQ MRTimingAndRelatedParametersSequence 1 dicom2003 (0018,9114) SQ MREchoSequence 1 dicom2003 (0018,9115) SQ MRModifierSequence 1 dicom2003 (0018,9117) SQ MRDiffusionSequence 1 dicom2003 (0018,9118) SQ CardiacTriggerSequence 1 dicom2003 (0018,9119) SQ MRAveragesSequence 1 dicom2003 (0018,9125) SQ MRFOVGeometrySequence 1 dicom2003 (0018,9126) SQ VolumeLocalizationSequence 1 dicom2003 (0018,9127) UL SpectroscopyAcquisitionDataColumns 1 dicom2003 (0018,9147) CS DiffusionAnisotropyType 1 dicom2003 (0018,9151) DT FrameReferenceDatetime 1 dicom2003 (0018,9152) SQ MRMetaboliteMapSequence 1 dicom2003 (0018,9155) FD ParallelReductionFactorOutOfPlane 1 dicom2003 (0018,9159) UL SpectroscopyAcquisitionOutOfPlanePhaseSteps 1 dicom2003 (0018,9166) CS BulkMotionStatus 1 dicom2003 (0018,9168) FD ParallelReductionFactorSecondInPlane 1 dicom2003 (0018,9169) CS CardiacBeatRejectionTechnique 1 dicom2003 (0018,9170) CS RespiratoryMotionCompensationTechnique 1 dicom2003 (0018,9171) CS RespiratorySignalSource 1 dicom2003 (0018,9172) CS BulkMotionCompensationTechnique 1 dicom2003 (0018,9173) CS BulkMotionSignalSource 1 dicom2003 (0018,9174) CS ApplicableSafetyStandardAgency 1 dicom2003 (0018,9175) LO ApplicableSafetyStandardDescription 1 dicom2003 (0018,9176) SQ OperatingModeSequence 1 dicom2003 (0018,9177) CS OperatingModeType 1 dicom2003 (0018,9178) CS OperationMode 1 dicom2003 (0018,9179) CS SpecificAbsorptionRateDefinition 1 dicom2003 (0018,9180) CS GradientOutputType 1 dicom2003 (0018,9181) FD SpecificAbsorptionRateValue 1 dicom2003 (0018,9182) FD GradientOutput 1 dicom2003 (0018,9183) CS FlowCompensationDirection 1 dicom2003 (0018,9184) FD TaggingDelay 1 dicom2003 (0018,9197) SQ MRVelocityEncodingSequence 1 dicom2003 (0018,9198) CS FirstOrderPhaseCorrection 1 dicom2003 (0018,9199) CS WaterReferencedPhaseCorrection 1 dicom2003 (0018,9200) CS MRSpectroscopyAcquisitionType 1 dicom2003 (0018,9214) CS RespiratoryCyclePosition 1 dicom2003 (0018,9217) FD VelocityEncodingMaximumValue 1 dicom2003 # VR changed from SS to FD in CP 379 (2004) (0018,9218) FD TagSpacingSecondDimension 1 dicom2004 (0018,9219) SS TagAngleSecondAxis 1 dicom2003 (0018,9220) FD FrameAcquisitionDuration 1 dicom2003 (0018,9226) SQ MRImageFrameTypeSequence 1 dicom2003 (0018,9227) SQ MRSpectroscopyFrameTypeSequence 1 dicom2003 (0018,9231) US MRAcquisitionPhaseEncodingStepsInPlane 1 dicom2003 (0018,9232) US MRAcquisitionPhaseEncodingStepsOutOfPlane 1 dicom2003 (0018,9234) UL SpectroscopyAcquisitionPhaseColumns 1 dicom2003 (0018,9236) CS CardiacCyclePosition 1 dicom2003 (0018,9239) SQ SpecificAbsorptionRateSequence 1 dicom2003 (0018,9240) US RFEchoTrainLength 1 dicom2004 (0018,9241) US GradientEchoTrainLength 1 dicom2004 (0018,9295) FD ChemicalShiftsMinimumIntegrationLimitInPpm 1 dicom2004 (0018,9296) FD ChemicalShiftsMaximumIntegrationLimitInPpm 1 dicom2004 (0018,9301) SQ CTAcquisitionTypeSequence 1 dicom2004 (0018,9302) CS AcquisitionType 1 dicom2004 (0018,9303) FD TubeAngle 1 dicom2004 (0018,9304) SQ CTAcquisitionDetailsSequence 1 dicom2004 (0018,9305) FD RevolutionTime 1 dicom2004 (0018,9306) FD SingleCollimationWidth 1 dicom2004 (0018,9307) FD TotalCollimationWidth 1 dicom2004 (0018,9308) SQ CTTableDynamicsSequence 1 dicom2004 (0018,9309) FD TableSpeed 1 dicom2004 (0018,9310) FD TableFeedPerRotation 1 dicom2004 (0018,9311) FD SpiralPitchFactor 1 dicom2004 (0018,9312) SQ CTGeometrySequence 1 dicom2004 (0018,9313) FD DataCollectionCenterPatient 3 dicom2004 (0018,9314) SQ CTReconstructionSequence 1 dicom2004 (0018,9315) CS ReconstructionAlgorithm 1 dicom2004 (0018,9316) CS ConvolutionKernelGroup 1 dicom2004 (0018,9317) FD ReconstructionFieldOfView 2 dicom2004 (0018,9318) FD ReconstructionTargetCenterPatient 3 dicom2004 (0018,9319) FD ReconstructionAngle 1 dicom2004 (0018,9320) SH ImageFilter 1 dicom2004 (0018,9321) SQ CTExposureSequence 1 dicom2004 (0018,9322) FD ReconstructionPixelSpacing 2 dicom2004 (0018,9323) CS ExposureModulationType 1 dicom2004 (0018,9324) FD EstimatedDoseSaving 1 dicom2004 (0018,9325) SQ CTXRayDetailsSequence 1 dicom2004 (0018,9326) SQ CTPositionSequence 1 dicom2004 (0018,9327) FD TablePosition 1 dicom2004 (0018,9328) FD ExposureTimeInms 1 dicom2004 (0018,9329) SQ CTImageFrameTypeSequence 1 dicom2004 (0018,9330) FD XRayTubeCurrentInmA 1 dicom2004 (0018,9332) FD ExposureInmAs 1 dicom2004 (0018,9333) CS ConstantVolumeFlag 1 dicom2004 (0018,9334) CS FluoroscopyFlag 1 dicom2004 (0018,9335) FD DistanceSourceToDataCollectionCenter 1 dicom2004 (0018,9337) US ContrastBolusAgentNumber 1 dicom2004 (0018,9338) SQ ContrastBolusIngredientCodeSequence 1 dicom2004 (0018,9340) SQ ContrastAdministrationProfileSequence 1 dicom2004 (0018,9341) SQ ContrastBolusUsageSequence 1 dicom2004 (0018,9342) CS ContrastBolusAgentAdministered 1 dicom2004 (0018,9343) CS ContrastBolusAgentDetected 1 dicom2004 (0018,9344) CS ContrastBolusAgentPhase 1 dicom2004 (0018,9345) FD CTDIvol 1 dicom2004 (0018,9401) SQ ProjectionPixelCalibrationSequence 1 dicom2005 (0018,9402) FL DistanceSourceToIsocenter 1 dicom2005 (0018,9403) FL DistanceObjectToTableTop 1 dicom2005 (0018,9404) FL ObjectPixelSpacingInCenterOfBeam 2 dicom2005 (0018,9405) SQ PositionerPositionSequence 1 dicom2005 (0018,9406) SQ TablePositionSequence 1 dicom2005 (0018,9407) SQ CollimatorShapeSequence 1 dicom2005 (0018,9412) SQ XA/XRFFrameCharacteristicsSequence 1 dicom2005 (0018,9420) CS XRayReceptorType 1 dicom2005 (0018,9423) LO AcquisitionProtocolName 1 dicom2005 (0018,9424) LT AcquisitionProtocolDescription 1 dicom2005 (0018,9425) CS Contrast/BolusIngredientOpaque 1 dicom2005 (0018,9426) FL DistanceReceptorPlaneToDetectorHousing 1 dicom2005 (0018,9427) CS IntensifierActiveShape 1 dicom2005 (0018,9428) FL IntensifierActiveDimension(s) 1-2 dicom2005 (0018,9429) FL PhysicalDetectorSize 2 dicom2005 (0018,9430) US PositionOfIsocenterProjection 2 dicom2005 (0018,9432) SQ FieldOfViewSequence 1 dicom2005 (0018,9433) LO FieldOfViewDescription 1 dicom2005 (0018,9434) SQ ExposureControlSensingRegionsSequence 1 dicom2005 (0018,9435) CS ExposureControlSensingRegionShape 1 dicom2005 (0018,9436) SS ExposureControlSensingRegionLeftVerticalEdge 1 dicom2005 (0018,9437) SS ExposureControlSensingRegionRightVerticalEdge 1 dicom2005 (0018,9438) SS ExposureControlSensingRegionUpperHorizontalEdge 1 dicom2005 (0018,9439) SS ExposureControlSensingRegionLowerHorizontalEdge 1 dicom2005 (0018,9440) SS CenterOfCircularExposureControlSensingRegion 2 dicom2005 (0018,9441) US RadiusOfCircularExposureControlSensingRegion 1 dicom2005 (0018,9442) SS VerticesOfThePolygonalExposureControlSensingRegion 2-n dicom2005 (0018,9447) FL ColumnAngulationPatient 1 dicom2005 (0018,9449) FL BeamAngle 1 dicom2005 (0018,9451) SQ FrameDetectorParametersSequence 1 dicom2005 (0018,9452) FL CalculatedAnatomyThickness 1 dicom2005 (0018,9455) SQ CalibrationSequence 1 dicom2005 (0018,9456) SQ ObjectThicknessSequence 1 dicom2005 (0018,9457) CS PlaneIdentification 1 dicom2005 (0018,9461) FL FieldOfViewDimensionsInFloat 1-2 dicom2005 (0018,9462) SQ IsocenterReferenceSystemSequence 1 dicom2005 (0018,9463) FL PositionerIsocenterPrimaryAngle 1 dicom2005 (0018,9464) FL PositionerIsocenterSecondaryAngle 1 dicom2005 (0018,9465) FL PositionerIsocenterDetectorRotationAngle 1 dicom2005 (0018,9466) FL TableXPositionToIsocenter 1 dicom2005 (0018,9467) FL TableYPositionToIsocenter 1 dicom2005 (0018,9468) FL TableZPositionToIsocenter 1 dicom2005 (0018,9469) FL TableHorizontalRotationAngle 1 dicom2005 (0018,9470) FL TableHeadTiltAngle 1 dicom2005 (0018,9471) FL TableCradleTiltAngle 1 dicom2005 (0018,9472) SQ FrameDisplayShutterSequence 1 dicom2005 (0018,9473) FL AcquiredImageAreaDoseProduct 1 dicom2005 (0018,9474) CS CArmPositionerTabletopRelationship 1 dicom2005 (0018,9476) SQ XRayGeometrySequence 1 dicom2005 (0018,9477) SQ IrradiationEventIdentificationSequence 1 dicom2005 (0018,A001) SQ ContributingEquipmentSequence 1 dicom2003 (0018,A002) DT ContributionDateTime 1 dicom2003 (0018,A003) ST ContributionDescription 1 dicom2003 (0020,0000) UL ImageGroupLength 1 dicom98 (0020,000D) UI StudyInstanceUID 1 dicom98 (0020,000E) UI SeriesInstanceUID 1 dicom98 (0020,0010) SH StudyID 1 dicom98 (0020,0011) IS SeriesNumber 1 dicom98 (0020,0012) IS AcquisitionNumber 1 dicom98 # InstanceNumber was named ImageNumber, renamed in CP 99 (09/1998) (0020,0013) IS InstanceNumber 1 dicom98 (0020,0019) IS ItemNumber 1 dicom99 (0020,0020) CS PatientOrientation 2 dicom98 (0020,0022) IS OverlayNumber 1 dicom98 (0020,0024) IS CurveNumber 1 dicom98 (0020,0026) IS LookupTableNumber 1 dicom98 (0020,0032) DS ImagePositionPatient 3 dicom98 (0020,0037) DS ImageOrientationPatient 6 dicom98 (0020,0052) UI FrameOfReferenceUID 1 dicom98 (0020,0060) CS Laterality 1 dicom98 (0020,0062) CS ImageLaterality 1 dicom99 (0020,0100) IS TemporalPositionIdentifier 1 dicom98 (0020,0105) IS NumberOfTemporalPositions 1 dicom98 (0020,0110) DS TemporalResolution 1 dicom98 (0020,0200) UI SynchronizationFrameOfReferenceUID 1 dicom2000 (0020,1000) IS SeriesInStudy 1 dicom98 (0020,1002) IS ImagesInAcquisition 1 dicom98 (0020,1004) IS AcquisitionsInStudy 1 dicom98 (0020,1040) LO PositionReferenceIndicator 1 dicom98 (0020,1041) DS SliceLocation 1 dicom98 (0020,1070) IS OtherStudyNumbers 1-n dicom98 (0020,1200) IS NumberOfPatientRelatedStudies 1 dicom98 (0020,1202) IS NumberOfPatientRelatedSeries 1 dicom98 # NumberOfPatientRelatedInstances was named NumberOfPatientRelatedImages, renamed in CP 99 (09/1998) (0020,1204) IS NumberOfPatientRelatedInstances 1 dicom98 (0020,1206) IS NumberOfStudyRelatedSeries 1 dicom98 # NumberOfStudyRelatedInstances was named NumberOfStudyRelatedImages, renamed in CP 99 (09/1998) (0020,1208) IS NumberOfStudyRelatedInstances 1 dicom98 # NumberOfSeriesRelatedInstances was named NumberOfSeriesRelatedImages, renamed in CP 99 (09/1998) (0020,1209) IS NumberOfSeriesRelatedInstances 1 dicom98 (0020,4000) LT ImageComments 1 dicom98 (0020,9056) SH StackID 1 dicom2003 (0020,9057) UL InStackPositionNumber 1 dicom2003 (0020,9071) SQ FrameAnatomySequence 1 dicom2003 (0020,9072) CS FrameLaterality 1 dicom2003 (0020,9111) SQ FrameContentSequence 1 dicom2003 (0020,9113) SQ PlanePositionSequence 1 dicom2003 (0020,9116) SQ PlaneOrientationSequence 1 dicom2003 (0020,9128) UL TemporalPositionIndex 1 dicom2003 (0020,9153) FD TriggerDelayTime 1 dicom2003 (0020,9156) US FrameAcquisitionNumber 1 dicom2003 (0020,9157) UL DimensionIndexValues 1-n dicom2003 (0020,9158) LT FrameComments 1 dicom2003 (0020,9161) UI ConcatenationUID 1 dicom2003 (0020,9162) US InConcatenationNumber 1 dicom2003 (0020,9163) US InConcatenationTotalNumber 1 dicom2003 (0020,9164) UI DimensionOrganizationUID 1 dicom2003 (0020,9165) AT DimensionIndexPointer 1 dicom2003 (0020,9167) AT FunctionalGroupPointer 1 dicom2003 (0020,9213) LO DimensionIndexPrivateCreator 1 dicom2003 (0020,9221) SQ DimensionOrganizationSequence 1 dicom2003 (0020,9222) SQ DimensionIndexSequence 1 dicom2003 (0020,9228) UL ConcatenationFrameOffsetNumber 1 dicom2003 (0020,9238) LO FunctionalGroupPrivateCreator 1 dicom2003 (0020,9421) LO DimensionDescriptionLabel 1 dicom2005 (0020,9450) SQ PatientOrientationInFrameSequence 1 dicom2005 (0020,9453) LO FrameLabel 1 dicom2005 (0022,0000) UL OphtalmologyGroupLength 1 dicom2004 (0022,0001) US LightPathFilterPass-ThroughWavelength 1 dicom2004 (0022,0002) US LightPathFilterPassBand 2 dicom2004 (0022,0003) US ImagePathFilterPass-ThroughWavelength 1 dicom2004 (0022,0004) US ImagePathFilterPassBand 2 dicom2004 (0022,0005) CS PatientEyeMovementCommanded 1 dicom2004 (0022,0006) SQ PatientEyeMovementCommandCodeSequence 1 dicom2004 (0022,0007) FL SphericalLensPower 1 dicom2004 (0022,0008) FL CylinderLensPower 1 dicom2004 (0022,0009) FL CylinderAxis 1 dicom2004 (0022,000A) FL EmmetropicMagnification 1 dicom2004 (0022,000B) FL IntraOcularPressure 1 dicom2004 (0022,000C) FL HorizontalFieldOfView 1 dicom2004 (0022,000D) CS PupilDilated 1 dicom2004 (0022,000E) FL DegreeOfDilation 1 dicom2004 (0022,0010) FL StereoBaselineAngle 1 dicom2004 (0022,0011) FL StereoBaselineDisplacement 1 dicom2004 (0022,0012) FL StereoHorizontalPixelOffset 1 dicom2004 (0022,0013) FL StereoVerticalPixelOffset 1 dicom2004 (0022,0014) FL StereoRotation 1 dicom2004 (0022,0015) SQ AcquisitionDeviceTypeCodeSequence 1 dicom2004 (0022,0016) SQ IlluminationTypeCodeSequence 1 dicom2004 (0022,0017) SQ LightPathFilterTypeStackCodeSequence 1 dicom2004 (0022,0018) SQ ImagePathFilterTypeStackCodeSequence 1 dicom2004 (0022,0019) SQ LensesCodeSequence 1 dicom2004 (0022,001A) SQ ChannelDescriptionCodeSequence 1 dicom2004 (0022,001B) SQ RefractiveStateSequence 1 dicom2004 (0022,001C) SQ MydriaticAgentCodeSequence 1 dicom2004 (0022,001D) SQ RelativeImagePositionCodeSequence 1 dicom2004 (0022,0020) SQ StereoPairsSequence 1 dicom2004 (0022,0021) SQ LeftImageSequence 1 dicom2004 (0022,0022) SQ RightImageSequence 1 dicom2004 (0028,0000) UL ImagePresentationGroupLength 1 dicom98 (0028,0002) US SamplesPerPixel 1 dicom98 (0028,0003) US SamplesPerPixelUsed 1 dicom2004 (0028,0004) CS PhotometricInterpretation 1 dicom98 (0028,0006) US PlanarConfiguration 1 dicom98 (0028,0008) IS NumberOfFrames 1 dicom98 # VM of (0028,0009) FrameIncrementPointer was 1 in DICOM93. Changed in DICOM96 (Supplement 7). (0028,0009) AT FrameIncrementPointer 1-n dicom98 (0028,000A) AT FrameDimensionPointer 1-n dicom2004 (0028,0010) US Rows 1 dicom98 (0028,0011) US Columns 1 dicom98 (0028,0012) US Planes 1 dicom98 (0028,0014) US UltrasoundColorDataPresent 1 dicom98 (0028,0030) DS PixelSpacing 2 dicom98 (0028,0031) DS ZoomFactor 2 dicom98 (0028,0032) DS ZoomCenter 2 dicom98 (0028,0034) IS PixelAspectRatio 2 dicom98 # VM of (0028,0051) CorrectedImage was 1 in DICOM93. Changed in DICOM96 (Supplement 7). (0028,0051) CS CorrectedImage 1-n dicom98 (0028,0100) US BitsAllocated 1 dicom98 (0028,0101) US BitsStored 1 dicom98 (0028,0102) US HighBit 1 dicom98 (0028,0103) US PixelRepresentation 1 dicom98 (0028,0106) xs SmallestImagePixelValue 1 dicom98 (0028,0107) xs LargestImagePixelValue 1 dicom98 (0028,0108) xs SmallestPixelValueInSeries 1 dicom98 (0028,0109) xs LargestPixelValueInSeries 1 dicom98 (0028,0110) xs SmallestImagePixelValueInPlane 1 dicom98 (0028,0111) xs LargestImagePixelValueInPlane 1 dicom98 (0028,0120) xs PixelPaddingValue 1 dicom98 (0028,0300) CS QualityControlImage 1 dicom99 (0028,0301) CS BurnedInAnnotation 1 dicom99 (0028,1040) CS PixelIntensityRelationship 1 dicom98 (0028,1041) SS PixelIntensityRelationshipSign 1 dicom99 (0028,1050) DS WindowCenter 1-n dicom98 (0028,1051) DS WindowWidth 1-n dicom98 (0028,1052) DS RescaleIntercept 1 dicom98 (0028,1053) DS RescaleSlope 1 dicom98 (0028,1054) LO RescaleType 1 dicom98 (0028,1055) LO WindowCenterWidthExplanation 1-n dicom98 (0028,1056) CS VOILUTFunction 1 dicom2005 (0028,1090) CS RecommendedViewingMode 1 dicom98 (0028,1101) xs RedPaletteColorLookupTableDescriptor 3 dicom98 (0028,1102) xs GreenPaletteColorLookupTableDescriptor 3 dicom98 (0028,1103) xs BluePaletteColorLookupTableDescriptor 3 dicom98 (0028,1199) UI PaletteColorLookupTableUID 1 dicom98 # VR for (0028,1201) RedPaletteColorLookupTableData was "US or SS" with VM=1-n in DICOM93. Changed in DICOM96 (Supplement 5). # now it is defined as US 1-n or SS 1-n or OW 1 (0028,1201) OW RedPaletteColorLookupTableData 1 dicom98 # VR for (0028,1202) GreenPaletteColorLookupTableData was "US or SS" with VM=1-n in DICOM93. Changed in DICOM96 (Supplement 5). # now it is defined as US 1-n or SS 1-n or OW 1 (0028,1202) OW GreenPaletteColorLookupTableData 1 dicom98 # VR for (0028,1203) BluePaletteColorLookupTableData was "US or SS" with VM=1-n in DICOM93. Changed in DICOM96 (Supplement 5). # now it is defined as US 1-n or SS 1-n or OW 1 (0028,1203) OW BluePaletteColorLookupTableData 1 dicom98 (0028,1221) OW SegmentedRedPaletteColorLookupTableData 1 dicom98 (0028,1222) OW SegmentedGreenPaletteColorLookupTableData 1 dicom98 (0028,1223) OW SegmentedBluePaletteColorLookupTableData 1 dicom98 (0028,1300) CS ImplantPresent 1 dicom99 (0028,1350) CS PartialView 1 dicom2000 (0028,1351) ST PartialViewDescription 1 dicom2000 (0028,1352) SQ PartialViewCodeSequence 1 dicom2005 (0028,135A) CS SpatialLocationsPreserved 1 dicom2005 (0028,2000) OB ICCProfile 1 dicom2005 (0028,2110) CS LossyImageCompression 1 dicom98 (0028,2112) DS LossyImageCompressionRatio 1-n dicom99 (0028,2114) CS LossyImageCompressionMethod 1-n dicom2004 (0028,3000) SQ ModalityLUTSequence 1 dicom98 (0028,3002) xs LUTDescriptor 3 dicom98 (0028,3003) LO LUTExplanation 1 dicom98 (0028,3004) LO ModalityLUTType 1 dicom98 # VM of (0028,3006) LUTData was US/SS in dicom93. Because US/SS does not allow to encode # LUTs with 64K entries in explicit VR, this was changed in dicom2000 (Supplement 33) # to US/SS/OW. We use a specific pseudo-VR for this case. (0028,3006) lt LUTData 1-n dicom2000 (0028,3010) SQ VOILUTSequence 1 dicom98 (0028,3110) SQ SoftcopyVOILUTSequence 1 dicom2000 (0028,5000) SQ BiPlaneAcquisitionSequence 1 dicom98 (0028,6010) US RepresentativeFrameNumber 1 dicom98 (0028,6020) US FrameNumbersOfInterestFOI 1-n dicom98 (0028,6022) LO FramesOfInterestDescription 1-n dicom98 (0028,6023) CS FrameOfInterestType 1-n dicom2004 (0028,6040) US RWavePointer 1-n dicom98 (0028,6100) SQ MaskSubtractionSequence 1 dicom98 (0028,6101) CS MaskOperation 1 dicom98 (0028,6102) US ApplicableFrameRange 2-2n dicom98 (0028,6110) US MaskFrameNumbers 1-n dicom98 (0028,6112) US ContrastFrameAveraging 1 dicom98 (0028,6114) FL MaskSubPixelShift 2 dicom98 (0028,6120) SS TIDOffset 1 dicom98 (0028,6190) ST MaskOperationExplanation 1 dicom98 (0028,9001) UL DataPointRows 1 dicom2003 (0028,9002) UL DataPointColumns 1 dicom2003 (0028,9003) CS SignalDomainColumns 1-2 dicom2003 (0028,9099) US LargestMonochromePixelValue 1 dicom2003 (0028,9108) CS DataRepresentation 1 dicom2003 (0028,9110) SQ PixelMeasuresSequence 1 dicom2003 (0028,9132) SQ FrameVOILUTSequence 1 dicom2003 (0028,9145) SQ PixelValueTransformationSequence 1 dicom2003 (0028,9235) CS SignalDomainRows 1 dicom2003 (0028,9411) FL DisplayFilterPercentage 1 dicom2005 (0028,9415) SQ FramePixelShiftSequence 1 dicom2005 (0028,9416) US SubtractionItemID 1 dicom2005 (0028,9422) SQ PixelIntensityRelationshipLUTSequence 1 dicom2005 (0028,9443) SQ FramePixelDataPropertiesSequence 1 dicom2005 (0028,9444) CS GeometricalProperties 1 dicom2005 (0028,9445) FL GeometricMaximumDistortion 1 dicom2005 (0028,9446) CS ImageProcessingApplied 1-n dicom2005 (0028,9454) CS MaskSelectionMode 1 dicom2005 (0028,9475) CS LUTFunction 1 dicom2005 (0032,0000) UL StudyGroupLength 1 dicom98 (0032,000A) CS StudyStatusID 1 dicom98 (0032,000C) CS StudyPriorityID 1 dicom98 (0032,0012) LO StudyIDIssuer 1 dicom98 (0032,0032) DA StudyVerifiedDate 1 dicom98 (0032,0033) TM StudyVerifiedTime 1 dicom98 (0032,0034) DA StudyReadDate 1 dicom98 (0032,0035) TM StudyReadTime 1 dicom98 (0032,1000) DA ScheduledStudyStartDate 1 dicom98 (0032,1001) TM ScheduledStudyStartTime 1 dicom98 (0032,1010) DA ScheduledStudyStopDate 1 dicom98 (0032,1011) TM ScheduledStudyStopTime 1 dicom98 (0032,1020) LO ScheduledStudyLocation 1 dicom98 (0032,1021) AE ScheduledStudyLocationAETitles 1-n dicom98 (0032,1030) LO ReasonForStudy 1 dicom98 (0032,1031) SQ RequestingPhysicianIdentificationSequence 1 dicom2003 (0032,1032) PN RequestingPhysician 1 dicom98 (0032,1033) LO RequestingService 1 dicom98 (0032,1040) DA StudyArrivalDate 1 dicom98 (0032,1041) TM StudyArrivalTime 1 dicom98 (0032,1050) DA StudyCompletionDate 1 dicom98 (0032,1051) TM StudyCompletionTime 1 dicom98 (0032,1055) CS StudyComponentStatusID 1 dicom98 (0032,1060) LO RequestedProcedureDescription 1 dicom98 (0032,1064) SQ RequestedProcedureCodeSequence 1 dicom98 (0032,1070) LO RequestedContrastAgent 1 dicom98 (0032,4000) LT StudyComments 1 dicom98 (0038,0000) UL VisitGroupLength 1 dicom98 (0038,0004) SQ ReferencedPatientAliasSequence 1 dicom98 (0038,0008) CS VisitStatusID 1 dicom98 (0038,0010) LO AdmissionID 1 dicom98 (0038,0011) LO IssuerOfAdmissionID 1 dicom98 (0038,0016) LO RouteOfAdmissions 1 dicom98 (0038,001A) DA ScheduledAdmissionDate 1 dicom98 (0038,001B) TM ScheduledAdmissionTime 1 dicom98 (0038,001C) DA ScheduledDischargeDate 1 dicom98 (0038,001D) TM ScheduledDischargeTime 1 dicom98 (0038,001E) LO ScheduledPatientInstitutionResidence 1 dicom98 (0038,0020) DA AdmittingDate 1 dicom98 (0038,0021) TM AdmittingTime 1 dicom98 (0038,0030) DA DischargeDate 1 dicom98 (0038,0032) TM DischargeTime 1 dicom98 (0038,0040) LO DischargeDiagnosisDescription 1 dicom98 (0038,0044) SQ DischargeDiagnosisCodeSequence 1 dicom98 (0038,0050) LO SpecialNeeds 1 dicom98 (0038,0100) SQ PertinentDocumentsSequence 1 dicom2005 (0038,0300) LO CurrentPatientLocation 1 dicom98 (0038,0400) LO PatientsInstitutionResidence 1 dicom98 (0038,0500) LO PatientState 1 dicom98 (0038,0502) SQ PatientClinicalTrialParticipationSequence 1 dicom2005 (0038,4000) LT VisitComments 1 dicom98 (003A,0000) UL WaveformGroupLength 1 dicom2000 (003A,0004) CS WaveformOriginality 1 dicom2000 (003A,0005) US NumberOfWaveformChannels 1 dicom2000 (003A,0010) UL NumberOfWaveformSamples 1 dicom2000 (003A,001A) DS SamplingFrequency 1 dicom2000 (003A,0020) SH MultiplexGroupLabel 1 dicom2000 (003A,0200) SQ ChannelDefinitionSequence 1 dicom2000 (003A,0202) IS WaveformChannelNumber 1 dicom2000 (003A,0203) SH ChannelLabel 1 dicom2000 (003A,0205) CS ChannelStatus 1-n dicom2000 (003A,0208) SQ ChannelSourceSequence 1 dicom2000 (003A,0209) SQ ChannelSourceModifiersSequence 1 dicom2000 (003A,020A) SQ SourceWaveformSequence 1 dicom2000 (003A,020C) LO ChannelDerivationDescription 1 dicom2000 (003A,0210) DS ChannelSensitivity 1 dicom2000 (003A,0211) SQ ChannelSensitivityUnitsSequence 1 dicom2000 (003A,0212) DS ChannelSensitivityCorrectionFactor 1 dicom2000 (003A,0213) DS ChannelBaseline 1 dicom2000 (003A,0214) DS ChannelTimeSkew 1 dicom2000 (003A,0215) DS ChannelSampleSkew 1 dicom2000 (003A,0218) DS ChannelOffset 1 dicom2000 (003A,021A) US WaveformBitsStored 1 dicom2000 (003A,0220) DS FilterLowFrequency 1 dicom2000 (003A,0221) DS FilterHighFrequency 1 dicom2000 (003A,0222) DS NotchFilterFrequency 1 dicom2000 (003A,0223) DS NotchFilterBandwidth 1 dicom2000 (003A,0300) SQ MultiplexedAudioChannelsDescriptionCodeSequence 1 dicom2004 (003A,0301) IS ChannelIdentificationCode 1 dicom2004 (003A,0302) CS ChannelMode 1 dicom2004 (0040,0000) UL ModalityWorklistGroupLength 1 dicom98 (0040,0001) AE ScheduledStationAETitle 1-n dicom98 (0040,0002) DA ScheduledProcedureStepStartDate 1 dicom98 (0040,0003) TM ScheduledProcedureStepStartTime 1 dicom98 (0040,0004) DA ScheduledProcedureStepEndDate 1 dicom98 (0040,0005) TM ScheduledProcedureStepEndTime 1 dicom98 (0040,0006) PN ScheduledPerformingPhysiciansName 1 dicom98 (0040,0007) LO ScheduledProcedureStepDescription 1 dicom98 # attribute renamed in CP 201, name was ScheduledActionItemCodeSequence before (0040,0008) SQ ScheduledProtocolCodeSequence 1 dicom2001 (0040,0009) SH ScheduledProcedureStepID 1 dicom98 (0040,000A) SQ StageCodeSequence 1 dicom2001 (0040,000B) SQ ScheduledPerformingPhysicianIdentificationSequence 1 dicom2003 (0040,0010) SH ScheduledStationName 1-n dicom98 (0040,0011) SH ScheduledProcedureStepLocation 1 dicom98 (0040,0012) LO PreMedication 1 dicom98 (0040,0020) CS ScheduledProcedureStepStatus 1 dicom98 (0040,0100) SQ ScheduledProcedureStepSequence 1 dicom98 # renamed in CP 243, name was ReferencedStandaloneSOPInstanceSequence before (0040,0220) SQ ReferencedNonImageCompositeSOPInstanceSequence 1 dicom2001 (0040,0241) AE PerformedStationAETitle 1 dicom98 (0040,0242) SH PerformedStationName 1 dicom98 (0040,0243) SH PerformedLocation 1 dicom98 (0040,0244) DA PerformedProcedureStepStartDate 1 dicom98 (0040,0245) TM PerformedProcedureStepStartTime 1 dicom98 (0040,0250) DA PerformedProcedureStepEndDate 1 dicom98 (0040,0251) TM PerformedProcedureStepEndTime 1 dicom98 (0040,0252) CS PerformedProcedureStepStatus 1 dicom98 # VR for (0040,0253) PerformedProcedureStepID was CS in DICOM98. Changed in DICOM99. (0040,0253) SH PerformedProcedureStepID 1 dicom99 (0040,0254) LO PerformedProcedureStepDescription 1 dicom98 (0040,0255) LO PerformedProcedureTypeDescription 1 dicom98 # attribute renamed in CP 201, name was PerformedActionItemSequence before (0040,0260) SQ PerformedProtocolCodeSequence 1 dicom2001 (0040,0270) SQ ScheduledStepAttributesSequence 1 dicom98 (0040,0275) SQ RequestAttributesSequence 1 dicom98 (0040,0280) ST CommentsOnThePerformedProcedureStep 1 dicom98 (0040,0281) SQ PerformedProcedureStepDiscontinuationReasonCodeSequence 1 dicom2003 (0040,0293) SQ QuantitySequence 1 dicom98 (0040,0294) DS Quantity 1 dicom98 (0040,0295) SQ MeasuringUnitsSequence 1 dicom98 (0040,0296) SQ BillingItemSequence 1 dicom98 (0040,0300) US TotalTimeOfFluoroscopy 1 dicom98 (0040,0301) US TotalNumberOfExposures 1 dicom98 (0040,0302) US EntranceDose 1 dicom98 (0040,0303) US ExposedArea 1-2 dicom98 (0040,0306) DS DistanceSourceToEntrance 1 dicom98 (0040,030E) SQ ExposureDoseSequence 1 dicom2001 (0040,0310) ST CommentsOnRadiationDose 1 dicom98 (0040,0312) DS XRayOutput 1 dicom99 (0040,0314) DS HalfValueLayer 1 dicom99 (0040,0316) DS OrganDose 1 dicom99 (0040,0318) CS OrganExposed 1 dicom99 (0040,0320) SQ BillingProcedureStepSequence 1 dicom98 (0040,0321) SQ FilmConsumptionSequence 1 dicom98 (0040,0324) SQ BillingSuppliesAndDevicesSequence 1 dicom98 (0040,0340) SQ PerformedSeriesSequence 1 dicom98 (0040,0400) LT CommentsOnTheScheduledProcedureStep 1 dicom98 (0040,0440) SQ ProtocolContextSequence 1 dicom2004 (0040,0441) SQ ContentItemModifierSequence 1 dicom2004 (0040,050A) LO SpecimenAccessionNumber 1 dicom2000 (0040,0550) SQ SpecimenSequence 1 dicom2000 (0040,0551) LO SpecimenIdentifier 1 dicom2000 (0040,0555) SQ AcquisitionContextSequence 1 dicom99 (0040,0556) ST AcquisitionContextDescription 1 dicom99 (0040,059A) SQ SpecimenTypeCodeSequence 1 dicom2000 (0040,06FA) LO SlideIdentifier 1 dicom99 (0040,071A) SQ ImageCenterPointCoordinatesSequence 1 dicom99 (0040,072A) DS XOffsetInSlideCoordinateSystem 1 dicom99 (0040,073A) DS YOffsetInSlideCoordinateSystem 1 dicom99 (0040,074A) DS ZOffsetInSlideCoordinateSystem 1 dicom99 (0040,08D8) SQ PixelSpacingSequence 1 dicom99 (0040,08DA) SQ CoordinateSystemAxisCodeSequence 1 dicom99 (0040,08EA) SQ MeasurementUnitsCodeSequence 1 dicom99 (0040,1001) SH RequestedProcedureID 1 dicom98 (0040,1002) LO ReasonForTheRequestedProcedure 1 dicom98 (0040,1003) SH RequestedProcedurePriority 1 dicom98 (0040,1004) LO PatientTransportArrangements 1 dicom98 (0040,1005) LO RequestedProcedureLocation 1 dicom98 (0040,1006) SH PlacerOrderNumberProcedure 1 dicom98 (0040,1007) SH FillerOrderNumberProcedure 1 dicom98 (0040,1008) LO ConfidentialityCode 1 dicom98 (0040,1009) SH ReportingPriority 1 dicom98 (0040,100A) SQ ReasonForRequestedProcedureCodeSequence 1 dicom2004 (0040,1010) PN NamesOfIntendedRecipientsOfResults 1-n dicom98 (0040,1011) SQ IntendedRecipientsOfResultsIdentificationSequence 1 dicom2003 (0040,1101) SQ PersonIdentificationCodeSequence 1 dicom2003 (0040,1102) ST PersonsAddress 1 dicom2003 (0040,1103) LO PersonsTelephoneNumbers 1-n dicom2003 (0040,1400) LT RequestedProcedureComments 1 dicom98 # Attribute renamed in CP 241, name was IssueDateOfImagingServiceRequest before (0040,2004) DA IssueDateOfImagingServiceRequest 1 dicom2001 # Attribute renamed in CP 241, name was IssueTimeOfImagingServiceRequest before (0040,2005) TM IssueTimeOfImagingServiceRequest 1 dicom2001 (0040,2008) PN OrderEnteredBy 1 dicom98 (0040,2009) SH OrderEnterersLocation 1 dicom98 (0040,2010) SH OrderCallbackPhoneNumber 1 dicom98 (0040,2016) LO PlacerOrderNumberImagingServiceRequest 1 dicom99 (0040,2017) LO FillerOrderNumberImagingServiceRequest 1 dicom99 (0040,2400) LT ImagingServiceRequestComments 1 dicom98 (0040,3001) LO ConfidentialityConstraintOnPatientDataDescription 1 dicom98 (0040,4001) CS GeneralPurposeScheduledProcedureStepStatus 1 dicom2001 (0040,4002) CS GeneralPurposePerformedProcedureStepStatus 1 dicom2001 (0040,4003) CS GeneralPurposeScheduledProcedureStepPriority 1 dicom2001 (0040,4004) SQ ScheduledProcessingApplicationsCodeSequence 1 dicom2001 (0040,4005) DT ScheduledProcedureStepStartDateAndTime 1 dicom2001 (0040,4006) CS MultipleCopiesFlag 1 dicom2001 (0040,4007) SQ PerformedProcessingApplicationsCodeSequence 1 dicom2001 (0040,4009) SQ HumanPerformerCodeSequence 1 dicom2001 (0040,4010) DT ScheduledProcedureStepModificationDateAndTime 1 dicom2004 (0040,4011) DT ExpectedCompletionDateAndTime 1 dicom2001 (0040,4015) SQ ResultingGeneralPurposePerformedProcedureStepsSequence 1 dicom2001 (0040,4016) SQ ReferencedGeneralPurposeScheduledProcedureStepSequence 1 dicom2001 (0040,4018) SQ ScheduledWorkitemCodeSequence 1 dicom2001 (0040,4019) SQ PerformedWorkitemCodeSequence 1 dicom2001 (0040,4020) CS InputAvailabilityFlag 1 dicom2001 (0040,4021) SQ InputInformationSequence 1 dicom2001 (0040,4022) SQ RelevantInformationSequence 1 dicom2001 (0040,4023) UI ReferencedGeneralPurposeScheduledProcedureStepTransactionUID 1 dicom2001 (0040,4025) SQ ScheduledStationNameCodeSequence 1 dicom2001 (0040,4026) SQ ScheduledStationClassCodeSequence 1 dicom2001 (0040,4027) SQ ScheduledStationGeographicLocationCodeSequence 1 dicom2001 (0040,4028) SQ PerformedStationNameCodeSequence 1 dicom2001 (0040,4029) SQ PerformedStationClassCodeSequence 1 dicom2001 (0040,4030) SQ PerformedStationGeographicLocationCodeSequence 1 dicom2001 (0040,4031) SQ RequestedSubsequentWorkitemCodeSequence 1 dicom2001 (0040,4032) SQ NonDICOMOutputCodeSequence 1 dicom2001 (0040,4033) SQ OutputInformationSequence 1 dicom2001 (0040,4034) SQ ScheduledHumanPerformersSequence 1 dicom2001 (0040,4035) SQ ActualHumanPerformersSequence 1 dicom2001 (0040,4036) LO HumanPerformersOrganization 1 dicom2001 (0040,4037) PN HumanPerformersName 1 dicom2001 (0040,8302) DS EntranceDoseInmGy 1 dicom2000 (0040,9094) SQ ReferencedImageRealWorldValueMappingSequence 1 dicom2005 (0040,9096) SQ RealWorldValueMappingSequence 1 dicom2003 (0040,9098) SQ PixelValueMappingCodeSequence 1 dicom2005 # VR corrected from SS to SH in CP 370 (2004) (0040,9210) SH LUTLabel 1 dicom2004 (0040,9211) xs RealWorldValueLastValueMapped 1 dicom2003 (0040,9212) FD RealWorldValueLUTData 1-n dicom2003 (0040,9216) xs RealWorldValueFirstValueMapped 1 dicom2003 (0040,9224) FD RealWorldValueIntercept 1 dicom2003 (0040,9225) FD RealWorldValueSlope 1 dicom2003 (0040,A010) CS RelationshipType 1 dicom2000 (0040,A027) LO VerifyingOrganization 1 dicom2000 (0040,A030) DT VerificationDateTime 1 dicom2000 (0040,A032) DT ObservationDateTime 1 dicom2000 (0040,A040) CS ValueType 1 dicom2000 (0040,A043) SQ ConceptNameCodeSequence 1 dicom99 (0040,A050) CS ContinuityOfContent 1 dicom2000 (0040,A073) SQ VerifyingObserverSequence 1 dicom2000 (0040,A075) PN VerifyingObserverName 1 dicom2000 (0040,A078) SQ AuthorObserverSequence 1 dicom2005 (0040,A07A) SQ ParticipantSequence 1 dicom2005 (0040,A07C) SQ CustodialOrganizationSequence 1 dicom2005 (0040,A080) CS ParticipationType 1 dicom2005 (0040,A082) DT ParticipationDatetime 1 dicom2005 (0040,A084) CS ObserverType 1 dicom2005 (0040,A088) SQ VerifyingObserverIdentificationCodeSequence 1 dicom2000 (0040,A090) SQ EquivalentCDADocumentSequence 1 dicom2005 (0040,A0B0) US ReferencedWaveformChannels 2-2n dicom2000 (0040,A120) DT DateTime 1 dicom2000 (0040,A121) DA Date 1 dicom99 (0040,A122) TM Time 1 dicom99 (0040,A123) PN PersonName 1 dicom99 (0040,A124) UI UID 1 dicom2000 (0040,A130) CS TemporalRangeType 1 dicom2000 (0040,A132) UL ReferencedSamplePositions 1-n dicom2000 (0040,A136) US ReferencedFrameNumbers 1-n dicom99 (0040,A138) DS ReferencedTimeOffsets 1-n dicom2000 (0040,A13A) DT ReferencedDatetime 1-n dicom2000 (0040,A160) UT TextValue 1 dicom99 (0040,A168) SQ ConceptCodeSequence 1 dicom99 (0040,A170) SQ PurposeOfReferenceCodeSequence 1 dicom2001 (0040,A180) US AnnotationGroupNumber 1 dicom2000 (0040,A195) SQ ModifierCodeSequence 1 dicom2000 (0040,A300) SQ MeasuredValueSequence 1 dicom2000 (0040,A301) SQ NumericValueQualifierCodeSequence 1 dicom2003 (0040,A30A) DS NumericValue 1-n dicom99 (0040,A360) SQ PredecessorDocumentsSequence 1 dicom2000 (0040,A370) SQ ReferencedRequestSequence 1 dicom2000 (0040,A372) SQ PerformedProcedureCodeSequence 1 dicom2000 (0040,A375) SQ CurrentRequestedProcedureEvidenceSequence 1 dicom2000 (0040,A385) SQ PertinentOtherEvidenceSequence 1 dicom2000 (0040,A390) SQ HL7StructuredDocumentReferenceSequence 1 dicom2005 (0040,A491) CS CompletionFlag 1 dicom2000 (0040,A492) LO CompletionFlagDescription 1 dicom2000 (0040,A493) CS VerificationFlag 1 dicom2000 (0040,A504) SQ ContentTemplateSequence 1 dicom2000 (0040,A525) SQ IdenticalDocumentsSequence 1 dicom2000 (0040,A730) SQ ContentSequence 1 dicom2000 (0040,B020) SQ AnnotationSequence 1 dicom2000 (0040,DB00) CS TemplateIdentifier 1 dicom2000 (0040,DB73) UL ReferencedContentItemIdentifier 1-n dicom2000 (0040,E001) ST HL7InstanceIdentifier 1 dicom2005 (0040,E004) DT HL7DocumentEffectiveTime 1 dicom2005 (0040,E006) SQ HL7DocumentTypeCodeSequence 1 dicom2005 (0040,E010) ST RetrieveURI 1 dicom2005 (0042,0000) UL EncapsulatedDocumentGroupLength 1 dicom2005 (0042,0010) ST DocumentTitle 1 dicom2005 (0042,0011) OB EncapsulatedDocument 1 dicom2005 (0042,0012) LO MIMETypeOfEncapsulatedDocument 1 dicom2005 (0042,0013) SQ SourceInstanceSequence 1 dicom2005 (0050,0000) UL XRayAngioDeviceGroupLength 1 dicom98 # name for (0050,0004) was CalibrationObject in DICOM96. Name changed to CalibrationImage in DICOM98. (0050,0004) CS CalibrationImage 1 dicom98 (0050,0010) SQ DeviceSequence 1 dicom98 (0050,0014) DS DeviceLength 1 dicom98 (0050,0016) DS DeviceDiameter 1 dicom98 (0050,0017) CS DeviceDiameterUnits 1 dicom98 (0050,0018) DS DeviceVolume 1 dicom98 (0050,0019) DS InterMarkerDistance 1 dicom98 (0050,0020) LO DeviceDescription 1 dicom98 (0054,0000) UL NuclearMedicineGroupLength 1 dicom98 (0054,0010) US EnergyWindowVector 1-n dicom98 (0054,0011) US NumberOfEnergyWindows 1 dicom98 (0054,0012) SQ EnergyWindowInformationSequence 1 dicom98 (0054,0013) SQ EnergyWindowRangeSequence 1 dicom98 (0054,0014) DS EnergyWindowLowerLimit 1 dicom98 (0054,0015) DS EnergyWindowUpperLimit 1 dicom98 (0054,0016) SQ RadiopharmaceuticalInformationSequence 1 dicom98 (0054,0017) IS ResidualSyringeCounts 1 dicom98 (0054,0018) SH EnergyWindowName 1 dicom98 (0054,0020) US DetectorVector 1-n dicom98 (0054,0021) US NumberOfDetectors 1 dicom98 (0054,0022) SQ DetectorInformationSequence 1 dicom98 (0054,0030) US PhaseVector 1-n dicom98 (0054,0031) US NumberOfPhases 1 dicom98 (0054,0032) SQ PhaseInformationSequence 1 dicom98 (0054,0033) US NumberOfFramesInPhase 1 dicom98 (0054,0036) IS PhaseDelay 1 dicom98 (0054,0038) IS PauseBetweenFrames 1 dicom98 (0054,0039) CS PhaseDescription 1 dicom2004 (0054,0050) US RotationVector 1-n dicom98 (0054,0051) US NumberOfRotations 1 dicom98 (0054,0052) SQ RotationInformationSequence 1 dicom98 (0054,0053) US NumberOfFramesInRotation 1 dicom98 (0054,0060) US RRIntervalVector 1-n dicom98 (0054,0061) US NumberOfRRIntervals 1 dicom98 (0054,0062) SQ GatedInformationSequence 1 dicom98 (0054,0063) SQ DataInformationSequence 1 dicom98 (0054,0070) US TimeSlotVector 1-n dicom98 (0054,0071) US NumberOfTimeSlots 1 dicom98 (0054,0072) SQ TimeSlotInformationSequence 1 dicom98 (0054,0073) DS TimeSlotTime 1 dicom98 (0054,0080) US SliceVector 1-n dicom98 (0054,0081) US NumberOfSlices 1 dicom98 (0054,0090) US AngularViewVector 1-n dicom98 (0054,0100) US TimeSliceVector 1-n dicom98 (0054,0101) US NumberOfTimeSlices 1 dicom98 (0054,0200) DS StartAngle 1 dicom98 (0054,0202) CS TypeOfDetectorMotion 1 dicom98 (0054,0210) IS TriggerVector 1-n dicom98 (0054,0211) US NumberOfTriggersInPhase 1 dicom98 (0054,0220) SQ ViewCodeSequence 1 dicom98 # (0054,0222) ViewAngulationModifierCodeSequence is renamed to ViewModifierSequence in Supplement 32. (0054,0222) SQ ViewModifierCodeSequence 1 dicom98 (0054,0300) SQ RadionuclideCodeSequence 1 dicom98 # name for (0054,0302) was RadiopharmaceuticalRouteCodeSequence in DICOM96. Name changed to AdministrationRouteCodeSequence in DICOM98. (0054,0302) SQ AdministrationRouteCodeSequence 1 dicom98 (0054,0304) SQ RadiopharmaceuticalCodeSequence 1 dicom98 (0054,0306) SQ CalibrationDataSequence 1 dicom98 (0054,0308) US EnergyWindowNumber 1 dicom98 (0054,0400) SH ImageID 1 dicom98 (0054,0410) SQ PatientOrientationCodeSequence 1 dicom98 (0054,0412) SQ PatientOrientationModifierCodeSequence 1 dicom98 (0054,0414) SQ PatientGantryRelationshipCodeSequence 1 dicom98 (0054,0500) CS SliceProgressionDirection 1 dicom2004 (0054,1000) CS SeriesType 2 dicom98 (0054,1001) CS Units 1 dicom98 (0054,1002) CS CountsSource 1 dicom98 (0054,1004) CS ReprojectionMethod 1 dicom98 (0054,1100) CS RandomsCorrectionMethod 1 dicom98 (0054,1101) LO AttenuationCorrectionMethod 1 dicom98 (0054,1102) CS DecayCorrection 1 dicom98 (0054,1103) LO ReconstructionMethod 1 dicom98 (0054,1104) LO DetectorLinesOfResponseUsed 1 dicom98 (0054,1105) LO ScatterCorrectionMethod 1 dicom98 (0054,1200) DS AxialAcceptance 1 dicom98 (0054,1201) IS AxialMash 2 dicom98 (0054,1202) IS TransverseMash 1 dicom98 (0054,1203) DS DetectorElementSize 2 dicom98 (0054,1210) DS CoincidenceWindowWidth 1 dicom98 (0054,1220) CS SecondaryCountsType 1-n dicom98 (0054,1300) DS FrameReferenceTime 1 dicom98 (0054,1310) IS PrimaryPromptsCountsAccumulated 1 dicom98 (0054,1311) IS SecondaryCountsAccumulated 1-n dicom98 (0054,1320) DS SliceSensitivityFactor 1 dicom98 (0054,1321) DS DecayFactor 1 dicom98 (0054,1322) DS DoseCalibrationFactor 1 dicom98 (0054,1323) DS ScatterFractionFactor 1 dicom98 (0054,1324) DS DeadTimeFactor 1 dicom98 (0054,1330) US ImageIndex 1 dicom98 (0054,1400) CS CountsIncluded 1-n dicom98 (0054,1401) CS DeadTimeCorrectionFlag 1 dicom98 (0060,0000) UL HistogramGroupLength 1 dicom99 (0060,3000) SQ HistogramSequence 1 dicom99 (0060,3002) US HistogramNumberOfBins 1 dicom99 (0060,3004) xs HistogramFirstBinValue 1 dicom99 (0060,3006) xs HistogramLastBinValue 1 dicom99 (0060,3008) US HistogramBinWidth 1 dicom99 (0060,3010) LO HistogramExplanation 1 dicom99 (0060,3020) UL HistogramData 1-n dicom99 (0070,0000) UL PresentationStateGroupLength 1 dicom2000 (0070,0001) SQ GraphicAnnotationSequence 1 dicom2000 (0070,0002) CS GraphicLayer 1 dicom2000 (0070,0003) CS BoundingBoxAnnotationUnits 1 dicom2000 (0070,0004) CS AnchorPointAnnotationUnits 1 dicom2000 (0070,0005) CS GraphicAnnotationUnits 1 dicom2000 (0070,0006) ST UnformattedTextValue 1 dicom2000 (0070,0008) SQ TextObjectSequence 1 dicom2000 (0070,0009) SQ GraphicObjectSequence 1 dicom2000 (0070,0010) FL BoundingBoxTopLeftHandCorner 2 dicom2000 (0070,0011) FL BoundingBoxBottomRightHandCorner 2 dicom2000 (0070,0012) CS BoundingBoxTextHorizontalJustification 1 dicom2000 (0070,0014) FL AnchorPoint 2 dicom2000 (0070,0015) CS AnchorPointVisibility 1 dicom2000 (0070,0020) US GraphicDimensions 1 dicom2000 (0070,0021) US NumberOfGraphicPoints 1 dicom2000 (0070,0022) FL GraphicData 2-n dicom2000 (0070,0023) CS GraphicType 1 dicom2000 (0070,0024) CS GraphicFilled 1 dicom2000 (0070,0041) CS ImageHorizontalFlip 1 dicom2000 (0070,0042) US ImageRotation 1 dicom2000 (0070,0052) SL DisplayedAreaTopLeftHandCorner 2 dicom2000 (0070,0053) SL DisplayedAreaBottomRightHandCorner 2 dicom2000 (0070,005A) SQ DisplayedAreaSelectionSequence 1 dicom2000 (0070,0060) SQ GraphicLayerSequence 1 dicom2000 (0070,0062) IS GraphicLayerOrder 1 dicom2000 (0070,0066) US GraphicLayerRecommendedDisplayGrayscaleValue 1 dicom2000 (0070,0067) US GraphicLayerRecommendedDisplayRGBValue 3 dicom2000 (0070,0068) LO GraphicLayerDescription 1 dicom2000 # name for (0070,0080) was PresentationLabel. Changed in DICOM 2004. (0070,0080) CS ContentLabel 1 dicom2004 # name for (0070,0081) was PresentationDescription. Changed in DICOM 2004. (0070,0081) LO ContentDescription 1 dicom2004 (0070,0082) DA PresentationCreationDate 1 dicom2000 (0070,0083) TM PresentationCreationTime 1 dicom2000 # name for (0070,0084) was PresentationCreatorsName. Changed in DICOM 2004. (0070,0084) PN ContentCreatorsName 1 dicom2004 (0070,0086) SQ ContentCreatorsIdentificationSequence 1 dicom2005 (0070,0100) CS PresentationSizeMode 1 dicom2000 (0070,0101) DS PresentationPixelSpacing 2 dicom2000 (0070,0102) IS PresentationPixelAspectRatio 2 dicom2000 (0070,0103) FL PresentationPixelMagnificationRatio 1 dicom2000 (0070,0306) CS ShapeType 1 dicom2004 (0070,0308) SQ RegistrationSequence 1 dicom2004 (0070,0309) SQ MatrixRegistrationSequence 1 dicom2004 (0070,030A) SQ MatrixSequence 1 dicom2004 (0070,030C) CS FrameOfReferenceTransformationMatrixType 1 dicom2004 (0070,030D) SQ RegistrationTypeCodeSequence 1 dicom2004 (0070,030F) ST FiducialDescription 1 dicom2004 (0070,0310) SH FiducialIdentifier 1 dicom2004 (0070,0311) SQ FiducialIdentifierCodeSequence 1 dicom2004 (0070,0312) FD ContourUncertaintyRadius 1 dicom2004 (0070,0314) SQ UsedFiducialsSequence 1 dicom2004 (0070,0318) SQ GraphicCoordinatesDataSequence 1 dicom2004 (0070,031A) UI FiducialUID 1 dicom2004 (0070,031C) SQ FiducialSetSequence 1 dicom2004 (0070,031E) SQ FiducialSequence 1 dicom2004 (0070,0401) US GraphicLayerRecommendedDisplayCIELabValue 3 dicom2005 (0070,0402) SQ BlendingSequence 1 dicom2005 (0070,0403) FL RelativeOpacity 1 dicom2005 (0070,0404) SQ ReferencedSpatialRegistrationSequence 1 dicom2005 (0070,0405) CS BlendingPosition 1 dicom2005 (0072,0000) UL HangingProtocolGroupLength 1 dicom2005 (0072,0002) SH HangingProtocolName 1 dicom2005 (0072,0004) LO HangingProtocolDescription 1 dicom2005 (0072,0006) CS HangingProtocolLevel 1 dicom2005 (0072,0008) LO HangingProtocolCreator 1 dicom2005 (0072,000A) DT HangingProtocolCreationDatetime 1 dicom2005 (0072,000C) SQ HangingProtocolDefinitionSequence 1 dicom2005 (0072,000E) SQ HangingProtocolUserIdentificationCodeSequence 1 dicom2005 (0072,0010) LO HangingProtocolUserGroupName 1 dicom2005 (0072,0012) SQ SourceHangingProtocolSequence 1 dicom2005 (0072,0014) US NumberOfPriorsReferenced 1 dicom2005 (0072,0020) SQ ImageSetsSequence 1 dicom2005 (0072,0022) SQ ImageSetSelectorSequence 1 dicom2005 (0072,0024) CS ImageSetSelectorUsageFlag 1 dicom2005 (0072,0026) AT SelectorAttribute 1 dicom2005 (0072,0028) US SelectorValueNumber 1 dicom2005 (0072,0030) SQ TimeBasedImageSetsSequence 1 dicom2005 (0072,0032) US ImageSetNumber 1 dicom2005 (0072,0034) CS ImageSetSelectorCategory 1 dicom2005 (0072,0038) US RelativeTime 2 dicom2005 (0072,003A) CS RelativeTimeUnits 1 dicom2005 (0072,003C) SS AbstractPriorValue 2 dicom2005 (0072,003E) SQ AbstractPriorCodeSequence 1 dicom2005 (0072,0040) LO ImageSetLabel 1 dicom2005 (0072,0050) CS SelectorAttributeVR 1 dicom2005 (0072,0052) AT SelectorSequencePointer 1 dicom2005 (0072,0054) LO SelectorSequencePointerPrivateCreator 1 dicom2005 (0072,0056) LO SelectorAttributePrivateCreator 1 dicom2005 (0072,0060) AT SelectorATValue 1-n dicom2005 (0072,0062) CS SelectorCSValue 1-n dicom2005 (0072,0064) IS SelectorISValue 1-n dicom2005 (0072,0066) LO SelectorLOValue 1-n dicom2005 (0072,0068) LT SelectorLTValue 1-n dicom2005 (0072,006A) PN SelectorPNValue 1-n dicom2005 (0072,006C) SH SelectorSHValue 1-n dicom2005 (0072,006E) ST SelectorSTValue 1-n dicom2005 (0072,0070) UT SelectorUTValue 1-n dicom2005 (0072,0072) DS SelectorDSValue 1-n dicom2005 (0072,0074) FD SelectorFDValue 1-n dicom2005 (0072,0076) FL SelectorFLValue 1-n dicom2005 (0072,0078) UL SelectorULValue 1-n dicom2005 (0072,007A) US SelectorUSValue 1-n dicom2005 (0072,007C) SL SelectorSLValue 1-n dicom2005 (0072,007E) SS SelectorSSValue 1-n dicom2005 (0072,0080) SQ SelectorCodeSequenceValue 1 dicom2005 (0072,0100) US NumberOfScreens 1 dicom2005 (0072,0102) SQ NominalScreenDefinitionSequence 1 dicom2005 (0072,0104) US NumberOfVerticalPixels 1 dicom2005 (0072,0106) US NumberOfHorizontalPixels 1 dicom2005 (0072,0108) FD DisplayEnvironmentSpatialPosition 4 dicom2005 (0072,010A) US ScreenMinimumGrayscaleBitDepth 1 dicom2005 (0072,010C) US ScreenMinimumColorBitDepth 1 dicom2005 (0072,010E) US ApplicationMaximumRepaintTime 1 dicom2005 (0072,0200) SQ DisplaySetsSequence 1 dicom2005 (0072,0202) US DisplaySetNumber 1 dicom2005 (0072,0204) US DisplaySetPresentationGroup 1 dicom2005 (0072,0206) LO DisplaySetPresentationGroupDescription 1 dicom2005 (0072,0208) CS PartialDataDisplayHandling 1 dicom2005 (0072,0210) SQ SynchronizedScrollingSequence 1 dicom2005 (0072,0212) US DisplaySetScrollingGroup 2-n dicom2005 (0072,0214) SQ NavigationIndicatorSequence 1 dicom2005 (0072,0216) US NavigationDisplaySet 1 dicom2005 (0072,0218) US ReferenceDisplaySets 1-n dicom2005 (0072,0300) SQ ImageBoxesSequence 1 dicom2005 (0072,0302) US ImageBoxNumber 1 dicom2005 (0072,0304) CS ImageBoxLayoutType 1 dicom2005 (0072,0306) US ImageBoxTileHorizontalDimension 1 dicom2005 (0072,0308) US ImageBoxTileVerticalDimension 1 dicom2005 (0072,0310) CS ImageBoxScrollDirection 1 dicom2005 (0072,0312) CS ImageBoxSmallScrollType 1 dicom2005 (0072,0314) US ImageBoxSmallScrollAmount 1 dicom2005 (0072,0316) CS ImageBoxLargeScrollType 1 dicom2005 (0072,0318) US ImageBoxLargeScrollAmount 1 dicom2005 (0072,0320) US ImageBoxOverlapPriority 1 dicom2005 (0072,0330) FD CineRelativeToRealTime 1 dicom2005 (0072,0400) SQ FilterOperationsSequence 1 dicom2005 (0072,0402) CS FilterByCategory 1 dicom2005 (0072,0404) CS FilterByAttributePresence 1 dicom2005 (0072,0406) CS FilterByOperator 1 dicom2005 (0072,0500) CS BlendingOperationType 1 dicom2005 (0072,0510) CS ReformattingOperationType 1 dicom2005 (0072,0512) FD ReformattingThickness 1 dicom2005 (0072,0514) FD ReformattingInterval 1 dicom2005 (0072,0516) CS ReformattingOperationInitialViewDirection 1 dicom2005 (0072,0520) CS 3DRenderingType 1-n dicom2005 (0072,0600) SQ SortingOperationsSequence 1 dicom2005 (0072,0602) CS SortByCategory 1 dicom2005 (0072,0604) CS SortingDirection 1 dicom2005 (0072,0700) CS DisplaySetPatientOrientation 2 dicom2005 (0072,0702) CS VOIType 1 dicom2005 (0072,0704) CS PseudoColorType 1 dicom2005 (0072,0706) CS ShowGrayscaleInverted 1 dicom2005 (0072,0710) CS ShowImageTrueSizeFlag 1 dicom2005 (0072,0712) CS ShowGraphicAnnotationFlag 1 dicom2005 (0072,0714) CS ShowPatientDemographicsFlag 1 dicom2005 (0072,0716) CS ShowAcquisitionTechniquesFlag 1 dicom2005 (0088,0000) UL StorageGroupLength 1 dicom98 (0088,0130) SH StorageMediaFileSetID 1 dicom98 (0088,0140) UI StorageMediaFileSetUID 1 dicom98 (0088,0200) SQ IconImageSequence 1 dicom98 (0088,0904) LO TopicTitle 1 dicom98 (0088,0906) ST TopicSubject 1 dicom98 (0088,0910) LO TopicAuthor 1 dicom98 (0088,0912) LO TopicKeyWords 1-32 dicom98 (0100,0000) UL AuthorizationGroupLength 1 dicom2000 (0100,0410) CS SOPInstanceStatus 1 dicom2000 (0100,0420) DT SOPAuthorizationDateAndTime 1 dicom2000 (0100,0424) LT SOPAuthorizationComment 1 dicom2000 (0100,0426) LO AuthorizationEquipmentCertificationNumber 1 dicom2000 (0400,0000) UL DigitalSignatureGroupLength 1 dicom2001 (0400,0005) US MACIDNumber 1 dicom2001 (0400,0010) UI MACCalculationTransferSyntaxUID 1 dicom2001 (0400,0015) CS MACAlgorithm 1 dicom2001 (0400,0020) AT DataElementsSigned 1-n dicom2001 (0400,0100) UI DigitalSignatureUID 1 dicom2001 (0400,0105) DT DigitalSignatureDateTime 1 dicom2001 (0400,0110) CS CertificateType 1 dicom2001 (0400,0115) OB CertificateOfSigner 1 dicom2001 (0400,0120) OB Signature 1 dicom2001 (0400,0305) CS CertifiedTimestampType 1 dicom2001 (0400,0310) OB CertifiedTimestamp 1 dicom2001 (0400,0401) SQ DigitalSignaturePurposeCodeSequence 1 dicom2005 (0400,0402) SQ ReferencedDigitalSignatureSequence 1 dicom2005 (0400,0403) SQ ReferencedSOPInstanceMACSequence 1 dicom2005 (0400,0404) OB MAC 1 dicom2005 (0400,0500) SQ EncryptedAttributesSequence 1 dicom2003 (0400,0510) UI EncryptedContentTransferSyntaxUID 1 dicom2003 (0400,0520) OB EncryptedContent 1 dicom2003 (0400,0550) SQ ModifiedAttributesSequence 1 dicom2003 (2000,0000) UL FilmSessionGroupLength 1 dicom98 (2000,0010) IS NumberOfCopies 1 dicom98 (2000,001E) SQ PrinterConfigurationSequence 1 dicom99 (2000,0020) CS PrintPriority 1 dicom98 (2000,0030) CS MediumType 1 dicom98 (2000,0040) CS FilmDestination 1 dicom98 (2000,0050) LO FilmSessionLabel 1 dicom98 (2000,0060) IS MemoryAllocation 1 dicom98 # MaximumMemoryAllocation is corrected in CP 164, was (2000,0062) in Supp37 which is already in use. (2000,0061) IS MaximumMemoryAllocation 1 dicom99 (2000,0062) CS ColorImagePrintingFlag 1 dicom98 (2000,0063) CS CollationFlag 1 dicom98 (2000,0065) CS AnnotationFlag 1 dicom98 (2000,0067) CS ImageOverlayFlag 1 dicom98 (2000,0069) CS PresentationLUTFlag 1 dicom98 (2000,006A) CS ImageBoxPresentationLUTFlag 1 dicom98 (2000,00A0) US MemoryBitDepth 1 dicom99 (2000,00A1) US PrintingBitDepth 1 dicom99 (2000,00A2) SQ MediaInstalledSequence 1 dicom99 (2000,00A4) SQ OtherMediaAvailableSequence 1 dicom99 (2000,00A8) SQ SupportedImageDisplayFormatsSequence 1 dicom99 (2000,0500) SQ ReferencedFilmBoxSequence 1 dicom98 (2000,0510) SQ ReferencedStoredPrintSequence 1 dicom98 (2010,0000) UL FilmBoxGroupLength 1 dicom98 (2010,0010) ST ImageDisplayFormat 1 dicom98 (2010,0030) CS AnnotationDisplayFormatID 1 dicom98 (2010,0040) CS FilmOrientation 1 dicom98 (2010,0050) CS FilmSizeID 1 dicom98 (2010,0052) CS PrinterResolutionID 1 dicom99 (2010,0054) CS DefaultPrinterResolutionID 1 dicom99 (2010,0060) CS MagnificationType 1 dicom98 (2010,0080) CS SmoothingType 1 dicom98 (2010,00A6) CS DefaultMagnificationType 1 dicom99 (2010,00A7) CS OtherMagnificationTypesAvailable 1-n dicom99 (2010,00A8) CS DefaultSmoothingType 1 dicom99 (2010,00A9) CS OtherSmoothingTypesAvailable 1-n dicom99 (2010,0100) CS BorderDensity 1 dicom98 (2010,0110) CS EmptyImageDensity 1 dicom98 (2010,0120) US MinDensity 1 dicom98 (2010,0130) US MaxDensity 1 dicom98 (2010,0140) CS Trim 1 dicom98 (2010,0150) ST ConfigurationInformation 1 dicom98 (2010,0152) LT ConfigurationInformationDescription 1 dicom99 (2010,0154) IS MaximumCollatedFilms 1 dicom99 (2010,015E) US Illumination 1 dicom98 (2010,0160) US ReflectedAmbientLight 1 dicom98 (2010,0376) DS PrinterPixelSpacing 2 dicom99 (2010,0500) SQ ReferencedFilmSessionSequence 1 dicom98 (2010,0510) SQ ReferencedImageBoxSequence 1 dicom98 (2010,0520) SQ ReferencedBasicAnnotationBoxSequence 1 dicom98 (2020,0000) UL ImageBoxGroupLength 1 dicom98 (2020,0010) US ImagePosition 1 dicom98 (2020,0020) CS Polarity 1 dicom98 (2020,0030) DS RequestedImageSize 1 dicom98 (2020,0040) CS RequestedDecimateCropBehavior 1 dicom99 (2020,0050) CS RequestedResolutionID 1 dicom99 (2020,00A0) CS RequestedImageSizeFlag 1 dicom99 (2020,00A2) CS DecimateCropResult 1 dicom99 # name for (2020,0110) was PreformattedGrayscaleImageSequence in DICOM96. Name changed to BasicGrayscaleImageSequence in DICOM98. (2020,0110) SQ BasicGrayscaleImageSequence 1 dicom98 # name for (2020,0110) was PreformattedColorImageSequence in DICOM96. Name changed to BasicColorImageSequence in DICOM98. (2020,0111) SQ BasicColorImageSequence 1 dicom98 (2030,0000) UL AnnotationGroupLength 1 dicom98 (2030,0010) US AnnotationPosition 1 dicom98 (2030,0020) LO TextString 1 dicom98 (2040,0000) UL OverlayBoxGroupLength 1 dicom98 (2040,0010) SQ ReferencedOverlayPlaneSequence 1 dicom98 (2040,0011) US ReferencedOverlayPlaneGroups 1-99 dicom98 (2040,0020) SQ OverlayPixelDataSequence 1 dicom99 (2040,0060) CS OverlayMagnificationType 1 dicom98 (2040,0070) CS OverlaySmoothingType 1 dicom98 (2040,0072) CS OverlayOrImageMagnification 1 dicom99 (2040,0074) US MagnifyToNumberOfColumns 1 dicom99 (2040,0080) CS OverlayForegroundDensity 1 dicom98 (2040,0082) CS OverlayBackgroundDensity 1 dicom99 (2040,0090) CS OverlayMode 1 dicom98 (2040,0100) CS ThresholdDensity 1 dicom98 (2050,0000) UL PresentationLUTGroupLength 1 dicom98 (2050,0010) SQ PresentationLUTSequence 1 dicom98 (2050,0020) CS PresentationLUTShape 1 dicom98 (2050,0500) SQ ReferencedPresentationLUTSequence 1 dicom98 (2100,0000) UL PrintJobGroupLength 1 dicom98 (2100,0010) SH PrintJobID 1 dicom98 (2100,0020) CS ExecutionStatus 1 dicom98 (2100,0030) CS ExecutionStatusInfo 1 dicom98 (2100,0040) DA CreationDate 1 dicom98 (2100,0050) TM CreationTime 1 dicom98 (2100,0070) AE Originator 1 dicom98 (2100,0140) AE DestinationAE 1 dicom98 (2100,0160) SH OwnerID 1 dicom98 (2100,0170) IS NumberOfFilms 1 dicom98 (2100,0500) SQ ReferencedPrintJobSequence 1 dicom98 (2110,0000) UL PrinterGroupLength 1 dicom98 (2110,0010) CS PrinterStatus 1 dicom98 (2110,0020) CS PrinterStatusInfo 1 dicom98 (2110,0030) LO PrinterName 1 dicom98 (2110,0099) SH PrintQueueID 1 dicom98 (2120,0000) UL QueueGroupLength 1 dicom98 (2120,0010) CS QueueStatus 1 dicom98 (2120,0050) SQ PrintJobDescriptionSequence 1 dicom98 # (2120,0070) is called ReferencedPrintJobSequence in the standard, but this collides with tag (2100,0500) (2120,0070) SQ QueueReferencedPrintJobSequence 1 dicom98 (2130,0000) UL PrintContentGroupLength 1 dicom98 (2130,0010) SQ PrintManagementCapabilitiesSequence 1 dicom98 (2130,0015) SQ PrinterCharacteristicsSequence 1 dicom98 (2130,0030) SQ FilmBoxContentSequence 1 dicom98 (2130,0040) SQ ImageBoxContentSequence 1 dicom98 (2130,0050) SQ AnnotationContentSequence 1 dicom98 (2130,0060) SQ ImageOverlayBoxContentSequence 1 dicom98 (2130,0080) SQ PresentationLUTContentSequence 1 dicom98 (2130,00A0) SQ ProposedStudySequence 1 dicom98 (2130,00C0) SQ OriginalImageSequence 1 dicom98 (2200,0000) UL MediaCreationGroupLength 1 dicom2004 (2200,0001) CS LabelUsingInformationExtractedFromInstances 1 dicom2004 (2200,0002) UT LabelText 1 dicom2004 (2200,0003) CS LabelStyleSelection 1 dicom2004 (2200,0004) LT MediaDisposition 1 dicom2004 (2200,0005) LT BarcodeValue 1 dicom2004 (2200,0006) CS BarcodeSymbology 1 dicom2004 (2200,0007) CS AllowMediaSplitting 1 dicom2004 (2200,0008) CS IncludeNon-DICOMObjects 1 dicom2004 (2200,0009) CS IncludeDisplayApplication 1 dicom2004 (2200,000A) CS PreserveCompositeInstancesAfterMediaCreation 1 dicom2004 (2200,000B) US TotalNumberOfPiecesOfMediaCreated 1 dicom2004 (2200,000C) LO RequestedMediaApplicationProfile 1 dicom2004 (2200,000D) SQ ReferencedStorageMediaSequence 1 dicom2004 (2200,000E) AT FailureAttributes 1-n dicom2004 (2200,000F) CS AllowLossyCompression 1 dicom2004 (2200,0020) CS RequestPriority 1 dicom2004 (3002,0000) UL RTImageGroupLength 1 dicom98 (3002,0002) SH RTImageLabel 1 dicom98 (3002,0003) LO RTImageName 1 dicom98 (3002,0004) ST RTImageDescription 1 dicom98 (3002,000A) CS ReportedValuesOrigin 1 dicom98 (3002,000C) CS RTImagePlane 1 dicom98 (3002,000D) DS XRayImageReceptorTranslation 3 dicom2000 (3002,000E) DS XRayImageReceptorAngle 1 dicom98 (3002,0010) DS RTImageOrientation 6 dicom98 (3002,0011) DS ImagePlanePixelSpacing 2 dicom98 (3002,0012) DS RTImagePosition 2 dicom98 (3002,0020) SH RadiationMachineName 1 dicom98 (3002,0022) DS RadiationMachineSAD 1 dicom98 (3002,0024) DS RadiationMachineSSD 1 dicom98 (3002,0026) DS RTImageSID 1 dicom98 (3002,0028) DS SourceToReferenceObjectDistance 1 dicom98 (3002,0029) IS FractionNumber 1 dicom98 (3002,0030) SQ ExposureSequence 1 dicom98 (3002,0032) DS MetersetExposure 1 dicom98 (3002,0034) DS DiaphragmPosition 4 dicom2001 (3002,0040) SQ FluenceeMapSequence 1 dicom2004 (3002,0041) CS FluenceDataSource 1 dicom2004 (3002,0042) DS FluenceDataScale 1 dicom2004 (3004,0000) UL RTDoseGroupLength 1 dicom98 (3004,0001) CS DVHType 1 dicom98 (3004,0002) CS DoseUnits 1 dicom98 (3004,0004) CS DoseType 1 dicom98 (3004,0006) LO DoseComment 1 dicom98 (3004,0008) DS NormalizationPoint 3 dicom98 (3004,000A) CS DoseSummationType 1 dicom98 (3004,000C) DS GridFrameOffsetVector 2-n dicom98 (3004,000E) DS DoseGridScaling 1 dicom98 (3004,0010) SQ RTDoseROISequence 1 dicom98 (3004,0012) DS DoseValue 1 dicom98 (3004,0014) CS TissueHeterogeneityCorrection 1-3 dicom2004 (3004,0040) DS DVHNormalizationPoint 3 dicom98 (3004,0042) DS DVHNormalizationDoseValue 1 dicom98 (3004,0050) SQ DVHSequence 1 dicom98 (3004,0052) DS DVHDoseScaling 1 dicom98 (3004,0054) CS DVHVolumeUnits 1 dicom98 (3004,0056) IS DVHNumberOfBins 1 dicom98 (3004,0058) DS DVHData 2-2n dicom98 (3004,0060) SQ DVHReferencedROISequence 1 dicom98 (3004,0062) CS DVHROIContributionType 1 dicom98 (3004,0070) DS DVHMinimumDose 1 dicom98 (3004,0072) DS DVHMaximumDose 1 dicom98 (3004,0074) DS DVHMeanDose 1 dicom98 (3006,0000) UL RTStructureSetGroupLength 1 dicom98 (3006,0002) SH StructureSetLabel 1 dicom98 (3006,0004) LO StructureSetName 1 dicom98 (3006,0006) ST StructureSetDescription 1 dicom98 (3006,0008) DA StructureSetDate 1 dicom98 (3006,0009) TM StructureSetTime 1 dicom98 (3006,0010) SQ ReferencedFrameOfReferenceSequence 1 dicom98 (3006,0012) SQ RTReferencedStudySequence 1 dicom98 (3006,0014) SQ RTReferencedSeriesSequence 1 dicom98 (3006,0016) SQ ContourImageSequence 1 dicom98 (3006,0020) SQ StructureSetROISequence 1 dicom98 (3006,0022) IS ROINumber 1 dicom98 (3006,0024) UI ReferencedFrameOfReferenceUID 1 dicom98 (3006,0026) LO ROIName 1 dicom98 (3006,0028) ST ROIDescription 1 dicom98 (3006,002A) IS ROIDisplayColor 3 dicom98 (3006,002C) DS ROIVolume 1 dicom98 (3006,0030) SQ RTRelatedROISequence 1 dicom98 (3006,0033) CS RTROIRelationship 1 dicom98 (3006,0036) CS ROIGenerationAlgorithm 1 dicom98 (3006,0038) LO ROIGenerationDescription 1 dicom98 (3006,0039) SQ ROIContourSequence 1 dicom98 (3006,0040) SQ ContourSequence 1 dicom98 (3006,0042) CS ContourGeometricType 1 dicom98 (3006,0044) DS ContourSlabThickness 1 dicom98 (3006,0045) DS ContourOffsetVector 3 dicom98 (3006,0046) IS NumberOfContourPoints 1 dicom98 (3006,0048) IS ContourNumber 1 dicom2000 (3006,0049) IS AttachedContours 1-n dicom2000 (3006,0050) DS ContourData 3-3n dicom98 (3006,0080) SQ RTROIObservationsSequence 1 dicom98 (3006,0082) IS ObservationNumber 1 dicom98 (3006,0084) IS ReferencedROINumber 1 dicom98 (3006,0085) SH ROIObservationLabel 1 dicom98 (3006,0086) SQ RTROIIdentificationCodeSequence 1 dicom98 (3006,0088) ST ROIObservationDescription 1 dicom98 (3006,00A0) SQ RelatedRTROIObservationsSequence 1 dicom98 (3006,00A4) CS RTROIInterpretedType 1 dicom98 (3006,00A6) PN ROIInterpreter 1 dicom98 (3006,00B0) SQ ROIPhysicalPropertiesSequence 1 dicom98 (3006,00B2) CS ROIPhysicalProperty 1 dicom98 (3006,00B4) DS ROIPhysicalPropertyValue 1 dicom98 (3006,00C0) SQ FrameOfReferenceRelationshipSequence 1 dicom98 (3006,00C2) UI RelatedFrameOfReferenceUID 1 dicom98 (3006,00C4) CS FrameOfReferenceTransformationType 1 dicom98 (3006,00C6) DS FrameOfReferenceTransformationMatrix 16 dicom98 (3006,00C8) LO FrameOfReferenceTransformationComment 1 dicom98 (3008,0000) UL RTTreatmentGroupLength 1 dicom99 (3008,0010) SQ MeasuredDoseReferenceSequence 1 dicom99 (3008,0012) ST MeasuredDoseDescription 1 dicom99 (3008,0014) CS MeasuredDoseType 1 dicom99 (3008,0016) DS MeasuredDoseValue 1 dicom99 (3008,0020) SQ TreatmentSessionBeamSequence 1 dicom99 (3008,0022) IS CurrentFractionNumber 1 dicom99 (3008,0024) DA TreatmentControlPointDate 1 dicom99 (3008,0025) TM TreatmentControlPointTime 1 dicom99 (3008,002A) CS TreatmentTerminationStatus 1 dicom99 (3008,002B) SH TreatmentTerminationCode 1 dicom99 (3008,002C) CS TreatmentVerificationStatus 1 dicom99 (3008,0030) SQ ReferencedTreatmentRecordSequence 1 dicom99 (3008,0032) DS SpecifiedPrimaryMeterset 1 dicom99 (3008,0033) DS SpecifiedSecondaryMeterset 1 dicom99 (3008,0036) DS DeliveredPrimaryMeterset 1 dicom99 (3008,0037) DS DeliveredSecondaryMeterset 1 dicom99 (3008,003A) DS SpecifiedTreatmentTime 1 dicom99 (3008,003B) DS DeliveredTreatmentTime 1 dicom99 (3008,0040) SQ ControlPointDeliverySequence 1 dicom99 (3008,0042) DS SpecifiedMeterset 1 dicom99 (3008,0044) DS DeliveredMeterset 1 dicom99 (3008,0048) DS DoseRateDelivered 1 dicom99 (3008,0050) SQ TreatmentSummaryCalculatedDoseReferenceSequence 1 dicom99 (3008,0052) DS CumulativeDoseToDoseReference 1 dicom99 (3008,0054) DA FirstTreatmentDate 1 dicom99 (3008,0056) DA MostRecentTreatmentDate 1 dicom99 (3008,005A) IS NumberOfFractionsDelivered 1 dicom99 (3008,0060) SQ OverrideSequence 1 dicom99 (3008,0062) AT OverrideParameterPointer 1 dicom99 (3008,0064) IS MeasuredDoseReferenceNumber 1 dicom99 (3008,0066) ST OverrideReason 1 dicom99 (3008,0070) SQ CalculatedDoseReferenceSequence 1 dicom99 (3008,0072) IS CalculatedDoseReferenceNumber 1 dicom99 (3008,0074) ST CalculatedDoseReferenceDescription 1 dicom99 (3008,0076) DS CalculatedDoseReferenceDoseValue 1 dicom99 (3008,0078) DS StartMeterset 1 dicom99 (3008,007A) DS EndMeterset 1 dicom99 (3008,0080) SQ ReferencedMeasuredDoseReferenceSequence 1 dicom99 (3008,0082) IS ReferencedMeasuredDoseReferenceNumber 1 dicom99 (3008,0090) SQ ReferencedCalculatedDoseReferenceSequence 1 dicom99 (3008,0092) IS ReferencedCalculatedDoseReferenceNumber 1 dicom99 (3008,00A0) SQ BeamLimitingDeviceLeafPairsSequence 1 dicom99 (3008,00B0) SQ RecordedWedgeSequence 1 dicom99 (3008,00C0) SQ RecordedCompensatorSequence 1 dicom99 (3008,00D0) SQ RecordedBlockSequence 1 dicom99 (3008,00E0) SQ TreatmentSummaryMeasuredDoseReferenceSequence 1 dicom99 (3008,0100) SQ RecordedSourceSequence 1 dicom99 (3008,0105) LO SourceSerialNumber 1 dicom99 (3008,0110) SQ TreatmentSessionApplicationSetupSequence 1 dicom99 (3008,0116) CS ApplicationSetupCheck 1 dicom99 (3008,0120) SQ RecordedBrachyAccessoryDeviceSequence 1 dicom99 (3008,0122) IS ReferencedBrachyAccessoryDeviceNumber 1 dicom99 (3008,0130) SQ RecordedChannelSequence 1 dicom99 (3008,0132) DS SpecifiedChannelTotalTime 1 dicom99 (3008,0134) DS DeliveredChannelTotalTime 1 dicom99 (3008,0136) IS SpecifiedNumberOfPulses 1 dicom99 (3008,0138) IS DeliveredNumberOfPulses 1 dicom99 (3008,013A) DS SpecifiedPulseRepetitionInterval 1 dicom99 (3008,013C) DS DeliveredPulseRepetitionInterval 1 dicom99 (3008,0140) SQ RecordedSourceApplicatorSequence 1 dicom99 (3008,0142) IS ReferencedSourceApplicatorNumber 1 dicom99 (3008,0150) SQ RecordedChannelShieldSequence 1 dicom99 (3008,0152) IS ReferencedChannelShieldNumber 1 dicom99 (3008,0160) SQ BrachyControlPointDeliveredSequence 1 dicom99 (3008,0162) DA SafePositionExitDate 1 dicom99 (3008,0164) TM SafePositionExitTime 1 dicom99 (3008,0166) DA SafePositionReturnDate 1 dicom99 (3008,0168) TM SafePositionReturnTime 1 dicom99 (3008,0200) CS CurrentTreatmentStatus 1 dicom99 (3008,0202) ST TreatmentStatusComment 1 dicom99 (3008,0220) SQ FractionGroupSummarySequence 1 dicom99 (3008,0223) IS ReferencedFractionNumber 1 dicom99 (3008,0224) CS FractionGroupType 1 dicom99 (3008,0230) CS BeamStopperPosition 1 dicom99 (3008,0240) SQ FractionStatusSummarySequence 1 dicom99 (3008,0250) DA TreatmentDate 1 dicom99 (3008,0251) TM TreatmentTime 1 dicom99 (300A,0000) UL RTPlanGroupLength 1 dicom98 (300A,0002) SH RTPlanLabel 1 dicom98 (300A,0003) LO RTPlanName 1 dicom98 (300A,0004) ST RTPlanDescription 1 dicom98 (300A,0006) DA RTPlanDate 1 dicom98 (300A,0007) TM RTPlanTime 1 dicom98 (300A,0009) LO TreatmentProtocols 1-n dicom98 # Name was TreatmentIntent (dicom98) changed in CPack 33 (dicom2005) (300A,000A) CS PlanIntent 1 dicom2005 (300A,000B) LO TreatmentSites 1-n dicom98 (300A,000C) CS RTPlanGeometry 1 dicom98 (300A,000E) ST PrescriptionDescription 1 dicom98 (300A,0010) SQ DoseReferenceSequence 1 dicom98 (300A,0012) IS DoseReferenceNumber 1 dicom98 (300A,0013) LO DoseReferenceUID 1 dicom2004 (300A,0014) CS DoseReferenceStructureType 1 dicom98 (300A,0015) CS NominalBeamEnergyUnit 1 dicom99 (300A,0016) LO DoseReferenceDescription 1 dicom98 (300A,0018) DS DoseReferencePointCoordinates 3 dicom98 (300A,001A) DS NominalPriorDose 1 dicom98 (300A,0020) CS DoseReferenceType 1 dicom98 (300A,0021) DS ConstraintWeight 1 dicom98 (300A,0022) DS DeliveryWarningDose 1 dicom98 (300A,0023) DS DeliveryMaximumDose 1 dicom98 (300A,0025) DS TargetMinimumDose 1 dicom98 (300A,0026) DS TargetPrescriptionDose 1 dicom98 (300A,0027) DS TargetMaximumDose 1 dicom98 (300A,0028) DS TargetUnderdoseVolumeFraction 1 dicom98 (300A,002A) DS OrganAtRiskFullVolumeDose 1 dicom98 (300A,002B) DS OrganAtRiskLimitDose 1 dicom98 (300A,002C) DS OrganAtRiskMaximumDose 1 dicom98 (300A,002D) DS OrganAtRiskOverdoseVolumeFraction 1 dicom98 (300A,0040) SQ ToleranceTableSequence 1 dicom98 (300A,0042) IS ToleranceTableNumber 1 dicom98 (300A,0043) SH ToleranceTableLabel 1 dicom98 (300A,0044) DS GantryAngleTolerance 1 dicom98 (300A,0046) DS BeamLimitingDeviceAngleTolerance 1 dicom98 (300A,0048) SQ BeamLimitingDeviceToleranceSequence 1 dicom98 (300A,004A) DS BeamLimitingDevicePositionTolerance 1 dicom98 (300A,004C) DS PatientSupportAngleTolerance 1 dicom98 (300A,004E) DS TableTopEccentricAngleTolerance 1 dicom98 (300A,0051) DS TableTopVerticalPositionTolerance 1 dicom98 (300A,0052) DS TableTopLongitudinalPositionTolerance 1 dicom98 (300A,0053) DS TableTopLateralPositionTolerance 1 dicom98 (300A,0055) CS RTPlanRelationship 1 dicom98 (300A,0070) SQ FractionGroupSequence 1 dicom98 (300A,0071) IS FractionGroupNumber 1 dicom98 (300A,0072) LO FractionGroupDescription 1 dicom2004 (300A,0078) IS NumberOfFractionsPlanned 1 dicom98 # Name changed in CP 210, name was NumberOfFractionsPerDay before (300A,0079) IS NumberOfFractionPatternDigitsPerDay 1 dicom2001 (300A,007A) IS RepeatFractionCycleLength 1 dicom98 (300A,007B) LT FractionPattern 1 dicom98 (300A,0080) IS NumberOfBeams 1 dicom98 (300A,0082) DS BeamDoseSpecificationPoint 3 dicom98 (300A,0084) DS BeamDose 1 dicom98 (300A,0086) DS BeamMeterset 1 dicom98 (300A,00A0) IS NumberOfBrachyApplicationSetups 1 dicom98 (300A,00A2) DS BrachyApplicationSetupDoseSpecificationPoint 3 dicom98 (300A,00A4) DS BrachyApplicationSetupDose 1 dicom98 (300A,00B0) SQ BeamSequence 1 dicom98 (300A,00B2) SH TreatmentMachineName 1 dicom98 (300A,00B3) CS PrimaryDosimeterUnit 1 dicom98 (300A,00B4) DS SourceAxisDistance 1 dicom98 (300A,00B6) SQ BeamLimitingDeviceSequence 1 dicom98 (300A,00B8) CS RTBeamLimitingDeviceType 1 dicom98 (300A,00BA) DS SourceToBeamLimitingDeviceDistance 1 dicom98 (300A,00BC) IS NumberOfLeafJawPairs 1 dicom98 (300A,00BE) DS LeafPositionBoundaries 3-n dicom98 (300A,00C0) IS BeamNumber 1 dicom98 (300A,00C2) LO BeamName 1 dicom98 (300A,00C3) ST BeamDescription 1 dicom98 (300A,00C4) CS BeamType 1 dicom98 (300A,00C6) CS RadiationType 1 dicom98 (300A,00C7) CS HighDoseTechniqueType 1 dicom2001 (300A,00C8) IS ReferenceImageNumber 1 dicom98 (300A,00CA) SQ PlannedVerificationImageSequence 1 dicom98 (300A,00CC) LO ImagingDeviceSpecificAcquisitionParameters 1-n dicom98 (300A,00CE) CS TreatmentDeliveryType 1 dicom98 (300A,00D0) IS NumberOfWedges 1 dicom98 (300A,00D1) SQ WedgeSequence 1 dicom98 (300A,00D2) IS WedgeNumber 1 dicom98 (300A,00D3) CS WedgeType 1 dicom98 (300A,00D4) SH WedgeID 1 dicom98 (300A,00D5) IS WedgeAngle 1 dicom98 (300A,00D6) DS WedgeFactor 1 dicom98 (300A,00D8) DS WedgeOrientation 1 dicom98 (300A,00DA) DS SourceToWedgeTrayDistance 1 dicom98 (300A,00DC) SH BolusID 1 dicom2005 (300A,00DD) ST BolusDescription 1 dicom2005 (300A,00E0) IS NumberOfCompensators 1 dicom98 (300A,00E1) SH MaterialID 1 dicom98 (300A,00E2) DS TotalCompensatorTrayFactor 1 dicom98 (300A,00E3) SQ CompensatorSequence 1 dicom98 (300A,00E4) IS CompensatorNumber 1 dicom98 (300A,00E5) SH CompensatorID 1 dicom98 (300A,00E6) DS SourceToCompensatorTrayDistance 1 dicom98 (300A,00E7) IS CompensatorRows 1 dicom98 (300A,00E8) IS CompensatorColumns 1 dicom98 (300A,00E9) DS CompensatorPixelSpacing 2 dicom98 (300A,00EA) DS CompensatorPosition 2 dicom98 (300A,00EB) DS CompensatorTransmissionData 1-n dicom98 (300A,00EC) DS CompensatorThicknessData 1-n dicom98 (300A,00ED) IS NumberOfBoli 1 dicom98 (300A,00EE) CS CompensatorType 1 dicom99 (300A,00F0) IS NumberOfBlocks 1 dicom98 (300A,00F2) DS TotalBlockTrayFactor 1 dicom98 (300A,00F4) SQ BlockSequence 1 dicom98 (300A,00F5) SH BlockTrayID 1 dicom98 (300A,00F6) DS SourceToBlockTrayDistance 1 dicom98 (300A,00F8) CS BlockType 1 dicom98 (300A,00FA) CS BlockDivergence 1 dicom98 (300A,00FB) CS BlockMountingPosition 1 dicom2003 (300A,00FC) IS BlockNumber 1 dicom98 (300A,00FE) LO BlockName 1 dicom98 (300A,0100) DS BlockThickness 1 dicom98 (300A,0102) DS BlockTransmission 1 dicom98 (300A,0104) IS BlockNumberOfPoints 1 dicom98 (300A,0106) DS BlockData 2-2n dicom98 (300A,0107) SQ ApplicatorSequence 1 dicom98 (300A,0108) SH ApplicatorID 1 dicom98 (300A,0109) CS ApplicatorType 1 dicom98 (300A,010A) LO ApplicatorDescription 1 dicom98 (300A,010C) DS CumulativeDoseReferenceCoefficient 1 dicom98 (300A,010E) DS FinalCumulativeMetersetWeight 1 dicom98 (300A,0110) IS NumberOfControlPoints 1 dicom98 (300A,0111) SQ ControlPointSequence 1 dicom98 (300A,0112) IS ControlPointIndex 1 dicom98 (300A,0114) DS NominalBeamEnergy 1 dicom98 (300A,0115) DS DoseRateSet 1 dicom98 (300A,0116) SQ WedgePositionSequence 1 dicom98 (300A,0118) CS WedgePosition 1 dicom98 (300A,011A) SQ BeamLimitingDevicePositionSequence 1 dicom98 (300A,011C) DS LeafJawPositions 2-2n dicom98 (300A,011E) DS GantryAngle 1 dicom98 (300A,011F) CS GantryRotationDirection 1 dicom98 (300A,0120) DS BeamLimitingDeviceAngle 1 dicom98 (300A,0121) CS BeamLimitingDeviceRotationDirection 1 dicom98 (300A,0122) DS PatientSupportAngle 1 dicom98 (300A,0123) CS PatientSupportRotationDirection 1 dicom98 (300A,0124) DS TableTopEccentricAxisDistance 1 dicom98 (300A,0125) DS TableTopEccentricAngle 1 dicom98 (300A,0126) CS TableTopEccentricRotationDirection 1 dicom98 (300A,0128) DS TableTopVerticalPosition 1 dicom98 (300A,0129) DS TableTopLongitudinalPosition 1 dicom98 (300A,012A) DS TableTopLateralPosition 1 dicom98 (300A,012C) DS IsocenterPosition 3 dicom98 (300A,012E) DS SurfaceEntryPoint 3 dicom98 (300A,0130) DS SourceToSurfaceDistance 1 dicom98 (300A,0134) DS CumulativeMetersetWeight 1 dicom98 (300A,0180) SQ PatientSetupSequence 1 dicom98 (300A,0182) IS PatientSetupNumber 1 dicom98 (300A,0183) LO PatientSetupLabel 1 dicom2005 (300A,0184) LO PatientAdditionalPosition 1 dicom98 (300A,0190) SQ FixationDeviceSequence 1 dicom98 (300A,0192) CS FixationDeviceType 1 dicom98 (300A,0194) SH FixationDeviceLabel 1 dicom98 (300A,0196) ST FixationDeviceDescription 1 dicom98 (300A,0198) SH FixationDevicePosition 1 dicom98 (300A,0199) FL FixationDevicePitchAngle 1 dicom2005 (300A,019A) FL FixationDeviceRollAngle 1 dicom2005 (300A,01A0) SQ ShieldingDeviceSequence 1 dicom98 (300A,01A2) CS ShieldingDeviceType 1 dicom98 (300A,01A4) SH ShieldingDeviceLabel 1 dicom98 (300A,01A6) ST ShieldingDeviceDescription 1 dicom98 (300A,01A8) SH ShieldingDevicePosition 1 dicom98 (300A,01B0) CS SetupTechnique 1 dicom98 (300A,01B2) ST SetupTechniqueDescription 1 dicom98 (300A,01B4) SQ SetupDeviceSequence 1 dicom98 (300A,01B6) CS SetupDeviceType 1 dicom98 (300A,01B8) SH SetupDeviceLabel 1 dicom98 (300A,01BA) ST SetupDeviceDescription 1 dicom98 (300A,01BC) DS SetupDeviceParameter 1 dicom98 (300A,01D0) ST SetupReferenceDescription 1 dicom98 (300A,01D2) DS TableTopVerticalSetupDisplacement 1 dicom98 (300A,01D4) DS TableTopLongitudinalSetupDisplacement 1 dicom98 (300A,01D6) DS TableTopLateralSetupDisplacement 1 dicom98 (300A,0200) CS BrachyTreatmentTechnique 1 dicom98 (300A,0202) CS BrachyTreatmentType 1 dicom98 (300A,0206) SQ TreatmentMachineSequence 1 dicom98 (300A,0210) SQ SourceSequence 1 dicom98 (300A,0212) IS SourceNumber 1 dicom98 (300A,0214) CS SourceType 1 dicom98 (300A,0216) LO SourceManufacturer 1 dicom98 (300A,0218) DS ActiveSourceDiameter 1 dicom98 (300A,021A) DS ActiveSourceLength 1 dicom98 (300A,0222) DS SourceEncapsulationNominalThickness 1 dicom98 (300A,0224) DS SourceEncapsulationNominalTransmission 1 dicom98 (300A,0226) LO SourceIsotopeName 1 dicom98 (300A,0228) DS SourceIsotopeHalfLife 1 dicom98 (300A,022A) DS ReferenceAirKermaRate 1 dicom98 (300A,022C) DA AirKermaRateReferenceDate 1 dicom98 (300A,022E) TM AirKermaRateReferenceTime 1 dicom98 (300A,0230) SQ ApplicationSetupSequence 1 dicom98 (300A,0232) CS ApplicationSetupType 1 dicom98 (300A,0234) IS ApplicationSetupNumber 1 dicom98 (300A,0236) LO ApplicationSetupName 1 dicom98 (300A,0238) LO ApplicationSetupManufacturer 1 dicom98 (300A,0240) IS TemplateNumber 1 dicom98 (300A,0242) SH TemplateType 1 dicom98 (300A,0244) LO TemplateName 1 dicom98 (300A,0250) DS TotalReferenceAirKerma 1 dicom98 (300A,0260) SQ BrachyAccessoryDeviceSequence 1 dicom98 (300A,0262) IS BrachyAccessoryDeviceNumber 1 dicom98 (300A,0263) SH BrachyAccessoryDeviceID 1 dicom98 (300A,0264) CS BrachyAccessoryDeviceType 1 dicom98 (300A,0266) LO BrachyAccessoryDeviceName 1 dicom98 (300A,026A) DS BrachyAccessoryDeviceNominalThickness 1 dicom98 (300A,026C) DS BrachyAccessoryDeviceNominalTransmission 1 dicom98 (300A,0280) SQ ChannelSequence 1 dicom98 (300A,0282) IS ChannelNumber 1 dicom98 (300A,0284) DS ChannelLength 1 dicom98 (300A,0286) DS ChannelTotalTime 1 dicom98 (300A,0288) CS SourceMovementType 1 dicom98 (300A,028A) IS NumberOfPulses 1 dicom98 (300A,028C) DS PulseRepetitionInterval 1 dicom98 (300A,0290) IS SourceApplicatorNumber 1 dicom98 (300A,0291) SH SourceApplicatorID 1 dicom98 (300A,0292) CS SourceApplicatorType 1 dicom98 (300A,0294) LO SourceApplicatorName 1 dicom98 (300A,0296) DS SourceApplicatorLength 1 dicom98 (300A,0298) LO SourceApplicatorManufacturer 1 dicom98 (300A,029C) DS SourceApplicatorWallNominalThickness 1 dicom98 (300A,029E) DS SourceApplicatorWallNominalTransmission 1 dicom98 (300A,02A0) DS SourceApplicatorStepSize 1 dicom98 (300A,02A2) IS TransferTubeNumber 1 dicom98 (300A,02A4) DS TransferTubeLength 1 dicom98 (300A,02B0) SQ ChannelShieldSequence 1 dicom98 (300A,02B2) IS ChannelShieldNumber 1 dicom98 (300A,02B3) SH ChannelShieldID 1 dicom98 (300A,02B4) LO ChannelShieldName 1 dicom98 (300A,02B8) DS ChannelShieldNominalThickness 1 dicom98 (300A,02BA) DS ChannelShieldNominalTransmission 1 dicom98 (300A,02C8) DS FinalCumulativeTimeWeight 1 dicom98 (300A,02D0) SQ BrachyControlPointSequence 1 dicom98 (300A,02D2) DS ControlPointRelativePosition 1 dicom98 (300A,02D4) DS ControlPoint3DPosition 3 dicom98 (300A,02D6) DS CumulativeTimeWeight 1 dicom98 (300A,02E0) CS CompensatorDivergence 1 dicom2003 (300A,02E1) CS CompensatorMountingPosition 1 dicom2003 (300A,02E2) DS SourceToCompensatorDistance 1-n dicom2003 (300A,0401) SQ ReferencedSetupImageSequence 1 dicom2005 (300A,0402) ST SetupImageComment 1 dicom2005 (300C,0000) UL RTRelationshipGroupLength 1 dicom98 (300C,0002) SQ ReferencedRTPlanSequence 1 dicom98 (300C,0004) SQ ReferencedBeamSequence 1 dicom98 (300C,0006) IS ReferencedBeamNumber 1 dicom98 (300C,0007) IS ReferencedReferenceImageNumber 1 dicom98 (300C,0008) DS StartCumulativeMetersetWeight 1 dicom98 (300C,0009) DS EndCumulativeMetersetWeight 1 dicom98 (300C,000A) SQ ReferencedBrachyApplicationSetupSequence 1 dicom98 (300C,000C) IS ReferencedBrachyApplicationSetupNumber 1 dicom98 (300C,000E) IS ReferencedSourceNumber 1 dicom98 (300C,0020) SQ ReferencedFractionGroupSequence 1 dicom98 (300C,0022) IS ReferencedFractionGroupNumber 1 dicom98 (300C,0040) SQ ReferencedVerificationImageSequence 1 dicom98 (300C,0042) SQ ReferencedReferenceImageSequence 1 dicom98 (300C,0050) SQ ReferencedDoseReferenceSequence 1 dicom98 (300C,0051) IS ReferencedDoseReferenceNumber 1 dicom98 (300C,0055) SQ BrachyReferencedDoseReferenceSequence 1 dicom98 (300C,0060) SQ ReferencedStructureSetSequence 1 dicom98 (300C,006A) IS ReferencedPatientSetupNumber 1 dicom98 (300C,0080) SQ ReferencedDoseSequence 1 dicom98 (300C,00A0) IS ReferencedToleranceTableNumber 1 dicom98 (300C,00B0) SQ ReferencedBolusSequence 1 dicom98 (300C,00C0) IS ReferencedWedgeNumber 1 dicom98 (300C,00D0) IS ReferencedCompensatorNumber 1 dicom98 (300C,00E0) IS ReferencedBlockNumber 1 dicom98 (300C,00F0) IS ReferencedControlPointIndex 1 dicom98 (300C,00F2) SQ ReferencedControlPointSequence 1 dicom2005 (300C,00F4) IS ReferencedStartControlPointIndex 1 dicom2005 (300C,00F6) IS ReferencedStopControlPointIndex 1 dicom2005 (300E,0000) UL RTApprovalGroupLength 1 dicom98 (300E,0002) CS ApprovalStatus 1 dicom98 (300E,0004) DA ReviewDate 1 dicom98 (300E,0005) TM ReviewTime 1 dicom98 (300E,0008) PN ReviewerName 1 dicom98 (4008,0000) UL ResultsGroupLength 1 dicom98 (4008,0040) SH ResultsID 1 dicom98 (4008,0042) LO ResultsIDIssuer 1 dicom98 (4008,0050) SQ ReferencedInterpretationSequence 1 dicom98 (4008,0100) DA InterpretationRecordedDate 1 dicom98 (4008,0101) TM InterpretationRecordedTime 1 dicom98 (4008,0102) PN InterpretationRecorder 1 dicom98 (4008,0103) LO ReferenceToRecordedSound 1 dicom98 (4008,0108) DA InterpretationTranscriptionDate 1 dicom98 (4008,0109) TM InterpretationTranscriptionTime 1 dicom98 (4008,010A) PN InterpretationTranscriber 1 dicom98 (4008,010B) ST InterpretationText 1 dicom98 (4008,010C) PN InterpretationAuthor 1 dicom98 (4008,0111) SQ InterpretationApproverSequence 1 dicom98 (4008,0112) DA InterpretationApprovalDate 1 dicom98 (4008,0113) TM InterpretationApprovalTime 1 dicom98 (4008,0114) PN PhysicianApprovingInterpretation 1 dicom98 (4008,0115) LT InterpretationDiagnosisDescription 1 dicom98 (4008,0117) SQ InterpretationDiagnosisCodeSequence 1 dicom98 (4008,0118) SQ ResultsDistributionListSequence 1 dicom98 (4008,0119) PN DistributionName 1 dicom98 (4008,011A) LO DistributionAddress 1 dicom98 (4008,0200) SH InterpretationID 1 dicom98 (4008,0202) LO InterpretationIDIssuer 1 dicom98 (4008,0210) CS InterpretationTypeID 1 dicom98 (4008,0212) CS InterpretationStatusID 1 dicom98 (4008,0300) ST Impressions 1 dicom98 (4008,4000) ST ResultsComments 1 dicom98 (4FFE,0000) UL MACParametersGroupLength 1 dicom2001 (4FFE,0001) SQ MACParametersSequence 1 dicom2001 (5000-50ff,0000) UL CurveGroupLength 1 dicom98 (5000-50ff,0005) US CurveDimensions 1 dicom98 (5000-50ff,0010) US NumberOfPoints 1 dicom98 (5000-50ff,0020) CS TypeOfData 1 dicom98 (5000-50ff,0022) LO CurveDescription 1 dicom98 (5000-50ff,0030) SH AxisUnits 1-n dicom98 (5000-50ff,0040) SH AxisLabels 1-n dicom98 (5000-50ff,0103) US DataValueRepresentation 1 dicom98 (5000-50ff,0104) US MinimumCoordinateValue 1-n dicom98 (5000-50ff,0105) US MaximumCoordinateValue 1-n dicom98 (5000-50ff,0106) SH CurveRange 1-n dicom98 # VM for (5000-50ff,0110) CurveDataDescriptor was 1 in DICOM93. Changed in DICOM96. (5000-50ff,0110) US CurveDataDescriptor 1-n dicom98 # VM for (5000-50ff,0112) CoordinateStartValue was 1 in DICOM98. Changed in CP 293 (2001). (5000-50ff,0112) US CoordinateStartValue 1-n dicom2003 # VM for (5000-50ff,0114) CoordinateStepValue was 1 in DICOM98. Changed in CP 293 (2001). (5000-50ff,0114) US CoordinateStepValue 1-n dicom2003 (5000-50ff,1001) CS CurveActivationLayer 1 dicom2000 (5000-50ff,2000) US AudioType 1 dicom98 (5000-50ff,2002) US AudioSampleFormat 1 dicom98 (5000-50ff,2004) US NumberOfChannels 1 dicom98 (5000-50ff,2006) UL NumberOfSamples 1 dicom98 (5000-50ff,2008) UL SampleRate 1 dicom98 (5000-50ff,200A) UL TotalTime 1 dicom98 (5000-50ff,200C) ox AudioSampleData 1 dicom98 (5000-50ff,200E) LT AudioComments 1 dicom98 (5000-50ff,2500) LO CurveLabel 1 dicom98 # (5000-50ff,2600) is called ReferencedOverlaySequence in the standard, but this collides with tag (0008,1130) (5000-50ff,2600) SQ CurveReferencedOverlaySequence 1 dicom98 # (5000-50ff,2600) is called ReferencedOverlaySequence in the standard, but this collides with tag (0008,1130) (5000-50ff,2610) US ReferencedOverlayGroup 1 dicom98 (5000-50ff,3000) ox CurveData 1 dicom98 (5200,9229) SQ SharedFunctionalGroupsSequence 1 dicom2003 (5200,9230) SQ PerFrameFunctionalGroupsSequence 1 dicom2003 (5400,0000) UL WaveformDataGroupLength 1 dicom2000 (5400,0100) SQ WaveformSequence 1 dicom2000 (5400,0110) ox ChannelMinimumValue 1 dicom2000 (5400,0112) ox ChannelMaximumValue 1 dicom2000 (5400,1004) US WaveformBitsAllocated 1 dicom2000 (5400,1006) CS WaveformSampleInterpretation 1 dicom2000 (5400,100A) ox WaveformPaddingValue 1 dicom2000 (5400,1010) ox WaveformData 1 dicom2000 (5600,0010) OF FirstOrderPhaseCorrectionAngle 1 dicom2003 (5600,0020) OF SpectroscopyData 1 dicom2003 (6000-60ff,0000) UL OverlayGroupLength 1 dicom98 (6000-60ff,0010) US OverlayRows 1 dicom98 (6000-60ff,0011) US OverlayColumns 1 dicom98 (6000-60ff,0012) US OverlayPlanes 1 dicom98 (6000-60ff,0015) IS NumberOfFramesInOverlay 1 dicom98 (6000-60ff,0022) LO OverlayDescription 1 dicom98 (6000-60ff,0040) CS OverlayType 1 dicom98 (6000-60ff,0045) LO OverlaySubtype 1 dicom98 (6000-60ff,0050) SS OverlayOrigin 2 dicom98 (6000-60ff,0051) US ImageFrameOrigin 1 dicom98 (6000-60ff,0052) US OverlayPlaneOrigin 1 dicom98 (6000-60ff,0100) US OverlayBitsAllocated 1 dicom98 (6000-60ff,0102) US OverlayBitPosition 1 dicom98 (6000-60ff,1001) CS OverlayActivationLayer 1 dicom2000 (6000-60ff,1301) IS ROIArea 1 dicom98 (6000-60ff,1302) DS ROIMean 1 dicom98 (6000-60ff,1303) DS ROIStandardDeviation 1 dicom98 (6000-60ff,1500) LO OverlayLabel 1 dicom98 # VM of (6000-60ff,3000) OverlayData was OW in dicom93. Changed to OB/OW in dicom2000 (Supplement 33). (6000-60ff,3000) ox OverlayData 1 dicom2000 (7FE0,0000) UL PixelDataGroupLength 1 dicom98 (7FE0,0010) ox PixelData 1 dicom98 (FFFA,FFFA) SQ DigitalSignaturesSequence 1 dicom2001 (FFFC,FFFC) OB DataSetTrailingPadding 1 dicom98 (FFFE,E000) na Item 1 dicom98 (FFFE,E00D) na ItemDelimitationItem 1 dicom98 (FFFE,E0DD) na SequenceDelimitationItem 1 dicom98 # #--------------------------------------------------------------------------- # # Private Creator Data Elements # (0009-o-ffff,0000) UL PrivateGroupLength 1 PRIVATE (0009-o-ffff,0001) UL PrivateGroupLengthToEnd 1 PRIVATE (0009-o-ffff,0010-u-00ff) LO PrivateCreator 1 PRIVATE (0001-o-0007,0000) UL IllegalGroupLength 1 ILLEGAL (0001-o-0007,0001) UL IllegalGroupLengthToEnd 1 ILLEGAL (0001-o-0007,0010-u-00ff) LO IllegalPrivateCreator 1 ILLEGAL # #--------------------------------------------------------------------------- # # A "catch all" for group length elements # (0000-u-ffff,0000) UL GenericGroupLength 1 GENERIC (0000-u-ffff,0001) UL GenericGroupLengthToEnd 1 GENERIC # #--------------------------------------------------------------------------- # # Retired data elements from previous editions of the DICOM standard # # cannot find reference to (0000,1007), maybe it stems from an early pre-1993 DICOM draft. # (0000,1007) AT RETIRED_ModificationList 1-n DICOM93 (0008,0042) CS RETIRED_NuclearMedicineSeriesType 1 DICOM93 (0008,2110) CS RETIRED_LossyImageCompression 1 DICOM93 (0008,2200) CS RETIRED_TransducerPosition 1 DICOM93 (0008,2204) CS RETIRED_TransducerOrientation 1 DICOM93 (0008,2208) CS RETIRED_AnatomicStructure 1 DICOM93 (0018,0030) LO RETIRED_Radionuclide 1-n DICOM93 (0018,0032) DS RETIRED_EnergyWindowCenterline 1 DICOM93 (0018,0033) DS RETIRED_EnergyWindowTotalWidth 1-n DICOM93 (0018,1146) DS RETIRED_RotationOffset 1-n DICOM93 # retired in CP 207 (2001) (0018,0037) CS RETIRED_TherapyType 1 dicom98 # retired in CP 159 (2004) (0018,0039) CS RETIRED_TherapyDescription 1 dicom2004 # retired in CP 422 (2004) (0018,5210) DS RETIRED_Image Transformation Matrix 6 dicom2004 # retired in CP 422 (2004) (0018,5212) DS RETIRED_Image Translation Vector 3 dicom2004 # retired in CP 303 (2001) (0018,6038) UL RETIRED_DopplerSampleVolumeXPosition 1 dicom2003 # retired in CP 303 (2001) (0018,603A) UL RETIRED_DopplerSampleVolumeYPosition 1 dicom2003 # retired in CP 303 (2001) (0018,603C) UL RETIRED_TMLinePositionX0 1 dicom2003 # retired in CP 303 (2001) (0018,603E) UL RETIRED_TMLinePositionY0 1 dicom2003 # retired in CP 303 (2001) (0018,6040) UL RETIRED_TMLinePositionX1 1 dicom2003 # retired in CP 303 (2001) (0018,6042) UL RETIRED_TMLinePositionY1 1 dicom2003 (0018,9096) FD RETIRED_ParallelReductionFactorInPlane 1 dicom2003 # Attribute (0018,9195) renamed and retired in CP 386 (03/2004), was ChemicalShiftsMinimumIntegrationLimit before (0018,9195) FD RETIRED_ChemicalShiftsMinimumIntegrationLimitInHz 1 dicom2003 # Attribute (0018,9196) renamed and retired in CP 386 (03/2004), was ChemicalShiftsMaximumIntegrationLimit before (0018,9196) FD RETIRED_ChemicalShiftsMaximumIntegrationLimitInHz 1 dicom2003 (0020,0014) IS RETIRED_IsotopeNumber 1 DICOM93 (0020,0015) IS RETIRED_PhaseNumber 1 DICOM93 (0020,0016) IS RETIRED_IntervalNumber 1 DICOM93 (0020,0017) IS RETIRED_TimeSlotNumber 1 DICOM93 (0020,0018) IS RETIRED_AngleNumber 1 DICOM93 # retired in CP 207 (2001) (0028,6030) US RETIRED_MaskPointers 1-n dicom98 # retired in CP 207 (2001) (0040,0307) DS RETIRED_DistanceSourceToSupport 1 dicom99 # retired in CP 207 (2001) (0040,0330) SQ RETIRED_ReferencedProcedureStepSequence 1 dicom98 # Attribute (0040,2001) retired in CP 409 (03/2004) (0040,2001) LO RETIRED_ReasonForTheImagingServiceRequest 1 dicom98 # retired in CP 163 (1999) (0040,2006) SH RETIRED_PlacerOrderNumberImagingServiceRequest 1 dicom98 # retired in CP 163 (1999) (0040,2007) SH RETIRED_FillerOrderNumberImagingServiceRequest 1 dicom98 # retired in CP 275 (2001) (0040,DB06) DT RETIRED_TemplateVersion 1 dicom2003 # retired in CP 275 (2001) (0040,DB07) DT RETIRED_TemplateLocalVersion 1 dicom2003 # retired in CP 275 (2001) (0040,DB0B) CS RETIRED_TemplateExtensionFlag 1 dicom2003 # retired in CP 275 (2001) (0040,DB0C) UI RETIRED_TemplateExtensionOrganizationUID 1 dicom2003 # retired in CP 275 (2001) (0040,DB0D) UI RETIRED_TemplateExtensionCreatorUID 1 dicom2003 # (2020,0130) ReferencedOverlayBoxSequence was retired in Supplement 35 (1999) (2020,0130) SQ RETIRED_ReferencedImageOverlayBoxSequence 1 dicom98 # (2020,0140) ReferencedVOILUTSequence was retired in Supplement 35 (1999) (2020,0140) SQ RETIRED_ReferencedVOILUTBoxSequence 1 dicom98 # Attribute (2040,0500) is retired by Correction Proposal 53. It is a duplicate of (2010,0510). (2040,0500) SQ RETIRED_ReferencedImageBoxSequence 1 DICOM93 (6000-60ff,1100) US RETIRED_OverlayDescriptorGray 1 DICOM93 (6000-60ff,1101) US RETIRED_OverlayDescriptorRed 1 DICOM93 (6000-60ff,1102) US RETIRED_OverlayDescriptorGreen 1 DICOM93 (6000-60ff,1103) US RETIRED_OverlayDescriptorBlue 1 DICOM93 (6000-60ff,1200) US RETIRED_OverlayGray 1-n DICOM93 (6000-60ff,1201) US RETIRED_OverlayRed 1-n DICOM93 (6000-60ff,1202) US RETIRED_OverlayGreen 1-n DICOM93 (6000-60ff,1203) US RETIRED_OverlayBlue 1-n DICOM93 # #--------------------------------------------------------------------------- # # Retired data elements from ACR/NEMA 2 (1988) # (0000,0001) UL ACR_NEMA_CommandGroupLengthToEnd 1 ACR/NEMA2 (0000,0010) CS ACR_NEMA_CommandRecognitionCode 1 ACR/NEMA2 (0000,0200) LO ACR_NEMA_Initiator 1 ACR/NEMA2 (0000,0300) LO ACR_NEMA_Receiver 1 ACR/NEMA2 (0000,0400) LO ACR_NEMA_FindLocation 1 ACR/NEMA2 (0000,0850) US ACR_NEMA_NumberOfMatches 1 ACR/NEMA2 (0000,0860) US ACR_NEMA_ResponseSequenceNumber 1 ACR/NEMA2 (0000,4000) LO ACR_NEMA_DialogReceiver 1 ACR/NEMA2 (0000,4010) LO ACR_NEMA_TerminalType 1 ACR/NEMA2 (0000,5010) LO ACR_NEMA_MessageSetID 1 ACR/NEMA2 (0000,5020) LO ACR_NEMA_EndMessageSet 1 ACR/NEMA2 (0000,5110) LO ACR_NEMA_DisplayFormat 1 ACR/NEMA2 (0000,5120) LO ACR_NEMA_PagePositionID 1 ACR/NEMA2 (0000,5130) LO ACR_NEMA_TextFormatID 1 ACR/NEMA2 (0000,5140) CS ACR_NEMA_NormalReverse 1 ACR/NEMA2 (0000,5150) CS ACR_NEMA_AddGrayScale 1 ACR/NEMA2 (0000,5160) CS ACR_NEMA_Borders 1 ACR/NEMA2 (0000,5170) IS ACR_NEMA_Copies 1 ACR/NEMA2 (0000,5180) LO ACR_NEMA_MagnificationType 1 ACR/NEMA2 (0000,5190) LO ACR_NEMA_Erase 1-n ACR/NEMA2 (0000,51A0) CS ACR_NEMA_Print 1 ACR/NEMA2 (0000,51B0) US ACR_NEMA_Overlays 1-n ACR/NEMA2 (0008,0001) UL ACR_NEMA_IdentifyingGroupLengthToEnd 1 ACR/NEMA2 (0008,0010) LO ACR_NEMA_RecognitionCode 1 ACR/NEMA2 (0008,0040) US ACR_NEMA_OldDataSetType 1 ACR/NEMA2 (0008,0041) LO ACR_NEMA_DataSetSubtype 1 ACR/NEMA2 (0008,1000) LO ACR_NEMA_NetworkID 1 ACR/NEMA2 (0008,4000) LT ACR_NEMA_IdentifyingComments 1-n ACR/NEMA2 (0010,1050) LT ACR_NEMA_InsurancePlanIdentification 1-n ACR/NEMA2 (0018,1240) IS ACR_NEMA_UpperLowerPixelValues 1-n ACR/NEMA2 (0018,4000) LT ACR_NEMA_AcquisitionComments 1-n ACR/NEMA2 (0018,5030) DS ACR_NEMA_DynamicRange 1 ACR/NEMA2 (0018,5040) DS ACR_NEMA_TotalGain 1 ACR/NEMA2 (0020,0030) DS ACR_NEMA_ImagePosition 3 ACR/NEMA2 (0020,0035) DS ACR_NEMA_ImageOrientation 6 ACR/NEMA2 (0020,0050) DS ACR_NEMA_Location 1 ACR/NEMA2 (0020,0070) LO ACR_NEMA_ImageGeometryType 1 ACR/NEMA2 (0020,0080) LO ACR_NEMA_MaskingImage 1-n ACR/NEMA2 (0020,1001) IS ACR_NEMA_AcquisitionsInSeries 1 ACR/NEMA2 (0020,1003) IS ACR_NEMA_ImagesInSeries 1 ACR/NEMA2 (0020,1005) IS ACR_NEMA_ImagesInStudy 1 ACR/NEMA2 (0020,1020) LO ACR_NEMA_Reference 1-n ACR/NEMA2 (0020,3100-31FF) LO ACR_NEMA_SourceImageID 1-n ACR/NEMA2 (0020,3401) LO ACR_NEMA_ModifyingDeviceID 1 ACR/NEMA2 (0020,3402) LO ACR_NEMA_ModifiedImageID 1 ACR/NEMA2 (0020,3403) DA ACR_NEMA_ModifiedImageDate 1 ACR/NEMA2 (0020,3404) LO ACR_NEMA_ModifyingDeviceManufacturer 1 ACR/NEMA2 (0020,3405) TM ACR_NEMA_ModifiedImageTime 1 ACR/NEMA2 (0020,3406) LO ACR_NEMA_ModifiedImageDescription 1 ACR/NEMA2 (0020,5000) AT ACR_NEMA_OriginalImageIdentification 1-n ACR/NEMA2 (0020,5002) LO ACR_NEMA_OriginalImageIdentificationNomenclature 1-n ACR/NEMA2 (0028,0005) US ACR_NEMA_ImageDimensions 1 ACR/NEMA2 (0028,0040) CS ACR_NEMA_ImageFormat 1 ACR/NEMA2 (0028,0050) LO ACR_NEMA_ManipulatedImage 1-n ACR/NEMA2 (0028,0060) CS ACR_NEMA_CompressionCode 1 ACR/NEMA2 (0028,0104) xs ACR_NEMA_SmallestValidPixelValue 1 ACR/NEMA2 (0028,0105) xs ACR_NEMA_LargestValidPixelValue 1 ACR/NEMA2 (0028,0200) US ACR_NEMA_ImageLocation 1 ACR/NEMA2 (0028,1080) CS ACR_NEMA_GrayScale 1 ACR/NEMA2 (0028,1100) xs ACR_NEMA_GrayLookupTableDescriptor 3 ACR/NEMA2 (0028,1200) xs ACR_NEMA_GrayLookupTableData 1-n ACR/NEMA2 (0028,4000) LT ACR_NEMA_ImagePresentationComments 1-n ACR/NEMA2 (4000,0000) UL ACR_NEMA_TextGroupLength 1 ACR/NEMA2 (4000,0010) LT ACR_NEMA_TextArbitrary 1-n ACR/NEMA2 (4000,4000) LT ACR_NEMA_TextComments 1-n ACR/NEMA2 (6000-60ff,0110) CS ACR_NEMA_OverlayFormat 1 ACR/NEMA2 (6000-60ff,0200) US ACR_NEMA_OverlayLocation 1 ACR/NEMA2 (6000-60ff,4000) LT ACR_NEMA_OverlayComments 1-n ACR/NEMA2 # #--------------------------------------------------------------------------- # # Retired data elements from the ACR/NEMA 2 compression enhancements # (0028,005F) CS ACR_NEMA_2C_CompressionRecognitionCode 1 ACR/NEMA2C (0028,0061) SH ACR_NEMA_2C_CompressionOriginator 1 ACR/NEMA2C (0028,0062) SH ACR_NEMA_2C_CompressionLabel 1 ACR/NEMA2C (0028,0063) SH ACR_NEMA_2C_CompressionDescription 1 ACR/NEMA2C (0028,0065) CS ACR_NEMA_2C_CompressionSequence 1-n ACR/NEMA2C (0028,0066) AT ACR_NEMA_2C_CompressionStepPointers 1-n ACR/NEMA2C (0028,0068) US ACR_NEMA_2C_RepeatInterval 1 ACR/NEMA2C (0028,0069) US ACR_NEMA_2C_BitsGrouped 1 ACR/NEMA2C (0028,0070) US ACR_NEMA_2C_PerimeterTable 1-n ACR/NEMA2C (0028,0071) xs ACR_NEMA_2C_PerimeterValue 1 ACR/NEMA2C (0028,0080) US ACR_NEMA_2C_PredictorRows 1 ACR/NEMA2C (0028,0081) US ACR_NEMA_2C_PredictorColumns 1 ACR/NEMA2C (0028,0082) US ACR_NEMA_2C_PredictorConstants 1-n ACR/NEMA2C (0028,0090) CS ACR_NEMA_2C_BlockedPixels 1 ACR/NEMA2C (0028,0091) US ACR_NEMA_2C_BlockRows 1 ACR/NEMA2C (0028,0092) US ACR_NEMA_2C_BlockColumns 1 ACR/NEMA2C (0028,0093) US ACR_NEMA_2C_RowOverlap 1 ACR/NEMA2C (0028,0094) US ACR_NEMA_2C_ColumnOverlap 1 ACR/NEMA2C (0028,0400) CS ACR_NEMA_2C_TransformLabel 1 ACR/NEMA2C (0028,0401) CS ACR_NEMA_2C_TransformVersionNumber 1 ACR/NEMA2C (0028,0402) US ACR_NEMA_2C_NumberOfTransformSteps 1 ACR/NEMA2C (0028,0403) CS ACR_NEMA_2C_SequenceOfCompressedData 1-n ACR/NEMA2C (0028,0404) AT ACR_NEMA_2C_DetailsOfCoefficients 1-n ACR/NEMA2C (0028,0410) US ACR_NEMA_2C_RowsForNthOrderCoefficients 1 ACR/NEMA2C (0028,0411) US ACR_NEMA_2C_ColumnsForNthOrderCoefficients 1 ACR/NEMA2C (0028,0412) CS ACR_NEMA_2C_CoefficientCoding 1-n ACR/NEMA2C (0028,0413) AT ACR_NEMA_2C_CoefficientCodingPointers 1-n ACR/NEMA2C (0028,0700) CS ACR_NEMA_2C_DCTLabel 1 ACR/NEMA2C (0028,0701) CS ACR_NEMA_2C_DataBlockDescription 1-n ACR/NEMA2C (0028,0702) AT ACR_NEMA_2C_DataBlock 1-n ACR/NEMA2C (0028,0710) US ACR_NEMA_2C_NormalizationFactorFormat 1 ACR/NEMA2C (0028,0720) US ACR_NEMA_2C_ZonalMapNumberFormat 1 ACR/NEMA2C (0028,0721) AT ACR_NEMA_2C_ZonalMapLocation 1-n ACR/NEMA2C (0028,0722) US ACR_NEMA_2C_ZonalMapFormat 1 ACR/NEMA2C (0028,0730) US ACR_NEMA_2C_AdaptiveMapFormat 1 ACR/NEMA2C (0028,0740) US ACR_NEMA_2C_CodeNumberFormat 1 ACR/NEMA2C (0028,0800) CS ACR_NEMA_2C_CodeLabel 1-n ACR/NEMA2C (0028,0802) US ACR_NEMA_2C_NumberOfTables 1 ACR/NEMA2C (0028,0803) AT ACR_NEMA_2C_CodeTableLocation 1-n ACR/NEMA2C (0028,0804) US ACR_NEMA_2C_BitsForCodeWord 1 ACR/NEMA2C (0028,0808) AT ACR_NEMA_2C_ImageDataLocation 1-n ACR/NEMA2C (1000,0000) UL ACR_NEMA_2C_CodeTableGroupLength 1 ACR/NEMA2C (1000,0010) US ACR_NEMA_2C_EscapeTriplet 3 ACR/NEMA2C (1000,0011) US ACR_NEMA_2C_RunLengthTriplet 3 ACR/NEMA2C (1000,0012) US ACR_NEMA_2C_HuffmanTableSize 1 ACR/NEMA2C (1000,0013) US ACR_NEMA_2C_HuffmanTableTriplet 3 ACR/NEMA2C (1000,0014) US ACR_NEMA_2C_ShiftTableSize 1 ACR/NEMA2C (1000,0015) US ACR_NEMA_2C_ShiftTableTriplet 3 ACR/NEMA2C (1010,0000) UL ACR_NEMA_2C_ZonalMapGroupLength 1 ACR/NEMA2C (1010,0004) US ACR_NEMA_2C_ZonalMap 1-n ACR/NEMA2C (6000-60ff,0060) CS ACR_NEMA_2C_OverlayCompressionCode 1 ACR/NEMA2C (6000-60ff,0061) SH ACR_NEMA_2C_OverlayCompressionOriginator 1 ACR/NEMA2C (6000-60ff,0062) SH ACR_NEMA_2C_OverlayCompressionLabel 1 ACR/NEMA2C (6000-60ff,0063) SH ACR_NEMA_2C_OverlayCompressionDescription 1 ACR/NEMA2C (6000-60ff,0066) AT ACR_NEMA_2C_OverlayCompressionStepPointers 1-n ACR/NEMA2C (6000-60ff,0068) US ACR_NEMA_2C_OverlayRepeatInterval 1 ACR/NEMA2C (6000-60ff,0069) US ACR_NEMA_2C_OverlayBitsGrouped 1 ACR/NEMA2C (6000-60ff,0800) CS ACR_NEMA_2C_OverlayCodeLabel 1-n ACR/NEMA2C (6000-60ff,0802) US ACR_NEMA_2C_OverlayNumberOfTables 1 ACR/NEMA2C (6000-60ff,0803) AT ACR_NEMA_2C_OverlayCodeTableLocation 1-n ACR/NEMA2C (6000-60ff,0804) US ACR_NEMA_2C_OverlayBitsForCodeWord 1 ACR/NEMA2C (7F00-7fff,0000) UL ACR_NEMA_2C_VariablePixelDataGroupLength 1 ACR/NEMA2C (7F00-7fff,0010) ox ACR_NEMA_2C_VariablePixelData 1 ACR/NEMA2C (7F00-7fff,0011) AT ACR_NEMA_2C_VariableNextDataGroup 1 ACR/NEMA2C (7F00-7fff,0020) OW ACR_NEMA_2C_VariableCoefficientsSDVN 1-n ACR/NEMA2C (7F00-7fff,0030) OW ACR_NEMA_2C_VariableCoefficientsSDHN 1-n ACR/NEMA2C (7F00-7fff,0040) OW ACR_NEMA_2C_VariableCoefficientsSDDN 1-n ACR/NEMA2C (7FE0,0020) OW ACR_NEMA_2C_CoefficientsSDVN 1-n ACR/NEMA2C (7FE0,0030) OW ACR_NEMA_2C_CoefficientsSDHN 1-n ACR/NEMA2C (7FE0,0040) OW ACR_NEMA_2C_CoefficientsSDDN 1-n ACR/NEMA2C # # EOF # # # Copyright (C) 1994-2005, OFFIS # # This software and supporting documentation were developed by # # Kuratorium OFFIS e.V. # Healthcare Information and Communication Systems # Escherweg 2 # D-26121 Oldenburg, Germany # # THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY # REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR # FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR # ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND # PERFORMANCE OF THE SOFTWARE IS WITH THE USER. # # Module: dcmdata # # Author: Andrew Hewett, Marco Eichelberg # # Purpose: # This is the private tag DICOM data dictionary for the dcmtk class library. # # Last Update: $Author: meichel $ # Update Date: $Date: 2005/10/24 16:56:22 $ # CVS/RCS Revision: $Revision: 1.11 $ # Status: $State: Exp $ # # # Dictionary of Private Tags # # This dictionary contains the private tags defined in the following # reference documents: # - David Clunie's dicom3tools package, 2002-04-20 snapshot # - Siemens Somatom syngo VA40B conformance statement # - Swissvision TR4000 conformance statement # - Philips Digital Diagnost 1.3 conformance statement # - Fuji CR console, 3rd release # - Intelerad Medical Systems Inc., Image Server # - private tags for DCMTK anonymizer tool # - Philips Integris H, catheterization laboratory, RIS-interface # - Philips Intera Achieva Conformance Statement # # Each line represents an entry in the data dictionary. Each line # has 5 fields (Tag, VR, Name, VM, Version). Entries need not be # in ascending tag order. # # Entries may override existing entries. # # Each field must be separated by a single tab. # The tag value may take one of two forms: # (gggg,"CREATOR",ee) # (gggg,"CREATOR",eeee) [eeee >= 1000] # The first form describes a private tag that may be used with different # element numbers as reserved by the private creator element. # The second form describes a private tag that may only occur with a # certain fixed element number. # In both cases, the tag values must be in hexadecimal. # Repeating groups are represented by indicating the range # (gggg-o-gggg,"CREATOR",ee) or (gggg-o-gggg,"CREATOR",eeee) # where "-o-" indicates that only odd group numbers match the definition. # The element part of the tag can also be a range. # # Comments have a '#' at the beginning of the line. # # Tag VR Name VM Version # (0019,"1.2.840.113681",10) ST CRImageParamsCommon 1 (0019,"1.2.840.113681",11) ST CRImageIPParamsSingle 1 (0019,"1.2.840.113681",12) ST CRImageIPParamsLeft 1 (0019,"1.2.840.113681",13) ST CRImageIPParamsRight 1 (0087,"1.2.840.113708.794.1.1.2.0",10) CS MediaType 1 (0087,"1.2.840.113708.794.1.1.2.0",20) CS MediaLocation 1 (0087,"1.2.840.113708.794.1.1.2.0",50) IS EstimatedRetrieveTime 1 (0009,"ACUSON",00) IS Unknown 1 (0009,"ACUSON",01) IS Unknown 1 (0009,"ACUSON",02) UN Unknown 1 (0009,"ACUSON",03) UN Unknown 1 (0009,"ACUSON",04) UN Unknown 1 (0009,"ACUSON",05) UN Unknown 1 (0009,"ACUSON",06) UN Unknown 1 (0009,"ACUSON",07) UN Unknown 1 (0009,"ACUSON",08) LT Unknown 1 (0009,"ACUSON",09) LT Unknown 1 (0009,"ACUSON",0a) IS Unknown 1 (0009,"ACUSON",0b) IS Unknown 1 (0009,"ACUSON",0c) IS Unknown 1 (0009,"ACUSON",0d) IS Unknown 1 (0009,"ACUSON",0e) IS Unknown 1 (0009,"ACUSON",0f) UN Unknown 1 (0009,"ACUSON",10) IS Unknown 1 (0009,"ACUSON",11) UN Unknown 1 (0009,"ACUSON",12) IS Unknown 1 (0009,"ACUSON",13) IS Unknown 1 (0009,"ACUSON",14) LT Unknown 1 (0009,"ACUSON",15) UN Unknown 1 (0003,"AEGIS_DICOM_2.00",00) US Unknown 1-n (0005,"AEGIS_DICOM_2.00",00) US Unknown 1-n (0009,"AEGIS_DICOM_2.00",00) US Unknown 1-n (0019,"AEGIS_DICOM_2.00",00) US Unknown 1-n (0029,"AEGIS_DICOM_2.00",00) US Unknown 1-n (1369,"AEGIS_DICOM_2.00",00) US Unknown 1-n (0009,"AGFA",10) LO Unknown 1 (0009,"AGFA",11) LO Unknown 1 (0009,"AGFA",13) LO Unknown 1 (0009,"AGFA",14) LO Unknown 1 (0009,"AGFA",15) LO Unknown 1 (0029,"CAMTRONICS IP",10) LT Unknown 1 (0029,"CAMTRONICS IP",20) UN Unknown 1 (0029,"CAMTRONICS IP",30) UN Unknown 1 (0029,"CAMTRONICS IP",40) UN Unknown 1 (0029,"CAMTRONICS",10) LT Commentline 1 (0029,"CAMTRONICS",20) DS EdgeEnhancementCoefficient 1 (0029,"CAMTRONICS",50) LT SceneText 1 (0029,"CAMTRONICS",60) LT ImageText 1 (0029,"CAMTRONICS",70) IS PixelShiftHorizontal 1 (0029,"CAMTRONICS",80) IS PixelShiftVertical 1 (0029,"CAMTRONICS",90) IS Unknown 1 (0009,"CARDIO-D.R. 1.0",00) UL FileLocation 1 (0009,"CARDIO-D.R. 1.0",01) UL FileSize 1 (0009,"CARDIO-D.R. 1.0",40) SQ AlternateImageSequence 1 (0019,"CARDIO-D.R. 1.0",00) CS ImageBlankingShape 1 (0019,"CARDIO-D.R. 1.0",02) IS ImageBlankingLeftVerticalEdge 1 (0019,"CARDIO-D.R. 1.0",04) IS ImageBlankingRightVerticalEdge 1 (0019,"CARDIO-D.R. 1.0",06) IS ImageBlankingUpperHorizontalEdge 1 (0019,"CARDIO-D.R. 1.0",08) IS ImageBlankingLowerHorizontalEdge 1 (0019,"CARDIO-D.R. 1.0",10) IS CenterOfCircularImageBlanking 1 (0019,"CARDIO-D.R. 1.0",12) IS RadiusOfCircularImageBlanking 1 (0019,"CARDIO-D.R. 1.0",30) UL MaximumImageFrameSize 1 (0021,"CARDIO-D.R. 1.0",13) IS ImageSequenceNumber 1 (0029,"CARDIO-D.R. 1.0",00) SQ EdgeEnhancementSequence 1 (0029,"CARDIO-D.R. 1.0",01) US ConvolutionKernelSize 2 (0029,"CARDIO-D.R. 1.0",02) DS ConvolutionKernelCoefficients 1-n (0029,"CARDIO-D.R. 1.0",03) DS EdgeEnhancementGain 1 (0009,"DCMTK_ANONYMIZER",00) SQ AnonymizerUIDMap 1 (0009,"DCMTK_ANONYMIZER",10) UI AnonymizerUIDKey 1 (0009,"DCMTK_ANONYMIZER",20) UI AnonymizerUIDValue 1 (0009,"DCMTK_ANONYMIZER",30) SQ AnonymizerPatientIDMap 1 (0009,"DCMTK_ANONYMIZER",40) LO AnonymizerPatientIDKey 1 (0009,"DCMTK_ANONYMIZER",50) LO AnonymizerPatientIDValue 1 (0019,"DIDI TO PCR 1.1",22) UN RouteAET 1 (0019,"DIDI TO PCR 1.1",23) DS PCRPrintScale 1 (0019,"DIDI TO PCR 1.1",24) UN PCRPrintJobEnd 1 (0019,"DIDI TO PCR 1.1",25) IS PCRNoFilmCopies 1 (0019,"DIDI TO PCR 1.1",26) IS PCRFilmLayoutPosition 1 (0019,"DIDI TO PCR 1.1",27) UN PCRPrintReportName 1 (0019,"DIDI TO PCR 1.1",70) UN RADProtocolPrinter 1 (0019,"DIDI TO PCR 1.1",71) UN RADProtocolMedium 1 (0019,"DIDI TO PCR 1.1",90) LO UnprocessedFlag 1 (0019,"DIDI TO PCR 1.1",91) UN KeyValues 1 (0019,"DIDI TO PCR 1.1",92) UN DestinationPostprocessingFunction 1 (0019,"DIDI TO PCR 1.1",A0) UN Version 1 (0019,"DIDI TO PCR 1.1",A1) UN RangingMode 1 (0019,"DIDI TO PCR 1.1",A2) UN AbdomenBrightness 1 (0019,"DIDI TO PCR 1.1",A3) UN FixedBrightness 1 (0019,"DIDI TO PCR 1.1",A4) UN DetailContrast 1 (0019,"DIDI TO PCR 1.1",A5) UN ContrastBalance 1 (0019,"DIDI TO PCR 1.1",A6) UN StructureBoost 1 (0019,"DIDI TO PCR 1.1",A7) UN StructurePreference 1 (0019,"DIDI TO PCR 1.1",A8) UN NoiseRobustness 1 (0019,"DIDI TO PCR 1.1",A9) UN NoiseDoseLimit 1 (0019,"DIDI TO PCR 1.1",AA) UN NoiseDoseStep 1 (0019,"DIDI TO PCR 1.1",AB) UN NoiseFrequencyLimit 1 (0019,"DIDI TO PCR 1.1",AC) UN WeakContrastLimit 1 (0019,"DIDI TO PCR 1.1",AD) UN StrongContrastLimit 1 (0019,"DIDI TO PCR 1.1",AE) UN StructureBoostOffset 1 (0019,"DIDI TO PCR 1.1",AF) UN SmoothGain 1 (0019,"DIDI TO PCR 1.1",B0) UN MeasureField1 1 (0019,"DIDI TO PCR 1.1",B1) UN MeasureField2 1 (0019,"DIDI TO PCR 1.1",B2) UN KeyPercentile1 1 (0019,"DIDI TO PCR 1.1",B3) UN KeyPercentile2 1 (0019,"DIDI TO PCR 1.1",B4) UN DensityLUT 1 (0019,"DIDI TO PCR 1.1",B5) UN Brightness 1 (0019,"DIDI TO PCR 1.1",B6) UN Gamma 1 (0089,"DIDI TO PCR 1.1",10) SQ Unknown 1 (0029,"DIGISCAN IMAGE",31) US Unknown 1-n (0029,"DIGISCAN IMAGE",32) US Unknown 1-n (0029,"DIGISCAN IMAGE",33) LT Unknown 1 (0029,"DIGISCAN IMAGE",34) LT Unknown 1 (7001-o-70ff,"DLX_ANNOT_01",04) ST TextAnnotation 1 (7001-o-70ff,"DLX_ANNOT_01",05) IS Box 2 (7001-o-70ff,"DLX_ANNOT_01",07) IS ArrowEnd 2 (0015,"DLX_EXAMS_01",01) DS StenosisCalibrationRatio 1 (0015,"DLX_EXAMS_01",02) DS StenosisMagnification 1 (0015,"DLX_EXAMS_01",03) DS CardiacCalibrationRatio 1 (6001-o-60ff,"DLX_LKUP_01",01) US GrayPaletteColorLookupTableDescriptor 3 (6001-o-60ff,"DLX_LKUP_01",02) US GrayPaletteColorLookupTableData 1 (0011,"DLX_PATNT_01",01) LT PatientDOB 1 (0019,"DLX_SERIE_01",01) DS AngleValueLArm 1 (0019,"DLX_SERIE_01",02) DS AngleValuePArm 1 (0019,"DLX_SERIE_01",03) DS AngleValueCArm 1 (0019,"DLX_SERIE_01",04) CS AngleLabelLArm 1 (0019,"DLX_SERIE_01",05) CS AngleLabelPArm 1 (0019,"DLX_SERIE_01",06) CS AngleLabelCArm 1 (0019,"DLX_SERIE_01",07) ST ProcedureName 1 (0019,"DLX_SERIE_01",08) ST ExamName 1 (0019,"DLX_SERIE_01",09) SH PatientSize 1 (0019,"DLX_SERIE_01",0a) IS RecordView 1 (0019,"DLX_SERIE_01",10) DS InjectorDelay 1 (0019,"DLX_SERIE_01",11) CS AutoInject 1 (0019,"DLX_SERIE_01",14) IS AcquisitionMode 1 (0019,"DLX_SERIE_01",15) CS CameraRotationEnabled 1 (0019,"DLX_SERIE_01",16) CS ReverseSweep 1 (0019,"DLX_SERIE_01",17) IS SpatialFilterStrength 1 (0019,"DLX_SERIE_01",18) IS ZoomFactor 1 (0019,"DLX_SERIE_01",19) IS XZoomCenter 1 (0019,"DLX_SERIE_01",1a) IS YZoomCenter 1 (0019,"DLX_SERIE_01",1b) DS Focus 1 (0019,"DLX_SERIE_01",1c) CS Dose 1 (0019,"DLX_SERIE_01",1d) IS SideMark 1 (0019,"DLX_SERIE_01",1e) IS PercentageLandscape 1 (0019,"DLX_SERIE_01",1f) DS ExposureDuration 1 (00E1,"ELSCINT1",01) US DataDictionaryVersion 1 (00E1,"ELSCINT1",14) LT Unknown 1 (00E1,"ELSCINT1",22) DS Unknown 2 (00E1,"ELSCINT1",23) DS Unknown 2 (00E1,"ELSCINT1",24) LT Unknown 1 (00E1,"ELSCINT1",25) LT Unknown 1 (00E1,"ELSCINT1",40) SH OffsetFromCTMRImages 1 (0601,"ELSCINT1",00) SH ImplementationVersion 1 (0601,"ELSCINT1",20) DS RelativeTablePosition 1 (0601,"ELSCINT1",21) DS RelativeTableHeight 1 (0601,"ELSCINT1",30) SH SurviewDirection 1 (0601,"ELSCINT1",31) DS SurviewLength 1 (0601,"ELSCINT1",50) SH ImageViewType 1 (0601,"ELSCINT1",70) DS BatchNumber 1 (0601,"ELSCINT1",71) DS BatchSize 1 (0601,"ELSCINT1",72) DS BatchSliceNumber 1 (0009,"FDMS 1.0",04) SH ImageControlUnit 1 (0009,"FDMS 1.0",05) OW ImageUID 1 (0009,"FDMS 1.0",06) OW RouteImage UID 1 (0009,"FDMS 1.0",08) UL ImageDisplayInformationVersionNo 1 (0009,"FDMS 1.0",09) UL PatientInformationVersionNo 1 (0009,"FDMS 1.0",0C) OW FilmUID 1 (0009,"FDMS 1.0",10) CS ExposureUnitTypeCode 1 (0009,"FDMS 1.0",80) LO KanjiHospitalName 1 (0009,"FDMS 1.0",90) ST DistributionCode 1 (0009,"FDMS 1.0",92) SH KanjiDepartmentName 1 (0009,"FDMS 1.0",F0) CS BlackeningProcessFlag 1 (0019,"FDMS 1.0",15) LO KanjiBodyPartForExposure 1 (0019,"FDMS 1.0",32) LO KanjiMenuName 1 (0019,"FDMS 1.0",40) CS ImageProcessingType 1 (0019,"FDMS 1.0",50) CS EDRMode 1 (0019,"FDMS 1.0",60) SH RadiographersCode 1 (0019,"FDMS 1.0",70) IS SplitExposureFormat 1 (0019,"FDMS 1.0",71) IS NoOfSplitExposureFrames 1 (0019,"FDMS 1.0",80) IS ReadingPositionSpecification 1 (0019,"FDMS 1.0",81) IS ReadingSensitivityCenter 1 (0019,"FDMS 1.0",90) SH FilmAnnotationCharacterString1 1 (0019,"FDMS 1.0",91) SH FilmAnnotationCharacterString2 1 (0021,"FDMS 1.0",10) CS FCRImageID 1 (0021,"FDMS 1.0",30) CS SetNo 1 (0021,"FDMS 1.0",40) IS ImageNoInTheSet 1 (0021,"FDMS 1.0",50) CS PairProcessingInformation 1 (0021,"FDMS 1.0",80) OB EquipmentTypeSpecificInformation 1 (0023,"FDMS 1.0",10) SQ Unknown 1 (0023,"FDMS 1.0",20) SQ Unknown 1 (0023,"FDMS 1.0",30) SQ Unknown 1 (0025,"FDMS 1.0",10) US RelativeLightEmissionAmountSk 1 (0025,"FDMS 1.0",11) US TermOfCorrectionForEachIPTypeSt 1 (0025,"FDMS 1.0",12) US ReadingGainGp 1 (0025,"FDMS 1.0",13) US Unknown 1 (0025,"FDMS 1.0",15) CS Unknown 1 (0025,"FDMS 1.0",20) US Unknown 2 (0025,"FDMS 1.0",21) US Unknown 1 (0025,"FDMS 1.0",30) US Unknown 1 (0025,"FDMS 1.0",31) SS Unknown 1 (0025,"FDMS 1.0",32) US Unknown 1 (0025,"FDMS 1.0",33) SS Unknown 1 (0025,"FDMS 1.0",34) SS Unknown 1 (0025,"FDMS 1.0",40) US Unknown 1 (0025,"FDMS 1.0",41) US Unknown 1 (0025,"FDMS 1.0",42) US Unknown 1 (0025,"FDMS 1.0",43) US Unknown 1 (0025,"FDMS 1.0",50) US Unknown 1 (0025,"FDMS 1.0",51) US Unknown 1 (0025,"FDMS 1.0",52) US Unknown 1 (0025,"FDMS 1.0",53) US Unknown 1 (0025,"FDMS 1.0",60) US Unknown 1 (0025,"FDMS 1.0",61) US Unknown 1 (0025,"FDMS 1.0",62) US Unknown 1 (0025,"FDMS 1.0",63) CS Unknown 1 (0025,"FDMS 1.0",70) US Unknown 1 (0025,"FDMS 1.0",71) US Unknown 1 (0025,"FDMS 1.0",72) US Unknown 1 (0025,"FDMS 1.0",73) US Unknown 1-n (0025,"FDMS 1.0",74) US Unknown 1-n (0025,"FDMS 1.0",80) US Unknown 1 (0025,"FDMS 1.0",81) US Unknown 1 (0025,"FDMS 1.0",82) US Unknown 1 (0025,"FDMS 1.0",83) US Unknown 1-n (0025,"FDMS 1.0",84) US Unknown 1-n (0025,"FDMS 1.0",90) US Unknown 1 (0025,"FDMS 1.0",91) US Unknown 1 (0025,"FDMS 1.0",92) US Unknown 1 (0025,"FDMS 1.0",93) US Unknown 1 (0025,"FDMS 1.0",94) US Unknown 1 (0025,"FDMS 1.0",95) US Unknown 1 (0025,"FDMS 1.0",96) CS Unknown 1 (0025,"FDMS 1.0",a0) US Unknown 1 (0025,"FDMS 1.0",a1) SS Unknown 1 (0025,"FDMS 1.0",a2) US Unknown 1 (0025,"FDMS 1.0",a3) SS Unknown 1 (0027,"FDMS 1.0",10) SQ Unknown 1 (0027,"FDMS 1.0",20) SQ Unknown 1 (0027,"FDMS 1.0",30) SQ Unknown 1 (0027,"FDMS 1.0",40) SQ Unknown 1 (0027,"FDMS 1.0",50) SQ Unknown 1 (0027,"FDMS 1.0",60) SQ Unknown 1 (0027,"FDMS 1.0",70) SQ Unknown 1 (0027,"FDMS 1.0",80) SQ Unknown 1 (0027,"FDMS 1.0",a0) IS Unknown 1 (0027,"FDMS 1.0",a1) CS Unknown 2 (0027,"FDMS 1.0",a2) CS Unknown 2 (0027,"FDMS 1.0",a3) SS Unknown 1-n (0029,"FDMS 1.0",20) CS ImageScanningDirection 1 (0029,"FDMS 1.0",30) CS ExtendedReadingSizeValue 1 (0029,"FDMS 1.0",34) US MagnificationReductionRatio 1 (0029,"FDMS 1.0",44) CS LineDensityCode 1 (0029,"FDMS 1.0",50) CS DataCompressionCode 1 (2011,"FDMS 1.0",11) CS ImagePosition SpecifyingFlag 1 (50F1,"FDMS 1.0",06) CS EnergySubtractionParam 1 (50F1,"FDMS 1.0",07) CS SubtractionRegistrationResult 1 (50F1,"FDMS 1.0",08) CS EnergySubtractionParam2 1 (50F1,"FDMS 1.0",09) SL AfinConversionCoefficient 1 (50F1,"FDMS 1.0",10) CS FilmOutputFormat 1 (50F1,"FDMS 1.0",20) CS ImageProcessingModificationFlag 1 (0009,"FFP DATA",01) UN CRHeaderInformation 1 (0019,"GE ??? From Adantage Review CS",30) LO CREDRMode 1 (0019,"GE ??? From Adantage Review CS",40) LO CRLatitude 1 (0019,"GE ??? From Adantage Review CS",50) LO CRGroupNumber 1 (0019,"GE ??? From Adantage Review CS",70) LO CRImageSerialNumber 1 (0019,"GE ??? From Adantage Review CS",80) LO CRBarCodeNumber 1 (0019,"GE ??? From Adantage Review CS",90) LO CRFilmOutputExposures 1 (0009,"GEMS_ACQU_01",24) DS Unknown 1 (0009,"GEMS_ACQU_01",25) US Unknown 1 (0009,"GEMS_ACQU_01",3e) US Unknown 1 (0009,"GEMS_ACQU_01",3f) US Unknown 1 (0009,"GEMS_ACQU_01",42) US Unknown 1 (0009,"GEMS_ACQU_01",43) US Unknown 1 (0009,"GEMS_ACQU_01",f8) US Unknown 1 (0009,"GEMS_ACQU_01",fb) IS Unknown 1 (0019,"GEMS_ACQU_01",01) LT Unknown 1 (0019,"GEMS_ACQU_01",02) SL NumberOfCellsInDetector 1 (0019,"GEMS_ACQU_01",03) DS CellNumberAtTheta 1 (0019,"GEMS_ACQU_01",04) DS CellSpacing 1 (0019,"GEMS_ACQU_01",05) LT Unknown 1 (0019,"GEMS_ACQU_01",06) UN Unknown 1 (0019,"GEMS_ACQU_01",0e) US Unknown 1 (0019,"GEMS_ACQU_01",0f) DS HorizontalFrameOfReference 1 (0019,"GEMS_ACQU_01",11) SS SeriesContrast 1 (0019,"GEMS_ACQU_01",12) SS LastPseq 1 (0019,"GEMS_ACQU_01",13) SS StartNumberForBaseline 1 (0019,"GEMS_ACQU_01",14) SS End NumberForBaseline 1 (0019,"GEMS_ACQU_01",15) SS StartNumberForEnhancedScans 1 (0019,"GEMS_ACQU_01",16) SS EndNumberForEnhancedScans 1 (0019,"GEMS_ACQU_01",17) SS SeriesPlane 1 (0019,"GEMS_ACQU_01",18) LO FirstScanRAS 1 (0019,"GEMS_ACQU_01",19) DS FirstScanLocation 1 (0019,"GEMS_ACQU_01",1a) LO LastScanRAS 1 (0019,"GEMS_ACQU_01",1b) DS LastScanLocation 1 (0019,"GEMS_ACQU_01",1e) DS DisplayFieldOfView 1 (0019,"GEMS_ACQU_01",20) DS Unknown 1 (0019,"GEMS_ACQU_01",22) DS Unknown 1 (0019,"GEMS_ACQU_01",23) DS TableSpeed 1 (0019,"GEMS_ACQU_01",24) DS MidScanTime 1 (0019,"GEMS_ACQU_01",25) SS MidScanFlag 1 (0019,"GEMS_ACQU_01",26) SL DegreesOfAzimuth 1 (0019,"GEMS_ACQU_01",27) DS GantryPeriod 1 (0019,"GEMS_ACQU_01",2a) DS XrayOnPosition 1 (0019,"GEMS_ACQU_01",2b) DS XrayOffPosition 1 (0019,"GEMS_ACQU_01",2c) SL NumberOfTriggers 1 (0019,"GEMS_ACQU_01",2d) US Unknown 1 (0019,"GEMS_ACQU_01",2e) DS AngleOfFirstView 1 (0019,"GEMS_ACQU_01",2f) DS TriggerFrequency 1 (0019,"GEMS_ACQU_01",39) SS ScanFOVType 1 (0019,"GEMS_ACQU_01",3a) IS Unknown 1 (0019,"GEMS_ACQU_01",3b) LT Unknown 1 (0019,"GEMS_ACQU_01",3c) UN Unknown 1 (0019,"GEMS_ACQU_01",3e) UN Unknown 1 (0019,"GEMS_ACQU_01",3f) UN Unknown 1 (0019,"GEMS_ACQU_01",40) SS StatReconFlag 1 (0019,"GEMS_ACQU_01",41) SS ComputeType 1 (0019,"GEMS_ACQU_01",42) SS SegmentNumber 1 (0019,"GEMS_ACQU_01",43) SS TotalSegmentsRequested 1 (0019,"GEMS_ACQU_01",44) DS InterscanDelay 1 (0019,"GEMS_ACQU_01",47) SS ViewCompressionFactor 1 (0019,"GEMS_ACQU_01",48) US Unknown 1 (0019,"GEMS_ACQU_01",49) US Unknown 1 (0019,"GEMS_ACQU_01",4a) SS TotalNumberOfRefChannels 1 (0019,"GEMS_ACQU_01",4b) SL DataSizeForScanData 1 (0019,"GEMS_ACQU_01",52) SS ReconPostProcessingFlag 1 (0019,"GEMS_ACQU_01",54) UN Unknown 1 (0019,"GEMS_ACQU_01",57) SS CTWaterNumber 1 (0019,"GEMS_ACQU_01",58) SS CTBoneNumber 1 (0019,"GEMS_ACQU_01",5a) FL AcquisitionDuration 1 (0019,"GEMS_ACQU_01",5d) US Unknown 1 (0019,"GEMS_ACQU_01",5e) SL NumberOfChannels1To512 1 (0019,"GEMS_ACQU_01",5f) SL IncrementBetweenChannels 1 (0019,"GEMS_ACQU_01",60) SL StartingView 1 (0019,"GEMS_ACQU_01",61) SL NumberOfViews 1 (0019,"GEMS_ACQU_01",62) SL IncrementBetweenViews 1 (0019,"GEMS_ACQU_01",6a) SS DependantOnNumberOfViewsProcessed 1 (0019,"GEMS_ACQU_01",6b) SS FieldOfViewInDetectorCells 1 (0019,"GEMS_ACQU_01",70) SS ValueOfBackProjectionButton 1 (0019,"GEMS_ACQU_01",71) SS SetIfFatqEstimatesWereUsed 1 (0019,"GEMS_ACQU_01",72) DS ZChannelAvgOverViews 1 (0019,"GEMS_ACQU_01",73) DS AvgOfLeftRefChannelsOverViews 1 (0019,"GEMS_ACQU_01",74) DS MaxLeftChannelOverViews 1 (0019,"GEMS_ACQU_01",75) DS AvgOfRightRefChannelsOverViews 1 (0019,"GEMS_ACQU_01",76) DS MaxRightChannelOverViews 1 (0019,"GEMS_ACQU_01",7d) DS SecondEcho 1 (0019,"GEMS_ACQU_01",7e) SS NumberOfEchos 1 (0019,"GEMS_ACQU_01",7f) DS TableDelta 1 (0019,"GEMS_ACQU_01",81) SS Contiguous 1 (0019,"GEMS_ACQU_01",82) US Unknown 1 (0019,"GEMS_ACQU_01",83) DS Unknown 1 (0019,"GEMS_ACQU_01",84) DS PeakSAR 1 (0019,"GEMS_ACQU_01",85) SS MonitorSAR 1 (0019,"GEMS_ACQU_01",86) US Unknown 1 (0019,"GEMS_ACQU_01",87) DS CardiacRepetition Time 1 (0019,"GEMS_ACQU_01",88) SS ImagesPerCardiacCycle 1 (0019,"GEMS_ACQU_01",8a) SS ActualReceiveGainAnalog 1 (0019,"GEMS_ACQU_01",8b) SS ActualReceiveGainDigital 1 (0019,"GEMS_ACQU_01",8d) DS DelayAfterTrigger 1 (0019,"GEMS_ACQU_01",8f) SS SwapPhaseFrequency 1 (0019,"GEMS_ACQU_01",90) SS PauseInterval 1 (0019,"GEMS_ACQU_01",91) DS PulseTime 1 (0019,"GEMS_ACQU_01",92) SL SliceOffsetOnFrequencyAxis 1 (0019,"GEMS_ACQU_01",93) DS CenterFrequency 1 (0019,"GEMS_ACQU_01",94) SS TransmitGain 1 (0019,"GEMS_ACQU_01",95) SS AnalogReceiverGain 1 (0019,"GEMS_ACQU_01",96) SS DigitalReceiverGain 1 (0019,"GEMS_ACQU_01",97) SL BitmapDefiningCVs 1 (0019,"GEMS_ACQU_01",98) SS CenterFrequencyMethod 1 (0019,"GEMS_ACQU_01",99) US Unknown 1 (0019,"GEMS_ACQU_01",9b) SS PulseSequenceMode 1 (0019,"GEMS_ACQU_01",9c) LO PulseSequenceName 1 (0019,"GEMS_ACQU_01",9d) DT PulseSequenceDate 1 (0019,"GEMS_ACQU_01",9e) LO InternalPulseSequenceName 1 (0019,"GEMS_ACQU_01",9f) SS TransmittingCoil 1 (0019,"GEMS_ACQU_01",a0) SS SurfaceCoilType 1 (0019,"GEMS_ACQU_01",a1) SS ExtremityCoilFlag 1 (0019,"GEMS_ACQU_01",a2) SL RawDataRunNumber 1 (0019,"GEMS_ACQU_01",a3) UL CalibratedFieldStrength 1 (0019,"GEMS_ACQU_01",a4) SS SATFatWaterBone 1 (0019,"GEMS_ACQU_01",a5) DS ReceiveBandwidth 1 (0019,"GEMS_ACQU_01",a7) DS UserData 1 (0019,"GEMS_ACQU_01",a8) DS UserData 1 (0019,"GEMS_ACQU_01",a9) DS UserData 1 (0019,"GEMS_ACQU_01",aa) DS UserData 1 (0019,"GEMS_ACQU_01",ab) DS UserData 1 (0019,"GEMS_ACQU_01",ac) DS UserData 1 (0019,"GEMS_ACQU_01",ad) DS UserData 1 (0019,"GEMS_ACQU_01",ae) DS UserData 1 (0019,"GEMS_ACQU_01",af) DS UserData 1 (0019,"GEMS_ACQU_01",b0) DS UserData 1 (0019,"GEMS_ACQU_01",b1) DS UserData 1 (0019,"GEMS_ACQU_01",b2) DS UserData 1 (0019,"GEMS_ACQU_01",b3) DS UserData 1 (0019,"GEMS_ACQU_01",b4) DS UserData 1 (0019,"GEMS_ACQU_01",b5) DS UserData 1 (0019,"GEMS_ACQU_01",b6) DS UserData 1 (0019,"GEMS_ACQU_01",b7) DS UserData 1 (0019,"GEMS_ACQU_01",b8) DS UserData 1 (0019,"GEMS_ACQU_01",b9) DS UserData 1 (0019,"GEMS_ACQU_01",ba) DS UserData 1 (0019,"GEMS_ACQU_01",bb) DS UserData 1 (0019,"GEMS_ACQU_01",bc) DS UserData 1 (0019,"GEMS_ACQU_01",bd) DS UserData 1 (0019,"GEMS_ACQU_01",be) DS ProjectionAngle 1 (0019,"GEMS_ACQU_01",c0) SS SaturationPlanes 1 (0019,"GEMS_ACQU_01",c1) SS SurfaceCoilIntensityCorrectionFlag 1 (0019,"GEMS_ACQU_01",c2) SS SATLocationR 1 (0019,"GEMS_ACQU_01",c3) SS SATLocationL 1 (0019,"GEMS_ACQU_01",c4) SS SATLocationA 1 (0019,"GEMS_ACQU_01",c5) SS SATLocationP 1 (0019,"GEMS_ACQU_01",c6) SS SATLocationH 1 (0019,"GEMS_ACQU_01",c7) SS SATLocationF 1 (0019,"GEMS_ACQU_01",c8) SS SATThicknessRL 1 (0019,"GEMS_ACQU_01",c9) SS SATThicknessAP 1 (0019,"GEMS_ACQU_01",ca) SS SATThicknessHF 1 (0019,"GEMS_ACQU_01",cb) SS PrescribedFlowAxis 1 (0019,"GEMS_ACQU_01",cc) SS VelocityEncoding 1 (0019,"GEMS_ACQU_01",cd) SS ThicknessDisclaimer 1 (0019,"GEMS_ACQU_01",ce) SS PrescanType 1 (0019,"GEMS_ACQU_01",cf) SS PrescanStatus 1 (0019,"GEMS_ACQU_01",d0) SH RawDataType 1 (0019,"GEMS_ACQU_01",d2) SS ProjectionAlgorithm 1 (0019,"GEMS_ACQU_01",d3) SH ProjectionAlgorithm 1 (0019,"GEMS_ACQU_01",d4) US Unknown 1 (0019,"GEMS_ACQU_01",d5) SS FractionalEcho 1 (0019,"GEMS_ACQU_01",d6) SS PrepPulse 1 (0019,"GEMS_ACQU_01",d7) SS CardiacPhases 1 (0019,"GEMS_ACQU_01",d8) SS VariableEchoFlag 1 (0019,"GEMS_ACQU_01",d9) DS ConcatenatedSAT 1 (0019,"GEMS_ACQU_01",da) SS ReferenceChannelUsed 1 (0019,"GEMS_ACQU_01",db) DS BackProjectorCoefficient 1 (0019,"GEMS_ACQU_01",dc) SS PrimarySpeedCorrectionUsed 1 (0019,"GEMS_ACQU_01",dd) SS OverrangeCorrectionUsed 1 (0019,"GEMS_ACQU_01",de) DS DynamicZAlphaValue 1 (0019,"GEMS_ACQU_01",df) DS UserData 1 (0019,"GEMS_ACQU_01",e0) DS UserData 1 (0019,"GEMS_ACQU_01",e1) DS Unknown 1 (0019,"GEMS_ACQU_01",e2) DS VelocityEncodeScale 1 (0019,"GEMS_ACQU_01",e3) LT Unknown 1 (0019,"GEMS_ACQU_01",e4) LT Unknown 1 (0019,"GEMS_ACQU_01",e5) IS Unknown 1 (0019,"GEMS_ACQU_01",e6) US Unknown 1 (0019,"GEMS_ACQU_01",e8) DS Unknown 1 (0019,"GEMS_ACQU_01",e9) DS Unknown 1 (0019,"GEMS_ACQU_01",eb) DS Unknown 1 (0019,"GEMS_ACQU_01",ec) US Unknown 1 (0019,"GEMS_ACQU_01",f0) UN Unknown 1 (0019,"GEMS_ACQU_01",f1) LT Unknown 1 (0019,"GEMS_ACQU_01",f2) SS FastPhases 1 (0019,"GEMS_ACQU_01",f3) LT Unknown 1 (0019,"GEMS_ACQU_01",f4) LT Unknown 1 (0019,"GEMS_ACQU_01",f9) DS TransmissionGain 1 (0023,"GEMS_ACRQA_1.0 BLOCK1",00) LO CRExposureMenuCode 1 (0023,"GEMS_ACRQA_1.0 BLOCK1",10) LO CRExposureMenuString 1 (0023,"GEMS_ACRQA_1.0 BLOCK1",20) LO CREDRMode 1 (0023,"GEMS_ACRQA_1.0 BLOCK1",30) LO CRLatitude 1 (0023,"GEMS_ACRQA_1.0 BLOCK1",40) LO CRGroupNumber 1 (0023,"GEMS_ACRQA_1.0 BLOCK1",50) US CRImageSerialNumber 1 (0023,"GEMS_ACRQA_1.0 BLOCK1",60) LO CRBarCodeNumber 1 (0023,"GEMS_ACRQA_1.0 BLOCK1",70) LO CRFilmOutputExposure 1 (0023,"GEMS_ACRQA_1.0 BLOCK1",80) LO CRFilmFormat 1 (0023,"GEMS_ACRQA_1.0 BLOCK1",90) LO CRSShiftString 1 (0023,"GEMS_ACRQA_1.0 BLOCK2",00) US CRSShift 1 (0023,"GEMS_ACRQA_1.0 BLOCK2",10) DS CRCShift 1 (0023,"GEMS_ACRQA_1.0 BLOCK2",20) DS CRGT 1 (0023,"GEMS_ACRQA_1.0 BLOCK2",30) DS CRGA 1 (0023,"GEMS_ACRQA_1.0 BLOCK2",40) DS CRGC 1 (0023,"GEMS_ACRQA_1.0 BLOCK2",50) DS CRGS 1 (0023,"GEMS_ACRQA_1.0 BLOCK2",60) DS CRRT 1 (0023,"GEMS_ACRQA_1.0 BLOCK2",70) DS CRRE 1 (0023,"GEMS_ACRQA_1.0 BLOCK2",80) US CRRN 1 (0023,"GEMS_ACRQA_1.0 BLOCK2",90) DS CRDRT 1 (0023,"GEMS_ACRQA_1.0 BLOCK3",00) DS CRDRE 1 (0023,"GEMS_ACRQA_1.0 BLOCK3",10) US CRDRN 1 (0023,"GEMS_ACRQA_1.0 BLOCK3",20) DS CRORE 1 (0023,"GEMS_ACRQA_1.0 BLOCK3",30) US CRORN 1 (0023,"GEMS_ACRQA_1.0 BLOCK3",40) US CRORD 1 (0023,"GEMS_ACRQA_1.0 BLOCK3",50) LO CRCassetteSize 1 (0023,"GEMS_ACRQA_1.0 BLOCK3",60) LO CRMachineID 1 (0023,"GEMS_ACRQA_1.0 BLOCK3",70) LO CRMachineType 1 (0023,"GEMS_ACRQA_1.0 BLOCK3",80) LO CRTechnicianCode 1 (0023,"GEMS_ACRQA_1.0 BLOCK3",90) LO CREnergySubtractionParameters 1 (0023,"GEMS_ACRQA_2.0 BLOCK1",00) LO CRExposureMenuCode 1 (0023,"GEMS_ACRQA_2.0 BLOCK1",10) LO CRExposureMenuString 1 (0023,"GEMS_ACRQA_2.0 BLOCK1",20) LO CREDRMode 1 (0023,"GEMS_ACRQA_2.0 BLOCK1",30) LO CRLatitude 1 (0023,"GEMS_ACRQA_2.0 BLOCK1",40) LO CRGroupNumber 1 (0023,"GEMS_ACRQA_2.0 BLOCK1",50) US CRImageSerialNumber 1 (0023,"GEMS_ACRQA_2.0 BLOCK1",60) LO CRBarCodeNumber 1 (0023,"GEMS_ACRQA_2.0 BLOCK1",70) LO CRFilmOutputExposure 1 (0023,"GEMS_ACRQA_2.0 BLOCK1",80) LO CRFilmFormat 1 (0023,"GEMS_ACRQA_2.0 BLOCK1",90) LO CRSShiftString 1 (0023,"GEMS_ACRQA_2.0 BLOCK2",00) US CRSShift 1 (0023,"GEMS_ACRQA_2.0 BLOCK2",10) LO CRCShift 1 (0023,"GEMS_ACRQA_2.0 BLOCK2",20) LO CRGT 1 (0023,"GEMS_ACRQA_2.0 BLOCK2",30) DS CRGA 1 (0023,"GEMS_ACRQA_2.0 BLOCK2",40) DS CRGC 1 (0023,"GEMS_ACRQA_2.0 BLOCK2",50) DS CRGS 1 (0023,"GEMS_ACRQA_2.0 BLOCK2",60) LO CRRT 1 (0023,"GEMS_ACRQA_2.0 BLOCK2",70) DS CRRE 1 (0023,"GEMS_ACRQA_2.0 BLOCK2",80) US CRRN 1 (0023,"GEMS_ACRQA_2.0 BLOCK2",90) DS CRDRT 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",00) DS CRDRE 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",10) US CRDRN 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",20) DS CRORE 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",30) US CRORN 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",40) US CRORD 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",50) LO CRCassetteSize 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",60) LO CRMachineID 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",70) LO CRMachineType 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",80) LO CRTechnicianCode 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",90) LO CREnergySubtractionParameters 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",f0) LO CRDistributionCode 1 (0023,"GEMS_ACRQA_2.0 BLOCK3",ff) US CRShuttersApplied 1 (0047,"GEMS_ADWSoft_3D1",01) SQ Reconstruction Parameters Sequence 1 (0047,"GEMS_ADWSoft_3D1",50) UL VolumeVoxelCount 1 (0047,"GEMS_ADWSoft_3D1",51) UL VolumeSegmentCount 1 (0047,"GEMS_ADWSoft_3D1",53) US VolumeSliceSize 1 (0047,"GEMS_ADWSoft_3D1",54) US VolumeSliceCount 1 (0047,"GEMS_ADWSoft_3D1",55) SL VolumeThresholdValue 1 (0047,"GEMS_ADWSoft_3D1",57) DS VolumeVoxelRatio 1 (0047,"GEMS_ADWSoft_3D1",58) DS VolumeVoxelSize 1 (0047,"GEMS_ADWSoft_3D1",59) US VolumeZPositionSize 1 (0047,"GEMS_ADWSoft_3D1",60) DS VolumeBaseLine 9 (0047,"GEMS_ADWSoft_3D1",61) DS VolumeCenterPoint 3 (0047,"GEMS_ADWSoft_3D1",63) SL VolumeSkewBase 1 (0047,"GEMS_ADWSoft_3D1",64) DS VolumeRegistrationTransformRotationMatrix 9 (0047,"GEMS_ADWSoft_3D1",65) DS VolumeRegistrationTransformTranslationVector 3 (0047,"GEMS_ADWSoft_3D1",70) DS KVPList 1-n (0047,"GEMS_ADWSoft_3D1",71) IS XRayTubeCurrentList 1-n (0047,"GEMS_ADWSoft_3D1",72) IS ExposureList 1-n (0047,"GEMS_ADWSoft_3D1",80) LO AcquisitionDLXIdentifier 1 (0047,"GEMS_ADWSoft_3D1",85) SQ AcquisitionDLX2DSeriesSequence 1 (0047,"GEMS_ADWSoft_3D1",89) DS ContrastAgentVolumeList 1-n (0047,"GEMS_ADWSoft_3D1",8A) US NumberOfInjections 1 (0047,"GEMS_ADWSoft_3D1",8B) US FrameCount 1 (0047,"GEMS_ADWSoft_3D1",91) LO XA3DReconstructionAlgorithmName 1 (0047,"GEMS_ADWSoft_3D1",92) CS XA3DReconstructionAlgorithmVersion 1 (0047,"GEMS_ADWSoft_3D1",93) DA DLXCalibrationDate 1 (0047,"GEMS_ADWSoft_3D1",94) TM DLXCalibrationTime 1 (0047,"GEMS_ADWSoft_3D1",95) CS DLXCalibrationStatus 1 (0047,"GEMS_ADWSoft_3D1",96) IS UsedFrames 1-n (0047,"GEMS_ADWSoft_3D1",98) US TransformCount 1 (0047,"GEMS_ADWSoft_3D1",99) SQ TransformSequence 1 (0047,"GEMS_ADWSoft_3D1",9A) DS TransformRotationMatrix 9 (0047,"GEMS_ADWSoft_3D1",9B) DS TransformTranslationVector 3 (0047,"GEMS_ADWSoft_3D1",9C) LO TransformLabel 1 (0047,"GEMS_ADWSoft_3D1",B0) SQ WireframeList 1 (0047,"GEMS_ADWSoft_3D1",B1) US WireframeCount 1 (0047,"GEMS_ADWSoft_3D1",B2) US LocationSystem 1 (0047,"GEMS_ADWSoft_3D1",B5) LO WireframeName 1 (0047,"GEMS_ADWSoft_3D1",B6) LO WireframeGroupName 1 (0047,"GEMS_ADWSoft_3D1",B7) LO WireframeColor 1 (0047,"GEMS_ADWSoft_3D1",B8) SL WireframeAttributes 1 (0047,"GEMS_ADWSoft_3D1",B9) SL WireframePointCount 1 (0047,"GEMS_ADWSoft_3D1",BA) SL WireframeTimestamp 1 (0047,"GEMS_ADWSoft_3D1",BB) SQ WireframePointList 1 (0047,"GEMS_ADWSoft_3D1",BC) DS WireframePointsCoordinates 3 (0047,"GEMS_ADWSoft_3D1",C0) DS VolumeUpperLeftHighCornerRAS 3 (0047,"GEMS_ADWSoft_3D1",C1) DS VolumeSliceToRASRotationMatrix 9 (0047,"GEMS_ADWSoft_3D1",C2) DS VolumeUpperLeftHighCornerTLOC 1 (0047,"GEMS_ADWSoft_3D1",D1) OB VolumeSegmentList 1 (0047,"GEMS_ADWSoft_3D1",D2) OB VolumeGradientList 1 (0047,"GEMS_ADWSoft_3D1",D3) OB VolumeDensityList 1 (0047,"GEMS_ADWSoft_3D1",D4) OB VolumeZPositionList 1 (0047,"GEMS_ADWSoft_3D1",D5) OB VolumeOriginalIndexList 1 (0039,"GEMS_ADWSoft_DPO",80) IS PrivateEntityNumber 1 (0039,"GEMS_ADWSoft_DPO",85) DA PrivateEntityDate 1 (0039,"GEMS_ADWSoft_DPO",90) TM PrivateEntityTime 1 (0039,"GEMS_ADWSoft_DPO",95) LO PrivateEntityLaunchCommand 1 (0039,"GEMS_ADWSoft_DPO",AA) CS PrivateEntityType 1 (0033,"GEMS_CTHD_01",02) UN Unknown 1 (0037,"GEMS_DRS_1",10) LO ReferringDepartment 1 (0037,"GEMS_DRS_1",20) US ScreenNumber 1 (0037,"GEMS_DRS_1",40) SH LeftOrientation 1 (0037,"GEMS_DRS_1",42) SH RightOrientation 1 (0037,"GEMS_DRS_1",50) CS Inversion 1 (0037,"GEMS_DRS_1",60) US DSA 1 (0009,"GEMS_GENIE_1",10) LO Unknown 1 (0009,"GEMS_GENIE_1",11) SL StudyFlags 1 (0009,"GEMS_GENIE_1",12) SL StudyType 1 (0009,"GEMS_GENIE_1",1e) UI Unknown 1 (0009,"GEMS_GENIE_1",20) LO Unknown 1 (0009,"GEMS_GENIE_1",21) SL SeriesFlags 1 (0009,"GEMS_GENIE_1",22) SH UserOrientation 1 (0009,"GEMS_GENIE_1",23) SL InitiationType 1 (0009,"GEMS_GENIE_1",24) SL InitiationDelay 1 (0009,"GEMS_GENIE_1",25) SL InitiationCountRate 1 (0009,"GEMS_GENIE_1",26) SL NumberEnergySets 1 (0009,"GEMS_GENIE_1",27) SL NumberDetectors 1 (0009,"GEMS_GENIE_1",29) SL Unknown 1 (0009,"GEMS_GENIE_1",2a) SL Unknown 1 (0009,"GEMS_GENIE_1",2c) LO SeriesComments 1 (0009,"GEMS_GENIE_1",2d) SL TrackBeatAverage 1 (0009,"GEMS_GENIE_1",2e) FD DistancePrescribed 1 (0009,"GEMS_GENIE_1",30) LO Unknown 1 (0009,"GEMS_GENIE_1",35) SL GantryLocusType 1 (0009,"GEMS_GENIE_1",37) SL StartingHeartRate 1 (0009,"GEMS_GENIE_1",38) SL RRWindowWidth 1 (0009,"GEMS_GENIE_1",39) SL RRWindowOffset 1 (0009,"GEMS_GENIE_1",3a) SL PercentCycleImaged 1 (0009,"GEMS_GENIE_1",40) LO Unknown 1 (0009,"GEMS_GENIE_1",41) SL PatientFlags 1 (0009,"GEMS_GENIE_1",42) DA PatientCreationDate 1 (0009,"GEMS_GENIE_1",43) TM PatientCreationTime 1 (0011,"GEMS_GENIE_1",0a) SL SeriesType 1 (0011,"GEMS_GENIE_1",0b) SL EffectiveSeriesDuration 1 (0011,"GEMS_GENIE_1",0c) SL NumBeats 1 (0011,"GEMS_GENIE_1",0d) LO RadioNuclideName 1 (0011,"GEMS_GENIE_1",10) LO Unknown 1 (0011,"GEMS_GENIE_1",12) LO DatasetName 1 (0011,"GEMS_GENIE_1",13) SL DatasetType 1 (0011,"GEMS_GENIE_1",15) SL DetectorNumber 1 (0011,"GEMS_GENIE_1",16) SL EnergyNumber 1 (0011,"GEMS_GENIE_1",17) SL RRIntervalWindowNumber 1 (0011,"GEMS_GENIE_1",18) SL MGBinNumber 1 (0011,"GEMS_GENIE_1",19) FD RadiusOfRotation 1 (0011,"GEMS_GENIE_1",1a) SL DetectorCountZone 1 (0011,"GEMS_GENIE_1",1b) SL NumEnergyWindows 1 (0011,"GEMS_GENIE_1",1c) SL EnergyOffset 4 (0011,"GEMS_GENIE_1",1d) SL EnergyRange 1 (0011,"GEMS_GENIE_1",1f) SL ImageOrientation 1 (0011,"GEMS_GENIE_1",23) SL UseFOVMask 1 (0011,"GEMS_GENIE_1",24) SL FOVMaskYCutoffAngle 1 (0011,"GEMS_GENIE_1",25) SL FOVMaskCutoffAngle 1 (0011,"GEMS_GENIE_1",26) SL TableOrientation 1 (0011,"GEMS_GENIE_1",27) SL ROITopLeft 2 (0011,"GEMS_GENIE_1",28) SL ROIBottomRight 2 (0011,"GEMS_GENIE_1",30) LO Unknown 1 (0011,"GEMS_GENIE_1",33) LO EnergyCorrectName 1 (0011,"GEMS_GENIE_1",34) LO SpatialCorrectName 1 (0011,"GEMS_GENIE_1",35) LO TuningCalibName 1 (0011,"GEMS_GENIE_1",36) LO UniformityCorrectName 1 (0011,"GEMS_GENIE_1",37) LO AcquisitionSpecificCorrectName 1 (0011,"GEMS_GENIE_1",38) SL ByteOrder 1 (0011,"GEMS_GENIE_1",3a) SL PictureFormat 1 (0011,"GEMS_GENIE_1",3b) FD PixelScale 1 (0011,"GEMS_GENIE_1",3c) FD PixelOffset 1 (0011,"GEMS_GENIE_1",3e) SL FOVShape 1 (0011,"GEMS_GENIE_1",3f) SL DatasetFlags 1 (0011,"GEMS_GENIE_1",44) FD ThresholdCenter 1 (0011,"GEMS_GENIE_1",45) FD ThresholdWidth 1 (0011,"GEMS_GENIE_1",46) SL InterpolationType 1 (0011,"GEMS_GENIE_1",55) FD Period 1 (0011,"GEMS_GENIE_1",56) FD ElapsedTime 1 (0013,"GEMS_GENIE_1",10) FD DigitalFOV 2 (0013,"GEMS_GENIE_1",11) SL Unknown 1 (0013,"GEMS_GENIE_1",12) SL Unknown 1 (0013,"GEMS_GENIE_1",16) SL AutoTrackPeak 1 (0013,"GEMS_GENIE_1",17) SL AutoTrackWidth 1 (0013,"GEMS_GENIE_1",18) FD TransmissionScanTime 1 (0013,"GEMS_GENIE_1",19) FD TransmissionMaskWidth 1 (0013,"GEMS_GENIE_1",1a) FD CopperAttenuatorThickness 1 (0013,"GEMS_GENIE_1",1c) FD Unknown 1 (0013,"GEMS_GENIE_1",1d) FD Unknown 1 (0013,"GEMS_GENIE_1",1e) FD TomoViewOffset 1-n (0013,"GEMS_GENIE_1",26) LT StudyComments 1 (0033,"GEMS_GNHD_01",01) UN Unknown 1 (0033,"GEMS_GNHD_01",02) UN Unknown 1 (0009,"GEMS_IDEN_01",01) LO FullFidelity 1 (0009,"GEMS_IDEN_01",02) SH SuiteId 1 (0009,"GEMS_IDEN_01",04) SH ProductId 1 (0009,"GEMS_IDEN_01",17) LT Unknown 1 (0009,"GEMS_IDEN_01",1a) US Unknown 1 (0009,"GEMS_IDEN_01",20) US Unknown 1 (0009,"GEMS_IDEN_01",27) SL ImageActualDate 1 (0009,"GEMS_IDEN_01",2f) LT Unknown 1 (0009,"GEMS_IDEN_01",30) SH ServiceId 1 (0009,"GEMS_IDEN_01",31) SH MobileLocationNumber 1 (0009,"GEMS_IDEN_01",e2) LT Unknown 1 (0009,"GEMS_IDEN_01",e3) UI EquipmentUID 1 (0009,"GEMS_IDEN_01",e6) SH GenesisVersionNow 1 (0009,"GEMS_IDEN_01",e7) UL ExamRecordChecksum 1 (0009,"GEMS_IDEN_01",e8) UL Unknown 1 (0009,"GEMS_IDEN_01",e9) SL ActualSeriesDataTimeStamp 1 (0027,"GEMS_IMAG_01",06) SL ImageArchiveFlag 1 (0027,"GEMS_IMAG_01",10) SS ScoutType 1 (0027,"GEMS_IMAG_01",1c) SL VmaMamp 1 (0027,"GEMS_IMAG_01",1d) SS VmaPhase 1 (0027,"GEMS_IMAG_01",1e) SL VmaMod 1 (0027,"GEMS_IMAG_01",1f) SL VmaClip 1 (0027,"GEMS_IMAG_01",20) SS SmartScanOnOffFlag 1 (0027,"GEMS_IMAG_01",30) SH ForeignImageRevision 1 (0027,"GEMS_IMAG_01",31) SS ImagingMode 1 (0027,"GEMS_IMAG_01",32) SS PulseSequence 1 (0027,"GEMS_IMAG_01",33) SL ImagingOptions 1 (0027,"GEMS_IMAG_01",35) SS PlaneType 1 (0027,"GEMS_IMAG_01",36) SL ObliquePlane 1 (0027,"GEMS_IMAG_01",40) SH RASLetterOfImageLocation 1 (0027,"GEMS_IMAG_01",41) FL ImageLocation 1 (0027,"GEMS_IMAG_01",42) FL CenterRCoordOfPlaneImage 1 (0027,"GEMS_IMAG_01",43) FL CenterACoordOfPlaneImage 1 (0027,"GEMS_IMAG_01",44) FL CenterSCoordOfPlaneImage 1 (0027,"GEMS_IMAG_01",45) FL NormalRCoord 1 (0027,"GEMS_IMAG_01",46) FL NormalACoord 1 (0027,"GEMS_IMAG_01",47) FL NormalSCoord 1 (0027,"GEMS_IMAG_01",48) FL RCoordOfTopRightCorner 1 (0027,"GEMS_IMAG_01",49) FL ACoordOfTopRightCorner 1 (0027,"GEMS_IMAG_01",4a) FL SCoordOfTopRightCorner 1 (0027,"GEMS_IMAG_01",4b) FL RCoordOfBottomRightCorner 1 (0027,"GEMS_IMAG_01",4c) FL ACoordOfBottomRightCorner 1 (0027,"GEMS_IMAG_01",4d) FL SCoordOfBottomRightCorner 1 (0027,"GEMS_IMAG_01",50) FL TableStartLocation 1 (0027,"GEMS_IMAG_01",51) FL TableEndLocation 1 (0027,"GEMS_IMAG_01",52) SH RASLetterForSideOfImage 1 (0027,"GEMS_IMAG_01",53) SH RASLetterForAnteriorPosterior 1 (0027,"GEMS_IMAG_01",54) SH RASLetterForScoutStartLoc 1 (0027,"GEMS_IMAG_01",55) SH RASLetterForScoutEndLoc 1 (0027,"GEMS_IMAG_01",60) FL ImageDimensionX 1 (0027,"GEMS_IMAG_01",61) FL ImageDimensionY 1 (0027,"GEMS_IMAG_01",62) FL NumberOfExcitations 1 (0029,"GEMS_IMPS_01",04) SL LowerRangeOfPixels 1 (0029,"GEMS_IMPS_01",05) DS LowerRangeOfPixels 1 (0029,"GEMS_IMPS_01",06) DS LowerRangeOfPixels 1 (0029,"GEMS_IMPS_01",07) SL LowerRangeOfPixels 1 (0029,"GEMS_IMPS_01",08) SH LowerRangeOfPixels 1 (0029,"GEMS_IMPS_01",09) SH LowerRangeOfPixels 1 (0029,"GEMS_IMPS_01",0a) SS LowerRangeOfPixels 1 (0029,"GEMS_IMPS_01",15) SL LowerRangeOfPixels 1 (0029,"GEMS_IMPS_01",16) SL LowerRangeOfPixels 1 (0029,"GEMS_IMPS_01",17) SL LowerRangeOfPixels 1 (0029,"GEMS_IMPS_01",18) SL UpperRangeOfPixels 1 (0029,"GEMS_IMPS_01",1a) SL LengthOfTotalHeaderInBytes 1 (0029,"GEMS_IMPS_01",26) SS VersionOfHeaderStructure 1 (0029,"GEMS_IMPS_01",34) SL AdvantageCompOverflow 1 (0029,"GEMS_IMPS_01",35) SL AdvantageCompUnderflow 1 (0043,"GEMS_PARM_01",01) SS BitmapOfPrescanOptions 1 (0043,"GEMS_PARM_01",02) SS GradientOffsetInX 1 (0043,"GEMS_PARM_01",03) SS GradientOffsetInY 1 (0043,"GEMS_PARM_01",04) SS GradientOffsetInZ 1 (0043,"GEMS_PARM_01",05) SS ImageIsOriginalOrUnoriginal 1 (0043,"GEMS_PARM_01",06) SS NumberOfEPIShots 1 (0043,"GEMS_PARM_01",07) SS ViewsPerSegment 1 (0043,"GEMS_PARM_01",08) SS RespiratoryRateInBPM 1 (0043,"GEMS_PARM_01",09) SS RespiratoryTriggerPoint 1 (0043,"GEMS_PARM_01",0a) SS TypeOfReceiverUsed 1 (0043,"GEMS_PARM_01",0b) DS PeakRateOfChangeOfGradientField 1 (0043,"GEMS_PARM_01",0c) DS LimitsInUnitsOfPercent 1 (0043,"GEMS_PARM_01",0d) DS PSDEstimatedLimit 1 (0043,"GEMS_PARM_01",0e) DS PSDEstimatedLimitInTeslaPerSecond 1 (0043,"GEMS_PARM_01",0f) DS SARAvgHead 1 (0043,"GEMS_PARM_01",10) US WindowValue 1 (0043,"GEMS_PARM_01",11) US TotalInputViews 1 (0043,"GEMS_PARM_01",12) SS XrayChain 3 (0043,"GEMS_PARM_01",13) SS ReconKernelParameters 5 (0043,"GEMS_PARM_01",14) SS CalibrationParameters 3 (0043,"GEMS_PARM_01",15) SS TotalOutputViews 3 (0043,"GEMS_PARM_01",16) SS NumberOfOverranges 5 (0043,"GEMS_PARM_01",17) DS IBHImageScaleFactors 1 (0043,"GEMS_PARM_01",18) DS BBH Coefficients 3 (0043,"GEMS_PARM_01",19) SS NumberOfBBHChainsToBlend 1 (0043,"GEMS_PARM_01",1a) SL StartingChannelNumber 1 (0043,"GEMS_PARM_01",1b) SS PPScanParameters 1 (0043,"GEMS_PARM_01",1c) SS GEImageIntegrity 1 (0043,"GEMS_PARM_01",1d) SS LevelValue 1 (0043,"GEMS_PARM_01",1e) DS DeltaStartTime 1 (0043,"GEMS_PARM_01",1f) SL MaxOverrangesInAView 1 (0043,"GEMS_PARM_01",20) DS AvgOverrangesAllViews 1 (0043,"GEMS_PARM_01",21) SS CorrectedAfterglowTerms 1 (0043,"GEMS_PARM_01",25) SS ReferenceChannels 6 (0043,"GEMS_PARM_01",26) US NoViewsRefChannelsBlocked 6 (0043,"GEMS_PARM_01",27) SH ScanPitchRatio 1 (0043,"GEMS_PARM_01",28) OB UniqueImageIdentifier 1 (0043,"GEMS_PARM_01",29) OB HistogramTables 1 (0043,"GEMS_PARM_01",2a) OB UserDefinedData 1 (0043,"GEMS_PARM_01",2b) SS PrivateScanOptions 4 (0043,"GEMS_PARM_01",2c) SS EffectiveEchoSpacing 1 (0043,"GEMS_PARM_01",2d) SH StringSlopField1 1 (0043,"GEMS_PARM_01",2e) SH StringSlopField2 1 (0043,"GEMS_PARM_01",2f) SS RawDataType 1 (0043,"GEMS_PARM_01",30) SS RawDataType 1 (0043,"GEMS_PARM_01",31) DS RACoordOfTargetReconCentre 2 (0043,"GEMS_PARM_01",32) SS RawDataType 1 (0043,"GEMS_PARM_01",33) FL NegScanSpacing 1 (0043,"GEMS_PARM_01",34) IS OffsetFrequency 1 (0043,"GEMS_PARM_01",35) UL UserUsageTag 1 (0043,"GEMS_PARM_01",36) UL UserFillMapMSW 1 (0043,"GEMS_PARM_01",37) UL UserFillMapLSW 1 (0043,"GEMS_PARM_01",38) FL User25ToUser48 24 (0043,"GEMS_PARM_01",39) IS SlopInteger6ToSlopInteger9 4 (0043,"GEMS_PARM_01",40) FL TriggerOnPosition 4 (0043,"GEMS_PARM_01",41) FL DegreeOfRotation 4 (0043,"GEMS_PARM_01",42) SL DASTriggerSource 4 (0043,"GEMS_PARM_01",43) SL DASFpaGain 4 (0043,"GEMS_PARM_01",44) SL DASOutputSource 4 (0043,"GEMS_PARM_01",45) SL DASAdInput 4 (0043,"GEMS_PARM_01",46) SL DASCalMode 4 (0043,"GEMS_PARM_01",47) SL DASCalFrequency 4 (0043,"GEMS_PARM_01",48) SL DASRegXm 4 (0043,"GEMS_PARM_01",49) SL DASAutoZero 4 (0043,"GEMS_PARM_01",4a) SS StartingChannelOfView 4 (0043,"GEMS_PARM_01",4b) SL DASXmPattern 4 (0043,"GEMS_PARM_01",4c) SS TGGCTriggerMode 4 (0043,"GEMS_PARM_01",4d) FL StartScanToXrayOnDelay 4 (0043,"GEMS_PARM_01",4e) FL DurationOfXrayOn 4 (0043,"GEMS_PARM_01",60) IS Unknown 8 (0043,"GEMS_PARM_01",61) UI Unknown 1 (0043,"GEMS_PARM_01",62) SH Unknown 1 (0043,"GEMS_PARM_01",6f) DS Unknown 3 (0011,"GEMS_PATI_01",10) SS PatientStatus 1 (0021,"GEMS_RELA_01",03) SS SeriesFromWhichPrescribed 1 (0021,"GEMS_RELA_01",05) SH GenesisVersionNow 1 (0021,"GEMS_RELA_01",07) UL SeriesRecordChecksum 1 (0021,"GEMS_RELA_01",15) US Unknown 1 (0021,"GEMS_RELA_01",16) SS Unknown 1 (0021,"GEMS_RELA_01",18) SH GenesisVersionNow 1 (0021,"GEMS_RELA_01",19) UL AcqReconRecordChecksum 1 (0021,"GEMS_RELA_01",20) DS TableStartLocation 1 (0021,"GEMS_RELA_01",35) SS SeriesFromWhichPrescribed 1 (0021,"GEMS_RELA_01",36) SS ImageFromWhichPrescribed 1 (0021,"GEMS_RELA_01",37) SS ScreenFormat 1 (0021,"GEMS_RELA_01",4a) LO AnatomicalReferenceForScout 1 (0021,"GEMS_RELA_01",4e) US Unknown 1 (0021,"GEMS_RELA_01",4f) SS LocationsInAcquisition 1 (0021,"GEMS_RELA_01",50) SS GraphicallyPrescribed 1 (0021,"GEMS_RELA_01",51) DS RotationFromSourceXRot 1 (0021,"GEMS_RELA_01",52) DS RotationFromSourceYRot 1 (0021,"GEMS_RELA_01",53) DS RotationFromSourceZRot 1 (0021,"GEMS_RELA_01",54) SH ImagePosition 3 (0021,"GEMS_RELA_01",55) SH ImageOrientation 6 (0021,"GEMS_RELA_01",56) SL IntegerSlop 1 (0021,"GEMS_RELA_01",57) SL IntegerSlop 1 (0021,"GEMS_RELA_01",58) SL IntegerSlop 1 (0021,"GEMS_RELA_01",59) SL IntegerSlop 1 (0021,"GEMS_RELA_01",5a) SL IntegerSlop 1 (0021,"GEMS_RELA_01",5b) DS FloatSlop 1 (0021,"GEMS_RELA_01",5c) DS FloatSlop 1 (0021,"GEMS_RELA_01",5d) DS FloatSlop 1 (0021,"GEMS_RELA_01",5e) DS FloatSlop 1 (0021,"GEMS_RELA_01",5f) DS FloatSlop 1 (0021,"GEMS_RELA_01",70) LT Unknown 1 (0021,"GEMS_RELA_01",71) LT Unknown 1 (0021,"GEMS_RELA_01",81) DS AutoWindowLevelAlpha 1 (0021,"GEMS_RELA_01",82) DS AutoWindowLevelBeta 1 (0021,"GEMS_RELA_01",83) DS AutoWindowLevelWindow 1 (0021,"GEMS_RELA_01",84) DS AutoWindowLevelLevel 1 (0021,"GEMS_RELA_01",90) SS TubeFocalSpotPosition 1 (0021,"GEMS_RELA_01",91) SS BiopsyPosition 1 (0021,"GEMS_RELA_01",92) FL BiopsyTLocation 1 (0021,"GEMS_RELA_01",93) FL BiopsyRefLocation 1 (0045,"GEMS_SENO_02",04) CS AES 1 (0045,"GEMS_SENO_02",06) DS Angulation 1 (0045,"GEMS_SENO_02",09) DS RealMagnificationFactor 1 (0045,"GEMS_SENO_02",0b) CS SenographType 1 (0045,"GEMS_SENO_02",0c) DS IntegrationTime 1 (0045,"GEMS_SENO_02",0d) DS ROIOriginXY 1 (0045,"GEMS_SENO_02",11) DS ReceptorSizeCmXY 2 (0045,"GEMS_SENO_02",12) IS ReceptorSizePixelsXY 2 (0045,"GEMS_SENO_02",13) ST Screen 1 (0045,"GEMS_SENO_02",14) DS PixelPitchMicrons 1 (0045,"GEMS_SENO_02",15) IS PixelDepthBits 1 (0045,"GEMS_SENO_02",16) IS BinningFactorXY 2 (0045,"GEMS_SENO_02",1B) CS ClinicalView 1 (0045,"GEMS_SENO_02",1D) DS MeanOfRawGrayLevels 1 (0045,"GEMS_SENO_02",1E) DS MeanOfOffsetGrayLevels 1 (0045,"GEMS_SENO_02",1F) DS MeanOfCorrectedGrayLevels 1 (0045,"GEMS_SENO_02",20) DS MeanOfRegionGrayLevels 1 (0045,"GEMS_SENO_02",21) DS MeanOfLogRegionGrayLevels 1 (0045,"GEMS_SENO_02",22) DS StandardDeviationOfRawGrayLevels 1 (0045,"GEMS_SENO_02",23) DS StandardDeviationOfCorrectedGrayLevels 1 (0045,"GEMS_SENO_02",24) DS StandardDeviationOfRegionGrayLevels 1 (0045,"GEMS_SENO_02",25) DS StandardDeviationOfLogRegionGrayLevels 1 (0045,"GEMS_SENO_02",26) OB MAOBuffer 1 (0045,"GEMS_SENO_02",27) IS SetNumber 1 (0045,"GEMS_SENO_02",28) CS WindowingType 1 (0045,"GEMS_SENO_02",29) DS WindowingParameters 1-n (0045,"GEMS_SENO_02",2a) IS CrosshairCursorXCoordinates 1 (0045,"GEMS_SENO_02",2b) IS CrosshairCursorYCoordinates 1 (0045,"GEMS_SENO_02",39) US VignetteRows 1 (0045,"GEMS_SENO_02",3a) US VignetteColumns 1 (0045,"GEMS_SENO_02",3b) US VignetteBitsAllocated 1 (0045,"GEMS_SENO_02",3c) US VignetteBitsStored 1 (0045,"GEMS_SENO_02",3d) US VignetteHighBit 1 (0045,"GEMS_SENO_02",3e) US VignettePixelRepresentation 1 (0045,"GEMS_SENO_02",3f) OB VignettePixelData 1 (0025,"GEMS_SERS_01",06) SS LastPulseSequenceUsed 1 (0025,"GEMS_SERS_01",07) SL ImagesInSeries 1 (0025,"GEMS_SERS_01",10) SL LandmarkCounter 1 (0025,"GEMS_SERS_01",11) SS NumberOfAcquisitions 1 (0025,"GEMS_SERS_01",14) SL IndicatesNumberOfUpdatesToHeader 1 (0025,"GEMS_SERS_01",17) SL SeriesCompleteFlag 1 (0025,"GEMS_SERS_01",18) SL NumberOfImagesArchived 1 (0025,"GEMS_SERS_01",19) SL LastImageNumberUsed 1 (0025,"GEMS_SERS_01",1a) SH PrimaryReceiverSuiteAndHost 1 (0023,"GEMS_STDY_01",01) SL NumberOfSeriesInStudy 1 (0023,"GEMS_STDY_01",02) SL NumberOfUnarchivedSeries 1 (0023,"GEMS_STDY_01",10) SS ReferenceImageField 1 (0023,"GEMS_STDY_01",50) SS SummaryImage 1 (0023,"GEMS_STDY_01",70) FD StartTimeSecsInFirstAxial 1 (0023,"GEMS_STDY_01",74) SL NumberOfUpdatesToHeader 1 (0023,"GEMS_STDY_01",7d) SS IndicatesIfStudyHasCompleteInfo 1 (0033,"GEMS_YMHD_01",05) UN Unknown 1 (0033,"GEMS_YMHD_01",06) UN Unknown 1 (0019,"GE_GENESIS_REV3.0",39) SS AxialType 1 (0019,"GE_GENESIS_REV3.0",8f) SS SwapPhaseFrequency 1 (0019,"GE_GENESIS_REV3.0",9c) SS PulseSequenceName 1 (0019,"GE_GENESIS_REV3.0",9f) SS CoilType 1 (0019,"GE_GENESIS_REV3.0",a4) SS SATFatWaterBone 1 (0019,"GE_GENESIS_REV3.0",c0) SS BitmapOfSATSelections 1 (0019,"GE_GENESIS_REV3.0",c1) SS SurfaceCoilIntensityCorrectionFlag 1 (0019,"GE_GENESIS_REV3.0",cb) SS PhaseContrastFlowAxis 1 (0019,"GE_GENESIS_REV3.0",cc) SS PhaseContrastVelocityEncoding 1 (0019,"GE_GENESIS_REV3.0",d5) SS FractionalEcho 1 (0019,"GE_GENESIS_REV3.0",d8) SS VariableEchoFlag 1 (0019,"GE_GENESIS_REV3.0",d9) DS ConcatenatedSat 1 (0019,"GE_GENESIS_REV3.0",f2) SS NumberOfPhases 1 (0043,"GE_GENESIS_REV3.0",1e) DS DeltaStartTime 1 (0043,"GE_GENESIS_REV3.0",27) SH ScanPitchRatio 1 (3f01,"INTELERAD MEDICAL SYSTEMS",01) LO InstitutionCode 1 (3f01,"INTELERAD MEDICAL SYSTEMS",02) LO RoutedTransferAE 1 (3f01,"INTELERAD MEDICAL SYSTEMS",03) LO SourceAE 1 (3f01,"INTELERAD MEDICAL SYSTEMS",04) LO DeferredValidation 1 (3f01,"INTELERAD MEDICAL SYSTEMS",05) LO SeriesOwner 1 (0041,"INTEGRIS 1.0",20) FL AccumulatedFluoroscopyDose 1 (0041,"INTEGRIS 1.0",30) FL AccumulatedExposureDose 1 (0041,"INTEGRIS 1.0",40) FL TotalDose 1 (0041,"INTEGRIS 1.0",41) FL TotalNumberOfFrames 1 (0041,"INTEGRIS 1.0",50) SQ ExposureInformationSequence 1 (0009,"INTEGRIS 1.0",08) CS ExposureChannel 1-n (0009,"INTEGRIS 1.0",32) TM ExposureStartTime 1 (0019,"INTEGRIS 1.0",00) LO APRName 1 (0019,"INTEGRIS 1.0",40) DS FrameRate 1 (0021,"INTEGRIS 1.0",12) IS ExposureNumber 1 (0029,"INTEGRIS 1.0",08) IS NumberOfExposureResults 1 (0029,"ISG shadow",70) IS Unknown 1 (0029,"ISG shadow",80) IS Unknown 1 (0029,"ISG shadow",90) IS Unknown 1 (0009,"ISI",01) UN SIENETGeneralPurposeIMGEF 1 (0009,"MERGE TECHNOLOGIES, INC.",00) OB Unknown 1 (0041,"PAPYRUS 3.0",00) LT PapyrusComments 1 (0041,"PAPYRUS 3.0",10) SQ PointerSequence 1 (0041,"PAPYRUS 3.0",11) UL ImagePointer 1 (0041,"PAPYRUS 3.0",12) UL PixelOffset 1 (0041,"PAPYRUS 3.0",13) SQ ImageIdentifierSequence 1 (0041,"PAPYRUS 3.0",14) SQ ExternalFileReferenceSequence 1 (0041,"PAPYRUS 3.0",15) US NumberOfImages 1 (0041,"PAPYRUS 3.0",21) UI ReferencedSOPClassUID 1 (0041,"PAPYRUS 3.0",22) UI ReferencedSOPInstanceUID 1 (0041,"PAPYRUS 3.0",31) LT ReferencedFileName 1 (0041,"PAPYRUS 3.0",32) LT ReferencedFilePath 1-n (0041,"PAPYRUS 3.0",41) UI ReferencedImageSOPClassUID 1 (0041,"PAPYRUS 3.0",42) UI ReferencedImageSOPInstanceUID 1 (0041,"PAPYRUS 3.0",50) SQ ImageSequence 1 (6001-o-60ff,"PAPYRUS 3.0",00) IS OverlayID 1 (6001-o-60ff,"PAPYRUS 3.0",01) LT LinkedOverlays 1-n (6001-o-60ff,"PAPYRUS 3.0",10) US OverlayRows 1 (6001-o-60ff,"PAPYRUS 3.0",11) US OverlayColumns 1 (6001-o-60ff,"PAPYRUS 3.0",40) LO OverlayType 1 (6001-o-60ff,"PAPYRUS 3.0",50) US OverlayOrigin 1-n (6001-o-60ff,"PAPYRUS 3.0",60) LO Editable 1 (6001-o-60ff,"PAPYRUS 3.0",70) LO OverlayFont 1 (6001-o-60ff,"PAPYRUS 3.0",72) LO OverlayStyle 1 (6001-o-60ff,"PAPYRUS 3.0",74) US OverlayFontSize 1 (6001-o-60ff,"PAPYRUS 3.0",76) LO OverlayColor 1 (6001-o-60ff,"PAPYRUS 3.0",78) US ShadowSize 1 (6001-o-60ff,"PAPYRUS 3.0",80) LO FillPattern 1 (6001-o-60ff,"PAPYRUS 3.0",82) US OverlayPenSize 1 (6001-o-60ff,"PAPYRUS 3.0",a0) LO Label 1 (6001-o-60ff,"PAPYRUS 3.0",a2) LT PostItText 1 (6001-o-60ff,"PAPYRUS 3.0",a4) US AnchorPoint 2 (6001-o-60ff,"PAPYRUS 3.0",b0) LO ROIType 1 (6001-o-60ff,"PAPYRUS 3.0",b2) LT AttachedAnnotation 1 (6001-o-60ff,"PAPYRUS 3.0",ba) US ContourPoints 1-n (6001-o-60ff,"PAPYRUS 3.0",bc) US MaskData 1-n (6001-o-60ff,"PAPYRUS 3.0",c0) SQ UINOverlaySequence 1 (0009,"PAPYRUS",00) LT OriginalFileName 1 (0009,"PAPYRUS",10) LT OriginalFileLocation 1 (0009,"PAPYRUS",18) LT DataSetIdentifier 1 (0041,"PAPYRUS",00) LT PapyrusComments 1-n (0041,"PAPYRUS",10) US FolderType 1 (0041,"PAPYRUS",11) LT PatientFolderDataSetID 1 (0041,"PAPYRUS",20) LT FolderName 1 (0041,"PAPYRUS",30) DA CreationDate 1 (0041,"PAPYRUS",32) TM CreationTime 1 (0041,"PAPYRUS",34) DA ModifiedDate 1 (0041,"PAPYRUS",36) TM ModifiedTime 1 (0041,"PAPYRUS",40) LT OwnerName 1-n (0041,"PAPYRUS",50) LT FolderStatus 1 (0041,"PAPYRUS",60) UL NumberOfImages 1 (0041,"PAPYRUS",62) UL NumberOfOther 1 (0041,"PAPYRUS",a0) LT ExternalFolderElementDSID 1-n (0041,"PAPYRUS",a1) US ExternalFolderElementDataSetType 1-n (0041,"PAPYRUS",a2) LT ExternalFolderElementFileLocation 1-n (0041,"PAPYRUS",a3) UL ExternalFolderElementLength 1-n (0041,"PAPYRUS",b0) LT InternalFolderElementDSID 1-n (0041,"PAPYRUS",b1) US InternalFolderElementDataSetType 1-n (0041,"PAPYRUS",b2) UL InternalOffsetToDataSet 1-n (0041,"PAPYRUS",b3) UL InternalOffsetToImage 1-n (2001,"Philips Imaging DD 001",01) FL ChemicalShift 1 (2001,"Philips Imaging DD 001",02) IS ChemicalShiftNumberMR 1 (2001,"Philips Imaging DD 001",03) FL DiffusionB-Factor 1 (2001,"Philips Imaging DD 001",04) CS DiffusionDirection 1 (2001,"Philips Imaging DD 001",06) CS ImageEnhanced 1 (2001,"Philips Imaging DD 001",07) CS ImageTypeEDES 1 (2001,"Philips Imaging DD 001",08) IS PhaseNumber 1 (2001,"Philips Imaging DD 001",0a) IS SliceNumberMR 1 (2001,"Philips Imaging DD 001",0b) CS SliceOrientation 1 (2001,"Philips Imaging DD 001",11) FL DiffusionEchoTime 1 (2001,"Philips Imaging DD 001",12) CS DynamicSeries 1 (2001,"Philips Imaging DD 001",13) SL EPIFactor 1 (2001,"Philips Imaging DD 001",14) SL NumberOfEchoes 1 (2001,"Philips Imaging DD 001",15) SS NumberOfLocations 1 (2001,"Philips Imaging DD 001",16) SS NumberOfPCDirections 1 (2001,"Philips Imaging DD 001",17) SL NumberOfPhasesMR 1 (2001,"Philips Imaging DD 001",18) SL NumberOfSlicesMR 1 (2001,"Philips Imaging DD 001",19) CS PartialMatrixScanned 1 (2001,"Philips Imaging DD 001",1a) FL PCVelocity 1-n (2001,"Philips Imaging DD 001",1b) FL PrepulseDelay 1 (2001,"Philips Imaging DD 001",1c) CS PrepulseType 1 (2001,"Philips Imaging DD 001",1d) IS ReconstructionNumberMR 1 (2001,"Philips Imaging DD 001",1f) CS RespirationSync 1 (2001,"Philips Imaging DD 001",21) CS SPIR 1 (2001,"Philips Imaging DD 001",22) FL WaterFatShift 1 (2001,"Philips Imaging DD 001",23) DS FlipAnglePhilips 1 (2001,"Philips Imaging DD 001",25) SH EchoTimeDisplayMR 1 (2001,"Philips Imaging DD 001",2d) SS StackNumberOfSlices 1 (2001,"Philips Imaging DD 001",32) FL StackRadialAngle 1 (2001,"Philips Imaging DD 001",33) CS StackRadialAxis 1 (2001,"Philips Imaging DD 001",35) SS StackSliceNumber 1 (2001,"Philips Imaging DD 001",36) CS StackType 1 (2001,"Philips Imaging DD 001",3f) CS ZoomMode 1 (2001,"Philips Imaging DD 001",5f) SQ StackSequence 1-n (2001,"Philips Imaging DD 001",60) SL NumberOfStacks 1 (2001,"Philips Imaging DD 001",63) CS ExaminationSource 1 (2001,"Philips Imaging DD 001",7b) IS AcquisitionNumber 1 (2001,"Philips Imaging DD 001",81) IS NumberOfDynamicScans 1 (2005,"Philips MR Imaging DD 001",05) CS SynergyReconstructionType 1 (2005,"Philips MR Imaging DD 001",20) SL NumberOfChemicalShifts 1 (2005,"Philips MR Imaging DD 001",a1) CS SyncraScanType 1 (2005,"Philips MR Imaging DD 001",83) SQ Unknown 1 (2005,"Philips MR Imaging DD 005",02) SQ Unknown 1 (0019,"PHILIPS MR R5.5/PART",1000) DS FieldOfView 1 (0019,"PHILIPS MR R5.6/PART",1000) DS FieldOfView 1 (0019,"PHILIPS MR SPECTRO;1",01) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",02) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",03) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",04) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",05) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",06) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",07) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",08) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",09) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",10) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",12) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",13) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",14) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",15) US Unknown 1-n (0019,"PHILIPS MR SPECTRO;1",16) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",17) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",18) UN Unknown 1 (0019,"PHILIPS MR SPECTRO;1",20) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",21) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",22) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",23) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",24) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",25) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",26) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",27) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",28) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",29) IS Unknown 1-n (0019,"PHILIPS MR SPECTRO;1",31) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",32) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",41) LT Unknown 1 (0019,"PHILIPS MR SPECTRO;1",42) IS Unknown 2 (0019,"PHILIPS MR SPECTRO;1",43) IS Unknown 2 (0019,"PHILIPS MR SPECTRO;1",45) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",46) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",47) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",48) IS Unknown 1 (0019,"PHILIPS MR SPECTRO;1",49) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",50) UN Unknown 1 (0019,"PHILIPS MR SPECTRO;1",60) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",61) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",70) UN Unknown 1 (0019,"PHILIPS MR SPECTRO;1",71) IS Unknown 1-n (0019,"PHILIPS MR SPECTRO;1",72) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",73) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",74) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",76) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",77) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",78) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",79) US Unknown 1 (0019,"PHILIPS MR SPECTRO;1",80) IS Unknown 1 (0009,"PHILIPS MR",10) LO SPIRelease 1 (0009,"PHILIPS MR",12) LO Unknown 1 (0019,"PHILIPS MR/LAST",09) DS MainMagneticField 1 (0019,"PHILIPS MR/LAST",0e) IS FlowCompensation 1 (0019,"PHILIPS MR/LAST",b1) IS MinimumRRInterval 1 (0019,"PHILIPS MR/LAST",b2) IS MaximumRRInterval 1 (0019,"PHILIPS MR/LAST",b3) IS NumberOfRejections 1 (0019,"PHILIPS MR/LAST",b4) IS NumberOfRRIntervals 1-n (0019,"PHILIPS MR/LAST",b5) IS ArrhythmiaRejection 1 (0019,"PHILIPS MR/LAST",c0) DS Unknown 1-n (0019,"PHILIPS MR/LAST",c6) IS CycledMultipleSlice 1 (0019,"PHILIPS MR/LAST",ce) IS REST 1 (0019,"PHILIPS MR/LAST",d5) DS Unknown 1 (0019,"PHILIPS MR/LAST",d6) IS FourierInterpolation 1 (0019,"PHILIPS MR/LAST",d9) IS Unknown 1-n (0019,"PHILIPS MR/LAST",e0) IS Prepulse 1 (0019,"PHILIPS MR/LAST",e1) DS PrepulseDelay 1 (0019,"PHILIPS MR/LAST",e2) IS Unknown 1 (0019,"PHILIPS MR/LAST",e3) DS Unknown 1 (0019,"PHILIPS MR/LAST",f0) LT WSProtocolString1 1 (0019,"PHILIPS MR/LAST",f1) LT WSProtocolString2 1 (0019,"PHILIPS MR/LAST",f2) LT WSProtocolString3 1 (0019,"PHILIPS MR/LAST",f3) LT WSProtocolString4 1 (0021,"PHILIPS MR/LAST",00) IS Unknown 1 (0021,"PHILIPS MR/LAST",10) IS Unknown 1 (0021,"PHILIPS MR/LAST",20) IS Unknown 1 (0021,"PHILIPS MR/LAST",21) DS SliceGap 1 (0021,"PHILIPS MR/LAST",22) DS StackRadialAngle 1 (0027,"PHILIPS MR/LAST",00) US Unknown 1 (0027,"PHILIPS MR/LAST",11) US Unknown 1-n (0027,"PHILIPS MR/LAST",12) DS Unknown 1-n (0027,"PHILIPS MR/LAST",13) DS Unknown 1-n (0027,"PHILIPS MR/LAST",14) DS Unknown 1-n (0027,"PHILIPS MR/LAST",15) DS Unknown 1-n (0027,"PHILIPS MR/LAST",16) LO Unknown 1 (0029,"PHILIPS MR/LAST",10) DS FPMin 1 (0029,"PHILIPS MR/LAST",20) DS FPMax 1 (0029,"PHILIPS MR/LAST",30) DS ScaledMinimum 1 (0029,"PHILIPS MR/LAST",40) DS ScaledMaximum 1 (0029,"PHILIPS MR/LAST",50) DS WindowMinimum 1 (0029,"PHILIPS MR/LAST",60) DS WindowMaximum 1 (0029,"PHILIPS MR/LAST",61) IS Unknown 1 (0029,"PHILIPS MR/LAST",70) DS Unknown 1 (0029,"PHILIPS MR/LAST",71) DS Unknown 1 (0029,"PHILIPS MR/LAST",72) IS Unknown 1 (0029,"PHILIPS MR/LAST",80) IS ViewCenter 1 (0029,"PHILIPS MR/LAST",81) IS ViewSize 1 (0029,"PHILIPS MR/LAST",82) IS ViewZoom 1 (0029,"PHILIPS MR/LAST",83) IS ViewTransform 1 (6001,"PHILIPS MR/LAST",00) LT Unknown 1 (0019,"PHILIPS MR/PART",1000) DS FieldOfView 1 (0019,"PHILIPS MR/PART",1005) DS CCAngulation 1 (0019,"PHILIPS MR/PART",1006) DS APAngulation 1 (0019,"PHILIPS MR/PART",1007) DS LRAngulation 1 (0019,"PHILIPS MR/PART",1008) IS PatientPosition 1 (0019,"PHILIPS MR/PART",1009) IS PatientOrientation 1 (0019,"PHILIPS MR/PART",100a) IS SliceOrientation 1 (0019,"PHILIPS MR/PART",100b) DS LROffcenter 1 (0019,"PHILIPS MR/PART",100c) DS CCOffcenter 1 (0019,"PHILIPS MR/PART",100d) DS APOffcenter 1 (0019,"PHILIPS MR/PART",100e) DS Unknown 1 (0019,"PHILIPS MR/PART",100f) IS NumberOfSlices 1 (0019,"PHILIPS MR/PART",1010) DS SliceFactor 1 (0019,"PHILIPS MR/PART",1011) DS EchoTimes 1-n (0019,"PHILIPS MR/PART",1015) IS DynamicStudy 1 (0019,"PHILIPS MR/PART",1018) DS HeartbeatInterval 1 (0019,"PHILIPS MR/PART",1019) DS RepetitionTimeFFE 1 (0019,"PHILIPS MR/PART",101a) DS FFEFlipAngle 1 (0019,"PHILIPS MR/PART",101b) IS NumberOfScans 1 (0019,"PHILIPS MR/PART",1021) DS Unknown 1-n (0019,"PHILIPS MR/PART",1022) DS DynamicScanTimeBegin 1 (0019,"PHILIPS MR/PART",1024) IS Unknown 1 (0019,"PHILIPS MR/PART",1064) DS RepetitionTimeSE 1 (0019,"PHILIPS MR/PART",1065) DS RepetitionTimeIR 1 (0019,"PHILIPS MR/PART",1069) IS NumberOfPhases 1 (0019,"PHILIPS MR/PART",106a) IS CardiacFrequency 1 (0019,"PHILIPS MR/PART",106b) DS InversionDelay 1 (0019,"PHILIPS MR/PART",106c) DS GateDelay 1 (0019,"PHILIPS MR/PART",106d) DS GateWidth 1 (0019,"PHILIPS MR/PART",106e) DS TriggerDelayTime 1 (0019,"PHILIPS MR/PART",1080) IS NumberOfChemicalShifts 1 (0019,"PHILIPS MR/PART",1081) DS ChemicalShift 1 (0019,"PHILIPS MR/PART",1084) IS NumberOfRows 1 (0019,"PHILIPS MR/PART",1085) IS NumberOfSamples 1 (0019,"PHILIPS MR/PART",1094) LO MagnetizationTransferContrast 1 (0019,"PHILIPS MR/PART",1095) LO SpectralPresaturationWithInversionRecovery 1 (0019,"PHILIPS MR/PART",1096) IS Unknown 1 (0019,"PHILIPS MR/PART",1097) LO Unknown 1 (0019,"PHILIPS MR/PART",10a0) IS Unknown 1 (0019,"PHILIPS MR/PART",10a1) DS Unknown 1 (0019,"PHILIPS MR/PART",10a3) DS Unknown 1 (0019,"PHILIPS MR/PART",10a4) CS Unknown 1 (0019,"PHILIPS MR/PART",10c8) IS Unknown 1 (0019,"PHILIPS MR/PART",10c9) IS FoldoverDirectionTransverse 1 (0019,"PHILIPS MR/PART",10ca) IS FoldoverDirectionSagittal 1 (0019,"PHILIPS MR/PART",10cb) IS FoldoverDirectionCoronal 1 (0019,"PHILIPS MR/PART",10cc) IS Unknown 1 (0019,"PHILIPS MR/PART",10cd) IS Unknown 1 (0019,"PHILIPS MR/PART",10ce) IS Unknown 1 (0019,"PHILIPS MR/PART",10cf) IS NumberOfEchoes 1 (0019,"PHILIPS MR/PART",10d0) IS ScanResolution 1 (0019,"PHILIPS MR/PART",10d2) LO WaterFatShift 2 (0019,"PHILIPS MR/PART",10d4) IS ArtifactReduction 1 (0019,"PHILIPS MR/PART",10d5) IS Unknown 1 (0019,"PHILIPS MR/PART",10d6) IS Unknown 1 (0019,"PHILIPS MR/PART",10d7) DS ScanPercentage 1 (0019,"PHILIPS MR/PART",10d8) IS Halfscan 1 (0019,"PHILIPS MR/PART",10d9) IS EPIFactor 1 (0019,"PHILIPS MR/PART",10da) IS TurboFactor 1 (0019,"PHILIPS MR/PART",10db) IS Unknown 1 (0019,"PHILIPS MR/PART",10e0) IS PercentageOfScanCompleted 1 (0019,"PHILIPS MR/PART",10e1) IS Unknown 1 (0019,"PHILIPS MR/PART",1100) IS NumberOfStacks 1 (0019,"PHILIPS MR/PART",1101) IS StackType 1-n (0019,"PHILIPS MR/PART",1102) IS Unknown 1-n (0019,"PHILIPS MR/PART",110b) DS LROffcenter 1 (0019,"PHILIPS MR/PART",110c) DS CCOffcenter 1 (0019,"PHILIPS MR/PART",110d) DS APOffcenter 1 (0019,"PHILIPS MR/PART",1145) IS ReconstructionResolution 1 (0019,"PHILIPS MR/PART",11fc) IS ResonanceFrequency 1 (0019,"PHILIPS MR/PART",12c0) DS TriggerDelayTimes 1 (0019,"PHILIPS MR/PART",12e0) IS PrepulseType 1 (0019,"PHILIPS MR/PART",12e1) DS PrepulseDelay 1 (0019,"PHILIPS MR/PART",12e3) DS PhaseContrastVelocity 1 (0021,"PHILIPS MR/PART",1000) IS ReconstructionNumber 1 (0021,"PHILIPS MR/PART",1010) IS ImageType 1 (0021,"PHILIPS MR/PART",1020) IS SliceNumber 1 (0021,"PHILIPS MR/PART",1030) IS EchoNumber 1 (0021,"PHILIPS MR/PART",1031) DS PatientReferenceID 1 (0021,"PHILIPS MR/PART",1035) IS ChemicalShiftNumber 1 (0021,"PHILIPS MR/PART",1040) IS PhaseNumber 1 (0021,"PHILIPS MR/PART",1050) IS DynamicScanNumber 1 (0021,"PHILIPS MR/PART",1060) IS NumberOfRowsInObject 1 (0021,"PHILIPS MR/PART",1061) IS RowNumber 1-n (0021,"PHILIPS MR/PART",1062) IS Unknown 1-n (0021,"PHILIPS MR/PART",1100) DA ScanDate 1 (0021,"PHILIPS MR/PART",1110) TM ScanTime 1 (0021,"PHILIPS MR/PART",1221) IS SliceGap 1 (0029,"PHILIPS MR/PART",00) DS Unknown 2 (0029,"PHILIPS MR/PART",04) US Unknown 1 (0029,"PHILIPS MR/PART",10) DS Unknown 1 (0029,"PHILIPS MR/PART",11) DS Unknown 1 (0029,"PHILIPS MR/PART",20) LO Unknown 1 (0029,"PHILIPS MR/PART",31) DS Unknown 2 (0029,"PHILIPS MR/PART",32) DS Unknown 2 (0029,"PHILIPS MR/PART",c3) IS ScanResolution 1 (0029,"PHILIPS MR/PART",c4) IS FieldOfView 1 (0029,"PHILIPS MR/PART",d5) LT SliceThickness 1 (0019,"PHILIPS-MR-1",11) IS ChemicalShiftNumber 1 (0019,"PHILIPS-MR-1",12) IS PhaseNumber 1 (0021,"PHILIPS-MR-1",01) IS ReconstructionNumber 1 (0021,"PHILIPS-MR-1",02) IS SliceNumber 1 (7001,"Picker NM Private Group",01) UI Unknown 1 (7001,"Picker NM Private Group",02) OB Unknown 1 (0019,"SIEMENS CM VA0 ACQU",10) LT ParameterFileName 1 (0019,"SIEMENS CM VA0 ACQU",11) LO SequenceFileName 1 (0019,"SIEMENS CM VA0 ACQU",12) LT SequenceFileOwner 1 (0019,"SIEMENS CM VA0 ACQU",13) LT SequenceDescription 1 (0019,"SIEMENS CM VA0 ACQU",14) LT EPIFileName 1 (0009,"SIEMENS CM VA0 CMS",00) DS NumberOfMeasurements 1 (0009,"SIEMENS CM VA0 CMS",10) LT StorageMode 1 (0009,"SIEMENS CM VA0 CMS",12) UL EvaluationMaskImage 1 (0009,"SIEMENS CM VA0 CMS",26) DA LastMoveDate 1 (0009,"SIEMENS CM VA0 CMS",27) TM LastMoveTime 1 (0011,"SIEMENS CM VA0 CMS",0a) LT Unknown 1 (0011,"SIEMENS CM VA0 CMS",10) DA RegistrationDate 1 (0011,"SIEMENS CM VA0 CMS",11) TM RegistrationTime 1 (0011,"SIEMENS CM VA0 CMS",22) LT Unknown 1 (0011,"SIEMENS CM VA0 CMS",23) DS UsedPatientWeight 1 (0011,"SIEMENS CM VA0 CMS",40) IS OrganCode 1 (0013,"SIEMENS CM VA0 CMS",00) LT ModifyingPhysician 1 (0013,"SIEMENS CM VA0 CMS",10) DA ModificationDate 1 (0013,"SIEMENS CM VA0 CMS",12) TM ModificationTime 1 (0013,"SIEMENS CM VA0 CMS",20) LO PatientName 1 (0013,"SIEMENS CM VA0 CMS",22) LO PatientId 1 (0013,"SIEMENS CM VA0 CMS",30) DA PatientBirthdate 1 (0013,"SIEMENS CM VA0 CMS",31) DS PatientWeight 1 (0013,"SIEMENS CM VA0 CMS",32) LT PatientsMaidenName 1 (0013,"SIEMENS CM VA0 CMS",33) LT ReferringPhysician 1 (0013,"SIEMENS CM VA0 CMS",34) LT AdmittingDiagnosis 1 (0013,"SIEMENS CM VA0 CMS",35) LO PatientSex 1 (0013,"SIEMENS CM VA0 CMS",40) LO ProcedureDescription 1 (0013,"SIEMENS CM VA0 CMS",42) LO RestDirection 1 (0013,"SIEMENS CM VA0 CMS",44) LO PatientPosition 1 (0013,"SIEMENS CM VA0 CMS",46) LT ViewDirection 1 (0013,"SIEMENS CM VA0 CMS",50) LT Unknown 1 (0013,"SIEMENS CM VA0 CMS",51) LT Unknown 1 (0013,"SIEMENS CM VA0 CMS",52) LT Unknown 1 (0013,"SIEMENS CM VA0 CMS",53) LT Unknown 1 (0013,"SIEMENS CM VA0 CMS",54) LT Unknown 1 (0013,"SIEMENS CM VA0 CMS",55) LT Unknown 1 (0013,"SIEMENS CM VA0 CMS",56) LT Unknown 1 (0019,"SIEMENS CM VA0 CMS",10) DS NetFrequency 1 (0019,"SIEMENS CM VA0 CMS",20) LT MeasurementMode 1 (0019,"SIEMENS CM VA0 CMS",30) LT CalculationMode 1 (0019,"SIEMENS CM VA0 CMS",50) IS NoiseLevel 1 (0019,"SIEMENS CM VA0 CMS",60) IS NumberOfDataBytes 1 (0021,"SIEMENS CM VA0 CMS",20) DS FoV 2 (0021,"SIEMENS CM VA0 CMS",22) DS ImageMagnificationFactor 1 (0021,"SIEMENS CM VA0 CMS",24) DS ImageScrollOffset 2 (0021,"SIEMENS CM VA0 CMS",26) IS ImagePixelOffset 1 (0021,"SIEMENS CM VA0 CMS",30) LT ViewDirection 1 (0021,"SIEMENS CM VA0 CMS",32) CS PatientRestDirection 1 (0021,"SIEMENS CM VA0 CMS",60) DS ImagePosition 3 (0021,"SIEMENS CM VA0 CMS",61) DS ImageNormal 3 (0021,"SIEMENS CM VA0 CMS",63) DS ImageDistance 1 (0021,"SIEMENS CM VA0 CMS",65) US ImagePositioningHistoryMask 1 (0021,"SIEMENS CM VA0 CMS",6a) DS ImageRow 3 (0021,"SIEMENS CM VA0 CMS",6b) DS ImageColumn 3 (0021,"SIEMENS CM VA0 CMS",70) LT PatientOrientationSet1 3 (0021,"SIEMENS CM VA0 CMS",71) LT PatientOrientationSet2 3 (0021,"SIEMENS CM VA0 CMS",80) LT StudyName 1 (0021,"SIEMENS CM VA0 CMS",82) LT StudyType 3 (0029,"SIEMENS CM VA0 CMS",10) LT WindowStyle 1 (0029,"SIEMENS CM VA0 CMS",11) LT Unknown 1 (0029,"SIEMENS CM VA0 CMS",13) LT Unknown 1 (0029,"SIEMENS CM VA0 CMS",20) LT PixelQualityCode 3 (0029,"SIEMENS CM VA0 CMS",22) IS PixelQualityValue 3 (0029,"SIEMENS CM VA0 CMS",50) LT ArchiveCode 1 (0029,"SIEMENS CM VA0 CMS",51) LT ExposureCode 1 (0029,"SIEMENS CM VA0 CMS",52) LT SortCode 1 (0029,"SIEMENS CM VA0 CMS",53) LT Unknown 1 (0029,"SIEMENS CM VA0 CMS",60) LT Splash 1 (0051,"SIEMENS CM VA0 CMS",10) LT ImageText 1-n (6021,"SIEMENS CM VA0 CMS",00) LT ImageGraphicsFormatCode 1 (6021,"SIEMENS CM VA0 CMS",10) LT ImageGraphics 1 (7fe1,"SIEMENS CM VA0 CMS",00) OB BinaryData 1-n (0009,"SIEMENS CM VA0 LAB",10) LT GeneratorIdentificationLabel 1 (0009,"SIEMENS CM VA0 LAB",11) LT GantryIdentificationLabel 1 (0009,"SIEMENS CM VA0 LAB",12) LT X-RayTubeIdentificationLabel 1 (0009,"SIEMENS CM VA0 LAB",13) LT DetectorIdentificationLabel 1 (0009,"SIEMENS CM VA0 LAB",14) LT DASIdentificationLabel 1 (0009,"SIEMENS CM VA0 LAB",15) LT SMIIdentificationLabel 1 (0009,"SIEMENS CM VA0 LAB",16) LT CPUIdentificationLabel 1 (0009,"SIEMENS CM VA0 LAB",20) LT HeaderVersion 1 (0029,"SIEMENS CSA HEADER",08) CS CSAImageHeaderType 1 (0029,"SIEMENS CSA HEADER",09) LO CSAImageHeaderVersion 1 (0029,"SIEMENS CSA HEADER",10) OB CSAImageHeaderInfo 1 (0029,"SIEMENS CSA HEADER",18) CS CSASeriesHeaderType 1 (0029,"SIEMENS CSA HEADER",19) LO CSASeriesHeaderVersion 1 (0029,"SIEMENS CSA HEADER",20) OB CSASeriesHeaderInfo 1 (0029,"SIEMENS CSA NON-IMAGE",08) CS CSADataType 1 (0029,"SIEMENS CSA NON-IMAGE",09) LO CSADataVersion 1 (0029,"SIEMENS CSA NON-IMAGE",10) OB CSADataInfo 1 (7FE1,"SIEMENS CSA NON-IMAGE",10) OB CSAData 1 (0019,"SIEMENS CT VA0 COAD",10) DS DistanceSourceToSourceSideCollimator 1 (0019,"SIEMENS CT VA0 COAD",11) DS DistanceSourceToDetectorSideCollimator 1 (0019,"SIEMENS CT VA0 COAD",20) IS NumberOfPossibleChannels 1 (0019,"SIEMENS CT VA0 COAD",21) IS MeanChannelNumber 1 (0019,"SIEMENS CT VA0 COAD",22) DS DetectorSpacing 1 (0019,"SIEMENS CT VA0 COAD",23) DS DetectorCenter 1 (0019,"SIEMENS CT VA0 COAD",24) DS ReadingIntegrationTime 1 (0019,"SIEMENS CT VA0 COAD",50) DS DetectorAlignment 1 (0019,"SIEMENS CT VA0 COAD",52) DS Unknown 1 (0019,"SIEMENS CT VA0 COAD",54) DS Unknown 1 (0019,"SIEMENS CT VA0 COAD",60) DS FocusAlignment 1 (0019,"SIEMENS CT VA0 COAD",65) UL FocalSpotDeflectionAmplitude 1 (0019,"SIEMENS CT VA0 COAD",66) UL FocalSpotDeflectionPhase 1 (0019,"SIEMENS CT VA0 COAD",67) UL FocalSpotDeflectionOffset 1 (0019,"SIEMENS CT VA0 COAD",70) DS WaterScalingFactor 1 (0019,"SIEMENS CT VA0 COAD",71) DS InterpolationFactor 1 (0019,"SIEMENS CT VA0 COAD",80) LT PatientRegion 1 (0019,"SIEMENS CT VA0 COAD",82) LT PatientPhaseOfLife 1 (0019,"SIEMENS CT VA0 COAD",90) DS OsteoOffset 1 (0019,"SIEMENS CT VA0 COAD",92) DS OsteoRegressionLineSlope 1 (0019,"SIEMENS CT VA0 COAD",93) DS OsteoRegressionLineIntercept 1 (0019,"SIEMENS CT VA0 COAD",94) DS OsteoStandardizationCode 1 (0019,"SIEMENS CT VA0 COAD",96) IS OsteoPhantomNumber 1 (0019,"SIEMENS CT VA0 COAD",A3) US Unknown 1-n (0019,"SIEMENS CT VA0 COAD",A4) DS Unknown 1 (0019,"SIEMENS CT VA0 COAD",A5) DS Unknown 1 (0019,"SIEMENS CT VA0 COAD",A6) US Unknown 1-n (0019,"SIEMENS CT VA0 COAD",A7) US Unknown 1-n (0019,"SIEMENS CT VA0 COAD",A8) US Unknown 1-n (0019,"SIEMENS CT VA0 COAD",A9) DS Unknown 1 (0019,"SIEMENS CT VA0 COAD",AA) LT Unknown 1 (0019,"SIEMENS CT VA0 COAD",AB) DS Unknown 1 (0019,"SIEMENS CT VA0 COAD",AC) DS Unknown 1 (0019,"SIEMENS CT VA0 COAD",AD) DS Unknown 1 (0019,"SIEMENS CT VA0 COAD",AE) DS Unknown 1 (0019,"SIEMENS CT VA0 COAD",AF) DS Unknown 1 (0019,"SIEMENS CT VA0 COAD",B0) DS FeedPerRotation 1 (0019,"SIEMENS CT VA0 COAD",BD) IS PulmoTriggerLevel 1 (0019,"SIEMENS CT VA0 COAD",BE) DS ExpiratoricReserveVolume 1 (0019,"SIEMENS CT VA0 COAD",BF) DS VitalCapacity 1 (0019,"SIEMENS CT VA0 COAD",C0) DS PulmoWater 1 (0019,"SIEMENS CT VA0 COAD",C1) DS PulmoAir 1 (0019,"SIEMENS CT VA0 COAD",C2) DA PulmoDate 1 (0019,"SIEMENS CT VA0 COAD",C3) TM PulmoTime 1 (0019,"SIEMENS CT VA0 GEN",10) DS SourceSideCollimatorAperture 1 (0019,"SIEMENS CT VA0 GEN",11) DS DetectorSideCollimatorAperture 1 (0019,"SIEMENS CT VA0 GEN",20) DS ExposureTime 1 (0019,"SIEMENS CT VA0 GEN",21) DS ExposureCurrent 1 (0019,"SIEMENS CT VA0 GEN",25) DS KVPGeneratorPowerCurrent 1 (0019,"SIEMENS CT VA0 GEN",26) DS GeneratorVoltage 1 (0019,"SIEMENS CT VA0 GEN",40) UL MasterControlMask 1 (0019,"SIEMENS CT VA0 GEN",42) US ProcessingMask 5 (0019,"SIEMENS CT VA0 GEN",44) US Unknown 1-n (0019,"SIEMENS CT VA0 GEN",45) US Unknown 1-n (0019,"SIEMENS CT VA0 GEN",62) IS NumberOfVirtuellChannels 1 (0019,"SIEMENS CT VA0 GEN",70) IS NumberOfReadings 1 (0019,"SIEMENS CT VA0 GEN",71) LT Unknown 1-n (0019,"SIEMENS CT VA0 GEN",74) IS NumberOfProjections 1 (0019,"SIEMENS CT VA0 GEN",75) IS NumberOfBytes 1 (0019,"SIEMENS CT VA0 GEN",80) LT ReconstructionAlgorithmSet 1 (0019,"SIEMENS CT VA0 GEN",81) LT ReconstructionAlgorithmIndex 1 (0019,"SIEMENS CT VA0 GEN",82) LT RegenerationSoftwareVersion 1 (0019,"SIEMENS CT VA0 GEN",88) DS Unknown 1 (0021,"SIEMENS CT VA0 GEN",10) IS RotationAngle 1 (0021,"SIEMENS CT VA0 GEN",11) IS StartAngle 1 (0021,"SIEMENS CT VA0 GEN",20) US Unknown 1-n (0021,"SIEMENS CT VA0 GEN",30) IS TopogramTubePosition 1 (0021,"SIEMENS CT VA0 GEN",32) DS LengthOfTopogram 1 (0021,"SIEMENS CT VA0 GEN",34) DS TopogramCorrectionFactor 1 (0021,"SIEMENS CT VA0 GEN",36) DS MaximumTablePosition 1 (0021,"SIEMENS CT VA0 GEN",40) IS TableMoveDirectionCode 1 (0021,"SIEMENS CT VA0 GEN",45) IS VOIStartRow 1 (0021,"SIEMENS CT VA0 GEN",46) IS VOIStopRow 1 (0021,"SIEMENS CT VA0 GEN",47) IS VOIStartColumn 1 (0021,"SIEMENS CT VA0 GEN",48) IS VOIStopColumn 1 (0021,"SIEMENS CT VA0 GEN",49) IS VOIStartSlice 1 (0021,"SIEMENS CT VA0 GEN",4a) IS VOIStopSlice 1 (0021,"SIEMENS CT VA0 GEN",50) IS VectorStartRow 1 (0021,"SIEMENS CT VA0 GEN",51) IS VectorRowStep 1 (0021,"SIEMENS CT VA0 GEN",52) IS VectorStartColumn 1 (0021,"SIEMENS CT VA0 GEN",53) IS VectorColumnStep 1 (0021,"SIEMENS CT VA0 GEN",60) IS RangeTypeCode 1 (0021,"SIEMENS CT VA0 GEN",62) IS ReferenceTypeCode 1 (0021,"SIEMENS CT VA0 GEN",70) DS ObjectOrientation 3 (0021,"SIEMENS CT VA0 GEN",72) DS LightOrientation 3 (0021,"SIEMENS CT VA0 GEN",75) DS LightBrightness 1 (0021,"SIEMENS CT VA0 GEN",76) DS LightContrast 1 (0021,"SIEMENS CT VA0 GEN",7a) IS OverlayThreshold 2 (0021,"SIEMENS CT VA0 GEN",7b) IS SurfaceThreshold 2 (0021,"SIEMENS CT VA0 GEN",7c) IS GreyScaleThreshold 2 (0021,"SIEMENS CT VA0 GEN",a0) DS Unknown 1 (0021,"SIEMENS CT VA0 GEN",a2) LT Unknown 1 (0021,"SIEMENS CT VA0 GEN",a7) LT Unknown 1 (0009,"SIEMENS CT VA0 IDE",10) LT Unknown 1 (0009,"SIEMENS CT VA0 IDE",30) LT Unknown 1 (0009,"SIEMENS CT VA0 IDE",31) LT Unknown 1 (0009,"SIEMENS CT VA0 IDE",32) LT Unknown 1 (0009,"SIEMENS CT VA0 IDE",34) LT Unknown 1 (0009,"SIEMENS CT VA0 IDE",40) LT Unknown 1 (0009,"SIEMENS CT VA0 IDE",42) LT Unknown 1 (0009,"SIEMENS CT VA0 IDE",50) LT Unknown 1 (0009,"SIEMENS CT VA0 IDE",51) LT Unknown 1 (0009,"SIEMENS CT VA0 ORI",20) LT Unknown 1 (0009,"SIEMENS CT VA0 ORI",30) LT Unknown 1 (6021,"SIEMENS CT VA0 OST",00) LT OsteoContourComment 1 (6021,"SIEMENS CT VA0 OST",10) US OsteoContourBuffer 256 (0021,"SIEMENS CT VA0 RAW",10) UL CreationMask 2 (0021,"SIEMENS CT VA0 RAW",20) UL EvaluationMask 2 (0021,"SIEMENS CT VA0 RAW",30) US ExtendedProcessingMask 7 (0021,"SIEMENS CT VA0 RAW",40) US Unknown 1-n (0021,"SIEMENS CT VA0 RAW",41) US Unknown 1-n (0021,"SIEMENS CT VA0 RAW",42) US Unknown 1-n (0021,"SIEMENS CT VA0 RAW",43) US Unknown 1-n (0021,"SIEMENS CT VA0 RAW",44) US Unknown 1-n (0021,"SIEMENS CT VA0 RAW",50) LT Unknown 1 (0009,"SIEMENS DICOM",10) UN Unknown 1 (0009,"SIEMENS DICOM",12) LT Unknown 1 (0019,"SIEMENS DLR.01",10) LT MeasurementMode 1 (0019,"SIEMENS DLR.01",11) LT ImageType 1 (0019,"SIEMENS DLR.01",15) LT SoftwareVersion 1 (0019,"SIEMENS DLR.01",20) LT MPMCode 1 (0019,"SIEMENS DLR.01",21) LT Latitude 1 (0019,"SIEMENS DLR.01",22) LT Sensitivity 1 (0019,"SIEMENS DLR.01",23) LT EDR 1 (0019,"SIEMENS DLR.01",24) LT LFix 1 (0019,"SIEMENS DLR.01",25) LT SFix 1 (0019,"SIEMENS DLR.01",26) LT PresetMode 1 (0019,"SIEMENS DLR.01",27) LT Region 1 (0019,"SIEMENS DLR.01",28) LT Subregion 1 (0019,"SIEMENS DLR.01",30) LT Orientation 1 (0019,"SIEMENS DLR.01",31) LT MarkOnFilm 1 (0019,"SIEMENS DLR.01",32) LT RotationOnDRC 1 (0019,"SIEMENS DLR.01",40) LT ReaderType 1 (0019,"SIEMENS DLR.01",41) LT SubModality 1 (0019,"SIEMENS DLR.01",42) LT ReaderSerialNumber 1 (0019,"SIEMENS DLR.01",50) LT CassetteScale 1 (0019,"SIEMENS DLR.01",51) LT CassetteMatrix 1 (0019,"SIEMENS DLR.01",52) LT CassetteSubmatrix 1 (0019,"SIEMENS DLR.01",53) LT Barcode 1 (0019,"SIEMENS DLR.01",60) LT ContrastType 1 (0019,"SIEMENS DLR.01",61) LT RotationAmount 1 (0019,"SIEMENS DLR.01",62) LT RotationCenter 1 (0019,"SIEMENS DLR.01",63) LT DensityShift 1 (0019,"SIEMENS DLR.01",64) US FrequencyRank 1 (0019,"SIEMENS DLR.01",65) LT FrequencyEnhancement 1 (0019,"SIEMENS DLR.01",66) LT FrequencyType 1 (0019,"SIEMENS DLR.01",67) LT KernelLength 1 (0019,"SIEMENS DLR.01",68) UL KernelMode 1 (0019,"SIEMENS DLR.01",69) UL ConvolutionMode 1 (0019,"SIEMENS DLR.01",70) LT PLASource 1 (0019,"SIEMENS DLR.01",71) LT PLADestination 1 (0019,"SIEMENS DLR.01",75) LT UIDOriginalImage 1 (0019,"SIEMENS DLR.01",76) LT Unknown 1 (0019,"SIEMENS DLR.01",80) LT ReaderHeader 1 (0019,"SIEMENS DLR.01",90) LT PLAOfSecondaryDestination 1 (0019,"SIEMENS DLR.01",a0) DS Unknown 1 (0019,"SIEMENS DLR.01",a1) DS Unknown 1 (0041,"SIEMENS DLR.01",10) US NumberOfHardcopies 1 (0041,"SIEMENS DLR.01",20) LT FilmFormat 1 (0041,"SIEMENS DLR.01",30) LT FilmSize 1 (0041,"SIEMENS DLR.01",31) LT FullFilmFormat 1 (0003,"SIEMENS ISI",08) US ISICommandField 1 (0003,"SIEMENS ISI",11) US AttachIDApplicationCode 1 (0003,"SIEMENS ISI",12) UL AttachIDMessageCount 1 (0003,"SIEMENS ISI",13) DA AttachIDDate 1 (0003,"SIEMENS ISI",14) TM AttachIDTime 1 (0003,"SIEMENS ISI",20) US MessageType 1 (0003,"SIEMENS ISI",30) DA MaxWaitingDate 1 (0003,"SIEMENS ISI",31) TM MaxWaitingTime 1 (0009,"SIEMENS ISI",01) UN RISPatientInfoIMGEF 1 (0011,"SIEMENS ISI",03) LT PatientUID 1 (0011,"SIEMENS ISI",04) LT PatientID 1 (0011,"SIEMENS ISI",0a) LT CaseID 1 (0011,"SIEMENS ISI",22) LT RequestID 1 (0011,"SIEMENS ISI",23) LT ExaminationUID 1 (0011,"SIEMENS ISI",a1) DA PatientRegistrationDate 1 (0011,"SIEMENS ISI",a2) TM PatientRegistrationTime 1 (0011,"SIEMENS ISI",b0) LT PatientLastName 1 (0011,"SIEMENS ISI",b2) LT PatientFirstName 1 (0011,"SIEMENS ISI",b4) LT PatientHospitalStatus 1 (0011,"SIEMENS ISI",bc) TM CurrentLocationTime 1 (0011,"SIEMENS ISI",c0) LT PatientInsuranceStatus 1 (0011,"SIEMENS ISI",d0) LT PatientBillingType 1 (0011,"SIEMENS ISI",d2) LT PatientBillingAddress 1 (0031,"SIEMENS ISI",12) LT ExaminationReason 1 (0031,"SIEMENS ISI",30) DA RequestedDate 1 (0031,"SIEMENS ISI",32) TM WorklistRequestStartTime 1 (0031,"SIEMENS ISI",33) TM WorklistRequestEndTime 1 (0031,"SIEMENS ISI",4a) TM RequestedTime 1 (0031,"SIEMENS ISI",80) LT RequestedLocation 1 (0055,"SIEMENS ISI",46) LT CurrentWard 1 (0193,"SIEMENS ISI",02) DS RISKey 1 (0307,"SIEMENS ISI",01) UN RISWorklistIMGEF 1 (0309,"SIEMENS ISI",01) UN RISReportIMGEF 1 (4009,"SIEMENS ISI",01) LT ReportID 1 (4009,"SIEMENS ISI",20) LT ReportStatus 1 (4009,"SIEMENS ISI",30) DA ReportCreationDate 1 (4009,"SIEMENS ISI",70) LT ReportApprovingPhysician 1 (4009,"SIEMENS ISI",e0) LT ReportText 1 (4009,"SIEMENS ISI",e1) LT ReportAuthor 1 (4009,"SIEMENS ISI",e3) LT ReportingRadiologist 1 (0029,"SIEMENS MED DISPLAY",04) LT PhotometricInterpretation 1 (0029,"SIEMENS MED DISPLAY",10) US RowsOfSubmatrix 1 (0029,"SIEMENS MED DISPLAY",11) US ColumnsOfSubmatrix 1 (0029,"SIEMENS MED DISPLAY",20) US Unknown 1 (0029,"SIEMENS MED DISPLAY",21) US Unknown 1 (0029,"SIEMENS MED DISPLAY",50) US OriginOfSubmatrix 1 (0029,"SIEMENS MED DISPLAY",99) LT ShutterType 1 (0029,"SIEMENS MED DISPLAY",a0) US RowsOfRectangularShutter 1 (0029,"SIEMENS MED DISPLAY",a1) US ColumnsOfRectangularShutter 1 (0029,"SIEMENS MED DISPLAY",a2) US OriginOfRectangularShutter 1 (0029,"SIEMENS MED DISPLAY",b0) US RadiusOfCircularShutter 1 (0029,"SIEMENS MED DISPLAY",b2) US OriginOfCircularShutter 1 (0029,"SIEMENS MED DISPLAY",c1) US ContourOfIrregularShutter 1 (0029,"SIEMENS MED HG",10) US ListOfGroupNumbers 1 (0029,"SIEMENS MED HG",15) LT ListOfShadowOwnerCodes 1 (0029,"SIEMENS MED HG",20) US ListOfElementNumbers 1 (0029,"SIEMENS MED HG",30) US ListOfTotalDisplayLength 1 (0029,"SIEMENS MED HG",40) LT ListOfDisplayPrefix 1 (0029,"SIEMENS MED HG",50) LT ListOfDisplayPostfix 1 (0029,"SIEMENS MED HG",60) US ListOfTextPosition 1 (0029,"SIEMENS MED HG",70) LT ListOfTextConcatenation 1 (0029,"SIEMENS MED MG",10) US ListOfGroupNumbers 1 (0029,"SIEMENS MED MG",15) LT ListOfShadowOwnerCodes 1 (0029,"SIEMENS MED MG",20) US ListOfElementNumbers 1 (0029,"SIEMENS MED MG",30) US ListOfTotalDisplayLength 1 (0029,"SIEMENS MED MG",40) LT ListOfDisplayPrefix 1 (0029,"SIEMENS MED MG",50) LT ListOfDisplayPostfix 1 (0029,"SIEMENS MED MG",60) US ListOfTextPosition 1 (0029,"SIEMENS MED MG",70) LT ListOfTextConcatenation 1 (0009,"SIEMENS MED",10) LO RecognitionCode 1 (0009,"SIEMENS MED",30) UL ByteOffsetOfOriginalHeader 1 (0009,"SIEMENS MED",31) UL LengthOfOriginalHeader 1 (0009,"SIEMENS MED",40) UL ByteOffsetOfPixelmatrix 1 (0009,"SIEMENS MED",41) UL LengthOfPixelmatrixInBytes 1 (0009,"SIEMENS MED",50) LT Unknown 1 (0009,"SIEMENS MED",51) LT Unknown 1 (0009,"SIEMENS MED",f5) LT PDMEFIDPlaceholder 1 (0009,"SIEMENS MED",f6) LT PDMDataObjectTypeExtension 1 (0021,"SIEMENS MED",10) DS Zoom 1 (0021,"SIEMENS MED",11) DS Target 2 (0021,"SIEMENS MED",12) IS TubeAngle 1 (0021,"SIEMENS MED",20) US ROIMask 1 (7001,"SIEMENS MED",10) LT Dummy 1 (7003,"SIEMENS MED",10) LT Header 1 (7005,"SIEMENS MED",10) LT Dummy 1 (0029,"SIEMENS MEDCOM HEADER",08) CS MedComHeaderType 1 (0029,"SIEMENS MEDCOM HEADER",09) LO MedComHeaderVersion 1 (0029,"SIEMENS MEDCOM HEADER",10) OB MedComHeaderInfo 1 (0029,"SIEMENS MEDCOM HEADER",20) OB MedComHistoryInformation 1 (0029,"SIEMENS MEDCOM HEADER",31) LO PMTFInformation1 1 (0029,"SIEMENS MEDCOM HEADER",32) UL PMTFInformation2 1 (0029,"SIEMENS MEDCOM HEADER",33) UL PMTFInformation3 1 (0029,"SIEMENS MEDCOM HEADER",34) CS PMTFInformation4 1 (0029,"SIEMENS MEDCOM HEADER",35) UL PMTFInformation5 1 (0029,"SIEMENS MEDCOM HEADER",40) SQ ApplicationHeaderSequence 1 (0029,"SIEMENS MEDCOM HEADER",41) CS ApplicationHeaderType 1 (0029,"SIEMENS MEDCOM HEADER",42) LO ApplicationHeaderID 1 (0029,"SIEMENS MEDCOM HEADER",43) LO ApplicationHeaderVersion 1 (0029,"SIEMENS MEDCOM HEADER",44) OB ApplicationHeaderInfo 1 (0029,"SIEMENS MEDCOM HEADER",50) LO WorkflowControlFlags 8 (0029,"SIEMENS MEDCOM HEADER",51) CS ArchiveManagementFlagKeepOnline 1 (0029,"SIEMENS MEDCOM HEADER",52) CS ArchiveManagementFlagDoNotArchive 1 (0029,"SIEMENS MEDCOM HEADER",53) CS ImageLocationStatus 1 (0029,"SIEMENS MEDCOM HEADER",54) DS EstimatedRetrieveTime 1 (0029,"SIEMENS MEDCOM HEADER",55) DS DataSizeOfRetrievedImages 1 (0029,"SIEMENS MEDCOM OOG",08) CS MEDCOMOOGType 1 (0029,"SIEMENS MEDCOM OOG",09) LO MEDCOMOOGVersion 1 (0029,"SIEMENS MEDCOM OOG",10) OB MEDCOMOOGInfo 1 (0019,"SIEMENS MR VA0 COAD",12) DS MagneticFieldStrength 1 (0019,"SIEMENS MR VA0 COAD",14) DS ADCVoltage 1 (0019,"SIEMENS MR VA0 COAD",16) DS ADCOffset 2 (0019,"SIEMENS MR VA0 COAD",20) DS TransmitterAmplitude 1 (0019,"SIEMENS MR VA0 COAD",21) IS NumberOfTransmitterAmplitudes 1 (0019,"SIEMENS MR VA0 COAD",22) DS TransmitterAttenuator 1 (0019,"SIEMENS MR VA0 COAD",24) DS TransmitterCalibration 1 (0019,"SIEMENS MR VA0 COAD",26) DS TransmitterReference 1 (0019,"SIEMENS MR VA0 COAD",50) DS ReceiverTotalGain 1 (0019,"SIEMENS MR VA0 COAD",51) DS ReceiverAmplifierGain 1 (0019,"SIEMENS MR VA0 COAD",52) DS ReceiverPreamplifierGain 1 (0019,"SIEMENS MR VA0 COAD",54) DS ReceiverCableAttenuation 1 (0019,"SIEMENS MR VA0 COAD",55) DS ReceiverReferenceGain 1 (0019,"SIEMENS MR VA0 COAD",56) DS ReceiverFilterFrequency 1 (0019,"SIEMENS MR VA0 COAD",60) DS ReconstructionScaleFactor 1 (0019,"SIEMENS MR VA0 COAD",62) DS ReferenceScaleFactor 1 (0019,"SIEMENS MR VA0 COAD",70) DS PhaseGradientAmplitude 1 (0019,"SIEMENS MR VA0 COAD",71) DS ReadoutGradientAmplitude 1 (0019,"SIEMENS MR VA0 COAD",72) DS SelectionGradientAmplitude 1 (0019,"SIEMENS MR VA0 COAD",80) DS GradientDelayTime 3 (0019,"SIEMENS MR VA0 COAD",82) DS TotalGradientDelayTime 1 (0019,"SIEMENS MR VA0 COAD",90) LT SensitivityCorrectionLabel 1 (0019,"SIEMENS MR VA0 COAD",91) DS SaturationPhaseEncodingVectorCoronalComponent 6 (0019,"SIEMENS MR VA0 COAD",92) DS SaturationReadoutVectorCoronalComponent 6 (0019,"SIEMENS MR VA0 COAD",a0) US RFWatchdogMask 3 (0019,"SIEMENS MR VA0 COAD",a1) DS EPIReconstructionSlope 1 (0019,"SIEMENS MR VA0 COAD",a2) DS RFPowerErrorIndicator 1 (0019,"SIEMENS MR VA0 COAD",a5) DS SpecificAbsorptionRateWholeBody 3 (0019,"SIEMENS MR VA0 COAD",a6) DS SpecificEnergyDose 3 (0019,"SIEMENS MR VA0 COAD",b0) UL AdjustmentStatusMask 1 (0019,"SIEMENS MR VA0 COAD",c1) DS EPICapacity 6 (0019,"SIEMENS MR VA0 COAD",c2) DS EPIInductance 3 (0019,"SIEMENS MR VA0 COAD",c3) IS EPISwitchConfigurationCode 1-n (0019,"SIEMENS MR VA0 COAD",c4) IS EPISwitchHardwareCode 1-n (0019,"SIEMENS MR VA0 COAD",c5) DS EPISwitchDelayTime 1-n (0019,"SIEMENS MR VA0 COAD",d1) DS FlowSensitivity 1 (0019,"SIEMENS MR VA0 COAD",d2) LT CalculationSubmode 1 (0019,"SIEMENS MR VA0 COAD",d3) DS FieldOfViewRatio 1 (0019,"SIEMENS MR VA0 COAD",d4) IS BaseRawMatrixSize 1 (0019,"SIEMENS MR VA0 COAD",d5) IS 2DOversamplingLines 1 (0019,"SIEMENS MR VA0 COAD",d6) IS 3DPhaseOversamplingPartitions 1 (0019,"SIEMENS MR VA0 COAD",d7) IS EchoLinePosition 1 (0019,"SIEMENS MR VA0 COAD",d8) IS EchoColumnPosition 1 (0019,"SIEMENS MR VA0 COAD",d9) IS LinesPerSegment 1 (0019,"SIEMENS MR VA0 COAD",da) LT PhaseCodingDirection 1 (0019,"SIEMENS MR VA0 GEN",10) DS TotalMeasurementTimeNominal 1 (0019,"SIEMENS MR VA0 GEN",11) DS TotalMeasurementTimeCurrent 1 (0019,"SIEMENS MR VA0 GEN",12) DS StartDelayTime 1 (0019,"SIEMENS MR VA0 GEN",13) DS DwellTime 1 (0019,"SIEMENS MR VA0 GEN",14) IS NumberOfPhases 1 (0019,"SIEMENS MR VA0 GEN",16) UL SequenceControlMask 2 (0019,"SIEMENS MR VA0 GEN",18) UL MeasurementStatusMask 1 (0019,"SIEMENS MR VA0 GEN",20) IS NumberOfFourierLinesNominal 1 (0019,"SIEMENS MR VA0 GEN",21) IS NumberOfFourierLinesCurrent 1 (0019,"SIEMENS MR VA0 GEN",26) IS NumberOfFourierLinesAfterZero 1 (0019,"SIEMENS MR VA0 GEN",28) IS FirstMeasuredFourierLine 1 (0019,"SIEMENS MR VA0 GEN",30) IS AcquisitionColumns 1 (0019,"SIEMENS MR VA0 GEN",31) IS ReconstructionColumns 1 (0019,"SIEMENS MR VA0 GEN",40) IS ArrayCoilElementNumber 1 (0019,"SIEMENS MR VA0 GEN",41) UL ArrayCoilElementSelectMask 1 (0019,"SIEMENS MR VA0 GEN",42) UL ArrayCoilElementDataMask 1 (0019,"SIEMENS MR VA0 GEN",43) IS ArrayCoilElementToADCConnect 1-n (0019,"SIEMENS MR VA0 GEN",44) DS ArrayCoilElementNoiseLevel 1-n (0019,"SIEMENS MR VA0 GEN",45) IS ArrayCoilADCPairNumber 1 (0019,"SIEMENS MR VA0 GEN",46) UL ArrayCoilCombinationMask 1 (0019,"SIEMENS MR VA0 GEN",50) IS NumberOfAverages 1 (0019,"SIEMENS MR VA0 GEN",60) DS FlipAngle 1 (0019,"SIEMENS MR VA0 GEN",70) IS NumberOfPrescans 1 (0019,"SIEMENS MR VA0 GEN",81) LT FilterTypeForRawData 1 (0019,"SIEMENS MR VA0 GEN",82) DS FilterParameterForRawData 1-n (0019,"SIEMENS MR VA0 GEN",83) LT FilterTypeForImageData 1 (0019,"SIEMENS MR VA0 GEN",84) DS FilterParameterForImageData 1-n (0019,"SIEMENS MR VA0 GEN",85) LT FilterTypeForPhaseCorrection 1 (0019,"SIEMENS MR VA0 GEN",86) DS FilterParameterForPhaseCorrection 1-n (0019,"SIEMENS MR VA0 GEN",87) LT NormalizationFilterTypeForImageData 1 (0019,"SIEMENS MR VA0 GEN",88) DS NormalizationFilterParameterForImageData 1-n (0019,"SIEMENS MR VA0 GEN",90) IS NumberOfSaturationRegions 1 (0019,"SIEMENS MR VA0 GEN",91) DS SaturationPhaseEncodingVectorSagittalComponent 6 (0019,"SIEMENS MR VA0 GEN",92) DS SaturationReadoutVectorSagittalComponent 6 (0019,"SIEMENS MR VA0 GEN",93) DS EPIStimulationMonitorMode 1 (0019,"SIEMENS MR VA0 GEN",94) DS ImageRotationAngle 1 (0019,"SIEMENS MR VA0 GEN",96) UL CoilIDMask 3 (0019,"SIEMENS MR VA0 GEN",97) UL CoilClassMask 2 (0019,"SIEMENS MR VA0 GEN",98) DS CoilPosition 3 (0019,"SIEMENS MR VA0 GEN",a0) DS EPIReconstructionPhase 1 (0019,"SIEMENS MR VA0 GEN",a1) DS EPIReconstructionSlope 1 (0021,"SIEMENS MR VA0 GEN",20) IS PhaseCorrectionRowsSequence 1 (0021,"SIEMENS MR VA0 GEN",21) IS PhaseCorrectionColumnsSequence 1 (0021,"SIEMENS MR VA0 GEN",22) IS PhaseCorrectionRowsReconstruction 1 (0021,"SIEMENS MR VA0 GEN",24) IS PhaseCorrectionColumnsReconstruction 1 (0021,"SIEMENS MR VA0 GEN",30) IS NumberOf3DRawPartitionsNominal 1 (0021,"SIEMENS MR VA0 GEN",31) IS NumberOf3DRawPartitionsCurrent 1 (0021,"SIEMENS MR VA0 GEN",34) IS NumberOf3DImagePartitions 1 (0021,"SIEMENS MR VA0 GEN",36) IS Actual3DImagePartitionNumber 1 (0021,"SIEMENS MR VA0 GEN",39) DS SlabThickness 1 (0021,"SIEMENS MR VA0 GEN",40) IS NumberOfSlicesNominal 1 (0021,"SIEMENS MR VA0 GEN",41) IS NumberOfSlicesCurrent 1 (0021,"SIEMENS MR VA0 GEN",42) IS CurrentSliceNumber 1 (0021,"SIEMENS MR VA0 GEN",43) IS CurrentGroupNumber 1 (0021,"SIEMENS MR VA0 GEN",44) DS CurrentSliceDistanceFactor 1 (0021,"SIEMENS MR VA0 GEN",45) IS MIPStartRow 1 (0021,"SIEMENS MR VA0 GEN",46) IS MIPStopRow 1 (0021,"SIEMENS MR VA0 GEN",47) IS MIPStartColumn 1 (0021,"SIEMENS MR VA0 GEN",48) IS MIPStartColumn 1 (0021,"SIEMENS MR VA0 GEN",49) IS MIPStartSlice Name= 1 (0021,"SIEMENS MR VA0 GEN",4a) IS MIPStartSlice 1 (0021,"SIEMENS MR VA0 GEN",4f) LT OrderofSlices 1 (0021,"SIEMENS MR VA0 GEN",50) US SignalMask 1 (0021,"SIEMENS MR VA0 GEN",52) DS DelayAfterTrigger 1 (0021,"SIEMENS MR VA0 GEN",53) IS RRInterval 1 (0021,"SIEMENS MR VA0 GEN",54) DS NumberOfTriggerPulses 1 (0021,"SIEMENS MR VA0 GEN",56) DS RepetitionTimeEffective 1 (0021,"SIEMENS MR VA0 GEN",57) LT GatePhase 1 (0021,"SIEMENS MR VA0 GEN",58) DS GateThreshold 1 (0021,"SIEMENS MR VA0 GEN",59) DS GatedRatio 1 (0021,"SIEMENS MR VA0 GEN",60) IS NumberOfInterpolatedImages 1 (0021,"SIEMENS MR VA0 GEN",70) IS NumberOfEchoes 1 (0021,"SIEMENS MR VA0 GEN",72) DS SecondEchoTime 1 (0021,"SIEMENS MR VA0 GEN",73) DS SecondRepetitionTime 1 (0021,"SIEMENS MR VA0 GEN",80) IS CardiacCode 1 (0021,"SIEMENS MR VA0 GEN",91) DS SaturationPhaseEncodingVectorTransverseComponent 6 (0021,"SIEMENS MR VA0 GEN",92) DS SaturationReadoutVectorTransverseComponent 6 (0021,"SIEMENS MR VA0 GEN",93) DS EPIChangeValueOfMagnitude 1 (0021,"SIEMENS MR VA0 GEN",94) DS EPIChangeValueOfXComponent 1 (0021,"SIEMENS MR VA0 GEN",95) DS EPIChangeValueOfYComponent 1 (0021,"SIEMENS MR VA0 GEN",96) DS EPIChangeValueOfZComponent 1 (0021,"SIEMENS MR VA0 RAW",00) LT SequenceType 1 (0021,"SIEMENS MR VA0 RAW",01) IS VectorSizeOriginal 1 (0021,"SIEMENS MR VA0 RAW",02) IS VectorSizeExtended 1 (0021,"SIEMENS MR VA0 RAW",03) DS AcquiredSpectralRange 1 (0021,"SIEMENS MR VA0 RAW",04) DS VOIPosition 3 (0021,"SIEMENS MR VA0 RAW",05) DS VOISize 3 (0021,"SIEMENS MR VA0 RAW",06) IS CSIMatrixSizeOriginal 3 (0021,"SIEMENS MR VA0 RAW",07) IS CSIMatrixSizeExtended 3 (0021,"SIEMENS MR VA0 RAW",08) DS SpatialGridShift 3 (0021,"SIEMENS MR VA0 RAW",09) DS SignalLimitsMinimum 1 (0021,"SIEMENS MR VA0 RAW",10) DS SignalLimitsMaximum 1 (0021,"SIEMENS MR VA0 RAW",11) DS SpecInfoMask 1 (0021,"SIEMENS MR VA0 RAW",12) DS EPITimeRateOfChangeOfMagnitude 1 (0021,"SIEMENS MR VA0 RAW",13) DS EPITimeRateOfChangeOfXComponent 1 (0021,"SIEMENS MR VA0 RAW",14) DS EPITimeRateOfChangeOfYComponent 1 (0021,"SIEMENS MR VA0 RAW",15) DS EPITimeRateOfChangeOfZComponent 1 (0021,"SIEMENS MR VA0 RAW",16) DS EPITimeRateOfChangeLegalLimit1 1 (0021,"SIEMENS MR VA0 RAW",17) DS EPIOperationModeFlag 1 (0021,"SIEMENS MR VA0 RAW",18) DS EPIFieldCalculationSafetyFactor 1 (0021,"SIEMENS MR VA0 RAW",19) DS EPILegalLimit1OfChangeValue 1 (0021,"SIEMENS MR VA0 RAW",20) DS EPILegalLimit2OfChangeValue 1 (0021,"SIEMENS MR VA0 RAW",21) DS EPIRiseTime 1 (0021,"SIEMENS MR VA0 RAW",30) DS ArrayCoilADCOffset 16 (0021,"SIEMENS MR VA0 RAW",31) DS ArrayCoilPreamplifierGain 16 (0021,"SIEMENS MR VA0 RAW",50) LT SaturationType 1 (0021,"SIEMENS MR VA0 RAW",51) DS SaturationNormalVector 3 (0021,"SIEMENS MR VA0 RAW",52) DS SaturationPositionVector 3 (0021,"SIEMENS MR VA0 RAW",53) DS SaturationThickness 6 (0021,"SIEMENS MR VA0 RAW",54) DS SaturationWidth 6 (0021,"SIEMENS MR VA0 RAW",55) DS SaturationDistance 6 (7fe3,"SIEMENS NUMARIS II",00) LT ImageGraphicsFormatCode 1 (7fe3,"SIEMENS NUMARIS II",10) OB ImageGraphics 1 (7fe3,"SIEMENS NUMARIS II",20) OB ImageGraphicsDummy 1 (0011,"SIEMENS RA GEN",20) SL FluoroTimer 1 (0011,"SIEMENS RA GEN",25) SL PtopDoseAreaProduct 1 (0011,"SIEMENS RA GEN",26) SL PtopTotalSkinDose 1 (0011,"SIEMENS RA GEN",30) LT Unknown 1 (0011,"SIEMENS RA GEN",35) LO PatientInitialPuckCounter 1 (0011,"SIEMENS RA GEN",40) SS SPIDataObjectType 1 (0019,"SIEMENS RA GEN",15) LO AcquiredPlane 1 (0019,"SIEMENS RA GEN",1f) SS DefaultTableIsoCenterHeight 1 (0019,"SIEMENS RA GEN",20) SL SceneFlag 1 (0019,"SIEMENS RA GEN",22) SL RefPhotofileFlag 1 (0019,"SIEMENS RA GEN",24) LO SceneName 1 (0019,"SIEMENS RA GEN",26) SS AcquisitionIndex 1 (0019,"SIEMENS RA GEN",28) SS MixedPulseMode 1 (0019,"SIEMENS RA GEN",2a) SS NoOfPositions 1 (0019,"SIEMENS RA GEN",2c) SS NoOfPhases 1 (0019,"SIEMENS RA GEN",2e) SS FrameRateForPositions 1-n (0019,"SIEMENS RA GEN",30) SS NoOfFramesForPositions 1-n (0019,"SIEMENS RA GEN",32) SS SteppingDirection 1 (0019,"SIEMENS RA GEN",34) US Unknown 1 (0019,"SIEMENS RA GEN",36) US Unknown 1 (0019,"SIEMENS RA GEN",38) US Unknown 1 (0019,"SIEMENS RA GEN",3a) US Unknown 1 (0019,"SIEMENS RA GEN",3c) US Unknown 1 (0019,"SIEMENS RA GEN",3e) US Unknown 1 (0019,"SIEMENS RA GEN",40) US Unknown 1 (0019,"SIEMENS RA GEN",42) US Unknown 1 (0019,"SIEMENS RA GEN",44) SS ImageTransferDelay 1 (0019,"SIEMENS RA GEN",46) SL InversFlag 1 (0019,"SIEMENS RA GEN",48) US Unknown 1 (0019,"SIEMENS RA GEN",4a) US Unknown 1 (0019,"SIEMENS RA GEN",4c) SS BlankingCircleDiameter 1 (0019,"SIEMENS RA GEN",50) SL StandDataValid 1 (0019,"SIEMENS RA GEN",52) SS TableTilt 1 (0019,"SIEMENS RA GEN",54) SS TableAxisRotation 1 (0019,"SIEMENS RA GEN",56) SS TableLongitudalPosition 1 (0019,"SIEMENS RA GEN",58) SS TableSideOffset 1 (0019,"SIEMENS RA GEN",5a) SS TableIsoCenterHeight 1 (0019,"SIEMENS RA GEN",5c) UN Unknown 1 (0019,"SIEMENS RA GEN",5e) SL CollimationDataValid 1 (0019,"SIEMENS RA GEN",60) SL PeriSequenceNo 1 (0019,"SIEMENS RA GEN",62) SL PeriTotalScenes 1 (0019,"SIEMENS RA GEN",64) SL PeriOverlapTop 1 (0019,"SIEMENS RA GEN",66) SL PeriOverlapBottom 1 (0019,"SIEMENS RA GEN",68) SL RawImageNumber 1 (0019,"SIEMENS RA GEN",6a) SL XRayDataValid 1 (0019,"SIEMENS RA GEN",70) US Unknown 1-n (0019,"SIEMENS RA GEN",72) US Unknown 1-n (0019,"SIEMENS RA GEN",74) US Unknown 1-n (0019,"SIEMENS RA GEN",76) SL FillingAverageFactor 1 (0019,"SIEMENS RA GEN",78) US Unknown 1-n (0019,"SIEMENS RA GEN",7a) US Unknown 1-n (0019,"SIEMENS RA GEN",7c) US Unknown 1-n (0019,"SIEMENS RA GEN",7e) US Unknown 1-n (0019,"SIEMENS RA GEN",80) US Unknown 1-n (0019,"SIEMENS RA GEN",82) US Unknown 1-n (0019,"SIEMENS RA GEN",84) US Unknown 1-n (0019,"SIEMENS RA GEN",86) US Unknown 1-n (0019,"SIEMENS RA GEN",88) US Unknown 1-n (0019,"SIEMENS RA GEN",8a) US Unknown 1-n (0019,"SIEMENS RA GEN",8c) US Unknown 1-n (0019,"SIEMENS RA GEN",8e) US Unknown 1-n (0019,"SIEMENS RA GEN",92) US Unknown 1-n (0019,"SIEMENS RA GEN",94) US Unknown 1-n (0019,"SIEMENS RA GEN",96) US Unknown 1-n (0019,"SIEMENS RA GEN",98) US Unknown 1-n (0019,"SIEMENS RA GEN",9a) US Unknown 1-n (0019,"SIEMENS RA GEN",9c) SL IntensifierLevelCalibrationFactor 1 (0019,"SIEMENS RA GEN",9e) SL NativeReviewFlag 1 (0019,"SIEMENS RA GEN",a2) SL SceneNumber 1 (0019,"SIEMENS RA GEN",a4) SS AcquisitionMode 1 (0019,"SIEMENS RA GEN",a5) SS AcquisitonFrameRate 1 (0019,"SIEMENS RA GEN",a6) SL ECGFlag 1 (0019,"SIEMENS RA GEN",a7) SL AdditionalSceneData 1 (0019,"SIEMENS RA GEN",a8) SL FileCopyFlag 1 (0019,"SIEMENS RA GEN",a9) SL PhlebovisionFlag 1 (0019,"SIEMENS RA GEN",aa) SL Co2Flag 1 (0019,"SIEMENS RA GEN",ab) SS MaxSpeed 1 (0019,"SIEMENS RA GEN",ac) SS StepWidth 1 (0019,"SIEMENS RA GEN",ad) SL DigitalAcquisitionZoom 1 (0019,"SIEMENS RA GEN",ff) SS Internal 1-n (0021,"SIEMENS RA GEN",15) SS ImagesInStudy 1 (0021,"SIEMENS RA GEN",20) SS ScenesInStudy 1 (0021,"SIEMENS RA GEN",25) SS ImagesInPhotofile 1 (0021,"SIEMENS RA GEN",27) SS PlaneBImagesExist 1 (0021,"SIEMENS RA GEN",28) SS NoOf2MBChunks 1 (0021,"SIEMENS RA GEN",30) SS ImagesInAllScenes 1 (0021,"SIEMENS RA GEN",40) SS ArchiveSWInternalVersion 1 (0011,"SIEMENS RA PLANE A",28) SL FluoroTimerA 1 (0011,"SIEMENS RA PLANE A",29) SL FluoroSkinDoseA 1 (0011,"SIEMENS RA PLANE A",2a) SL TotalSkinDoseA 1 (0011,"SIEMENS RA PLANE A",2b) SL FluoroDoseAreaProductA 1 (0011,"SIEMENS RA PLANE A",2c) SL TotalDoseAreaProductA 1 (0019,"SIEMENS RA PLANE A",15) LT OfflineUID 1 (0019,"SIEMENS RA PLANE A",18) SS Internal 1 (0019,"SIEMENS RA PLANE A",19) SS Internal 1 (0019,"SIEMENS RA PLANE A",1a) SS Internal 1 (0019,"SIEMENS RA PLANE A",1b) SS Internal 1 (0019,"SIEMENS RA PLANE A",1c) SS Internal 1 (0019,"SIEMENS RA PLANE A",1d) SS Internal 1 (0019,"SIEMENS RA PLANE A",1e) SS Internal 1 (0019,"SIEMENS RA PLANE A",1f) SS Internal 1-n (0019,"SIEMENS RA PLANE A",20) SS SystemCalibFactorPlaneA 1 (0019,"SIEMENS RA PLANE A",22) SS XRayParameterSetNo 1 (0019,"SIEMENS RA PLANE A",24) SS XRaySystem 1 (0019,"SIEMENS RA PLANE A",26) US Unknown 1 (0019,"SIEMENS RA PLANE A",28) SS AcquiredDisplayMode 1 (0019,"SIEMENS RA PLANE A",2a) SS AcquisitionDelay 1 (0019,"SIEMENS RA PLANE A",2c) US Unknown 1 (0019,"SIEMENS RA PLANE A",2e) SS MaxFramesLimit 1 (0019,"SIEMENS RA PLANE A",30) US MaximumFrameSizeNIU 1 (0019,"SIEMENS RA PLANE A",32) SS SubtractedFilterType 1 (0019,"SIEMENS RA PLANE A",34) SS FilterFactorNative 1 (0019,"SIEMENS RA PLANE A",36) SS AnatomicBackgroundFactor 1 (0019,"SIEMENS RA PLANE A",38) SS WindowUpperLimitNative 1 (0019,"SIEMENS RA PLANE A",3a) SS WindowLowerLimitNative 1 (0019,"SIEMENS RA PLANE A",3c) SS WindowBrightnessPhase1 1 (0019,"SIEMENS RA PLANE A",3e) SS WindowBrightnessPhase2 1 (0019,"SIEMENS RA PLANE A",40) SS WindowContrastPhase1 1 (0019,"SIEMENS RA PLANE A",42) SS WindowContrastPhase2 1 (0019,"SIEMENS RA PLANE A",44) SS FilterFactorSub 1 (0019,"SIEMENS RA PLANE A",46) SS PeakOpacified 1 (0019,"SIEMENS RA PLANE A",48) SL MaskFrame 1 (0019,"SIEMENS RA PLANE A",4a) SL BIHFrame 1 (0019,"SIEMENS RA PLANE A",4c) SS CentBeamAngulationCaudCran 1 (0019,"SIEMENS RA PLANE A",4e) SS CentBeamAngulationLRAnterior 1 (0019,"SIEMENS RA PLANE A",50) SS LongitudinalPosition 1 (0019,"SIEMENS RA PLANE A",52) SS SideOffset 1 (0019,"SIEMENS RA PLANE A",54) SS IsoCenterHeight 1 (0019,"SIEMENS RA PLANE A",56) SS ImageTwist 1 (0019,"SIEMENS RA PLANE A",58) SS SourceImageDistance 1 (0019,"SIEMENS RA PLANE A",5a) SS MechanicalMagnificationFactor 1 (0019,"SIEMENS RA PLANE A",5c) SL CalibrationFlag 1 (0019,"SIEMENS RA PLANE A",5e) SL CalibrationAngleCranCaud 1 (0019,"SIEMENS RA PLANE A",60) SL CalibrationAngleRAOLAO 1 (0019,"SIEMENS RA PLANE A",62) SL CalibrationTableToFloorDist 1 (0019,"SIEMENS RA PLANE A",64) SL CalibrationIsocenterToFloorDist 1 (0019,"SIEMENS RA PLANE A",66) SL CalibrationIsocenterToSourceDist 1 (0019,"SIEMENS RA PLANE A",68) SL CalibrationSourceToII 1 (0019,"SIEMENS RA PLANE A",6a) SL CalibrationIIZoom 1 (0019,"SIEMENS RA PLANE A",6c) SL CalibrationIIField 1 (0019,"SIEMENS RA PLANE A",6e) SL CalibrationFactor 1 (0019,"SIEMENS RA PLANE A",70) SL CalibrationObjectToImageDistance 1 (0019,"SIEMENS RA PLANE A",72) SL CalibrationSystemFactor 1-n (0019,"SIEMENS RA PLANE A",74) SL CalibrationSystemCorrection 1-n (0019,"SIEMENS RA PLANE A",76) SL CalibrationSystemIIFormats 1-n (0019,"SIEMENS RA PLANE A",78) SL CalibrationGantryDataValid 1 (0019,"SIEMENS RA PLANE A",7a) SS CollimatorSquareBreadth 1 (0019,"SIEMENS RA PLANE A",7c) SS CollimatorSquareHeight 1 (0019,"SIEMENS RA PLANE A",7e) SS CollimatorSquareDiameter 1 (0019,"SIEMENS RA PLANE A",80) SS CollimaterFingerTurnAngle 1 (0019,"SIEMENS RA PLANE A",82) SS CollimaterFingerPosition 1 (0019,"SIEMENS RA PLANE A",84) SS CollimaterDiaphragmTurnAngle 1 (0019,"SIEMENS RA PLANE A",86) SS CollimaterDiaphragmPosition1 1 (0019,"SIEMENS RA PLANE A",88) SS CollimaterDiaphragmPosition2 1 (0019,"SIEMENS RA PLANE A",8a) SS CollimaterDiaphragmMode 1 (0019,"SIEMENS RA PLANE A",8c) SS CollimaterBeamLimitBreadth 1 (0019,"SIEMENS RA PLANE A",8e) SS CollimaterBeamLimitHeight 1 (0019,"SIEMENS RA PLANE A",90) SS CollimaterBeamLimitDiameter 1 (0019,"SIEMENS RA PLANE A",92) SS X-RayControlMOde 1 (0019,"SIEMENS RA PLANE A",94) SS X-RaySystem 1 (0019,"SIEMENS RA PLANE A",96) SS FocalSpot 1 (0019,"SIEMENS RA PLANE A",98) SS ExposureControl 1 (0019,"SIEMENS RA PLANE A",9a) SL XRayVoltage 1 (0019,"SIEMENS RA PLANE A",9c) SL XRayCurrent 1 (0019,"SIEMENS RA PLANE A",9e) SL XRayCurrentTimeProduct 1 (0019,"SIEMENS RA PLANE A",a0) SL XRayPulseTime 1 (0019,"SIEMENS RA PLANE A",a2) SL XRaySceneTimeFluoroClock 1 (0019,"SIEMENS RA PLANE A",a4) SS MaximumPulseRate 1 (0019,"SIEMENS RA PLANE A",a6) SS PulsesPerScene 1 (0019,"SIEMENS RA PLANE A",a8) SL DoseAreaProductOfScene 1 (0019,"SIEMENS RA PLANE A",aa) SS Dose 1 (0019,"SIEMENS RA PLANE A",ac) SS DoseRate 1 (0019,"SIEMENS RA PLANE A",ae) SL IIToCoverDistance 1 (0019,"SIEMENS RA PLANE A",b0) SS LastFramePhase1 1 (0019,"SIEMENS RA PLANE A",b1) SS FrameRatePhase1 1 (0019,"SIEMENS RA PLANE A",b2) SS LastFramePhase2 1 (0019,"SIEMENS RA PLANE A",b3) SS FrameRatePhase2 1 (0019,"SIEMENS RA PLANE A",b4) SS LastFramePhase3 1 (0019,"SIEMENS RA PLANE A",b5) SS FrameRatePhase3 1 (0019,"SIEMENS RA PLANE A",b6) SS LastFramePhase4 1 (0019,"SIEMENS RA PLANE A",b7) SS FrameRatePhase4 1 (0019,"SIEMENS RA PLANE A",b8) SS GammaOfNativeImage 1 (0019,"SIEMENS RA PLANE A",b9) SS GammaOfTVSystem 1 (0019,"SIEMENS RA PLANE A",bb) SL PixelshiftX 1 (0019,"SIEMENS RA PLANE A",bc) SL PixelshiftY 1 (0019,"SIEMENS RA PLANE A",bd) SL MaskAverageFactor 1 (0019,"SIEMENS RA PLANE A",be) SL BlankingCircleFlag 1 (0019,"SIEMENS RA PLANE A",bf) SL CircleRowStart 1 (0019,"SIEMENS RA PLANE A",c0) SL CircleRowEnd 1 (0019,"SIEMENS RA PLANE A",c1) SL CircleColumnStart 1 (0019,"SIEMENS RA PLANE A",c2) SL CircleColumnEnd 1 (0019,"SIEMENS RA PLANE A",c3) SL CircleDiameter 1 (0019,"SIEMENS RA PLANE A",c4) SL RectangularCollimaterFlag 1 (0019,"SIEMENS RA PLANE A",c5) SL RectangleRowStart 1 (0019,"SIEMENS RA PLANE A",c6) SL RectangleRowEnd 1 (0019,"SIEMENS RA PLANE A",c7) SL RectangleColumnStart 1 (0019,"SIEMENS RA PLANE A",c8) SL RectangleColumnEnd 1 (0019,"SIEMENS RA PLANE A",c9) SL RectangleAngulation 1 (0019,"SIEMENS RA PLANE A",ca) SL IrisCollimatorFlag 1 (0019,"SIEMENS RA PLANE A",cb) SL IrisRowStart 1 (0019,"SIEMENS RA PLANE A",cc) SL IrisRowEnd 1 (0019,"SIEMENS RA PLANE A",cd) SL IrisColumnStart 1 (0019,"SIEMENS RA PLANE A",ce) SL IrisColumnEnd 1 (0019,"SIEMENS RA PLANE A",cf) SL IrisAngulation 1 (0019,"SIEMENS RA PLANE A",d1) SS NumberOfFramesPlane 1 (0019,"SIEMENS RA PLANE A",d2) SS Internal 1 (0019,"SIEMENS RA PLANE A",d3) SS Internal 1 (0019,"SIEMENS RA PLANE A",d4) SS Internal 1 (0019,"SIEMENS RA PLANE A",d5) SS Internal 1 (0019,"SIEMENS RA PLANE A",d6) SS Internal 1-n (0019,"SIEMENS RA PLANE A",d7) SS Internal 1-n (0019,"SIEMENS RA PLANE A",d8) SS Internal 1 (0019,"SIEMENS RA PLANE A",d9) SS Internal 1 (0019,"SIEMENS RA PLANE A",da) SS Internal 1 (0019,"SIEMENS RA PLANE A",db) SS Internal 1 (0019,"SIEMENS RA PLANE A",dc) SS Internal 1 (0019,"SIEMENS RA PLANE A",dd) SL AnatomicBackground 1 (0019,"SIEMENS RA PLANE A",de) SL AutoWindowBase 1-n (0019,"SIEMENS RA PLANE A",df) SS Internal 1 (0019,"SIEMENS RA PLANE A",e0) SL Internal 1 (0011,"SIEMENS RA PLANE B",28) SL FluoroTimerB 1 (0011,"SIEMENS RA PLANE B",29) SL FluoroSkinDoseB 1 (0011,"SIEMENS RA PLANE B",2a) SL TotalSkinDoseB 1 (0011,"SIEMENS RA PLANE B",2b) SL FluoroDoseAreaProductB 1 (0011,"SIEMENS RA PLANE B",2c) SL TotalDoseAreaProductB 1 (0019,"SIEMENS RA PLANE B",18) SS Internal 1 (0019,"SIEMENS RA PLANE B",19) SS Internal 1 (0019,"SIEMENS RA PLANE B",1a) SS Internal 1 (0019,"SIEMENS RA PLANE B",1b) SS Internal 1 (0019,"SIEMENS RA PLANE B",1c) SS Internal 1 (0019,"SIEMENS RA PLANE B",1d) SS Internal 1 (0019,"SIEMENS RA PLANE B",1e) SS Internal 1 (0019,"SIEMENS RA PLANE B",1f) SS Internal 1 (0019,"SIEMENS RA PLANE B",20) SL SystemCalibFactorPlaneB 1-n (0019,"SIEMENS RA PLANE B",22) US Unknown 1 (0019,"SIEMENS RA PLANE B",24) US Unknown 1 (0019,"SIEMENS RA PLANE B",26) US Unknown 1 (0019,"SIEMENS RA PLANE B",28) US Unknown 1 (0019,"SIEMENS RA PLANE B",2a) US Unknown 1 (0019,"SIEMENS RA PLANE B",2c) US Unknown 1 (0019,"SIEMENS RA PLANE B",2e) US Unknown 1 (0019,"SIEMENS RA PLANE B",30) US Unknown 1 (0019,"SIEMENS RA PLANE B",32) US Unknown 1 (0019,"SIEMENS RA PLANE B",34) US Unknown 1 (0019,"SIEMENS RA PLANE B",36) US Unknown 1 (0019,"SIEMENS RA PLANE B",38) US Unknown 1 (0019,"SIEMENS RA PLANE B",3a) US Unknown 1 (0019,"SIEMENS RA PLANE B",3c) US Unknown 1 (0019,"SIEMENS RA PLANE B",3e) US Unknown 1 (0019,"SIEMENS RA PLANE B",40) US Unknown 1 (0019,"SIEMENS RA PLANE B",42) US Unknown 1 (0019,"SIEMENS RA PLANE B",44) US Unknown 1 (0019,"SIEMENS RA PLANE B",46) US Unknown 1 (0019,"SIEMENS RA PLANE B",48) US Unknown 1 (0019,"SIEMENS RA PLANE B",4a) US Unknown 1-n (0019,"SIEMENS RA PLANE B",4c) US Unknown 1-n (0019,"SIEMENS RA PLANE B",4e) US Unknown 1-n (0019,"SIEMENS RA PLANE B",50) US Unknown 1 (0019,"SIEMENS RA PLANE B",52) US Unknown 1 (0019,"SIEMENS RA PLANE B",54) US Unknown 1 (0019,"SIEMENS RA PLANE B",56) US Unknown 1 (0019,"SIEMENS RA PLANE B",58) US Unknown 1 (0019,"SIEMENS RA PLANE B",5a) US Unknown 1 (0019,"SIEMENS RA PLANE B",5c) US Unknown 1-n (0019,"SIEMENS RA PLANE B",5e) US Unknown 1-n (0019,"SIEMENS RA PLANE B",60) US Unknown 1-n (0019,"SIEMENS RA PLANE B",62) US Unknown 1-n (0019,"SIEMENS RA PLANE B",64) US Unknown 1-n (0019,"SIEMENS RA PLANE B",66) US Unknown 1-n (0019,"SIEMENS RA PLANE B",68) US Unknown 1-n (0019,"SIEMENS RA PLANE B",6a) US Unknown 1-n (0019,"SIEMENS RA PLANE B",6c) US Unknown 1-n (0019,"SIEMENS RA PLANE B",6e) US Unknown 1-n (0019,"SIEMENS RA PLANE B",70) US Unknown 1-n (0019,"SIEMENS RA PLANE B",72) UN Unknown 1 (0019,"SIEMENS RA PLANE B",74) UN Unknown 1 (0019,"SIEMENS RA PLANE B",76) UN Unknown 1 (0019,"SIEMENS RA PLANE B",78) US Unknown 1-n (0019,"SIEMENS RA PLANE B",7a) US Unknown 1 (0019,"SIEMENS RA PLANE B",7c) US Unknown 1 (0019,"SIEMENS RA PLANE B",7e) US Unknown 1 (0019,"SIEMENS RA PLANE B",80) US Unknown 1 (0019,"SIEMENS RA PLANE B",82) US Unknown 1 (0019,"SIEMENS RA PLANE B",84) US Unknown 1 (0019,"SIEMENS RA PLANE B",86) US Unknown 1 (0019,"SIEMENS RA PLANE B",88) US Unknown 1 (0019,"SIEMENS RA PLANE B",8a) US Unknown 1 (0019,"SIEMENS RA PLANE B",8c) US Unknown 1 (0019,"SIEMENS RA PLANE B",8e) US Unknown 1 (0019,"SIEMENS RA PLANE B",90) US Unknown 1 (0019,"SIEMENS RA PLANE B",92) US Unknown 1 (0019,"SIEMENS RA PLANE B",94) US Unknown 1 (0019,"SIEMENS RA PLANE B",96) US Unknown 1 (0019,"SIEMENS RA PLANE B",98) US Unknown 1 (0019,"SIEMENS RA PLANE B",9a) US Unknown 1-n (0019,"SIEMENS RA PLANE B",9c) US Unknown 1-n (0019,"SIEMENS RA PLANE B",9e) US Unknown 1-n (0019,"SIEMENS RA PLANE B",a0) US Unknown 1-n (0019,"SIEMENS RA PLANE B",a2) US Unknown 1-n (0019,"SIEMENS RA PLANE B",a4) US Unknown 1 (0019,"SIEMENS RA PLANE B",a6) US Unknown 1 (0019,"SIEMENS RA PLANE B",a8) US Unknown 1-n (0019,"SIEMENS RA PLANE B",aa) US Unknown 1 (0019,"SIEMENS RA PLANE B",ac) US Unknown 1 (0011,"SIEMENS RIS",10) LT PatientUID 1 (0011,"SIEMENS RIS",11) LT PatientID 1 (0011,"SIEMENS RIS",20) DA PatientRegistrationDate 1 (0011,"SIEMENS RIS",21) TM PatientRegistrationTime 1 (0011,"SIEMENS RIS",30) LT PatientnameRIS 1 (0011,"SIEMENS RIS",31) LT PatientprenameRIS 1 (0011,"SIEMENS RIS",40) LT PatientHospitalStatus 1 (0011,"SIEMENS RIS",41) LT MedicalAlerts 1 (0011,"SIEMENS RIS",42) LT ContrastAllergies 1 (0031,"SIEMENS RIS",10) LT RequestUID 1 (0031,"SIEMENS RIS",45) LT RequestingPhysician 1 (0031,"SIEMENS RIS",50) LT RequestedPhysician 1 (0033,"SIEMENS RIS",10) LT PatientStudyUID 1 (0009,"SIENET",01) US SIENETCommandField 1 (0009,"SIENET",14) LT ReceiverPLA 1 (0009,"SIENET",16) US TransferPriority 1 (0009,"SIENET",29) LT ActualUser 1 (0095,"SIENET",01) LT ExaminationFolderID 1 (0095,"SIENET",04) UL FolderReportedStatus 1 (0095,"SIENET",05) LT FolderReportingRadiologist 1 (0095,"SIENET",07) LT SIENETISAPLA 1 (0099,"SIENET",02) UL DataObjectAttributes 1 (0009,"SPI RELEASE 1",10) LT Comments 1 (0009,"SPI RELEASE 1",15) LO SPIImageUID 1 (0009,"SPI RELEASE 1",40) US DataObjectType 1 (0009,"SPI RELEASE 1",41) LO DataObjectSubtype 1 (0011,"SPI RELEASE 1",10) LO Organ 1 (0011,"SPI RELEASE 1",15) LO AllergyIndication 1 (0011,"SPI RELEASE 1",20) LO Pregnancy 1 (0029,"SPI RELEASE 1",60) LT CompressionAlgorithm 1 (0009,"SPI Release 1",10) LT Comments 1 (0009,"SPI Release 1",15) LO SPIImageUID 1 (0009,"SPI Release 1",40) US DataObjectType 1 (0009,"SPI Release 1",41) LO DataObjectSubtype 1 (0011,"SPI Release 1",10) LO Organ 1 (0011,"SPI Release 1",15) LO AllergyIndication 1 (0011,"SPI Release 1",20) LO Pregnancy 1 (0029,"SPI Release 1",60) LT CompressionAlgorithm 1 (0009,"SPI",10) LO Comments 1 (0009,"SPI",15) LO SPIImageUID 1 (0009,"SPI",40) US DataObjectType 1 (0009,"SPI",41) LT DataObjectSubtype 1 (0011,"SPI",10) LT Organ 1 (0011,"SPI",15) LT AllergyIndication 1 (0011,"SPI",20) LT Pregnancy 1 (0029,"SPI",60) LT CompressionAlgorithm 1 (0011,"SPI RELEASE 1",10) LO Organ 1 (0011,"SPI RELEASE 1",15) LO AllergyIndication 1 (0011,"SPI RELEASE 1",20) LO Pregnancy 1 (0009,"SPI-P Release 1",00) LT DataObjectRecognitionCode 1 (0009,"SPI-P Release 1",04) LO ImageDataConsistence 1 (0009,"SPI-P Release 1",08) US Unknown 1 (0009,"SPI-P Release 1",12) LO Unknown 1 (0009,"SPI-P Release 1",15) LO UniqueIdentifier 1 (0009,"SPI-P Release 1",16) LO Unknown 1 (0009,"SPI-P Release 1",18) LO Unknown 1 (0009,"SPI-P Release 1",21) LT Unknown 1 (0009,"SPI-P Release 1",31) LT PACSUniqueIdentifier 1 (0009,"SPI-P Release 1",34) LT ClusterUniqueIdentifier 1 (0009,"SPI-P Release 1",38) LT SystemUniqueIdentifier 1 (0009,"SPI-P Release 1",39) LT Unknown 1 (0009,"SPI-P Release 1",51) LT StudyUniqueIdentifier 1 (0009,"SPI-P Release 1",61) LT SeriesUniqueIdentifier 1 (0009,"SPI-P Release 1",91) LT Unknown 1 (0009,"SPI-P Release 1",f2) LT Unknown 1 (0009,"SPI-P Release 1",f3) UN Unknown 1 (0009,"SPI-P Release 1",f4) LT Unknown 1 (0009,"SPI-P Release 1",f5) UN Unknown 1 (0009,"SPI-P Release 1",f7) LT Unknown 1 (0011,"SPI-P Release 1",10) LT PatientEntryID 1 (0011,"SPI-P Release 1",21) UN Unknown 1 (0011,"SPI-P Release 1",22) UN Unknown 1 (0011,"SPI-P Release 1",31) UN Unknown 1 (0011,"SPI-P Release 1",32) UN Unknown 1 (0019,"SPI-P Release 1",00) UN Unknown 1 (0019,"SPI-P Release 1",01) UN Unknown 1 (0019,"SPI-P Release 1",02) UN Unknown 1 (0019,"SPI-P Release 1",10) US MainsFrequency 1 (0019,"SPI-P Release 1",25) LT OriginalPixelDataQuality 1-n (0019,"SPI-P Release 1",30) US ECGTriggering 1 (0019,"SPI-P Release 1",31) UN ECG1Offset 1 (0019,"SPI-P Release 1",32) UN ECG2Offset1 1 (0019,"SPI-P Release 1",33) UN ECG2Offset2 1 (0019,"SPI-P Release 1",50) US VideoScanMode 1 (0019,"SPI-P Release 1",51) US VideoLineRate 1 (0019,"SPI-P Release 1",60) US XrayTechnique 1 (0019,"SPI-P Release 1",61) DS ImageIdentifierFromat 1 (0019,"SPI-P Release 1",62) US IrisDiaphragm 1 (0019,"SPI-P Release 1",63) CS Filter 1 (0019,"SPI-P Release 1",64) CS CineParallel 1 (0019,"SPI-P Release 1",65) CS CineMaster 1 (0019,"SPI-P Release 1",70) US ExposureChannel 1 (0019,"SPI-P Release 1",71) UN ExposureChannelFirstImage 1 (0019,"SPI-P Release 1",72) US ProcessingChannel 1 (0019,"SPI-P Release 1",80) DS AcquisitionDelay 1 (0019,"SPI-P Release 1",81) UN RelativeImageTime 1 (0019,"SPI-P Release 1",90) CS VideoWhiteCompression 1 (0019,"SPI-P Release 1",a0) US Angulation 1 (0019,"SPI-P Release 1",a1) US Rotation 1 (0021,"SPI-P Release 1",12) LT SeriesUniqueIdentifier 1 (0021,"SPI-P Release 1",14) LT Unknown 1 (0029,"SPI-P Release 1",00) DS Unknown 4 (0029,"SPI-P Release 1",20) DS PixelAspectRatio 1 (0029,"SPI-P Release 1",25) LO ProcessedPixelDataQuality 1-n (0029,"SPI-P Release 1",30) LT Unknown 1 (0029,"SPI-P Release 1",38) US Unknown 1 (0029,"SPI-P Release 1",60) LT Unknown 1 (0029,"SPI-P Release 1",61) LT Unknown 1 (0029,"SPI-P Release 1",67) LT Unknown 1 (0029,"SPI-P Release 1",70) LT WindowID 1 (0029,"SPI-P Release 1",71) CS VideoInvertSubtracted 1 (0029,"SPI-P Release 1",72) CS VideoInvertNonsubtracted 1 (0029,"SPI-P Release 1",77) CS WindowSelectStatus 1 (0029,"SPI-P Release 1",78) LT ECGDisplayPrintingID 1 (0029,"SPI-P Release 1",79) CS ECGDisplayPrinting 1 (0029,"SPI-P Release 1",7e) CS ECGDisplayPrintingEnableStatus 1 (0029,"SPI-P Release 1",7f) CS ECGDisplayPrintingSelectStatus 1 (0029,"SPI-P Release 1",80) LT PhysiologicalDisplayID 1 (0029,"SPI-P Release 1",81) US PreferredPhysiologicalChannelDisplay 1 (0029,"SPI-P Release 1",8e) CS PhysiologicalDisplayEnableStatus 1 (0029,"SPI-P Release 1",8f) CS PhysiologicalDisplaySelectStatus 1 (0029,"SPI-P Release 1",c0) LT FunctionalShutterID 1 (0029,"SPI-P Release 1",c1) US FieldOfShutter 1 (0029,"SPI-P Release 1",c5) LT FieldOfShutterRectangle 1 (0029,"SPI-P Release 1",ce) CS ShutterEnableStatus 1 (0029,"SPI-P Release 1",cf) CS ShutterSelectStatus 1 (7FE1,"SPI-P Release 1",10) ox PixelData 1 (0009,"SPI-P Release 1;1",c0) LT Unknown 1 (0009,"SPI-P Release 1;1",c1) LT Unknown 1 (0019,"SPI-P Release 1;1",00) UN PhysiologicalDataType 1 (0019,"SPI-P Release 1;1",01) UN PhysiologicalDataChannelAndKind 1 (0019,"SPI-P Release 1;1",02) US SampleBitsAllocated 1 (0019,"SPI-P Release 1;1",03) US SampleBitsStored 1 (0019,"SPI-P Release 1;1",04) US SampleHighBit 1 (0019,"SPI-P Release 1;1",05) US SampleRepresentation 1 (0019,"SPI-P Release 1;1",06) UN SmallestSampleValue 1 (0019,"SPI-P Release 1;1",07) UN LargestSampleValue 1 (0019,"SPI-P Release 1;1",08) UN NumberOfSamples 1 (0019,"SPI-P Release 1;1",09) UN SampleData 1 (0019,"SPI-P Release 1;1",0a) UN SampleRate 1 (0019,"SPI-P Release 1;1",10) UN PhysiologicalDataType2 1 (0019,"SPI-P Release 1;1",11) UN PhysiologicalDataChannelAndKind2 1 (0019,"SPI-P Release 1;1",12) US SampleBitsAllocated2 1 (0019,"SPI-P Release 1;1",13) US SampleBitsStored2 1 (0019,"SPI-P Release 1;1",14) US SampleHighBit2 1 (0019,"SPI-P Release 1;1",15) US SampleRepresentation2 1 (0019,"SPI-P Release 1;1",16) UN SmallestSampleValue2 1 (0019,"SPI-P Release 1;1",17) UN LargestSampleValue2 1 (0019,"SPI-P Release 1;1",18) UN NumberOfSamples2 1 (0019,"SPI-P Release 1;1",19) UN SampleData2 1 (0019,"SPI-P Release 1;1",1a) UN SampleRate2 1 (0029,"SPI-P Release 1;1",00) LT ZoomID 1 (0029,"SPI-P Release 1;1",01) DS ZoomRectangle 1-n (0029,"SPI-P Release 1;1",03) DS ZoomFactor 1 (0029,"SPI-P Release 1;1",04) US ZoomFunction 1 (0029,"SPI-P Release 1;1",0e) CS ZoomEnableStatus 1 (0029,"SPI-P Release 1;1",0f) CS ZoomSelectStatus 1 (0029,"SPI-P Release 1;1",40) LT MagnifyingGlassID 1 (0029,"SPI-P Release 1;1",41) DS MagnifyingGlassRectangle 1-n (0029,"SPI-P Release 1;1",43) DS MagnifyingGlassFactor 1 (0029,"SPI-P Release 1;1",44) US MagnifyingGlassFunction 1 (0029,"SPI-P Release 1;1",4e) CS MagnifyingGlassEnableStatus 1 (0029,"SPI-P Release 1;1",4f) CS MagnifyingGlassSelectStatus 1 (0029,"SPI-P Release 1;2",00) LT SubtractionMaskID 1 (0029,"SPI-P Release 1;2",04) UN MaskingFunction 1 (0029,"SPI-P Release 1;2",0c) UN ProprietaryMaskingParameters 1 (0029,"SPI-P Release 1;2",1e) CS SubtractionMaskEnableStatus 1 (0029,"SPI-P Release 1;2",1f) CS SubtractionMaskSelectStatus 1 (0029,"SPI-P Release 1;3",00) LT ImageEnhancementID 1 (0029,"SPI-P Release 1;3",01) LT ImageEnhancement 1 (0029,"SPI-P Release 1;3",02) LT ConvolutionID 1 (0029,"SPI-P Release 1;3",03) LT ConvolutionType 1 (0029,"SPI-P Release 1;3",04) LT ConvolutionKernelSizeID 1 (0029,"SPI-P Release 1;3",05) US ConvolutionKernelSize 2 (0029,"SPI-P Release 1;3",06) US ConvolutionKernel 1-n (0029,"SPI-P Release 1;3",0c) DS EnhancementGain 1 (0029,"SPI-P Release 1;3",1e) CS ImageEnhancementEnableStatus 1 (0029,"SPI-P Release 1;3",1f) CS ImageEnhancementSelectStatus 1 (0011,"SPI-P Release 2;1",18) LT Unknown 1 (0023,"SPI-P Release 2;1",0d) UI Unknown 1 (0023,"SPI-P Release 2;1",0e) UI Unknown 1 (0009,"SPI-P-GV-CT Release 1",00) LO Unknown 1 (0009,"SPI-P-GV-CT Release 1",10) LO Unknown 1 (0009,"SPI-P-GV-CT Release 1",20) LO Unknown 1 (0009,"SPI-P-GV-CT Release 1",30) LO Unknown 1 (0009,"SPI-P-GV-CT Release 1",40) LO Unknown 1 (0009,"SPI-P-GV-CT Release 1",50) LO Unknown 1 (0009,"SPI-P-GV-CT Release 1",60) LO Unknown 1 (0009,"SPI-P-GV-CT Release 1",70) LO Unknown 1 (0009,"SPI-P-GV-CT Release 1",75) LO Unknown 1 (0009,"SPI-P-GV-CT Release 1",80) LO Unknown 1 (0009,"SPI-P-GV-CT Release 1",90) LO Unknown 1 (0019,"SPI-P-GV-CT Release 1",08) IS Unknown 1 (0019,"SPI-P-GV-CT Release 1",09) IS Unknown 1 (0019,"SPI-P-GV-CT Release 1",0a) IS Unknown 1 (0019,"SPI-P-GV-CT Release 1",10) LO Unknown 1 (0019,"SPI-P-GV-CT Release 1",20) TM Unknown 1 (0019,"SPI-P-GV-CT Release 1",50) LO Unknown 1 (0019,"SPI-P-GV-CT Release 1",60) DS Unknown 1 (0019,"SPI-P-GV-CT Release 1",61) US Unknown 1 (0019,"SPI-P-GV-CT Release 1",63) LO Unknown 1 (0019,"SPI-P-GV-CT Release 1",64) US Unknown 1 (0019,"SPI-P-GV-CT Release 1",65) IS Unknown 1 (0019,"SPI-P-GV-CT Release 1",70) LT Unknown 1 (0019,"SPI-P-GV-CT Release 1",80) LO Unknown 1 (0019,"SPI-P-GV-CT Release 1",81) LO Unknown 1 (0019,"SPI-P-GV-CT Release 1",90) LO Unknown 1 (0019,"SPI-P-GV-CT Release 1",a0) LO Unknown 1 (0019,"SPI-P-GV-CT Release 1",a1) US Unknown 1 (0019,"SPI-P-GV-CT Release 1",a2) US Unknown 1 (0019,"SPI-P-GV-CT Release 1",a3) US Unknown 1 (0019,"SPI-P-GV-CT Release 1",b0) LO Unknown 1 (0019,"SPI-P-GV-CT Release 1",b1) LO Unknown 1 (0021,"SPI-P-GV-CT Release 1",20) LO Unknown 1 (0021,"SPI-P-GV-CT Release 1",30) DS Unknown 1 (0021,"SPI-P-GV-CT Release 1",40) LO Unknown 1 (0021,"SPI-P-GV-CT Release 1",50) LO Unknown 1 (0021,"SPI-P-GV-CT Release 1",60) DS Unknown 1 (0021,"SPI-P-GV-CT Release 1",70) DS Unknown 1 (0021,"SPI-P-GV-CT Release 1",80) DS Unknown 1 (0021,"SPI-P-GV-CT Release 1",90) DS Unknown 1 (0021,"SPI-P-GV-CT Release 1",a0) US Unknown 1 (0021,"SPI-P-GV-CT Release 1",a1) DS Unknown 1 (0021,"SPI-P-GV-CT Release 1",a2) DS Unknown 1 (0021,"SPI-P-GV-CT Release 1",a3) LT Unknown 1 (0021,"SPI-P-GV-CT Release 1",a4) LT Unknown 1 (0021,"SPI-P-GV-CT Release 1",b0) LO Unknown 1 (0021,"SPI-P-GV-CT Release 1",c0) LO Unknown 1 (0029,"SPI-P-GV-CT Release 1",10) LO Unknown 1 (0029,"SPI-P-GV-CT Release 1",30) UL Unknown 1 (0029,"SPI-P-GV-CT Release 1",31) UL Unknown 1 (0029,"SPI-P-GV-CT Release 1",32) UL Unknown 1 (0029,"SPI-P-GV-CT Release 1",33) UL Unknown 1 (0029,"SPI-P-GV-CT Release 1",80) LO Unknown 1 (0029,"SPI-P-GV-CT Release 1",90) LO Unknown 1 (0029,"SPI-P-GV-CT Release 1",d0) IS Unknown 1 (0029,"SPI-P-GV-CT Release 1",d1) IS Unknown 1 (0019,"SPI-P-PCR Release 2",30) US Unknown 1 (0021,"SPI-P-Private-CWS Release 1",00) LT WindowOfImagesID 1 (0021,"SPI-P-Private-CWS Release 1",01) CS WindowOfImagesType 1 (0021,"SPI-P-Private-CWS Release 1",02) IS WindowOfImagesScope 1-n (0019,"SPI-P-Private-DCI Release 1",10) UN ECGTimeMapDataBitsAllocated 1 (0019,"SPI-P-Private-DCI Release 1",11) UN ECGTimeMapDataBitsStored 1 (0019,"SPI-P-Private-DCI Release 1",12) UN ECGTimeMapDataHighBit 1 (0019,"SPI-P-Private-DCI Release 1",13) UN ECGTimeMapDataRepresentation 1 (0019,"SPI-P-Private-DCI Release 1",14) UN ECGTimeMapDataSmallestDataValue 1 (0019,"SPI-P-Private-DCI Release 1",15) UN ECGTimeMapDataLargestDataValue 1 (0019,"SPI-P-Private-DCI Release 1",16) UN ECGTimeMapDataNumberOfDataValues 1 (0019,"SPI-P-Private-DCI Release 1",17) UN ECGTimeMapData 1 (0021,"SPI-P-Private_CDS Release 1",40) IS Unknown 1 (0029,"SPI-P-Private_CDS Release 1",00) UN Unknown 1 (0019,"SPI-P-Private_ICS Release 1",30) DS Unknown 1 (0019,"SPI-P-Private_ICS Release 1",31) LO Unknown 1 (0029,"SPI-P-Private_ICS Release 1",08) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1",0f) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1",10) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1",1b) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1",1c) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1",21) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1",43) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1",44) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1",4C) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1",67) LO Unknown 1 (0029,"SPI-P-Private_ICS Release 1",68) US Unknown 1 (0029,"SPI-P-Private_ICS Release 1",6A) LO Unknown 1 (0029,"SPI-P-Private_ICS Release 1",6B) US Unknown 1 (0029,"SPI-P-Private_ICS Release 1;1",00) SL Unknown 1 (0029,"SPI-P-Private_ICS Release 1;1",05) FL Unknown 1 (0029,"SPI-P-Private_ICS Release 1;1",06) FL Unknown 1 (0029,"SPI-P-Private_ICS Release 1;1",20) FL Unknown 1 (0029,"SPI-P-Private_ICS Release 1;1",21) FL Unknown 1 (0029,"SPI-P-Private_ICS Release 1;1",CD) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1;2",00) FD Unknown 1 (0029,"SPI-P-Private_ICS Release 1;2",01) FD Unknown 1 (0029,"SPI-P-Private_ICS Release 1;2",02) FD Unknown 1 (0029,"SPI-P-Private_ICS Release 1;2",03) SL Unknown 1 (0029,"SPI-P-Private_ICS Release 1;2",04) SL Unknown 1 (0029,"SPI-P-Private_ICS Release 1;2",05) SL Unknown 1 (0029,"SPI-P-Private_ICS Release 1;3",C0) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1;3",C1) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1;3",C2) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1;3",C3) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1;3",C4) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1;3",C5) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1;4",02) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1;4",9A) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1;4",E0) SQ Unknown 1 (0029,"SPI-P-Private_ICS Release 1;5",50) CS Unknown 1 (0029,"SPI-P-Private_ICS Release 1;5",55) CS Unknown 1 (0019,"SPI-P-XSB-DCI Release 1",10) LT VideoBeamBoost 1 (0019,"SPI-P-XSB-DCI Release 1",11) US ChannelGeneratingVideoSync 1 (0019,"SPI-P-XSB-DCI Release 1",12) US VideoGain 1 (0019,"SPI-P-XSB-DCI Release 1",13) US VideoOffset 1 (0019,"SPI-P-XSB-DCI Release 1",20) DS RTDDataCompressionFactor 1 (0029,"Silhouette Annot V1.0",11) IS AnnotationName 1 (0029,"Silhouette Annot V1.0",12) LT AnnotationFont 1 (0029,"Silhouette Annot V1.0",13) LT AnnotationTextForegroundColor 1 (0029,"Silhouette Annot V1.0",14) LT AnnotationTextBackgroundColor 1 (0029,"Silhouette Annot V1.0",15) UL AnnotationTextBackingMode 1 (0029,"Silhouette Annot V1.0",16) UL AnnotationTextJustification 1 (0029,"Silhouette Annot V1.0",17) UL AnnotationTextLocation 1 (0029,"Silhouette Annot V1.0",18) LT AnnotationTextString 1 (0029,"Silhouette Annot V1.0",19) UL AnnotationTextAttachMode 1 (0029,"Silhouette Annot V1.0",20) UL AnnotationTextCursorMode 1 (0029,"Silhouette Annot V1.0",21) UL AnnotationTextShadowOffsetX 1 (0029,"Silhouette Annot V1.0",22) UL AnnotationTextShadowOffsetY 1 (0029,"Silhouette Annot V1.0",23) LT AnnotationLineColor 1 (0029,"Silhouette Annot V1.0",24) UL AnnotationLineThickness 1 (0029,"Silhouette Annot V1.0",25) UL AnnotationLineType 1 (0029,"Silhouette Annot V1.0",26) UL AnnotationLineStyle 1 (0029,"Silhouette Annot V1.0",27) UL AnnotationLineDashLength 1 (0029,"Silhouette Annot V1.0",28) UL AnnotationLineAttachMode 1 (0029,"Silhouette Annot V1.0",29) UL AnnotationLinePointCount 1 (0029,"Silhouette Annot V1.0",30) FD AnnotationLinePoints 1 (0029,"Silhouette Annot V1.0",31) UL AnnotationLineControlSize 1 (0029,"Silhouette Annot V1.0",32) LT AnnotationMarkerColor 1 (0029,"Silhouette Annot V1.0",33) UL AnnotationMarkerType 1 (0029,"Silhouette Annot V1.0",34) UL AnnotationMarkerSize 1 (0029,"Silhouette Annot V1.0",35) FD AnnotationMarkerLocation 1 (0029,"Silhouette Annot V1.0",36) UL AnnotationMarkerAttachMode 1 (0029,"Silhouette Annot V1.0",37) LT AnnotationGeomColor 1 (0029,"Silhouette Annot V1.0",38) UL AnnotationGeomThickness 1 (0029,"Silhouette Annot V1.0",39) UL AnnotationGeomLineStyle 1 (0029,"Silhouette Annot V1.0",40) UL AnnotationGeomDashLength 1 (0029,"Silhouette Annot V1.0",41) UL AnnotationGeomFillPattern 1 (0029,"Silhouette Annot V1.0",42) UL AnnotationInteractivity 1 (0029,"Silhouette Annot V1.0",43) FD AnnotationArrowLength 1 (0029,"Silhouette Annot V1.0",44) FD AnnotationArrowAngle 1 (0029,"Silhouette Annot V1.0",45) UL AnnotationDontSave 1 (0029,"Silhouette Graphics Export V1.0",00) UI Unknown 1 (0029,"Silhouette Line V1.0",11) IS LineName 1 (0029,"Silhouette Line V1.0",12) LT LineNameFont 1 (0029,"Silhouette Line V1.0",13) UL LineNameDisplay 1 (0029,"Silhouette Line V1.0",14) LT LineNormalColor 1 (0029,"Silhouette Line V1.0",15) UL LineType 1 (0029,"Silhouette Line V1.0",16) UL LineThickness 1 (0029,"Silhouette Line V1.0",17) UL LineStyle 1 (0029,"Silhouette Line V1.0",18) UL LineDashLength 1 (0029,"Silhouette Line V1.0",19) UL LineInteractivity 1 (0029,"Silhouette Line V1.0",20) LT LineMeasurementColor 1 (0029,"Silhouette Line V1.0",21) LT LineMeasurementFont 1 (0029,"Silhouette Line V1.0",22) UL LineMeasurementDashLength 1 (0029,"Silhouette Line V1.0",23) UL LinePointSpace 1 (0029,"Silhouette Line V1.0",24) FD LinePoints 1 (0029,"Silhouette Line V1.0",25) UL LineControlPointSize 1 (0029,"Silhouette Line V1.0",26) UL LineControlPointSpace 1 (0029,"Silhouette Line V1.0",27) FD LineControlPoints 1 (0029,"Silhouette Line V1.0",28) LT LineLabel 1 (0029,"Silhouette Line V1.0",29) UL LineDontSave 1 (0029,"Silhouette ROI V1.0",11) IS ROIName 1 (0029,"Silhouette ROI V1.0",12) LT ROINameFont 1 (0029,"Silhouette ROI V1.0",13) LT ROINormalColor 1 (0029,"Silhouette ROI V1.0",14) UL ROIFillPattern 1 (0029,"Silhouette ROI V1.0",15) UL ROIBpSeg 1 (0029,"Silhouette ROI V1.0",16) UN ROIBpSegPairs 1 (0029,"Silhouette ROI V1.0",17) UL ROISeedSpace 1 (0029,"Silhouette ROI V1.0",18) UN ROISeeds 1 (0029,"Silhouette ROI V1.0",19) UL ROILineThickness 1 (0029,"Silhouette ROI V1.0",20) UL ROILineStyle 1 (0029,"Silhouette ROI V1.0",21) UL ROILineDashLength 1 (0029,"Silhouette ROI V1.0",22) UL ROIInteractivity 1 (0029,"Silhouette ROI V1.0",23) UL ROINamePosition 1 (0029,"Silhouette ROI V1.0",24) UL ROINameDisplay 1 (0029,"Silhouette ROI V1.0",25) LT ROILabel 1 (0029,"Silhouette ROI V1.0",26) UL ROIShape 1 (0029,"Silhouette ROI V1.0",27) FD ROIShapeTilt 1 (0029,"Silhouette ROI V1.0",28) UL ROIShapePointsCount 1 (0029,"Silhouette ROI V1.0",29) UL ROIShapePointsSpace 1 (0029,"Silhouette ROI V1.0",30) FD ROIShapePoints 1 (0029,"Silhouette ROI V1.0",31) UL ROIShapeControlPointsCount 1 (0029,"Silhouette ROI V1.0",32) UL ROIShapeControlPointsSpace 1 (0029,"Silhouette ROI V1.0",33) FD ROIShapeControlPoints 1 (0029,"Silhouette ROI V1.0",34) UL ROIDontSave 1 (0029,"Silhouette Sequence Ids V1.0",41) SQ Unknown 1 (0029,"Silhouette Sequence Ids V1.0",42) SQ Unknown 1 (0029,"Silhouette Sequence Ids V1.0",43) SQ Unknown 1 (0029,"Silhouette V1.0",13) UL Unknown 1 (0029,"Silhouette V1.0",14) UL Unknown 1 (0029,"Silhouette V1.0",17) UN Unknown 1 (0029,"Silhouette V1.0",18) UN Unknown 1 (0029,"Silhouette V1.0",19) UL Unknown 1 (0029,"Silhouette V1.0",1a) UN Unknown 1 (0029,"Silhouette V1.0",1b) UL Unknown 1 (0029,"Silhouette V1.0",1c) UL Unknown 1 (0029,"Silhouette V1.0",1d) UN Unknown 1 (0029,"Silhouette V1.0",1e) UN Unknown 1 (0029,"Silhouette V1.0",21) US Unknown 1 (0029,"Silhouette V1.0",22) US Unknown 1 (0029,"Silhouette V1.0",23) US Unknown 1 (0029,"Silhouette V1.0",24) US Unknown 1 (0029,"Silhouette V1.0",25) US Unknown 1 (0029,"Silhouette V1.0",27) UN Unknown 1 (0029,"Silhouette V1.0",28) UN Unknown 1 (0029,"Silhouette V1.0",29) UN Unknown 1 (0029,"Silhouette V1.0",30) UN Unknown 1 (0029,"Silhouette V1.0",52) US Unknown 1 (0029,"Silhouette V1.0",53) LT Unknown 1 (0029,"Silhouette V1.0",54) UN Unknown 1 (0029,"Silhouette V1.0",55) LT Unknown 1 (0029,"Silhouette V1.0",56) LT Unknown 1 (0029,"Silhouette V1.0",57) UN Unknown 1 (0017,"SVISION",00) LO ExtendedBodyPart 1 (0017,"SVISION",10) LO ExtendedViewPosition 1 (0017,"SVISION",F0) IS ImagesSOPClass 1 (0019,"SVISION",00) IS AECField 1 (0019,"SVISION",01) IS AECFilmScreen 1 (0019,"SVISION",02) IS AECDensity 1 (0019,"SVISION",10) IS PatientThickness 1 (0019,"SVISION",18) IS BeamDistance 1 (0019,"SVISION",20) IS WorkstationNumber 1 (0019,"SVISION",28) IS TubeNumber 1 (0019,"SVISION",30) IS BuckyGrid 1 (0019,"SVISION",34) IS Focus 1 (0019,"SVISION",38) IS Child 1 (0019,"SVISION",40) IS CollimatorDistanceX 1 (0019,"SVISION",41) IS CollimatorDistanceY 1 (0019,"SVISION",50) IS CentralBeamHeight 1 (0019,"SVISION",60) IS BuckyAngle 1 (0019,"SVISION",68) IS CArmAngle 1 (0019,"SVISION",69) IS CollimatorAngle 1 (0019,"SVISION",70) IS FilterNumber 1 (0019,"SVISION",74) LO FilterMaterial1 1 (0019,"SVISION",75) LO FilterMaterial2 1 (0019,"SVISION",78) DS FilterThickness1 1 (0019,"SVISION",79) DS FilterThickness2 1 (0019,"SVISION",80) IS BuckyFormat 1 (0019,"SVISION",81) IS ObjectPosition 1 (0019,"SVISION",90) LO DeskCommand 1 (0019,"SVISION",A0) DS ExtendedExposureTime 1 (0019,"SVISION",A1) DS ActualExposureTime 1 (0019,"SVISION",A8) DS ExtendedXRayTubeCurrent 1 (0021,"SVISION",00) DS NoiseReduction 1 (0021,"SVISION",01) DS ContrastAmplification 1 (0021,"SVISION",02) DS EdgeContrastBoosting 1 (0021,"SVISION",03) DS LatitudeReduction 1 (0021,"SVISION",10) LO FindRangeAlgorithm 1 (0021,"SVISION",11) DS ThresholdCAlgorithm 1 (0021,"SVISION",20) LO SensometricCurve 1 (0021,"SVISION",30) DS LowerWindowOffset 1 (0021,"SVISION",31) DS UpperWindowOffset 1 (0021,"SVISION",40) DS MinPrintableDensity 1 (0021,"SVISION",41) DS MaxPrintableDensity 1 (0021,"SVISION",90) DS Brightness 1 (0021,"SVISION",91) DS Contrast 1 (0021,"SVISION",92) DS ShapeFactor 1 (0023,"SVISION",00) LO ImageLaterality 1 (0023,"SVISION",01) IS LetterPosition 1 (0023,"SVISION",02) IS BurnedInAnnotation 1 (0023,"SVISION",03) LO Unknown 1 (0023,"SVISION",F0) IS ImageSOPClass 1 (0025,"SVISION",00) IS OriginalImage 1 (0025,"SVISION",01) IS NotProcessedImage 1 (0025,"SVISION",02) IS CutOutImage 1 (0025,"SVISION",03) IS DuplicatedImage 1 (0025,"SVISION",04) IS StoredImage 1 (0025,"SVISION",05) IS RetrievedImage 1 (0025,"SVISION",06) IS RemoteImage 1 (0025,"SVISION",07) IS MediaStoredImage 1 (0025,"SVISION",08) IS ImageState 1 (0025,"SVISION",20) LO SourceImageFile 1 (0025,"SVISION",21) UI Unknown 1 (0027,"SVISION",00) IS NumberOfSeries 1 (0027,"SVISION",01) IS NumberOfStudies 1 (0027,"SVISION",10) DT OldestSeries 1 (0027,"SVISION",11) DT NewestSeries 1 (0027,"SVISION",12) DT OldestStudy 1 (0027,"SVISION",13) DT NewestStudy 1 (0009,"TOSHIBA_MEC_1.0",01) LT Unknown 1 (0009,"TOSHIBA_MEC_1.0",02) US Unknown 1-n (0009,"TOSHIBA_MEC_1.0",03) US Unknown 1-n (0009,"TOSHIBA_MEC_1.0",04) US Unknown 1-n (0011,"TOSHIBA_MEC_1.0",01) LT Unknown 1 (0011,"TOSHIBA_MEC_1.0",02) US Unknown 1-n (0019,"TOSHIBA_MEC_1.0",01) US Unknown 1-n (0019,"TOSHIBA_MEC_1.0",02) US Unknown 1-n (0021,"TOSHIBA_MEC_1.0",01) US Unknown 1-n (0021,"TOSHIBA_MEC_1.0",02) US Unknown 1-n (0021,"TOSHIBA_MEC_1.0",03) US Unknown 1-n (7ff1,"TOSHIBA_MEC_1.0",01) US Unknown 1-n (7ff1,"TOSHIBA_MEC_1.0",02) US Unknown 1-n (7ff1,"TOSHIBA_MEC_1.0",03) US Unknown 1-n (7ff1,"TOSHIBA_MEC_1.0",10) US Unknown 1-n (0019,"TOSHIBA_MEC_CT_1.0",01) IS Unknown 1 (0019,"TOSHIBA_MEC_CT_1.0",02) IS Unknown 1 (0019,"TOSHIBA_MEC_CT_1.0",03) US Unknown 1-n (0019,"TOSHIBA_MEC_CT_1.0",04) LT Unknown 1 (0019,"TOSHIBA_MEC_CT_1.0",05) LT Unknown 1 (0019,"TOSHIBA_MEC_CT_1.0",06) US Unknown 1-n (0019,"TOSHIBA_MEC_CT_1.0",07) US Unknown 1-n (0019,"TOSHIBA_MEC_CT_1.0",08) LT OrientationHeadFeet 1 (0019,"TOSHIBA_MEC_CT_1.0",09) LT ViewDirection 1 (0019,"TOSHIBA_MEC_CT_1.0",0a) LT OrientationSupineProne 1 (0019,"TOSHIBA_MEC_CT_1.0",0b) DS Unknown 1 (0019,"TOSHIBA_MEC_CT_1.0",0c) US Unknown 1-n (0019,"TOSHIBA_MEC_CT_1.0",0d) TM Time 1 (0019,"TOSHIBA_MEC_CT_1.0",0e) DS Unknown 1 (7ff1,"TOSHIBA_MEC_CT_1.0",01) US Unknown 1-n (7ff1,"TOSHIBA_MEC_CT_1.0",02) US Unknown 1-n (7ff1,"TOSHIBA_MEC_CT_1.0",03) IS Unknown 1 (7ff1,"TOSHIBA_MEC_CT_1.0",04) IS Unknown 1 (7ff1,"TOSHIBA_MEC_CT_1.0",05) US Unknown 1-n (7ff1,"TOSHIBA_MEC_CT_1.0",07) US Unknown 1-n (7ff1,"TOSHIBA_MEC_CT_1.0",08) US Unknown 1-n (7ff1,"TOSHIBA_MEC_CT_1.0",09) US Unknown 1-n (7ff1,"TOSHIBA_MEC_CT_1.0",0a) LT Unknown 1 (7ff1,"TOSHIBA_MEC_CT_1.0",0b) US Unknown 1-n (7ff1,"TOSHIBA_MEC_CT_1.0",0c) US Unknown 1-n (7ff1,"TOSHIBA_MEC_CT_1.0",0d) US Unknown 1-n # # end of private.dic # plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dicom_probe.cxx000066400000000000000000000023251321604176500305410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "dicom_probe.h" #if PLM_DCM_USE_DCMTK #include "dcmtk_rtdose.h" #include "dcmtk_rtss.h" #include "dcmtk_rtplan.h" #elif PLM_DCM_USE_GDCM1 #include "gdcm1_dose.h" #include "gdcm1_rtss.h" #else /* Nothing */ #endif #include "make_string.h" /* Return true if the file is a dicom rtstruct */ bool dicom_probe_rtss (const char *rtss_fn) { #if PLM_DCM_USE_DCMTK return dcmtk_rtss_probe (rtss_fn); #elif PLM_DCM_USE_GDCM1 return gdcm_rtss_probe (rtss_fn); #else return false; #endif } /* Return true if the file is a dicom rt dose */ bool dicom_probe_dose (const char *fn) { #if PLM_DCM_USE_DCMTK return dcmtk_dose_probe (fn); #elif PLM_DCM_USE_GDCM1 return gdcm1_dose_probe (fn); #else return false; #endif } /* Return true if the file is a dicom rtplan */ bool dicom_probe_rtplan(const char *rtplan_fn) { #if PLM_DCM_USE_DCMTK return dcmtk_rtplan_probe(rtplan_fn); #elif PLM_DCM_USE_GDCM1 return false; #else return false; #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dicom_probe.h000066400000000000000000000007351321604176500301710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcm_probe_h_ #define _dcm_probe_h_ #include "plmbase_config.h" PLMBASE_C_API bool dicom_probe_dose (const char *fn); PLMBASE_C_API bool dicom_probe_rtss (const char *fn); PLMBASE_C_API bool dicom_probe_rtplan(const char *fn); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dicom_util.cxx000066400000000000000000000034101321604176500304030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "dicom_util.h" #include "make_string.h" #if PLM_DCM_USE_DCMTK #include "dcmtk_rdd.h" #include "dcmtk_uid.h" #include "dcmtk_util.h" #elif PLM_DCM_USE_GDCM1 #include "gdcm1_rdd.h" #include "gdcm1_util.h" #else #include "gdcm2_util.h" #endif #include "plm_uid_prefix.h" void dicom_get_date_time ( std::string *date, std::string *time ) { #if PLM_DCM_USE_DCMTK dcmtk_get_date_time (date, time); #elif PLM_DCM_USE_GDCM1 gdcm1_get_date_time (date, time); #else gdcm2_get_date_time (date, time); #endif } std::string dicom_anon_patient_id (void) { int i; unsigned char uuid[16]; std::string patient_id = "PL"; srand (time (0)); for (i = 0; i < 16; i++) { int r = (int) (10.0 * rand() / RAND_MAX); uuid[i] = '0' + r; } uuid [15] = '\0'; patient_id = patient_id + make_string (uuid); return patient_id; } void dicom_load_rdd (Rt_study_metadata::Pointer rsm, const char* dicom_dir) { #if PLM_DCM_USE_DCMTK dcmtk_load_rdd (rsm, dicom_dir); #elif PLM_DCM_USE_GDCM1 gdcm1_load_rdd (rsm.get(), dicom_dir); #else /* Do nothing */ #endif } char* dicom_uid (char *uid, const char *uid_root) { #if PLM_DCM_USE_DCMTK return dcmtk_uid (uid, uid_root); #else return gdcm_uid (uid, uid_root); #endif } std::string dicom_uid (const char *uid_root) { char uid[100]; dicom_uid (uid, uid_root); return std::string (uid); } std::string dicom_uid () { return dicom_uid (PLM_UID_PREFIX); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/dicom_util.h000066400000000000000000000013651321604176500300370ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dcm_util_h_ #define _dcm_util_h_ #include "plmbase_config.h" #include #include "rt_study_metadata.h" class Rt_study_metadata; std::string dicom_anon_patient_id (void); void dicom_load_rdd (Rt_study_metadata::Pointer rsm, const char* dicom_dir); PLMBASE_C_API void dicom_get_date_time ( std::string *date, std::string *time ); PLMBASE_C_API char* dicom_uid (char *uid, const char *uid_root); PLMBASE_API std::string dicom_uid (const char *uid_root); PLMBASE_API std::string dicom_uid (); #endif direction_cosines.cxx000066400000000000000000000153521321604176500317070ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "direction_cosines.h" #include "itk_image.h" #include "plm_math.h" #include "print_and_exit.h" #include "string_util.h" #define DIRECTION_COSINES_IDENTITY_THRESH 1e-9 class Direction_cosines_private { public: float direction_matrix[9]; float inv_direction_matrix[9]; }; Direction_cosines::Direction_cosines () { this->d_ptr = new Direction_cosines_private; this->set_identity (); } Direction_cosines::Direction_cosines (const float *dm) { this->d_ptr = new Direction_cosines_private; this->set (dm); } Direction_cosines::Direction_cosines (const DirectionType& itk_dc) { this->d_ptr = new Direction_cosines_private; this->set (itk_dc); } Direction_cosines::~Direction_cosines () { delete this->d_ptr; } Direction_cosines::operator const float* () const { return d_ptr->direction_matrix; } Direction_cosines::operator float* () { return d_ptr->direction_matrix; } bool Direction_cosines::operator==(const Direction_cosines& dc) const { for (int i = 0; i < 9; i++) { float diff = fabs(this->d_ptr->direction_matrix[i] - dc.d_ptr->direction_matrix[i]); if (diff > DIRECTION_COSINES_EQUALITY_THRESH) { return false; } } return true; } void Direction_cosines::set_identity () { d_ptr->direction_matrix[0] = 1.; d_ptr->direction_matrix[1] = 0.; d_ptr->direction_matrix[2] = 0.; d_ptr->direction_matrix[3] = 0.; d_ptr->direction_matrix[4] = 1.; d_ptr->direction_matrix[5] = 0.; d_ptr->direction_matrix[6] = 0.; d_ptr->direction_matrix[7] = 0.; d_ptr->direction_matrix[8] = 1.; solve_inverse (); } void Direction_cosines::set_rotated_1 () { d_ptr->direction_matrix[0] = 0.894427190999916; d_ptr->direction_matrix[1] = 0.447213595499958; d_ptr->direction_matrix[2] = 0.; d_ptr->direction_matrix[3] = -0.447213595499958; d_ptr->direction_matrix[4] = 0.894427190999916; d_ptr->direction_matrix[5] = 0.; d_ptr->direction_matrix[6] = 0.; d_ptr->direction_matrix[7] = 0.; d_ptr->direction_matrix[8] = 1.; solve_inverse (); } void Direction_cosines::set_rotated_2 () { d_ptr->direction_matrix[0] = M_SQRT1_2; d_ptr->direction_matrix[1] = -M_SQRT1_2; d_ptr->direction_matrix[2] = 0.; d_ptr->direction_matrix[3] = M_SQRT1_2; d_ptr->direction_matrix[4] = M_SQRT1_2; d_ptr->direction_matrix[5] = 0.; d_ptr->direction_matrix[6] = 0.; d_ptr->direction_matrix[7] = 0.; d_ptr->direction_matrix[8] = 1.; solve_inverse (); } void Direction_cosines::set_rotated_3 () { d_ptr->direction_matrix[0] = -0.855063803257865; d_ptr->direction_matrix[1] = 0.498361271551590; d_ptr->direction_matrix[2] = -0.143184969098287; d_ptr->direction_matrix[3] = -0.428158353951640; d_ptr->direction_matrix[4] = -0.834358655093045; d_ptr->direction_matrix[5] = -0.347168631377818; d_ptr->direction_matrix[6] = -0.292483018822660; d_ptr->direction_matrix[7] = -0.235545489638006; d_ptr->direction_matrix[8] = 0.926807426605751; solve_inverse (); } void Direction_cosines::set_skewed () { d_ptr->direction_matrix[0] = 1.; d_ptr->direction_matrix[1] = 0.; d_ptr->direction_matrix[2] = 0.; d_ptr->direction_matrix[3] = M_SQRT1_2; d_ptr->direction_matrix[4] = M_SQRT1_2; d_ptr->direction_matrix[5] = 0.; d_ptr->direction_matrix[6] = 0.; d_ptr->direction_matrix[7] = 0.; d_ptr->direction_matrix[8] = 1.; solve_inverse (); } static void volume_matrix3x3inverse (float *out, const float *m) { float det; det = m[0]*(m[4]*m[8]-m[5]*m[7]) -m[1]*(m[3]*m[8]-m[5]*m[6]) +m[2]*(m[3]*m[7]-m[4]*m[6]); if (fabs(det)<1e-8) { print_and_exit ("Error: singular matrix of direction cosines\n"); } out[0]= (m[4]*m[8]-m[5]*m[7]) / det; out[1]= -(m[1]*m[8]-m[2]*m[7]) / det; out[2]= (m[1]*m[5]-m[2]*m[4]) / det; out[3]= -(m[3]*m[8]-m[5]*m[6]) / det; out[4]= (m[0]*m[8]-m[2]*m[6]) / det; out[5]= -(m[0]*m[5]-m[2]*m[3]) / det; out[6]= (m[3]*m[7]-m[4]*m[6]) / det; out[7]= -(m[0]*m[7]-m[1]*m[6]) / det; out[8]= (m[0]*m[4]-m[1]*m[3]) / det; } void Direction_cosines::solve_inverse () { volume_matrix3x3inverse (d_ptr->inv_direction_matrix, d_ptr->direction_matrix); } void Direction_cosines::set (const float dc[]) { for (int i = 0; i < 9; i++) { d_ptr->direction_matrix[i] = dc[i]; } solve_inverse (); } void Direction_cosines::set (const DirectionType& itk_dc) { for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { d_ptr->direction_matrix[d1*3+d2] = itk_dc[d1][d2]; } } solve_inverse (); } const float * Direction_cosines::get_matrix () const { return d_ptr->direction_matrix; } float * Direction_cosines::get_matrix () { return d_ptr->direction_matrix; } const float * Direction_cosines::get_inverse () const { return d_ptr->inv_direction_matrix; } bool Direction_cosines::set_from_string (std::string& str) { float dc[9]; int rc; /* First check presets */ if (str == "identity") { this->set_identity (); return true; } else if (str == "rotated-1") { this->set_rotated_1 (); return true; } else if (str == "rotated-2") { this->set_rotated_2 (); return true; } else if (str == "rotated-3") { this->set_rotated_3 (); return true; } else if (str == "skewed") { this->set_skewed (); return true; } /* Not a preset, must be 9 digit string */ rc = sscanf (str.c_str(), "%g %g %g %g %g %g %g %g %g", &dc[0], &dc[1], &dc[2], &dc[3], &dc[4], &dc[5], &dc[6], &dc[7], &dc[8]); if (rc != 9) { return false; } this->set (dc); return true; } bool Direction_cosines::is_identity () { Direction_cosines id; float frob = 0.; for (int i = 0; i < 9; i++) { frob += fabs ( d_ptr->direction_matrix[i] - id.d_ptr->direction_matrix[i]); } return frob < DIRECTION_COSINES_IDENTITY_THRESH; } std::string Direction_cosines::get_string () const { std::string s = string_format ("%g %g %g %g %g %g %g %g %g", d_ptr->direction_matrix[0], d_ptr->direction_matrix[1], d_ptr->direction_matrix[2], d_ptr->direction_matrix[3], d_ptr->direction_matrix[4], d_ptr->direction_matrix[5], d_ptr->direction_matrix[6], d_ptr->direction_matrix[7], d_ptr->direction_matrix[8]); return s; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/direction_cosines.h000066400000000000000000000031231321604176500314040ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _direction_cosines_h_ #define _direction_cosines_h_ #include "plmbase_config.h" #include #include #include "plm_math.h" #define DIRECTION_COSINES_IDENTITY_THRESH 1e-9 #define DIRECTION_COSINES_EQUALITY_THRESH 1e-9 namespace itk { template class Matrix; } typedef itk::Matrix < double, 3, 3 > DirectionType; class Direction_cosines_private; class PLMBASE_API Direction_cosines { public: Direction_cosines_private *d_ptr; public: Direction_cosines (); Direction_cosines (const float *dm); Direction_cosines (const DirectionType& itk_dc); ~Direction_cosines (); public: operator const float* () const; operator float* (); bool operator==(const Direction_cosines& dc) const; public: void set_identity (); /* Presets */ void set_rotated_1 (); void set_rotated_2 (); void set_rotated_3 (); void set_skewed (); const float* get_matrix () const; float* get_matrix (); const float* get_inverse () const; void set (const float dc[]); void set (const DirectionType& itk_dc); bool set_from_string (std::string& str); bool is_identity (); std::string get_string () const; protected: void solve_inverse (); private: Direction_cosines (const Direction_cosines&); void operator= (const Direction_cosines&); }; #endif direction_matrices.cxx000066400000000000000000000012111321604176500320400ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "direction_cosines.h" #include "direction_matrices.h" void compute_direction_matrices (float *step, float *proj, const Direction_cosines& dc, const float *spacing) { const float* inv_dc = dc.get_inverse (); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { step[3*i+j] = dc[3*i+j] * spacing[j]; proj[3*i+j] = inv_dc[3*i+j] / spacing[i]; } } } direction_matrices.h000066400000000000000000000007421321604176500314750ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _direction_matrices_h_ #define _direction_matrices_h_ #include "plmbase_config.h" class Direction_cosines; PLMBASE_API void compute_direction_matrices (float *step, float *proj, const Direction_cosines& dc, const float *spacing); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/exchkeys.cxx000066400000000000000000000001651321604176500301020ustar00rootroot00000000000000/* Define RTOG parsing structure */ #include "plmbase_config.h" #define DEFINE_RTOG_STRINGS 1 #include "exchkeys.h" plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/exchkeys.h000066400000000000000000000317621321604176500275360ustar00rootroot00000000000000/* GCS - Adapted from exchkeys.h http://itc.wustl.edu/Exchcode.html http://itc.wustl.edu/exchange_files/tapeexch400.htm */ /*********************************************************************** * $Id: exchkeys.h,v 1.2 2000/01/18 20:07:09 jwm Exp $ * Description: include file for RTOG submission * *********************************************************************** * $Log: exchkeys.h,v $ * Revision 1.2 2000/01/18 20:07:09 jwm * Correct comment * * Revision 1.1 2000/01/14 22:49:16 jwm * Remove comments originating in other development trees * * Revision 1.0 2000/01/14 22:42:38 jwm * Initial revision **********************************************************************/ /*********************************************************************** Description: This file contains the definitions of the keyword and keyvalues required to support patient data exchange as specified in: Specifications for Tape Format for Exchange of Treatment Planning Information based on AAPM Report #10 as used and modified by The NCI Particle Intercomparison Contract The NCI High Energy Photon External Beam Treatment Planning Contract The NCI Electron External Beam Treatment Planning Contract and The RTOG 3D QA Center Version 4.00 Wm. B. Harms, Sr. RTOG 3D QA Center Radiation Oncology Center Mallinckrodt Institute of Radiology Washington University School of Medicine 510 South Kingshighway Blvd. St. Louis, MO 63110 *********************************************************************/ /* NUMBER OF CURRENTLY SUPPORTED (AND DEFINED) KEYWORDS */ #define RTOG_NUM_KEYS 119 /* NUMBER OF CURRENTLY SUPPORTED (AND DEFINED) KEY VALUES */ #define RTOG_NUM_KEY_VALS 70 /* GCS: Deleted the rather useless "key_list" and "key_value" lists */ /*********************************************************************** key_list, key_list_words AND key_type MUST MAINTAIN A 1-1 CORRESPONDENCE. WHEN YOU ADD SOMETHING TO key_list, YOU MUST ADD A CORRESPONDING ENUM VALUE IN key_type AT THE SAME LOCATION IN THE LIST SIMILARLY, key_value, key_value_words AND key_value_type MUST MAINTAIN A 1-1 CORRESPONDENCE. WHILE IT IS NOT GOOD PROGRAMMING STYLE TO ALLOCATE MEMORY IN HEADER FILES, IT WAS THE SIMPLEST SOLUTION TO THE LARGE AMOUNT OF DEFINITIONS REQUIRED FOR THE TAPE EXCHANGE (KEYWORDS AND VALUES). THEREFORE, A VALUE IS DEFINED CALLED "NOT_MAIN" WHICH MUST BE DEFINED IN ALL SOURCE CODE FILES WHICH DO NOT CONTAIN THE main() ROUTINE. THIS SHOULD NOT BE DEFINED FOR THE main() MODULE(S) ***********************************************************************/ /* GCS Simplify the above, so that you don't define anything unless you want to define the structures */ #if defined (DEFINE_RTOG_STRINGS) char *key_list_words[RTOG_NUM_KEYS] = { /* THIS ARRAY OF STRINGS MUST MAINTAIN A 1-1 CORRESPONDENCE WITH THE key_type ENUM AS THEY ARE REFERENCED USING THIS ENUM. IT CONTAINS THE EXACT STRING (ENGLISH) REPRESENTATIONS USED FOR OUTPUT OF THE DIRECTORY FILE. */ /********* 0 through 9 ***********************/ "TAPE STANDARD #", "INTERCOMPARISON STANDARD #", "INSTITUTION", "DATE CREATED", "WRITER", "IMAGE #", "IMAGE TYPE", "CASE #", "PATIENT NAME", "DATE WRITTEN", /********* 10 through 19 ***********************/ "UNIT #", "FILE OF ORIGIN", "COMMENT DESCRIPTION", "SCAN TYPE", "CT OFFSET", "GRID 1 UNITS", "GRID 2 UNITS", "NUMBER REPRESENTATION", "BYTES PER PIXEL", "NUMBER OF DIMENSIONS", /********* 20 through 29 ***********************/ "SIZE OF DIMENSION 1", "SIZE OF DIMENSION 2", "Z VALUE", "X OFFSET", "Y OFFSET", "CT-AIR", "CT-WATER", "SITE OF INTEREST", "SCAN DESCRIPTION", "SCANNER TYPE", /********* 30 through 39 ***********************/ "HEAD IN/OUT", "POSITION IN SCAN", "PATIENT ATTITUDE", "TAPE OF ORIGIN", "SCAN ID", "SCAN#", "SCAN DATE", "SCAN FILE NAME", "SLICE THICKNESS", "CT SCALE", /********* 40 through 49 ***********************/ "DISTRUST ABOVE", "STRUCTURE NAME", "STRUCTURE FORMAT", "NUMBER OF SCANS", "MAXIMUM # SCANS", "MAXIMUM POINTS PER SEGMENT", "MAXIMUM SEGMENTS PER SCAN", "STRUCTURE EDITION", "STRUCTURE COLOR", "STRUCTURE DESCRIPTION", /********* 50 through 59 ***********************/ "STUDY NUMBER OF ORIGIN", /* Fixed, GCS */ "ORIENTATION OF STRUCTURE", "DOSE #", "DOSE TYPE", "DOSE UNITS", "ORIENTATION OF DOSE", "SIZE OF DIMENSION 3", "COORD 1 OF FIRST POINT", "COORD 2 OF FIRST POINT", "HORIZONTAL GRID INTERVAL", /********* 60 through 69 ***********************/ "VERTICAL GRID INTERVAL", "DOSE DESCRIPTION", "DOSE EDITION", "PLAN # OF ORIGIN", "PLAN EDITION OF ORIGIN", "VERSION # OF PROGRAM", "XCOORD OF NORMALIZN POINT", "YCOORD OF NORMALIZN POINT", "ZCOORD OF NORMALIZN POINT", "DOSE AT NORMALIZN POINT", /********* 70 through 79 ***********************/ "DOSE ERROR", "BEAM #", "BEAM MODALITY", "BEAM ENERGY(MEV)", "BEAM DESCRIPTION", "RX DOSE PER TX (GY)", "NUMBER OF TX", "FRACTION GROUP ID", "BEAM TYPE", "PLAN ID OF ORIGIN", /********* 80 through 89 ***********************/ "COLLIMATOR TYPE", "APERTURE TYPE", "APERTURE DESCRIPTION", "COLLIMATOR ANGLE", "GANTRY ANGLE", "COUCH ANGLE", "NOMINAL ISOCENTER DIST", "APERTURE ID", "WEDGE ANGLE", "WEDGE ROTATION ANGLE", /********* 90 through 99 ***********************/ "ARC ANGLE", "COMPENSATOR", "VOLUME TYPE", "NUMBER OF PAIRS", "MAXIMUM # PAIRS", "DATE OF DVH", "DOSE SCALE", "VOLUME SCALE", "NUMBER OF FRACTIONS", "FILM NUMBER", /********* 100 through 109 ***********************/ "FILM DATE", "FILM TYPE", "SOURCE IMAGE DISTANCE", "FILM DESCRIPTION", "FILM SOURCE", "OD SCALE", "BITS PER PIXEL", "DOSE VOLUME HISTOGRAM", "SEED MODEL", "ISOTOPE", /********* 110 through 116 ***********************/ "SEED STRENGTH", "STRENGTH UNITS", "DATE OF IMPLANT", "NUMBER OF SEEDS", "IMAGE SOURCE", "PIXEL OFFSET", "UNDEFINEDKEY", "COORD 3 OF FIRST POINT", /* GCS */ "DEPTH GRID INTERVAL" /* GCS */ }; char *key_value_words[RTOG_NUM_KEY_VALS] = { /* THIS ARRAY OF STRINGS MUST MAINTAIN A 1-1 CORRESPONDENCE WITH THE key_value_type ENUM AS THEY ARE REFERENCED USING THIS ENUM. IT CONTAINS THE EXACT STRING REPRESENTATIONS USED FOR OUTPUT OF THE DIRECTORY FILE. */ /*********** 0 through 9 *************************/ "COMMENT", "CT SCAN", "MRI", "ULTRASOUND", "STRUCTURE", "BEAM GEOMETRY", "DIGITAL FILM", "DOSE", "DOSE VOLUME HISTOGRAM", "SEED GEOMETRY", /*********** 10 through 19 *************************/ "TRANSVERSE", "SAGITTAL", "CORONAL", "TWO'S COMPLEMENT INTEGER", "CHARACTER", "IN", "OUT", "NOSE UP", "NOSE DOWN", "LEFT SIDE DOWN", /*********** 20 through 39 *************************/ "RIGHT SIDE DOWN", "SCAN-BASED", "NOMINAL", "MINIMUM", "MAXIMUM", "PHYSICAL", "EFFECTIVE", "LET", "OER", "ERROR", /*********** 30 through 39 *************************/ "GRAYS", "RADS", "CGYS", "PERCENT", "RELATIVE", "ABSOLUTE", "CGE", "SIMULATOR", "DRR", "PORT", /*********** 40 through 49 *************************/ "UNSIGNED BYTE", "X-RAY", "ELECTRON", "NEUTRON", "PROTON", "OTHER", "COLLIMATOR", "BLOCK", "MLC_X", "MLC_Y", /*********** 50 through 59 *************************/ "MLC_XY", "STATIC", "ARC", "SYMMETRIC", "ASYMMETRIC", "ASYMMETRIC_X", "ASYMMETRIC_Y", "NONE", "1D-X", "1D-Y", /*********** 60 through 69 *************************/ "2D", "3D", "FILM", "ONLINE", "COMPUTED", "I125", "PD103", "MCI", "CGYCM2PERHR", "SECONDARY CAPTURE" }; #endif /* SINCE THIS IS NOT BEING INCLUDED IN main(), DEFINE THE EXTERNAL REFERENCE. */ extern char *key_value[]; extern char *key_list[]; extern char *key_value_words[]; extern char *key_list_words[]; /* THE ENUM'S ARE NEEDED EVERYWHERE */ typedef enum { /* THIS ENUM MUST MAINTAIN A 1-1 CORESPONDENCE WITH THE key_value AND key_list STRING ARRAYS AS THE STRINGS ARE GENERALLY REFERENCED VIA THE VALUE OF THE ENUM */ /********* 0 through 9 ***********************/ ekTAPESTANDARDNUMBER, ekINTERCOMPARISONSTANDARDNUMBER, ekINSTITUTION, ekDATECREATED, ekWRITER, ekIMAGENUMBER, ekIMAGETYPE, ekCASENUMBER, ekPATIENTNAME, ekDATEWRITTEN, /********* 10 through 19 ***********************/ ekUNITNUMBER, ekFILEOFORIGIN, ekCOMMENTDESCRIPTION, ekSCANTYPE, ekCTOFFSET, ekGRID1UNITS, ekGRID2UNITS, ekNUMBERREPRESENTATION, ekBYTESPERPIXEL, ekNUMBEROFDIMENSIONS, /********* 20 through 29 ***********************/ ekSIZEOFDIMENSION1, ekSIZEOFDIMENSION2, ekZVALUE, ekXOFFSET, ekYOFFSET, ekCTAIR, ekCTWATER, ekSITEOFINTEREST, ekSCANDESCRIPTION, ekSCANNERTYPE, /********* 30 through 39 ***********************/ ekHEADIN, ekPOSITIONINSCAN, ekPATIENTATTITUDE, ekTAPEOFORIGIN, ekSCANID, ekSCANNUMBER, ekSCANDATE, ekSCANFILENAME, ekSLICETHICKNESS, ekCTSCALE, /********* 40 through 49 ***********************/ ekDISTRUSTABOVE, ekSTRUCTURENAME, ekSTRUCTUREFORMAT, ekNUMBEROFSCANS, ekMAXIMUMNUMBERSCANS, ekMAXIMUMPOINTSPERSEGMENT, ekMAXIMUMSEGMENTSPERSCAN, ekSTRUCTUREEDITION, ekSTRUCTURECOLOR, ekSTRUCTUREDESCRIPTION, /********* 50 through 59 ***********************/ ekSTUDYNUMBEROFORIGIN, ekORIENTATIONOFSTRUCTURE, ekDOSENUMBER, ekDOSETYPE, ekDOSEUNITS, ekORIENTATIONOFDOSE, ekSIZEOFDIMENSION3, ekCOORD1OFFIRSTPOINT, ekCOORD2OFFIRSTPOINT, ekHORIZONTALGRIDINTERVAL, /********* 60 through 69 ***********************/ ekVERTICALGRIDINTERVAL, ekDOSEDESCRIPTION, ekDOSEEDITION, ekPLANNUMBEROFORIGIN, ekPLANEDITIONOFORIGIN, ekVERSIONNUMBEROFPROGRAM, ekXCOORDOFNORMALIZNPOINT, ekYCOORDOFNORMALIZNPOINT, ekZCOORDOFNORMALIZNPOINT, ekDOSEATNORMALIZNPOINT, /********* 70 through 79 ***********************/ ekDOSEERROR, ekBEAMNUMBER, ekBEAMMODALITY, ekBEAMENERGYMEV, ekBEAMDESCRIPTION, ekRXDOSEPERTXGY, ekNUMBEROFTX, ekFRACTIONGROUPID, ekBEAMTYPE, ekPLANIDOFORIGIN, /********* 80 through 89 ***********************/ ekCOLLIMATORTYPE, ekAPERTURETYPE, ekAPERTUREDESCRIPTION, ekCOLLIMATORANGLE, ekGANTRYANGLE, ekCOUCHANGLE, ekNOMINALISOCENTERDIST, ekAPERTUREID, ekWEDGEANGLE, ekWEDGEROTATIONANGLE, /********* 90 through 99 ***********************/ ekARCANGLE, ekCOMPENSATOR, ekVOLUMETYPE, ekNUMBEROFPAIRS, ekMAXIMUMNUMBERPAIRS, ekDATEOFDVH, ekDOSESCALE, ekVOLUMESCALE, ekNUMBEROFFRACTIONS, ekFILMNUMBER, /********* 100 through 109 ***********************/ ekFILMDATE, ekFILMTYPE, ekSOURCEIMAGEDISTANCE, ekFILMDESCRIPTION, ekFILMSOURCE, ekODSCALE, ekBITSPERPIXEL, ekDOSEVOLUMEHISTOGRAM, ekSEEDMODEL, ekSEEDISOTOPE, /********* 110 through 116 ***********************/ ekSEEDSTRENGTH, ekSEEDSTRENGTHUNITS, ekDATEOFIMPLANT, ekNUMBEROFSEEDS, ekIMAGESOURCE, ekPIXELOFFSET, ekUNDEFINEDKEY, ekCOORD3OFFIRSTPOINT, ekDEPTHGRIDINTERVAL } key_type; typedef enum { /* THIS ENUM MUST MAINTAIN A 1-1 CORRESPONDENCE WITH THE key_value AND key_value_words STRING ARRAYS AS THE STRINGS ARE GENERALLY REFERENCED VIA THE VALUE OF THE ENUM */ /*********** 0 through 9 *************************/ evCOMMENT, evCTSCAN, evMRSCAN, evULTRASOUND, evSTRUCTURE, evBEAMGEOMETRY, evDIGITALFILM, evDOSE, evDOSEVOLUMEHISTOGRAM, evSEEDGEOMETRY, /*********** 10 through 19 *************************/ evTRANSVERSE, evSAGITTAL, evCORONAL, evTWOSCOMP, evCHARACTER, evIN, evOUT, evNOSEUP, evNOSEDOWN, evLEFTSIDEDOWN, /*********** 20 through 39 *************************/ evRIGHTSIDEDOWN, evSCANBASED, evNOMINAL, evMINIMUM, evMAXIMUM, evPHYSICAL, evEFFECTIVE, evLET, evOER, evERROR, /*********** 30 through 39 *************************/ evGRAYS, evRADS, evCGYS, evPERCENT, evRELATIVE, evABSOLUTE, evCGE, evSIMULATOR, evDRR, evPORT, /*********** 40 through 49 *************************/ evUNSIGNEDBYTE, evXRAY, evELECTRON, evNEUTRON, evPROTON, evOTHER, evCOLLIMATOR, evBLOCK, evMLC_X, evMLC_Y, /*********** 50 through 59 *************************/ evMLC_XY, evSTATIC, evARC, evSYMMETRIC, evASYMMETRIC, evASYMMETRIC_X, evASYMMETRIC_Y, evNONE, ev1D_X, ev1D_Y, /*********** 60 through 69 *************************/ ev2D, ev3D, evFILM, evONLINE, evCOMPUTED, evI125, evPD103, evMCI, evCGYCM2PERHR, evSECONDARYCAPTURE } key_value_type; typedef enum { /* THESE ARE THE DATA TYPES SUPPORTED BY THE aapm_entry ROUTINE FOR FORMATTING AND RECORDING A KEYWORD/KEYVALUE COMBINATION IN A BUFFERED AAPM FILE DATA BLOCK */ aSTRING, aINT, aFLOAT } key_data_type; /******************************** End of exchkeys.h *************************/ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/float_pair_list.cxx000066400000000000000000000032151321604176500314310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include "float_pair_list.h" #include "plm_math.h" #include "string_util.h" static void get_next_number (int& rc, float& f, const char*& c) { int n; /* Skip whitespace */ while (isspace(*c)) ++c; if (string_starts_with (c, "inf")) { rc = 1; f = std::numeric_limits::max(); c += 3; } else if (string_starts_with (c, "-inf")) { rc = 1; f = -std::numeric_limits::max(); c += 4; } else { rc = sscanf (c, "%f%n", &f, &n); if (rc >= 1) { c += n; } } /* Skip whitespace */ while (isspace(*c)) ++c; /* Skip trailing comma */ while (*c == ',') ++c; } Float_pair_list parse_float_pairs (const std::string& s) { Float_pair_list al; const char* c = s.c_str(); while (1) { int rc; float f1, f2; get_next_number (rc, f1, c); if (rc < 1) { break; } get_next_number (rc, f2, c); if (rc < 1) { break; } /* Look for end-caps */ if (!is_number(f1)) { if (al.size() == 0) { f1 = -std::numeric_limits::max(); } else { f1 = std::numeric_limits::max(); } } /* Append (x,y) pair to list */ al.push_back (std::make_pair (f1, f2)); } return al; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/float_pair_list.h000066400000000000000000000010101321604176500310450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _float_pair_list_h_ #define _float_pair_list_h_ #include "plmbase_config.h" #include #include #include "itk_image_type.h" typedef std::list< std::pair< float, float > > Float_pair_list; PLMBASE_API Float_pair_list parse_float_pairs (const std::string& s); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gaussian.cxx000066400000000000000000000027731321604176500301000ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include "gaussian.h" /* This function creates the smoothing kernel */ float* create_ker (float coeff, int half_width) { int i,j=0; float sum = 0.0; int width = 2*half_width + 1; float* ker = (float*) malloc (sizeof(float) * width); if (!ker) { printf("Allocation failed 5.....Exiting\n"); exit(-1); } for (i = -half_width, j = 0; i <= half_width; i++, j++) { ker[j] = exp((((float)(-(i*i)))/(2*coeff*coeff))); sum = sum + ker[j]; } for (i = 0; i < width; i++) { ker[i] = ker[i] / sum; } return ker; } void validate_filter_widths (int *fw_out, int *fw_in) { int i; for (i = 0; i < 3; i++) { if (fw_in[i] < 3) { fw_out[i] = 3; } else { fw_out[i] = 2 * (fw_in[i] / 2) + 1; } } } void kernel_stats (float* kerx, float* kery, float* kerz, int fw[]) { int i; printf ("kerx: "); for (i = 0; i < fw[0]; i++) { printf ("%.10f ", kerx[i]); } printf ("\n"); printf ("kery: "); for (i = 0; i < fw[1]; i++) { printf ("%.10f ", kery[i]); } printf ("\n"); printf ("kerz: "); for (i = 0; i < fw[2]; i++) { printf ("%.10f ", kerz[i]); } printf ("\n"); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gaussian.h000066400000000000000000000010051321604176500275100ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gaussian_h_ #define _gaussian_h_ #include "plmbase_config.h" PLMBASE_API float* create_ker (float coeff, int half_width); PLMBASE_API void validate_filter_widths (int *fw_out, int *fw_in); PLMBASE_API void kernel_stats (float* kerx, float* kery, float* kerz, int fw[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_dose.cxx000066400000000000000000000340631321604176500302700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "gdcmBinEntry.h" #include "gdcmFile.h" #include "gdcmFileHelper.h" #include "gdcmGlobal.h" #include "gdcmSeqEntry.h" #include "gdcmSQItem.h" #include "gdcmUtil.h" #include "file_util.h" #include "gdcm1_dose.h" #include "gdcm1_util.h" #include "gdcm1_series.h" #include "itk_image_stats.h" #include "logfile.h" #include "print_and_exit.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_int.h" #include "plm_uid_prefix.h" #include "plm_version.h" #include "rt_study_metadata.h" #include "volume.h" /* winbase.h defines GetCurrentTime which conflicts with gdcm function */ #if defined GetCurrentTime # undef GetCurrentTime #endif /* This is the tolerance on irregularity of the grid spacing (in mm) */ #define GFOV_SPACING_TOL (1e-1) /* This function probes whether or not the file is a dicom dose format */ bool gdcm1_dose_probe (const char *dose_fn) { gdcm::File *gdcm_file = new gdcm::File; std::string tmp; gdcm_file->SetMaxSizeLoadEntry (0xffff); gdcm_file->SetFileName (dose_fn); gdcm_file->SetLoadMode (0); gdcm_file->Load(); /* Modality -- better be RTDOSE */ tmp = gdcm_file->GetEntryValue (0x0008, 0x0060); delete gdcm_file; if (strncmp (tmp.c_str(), "RTDOSE", strlen("RTDOSE"))) { return false; } else { return true; } } template static void gdcm1_dose_copy_raw (float *img_out, T *img_in, int nvox, float scale) { for (int i = 0; i < nvox; i++) { img_out[i] = img_in[i] * scale; } } Plm_image* gdcm1_dose_load (Plm_image *pli, const char *dose_fn) { int d, rc; gdcm::File *gdcm_file = new gdcm::File; Gdcm_series gs; std::string tmp; float ipp[3]; plm_long dim[3]; float spacing[3]; float *gfov; /* gfov = GridFrameOffsetVector */ plm_long gfov_len; const char *gfov_str; float dose_scaling; gdcm_file->SetMaxSizeLoadEntry (0xffff); gdcm_file->SetFileName (dose_fn); gdcm_file->SetLoadMode (0); gdcm_file->Load(); std::cout << " loading dose " << std::endl; /* Modality -- better be RTDOSE */ tmp = gdcm_file->GetEntryValue (0x0008, 0x0060); if (strncmp (tmp.c_str(), "RTDOSE", strlen("RTDOSE"))) { print_and_exit ("Error. Input file not RTDOSE: %s\n", dose_fn); } /* ImagePositionPatient */ tmp = gdcm_file->GetEntryValue (0x0020, 0x0032); rc = sscanf (tmp.c_str(), "%f\\%f\\%f", &ipp[0], &ipp[1], &ipp[2]); if (rc != 3) { print_and_exit ("Error parsing RTDOSE ipp.\n"); } /* Rows */ tmp = gdcm_file->GetEntryValue (0x0028, 0x0010); rc = sscanf (tmp.c_str(), "%d", &d); if (rc != 1) { print_and_exit ("Error parsing RTDOSE rows.\n"); } dim[1] = d; /* Columns */ tmp = gdcm_file->GetEntryValue (0x0028, 0x0011); rc = sscanf (tmp.c_str(), "%d", &d); if (rc != 1) { print_and_exit ("Error parsing RTDOSE columns.\n"); } dim[0] = d; /* PixelSpacing */ tmp = gdcm_file->GetEntryValue (0x0028, 0x0030); rc = sscanf (tmp.c_str(), "%g\\%g", &spacing[1], &spacing[0]); if (rc != 2) { print_and_exit ("Error parsing RTDOSE pixel spacing.\n"); } /* GridFrameOffsetVector */ tmp = gdcm_file->GetEntryValue (0x3004, 0x000C); gfov = 0; gfov_len = 0; gfov_str = tmp.c_str(); while (1) { int len; gfov = (float*) realloc (gfov, (gfov_len + 1) * sizeof(float)); rc = sscanf (gfov_str, "%g%n", &gfov[gfov_len], &len); if (rc != 1) { break; } gfov_len ++; gfov_str += len; if (gfov_str[0] == '\\') { gfov_str ++; } } dim[2] = gfov_len; if (gfov_len == 0) { print_and_exit ("Error parsing RTDOSE gfov.\n"); } /* --- Analyze GridFrameOffsetVector --- */ /* (1) Make sure first element is 0. */ if (gfov[0] != 0.) { if (gfov[0] == ipp[2]) { /* In this case, gfov values are absolute rather than relative positions, but we process the same way. */ } else { /* This is wrong. But Nucletron does it. */ logfile_printf ( "Warning: RTDOSE gfov[0] is neither 0 nor ipp[2].\n" "This violates the DICOM standard. Proceeding anyway...\n"); /* Nucletron seems to work by ignoring absolute offset (???) */ } } /* (2) Handle case where gfov_len == 1 (only one slice). */ if (gfov_len == 1) { spacing[2] = spacing[0]; } /* (3) Check to make sure spacing is regular. */ for (plm_long i = 1; i < gfov_len; i++) { if (i == 1) { spacing[2] = gfov[1] - gfov[0]; } else { float sp = gfov[i] - gfov[i-1]; if (fabs(sp - spacing[2]) > GFOV_SPACING_TOL) { print_and_exit ("Error RTDOSE grid has irregular spacing:" "%f vs %f.\n", sp, spacing[2]); } } } /* DoseGridScaling */ dose_scaling = 1.0; tmp = gdcm_file->GetEntryValue (0x3004, 0x000E); rc = sscanf (tmp.c_str(), "%f", &dose_scaling); /* If element doesn't exist, scaling is 1.0 */ /* Create output pli if necessary */ if (!pli) pli = new Plm_image; pli->free (); /* Create Volume */ Volume *vol = new Volume (dim, ipp, spacing, 0, PT_FLOAT, 1); float *img = (float*) vol->img; /* PixelData */ gdcm::FileHelper gdcm_file_helper (gdcm_file); //plm_long image_data_size = gdcm_file_helper.GetImageDataSize(); if (strcmp (gdcm_file->GetPixelType().c_str(), "16U")==0) { unsigned short* image_data = (unsigned short*) gdcm_file_helper.GetImageData(); gdcm1_dose_copy_raw (img, image_data, vol->npix, dose_scaling); } else if (strcmp(gdcm_file->GetPixelType().c_str(),"32U")==0){ printf ("Got 32U.\n"); uint32_t* image_data = (uint32_t*) gdcm_file_helper.GetImageData (); gdcm1_dose_copy_raw (img, image_data, vol->npix, dose_scaling); } else { print_and_exit ("Error RTDOSE not type 16U and 32U (type=%s)\n",gdcm_file->GetPixelType().c_str()); } /* GCS FIX: Do I need to do something about endian-ness? */ /* Bind volume to plm_image */ pli->set_volume (vol); #if defined (commentout) printf ("IPP = %f %f %f\n", ipp[0], ipp[1], ipp[2]); printf ("DIM = %d %d %d\n", dim[0], dim[1], dim[2]); printf ("SPC = %f %f %f\n", spacing[0], spacing[1], spacing[2]); printf ("NVX = %d\n", dim[0] * dim[1] * dim[2]); printf ("ID = size %d, type %s\n", image_data_size, gdcm_file->GetPixelType().c_str()); #endif free (gfov); delete gdcm_file; return pli; } void gdcm1_dose_save ( Plm_image *pli, /* Input: dose image */ const Rt_study_metadata *rsm, const char *dose_fn /* Input: file to write to */ ) { int i; gdcm::File *gf = new gdcm::File (); Gdcm_series gs; const std::string ¤t_date = gdcm::Util::GetCurrentDate(); const std::string ¤t_time = gdcm::Util::GetCurrentTime(); std::string s; Plm_image_header plh; plh.set_from_plm_image (pli); printf ("Hello from gdcm_dose_save: fn = %s\n", dose_fn); make_directory_recursive (dose_fn); const Metadata::Pointer& meta = rsm->get_dose_metadata (); /* ----------------------------------------------------------------- */ /* Part 1 -- General header */ /* ----------------------------------------------------------------- */ /* InstanceCreationDate */ gf->InsertValEntry (current_date, 0x0008, 0x0012); /* InstanceCreationTime */ gf->InsertValEntry (current_time, 0x0008, 0x0013); /* InstanceCreatorUID */ gf->InsertValEntry (PLM_UID_PREFIX, 0x0008, 0x0014); /* SOPClassUID = RTDoseStorage */ gf->InsertValEntry ("1.2.840.10008.5.1.4.1.1.481.2", 0x0008, 0x0016); /* SOPInstanceUID */ gf->InsertValEntry (gdcm::Util::CreateUniqueUID (PLM_UID_PREFIX), 0x0008, 0x0018); /* StudyDate */ gf->InsertValEntry ("20000101", 0x0008, 0x0020); /* StudyTime */ gf->InsertValEntry ("120000", 0x0008, 0x0030); /* AccessionNumber */ gf->InsertValEntry ("", 0x0008, 0x0050); /* Modality */ gf->InsertValEntry ("RTDOSE", 0x0008, 0x0060); /* Manufacturer */ gf->InsertValEntry ("Plastimatch", 0x0008, 0x0070); /* ReferringPhysiciansName */ gf->InsertValEntry ("", 0x0008, 0x0090); /* SeriesDescription */ set_gdcm_file_from_metadata (gf, meta, 0x0008, 0x103e); /* ManufacturersModelName */ gf->InsertValEntry ("Plastimatch", 0x0008, 0x1090); /* PatientsName */ set_gdcm_file_from_metadata (gf, meta, 0x0010, 0x0010); /* PatientID */ set_gdcm_file_from_metadata (gf, meta, 0x0010, 0x0020); /* PatientsBirthDate */ gf->InsertValEntry ("", 0x0010, 0x0030); /* PatientsSex */ set_gdcm_file_from_metadata (gf, meta, 0x0010, 0x0040); /* SliceThickness */ gf->InsertValEntry ("", 0x0018, 0x0050); /* SoftwareVersions */ gf->InsertValEntry (PLASTIMATCH_VERSION_STRING, 0x0018, 0x1020); /* StudyInstanceUID */ gf->InsertValEntry ((const char*) rsm->get_study_uid(), 0x0020, 0x000d); /* SeriesInstanceUID */ gf->InsertValEntry (gdcm::Util::CreateUniqueUID (PLM_UID_PREFIX), 0x0020, 0x000e); /* StudyID */ set_gdcm_file_from_metadata (gf, meta, 0x0020, 0x0010); /* SeriesNumber */ gf->InsertValEntry ("", 0x0020, 0x0011); /* InstanceNumber */ gf->InsertValEntry ("1", 0x0020, 0x0013); /* ImagePositionPatient */ s = gdcm::Util::Format ("%g\\%g\\%g", plh.GetOrigin()[0], plh.GetOrigin()[1], plh.GetOrigin()[2]); gf->InsertValEntry (s, 0x0020, 0x0032); /* ImageOrientationPatient */ itk::Matrix < double, 3, 3 > direction=plh.GetDirection(); s = gdcm::Util::Format ("%g\\%g\\%g\\%g\\%g\\%g", direction[0][0], direction[0][1], direction[0][2], direction[1][0], direction[1][1], direction[1][2]); gf->InsertValEntry (s, 0x0020, 0x0037); /* FrameOfReferenceUID */ gf->InsertValEntry (rsm->get_frame_of_reference_uid(), 0x0020, 0x0052); /* SamplesPerPixel */ gf->InsertValEntry ("1", 0x0028, 0x0002); /* PhotometricInterpretation */ gf->InsertValEntry ("MONOCHROME2", 0x0028, 0x0004); /* NumberOfFrames */ s = gdcm::Util::Format ("%d", plh.GetSize()[2]); gf->InsertValEntry (s, 0x0028, 0x0008); /* FrameIncrementPointer */ /* Note: InsertValEntry doesn't work for AT value representations gf->InsertValEntry ("3004,000c", 0x0028, 0x0009); */ uint16_t fip[2] = { 0x3004, 0x000c }; gf->InsertBinEntry ((uint8_t*)fip, 4, 0x0028, 0x0009, std::string("AT")); /* Rows */ s = gdcm::Util::Format ("%d", plh.GetSize()[1]); gf->InsertValEntry (s, 0x0028, 0x0010); /* Columns */ s = gdcm::Util::Format ("%d", plh.GetSize()[0]); gf->InsertValEntry (s, 0x0028, 0x0011); /* PixelSpacing */ s = gdcm::Util::Format ("%g\\%g", plh.GetSpacing()[1], plh.GetSpacing()[0]); gf->InsertValEntry (s, 0x0028, 0x0030); /* BitsAllocated */ gf->InsertValEntry ("32", 0x0028, 0x0100); /* BitsStored */ gf->InsertValEntry ("32", 0x0028, 0x0101); /* HighBit */ gf->InsertValEntry ("31", 0x0028, 0x0102); /* PixelRepresentation */ if (meta->get_metadata(0x3004, 0x0004) != "ERROR") { gf->InsertValEntry ("0", 0x0028, 0x0103); } else { gf->InsertValEntry ("1", 0x0028, 0x0103); } /* Do I need SmallestImagePixelValue, LargestImagePixelValue? */ /* DoseUnits */ gf->InsertValEntry ("GY", 0x3004, 0x0002); /* DoseType */ if (meta->get_metadata(0x3004, 0x0004) != "") { set_gdcm_file_from_metadata (gf, meta, 0x3004, 0x0004); } else { gf->InsertValEntry ("PHYSICAL", 0x3004, 0x0004); } /* DoseSummationType */ gf->InsertValEntry ("PLAN", 0x3004, 0x000a); /* GridFrameOffsetVector */ s = std::string ("0"); for (i = 1; i < plh.GetSize()[2]; i++) { s += gdcm::Util::Format ("\\%g", i * plh.GetSpacing()[2]); } gf->InsertValEntry (s, 0x3004, 0x000c); /* GCS FIX: Leave ReferencedRTPlanSequence empty (until I can cross reference) */ /* We need to convert image to uint16_t, but first we need to scale it. The maximum dose needs to fit in a 16-bit unsigned integer. Older versions of plastimatch set the dose_scale to a fixed value of 0.04 (based on the fact that this number was found in the XiO sample). With this scaling, the maximum dose is 262 Gy. Now we compute an appropriate scaling factor based on the maximum dose. */ /* Copy the image so we don't corrupt the original */ Plm_image::Pointer tmp = pli->clone (); /* Find the maximum value in the image */ double min_val, max_val, avg; int non_zero, num_vox; tmp->convert (PLM_IMG_TYPE_ITK_FLOAT); itk_image_stats (tmp->m_itk_float, &min_val, &max_val, &avg, &non_zero, &num_vox); float dose_scale; if (meta->get_metadata(0x3004, 0x0004) != "ERROR") { /* Dose is unsigned integer */ dose_scale = max_val / UINT32_T_MAX * 1.001; } else { /* Dose error is signed integer */ float dose_scale_min = min_val / INT32_T_MIN * 1.001; float dose_scale_max = max_val / INT32_T_MAX * 1.001; dose_scale = std::max(dose_scale_min, dose_scale_max); } /* Scale the image */ tmp->convert (PLM_IMG_TYPE_GPUIT_FLOAT); Volume *vol = tmp->get_vol (); vol->scale_inplace (1 / dose_scale); /* Convert to integer */ if (meta->get_metadata(0x3004, 0x0004) != "ERROR") { tmp->convert (PLM_IMG_TYPE_GPUIT_UINT32); } else { tmp->convert (PLM_IMG_TYPE_GPUIT_INT32); } vol = tmp->get_vol (); /* DoseGridScaling */ s = gdcm::Util::Format ("%g", dose_scale); gf->InsertValEntry (s, 0x3004, 0x000e); /* PixelData */ gdcm::FileHelper gfh (gf); gfh.SetImageData ((uint8_t*) vol->img, vol->npix * vol->pix_size); /* Do the actual writing out to file */ gfh.WriteDcmExplVR (dose_fn); } /* Explicit instantiations */ template void gdcm1_dose_copy_raw (float *img_out, unsigned short *img_in, int nvox, float scale); template void gdcm1_dose_copy_raw (float *img_out, unsigned long int *img_in, int nvox, float scale); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_dose.h000066400000000000000000000014521321604176500277110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gdcm1_dose_h_ #define _gdcm1_dose_h_ #include "plmbase_config.h" class Metadata; class Plm_image; class Rt_study_metadata; #if PLM_DCM_USE_GDCM1 /* gdcm1_dose.cxx */ PLMBASE_C_API bool gdcm1_dose_probe (const char *dose_fn); PLMBASE_C_API Plm_image* gdcm1_dose_load ( Plm_image *pli, const char *dose_fn); PLMBASE_C_API void gdcm1_dose_save ( Plm_image *pli, const Rt_study_metadata *rsm, const char *dose_fn); /* gdcm1_series.cxx */ PLMBASE_C_API void gdcm1_series_test (char *dicom_dir); #endif #endif /* _gdcm1_dose_h_ */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_file.cxx000066400000000000000000000015101321604176500302440ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "gdcmFile.h" #include "gdcmFileHelper.h" #include "gdcm1_file.h" #include "metadata.h" void meta_from_gdcm_file ( Metadata *meta, gdcm::File gdcm_file, unsigned short group, unsigned short elem) { } std::string gdcm_file_GetEntryValue (gdcm::File *file, unsigned short group, unsigned short elem) { return file->GetEntryValue (group, elem); } const std::string& gdcm_file_GDCM_UNKNOWN () { return gdcm::GDCM_UNKNOWN; } const std::string& gdcm_file_GDCM_UNFOUND () { return gdcm::GDCM_UNFOUND; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_file.h000066400000000000000000000011561321604176500276770ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gdcm1_file_h_ #define _gdcm1_file_h_ #include "plmbase_config.h" #include namespace gdcm { class File; }; PLMBASE_API std::string gdcm_file_GetEntryValue ( gdcm::File *file, unsigned short group, unsigned short elem ); PLMBASE_API const std::string& gdcm_file_GDCM_UNKNOWN (); PLMBASE_API const std::string& gdcm_file_GDCM_UNFOUND (); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_rdd.cxx000066400000000000000000000042671321604176500301120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "gdcm1_file.h" #include "gdcm1_rdd.h" #include "gdcm1_series.h" #include "gdcm1_util.h" #include "metadata.h" #include "plm_image_header.h" #include "plm_math.h" #include "plm_uid_prefix.h" #include "rt_study_metadata.h" void gdcm1_load_rdd ( Rt_study_metadata *rdd, const char *dicom_dir ) { Gdcm_series gs; std::string tmp; if (!dicom_dir) { return; } gs.load (dicom_dir); gs.digest_files (); if (!gs.m_have_ct) { return; } gdcm::File* file = gs.get_ct_slice (); /* Add geometry */ int d; float offset[3], spacing[3]; /* Convert double to float */ for (d = 0; d < 3; d++) { offset[d] = gs.m_origin[d]; spacing[d] = gs.m_spacing[d]; } rdd->set_image_header (Plm_image_header (gs.m_dim, offset, spacing, 0)); /* Store metadata into here */ Metadata::Pointer& meta = rdd->get_study_metadata (); /* PatientName */ set_metadata_from_gdcm_file (meta, file, 0x0010, 0x0010); /* PatientID */ set_metadata_from_gdcm_file (meta, file, 0x0010, 0x0020); /* PatientSex */ set_metadata_from_gdcm_file (meta, file, 0x0010, 0x0040); /* PatientPosition */ set_metadata_from_gdcm_file (meta, file, 0x0018, 0x5100); /* StudyID */ tmp = gdcm_file_GetEntryValue (file, 0x0020, 0x0010); if (tmp != gdcm_file_GDCM_UNFOUND()) { meta->set_metadata (0x0020, 0x0010, tmp.c_str()); } /* StudyInstanceUID */ tmp = gdcm_file_GetEntryValue (file, 0x0020, 0x000d); rdd->set_study_uid (tmp.c_str()); /* SeriesInstanceUID */ tmp = gdcm_file_GetEntryValue (file, 0x0020, 0x000e); rdd->set_ct_series_uid (tmp.c_str()); /* FrameOfReferenceUID */ tmp = gdcm_file_GetEntryValue (file, 0x0020, 0x0052); rdd->set_frame_of_reference_uid (tmp.c_str()); /* Slice uids */ gs.get_slice_uids (rdd); /* Done */ rdd->set_slice_list_complete (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_rdd.h000066400000000000000000000006741321604176500275350ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gdcm1_rdd_h_ #define _gdcm1_rdd_h_ #include "plmbase_config.h" #if PLM_DCM_USE_GDCM1 class Rt_study_metadata; void gdcm1_load_rdd ( Rt_study_metadata *rdd, const char *dicom_dir ); #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_rtss.cxx000066400000000000000000000533341321604176500303330ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "gdcmDocEntry.h" #include "gdcmDocEntrySet.h" #include "gdcmFile.h" #include "gdcmFileHelper.h" #include "gdcmGlobal.h" #include "gdcmSeqEntry.h" #include "gdcmSQItem.h" #include "gdcmUtil.h" #include "gdcmValEntry.h" #include "file_util.h" #include "gdcm1_rtss.h" #include "gdcm1_util.h" #include "metadata.h" #include "plm_uid_prefix.h" #include "plm_version.h" #include "print_and_exit.h" #include "rt_study_metadata.h" #include "rtss.h" #include "rtss_contour.h" #include "rtss_roi.h" /* winbase.h defines GetCurrentTime which conflicts with gdcm function */ #if defined GetCurrentTime # undef GetCurrentTime #endif /* This function probes whether or not the file is a dicom rtss format */ bool gdcm_rtss_probe (const char *rtss_fn) { gdcm::File *rtss_file = new gdcm::File; std::string tmp; rtss_file->SetMaxSizeLoadEntry (0xffffff); rtss_file->SetFileName (rtss_fn); rtss_file->SetLoadMode (0); rtss_file->Load(); /* Modality -- better be RTSTRUCT */ tmp = rtss_file->GetEntryValue (0x0008, 0x0060); delete rtss_file; if (strncmp (tmp.c_str(), "RTSTRUCT", strlen("RTSTRUCT"))) { return false; } else { return true; } } void gdcm_rtss_load ( Rtss *cxt, /* Output: this gets loaded into */ Rt_study_metadata *rsm, /* Output: this gets updated too */ const char *rtss_fn /* Input: the file that gets read */ ) { gdcm::File *rtss_file = new gdcm::File; gdcm::SeqEntry *seq; gdcm::SQItem *item; std::string tmp; rtss_file->SetMaxSizeLoadEntry (0xffffff); rtss_file->SetFileName (rtss_fn); rtss_file->SetLoadMode (0); rtss_file->Load(); /* Modality -- better be RTSTRUCT */ tmp = rtss_file->GetEntryValue (0x0008, 0x0060); if (strncmp (tmp.c_str(), "RTSTRUCT", strlen("RTSTRUCT"))) { print_and_exit ("Error. Input file not an RT structure set: %s\n", rtss_fn); } Metadata::Pointer& meta = rsm->get_study_metadata (); /* PatientName */ set_metadata_from_gdcm_file (meta, rtss_file, 0x0010, 0x0010); /* PatientID */ set_metadata_from_gdcm_file (meta, rtss_file, 0x0010, 0x0020); /* PatientSex */ set_metadata_from_gdcm_file (meta, rtss_file, 0x0010, 0x0040); /* StudyID */ /* GCS FIX: It would be useful to distinguish a loaded value from a generated one */ #if defined (commentout) if (rdd->m_study_id.empty()) { tmp = rtss_file->GetEntryValue (0x0020, 0x0010); if (tmp != gdcm::GDCM_UNFOUND) { rdd->m_study_id = tmp.c_str(); } } #endif tmp = rtss_file->GetEntryValue (0x0020, 0x0010); if (tmp != gdcm::GDCM_UNFOUND) { meta->set_metadata (0x0020, 0x0010, tmp.c_str()); } /* StudyInstanceUID */ /* GCS FIX: Here is another case where it would be useful to distinguish a loaded UID from a generated UID. Until I get a fix, I'll omit loading this, and presume it is loaded through either image load or referenced-ct */ #if defined (commentout) if (rdd->m_ct_study_uid.empty()) { tmp = rtss_file->GetEntryValue (0x0020, 0x000d); rdd->m_ct_study_uid = tmp.c_str(); } #endif /* ReferencedFrameOfReferenceSequence */ gdcm::SeqEntry *rfor_seq = rtss_file->GetSeqEntry (0x3006,0x0010); if (rfor_seq) { /* FrameOfReferenceUID */ item = rfor_seq->GetFirstSQItem (); if (item) { /* GCS FIX: Ditto */ #if defined (commentout) tmp = item->GetEntryValue (0x0020,0x0052); if (rdd->m_ct_fref_uid.empty()) { if (tmp != gdcm::GDCM_UNFOUND) { rdd->m_ct_fref_uid = tmp.c_str(); } } #endif /* RTReferencedStudySequence */ gdcm::SeqEntry *rtrstudy_seq = item->GetSeqEntry (0x3006, 0x0012); if (rtrstudy_seq) { /* RTReferencedSeriesSequence */ item = rtrstudy_seq->GetFirstSQItem (); if (item) { gdcm::SeqEntry *rtrseries_seq = item->GetSeqEntry (0x3006, 0x0014); if (rtrseries_seq) { item = rtrseries_seq->GetFirstSQItem (); /* SeriesInstanceUID */ if (item) { /* GCS FIX: Ditto */ #if defined (commentout) tmp = item->GetEntryValue (0x0020, 0x000e); if (rdd->m_ct_series_uid.empty()) { if (tmp != gdcm::GDCM_UNFOUND) { rdd->m_ct_series_uid = tmp.c_str(); } } #endif } } } } } } /* StructureSetROISequence */ seq = rtss_file->GetSeqEntry (0x3006,0x0020); for (item = seq->GetFirstSQItem (); item; item = seq->GetNextSQItem ()) { int structure_id; std::string roi_number, roi_name; roi_number = item->GetEntryValue (0x3006,0x0022); roi_name = item->GetEntryValue (0x3006,0x0026); if (1 != sscanf (roi_number.c_str(), "%d", &structure_id)) { continue; } cxt->add_structure (roi_name, std::string(), structure_id); } /* ROIContourSequence */ seq = rtss_file->GetSeqEntry (0x3006,0x0039); for (item = seq->GetFirstSQItem (); item; item = seq->GetNextSQItem ()) { int structure_id; std::string roi_display_color, referenced_roi_number; gdcm::SeqEntry *c_seq; gdcm::SQItem *c_item; Rtss_roi *curr_structure; /* Get id and color */ referenced_roi_number = item->GetEntryValue (0x3006,0x0084); roi_display_color = item->GetEntryValue (0x3006,0x002a); printf ("RRN = [%s], RDC = [%s]\n", referenced_roi_number.c_str(), roi_display_color.c_str()); if (1 != sscanf (referenced_roi_number.c_str(), "%d", &structure_id)) { printf ("Error parsing rrn...\n"); continue; } /* Look up the cxt structure for this id */ curr_structure = cxt->find_structure_by_id (structure_id); if (!curr_structure) { printf ("Couldn't reference structure with id %d\n", structure_id); exit (-1); } curr_structure->set_color (roi_display_color.c_str()); /* ContourSequence */ c_seq = item->GetSeqEntry (0x3006,0x0040); if (c_seq) { for (c_item = c_seq->GetFirstSQItem (); c_item; c_item = c_seq->GetNextSQItem ()) { int i, p, n, contour_data_len; int num_points; std::string contour_geometric_type; std::string contour_data; std::string number_of_contour_points; Rtss_contour *curr_polyline; /* Grab data from dicom */ contour_geometric_type = c_item->GetEntryValue (0x3006,0x0042); if (strncmp (contour_geometric_type.c_str(), "CLOSED_PLANAR", strlen("CLOSED_PLANAR"))) { /* Might be "POINT". Do I want to preserve this? */ printf ("Skipping geometric type: [%s]\n", contour_geometric_type.c_str()); continue; } number_of_contour_points = c_item->GetEntryValue (0x3006,0x0046); if (1 != sscanf (number_of_contour_points.c_str(), "%d", &num_points)) { printf ("Error parsing number_of_contour_points...\n"); continue; } if (num_points <= 0) { /* Polyline with zero points? Skip it. */ continue; } contour_data = c_item->GetEntryValue (0x3006,0x0050); if (contour_data == gdcm::GDCM_UNFOUND) { printf ("Error grabbing contour data.\n"); continue; } /* Create a new polyline for this structure */ curr_polyline = curr_structure->add_polyline (); curr_polyline->slice_no = -1; //curr_polyline->ct_slice_uid = ""; curr_polyline->num_vertices = num_points; curr_polyline->x = (float*) malloc (num_points * sizeof(float)); curr_polyline->y = (float*) malloc (num_points * sizeof(float)); curr_polyline->z = (float*) malloc (num_points * sizeof(float)); /* Parse dicom data string */ i = 0; n = 0; contour_data_len = strlen (contour_data.c_str()); for (p = 0; p < 3 * num_points; p++) { float f; int this_n; /* Skip \\ */ if (n < contour_data_len) { if (contour_data.c_str()[n] == '\\') { n++; } } /* Parse float value */ if (1 != sscanf (&contour_data[n], "%f%n", &f, &this_n)) { printf ("Error parsing data...\n"); printf ("%d points\n", num_points); printf ("%s\n", contour_data.c_str()); break; } n += this_n; /* Put value into polyline */ switch (i) { case 0: curr_polyline->x[p/3] = f; break; case 1: curr_polyline->y[p/3] = f; break; case 2: curr_polyline->z[p/3] = f; break; } i = (i + 1) % 3; } } } } printf ("Loading complete.\n"); delete rtss_file; } /* GCS: I had to copy from gdcm::Document because the function is protected. */ int plm_ComputeGroup0002Length (gdcm::File *gf) { uint16_t gr; std::string vr; int groupLength = 0; bool found0002 = false; // for each zero-level Tag in the DCM Header gdcm::DocEntry *entry = gf->GetFirstEntry(); while( entry ) { gr = entry->GetGroup(); if ( gr == 0x0002 ) { found0002 = true; if ( entry->GetElement() != 0x0000 ) { vr = entry->GetVR(); //if ( (vr == "OB")||(vr == "OW")||(vr == "UT")||(vr == "SQ")) // (no SQ, OW, UT in group 0x0002;) if ( vr == "OB" ) { // explicit VR AND (OB, OW, SQ, UT) : 4 more bytes groupLength += 4; } groupLength += 2 + 2 + 4 + entry->GetLength(); } } else if (found0002 ) break; entry = gf->GetNextEntry(); } return groupLength; } void gdcm_rtss_save ( Rtss *cxt, /* Input: this is what gets saved */ const Rt_study_metadata::Pointer& rsm, /* In: save this too */ const char *rtss_fn /* Input: name of file to write to */ ) { int k; gdcm::File *gf = new gdcm::File (); const std::string ¤t_date = gdcm::Util::GetCurrentDate(); const std::string ¤t_time = gdcm::Util::GetCurrentTime(); printf ("Hello from gdcm_rtss_save (%s)\n", rtss_fn); /* Due to a bug in gdcm, it is not possible to create a gdcmFile which does not have a (7fe0,0000) PixelDataGroupLength element. Therefore we have to write using Document::WriteContent() */ make_parent_directories (rtss_fn); std::ofstream *fp; fp = new std::ofstream (rtss_fn, std::ios::out | std::ios::binary); if (*fp == NULL) { fprintf (stderr, "Error opening file for write: %s\n", rtss_fn); return; } /* ----------------------------------------------------------------- */ /* Part 1 -- General header */ /* ----------------------------------------------------------------- */ /* FIX: DICOM file meta information cannot be stored when writing with Document::WriteContent(). So there's no TransferSyntaxUID etc. We need a better workaround for the gdcm bug. */ Metadata::Pointer& meta = rsm->get_study_metadata(); /* InstanceCreationDate */ gf->InsertValEntry (current_date, 0x0008, 0x0012); /* InstanceCreationTime */ gf->InsertValEntry (current_time, 0x0008, 0x0013); /* InstanceCreatorUID */ gf->InsertValEntry (PLM_UID_PREFIX, 0x0008, 0x0014); /* SOPClassUID = RTStructureSetStorage */ gf->InsertValEntry ("1.2.840.10008.5.1.4.1.1.481.3", 0x0008, 0x0016); /* SOPInstanceUID */ gf->InsertValEntry (gdcm::Util::CreateUniqueUID (PLM_UID_PREFIX), 0x0008, 0x0018); /* StudyDate */ gf->InsertValEntry ("20000101", 0x0008, 0x0020); /* StudyTime */ gf->InsertValEntry ("120000", 0x0008, 0x0030); /* AccessionNumber */ gf->InsertValEntry ("", 0x0008, 0x0050); /* Modality */ gf->InsertValEntry ("RTSTRUCT", 0x0008, 0x0060); /* Manufacturer */ gf->InsertValEntry ("Plastimatch", 0x0008, 0x0070); /* InstitutionName */ gf->InsertValEntry ("", 0x0008, 0x0080); /* ReferringPhysiciansName */ gf->InsertValEntry ("", 0x0008, 0x0090); /* StationName */ gf->InsertValEntry ("", 0x0008, 0x1010); /* SeriesDescription */ set_gdcm_file_from_metadata (gf, meta, 0x0008, 0x103e); /* ManufacturersModelName */ gf->InsertValEntry ("Plastimatch", 0x0008, 0x1090); /* PatientsName */ set_gdcm_file_from_metadata (gf, meta, 0x0010, 0x0010); /* PatientID */ set_gdcm_file_from_metadata (gf, meta, 0x0010, 0x0020); /* PatientsBirthDate */ gf->InsertValEntry ("", 0x0010, 0x0030); /* PatientsSex */ set_gdcm_file_from_metadata (gf, meta, 0x0010, 0x0040); /* SoftwareVersions */ gf->InsertValEntry (PLASTIMATCH_VERSION_STRING, 0x0018, 0x1020); /* PatientPosition */ // gf->InsertValEntry (xxx, 0x0018, 0x5100); /* StudyInstanceUID */ gf->InsertValEntry ((const char*) rsm->get_study_uid(), 0x0020, 0x000d); /* SeriesInstanceUID */ gf->InsertValEntry (gdcm::Util::CreateUniqueUID (PLM_UID_PREFIX), 0x0020, 0x000e); /* StudyID */ set_gdcm_file_from_metadata (gf, meta, 0x0020, 0x0010); /* SeriesNumber */ gf->InsertValEntry ("103", 0x0020, 0x0011); /* InstanceNumber */ gf->InsertValEntry ("1", 0x0020, 0x0013); /* StructureSetLabel */ gf->InsertValEntry ("AutoSS", 0x3006, 0x0002); /* StructureSetName */ gf->InsertValEntry ("AutoSS", 0x3006, 0x0004); /* StructureSetDate */ gf->InsertValEntry (current_date, 0x3006, 0x0008); /* StructureSetTime */ gf->InsertValEntry (current_time, 0x3006, 0x0009); /* ----------------------------------------------------------------- */ /* Part 2 -- UID's for CT series */ /* ----------------------------------------------------------------- */ /* ReferencedFrameOfReferenceSequence */ gdcm::SeqEntry *rfor_seq = gf->InsertSeqEntry (0x3006, 0x0010); gdcm::SQItem *rfor_item = new gdcm::SQItem (rfor_seq->GetDepthLevel()); rfor_seq->AddSQItem (rfor_item, 1); /* FrameOfReferenceUID */ rfor_item->InsertValEntry (rsm->get_frame_of_reference_uid(), 0x0020, 0x0052); /* RTReferencedStudySequence */ gdcm::SeqEntry *rtrstudy_seq = rfor_item->InsertSeqEntry (0x3006, 0x0012); gdcm::SQItem *rtrstudy_item = new gdcm::SQItem (rtrstudy_seq->GetDepthLevel()); rtrstudy_seq->AddSQItem (rtrstudy_item, 1); /* ReferencedSOPClassUID = DetachedStudyManagementSOPClass */ rtrstudy_item->InsertValEntry ("1.2.840.10008.3.1.2.3.1", 0x0008, 0x1150); /* ReferencedSOPInstanceUID */ rtrstudy_item->InsertValEntry (rsm->get_study_uid(), 0x0008, 0x1155); /* RTReferencedSeriesSequence */ gdcm::SeqEntry *rtrseries_seq = rtrstudy_item->InsertSeqEntry (0x3006, 0x0014); gdcm::SQItem *rtrseries_item = new gdcm::SQItem (rtrseries_seq->GetDepthLevel()); rtrseries_seq->AddSQItem (rtrseries_item, 1); /* SeriesInstanceUID */ rtrseries_item->InsertValEntry (rsm->get_ct_series_uid(), 0x0020, 0x000e); /* ContourImageSequence */ gdcm::SeqEntry *ci_seq = rtrseries_item->InsertSeqEntry (0x3006, 0x0016); if (!rsm->slice_list_complete()) { printf ("Warning: CT UIDs not found. " "ContourImageSequence not generated.\n"); } for (int slice = 0, sqi = 1; slice < rsm->num_slices(); slice++, sqi++) { /* Get SOPInstanceUID of CT slice */ std::string tmp = rsm->get_slice_uid (slice); /* Put item into sequence */ gdcm::SQItem *ci_item = new gdcm::SQItem (ci_seq->GetDepthLevel()); ci_seq->AddSQItem (ci_item, sqi++); /* ReferencedSOPClassUID = CTImageStorage */ ci_item->InsertValEntry ("1.2.840.10008.5.1.4.1.1.2", 0x0008, 0x1150); /* Put ReferencedSOPInstanceUID into item */ ci_item->InsertValEntry (tmp, 0x0008, 0x1155); } /* ----------------------------------------------------------------- */ /* Part 3 -- Structure info */ /* ----------------------------------------------------------------- */ /* StructureSetROISequence */ gdcm::SeqEntry *ssroi_seq = gf->InsertSeqEntry (0x3006, 0x0020); for (size_t i = 0; i < cxt->num_structures; i++) { gdcm::SQItem *ssroi_item = new gdcm::SQItem (ssroi_seq->GetDepthLevel()); ssroi_seq->AddSQItem (ssroi_item, i+1); /* ROINumber */ ssroi_item->InsertValEntry (gdcm::Util::Format ("%d", cxt->slist[i]->id), 0x3006, 0x0022); /* ReferencedFrameOfReferenceUID */ ssroi_item->InsertValEntry ( rsm->get_frame_of_reference_uid(), 0x3006, 0x0024); /* ROIName */ ssroi_item->InsertValEntry ( cxt->slist[i]->name.c_str(), 0x3006, 0x0026); /* ROIGenerationAlgorithm */ ssroi_item->InsertValEntry ("", 0x3006, 0x0036); } /* ----------------------------------------------------------------- */ /* Part 4 -- Contour info */ /* ----------------------------------------------------------------- */ /* ROIContourSequence */ gdcm::SeqEntry *roic_seq = gf->InsertSeqEntry (0x3006, 0x0039); for (size_t i = 0; i < cxt->num_structures; i++) { Rtss_roi *curr_structure = cxt->slist[i]; gdcm::SQItem *roic_item = new gdcm::SQItem (roic_seq->GetDepthLevel()); roic_seq->AddSQItem (roic_item, i+1); /* ROIDisplayColor */ std::string dcm_color; dcm_color = curr_structure->get_dcm_color_string (); roic_item->InsertValEntry (dcm_color.c_str(), 0x3006, 0x002a); /* ContourSequence */ gdcm::SeqEntry *c_seq = roic_item->InsertSeqEntry (0x3006, 0x0040); for (size_t j = 0; j < curr_structure->num_contours; j++) { Rtss_contour *curr_contour = curr_structure->pslist[j]; if (curr_contour->num_vertices <= 0) continue; #if defined (commentout) /* GCS 2013-07-02: DICOM standard allows contours without an associated slice UID. Maybe this bug is now fixed in XiO??? */ /* GE -> XiO transfer does not work if contour does not have corresponding slice uid */ if (curr_contour->ct_slice_uid.empty()) { printf ("Warning: Omitting contour (%ld,%ld)\n", (long) i, (long) j); continue; } #endif /* Add item to ContourSequence */ gdcm::SQItem *c_item = new gdcm::SQItem ( c_seq->GetDepthLevel()); c_seq->AddSQItem (c_item, j+1); /* ContourImageSequence */ if (curr_contour->ct_slice_uid != "") { gdcm::SeqEntry *ci_seq = c_item->InsertSeqEntry (0x3006, 0x0016); gdcm::SQItem *ci_item = new gdcm::SQItem (ci_seq->GetDepthLevel()); ci_seq->AddSQItem (ci_item, 1); /* ReferencedSOPClassUID = CTImageStorage */ ci_item->InsertValEntry ("1.2.840.10008.5.1.4.1.1.2", 0x0008, 0x1150); /* ReferencedSOPInstanceUID */ ci_item->InsertValEntry ( curr_contour->ct_slice_uid.c_str(), 0x0008, 0x1155); } /* ContourGeometricType */ c_item->InsertValEntry ("CLOSED_PLANAR", 0x3006, 0x0042); /* NumberOfContourPoints */ c_item->InsertValEntry (gdcm::Util::Format ("%d", curr_contour->num_vertices), 0x3006, 0x0046); /* ContourData */ std::string contour_string = gdcm::Util::Format ("%g\\%g\\%g", curr_contour->x[0], curr_contour->y[0], curr_contour->z[0]); for (k = 1; k < curr_contour->num_vertices; k++) { contour_string += gdcm::Util::Format ("\\%g\\%g\\%g", curr_contour->x[k], curr_contour->y[k], curr_contour->z[k]); } c_item->InsertValEntry (contour_string, 0x3006, 0x0050); } /* ReferencedROINumber */ roic_item->InsertValEntry (gdcm::Util::Format ("%d", curr_structure->id), 0x3006, 0x0084); } /* ----------------------------------------------------------------- */ /* Part 5 -- More structure info */ /* ----------------------------------------------------------------- */ /* RTROIObservationsSequence */ gdcm::SeqEntry *rtroio_seq = gf->InsertSeqEntry (0x3006, 0x0080); for (size_t i = 0; i < cxt->num_structures; i++) { Rtss_roi *curr_structure = cxt->slist[i]; gdcm::SQItem *rtroio_item = new gdcm::SQItem (rtroio_seq->GetDepthLevel()); rtroio_seq->AddSQItem (rtroio_item, i+1); /* ObservationNumber */ rtroio_item->InsertValEntry (gdcm::Util::Format ("%d", curr_structure->id), 0x3006, 0x0082); /* ReferencedROINumber */ rtroio_item->InsertValEntry (gdcm::Util::Format ("%d", curr_structure->id), 0x3006, 0x0084); /* ROIObservationLabel */ if (curr_structure->name.length() <= 16) { rtroio_item->InsertValEntry ( curr_structure->name.c_str(), 0x3006, 0x0085); } else { /* VR is SH, max length 16 */ std::string tmp_name = curr_structure->name.substr (0, 16); rtroio_item->InsertValEntry ( tmp_name.c_str(), 0x3006, 0x0085); } /* RTROIInterpretedType */ rtroio_item->InsertValEntry ("", 0x3006, 0x00a4); /* ROIInterpreter */ rtroio_item->InsertValEntry ("", 0x3006, 0x00a6); } /* Create DICOM meta-information header -- gdcm suxxors :P */ gf->InsertValEntry ("0", 0x0002, 0x0000); uint8_t fmiv[2] = { 0x00, 0x01 }; gf->InsertBinEntry (fmiv, 2, 0x0002, 0x0001, std::string("OB")); gf->InsertValEntry ("1.2.840.10008.5.1.4.1.1.481.3", 0x0002, 0x0002); gf->InsertValEntry (gf->GetEntryValue (0x0008, 0x0018), 0x0002, 0x0003); // Implicit VR Little Endian = "1.2.840.10008.1.2" // Explicit VR Little Endian = "1.2.840.10008.1.2.1" gf->InsertValEntry ("1.2.840.10008.1.2.1", 0x0002, 0x0010); gf->InsertValEntry (std::string (PLM_UID_PREFIX) + ".101" , 0x0002, 0x0012); /* NB: (0002,0013) only allows up to 16 characters */ gf->InsertValEntry (std::string("Plastimatch 1.4"), 0x0002, 0x0013); /* Calculate size of meta-information header */ /* GCS: I copied this from gdcm::File::Write */ gdcm::ValEntry *e0000 = gf->GetValEntry (0x0002,0x0000); if (e0000) { itksys_ios::ostringstream sLen; sLen << plm_ComputeGroup0002Length (gf); e0000->SetValue(sLen.str()); } /* Do the actual writing out to file */ gf->WriteContent (fp, gdcm::ExplicitVR); fp->close(); delete fp; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_rtss.h000066400000000000000000000016651321604176500277600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gdcm1_rtss_h_ #define _gdcm1_rtss_h_ #include "plmbase_config.h" #include "rt_study_metadata.h" #if PLM_DCM_USE_GDCM1 class Metadata; class Rtss; PLMBASE_API bool gdcm_rtss_probe (const char *rtss_fn); PLMBASE_API void gdcm_rtss_load ( Rtss *cxt, /* Output: this gets loaded into */ Rt_study_metadata *rsm, /* Output: this gets updated too */ const char *rtss_fn /* Input: the file that gets read */ ); PLMBASE_API void gdcm_rtss_save ( Rtss *cxt, /* Input: this is what gets saved */ const Rt_study_metadata::Pointer& rsm, /* In: need to look at this too */ const char *rtss_fn /* Input: name of file to write to */ ); #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_series.cxx000066400000000000000000000224701321604176500306270ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "itkGDCMImageIO.h" #include "itkGDCMSeriesFileNames.h" #include "gdcmFile.h" #include "gdcmFileHelper.h" #include "gdcmGlobal.h" #include "gdcmSeqEntry.h" #include "gdcmSQItem.h" #include "gdcmUtil.h" #include "gdcm1_series.h" #include "gdcm1_series_helper_2.h" #include "metadata.h" #include "plm_math.h" #include "plm_uid_prefix.h" #include "plm_version.h" #include "print_and_exit.h" #include "rt_study_metadata.h" void gdcm1_series_test (char *dicom_dir) { Gdcm_series gs; gs.load (dicom_dir); } static void digest_file_list ( gdcm::FileList *file_list, double origin[3], int dim[3], double spacing[3]) { int loop = 0; double prev_z = 0.0; // For all the files of a SingleSerieUID File set for (gdcm::FileList::iterator it = file_list->begin(); it != file_list->end(); ++it) { if (loop == 0) { spacing[0] = (*it)->GetXSpacing (); spacing[1] = (*it)->GetYSpacing (); origin[0] = (*it)->GetXOrigin (); origin[1] = (*it)->GetYOrigin (); prev_z = origin[2] = (*it)->GetZOrigin (); dim[0] = (*it)->GetXSize (); dim[1] = (*it)->GetYSize (); loop ++; } else if (loop == 1) { double z = (*it)->GetZOrigin (); if (z - prev_z > 1e-5) { spacing[2] = z - origin[2]; loop ++; } else { printf ("Warning: duplicate slice locations (%g)\n", z); } prev_z = z; } else { double z = (*it)->GetZOrigin (); if (z - prev_z > 1e-5) { //printf (">> %g %g %g\n", z, prev_z, spacing[2]); /* XiO rounds IPP to nearest .1 mm */ if (fabs (z - prev_z - spacing[2]) > 0.11) { print_and_exit ("Error: irregular slice spacing in dicom series\n"); } loop ++; } else { print_and_exit ("Error: duplicate slice locations (%g)\n", z); } prev_z = z; } } dim[2] = loop; } Gdcm_series::Gdcm_series (void) { this->m_gsh2 = 0; this->m_have_ct = 0; this->m_ct_file_list = 0; this->m_rtdose_file_list = 0; this->m_rtstruct_file_list = 0; } Gdcm_series::~Gdcm_series (void) { if (this->m_gsh2) { delete this->m_gsh2; } } void Gdcm_series::load (const char *dicom_dir) { bool recursive = false; this->m_gsh2 = new gdcm::SerieHelper2(); this->m_gsh2->Clear (); this->m_gsh2->SetUseSeriesDetails (true); // --------------------------------------------------------------------- // The below code is modified from CreateDefaultUniqueSeriesIdentifier. // If there was an API function called RemoveRestriction(), // we could call CreateDefaultUniqueSeriesIdentifier() and then // call RemoveRestriction(0x0018, 0x0050). // --------------------------------------------------------------------- // 0020 0011 Series Number // A scout scan prior to a CT volume scan can share the same // SeriesUID, but they will sometimes have a different Series Number this->m_gsh2->AddRestriction( 0x0020, 0x0011); // 0018 0024 Sequence Name // For T1-map and phase-contrast MRA, the different flip angles and // directions are only distinguished by the Sequence Name this->m_gsh2->AddRestriction(0x0018, 0x0024); // 0018 0050 Slice Thickness // On some CT systems, scout scans and subsequence volume scans will // have the same SeriesUID and Series Number - YET the slice // thickness will differ from the scout slice and the volume slices. // GCS: We don't want GDCM to use slice thickness to distinguish series. // CERR sets the slice thickness to different values within // a single series based on subtle differences in the Z position. // -- AddRestriction(0x0018, 0x0050); -- // 0028 0010 Rows // If the 2D images in a sequence don't have the same number of rows, // then it is difficult to reconstruct them into a 3D volume. this->m_gsh2->AddRestriction(0x0028, 0x0010); // 0028 0011 Columns // If the 2D images in a sequence don't have the same number of columns, // then it is difficult to reconstruct them into a 3D volume. this->m_gsh2->AddRestriction(0x0028, 0x0011); this->m_gsh2->SetDirectory (dicom_dir, recursive); #if defined (commentout) this->m_gsh2->Print (); #endif gdcm::FileList *file_list = this->m_gsh2->GetFirstSingleSerieUIDFileSet (); while (file_list) { if (file_list->size()) { this->m_gsh2->OrderFileList (file_list); #if defined (commentout) /* Choose one file, and print the id */ gdcm::File *file = (*file_list)[0]; std::string id = this->m_gsh2-> CreateUniqueSeriesIdentifier(file).c_str(); printf ("id = %s\n", id.c_str()); #endif } file_list = this->m_gsh2->GetNextSingleSerieUIDFileSet(); } } void Gdcm_series::digest_files (void) { int d; for (d = 0; d < 3; d++) { this->m_origin[d] = 0.0; this->m_dim[d] = 0; this->m_spacing[d] = 0.0; } if (!this->m_gsh2) { return; } gdcm::FileList *file_list = this->m_gsh2->GetFirstSingleSerieUIDFileSet (); while (file_list) { if (file_list->size()) { this->m_gsh2->OrderFileList (file_list); /* Get the USI */ gdcm::File *file = (*file_list)[0]; std::string id = this->m_gsh2-> CreateUniqueSeriesIdentifier(file).c_str(); #if defined (commentout) printf ("id = %s\n", id.c_str()); #endif /* Is this a CT? */ std::string modality = file->GetEntryValue (0x0008, 0x0060); if (modality == std::string ("CT")) { int dim[3] = {0, 0, 0}; double origin[3] = {0., 0., 0.}; double spacing[3] = {0., 0., 0.}; /* OK, I guess we have a CT */ this->m_have_ct = 1; /* Digest the USI */ digest_file_list (file_list, origin, dim, spacing); #if defined (commentout) printf ("---- %s\n", id.c_str()); printf ("DIM = %d %d %d\n", dim[0], dim[1], dim[2]); printf ("OFF = %g %g %g\n", origin[0], origin[1], origin[2]); printf ("SPA = %g %g %g\n", spacing[0], spacing[1], spacing[2]); #endif /* Pick the CT with the largest dim[2] */ if (dim[2] > this->m_dim[2]) { this->m_ct_file_list = file_list; for (d = 0; d < 3; d++) { this->m_origin[d] = origin[d]; this->m_dim[d] = dim[d]; this->m_spacing[d] = spacing[d]; } } } else if (modality == std::string ("RTDOSE")) { printf ("Found RTDOSE!\n"); this->m_rtdose_file_list = file_list; } else if (modality == std::string ("RTPLAN")) { //printf ("Found RTPLAN!\n"); } else if (modality == std::string ("RTSTRUCT")) { printf ("Found RTSTRUCT!\n"); this->m_rtstruct_file_list = file_list; } else { printf ("Found unknown modality %s\n", modality.c_str()); } } file_list = this->m_gsh2->GetNextSingleSerieUIDFileSet(); } } void Gdcm_series::get_slice_info ( int *slice_no, /* Output */ std::string *ct_slice_uid, /* Output */ float z /* Input */ ) { if (!this->m_have_ct) { return; } /* NOTE: This algorithm doesn't work if there are duplicate slices */ *slice_no = ROUND_INT ((z - this->m_origin[2]) / this->m_spacing[2]); if (*slice_no < 0 || *slice_no >= this->m_dim[2]) { *slice_no = -1; return; } gdcm::File *file = (*this->m_ct_file_list)[*slice_no]; if (!file) { print_and_exit ("Error finding slice %d in volume\n", *slice_no); } *ct_slice_uid = file->GetEntryValue (0x0008, 0x0018); } void Gdcm_series::get_slice_uids (Rt_study_metadata *rsm) { rsm->reset_slice_uids (); if (!this->m_have_ct) { return; } int i = 0; for (gdcm::FileList::iterator it = this->m_ct_file_list->begin(); it != this->m_ct_file_list->end(); ++it) { std::string slice_uid = (*it)->GetEntryValue (0x0008, 0x0018); rsm->set_slice_uid (i, slice_uid.c_str()); i++; } } gdcm::File* Gdcm_series::get_ct_slice (void) { if (!this->m_have_ct) { return 0; } return (*this->m_ct_file_list)[0]; } const std::string& Gdcm_series::get_rtdose_filename () { gdcm::File *file = (*(m_rtdose_file_list))[0]; return file->GetFileName(); } const std::string& Gdcm_series::get_rtstruct_filename () { gdcm::File *file = (*(m_rtstruct_file_list))[0]; return file->GetFileName(); } std::string Gdcm_series::get_patient_position () { gdcm::File* file = this->get_ct_slice (); std::string tmp; /* Get patient position */ tmp = file->GetEntryValue (0x0018, 0x5100); if (tmp == gdcm::GDCM_UNFOUND) { tmp = ""; } return tmp; } void Gdcm_series::get_metadata (const Metadata::Pointer& meta) { if (m_have_ct) { gdcm::File *file = (*this->m_ct_file_list)[0]; #if defined (commentout) meta->m_patient_name = file->GetEntryValue(0x0010, 0x0010).c_str(); meta->m_patient_id = file->GetEntryValue(0x0010, 0x0020).c_str(); meta->m_patient_sex = file->GetEntryValue(0x0010, 0x0040).c_str(); #endif meta->set_metadata ( meta->make_key (0x0010, 0x0010), file->GetEntryValue(0x0010, 0x0010)); meta->set_metadata ( meta->make_key (0x0010, 0x0020), file->GetEntryValue(0x0010, 0x0020)); meta->set_metadata ( meta->make_key (0x0010, 0x0040), file->GetEntryValue(0x0010, 0x0040)); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_series.h000066400000000000000000000024511321604176500302510ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gdcm1_series_h_ #define _gdcm1_series_h_ #include "plmbase_config.h" #include "sys/plm_int.h" #include #include #include #include "metadata.h" class Rt_study_metadata; /* Forward declarations */ namespace gdcm { class File; typedef std::vector FileList; class SerieHelper2; }; class PLMBASE_API Gdcm_series { public: Gdcm_series (); ~Gdcm_series (); void load (const char *dicom_dir); void digest_files (void); void get_slice_info (int *slice_no, std::string *ct_slice_uid, float z); gdcm::File *get_ct_slice (void); void get_slice_uids (Rt_study_metadata *rsm); std::string get_patient_position (); const std::string& get_rtdose_filename (); const std::string& get_rtstruct_filename (); void get_metadata (const Metadata::Pointer& meta); gdcm::SerieHelper2 *m_gsh2; int m_have_ct; gdcm::FileList *m_ct_file_list; gdcm::FileList *m_rtdose_file_list; gdcm::FileList *m_rtstruct_file_list; plm_long m_dim[3]; double m_origin[3]; double m_spacing[3]; }; #endif gdcm1_series_helper_2.cxx000066400000000000000000000714611321604176500323340ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/*========================================================================= Program: gdcm Module: $RCSfile: gdcmSerieHelper.cxx,v $ Language: C++ Date: $Date: 2007-06-18 10:20:26 $ Version: $Revision: 1.25 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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 "plmbase_config.h" #include #include #include #include #include #include "gdcmDirList.h" #include "gdcmFile.h" #include "gdcmDictEntry.h" // for TranslateToKey #include "gdcmDebug.h" #include "gdcmUtil.h" #include "gdcm1_series_helper_2.h" namespace gdcm { //----------------------------------------------------------------------------- // Constructor / Destructor /** * brief Constructor from a given SerieHelper2 */ SerieHelper2::SerieHelper2() { m_UseSeriesDetails = false; ClearAll(); UserLessThanFunction = 0; DirectOrder = true; LoadMode = 0; } /** * brief Canonical destructor. */ SerieHelper2::~SerieHelper2() { ClearAll(); } /** * brief Preventively, clear everything at constructor time. * ( use it at destructor time.) */ void SerieHelper2::ClearAll() { // For all the 'Single SerieUID' Filesets that may already exist FileList *l = GetFirstSingleSerieUIDFileSet(); while (l) { // For all the gdcm::File of a File set for (gdcm::FileList::iterator it = l->begin(); it != l->end(); ++it) { delete *it; // remove each entry } l->clear(); delete l; // remove the container l = GetNextSingleSerieUIDFileSet(); } // Need to clear that too: SingleSerieUIDFileSetHT.clear(); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Public /** * brief add a gdcm::File to the Fileset corresponding to its Serie UID * @param filename Name of the file to deal with */ void SerieHelper2::AddFileName(std::string const &filename) { // Create a DICOM file File *header = new File (); header->SetLoadMode(LoadMode); header->SetFileName( filename ); //printf ("------ AddFileName (%s)\n", filename.c_str()); header->Load(); /* GCS: Sept 12, 2009. gdcm::File::IsReadable() is too strict about which tags are required. Therefore non-image files such as dicomrt will not show up in the list of series. */ if (header->IsParsable()) { if ( !AddFile( header ) ) { // at least one rule was unmatched we need to deallocate the file: delete header; } } else { //printf ("Header not readable: %s\n", filename.c_str()); gdcmWarningMacro("Could not read file: " << filename ); delete header; } } /** * brief add a gdcm::File to the first (and supposed to be unique) file set * of the gdcm::SerieHelper2. * \warning : this method should be used by aware users only! * Passing a gdcm::File* has the same effect than passing a file name! * \todo : decide which one is wrong (the method, or the commentary)! * the following comment doesn't match the method :-( * User is supposed to know the files he want to deal with * and consider them they belong to the same Serie * (even if their Serie UID is different) * user will probabely OrderFileList() this list (actually, ordering * user choosen gdm::File is the sole interest of this method) * Moreover, using vtkGdcmReader::SetCoherentFileList() will avoid * vtkGdcmReader parsing twice the same files. * *no* coherence check is performed, but those specified * by SerieHelper2::AddRestriction() * @param header gdcm::File* of the file to deal with * @return true if file was added, false if file was rejected */ bool SerieHelper2::AddFile(File *header) { int allrules = 1; // First step the user has defined a set of rules for the DICOM // he is looking for. // make sure the file correspond to his set of rules: std::string debug_string = header->GetEntryValue (0x0010, 0x0010); printf ("Patient ID = %s\n", debug_string.c_str()); std::string s; for(SerieExRestrictions::iterator it2 = ExRestrictions.begin(); it2 != ExRestrictions.end(); ++it2) { const ExRule &r = *it2; s = header->GetEntryValue( r.group, r.elem ); if ( !Util::CompareDicomString(s, r.value.c_str(), r.op) ) { printf ("Failed comparison: 0x%04x 0x%04x\n", r.group, r.elem); // Argh ! This rule is unmatched; let's just quit allrules = 0; break; } } if ( allrules ) // all rules are respected: { // Allright! we have a found a DICOM that matches the user expectation. // Let's add it to the specific 'id' which by default is uid (Serie UID) // but can be `refined` by user with more paramater (see AddRestriction(g,e)) std::string id = CreateUniqueSeriesIdentifier( header ); // if id == GDCM_UNFOUND then consistently we should find GDCM_UNFOUND // no need here to do anything special if ( SingleSerieUIDFileSetHT.count(id) == 0 ) { gdcmDebugMacro(" New Serie UID :[" << id << "]"); // create a std::list in 'id' position SingleSerieUIDFileSetHT[id] = new FileList; } // Current Serie UID and DICOM header seems to match add the file: SingleSerieUIDFileSetHT[id]->push_back( header ); } else { // one rule not matched, tell user: return false; } return true; } /** * brief add a rule for restricting a DICOM file to be in the serie we are * trying to find. For example you can select only the DICOM files from a * directory which would have a particular EchoTime==4.0. * This method is a user level, value is not required to be formatted as a DICOM * string * \todo find a trick to allow user to say if he wants the Rectrictions * to be *ored* (and not only *anded*) * @param group Group number of the target tag. * @param elem Element number of the target tag. * @param value value to be checked to exclude File * @param op operator we want to use to check */ void SerieHelper2::AddRestriction(uint16_t group, uint16_t elem, std::string const &value, int op) { ExRule r; r.group = group; r.elem = elem; r.value = value; r.op = op; ExRestrictions.push_back( r ); } void SerieHelper2::AddRestriction(uint16_t group, uint16_t elem) { ExRule r; r.group = group; r.elem = elem; ExRefine.push_back( r ); } #ifndef GDCM_LEGACY_REMOVE /** * brief add a rule for restricting a DICOM file to be in the serie we are * trying to find. For example you can select only the DICOM files from a * directory which would have a particular EchoTime==4.0. * This method is a user level, value is not required to be formatted as a DICOM * string * @param group Group number of the target tag. * @param elem Element number of the target tag. * @param value value to be checked to exclude File * @deprecated use : AddRestriction(uint16_t group, uint16_t elem, * std::string const &value, int op); */ void SerieHelper2::AddRestriction(TagKey const &key, std::string const &value) { Rule r; r.first = key; r.second = value; Restrictions.push_back( r ); } #endif /** * brief Sets the root Directory * @param dir Name of the directory to deal with * @param recursive whether we want explore recursively the root Directory */ void SerieHelper2::SetDirectory(std::string const &dir, bool recursive) { DirList dirList(dir, recursive); // OS specific DirListType filenames_list = dirList.GetFilenames(); for( DirListType::const_iterator it = filenames_list.begin(); it != filenames_list.end(); ++it) { AddFileName( *it ); } } /** * brief Sorts the given Fileset * \warning This could be implemented in a 'Strategy Pattern' approach * But as I don't know how to do it, I leave it this way * BTW, this is also a Strategy, I don't know this is * the best approach :) */ void SerieHelper2::OrderFileList(FileList *fileSet) { if ( SerieHelper2::UserLessThanFunction ) { UserOrdering( fileSet ); return; } else if ( ImagePositionPatientOrdering( fileSet ) ) { return ; } else if ( ImageNumberOrdering(fileSet ) ) { return ; } else { FileNameOrdering(fileSet ); } } /** * brief Elementary coherence checking of the files with the same Serie UID * Only sizes and pixel type are checked right now ... */ bool SerieHelper2::IsCoherent(FileList *fileSet) { if(fileSet->size() == 1) return true; FileList::const_iterator it = fileSet->begin(); int nX = (*it)->GetXSize(); int nY = (*it)->GetYSize(); int pixelSize = (*it)->GetPixelSize(); bool signedPixelData = (*it)->IsSignedPixelData(); it ++; for ( ; it != fileSet->end(); ++it) { if ( (*it)->GetXSize() != nX ) return false; if ( (*it)->GetYSize() != nY ) return false; if ( (*it)->GetPixelSize() != pixelSize ) return false; if ( (*it)->IsSignedPixelData() != signedPixelData ) return false; // probabely more is to be checked (?) } return true; } #ifndef GDCM_LEGACY_REMOVE /** * brief accessor (DEPRECATED : use GetFirstSingleSerieUIDFileSet ) * Warning : 'coherent' means here they have the same Serie UID * @return The first FileList if found, otherwhise NULL */ FileList *SerieHelper2::GetFirstCoherentFileList() { ItFileSetHt = SingleSerieUIDFileSetHT.begin(); if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() ) return ItFileSetHt->second; return NULL; } /** * brief accessor (DEPRECATED : use GetNextSingleSerieUIDFileSet ) * Warning : 'coherent' means here they have the same Serie UID * \note : meaningfull only if GetFirstCoherentFileList() already called * @return The next FileList if found, otherwhise NULL */ FileList *SerieHelper2::GetNextCoherentFileList() { gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end()); ++ItFileSetHt; if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() ) return ItFileSetHt->second; return NULL; } /** * brief accessor (DEPRECATED : use GetSingleSerieUIDFileSet ) * Warning : 'coherent' means here they have the same Serie UID * @param SerieUID SerieUID * \return pointer to the FileList if found, otherwhise NULL */ FileList *SerieHelper2::GetCoherentFileList(std::string SerieUID) { if ( SingleSerieUIDFileSetHT.count(SerieUID) == 0 ) return 0; return SingleSerieUIDFileSetHT[SerieUID]; } #endif /** * brief Get the first Fileset while visiting the SingleSerieUIDFileSetmap * @return The first FileList (SingleSerieUIDFileSet) if found, otherwhise 0 */ FileList *SerieHelper2::GetFirstSingleSerieUIDFileSet() { ItFileSetHt = SingleSerieUIDFileSetHT.begin(); if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() ) return ItFileSetHt->second; return NULL; } /** * brief Get the next Fileset while visiting the SingleSerieUIDFileSetmap * \note : meaningfull only if GetNextSingleSerieUIDFileSet() already called * @return The next FileList (SingleSerieUIDFileSet) if found, otherwhise 0 */ FileList *SerieHelper2::GetNextSingleSerieUIDFileSet() { gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end()); ++ItFileSetHt; if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() ) return ItFileSetHt->second; return NULL; } /** * brief Get the SingleSerieUIDFileSet according to its Serie UID * @param SerieUID SerieUID to retrieve * \return pointer to the FileList (SingleSerieUIDFileSet) if found, otherwhise 0 */ FileList *SerieHelper2::GetSingleSerieUIDFileSet(std::string SerieUID) { if ( SingleSerieUIDFileSetHT.count(SerieUID) == 0 ) return 0; return SingleSerieUIDFileSetHT[SerieUID]; } /** * brief Splits a Single SerieUID Fileset according to the Orientations * @param fileSet File Set to be splitted * \return std::map of 'Xcoherent' File sets */ XCoherentFileSetmap SerieHelper2::SplitOnOrientation(FileList *fileSet) { XCoherentFileSetmap CoherentFileSet; size_t nb = fileSet->size(); if (nb == 0 ) return CoherentFileSet; float iop[6]; std::string strOrient; itksys_ios::ostringstream ossOrient; FileList::const_iterator it = fileSet->begin(); for ( ; it != fileSet->end(); ++it) { // Information is in : // 0020 0037 : Image Orientation (Patient) or // 0020 0035 : Image Orientation (RET) // Let's build again the 'cosines' string, to be sure of it's format (*it)->GetImageOrientationPatient(iop); ossOrient << iop[0]; for (int i = 1; i < 6; i++) { ossOrient << "\\"; ossOrient << iop[i]; } strOrient = ossOrient.str(); ossOrient.str(""); if ( CoherentFileSet.count(strOrient) == 0 ) { gdcmDebugMacro(" New Orientation :[" << strOrient << "]"); // create a File set in 'orientation' position CoherentFileSet[strOrient] = new FileList; } // Current Orientation and DICOM header match; add the file: CoherentFileSet[strOrient]->push_back( (*it) ); } return CoherentFileSet; } /** * brief Splits a 'Single SerieUID' Fileset according to the Positions * @param fileSet File Set to be splitted * \return std::map of 'Xcoherent' File sets */ XCoherentFileSetmap SerieHelper2::SplitOnPosition(FileList *fileSet) { XCoherentFileSetmap CoherentFileSet; size_t nb = fileSet->size(); if (nb == 0 ) return CoherentFileSet; float pos[3]; std::string strImPos; // read on disc itksys_ios::ostringstream ossPosition; std::string strPosition; // re computed FileList::const_iterator it = fileSet->begin(); for ( ; it != fileSet->end(); ++it) { // Information is in : // 0020,0032 : Image Position Patient // 0020,0030 : Image Position (RET) strImPos = (*it)->GetEntryValue(0x0020,0x0032); if ( strImPos == GDCM_UNFOUND) { gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)"); strImPos = (*it)->GetEntryValue(0x0020,0x0030); // For ACR-NEMA images if ( strImPos == GDCM_UNFOUND ) { gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)"); // User wants to split on the 'Position' // No 'Position' info found. // We return an empty Htable ! return CoherentFileSet; } } if ( sscanf( strImPos.c_str(), "%f \\%f \\%f ", &pos[0], &pos[1], &pos[2]) != 3 ) { gdcmWarningMacro( "Wrong number for Position : [" << strImPos << "]" ); return CoherentFileSet; } // Let's build again the 'position' string, to be sure of it's format ossPosition << pos[0]; for (int i = 1; i < 3; i++) { ossPosition << "\\"; ossPosition << pos[i]; } strPosition = ossPosition.str(); ossPosition.str(""); if ( CoherentFileSet.count(strPosition) == 0 ) { gdcmDebugMacro(" New Position :[" << strPosition << "]"); // create a File set in 'position' position CoherentFileSet[strPosition] = new FileList; } // Current Position and DICOM header match; add the file: CoherentFileSet[strPosition]->push_back( (*it) ); } return CoherentFileSet; } /** * brief Splits a 'Single SerieUID' File set Coherent according to the * value of a given Tag * @param fileSet File Set to be splitted * @param group group number of the target Element * @param elem element number of the target Element * \return std::map of 'Xcoherent' File sets */ XCoherentFileSetmap SerieHelper2::SplitOnTagValue(FileList *fileSet, uint16_t group, uint16_t element) { XCoherentFileSetmap CoherentFileSet; size_t nb = fileSet->size(); if (nb == 0 ) return CoherentFileSet; std::string strTagValue; // read on disc FileList::const_iterator it = fileSet->begin(); for ( ; it != fileSet->end(); ++it) { // Information is in : // 0020,0032 : Image Position Patient // 0020,0030 : Image Position (RET) strTagValue = (*it)->GetEntryValue(group,element); if ( CoherentFileSet.count(strTagValue) == 0 ) { gdcmDebugMacro(" New Tag Value :[" << strTagValue << "]"); // create a File set in 'position' position CoherentFileSet[strTagValue] = new FileList; } // Current Tag value and DICOM header match; add the file: CoherentFileSet[strTagValue]->push_back( (*it) ); } return CoherentFileSet; } //----------------------------------------------------------------------------- // Protected //----------------------------------------------------------------------------- // Private /** * brief sorts the images, according to their Patient Position. * * We may order, considering : * -# Image Position Patient * -# Image Number * -# file name * -# More to come :-) * \note : FileList = std::vector * @param fileList Coherent File list (same Serie UID) to sort * @return false only if the header is bugged ! */ bool SerieHelper2::ImagePositionPatientOrdering( FileList *fileList ) //based on Jolinda Smith's algorithm { //iop is calculated based on the file file float cosines[6]; double normal[3] = {0., 0., 0.}; double ipp[3]; double dist; double min = 0, max = 0; bool first = true; std::multimap distmultimap; // Use a multimap to sort the distances from 0,0,0 for ( FileList::const_iterator it = fileList->begin(); it != fileList->end(); ++it ) { if ( first ) { (*it)->GetImageOrientationPatient( cosines ); // You only have to do this once for all slices in the volume. Next, // for each slice, calculate the distance along the slice normal // using the IPP ("Image Position Patient") tag. // ("dist" is initialized to zero before reading the first slice) : normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4]; normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5]; normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3]; ipp[0] = (*it)->GetXOrigin(); ipp[1] = (*it)->GetYOrigin(); ipp[2] = (*it)->GetZOrigin(); dist = 0; for ( int i = 0; i < 3; ++i ) { dist += normal[i]*ipp[i]; } distmultimap.insert(std::pair(dist, *it)); max = min = dist; first = false; } else { ipp[0] = (*it)->GetXOrigin(); ipp[1] = (*it)->GetYOrigin(); ipp[2] = (*it)->GetZOrigin(); dist = 0; for ( int i = 0; i < 3; ++i ) { dist += normal[i]*ipp[i]; } distmultimap.insert(std::pair(dist, *it)); min = (min < dist) ? min : dist; max = (max > dist) ? max : dist; } } // Find out if min/max are coherent if ( min == max ) { gdcmWarningMacro("Looks like all images have the exact same image position" << ". No PositionPatientOrdering sort performed" ); return false; } // Check to see if image shares a common position bool ok = true; for (std::multimap::iterator it2 = distmultimap.begin(); it2 != distmultimap.end(); ++it2) { if (distmultimap.count((*it2).first) != 1) { gdcmErrorMacro("File: " << ((*it2).second->GetFileName()) << " Distance: " << (*it2).first << " position is not unique"); ok = false; } } if (!ok) { return false; } fileList->clear(); // doesn't delete list elements, only nodes if (DirectOrder) { for (std::multimap::iterator it3 = distmultimap.begin(); it3 != distmultimap.end(); ++it3) { fileList->push_back( (*it3).second ); } } else // user asked for reverse order { std::multimap::const_iterator it4; it4 = distmultimap.end(); do { it4--; fileList->push_back( (*it4).second ); } while (it4 != distmultimap.begin() ); } distmultimap.clear(); return true; } //----------------------------------------------------------------------------- static bool ImageNumberLessThan(File *file1, File *file2) { return file1->GetImageNumber() < file2->GetImageNumber(); } static bool ImageNumberGreaterThan (File *file1, File *file2) { return file1->GetImageNumber() > file2->GetImageNumber(); } static bool FileNameLessThan (File *file1, File *file2) { return file1->GetFileName() < file2->GetFileName(); } static bool FileNameGreaterThan (File *file1, File *file2) { return file1->GetFileName() > file2->GetFileName(); } class SortFunctor { public: bool operator() (File *file1, File *file2) { return (SortFunction)(file1, file2); } BOOL_FUNCTION_PFILE_PFILE_POINTER SortFunction; SortFunctor() { SortFunction = 0; } SortFunctor(SortFunctor const &sf) { SortFunction = sf.SortFunction; } void operator=(BOOL_FUNCTION_PFILE_PFILE_POINTER sf) { SortFunction = sf; } }; //----------------------------------------------------------------------------- // Sort /** * brief Sort FileList. */ static void Sort(FileList *fileList, SortFunctor &sf) { std::sort(fileList->begin(), fileList->end(), sf ); } /** * brief sorts the images, according to their Image Number * \note Works only on bona fide files (i.e image number is a character string * corresponding to an integer) * within a bona fide serie (i.e image numbers are consecutive) * @param fileList File set (same Serie UID) to sort * @return false if non bona fide stuff encountered */ bool SerieHelper2::ImageNumberOrdering(FileList *fileList) { int min, max, pos; size_t n = fileList->size(); FileList::const_iterator it = fileList->begin(); min = max = (*it)->GetImageNumber(); for (; it != fileList->end(); ++it, ++n) { pos = (*it)->GetImageNumber(); min = (min < pos) ? min : pos; max = (max > pos) ? max : pos; } // Find out if image numbers are coherent (consecutive) if ( min == max || max == 0 || max >= (static_cast(n)+min) ) { gdcmWarningMacro( " 'Image numbers' not coherent. " << " No ImageNumberOrdering sort performed."); return false; } SortFunctor sf; if (DirectOrder) sf = ImageNumberLessThan; else sf = ImageNumberGreaterThan; Sort(fileList, sf); return true; } /** * brief sorts the images, according to their File Name * @param fileList Coherent File list (same Serie UID) to sort * @return false only if the header is bugged ! */ bool SerieHelper2::FileNameOrdering(FileList *fileList) { SortFunctor sf; if (DirectOrder) sf = FileNameLessThan; else sf = FileNameGreaterThan; Sort(fileList, sf); return true; } /** * brief sorts the images, according to user supplied function * @param fileList Coherent File list (same Serie UID) to sort * @return false only if the header is bugged ! */ bool SerieHelper2::UserOrdering(FileList *fileList) { SortFunctor sf; sf = SerieHelper2::UserLessThanFunction; Sort(fileList,sf); if (!DirectOrder) { std::reverse(fileList->begin(), fileList->end()); } return true; } //----------------------------------------------------------------------------- // Print /** * brief Canonical printer. */ void SerieHelper2::Print(std::ostream &os, std::string const &indent) { // For all the Coherent File lists of the gdcm::Serie SingleSerieUIDFileSetmap::iterator itl = SingleSerieUIDFileSetHT.begin(); if ( itl == SingleSerieUIDFileSetHT.end() ) { gdcmWarningMacro( "No SingleSerieUID File set found" ); return; } while (itl != SingleSerieUIDFileSetHT.end()) { os << "Serie UID :[" << itl->first << "]" << std::endl; // For all the files of a SingleSerieUID File set for (FileList::iterator it = (itl->second)->begin(); it != (itl->second)->end(); ++it) { os << indent << " --- " << (*it)->GetFileName() << std::endl; } ++itl; } } void SerieHelper2::CreateDefaultUniqueSeriesIdentifier() { // If the user requests, additional information can be appended // to the SeriesUID to further differentiate volumes in the DICOM // objects being processed. // 0020 0011 Series Number // A scout scan prior to a CT volume scan can share the same // SeriesUID, but they will sometimes have a different Series Number AddRestriction( 0x0020, 0x0011); // 0018 0024 Sequence Name // For T1-map and phase-contrast MRA, the different flip angles and // directions are only distinguished by the Sequence Name AddRestriction(0x0018, 0x0024); // 0018 0050 Slice Thickness // On some CT systems, scout scans and subsequence volume scans will // have the same SeriesUID and Series Number - YET the slice // thickness will differ from the scout slice and the volume slices. AddRestriction(0x0018, 0x0050); // 0028 0010 Rows // If the 2D images in a sequence don't have the same number of rows, // then it is difficult to reconstruct them into a 3D volume. AddRestriction(0x0028, 0x0010); // 0028 0011 Columns // If the 2D images in a sequence don't have the same number of columns, // then it is difficult to reconstruct them into a 3D volume. AddRestriction(0x0028, 0x0011); } /** * brief Heuristics to *try* to build a Serie Identifier that would ensure * all the images are coherent. * * By default, uses the SeriesUID. If UseSeriesDetails(true) has been called, * then additional identifying information is used. * We allow user to add his own critierions, using AddSeriesDetail * (he knows more than we do about his images!) * ex : in tagging series, the only pertnent tag is * 0018|1312 [In-plane Phase Encoding Direction] value : ROW/COLUMN * @param inFile gdcm::File we want to build a Serie Identifier for. * @return the SeriesIdentifier */ std::string SerieHelper2::CreateUniqueSeriesIdentifier( File *inFile ) { /* GCS: Sept 12, 2009. gdcm::File::IsReadable() is too strict about which tags are required. Therefore non-image files such as dicomrt will not show up in the list of series. */ if (inFile->IsParsable()) { // 0020 000e UI REL Series Instance UID std::string uid = inFile->GetEntryValue (0x0020, 0x000e); std::string id = uid.c_str(); if(m_UseSeriesDetails) { for(SerieExRestrictions::iterator it2 = ExRefine.begin(); it2 != ExRefine.end(); ++it2) { const ExRule &r = *it2; std::string s = inFile->GetEntryValue( r.group, r.elem ); if( s == gdcm::GDCM_UNFOUND ) { s = ""; } //if( id == uid && !s.empty() ) if( !s.empty() ) { id += ";"; // add separator } id += s; } } // Eliminate non-alnum characters, including whitespace... // that may have been introduced by concats. for(size_t i=0; i= 'a' && id[i] <= 'z') || (id[i] >= '0' && id[i] <= '9') || (id[i] >= 'A' && id[i] <= 'Z'))) { id.erase(i, 1); } } return id; } else // Could not open inFile { gdcmWarningMacro("Could not parse series info."); std::string id = gdcm::GDCM_UNFOUND; return id; } } //----------------------------------------------------------------------------- } // end namespace gdcm gdcm1_series_helper_2.h000066400000000000000000000213361321604176500317550ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/*========================================================================= Program: gdcm Module: $RCSfile: gdcmSerieHelper.h,v $ Language: C++ Date: $Date: 2008-05-14 12:25:32 $ Version: $Revision: 1.14 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html 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. =========================================================================*/ #ifndef _gdcm1_series_helper_ #define _gdcm1_series_helper_ #include "plmbase_config.h" #include "gdcmCommon.h" #include "gdcmDebug.h" // for LEGACY #include #include #include #include // for sscanf namespace gdcm { class File; typedef std::vector FileList; #ifndef GDCM_LEGACY_REMOVE typedef std::vector GdcmFileList; #endif /// XCoherent stands for 'Extra Coherent', /// (The name 'Coherent' would be enough but it was used before; /// I don't want to put a bomb in the code) /// Any 'better name' is welcome ! typedef std::map XCoherentFileSetmap; typedef bool (*BOOL_FUNCTION_PFILE_PFILE_POINTER)(File *, File *); //----------------------------------------------------------------------------- /* * This class should be used for a stack of 2D dicom images. * * - It allows to explore (recursively or not) a directory and * makes a set of 'Coherent Files' lists (coherent : same SerieUID) * - It allows : * - - to sort any of the Coherent File list on the image position. * - - to split any of the Single SerieUID Filesets (better use this name than * 'Coherent File List' : it's NOT a std::list, files are NOT coherent ...) * into several XCoherent Filesets * XCoherent stands for 'Extra Coherent' (same orientation, or same position) */ class GDCM_EXPORT SerieHelper2 { public: /// SingleSerieUIDFileSetmap replaces the former CoherentFileListmap /// ( List were actually std::vectors, and wher no coherent at all : /// They were only Single SeriesInstanceUID File sets) typedef std::map SingleSerieUIDFileSetmap; typedef std::map SingleSerieUIDSeriesSetmap; typedef std::vector FileVector; SerieHelper2(); ~SerieHelper2(); void Print(std::ostream &os = std::cout, std::string const &indent = "" ); /// \todo should return bool or throw error ? void AddFileName(std::string const &filename); bool AddFile(File *header); #ifndef GDCM_LEGACY_REMOVE bool AddGdcmFile(File* header) { return AddFile(header); } #endif void SetDirectory(std::string const &dir, bool recursive=false); bool IsCoherent(FileList *fileSet); void OrderFileList(FileList *fileSet); void Clear() { ClearAll(); } /// brief Gets the FIRST Single SerieUID Fileset. /// Deprecated; kept not to break the API /// note Caller must call OrderFileList first /// return the (first) Single SerieUID Fileset const FileList &GetFileList() { return *SingleSerieUIDFileSetHT.begin()->second; } GDCM_LEGACY( FileList *GetFirstCoherentFileList() ) GDCM_LEGACY( FileList *GetNextCoherentFileList() ) GDCM_LEGACY( FileList *GetCoherentFileList(std::string serieUID) ) FileList *GetFirstSingleSerieUIDFileSet(); FileList *GetNextSingleSerieUIDFileSet(); FileList *GetSingleSerieUIDFileSet(std::string serieUID); /// brief returns the 'Series Instance UID' Single SerieUID FileSet std::string GetCurrentSerieUIDFileSetUID() { return (*ItFileSetHt).first; } /// All the following allow user to restrict DICOM file to be part /// of a particular serie GDCM_LEGACY( void AddRestriction(TagKey const &key, std::string const &value) ) /// Allow user to specify that the serie should also be consistent (== operation), /// on the particular tag (group,element) void AddRestriction(uint16_t group, uint16_t elem); /// Same as above accept use the format: "0x1234|0x5678" void AddRestriction(const std::string & tag) { unsigned int group, element; sscanf( tag.c_str(), "%04x|%04x", &group, &element); AddRestriction( group, element ); } /// Allow user to refine the selection of a serie by specifying operation (op) on a /// particular tag (group, elem) with a particular value (value). void AddRestriction(uint16_t group, uint16_t elem, std::string const &value, int op); /// brief Use additional series information such as ProtocolName /// and SeriesName to identify when a single SeriesUID contains /// multiple 3D volumes - as can occur with perfusion and DTI imaging void SetUseSeriesDetails( bool useSeriesDetails ) { m_UseSeriesDetails = useSeriesDetails; } bool GetUseSeriesDetails() { return m_UseSeriesDetails; } /// brief This function will add the following DICOM tag as being part of a /// 'fake' uid. This is usefull when the Serie UID is not enough to disseminate /// into multiple sub serie when needed: /// 0020 0011 Series Number /// 0018 0024 Sequence Name /// 0018 0050 Slice Thickness /// 0028 0010 Rows /// 0028 0011 Columns void CreateDefaultUniqueSeriesIdentifier(); /// brief Create a string that uniquely identifies a series. By default // uses the SeriesUID. If UseSeriesDetails(true) has been called, // then additional identifying information is used. std::string CreateUniqueSeriesIdentifier( File * inFile ); /** * brief Sets the LoadMode as a boolean string. * LD_NOSEQ, LD_NOSHADOW, LD_NOSHADOWSEQ * ... (nothing more, right now) * WARNING : before using LD_NOSHADOW, be sure *all* your files * contain accurate values in the 0x0000 element (if any) * of *each* Shadow Group. The parser will fail if the size is wrong ! * @param mode Load mode to be used */ void SetLoadMode (int mode) { LoadMode = mode; } /// Brief User wants the files to be sorted Direct Order (default value) void SetSortOrderToDirect() { DirectOrder = true; } /// Brief User wants the files to be sorted Reverse Order void SetSortOrderToReverse() { DirectOrder = false; } /// to allow user to give is own comparison function void SetUserLessThanFunction( BOOL_FUNCTION_PFILE_PFILE_POINTER userFunc ) { UserLessThanFunction = userFunc; } XCoherentFileSetmap SplitOnOrientation(FileList *fileSet); XCoherentFileSetmap SplitOnPosition(FileList *fileSet); XCoherentFileSetmap SplitOnTagValue(FileList *fileSet, uint16_t group, uint16_t element); private: void ClearAll(); bool UserOrdering(FileList *fileSet); bool ImagePositionPatientOrdering(FileList *fileSet); bool ImageNumberOrdering(FileList *fileSet); bool FileNameOrdering(FileList *fileSet); //Attributes: SingleSerieUIDFileSetmap SingleSerieUIDFileSetHT; SingleSerieUIDFileSetmap::iterator ItFileSetHt; #ifndef GDCM_LEGACY_REMOVE typedef std::pair Rule; typedef std::vector SerieRestrictions; SerieRestrictions Restrictions; #endif public: // New style for (extented) Rules typedef struct { uint16_t group; uint16_t elem; std::string value; int op; } ExRule; typedef std::vector SerieExRestrictions; private: SerieExRestrictions ExRestrictions; SerieExRestrictions ExRefine; /// brief Bit string integer (each one considered as a boolean) /// Bit 0 : Skip Sequences, if possible /// Bit 1 : Skip Shadow Groups if possible /// Probabely, some more to add int LoadMode; /// brief whether we want to sort in direct order or not (reverse order). /// To be used by aware user only bool DirectOrder; /// brief If user knows more about his images than gdcm does, /// he may supply his own comparison function. BOOL_FUNCTION_PFILE_PFILE_POINTER UserLessThanFunction; bool m_UseSeriesDetails; }; } // end namespace gdcm //----------------------------------------------------------------------------- #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_util.cxx000066400000000000000000000026131321604176500303070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "gdcmBinEntry.h" #include "gdcmFile.h" #include "gdcmUtil.h" #include "gdcm1_util.h" #include "metadata.h" /* winbase.h defines GetCurrentTime which conflicts with gdcm function */ #if defined GetCurrentTime # undef GetCurrentTime #endif void gdcm1_get_date_time ( std::string *date, std::string *time ) { *date = gdcm::Util::GetCurrentDate(); *time = gdcm::Util::GetCurrentTime(); } void set_metadata_from_gdcm_file ( Metadata::Pointer& meta, /* const */ gdcm::File *gdcm_file, unsigned short group, unsigned short elem ) { std::string tmp = gdcm_file->GetEntryValue (group, elem); if (tmp != gdcm::GDCM_UNFOUND) { meta->set_metadata (group, elem, tmp); } } void set_gdcm_file_from_metadata ( gdcm::File *gdcm_file, const Metadata::Pointer& meta, unsigned short group, unsigned short elem ) { gdcm_file->InsertValEntry ( meta->get_metadata (group, elem), group, elem); } char* gdcm_uid (char *uid, const char *uid_root) { std::string uid_s = gdcm::Util::CreateUniqueUID (uid_root); strcpy (uid, uid_s.c_str()); return uid; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm1_util.h000066400000000000000000000015211321604176500277310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gdcm1_util_h_ #define _gdcm1_util_h_ #include "plmbase_config.h" #include "metadata.h" #if PLM_DCM_USE_GDCM1 class Metadata; namespace gdcm { class File; }; void gdcm1_get_date_time ( std::string *date, std::string *time ); void set_metadata_from_gdcm_file ( Metadata::Pointer& meta, /* const */ gdcm::File *gdcm_file, unsigned short group, unsigned short elem ); void set_gdcm_file_from_metadata ( gdcm::File *gdcm_file, const Metadata::Pointer& meta, unsigned short group, unsigned short elem ); char* gdcm_uid (char *uid, const char *uid_root); #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm2_util.cxx000066400000000000000000000024231321604176500303070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "gdcmSystem.h" #include "gdcmUIDGenerator.h" #include "gdcm2_util.h" #include "metadata.h" namespace gdcm { class File; }; void gdcm2_get_date_time ( std::string *date, std::string *time ) { char datetime[22]; gdcm::System::GetCurrentDateTime (datetime); char c_date[9]; char c_time[14]; memcpy (c_date, datetime, 8); c_date[8] = 0; memcpy (c_time, datetime+8, 13); c_time[13] = 0; *date = c_date; *time = c_time; } void set_metadata_from_gdcm_file ( Metadata *meta, /* const */ gdcm::File *gdcm_file, unsigned short group, unsigned short elem ) { } void set_gdcm_file_from_metadata ( gdcm::File *gdcm_file, const Metadata *meta, unsigned short group, unsigned short elem ) { } char* gdcm_uid (char *uid, const char *uid_root) { gdcm::UIDGenerator generator; generator.SetRoot (uid_root); const char *uid_g = generator.Generate (); strcpy (uid, uid_g); return uid; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/gdcm2_util.h000066400000000000000000000014741321604176500277410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gdcm2_util_h_ #define _gdcm2_util_h_ #include "plmbase_config.h" #if PLM_DCM_USE_GDCM2 #include class Metadata; namespace gdcm { class File; }; void gdcm2_get_date_time ( std::string *date, std::string *time ); void set_metadata_from_gdcm_file ( Metadata *meta, /* const */ gdcm::File *gdcm_file, unsigned short group, unsigned short elem ); void set_gdcm_file_from_metadata ( gdcm::File *gdcm_file, const Metadata *meta, unsigned short group, unsigned short elem ); char* gdcm_uid (char *uid, const char *uid_root); #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/hnd_io.cxx000077500000000000000000000254221321604176500275250ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "compiler_warnings.h" #include "file_util.h" #include "hnd_io_p.h" #include "hnd_io.h" #include "plm_math.h" #include "print_and_exit.h" #include "proj_image.h" #include "proj_matrix.h" #define HND_INTENSITY_MAX (139000) //#define HND_INTENSITY_MAX (10000) /* ----------------------------------------------------------------------- Private functions ----------------------------------------------------------------------- */ static void hnd_adjust_intensity (Proj_image *proj) { int i; float *img = proj->img; for (i = 0; i < proj->dim[0] * proj->dim[1]; i++) { if (img[i] == 0.0f) { continue; } img[i] = img[i] / HND_INTENSITY_MAX; img[i] = 1.0 - img[i]; if (img[i] < 0.0f) img[i] = 0.0; /* Exponential mapping -- maybe this helps a little */ img[i] = exp(img[i]) - 1; } } static void hnd_set_proj_matrix ( Proj_image *proj, double angle, double sad, double sid, const double xy_offset[2] /* Offset from center position by how much? */ ) { double vup[3] = {0, 0, 1}; double tgt[3] = {0.0, 0.0, 0.0}; Proj_matrix *pmat = proj->pmat; /* Set physical size of imager in mm */ int isize[2] = { 400, 300 }; /* Actual resolution */ /* Set pixel size in mm */ double ps[2] = { (double) isize[0] / (double) proj->dim[0], (double) isize[1] / (double) proj->dim[1] }; double cam[3]; double tmp[3]; pmat->sad = sad; pmat->sid = sid; /* Set ic = image center (in pixels) */ pmat->ic[0] = 0.5 * proj->dim[0] - 0.5; pmat->ic[1] = 0.5 * proj->dim[1] - 0.5; if (xy_offset) { pmat->ic[0] += xy_offset[0]; pmat->ic[1] += xy_offset[1]; } /* Change from varian angles to plastimatch angles */ cam[0] = sad * cos ((angle + 270) * M_PI / 180.0); cam[1] = sad * sin ((angle + 270) * M_PI / 180.0); cam[2] = 0.0; /* Place camera at distance "sad" from the volume isocenter */ vec3_sub3 (pmat->nrm, tgt, cam); vec3_normalize1 (pmat->nrm); vec3_scale3 (tmp, pmat->nrm, sad); vec3_copy (cam, tgt); vec3_sub2 (cam, tmp); pmat->set (cam, tgt, vup, sid, pmat->ic, ps); } /* ----------------------------------------------------------------------- Public functions ----------------------------------------------------------------------- */ void hnd_load (Proj_image *proj, const char *fn, const double xy_offset[2]) { Hnd_header hnd; FILE *fp; uint32_t* buf; unsigned char *pt_lut; uint32_t a; unsigned char v; int lut_idx, lut_off; size_t num_read; char dc; short ds; long dl, diff = 0l; uint32_t i; /* JAS 2012.02.06 * Use a bit bucket to supress compiler warnings for now. * TODO: Implement proper error checking instead */ size_t bit_bucket; UNUSED_VARIABLE (bit_bucket); /* GCS FIX: This is hard coded during debug */ //double xy_offset[2] = { -2.21 * 4, 0.24 * 4 }; // Good values for test if (!proj) return; if (!file_exists (fn)) { print_and_exit ("Error: hnd_file (%s) does not exist.\n", fn); } fp = fopen (fn, "rb"); if (fp == NULL) { print_and_exit ("Cannot open %s for read\n", fn); } bit_bucket = fread ((void *) hnd.sFileType, sizeof(char), 32, fp); bit_bucket = fread ((void *) &hnd.FileLength, sizeof(uint32_t), 1, fp); bit_bucket = fread ((void *) hnd.sChecksumSpec, sizeof(char), 4, fp); bit_bucket = fread ((void *) &hnd.nCheckSum, sizeof(uint32_t), 1, fp); bit_bucket = fread ((void *) hnd.sCreationDate, sizeof(char), 8, fp); bit_bucket = fread ((void *) hnd.sCreationTime, sizeof(char), 8, fp); bit_bucket = fread ((void *) hnd.sPatientID, sizeof(char), 16, fp); bit_bucket = fread ((void *) &hnd.nPatientSer, sizeof(uint32_t), 1, fp); bit_bucket = fread ((void *) hnd.sSeriesID, sizeof(char), 16, fp); bit_bucket = fread ((void *) &hnd.nSeriesSer, sizeof(uint32_t), 1, fp); bit_bucket = fread ((void *) hnd.sSliceID, sizeof(char), 16, fp); bit_bucket = fread ((void *) &hnd.nSliceSer, sizeof(uint32_t), 1, fp); bit_bucket = fread ((void *) &hnd.SizeX, sizeof(uint32_t), 1, fp); bit_bucket = fread ((void *) &hnd.SizeY, sizeof(uint32_t), 1, fp); bit_bucket = fread ((void *) &hnd.dSliceZPos, sizeof(double), 1, fp); bit_bucket = fread ((void *) hnd.sModality, sizeof(char), 16, fp); bit_bucket = fread ((void *) &hnd.nWindow, sizeof(uint32_t), 1, fp); bit_bucket = fread ((void *) &hnd.nLevel, sizeof(uint32_t), 1, fp); bit_bucket = fread ((void *) &hnd.nPixelOffset, sizeof(uint32_t), 1, fp); bit_bucket = fread ((void *) hnd.sImageType, sizeof(char), 4, fp); bit_bucket = fread ((void *) &hnd.dGantryRtn, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dSAD, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dSFD, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dCollX1, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dCollX2, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dCollY1, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dCollY2, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dCollRtn, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dFieldX, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dFieldY, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dBladeX1, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dBladeX2, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dBladeY1, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dBladeY2, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dIDUPosLng, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dIDUPosLat, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dIDUPosVrt, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dIDUPosRtn, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dPatientSupportAngle, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dTableTopEccentricAngle, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dCouchVrt, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dCouchLng, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dCouchLat, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dIDUResolutionX, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dIDUResolutionY, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dImageResolutionX, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dImageResolutionY, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dEnergy, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dDoseRate, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dXRayKV, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dXRayMA, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dMetersetExposure, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dAcqAdjustment, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dCTProjectionAngle, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dCTNormChamber, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dGatingTimeTag, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dGating4DInfoX, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dGating4DInfoY, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dGating4DInfoZ, sizeof(double), 1, fp); bit_bucket = fread ((void *) &hnd.dGating4DInfoTime, sizeof(double), 1, fp); printf ("%s %f\n", fn, hnd.dCTProjectionAngle); pt_lut = (unsigned char*) malloc ( sizeof (unsigned char) * hnd.SizeX * hnd.SizeY); buf = (uint32_t*) malloc ( sizeof(uint32_t) * hnd.SizeX * hnd.SizeY); /* Read LUT */ fseek (fp, 1024, SEEK_SET); bit_bucket = fread (pt_lut, sizeof(unsigned char), (hnd.SizeY-1)*hnd.SizeX / 4, fp); /* Read first row */ for (i = 0; i < hnd.SizeX; i++) { bit_bucket = fread (&a, sizeof(uint32_t), 1, fp); buf[i] = a; } /* Read first pixel of second row */ bit_bucket = fread (&a, sizeof(uint32_t), 1, fp); buf[i++] = a; /* Decompress the rest */ lut_idx = 0; lut_off = 0; while (i < hnd.SizeX * hnd.SizeY) { uint32_t r11, r12, r21; r11 = buf[i-hnd.SizeX-1]; r12 = buf[i-hnd.SizeX]; r21 = buf[i-1]; v = pt_lut[lut_idx]; switch (lut_off) { case 0: v = v & 0x03; lut_off ++; break; case 1: v = (v & 0x0C) >> 2; lut_off ++; break; case 2: v = (v & 0x30) >> 4; lut_off ++; break; case 3: v = (v & 0xC0) >> 6; lut_off = 0; lut_idx ++; break; } switch (v) { case 0: num_read = fread (&dc, sizeof(unsigned char), 1, fp); if (num_read != 1) goto read_error; diff = dc; break; case 1: num_read = fread (&ds, sizeof(unsigned short), 1, fp); if (num_read != 1) goto read_error; diff = ds; break; case 2: num_read = fread (&dl, sizeof(uint32_t), 1, fp); if (num_read != 1) goto read_error; diff = dl; break; } buf[i] = r21 + r12 + diff - r11; i++; } /* Convert hnd to proj_image */ proj->dim[0] = hnd.SizeX; proj->dim[1] = hnd.SizeY; proj->img = (float*) malloc ( hnd.SizeX * hnd.SizeY * sizeof(float)); if (!proj->img) { print_and_exit ("Error allocating memory\n"); } for (i = 0; i < hnd.SizeX * hnd.SizeY; i++) { proj->img[i] = (float) buf[i]; } /* Convert from "raw" intensities to attenuation values */ hnd_adjust_intensity (proj); /* Set the matrix */ /* Note: Varian HND seems to give 0 for the SFD. We will hard code the sid to 1500 until told otherwise. */ /* GCS: Sometimes the SAD is 100 (cm) and sometimes it is 1000 (mm). So we will hard code the SAD to 1000 mm. */ proj->pmat = new Proj_matrix; hnd_set_proj_matrix (proj, hnd.dCTProjectionAngle, 1000, 1500, xy_offset); /* Clean up */ free (pt_lut); free (buf); fclose (fp); return; read_error: fprintf (stderr, "Error reading hnd file\n"); free (pt_lut); free (buf); fclose (fp); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/hnd_io.h000066400000000000000000000006711321604176500271460ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _hnd_io_h_ #define _hnd_io_h_ #include "plmbase_config.h" class Proj_image; PLMBASE_C_API void hnd_load ( Proj_image *proj, const char *fn, const double xy_offset[2] ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/hnd_io_p.h000066400000000000000000000034231321604176500274630ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _hnd_io_p_h_ #define _hnd_io_p_h_ #include "plmbase_config.h" typedef struct hnd_header Hnd_header; struct hnd_header { char sFileType[32]; uint32_t FileLength; char sChecksumSpec[4]; uint32_t nCheckSum; char sCreationDate[8]; char sCreationTime[8]; char sPatientID[16]; uint32_t nPatientSer; char sSeriesID[16]; uint32_t nSeriesSer; char sSliceID[16]; uint32_t nSliceSer; uint32_t SizeX; uint32_t SizeY; double dSliceZPos; char sModality[16]; uint32_t nWindow; uint32_t nLevel; uint32_t nPixelOffset; char sImageType[4]; double dGantryRtn; double dSAD; double dSFD; double dCollX1; double dCollX2; double dCollY1; double dCollY2; double dCollRtn; double dFieldX; double dFieldY; double dBladeX1; double dBladeX2; double dBladeY1; double dBladeY2; double dIDUPosLng; double dIDUPosLat; double dIDUPosVrt; double dIDUPosRtn; double dPatientSupportAngle; double dTableTopEccentricAngle; double dCouchVrt; double dCouchLng; double dCouchLat; double dIDUResolutionX; double dIDUResolutionY; double dImageResolutionX; double dImageResolutionY; double dEnergy; double dDoseRate; double dXRayKV; double dXRayMA; double dMetersetExposure; double dAcqAdjustment; double dCTProjectionAngle; double dCTNormChamber; double dGatingTimeTag; double dGating4DInfoX; double dGating4DInfoY; double dGating4DInfoZ; double dGating4DInfoTime; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/interpolate.cxx000077500000000000000000000122061321604176500306070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "interpolate.h" #include "plm_math.h" #include "volume.h" /* Clipping is done using clamping. Note: the value of *maf can be at most dim[x]-2, because the linear interpolation code assumes that the "lower" pixel is always valid. */ void li_clamp ( float ma, /* Input: (Unrounded) pixel coordinate (in vox) */ plm_long dmax, /* Input: Maximum coordinate in this dimension */ plm_long* maf, /* Output: x, y, or z coord of "floor" pixel in moving img */ plm_long* mar, /* Output: x, y, or z coord of "round" pixel in moving img */ float* fa1, /* Output: Fraction of interpolant for lower index voxel */ float* fa2 /* Output: Fraction of interpolant for upper index voxel */ ) { if (ma < 0.f) { *maf = 0; *mar = 0; *fa2 = 0.0f; } else if (ma >= dmax) { *maf = dmax - 1; *mar = dmax; *fa2 = 1.0f; } else { *maf = FLOOR_PLM_LONG (ma); *mar = ROUND_PLM_LONG (ma); *fa2 = ma - *maf; } *fa1 = 1.0f - *fa2; } /* Clipping is done by setting fractional values to 0.f */ static void li_noclamp ( plm_long* f, /* Output: x, y, or z coord of "floor" pixel */ float* fa1, /* Output: Fraction of interpolant for lower index voxel */ float* fa2, /* Output: Fraction of interpolant for upper index voxel */ float idx, /* Input: (Unrounded) pixel coordinate (in vox) */ plm_long dmax /* Input: Maximum coordinate in this dimension */ ) { *f = FLOOR_PLM_LONG (idx); *fa2 = idx - *f; *fa1 = 1.0f - *fa2; if (*f < 0) { *fa1 = 0.f; if (*f < -1) { *fa2 = 0.f; return; } } if (*f > dmax - 2) { *fa2 = 0.f; if (*f > dmax - 1) { *fa1 = 0.f; return; } } } /* Simple li, with no processing */ static void li ( plm_long* f, /* Output: x, y, or z coord of "floor" pixel */ float* fa1, /* Output: Fraction of interpolant for lower index voxel */ float* fa2, /* Output: Fraction of interpolant for upper index voxel */ float idx, /* Input: (Unrounded) pixel coordinate (in vox) */ plm_long dmax /* Input: Maximum coordinate in this dimension */ ) { *f = FLOOR_PLM_LONG (idx); *fa2 = idx - *f; *fa1 = 1.0f - *fa2; } void li_clamp_3d ( const float mijk[3], /* Input: Unrounded pixel coordinates in vox */ plm_long mijk_f[3], /* Output: "floor" pixel in moving img in vox*/ plm_long mijk_r[3], /* Ouptut: "round" pixel in moving img in vox*/ float li_frac_1[3], /* Output: Fraction for upper index voxel */ float li_frac_2[3], /* Output: Fraction for lower index voxel */ const Volume *moving /* Input: Volume (for dims) */ ) { li_clamp (mijk[0], moving->dim[0]-1, &mijk_f[0], &mijk_r[0], &li_frac_1[0], &li_frac_2[0]); li_clamp (mijk[1], moving->dim[1]-1, &mijk_f[1], &mijk_r[1], &li_frac_1[1], &li_frac_2[1]); li_clamp (mijk[2], moving->dim[2]-1, &mijk_f[2], &mijk_r[2], &li_frac_1[2], &li_frac_2[2]); } void li_noclamp_3d ( plm_long ijk_f[3], float li_frac_1[3], float li_frac_2[3], const float ijk[3], const plm_long dim[3] ) { li_noclamp (&ijk_f[0], &li_frac_1[0], &li_frac_2[0], ijk[0], dim[0]); li_noclamp (&ijk_f[1], &li_frac_1[1], &li_frac_2[1], ijk[1], dim[1]); li_noclamp (&ijk_f[2], &li_frac_1[2], &li_frac_2[2], ijk[2], dim[2]); } void li_2d ( plm_long *ijk_f, float *li_frac_1, float *li_frac_2, const float *ijk, const plm_long *dim ) { li (&ijk_f[0], &li_frac_1[0], &li_frac_2[0], ijk[0], dim[0]); li (&ijk_f[1], &li_frac_1[1], &li_frac_2[1], ijk[1], dim[1]); } float li_value ( float fx1, float fx2, /* Input: Fraction of upper, lower x voxel */ float fy1, float fy2, /* Input: Fraction of upper, lower y voxel */ float fz1, float fz2, /* Input: Fraction of upper, lower z voxel */ plm_long mvf, /* Input: Index of lower-left voxel in 8-group */ float *m_img, /* Input: Pointer to raw data */ Volume *moving /* Input: Volume (for dimensions) */ ) { float m_x1y1z1, m_x2y1z1, m_x1y2z1, m_x2y2z1; float m_x1y1z2, m_x2y1z2, m_x1y2z2, m_x2y2z2; float m_val; m_x1y1z1 = fx1 * fy1 * fz1 * m_img[mvf]; m_x2y1z1 = fx2 * fy1 * fz1 * m_img[mvf+1]; m_x1y2z1 = fx1 * fy2 * fz1 * m_img[mvf+moving->dim[0]]; m_x2y2z1 = fx2 * fy2 * fz1 * m_img[mvf+moving->dim[0]+1]; m_x1y1z2 = fx1 * fy1 * fz2 * m_img[mvf+moving->dim[1]*moving->dim[0]]; m_x2y1z2 = fx2 * fy1 * fz2 * m_img[mvf+moving->dim[1]*moving->dim[0]+1]; m_x1y2z2 = fx1 * fy2 * fz2 * m_img[mvf+moving->dim[1]*moving->dim[0]+moving->dim[0]]; m_x2y2z2 = fx2 * fy2 * fz2 * m_img[mvf+moving->dim[1]*moving->dim[0]+moving->dim[0]+1]; m_val = m_x1y1z1 + m_x2y1z1 + m_x1y2z1 + m_x2y2z1 + m_x1y1z2 + m_x2y1z2 + m_x1y2z2 + m_x2y2z2; return m_val; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/interpolate.h000077500000000000000000000024271321604176500302400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _interpolate_h_ #define _interpolate_h_ #include "plmbase_config.h" #include "plm_int.h" class Volume; PLMBASE_C_API void li_clamp ( float ma, plm_long dmax, plm_long* maf, plm_long* mar, float* fa1, float* fa2 ); PLMBASE_C_API void li_clamp_3d ( const float mijk[3], plm_long mijk_f[3], plm_long mijk_r[3], float li_frac_1[3], float li_frac_2[3], const Volume *moving ); /* Compute only fractional components, do not solve for value. Clamping is not done; instead, fractions are set to 0.f if xyz lies outside limits of dim. */ PLMBASE_C_API void li_noclamp_3d ( plm_long ijk_f[3], float li_frac_1[3], float li_frac_2[3], const float ijk[3], const plm_long dim[3] ); PLMBASE_C_API void li_2d ( plm_long *ijk_f, float *li_frac_1, float *li_frac_2, const float *ijk, const plm_long *dim ); PLMBASE_C_API float li_value ( float fx1, float fx2, float fy1, float fy2, float fz1, float fz2, plm_long mvf, float *m_img, Volume *moving ); #endif interpolate_macros.h000066400000000000000000000111551321604176500315200ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _interpolate_macros_h_ #define _interpolate_macros_h_ #define LI_CLAMP_3D( \ mijk, mijk_f, mijk_r, \ li_frac_1, li_frac_2, moving) \ do { \ li_clamp (mijk[0], moving->dim[0]-1, \ &mijk_f[0], &mijk_r[0], \ &li_frac_1[0], &li_frac_2[0]); \ li_clamp (mijk[1], moving->dim[1]-1, \ &mijk_f[1], &mijk_r[1], \ &li_frac_1[1], &li_frac_2[1]); \ li_clamp (mijk[2], moving->dim[2]-1, \ &mijk_f[2], &mijk_r[2], \ &li_frac_1[2], &li_frac_2[2]); \ } while (0) #define LI_VALUE(m_val, fx1, fx2, fy1, fy2, fz1, fz2, mvf, m_img, moving) \ do { \ float m_x1y1z1, m_x2y1z1, m_x1y2z1, m_x2y2z1; \ float m_x1y1z2, m_x2y1z2, m_x1y2z2, m_x2y2z2; \ \ m_x1y1z1 = fx1 * fy1 * fz1 * m_img[mvf]; \ m_x2y1z1 = fx2 * fy1 * fz1 * m_img[mvf+1]; \ m_x1y2z1 = fx1 * fy2 * fz1 * m_img[mvf+moving->dim[0]]; \ m_x2y2z1 = fx2 * fy2 * fz1 * m_img[mvf+moving->dim[0]+1]; \ m_x1y1z2 = fx1 * fy1 * fz2 * m_img[mvf+moving->dim[1]*moving->dim[0]]; \ m_x2y1z2 = fx2 * fy1 * fz2 * m_img[mvf+moving->dim[1]*moving->dim[0]+1]; \ m_x1y2z2 = fx1 * fy2 * fz2 * m_img[mvf+moving->dim[1]*moving->dim[0]+moving->dim[0]]; \ m_x2y2z2 = fx2 * fy2 * fz2 * m_img[mvf+moving->dim[1]*moving->dim[0]+moving->dim[0]+1]; \ m_val = m_x1y1z1 + m_x2y1z1 + m_x1y2z1 + m_x2y2z1 \ + m_x1y1z2 + m_x2y1z2 + m_x1y2z2 + m_x2y2z2; \ } while (0) #define LI_VALUE_ALT(m_val, fx1, fx2, fy1, fy2, fz1, fz2, \ mvf, m_img, moving, plane) \ do { \ int idx_x1y1z1, idx_x2y1z1, idx_x1y2z1, idx_x2y2z1; \ int idx_x1y1z2, idx_x2y1z2, idx_x1y2z2, idx_x2y2z2; \ float m_x1y1z1, m_x2y1z1, m_x1y2z1, m_x2y2z1; \ float m_x1y1z2, m_x2y1z2, m_x1y2z2, m_x2y2z2; \ \ idx_x1y1z1 = mvf; \ idx_x2y1z1 = mvf+1; \ idx_x1y2z1 = mvf+moving->dim[0]; \ idx_x2y2z1 = mvf+moving->dim[0+1]; \ idx_x1y1z2 = mvf+moving->dim[1]*moving->dim[0]; \ idx_x2y1z2 = mvf+moving->dim[1]*moving->dim[0]+1; \ idx_x1y2z2 = mvf+moving->dim[1]*moving->dim[0]+moving->dim[0]; \ idx_x2y2z2 = mvf+moving->dim[1]*moving->dim[0]+moving->dim[0]+1; \ \ m_x1y1z1 = fx1 * fy1 * fz1 * m_img[idx_x1y1z1]; \ m_x2y1z1 = fx2 * fy1 * fz1 * m_img[idx_x2y1z1]; \ m_x1y2z1 = fx1 * fy2 * fz1 * m_img[idx_x1y2z1]; \ m_x2y2z1 = fx2 * fy2 * fz1 * m_img[idx_x2y2z1]; \ m_x1y1z2 = fx1 * fy1 * fz2 * m_img[idx_x1y1z2]; \ m_x2y1z2 = fx2 * fy1 * fz2 * m_img[idx_x2y1z2]; \ m_x1y2z2 = fx1 * fy2 * fz2 * m_img[idx_x1y2z2]; \ m_x2y2z2 = fx2 * fy2 * fz2 * m_img[idx_x2y2z2]; \ m_val = m_x1y1z1 + m_x2y1z1 + m_x1y2z1 + m_x2y2z1 \ + m_x1y1z2 + m_x2y1z2 + m_x1y2z2 + m_x2y2z2; \ } while (0) #define LI_VALUE_INTERLEAVED(m_val, fx1, fx2, fy1, fy2, fz1, fz2, \ mvf, m_img, moving, plane) \ do { \ plm_ssize_t idx_x1y1z1, idx_x2y1z1, idx_x1y2z1, idx_x2y2z1; \ plm_ssize_t idx_x1y1z2, idx_x2y1z2, idx_x1y2z2, idx_x2y2z2; \ float m_x1y1z1, m_x2y1z1, m_x1y2z1, m_x2y2z1; \ float m_x1y1z2, m_x2y1z2, m_x1y2z2, m_x2y2z2; \ \ idx_x1y1z1 = mvf; \ idx_x2y1z1 = mvf+1; \ idx_x1y2z1 = mvf+moving->dim[0]; \ idx_x2y2z1 = mvf+moving->dim[0+1]; \ idx_x1y1z2 = mvf+moving->dim[1]*moving->dim[0]; \ idx_x2y1z2 = mvf+moving->dim[1]*moving->dim[0]+1; \ idx_x1y2z2 = mvf+moving->dim[1]*moving->dim[0]+moving->dim[0]; \ idx_x2y2z2 = mvf+moving->dim[1]*moving->dim[0]+moving->dim[0]+1; \ \ idx_x1y1z1 = idx_x1y1z1 * moving->vox_planes + plane; \ idx_x2y1z1 = idx_x2y1z1 * moving->vox_planes + plane; \ idx_x1y2z1 = idx_x1y2z1 * moving->vox_planes + plane; \ idx_x2y2z1 = idx_x2y2z1 * moving->vox_planes + plane; \ idx_x1y1z2 = idx_x1y1z2 * moving->vox_planes + plane; \ idx_x2y1z2 = idx_x2y1z2 * moving->vox_planes + plane; \ idx_x1y2z2 = idx_x1y2z2 * moving->vox_planes + plane; \ idx_x2y2z2 = idx_x2y2z2 * moving->vox_planes + plane; \ \ m_x1y1z1 = fx1 * fy1 * fz1 * m_img[idx_x1y1z1]; \ m_x2y1z1 = fx2 * fy1 * fz1 * m_img[idx_x2y1z1]; \ m_x1y2z1 = fx1 * fy2 * fz1 * m_img[idx_x1y2z1]; \ m_x2y2z1 = fx2 * fy2 * fz1 * m_img[idx_x2y2z1]; \ m_x1y1z2 = fx1 * fy1 * fz2 * m_img[idx_x1y1z2]; \ m_x2y1z2 = fx2 * fy1 * fz2 * m_img[idx_x2y1z2]; \ m_x1y2z2 = fx1 * fy2 * fz2 * m_img[idx_x1y2z2]; \ m_x2y2z2 = fx2 * fy2 * fz2 * m_img[idx_x2y2z2]; \ m_val = m_x1y1z1 + m_x2y1z1 + m_x1y2z1 + m_x2y2z1 \ + m_x1y1z2 + m_x2y1z2 + m_x1y2z2 + m_x2y2z2; \ } while (0) #endif itkAndConstantToImageFilter.h000066400000000000000000000071171321604176500331710ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __itkAndConstantToImageFilter_h #define __itkAndConstantToImageFilter_h #include "itkUnaryFunctorImageFilter.h" #include "itkNumericTraits.h" namespace itk { /* Thanks for broilerplate code: * \author Tom Vercauteren, INRIA & Mauna Kea Technologies * which is based on filters from the Insight Journal paper: * http://hdl.handle.net/1926/510 */ namespace Functor { template< class TInput, class TConstant, class TOutput> class AndConstantTo { public: AndConstantTo() : m_Constant(NumericTraits::One) {}; ~AndConstantTo() {}; bool operator!=( const AndConstantTo & other ) const { return !(*this == other); } bool operator==( const AndConstantTo & other ) const { return other.m_Constant == m_Constant; } inline TOutput operator()( const TInput & A ) const { // Because the user has to specify the constant we don't // check if the cte is not 0; return static_cast( ((A & m_Constant) > 0) ); } void SetConstant(TConstant ct) {this->m_Constant = ct; } const TConstant & GetConstant() const { return m_Constant; } TConstant m_Constant; }; } template class ITK_EXPORT AndConstantToImageFilter : public UnaryFunctorImageFilter > { public: /** Standard class typedefs. */ typedef AndConstantToImageFilter Self; typedef UnaryFunctorImageFilter< TInputImage,TOutputImage, Functor::AndConstantTo< typename TInputImage::PixelType, TConstant, typename TOutputImage::PixelType> > Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(AndConstantToImageFilter, UnaryFunctorImageFilter); /** Set the constant that will be used to multiply all the image * pixels */ void SetConstant(TConstant ct) { if( ct != this->GetFunctor().GetConstant() ) { this->GetFunctor().SetConstant(ct); this->Modified(); } } const TConstant & GetConstant() const { return this->GetFunctor().GetConstant(); } #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(InputConvertibleToOutputCheck, (Concept::Convertible)); itkConceptMacro(Input1Input2OutputAndOperatorCheck, (Concept::AdditiveOperators)); /** End concept checking */ #endif protected: AndConstantToImageFilter() {}; virtual ~AndConstantToImageFilter() {}; void PrintSelf(std::ostream &os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Constant: " << static_cast::PrintType>(this->GetConstant()) << std::endl; } private: AndConstantToImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented }; } // end namespace itk #endif itkClampCastImageFilter.h000066400000000000000000000041731321604176500323200ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __itkClampCastImageFilter_h #define __itkClampCastImageFilter_h #include "itkConfigure.h" #include "itkImageToImageFilter.h" namespace itk { template class ITK_EXPORT ClampCastImageFilter : public ImageToImageFilter { public: /** Standard class typedefs. */ typedef ClampCastImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(ClampCastImageFilter, UnaryFunctorImageFilter); /** Some additional typedefs. */ typedef typename TInputImage::ConstPointer InputImagePointer; typedef typename TInputImage::RegionType InputImageRegionType; typedef typename TInputImage::PixelType InputImagePixelType; /** Some additional typedefs. */ typedef typename TOutputImage::Pointer OutputImagePointer; typedef typename TOutputImage::RegionType OutputImageRegionType; typedef typename TOutputImage::PixelType OutputImagePixelType; protected: ClampCastImageFilter(); ~ClampCastImageFilter() {}; void PrintSelf(std::ostream& os, Indent indent) const; #if ITK_VERSION_MAJOR == 3 void ThreadedGenerateData ( const OutputImageRegionType& outputRegionForThread, int threadId); #else /* ITK 4 */ void ThreadedGenerateData ( const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId); #endif private: ClampCastImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkClampCastImageFilter.txx" #endif #endif itkClampCastImageFilter.txx000066400000000000000000000054131321604176500327120ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __itkClampCastImageFilter_txx #define __itkClampCastImageFilter_txx #include "itkClampCastImageFilter.h" #include "itkImageRegionIterator.h" #include "itkImageRegionConstIterator.h" #include "itkNumericTraits.h" #include "itkObjectFactory.h" #include "itkProgressReporter.h" namespace itk { template ClampCastImageFilter ::ClampCastImageFilter() { /* Do nothing */ } template void ClampCastImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { /* Do nothing */ } template void ClampCastImageFilter ::ThreadedGenerateData ( const OutputImageRegionType& outputRegionForThread, #if ITK_VERSION_MAJOR == 3 int threadId #else /* ITK 4 */ ThreadIdType threadId #endif ) { itkDebugMacro(<<"Actually executing"); // Get the input and output pointers InputImagePointer inputPtr = this->GetInput(); OutputImagePointer outputPtr = this->GetOutput(0); /* Get iterators */ typedef ImageRegionConstIterator InputIterator; typedef ImageRegionIterator OutputIterator; InputIterator in_it(inputPtr, outputRegionForThread); OutputIterator out_it(outputPtr, outputRegionForThread); /* Get min and max values of output pixel type */ OutputImagePixelType out_min = NumericTraits< OutputImagePixelType>::NonpositiveMin(); OutputImagePixelType out_max = NumericTraits< OutputImagePixelType>::max(); /* support progress methods/callbacks */ ProgressReporter progress (this, threadId, outputRegionForThread.GetNumberOfPixels()); /* Make gcc accept the below without complaining about signed/unsigned compare */ //#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6) //#pragma GCC diagnostic push //#pragma GCC diagnostic ignored "-Wsign-compare" //#endif /* walk through image, clamping and casting each pixel */ while (!out_it.IsAtEnd()) { const InputImagePixelType in_value = in_it.Get(); if (!NumericTraits::is_signed && in_value < 0) { out_it.Set (0); } else if (in_value > out_max) { out_it.Set (out_max); } else if (in_value < out_min) { out_it.Set (out_min); } else { out_it.Set (static_cast (in_it.Get())); } ++in_it; ++out_it; progress.CompletedPixel(); } //#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6) //#pragma GCC diagnostic pop //#endif } } // end namespace itk #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_bbox.cxx000066400000000000000000000032741321604176500300640ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include "itkContinuousIndex.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itk_bbox.h" #include "itk_image.h" void itk_bbox (UCharImageType::Pointer img, float *bbox) { for (int d = 0; d < 3; d++) { bbox[2*d+0] = FLT_MAX; bbox[2*d+1] = -FLT_MAX; } UCharImageType::RegionType region = img->GetLargestPossibleRegion(); itk::ImageRegionConstIteratorWithIndex< UCharImageType > it (img, region); for (it.GoToBegin(); !it.IsAtEnd(); ++it) { unsigned char c = it.Get(); if (!c) { continue; } /* If voxel is non-zero, loop through the eight corners of the voxels, find their position, and set bounding box to contain */ itk::ContinuousIndex cidx = it.GetIndex(); for (int i = 0; i < 8; i++) { itk::ContinuousIndex cidx_corner = cidx; cidx_corner[0] += (i % 2) - 0.5; cidx_corner[1] += ((i / 2) % 2) - 0.5; cidx_corner[2] += (i / 4) - 0.5; FloatPoint3DType point; img->TransformContinuousIndexToPhysicalPoint (cidx_corner, point); for (int d = 0; d < 3; d++) { if (point[d] < bbox[2*d+0]) { bbox[2*d+0] = point[d]; } if (point[d] > bbox[2*d+1]) { bbox[2*d+1] = point[d]; } } } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_bbox.h000066400000000000000000000006341321604176500275060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_bbox_h_ #define _itk_bbox_h_ #include "plmbase_config.h" #include "itk_image_type.h" PLMBASE_API void itk_bbox (const UCharImageType::Pointer img, float *bbox); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_dicom_load.cxx000066400000000000000000000214221321604176500312170ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "itkGDCMImageIO.h" #include "itkGDCMSeriesFileNames.h" #include "itkImageSeriesReader.h" #include "itk_dicom_load.h" #include "logfile.h" #include "print_and_exit.h" /* winbase.h defines GetCurrentTime which conflicts with gdcm function */ #if defined GetCurrentTime # undef GetCurrentTime #endif #include "gdcmFile.h" #if GDCM_MAJOR_VERSION < 2 #include "gdcmUtil.h" #else #include "gdcmUIDGenerator.h" #endif /* ----------------------------------------------------------------------- Definitions ----------------------------------------------------------------------- */ typedef itk::ImageSeriesReader < CharImageType > DicomCharReaderType; typedef itk::ImageSeriesReader < UCharImageType > DicomUCharReaderType; typedef itk::ImageSeriesReader < ShortImageType > DicomShortReaderType; typedef itk::ImageSeriesReader < UShortImageType > DicomUShortReaderType; typedef itk::ImageSeriesReader < Int32ImageType > DicomInt32ReaderType; typedef itk::ImageSeriesReader < UInt32ImageType > DicomUInt32ReaderType; typedef itk::ImageSeriesReader < FloatImageType > DicomFloatReaderType; typedef itk::ImageSeriesReader < DoubleImageType > DicomDoubleReaderType; /* ----------------------------------------------------------------------- functions ----------------------------------------------------------------------- */ #if GDCM_MAJOR_VERSION < 2 static bool test_dicom_ok (const std::string& fn) { gdcm::File header; header.SetLoadMode (0); header.SetFileName (fn); header.Load (); if (!header.IsReadable()) { return false; } std::string s; /* Reject GE Scouts */ s = header.GetEntryValue (0x0018, 0x0022); if (s == "SCOUT MODE") { logfile_printf ("Rejecting GE scout\n"); return false; } /* Reject GE Dose reports */ s = header.GetEntryValue (0x0008, 0x103e); if (s == "Dose Report" || s == "Dose Report ") { logfile_printf ("Rejecting GE dose report\n"); return false; } /* Reject RTDOSE, which can get interpreted as an image (and gets read incorretly anyway). Dose is read by rtds.cxx instead. */ s = header.GetEntryValue (0x0008, 0x0060); if (s == "RTDOSE") { logfile_printf ("Rejecting RTDOSE\n"); return false; } return true; } #endif template void load_dicom_dir_rdr(T rdr, const char *dicom_dir) { typedef itk::GDCMImageIO ImageIOType; ImageIOType::Pointer dicomIO = ImageIOType::New(); rdr->SetImageIO (dicomIO); /* Read the filenames from the directory */ typedef itk::GDCMSeriesFileNames NamesGeneratorType; NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New(); nameGenerator->SetUseSeriesDetails (true); /* GCS 2011-09-16. AddRestriction() causes seg fault when reading DICOM files with empty fields. Wow. Anyway, we can't use them. Possibly only with GDCM 1.X? */ #if GDCM_MAJOR_VERSION == 2 /* Reject RTDOSE, which can get interpreted as an image (and gets read incorretly anyway). Dose is read by rtds.cxx instead. */ gdcm::SerieHelper* gsh = nameGenerator->GetSeriesHelper (); gsh->AddRestriction (0x0008, 0x0060, "RTDOSE", gdcm::GDCM_DIFFERENT); /* Reject GE Scouts */ gsh->AddRestriction (0x0018, 0x0022, "SCOUT MODE", gdcm::GDCM_DIFFERENT); /* Reject GE Dose reports */ gsh->AddRestriction (0x0008, 0x103e, "Dose Report", gdcm::GDCM_DIFFERENT); #endif nameGenerator->SetDirectory (dicom_dir); try { std::cout << std::endl << "The directory: " << std::endl; std::cout << std::endl << dicom_dir << std::endl << std::endl; std::cout << "Contains the following DICOM Series: "; std::cout << std::endl; typedef std::vector< std::string > SeriesIdContainer; const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs(); SeriesIdContainer::const_iterator seriesItr = seriesUID.begin(); SeriesIdContainer::const_iterator seriesEnd = seriesUID.end(); while (seriesItr != seriesEnd) { std::cout << seriesItr->c_str() << std::endl; seriesItr++; } std::cout << std::endl; /* Loop through series and use first one that loads */ seriesItr = seriesUID.begin(); bool dicom_load_succeeded = false; while (!dicom_load_succeeded && seriesItr != seriesEnd) { std::string seriesIdentifier; seriesIdentifier = seriesItr->c_str(); std::cout << "Now reading series: " << std::endl; std::cout << seriesIdentifier << std::endl; /* Read the files */ typedef std::vector< std::string > FileNamesContainer; FileNamesContainer file_names; file_names = nameGenerator->GetFileNames (seriesIdentifier); /* Get the first filename */ std::string first_fn = *(file_names.begin()); /* Test against restrictions */ #if GDCM_MAJOR_VERSION < 2 if (!test_dicom_ok (first_fn)) { seriesItr++; continue; } #endif #if defined (commentout) /* Print out the file names */ FileNamesContainer::const_iterator fn_it = file_names.begin(); printf ("File names are:\n"); while (fn_it != file_names.end()) { printf (" %s\n", fn_it->c_str()); fn_it ++; } #endif rdr->SetFileNames (file_names); try { rdr->Update(); dicom_load_succeeded = true; } catch (itk::ExceptionObject &ex) { /* do nothing */ logfile_printf ("Failed to load: %s\n", ex.GetDescription()); } seriesItr++; } if (!dicom_load_succeeded) { print_and_exit ("Error, unable to load dicom series.\n"); } } catch (itk::ExceptionObject &ex) { std::cout << ex << std::endl; print_and_exit ("Error loading dicom series.\n"); } } CharImageType::Pointer load_dicom_char (const char *dicom_dir) { DicomCharReaderType::Pointer fixed_input_rdr = DicomCharReaderType::New(); load_dicom_dir_rdr (fixed_input_rdr, dicom_dir); fixed_input_rdr->Update(); return fixed_input_rdr->GetOutput(); } UCharImageType::Pointer load_dicom_uchar (const char *dicom_dir) { DicomUCharReaderType::Pointer fixed_input_rdr = DicomUCharReaderType::New(); load_dicom_dir_rdr (fixed_input_rdr, dicom_dir); fixed_input_rdr->Update(); return fixed_input_rdr->GetOutput(); } ShortImageType::Pointer load_dicom_short (const char *dicom_dir) { DicomShortReaderType::Pointer fixed_input_rdr = DicomShortReaderType::New(); load_dicom_dir_rdr (fixed_input_rdr, dicom_dir); fixed_input_rdr->Update(); return fixed_input_rdr->GetOutput(); } UShortImageType::Pointer load_dicom_ushort (const char *dicom_dir) { DicomUShortReaderType::Pointer fixed_input_rdr = DicomUShortReaderType::New(); load_dicom_dir_rdr (fixed_input_rdr, dicom_dir); fixed_input_rdr->Update(); return fixed_input_rdr->GetOutput(); } Int32ImageType::Pointer load_dicom_int32 (const char *dicom_dir) { DicomInt32ReaderType::Pointer fixed_input_rdr = DicomInt32ReaderType::New(); load_dicom_dir_rdr (fixed_input_rdr, dicom_dir); fixed_input_rdr->Update(); return fixed_input_rdr->GetOutput(); } UInt32ImageType::Pointer load_dicom_uint32 (const char *dicom_dir) { DicomUInt32ReaderType::Pointer fixed_input_rdr = DicomUInt32ReaderType::New(); load_dicom_dir_rdr (fixed_input_rdr, dicom_dir); fixed_input_rdr->Update(); return fixed_input_rdr->GetOutput(); } FloatImageType::Pointer load_dicom_float (const char *dicom_dir) { DicomFloatReaderType::Pointer fixed_input_rdr = DicomFloatReaderType::New(); load_dicom_dir_rdr (fixed_input_rdr, dicom_dir); fixed_input_rdr->Update(); return fixed_input_rdr->GetOutput(); } DoubleImageType::Pointer load_dicom_double (const char *dicom_dir) { DicomDoubleReaderType::Pointer fixed_input_rdr = DicomDoubleReaderType::New(); load_dicom_dir_rdr (fixed_input_rdr, dicom_dir); fixed_input_rdr->Update(); return fixed_input_rdr->GetOutput(); } /* Explicit instantiations */ template void load_dicom_dir_rdr(DicomShortReaderType::Pointer rdr, const char *dicom_dir); template void load_dicom_dir_rdr(DicomUShortReaderType::Pointer rdr, const char *dicom_dir); template void load_dicom_dir_rdr(DicomFloatReaderType::Pointer rdr, const char *dicom_dir); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_dicom_load.h000066400000000000000000000015601321604176500306450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_dicom_load_h_ #define _itk_dicom_load_h_ #include "plmbase_config.h" #include "itk_image_type.h" CharImageType::Pointer load_dicom_char (const char *dicom_dir); UCharImageType::Pointer load_dicom_uchar (const char *dicom_dir); ShortImageType::Pointer load_dicom_short (const char *dicom_dir); UShortImageType::Pointer load_dicom_ushort (const char *dicom_dir); Int32ImageType::Pointer load_dicom_int32 (const char *dicom_dir); UInt32ImageType::Pointer load_dicom_uint32 (const char *dicom_dir); FloatImageType::Pointer load_dicom_float (const char *dicom_dir); DoubleImageType::Pointer load_dicom_double (const char *dicom_dir); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_dicom_save.cxx000066400000000000000000000244231321604176500312420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "itksys/SystemTools.hxx" #include "itkGDCMImageIO.h" #include "itkGDCMSeriesFileNames.h" #include "itkNumericSeriesFileNames.h" #include "itkImageSeriesWriter.h" #include "dicom_util.h" #include "gdcm1_util.h" #include "gdcm2_util.h" #include "itk_dicom_save.h" #include "logfile.h" #include "make_string.h" #include "metadata.h" #include "plm_uid_prefix.h" #include "rt_study_metadata.h" /* winbase.h defines GetCurrentTime which conflicts with gdcm function */ #if defined GetCurrentTime # undef GetCurrentTime #endif #include "gdcmFile.h" #if GDCM_MAJOR_VERSION < 2 #include "gdcmUtil.h" #else #include "gdcmUIDGenerator.h" #endif typedef itk::ImageSeriesWriter < ShortImageType, ShortImage2DType > DicomShortWriterType; typedef itk::GDCMImageIO ImageIOType; static void encapsulate ( itk::MetaDataDictionary& dict, std::string tagkey, std::string value ) { itk::EncapsulateMetaData (dict, tagkey, value); } static const std::string itk_make_uid (ImageIOType::Pointer& gdcmIO) { char uid[100]; const char* uid_root = PLM_UID_PREFIX; std::string uid_string = dicom_uid (uid, uid_root); return uid_string; } static void copy_dictionary ( itk::MetaDataDictionary &fromDict, itk::MetaDataDictionary &toDict ) { typedef itk::MetaDataDictionary DictionaryType; DictionaryType::ConstIterator itr = fromDict.Begin(); DictionaryType::ConstIterator end = fromDict.End(); typedef itk::MetaDataObject< std::string > MetaDataStringType; while( itr != end ) { itk::MetaDataObjectBase::Pointer entry = itr->second; MetaDataStringType::Pointer entryvalue = dynamic_cast( entry.GetPointer() ) ; if( entryvalue ) { std::string tagkey = itr->first; std::string tagvalue = entryvalue->GetMetaDataObjectValue(); itk::EncapsulateMetaData(toDict, tagkey, tagvalue); } ++itr; } } void itk_dicom_save ( ShortImageType::Pointer short_img, /* Input: image to write */ const char *dir_name, /* Input: name of output dir */ Rt_study_metadata *rsm /* In/out: slice uids get set */ ) { typedef itk::NumericSeriesFileNames NamesGeneratorType; const int export_as_ct = 1; itksys::SystemTools::MakeDirectory (dir_name); ImageIOType::Pointer gdcmIO = ImageIOType::New(); gdcmIO->SetUIDPrefix (PLM_UID_PREFIX); /* There is apparently no way to get the ITK-generated UIDs out of ITK without re-reading the files. So we tell ITK not to make them. Instead generate them here, and add them to the dictionary. */ gdcmIO->SetKeepOriginalUID (true); /* Set up a few things in referenced_dicom_dir */ if (rsm) { rsm->set_image_header (short_img); rsm->reset_slice_uids (); } /* PLM (input) metadata */ Metadata::Pointer meta; Metadata::Pointer study_meta; if (rsm) { meta = rsm->get_image_metadata (); study_meta = rsm->get_image_metadata (); } /* DICOM date string looks like this: 20110601 DICOM time string looks like this: 203842 or 203842.805219 */ std::string current_date, current_time; /* Get date and time from original set if available - otherwise get current values */ if (meta) { std::cout<<"date and time from meta"<get_metadata (0x0008, 0x0012); current_time = meta->get_metadata (0x0008, 0x0013); } else{ std::cout<<"date and time from today"<GetMetaDataDictionary(); if (export_as_ct) { /* Image Type */ encapsulate (dict, "0008|0008", "DERIVED\\SECONDARY\\REFORMATTED"); /* SOP Class UID */ encapsulate (dict, "0008|0016", "1.2.840.10008.5.1.4.1.1.2"); /* Modality */ encapsulate (dict, "0008|0060", "CT"); /* Conversion Type */ /* Note: Proton XiO does not like conversion type of SYN */ encapsulate (dict, "0008|0064", ""); } else { /* Export as secondary capture */ /* Image Type */ encapsulate (dict, "0008|0008", "DERIVED\\SECONDARY"); /* Conversion Type */ encapsulate (dict, "0008|0064", "DV"); } /* StudyDate, SeriesDate, AcquisitionDate */ encapsulate (dict, "0008|0021", current_date); encapsulate (dict, "0008|0022", current_date); encapsulate (dict, "0008|0023", current_date); /* StudyTime, SeriesTime, AcquisitionTime */ encapsulate (dict, "0008|0031", current_time); encapsulate (dict, "0008|0032", current_time); encapsulate (dict, "0008|0033", current_time); /* Manufacturer */ encapsulate (dict, "0008|0070", "Plastimatch"); /* InstitutionName */ encapsulate (dict, "0008|0080", ""); /* ManufacturersModelName */ encapsulate (dict, "0008|1090", "Plastimatch"); if (meta) { /* Patient name */ encapsulate (dict, "0010|0010", meta->get_metadata (0x0010, 0x0010)); /* Patient id */ encapsulate (dict, "0010|0020", meta->get_metadata (0x0010, 0x0020)); /* Patient sex */ encapsulate (dict, "0010|0040", meta->get_metadata (0x0010, 0x0040)); /* Series description */ encapsulate (dict, "0008|103e", meta->get_metadata (0x0008, 0x103e)); } else { /* Patient name */ encapsulate (dict, "0010|0010", "ANONYMOUS"); /* Patient id */ encapsulate (dict, "0010|0020", dicom_anon_patient_id()); /* Patient sex */ encapsulate (dict, "0010|0040", "O"); } /* Slice thickness */ std::string value; value = make_string ((double) (short_img->GetSpacing()[2])); encapsulate (dict, "0018|0050", value); /* Patient position */ if (meta) { value = meta->get_metadata (0x0018, 0x5100); if (value == "HFS" || value == "FFS" || value == "HFP" || value == "FFP" || value == "HFDL" || value == "HFDR" || value == "FFDL" || value == "FFDR") { encapsulate (dict, "0018|5100", value); } else { encapsulate (dict, "0018|5100", "HFS"); } } else { encapsulate (dict, "0018|5100", "HFS"); } /* StudyInstanceUID */ value = ""; if (meta) { value = meta->get_metadata (0x0020, 0x000d); } if (value == "") { value = itk_make_uid (gdcmIO); } encapsulate (dict, "0020|000d", value); if (rsm) { rsm->set_study_uid (value.c_str()); } /* SeriesInstanceUID */ value = itk_make_uid (gdcmIO); encapsulate (dict, "0020|000e", value); if (rsm) { rsm->set_ct_series_uid (value.c_str()); } /* StudyId */ value = "10001"; encapsulate (dict, "0020|0010", value); if (study_meta) { study_meta->set_metadata (0x0020, 0x0010, value.c_str()); } /* SeriesNumber */ encapsulate (dict, "0020|0011", "303"); /* Frame of Reference UID */ value = itk_make_uid(gdcmIO); encapsulate (dict, "0020|0052", value); if (rsm) { rsm->set_frame_of_reference_uid (value.c_str()); } /* Position Reference Indicator */ encapsulate (dict, "0020|1040", ""); /* 0008,2112 is "Source Image Sequence", defined as "A Sequence that identifies the set of Image SOP Class/Instance pairs of the Images that were used to derive this Image. Zero or more Items may be included in this Sequence." Ideally, this would be used to refer to the original image before warping. */ /* CERR requires slope and offset */ /* Rescale intercept */ encapsulate (dict, "0028|1052", "0"); /* Rescale slope */ encapsulate (dict, "0028|1053", "1"); /* Can the series writer set Slice Location "0020,1041"? Yes it can. The below code is adapted from: http://www.nabble.com/Read-DICOM-Series-Write-DICOM-Series-with-a-different-number-of-slices-td17357270.html */ DicomShortWriterType::DictionaryArrayType dict_array; for (unsigned int f = 0; f < short_img->GetLargestPossibleRegion().GetSize()[2]; f++) { DicomShortWriterType::DictionaryRawPointer slice_dict = new DicomShortWriterType::DictionaryType; copy_dictionary (dict, *slice_dict); /* SOPInstanceUID */ value = itk_make_uid(gdcmIO); encapsulate (*slice_dict, "0008|0018", value); if (rsm) { #if defined (commentout) rdd->m_ct_slice_uids.push_back(value.c_str()); #endif rsm->set_slice_uid (f, value.c_str()); } /* Image Number */ value = make_string ((int) f); encapsulate (*slice_dict, "0020|0013", value); /* Image Position Patient */ ShortImageType::PointType position; ShortImageType::IndexType index; index[0] = 0; index[1] = 0; index[2] = f; short_img->TransformIndexToPhysicalPoint (index, position); value = make_string (position[0]) + "\\" + make_string (position[1]) + "\\" + make_string (position[2]); encapsulate (*slice_dict, "0020|0032", value); /* Slice Location */ value = make_string ((float) position[2]); encapsulate (*slice_dict, "0020|1041", value); dict_array.push_back (slice_dict); } if (rsm) { rsm->set_slice_list_complete (); } /* Create file names */ DicomShortWriterType::Pointer seriesWriter = DicomShortWriterType::New(); NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New(); ShortImageType::RegionType region = short_img->GetLargestPossibleRegion(); ShortImageType::IndexType start = region.GetIndex(); ShortImageType::SizeType size = region.GetSize(); std::string format = dir_name; format += "/image%04d.dcm"; namesGenerator->SetSeriesFormat (format.c_str()); namesGenerator->SetStartIndex (start[2]); namesGenerator->SetEndIndex (start[2] + size[2] - 1); namesGenerator->SetIncrementIndex (1); seriesWriter->SetInput (short_img); seriesWriter->SetImageIO (gdcmIO); seriesWriter->SetFileNames (namesGenerator->GetFileNames()); seriesWriter->SetMetaDataDictionaryArray (&dict_array); try { seriesWriter->Update(); } catch (itk::ExceptionObject & excp) { std::cerr << "Exception thrown while writing the series " << std::endl; std::cerr << excp << std::endl; exit (-1); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_dicom_save.h000066400000000000000000000011401321604176500306560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_dicom_h_ #define _itk_dicom_h_ #include "plmbase_config.h" #include "itk_image_type.h" class Rt_study_metadata; void itk_dicom_save ( ShortImageType::Pointer short_img, /* Input: image to write */ const char *dir_name, /* Input: name of output dir */ Rt_study_metadata *rsm /* In/out: slice uids get set */ ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_directions.cxx000066400000000000000000000022521321604176500312700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_directions.h" void itk_direction_from_dc (DirectionType* itk_dc, const Direction_cosines& dc) { for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { (*itk_dc)[d1][d2] = dc[d1*3+d2]; } } } void itk_direction_from_dc ( DirectionType* itk_direction, const float dc[9] ) { for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { (*itk_direction)[d1][d2] = dc[d1*3+d2]; } } } void dc_from_itk_direction ( float dc[9], const DirectionType* itk_direction ) { for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { dc[d1*3+d2] = (*itk_direction)[d1][d2]; } } } void itk_direction_set_identity (DirectionType* itk_direction) { for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { (*itk_direction)[d1][d2] = (float) (d1 == d2); } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_directions.h000066400000000000000000000013651321604176500307210ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_directions_h_ #define _itk_directions_h_ #include "plmbase_config.h" #include "direction_cosines.h" #include "itk_image.h" PLMBASE_API void itk_direction_from_dc ( DirectionType* itk_dc, const Direction_cosines& dc ); PLMBASE_API void itk_direction_from_dc ( DirectionType* itk_direction, const float dc[9] ); PLMBASE_C_API void dc_from_itk_direction ( float dc[9], const DirectionType* itk_direction ); PLMBASE_C_API void itk_direction_set_identity (DirectionType* itk_direction); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image.cxx000066400000000000000000000221021321604176500302030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkCastImageFilter.h" #include "itkOrientImageFilter.h" #include "direction_cosines.h" #include "itk_image.h" #include "itk_volume_header.h" #include "plm_image_header.h" #include "plm_int.h" #include "volume_header.h" /* ----------------------------------------------------------------------- Functions ----------------------------------------------------------------------- */ void itk_image_get_props ( const std::string& fileName, int *num_dimensions, itk::ImageIOBase::IOPixelType *pixel_type, itk::ImageIOBase::IOComponentType *component_type, int *num_components ) { *pixel_type = itk::ImageIOBase::UNKNOWNPIXELTYPE; *component_type = itk::ImageIOBase::UNKNOWNCOMPONENTTYPE; *num_dimensions = 0; *num_components = 0; typedef itk::Image ImageType; itk::ImageFileReader::Pointer imageReader = itk::ImageFileReader::New(); imageReader->SetFileName(fileName.c_str()); try { imageReader->UpdateOutputInformation(); *pixel_type = imageReader->GetImageIO()->GetPixelType(); *component_type = imageReader->GetImageIO()->GetComponentType(); *num_dimensions = imageReader->GetImageIO()->GetNumberOfDimensions(); *num_components = imageReader->GetImageIO()->GetNumberOfComponents(); } catch (itk::ExceptionObject &ex) { printf ("ITK exception.\n"); std::cout << ex << std::endl; } } /* ----------------------------------------------------------------------- Reading Image Headers ----------------------------------------------------------------------- */ template void get_image_header (plm_long dim[3], float offset[3], float spacing[3], T image) { typename T::ObjectType::RegionType rg = image->GetLargestPossibleRegion (); typename T::ObjectType::PointType og = image->GetOrigin(); typename T::ObjectType::SpacingType sp = image->GetSpacing(); typename T::ObjectType::SizeType sz = rg.GetSize(); /* Copy header & allocate data for gpuit float */ for (int d = 0; d < 3; d++) { if (dim) { dim[d] = sz[d]; } if (offset) { offset[d] = og[d]; } if (spacing) { spacing[d] = sp[d]; } } } template void itk_image_get_image_header (plm_long dim[3], float offset[3], float spacing[3], Direction_cosines& dc, const T image) { typename T::ObjectType::RegionType rg = image->GetLargestPossibleRegion (); typename T::ObjectType::PointType og = image->GetOrigin(); typename T::ObjectType::SpacingType sp = image->GetSpacing(); typename T::ObjectType::SizeType sz = rg.GetSize(); /* Copy header & allocate data for gpuit float */ for (int d = 0; d < 3; d++) { dim[d] = sz[d]; offset[d] = og[d]; spacing[d] = sp[d]; } /* Copy direction cosines */ DirectionType itk_dc = image->GetDirection (); for (int a = 0; a < 3; a++) { for (int b = 0; b < 3; b++) { dc[a*3+b] = itk_dc[a][b]; } } } template void itk_image_get_volume_header (Volume_header *vh, T image) { itk_image_get_image_header (vh->get_dim(), vh->get_origin(), vh->get_spacing(), vh->get_direction_cosines(), image); } template void itk_image_set_header (T dest, const Plm_image_header *pih) { dest->SetRegions (pih->GetRegion()); dest->SetOrigin (pih->GetOrigin()); dest->SetSpacing (pih->GetSpacing()); dest->SetDirection (pih->GetDirection()); } template void itk_image_set_header (T dest, const Plm_image_header& pih) { itk_image_set_header (dest, &pih); } template void itk_image_header_copy (T dest, U src) { typedef typename U::ObjectType SrcImageType; typedef typename T::ObjectType DestImageType; const typename SrcImageType::RegionType src_rgn = src->GetLargestPossibleRegion(); const typename SrcImageType::PointType& src_og = src->GetOrigin(); const typename SrcImageType::SpacingType& src_sp = src->GetSpacing(); const typename SrcImageType::DirectionType& src_dc = src->GetDirection(); dest->SetRegions (src_rgn); dest->SetOrigin (src_og); dest->SetSpacing (src_sp); dest->SetDirection (src_dc); } /* Return true if the headers are the same */ template bool itk_image_header_compare (T image1, U image2) { typedef typename U::ObjectType I1ImageType; typedef typename T::ObjectType I2ImageType; const SizeType& i1_sz = image1->GetLargestPossibleRegion().GetSize (); const OriginType i1_og = itk_image_origin (image1); const typename I1ImageType::SpacingType& i1_sp = image1->GetSpacing(); const typename I1ImageType::DirectionType& i1_dc = image1->GetDirection(); const SizeType& i2_sz = image2->GetLargestPossibleRegion().GetSize (); const OriginType i2_og = itk_image_origin (image2); const typename I2ImageType::SpacingType& i2_sp = image2->GetSpacing(); const typename I2ImageType::DirectionType& i2_dc = image2->GetDirection(); if (i1_sz != i2_sz || i1_og != i2_og || i1_sp != i2_sp || i1_dc != i2_dc) { return false; } else { return true; } } template void itk_volume_center (float center[3], const T image) { Itk_volume_header ivh; ivh.set_from_itk_image (image); ivh.get_image_center (center); } template T itk_image_fix_negative_spacing (T img) { typename T::ObjectType::SpacingType sp = img->GetSpacing (); typename T::ObjectType::DirectionType dc = img->GetDirection (); for (int d = 0; d < 3; d++) { if (sp[d] < 0) { sp[d] = -sp[d]; for (int dd = 0; dd < 3; dd++) { dc[d][dd] = -dc[d][dd]; } } } return img; } /* Explicit instantiations */ template PLMBASE_API void get_image_header (plm_long dim[3], float offset[3], float spacing[3], UCharImageType::Pointer image); template PLMBASE_API void get_image_header (plm_long dim[3], float offset[3], float spacing[3], ShortImageType::Pointer image); template PLMBASE_API void get_image_header (plm_long dim[3], float offset[3], float spacing[3], UShortImageType::Pointer image); template PLMBASE_API void get_image_header (plm_long dim[3], float offset[3], float spacing[3], FloatImageType::Pointer image); template PLMBASE_API void itk_image_set_header (UCharVecImageType::Pointer, const Plm_image_header *pih); template PLMBASE_API void itk_image_set_header (DeformationFieldType::Pointer, const Plm_image_header *pih); template PLMBASE_API void itk_image_set_header (UCharVecImageType::Pointer, const Plm_image_header& pih); template PLMBASE_API void itk_image_set_header (DeformationFieldType::Pointer, const Plm_image_header& pih); template PLMBASE_API void itk_image_header_copy (UCharVecImageType::Pointer, UCharImageType::Pointer); template PLMBASE_API void itk_image_header_copy (UCharVecImageType::Pointer, UInt32ImageType::Pointer); template PLMBASE_API void itk_image_header_copy (UCharVecImageType::Pointer, UCharVecImageType::Pointer); template PLMBASE_API void itk_image_header_copy (UCharVecImageType::Pointer, DeformationFieldType::Pointer); template PLMBASE_API void itk_image_header_copy (UCharImageType::Pointer, UCharVecImageType::Pointer); template PLMBASE_API void itk_image_header_copy (UCharImageType::Pointer, FloatImageType::Pointer); template PLMBASE_API void itk_image_header_copy (UCharImage2DType::Pointer, UCharVecImage2DType::Pointer); template PLMBASE_API void itk_image_get_volume_header (Volume_header *, DeformationFieldType::Pointer); template PLMBASE_API bool itk_image_header_compare (UCharImageType::Pointer image1, UCharImageType::Pointer image2); template PLMBASE_API void itk_volume_center (float center[3], const FloatImageType::Pointer image); template PLMBASE_API UCharImageType::Pointer itk_image_fix_negative_spacing (UCharImageType::Pointer image); template PLMBASE_API CharImageType::Pointer itk_image_fix_negative_spacing (CharImageType::Pointer image); template PLMBASE_API UShortImageType::Pointer itk_image_fix_negative_spacing (UShortImageType::Pointer image); template PLMBASE_API ShortImageType::Pointer itk_image_fix_negative_spacing (ShortImageType::Pointer image); template PLMBASE_API Int32ImageType::Pointer itk_image_fix_negative_spacing (Int32ImageType::Pointer image); template PLMBASE_API UInt32ImageType::Pointer itk_image_fix_negative_spacing (UInt32ImageType::Pointer image); template PLMBASE_API FloatImageType::Pointer itk_image_fix_negative_spacing (FloatImageType::Pointer image); template PLMBASE_API DoubleImageType::Pointer itk_image_fix_negative_spacing (DoubleImageType::Pointer image); template PLMBASE_API UCharVecImageType::Pointer itk_image_fix_negative_spacing (UCharVecImageType::Pointer image); template PLMBASE_API DeformationFieldType::Pointer itk_image_fix_negative_spacing (DeformationFieldType::Pointer image); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image.h000066400000000000000000000035401321604176500276350ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_h_ #define _itk_image_h_ #include "plmbase_config.h" #include "plm_int.h" #include "itk_image_type.h" class Plm_image_header; class Volume_header; /* Other types */ typedef itk::Matrix < double, 3, 3 > DirectionType; typedef itk::Index < 3 > IndexType; typedef itk::Point < double, 3 > OriginType; typedef itk::ImageRegion < 3 > RegionType; typedef itk::Size < 3 > SizeType; typedef itk::Vector < double, 3 > SpacingType; typedef itk::VariableLengthVector UCharVecType; /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ PLMBASE_C_API void itk_image_get_props ( const std::string& fileName, int *num_dimensions, itk::ImageIOBase::IOPixelType *pixel_type, itk::ImageIOBase::IOComponentType *component_type, int *num_components ); template PLMBASE_API void get_image_header (plm_long dim[3], float offset[3], float spacing[3], T image); template PLMBASE_API void itk_image_get_volume_header (Volume_header *vh, T image); template PLMBASE_API void itk_image_set_header (T image, const Plm_image_header *pih); template PLMBASE_API void itk_image_set_header (T image, const Plm_image_header& pih); template PLMBASE_API void itk_image_header_copy (T dest, U src); template PLMBASE_API bool itk_image_header_compare (T image1, U image2); template PLMBASE_API void itk_volume_center (float center[3], const T image); template PLMBASE_API T itk_image_fix_negative_spacing (T img); #endif itk_image_accumulate.cxx000066400000000000000000000017271321604176500323410ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itkImageRegionIterator.h" #include "itk_image_scale.h" template void itk_image_accumulate ( T img_accumulate, double weight, T img) { typedef typename T::ObjectType ImageType; typedef itk::ImageRegionIterator< ImageType > IteratorType; typename ImageType::RegionType rg = img->GetLargestPossibleRegion (); IteratorType it_a (img_accumulate, rg); IteratorType it_b (img, rg); for (it_a.GoToBegin(), it_b.GoToBegin(); !it_a.IsAtEnd(); ++it_a, ++it_b) { it_a.Set ((double) it_a.Get() + weight * (double) it_b.Get()); } } /* Explicit instantiations */ template PLMBASE_API void itk_image_accumulate (FloatImageType::Pointer, double, FloatImageType::Pointer); itk_image_accumulate.h000066400000000000000000000012031321604176500317530ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_accumulate_h_ #define _itk_image_accumulate_h_ #include "plmbase_config.h" #include "itk_image.h" /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ template PLMBASE_API void itk_image_accumulate ( T img_accumulate, double weight, T img ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_cast.cxx000066400000000000000000000171321321604176500312240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkOrientImageFilter.h" #include "itk_image_type.h" #include "itkClampCastImageFilter.h" /* ----------------------------------------------------------------------- Casting image types ----------------------------------------------------------------------- */ template CharImageType::Pointer cast_char (T image) { typedef typename T::ObjectType ImageType; typedef itk::ClampCastImageFilter < ImageType, CharImageType > ClampCastFilterType; typename ClampCastFilterType::Pointer caster = ClampCastFilterType::New (); caster->SetInput(image); try { caster->Update(); } catch (itk::ExceptionObject & ex) { printf ("ITK exception in CastFilter.\n"); std::cout << ex << std::endl; exit(1); } return caster->GetOutput(); } template UCharImageType::Pointer cast_uchar (T image) { typedef typename T::ObjectType ImageType; typedef itk::ClampCastImageFilter < ImageType, UCharImageType > ClampCastFilterType; typename ClampCastFilterType::Pointer caster = ClampCastFilterType::New(); caster->SetInput(image); try { caster->Update(); } catch (itk::ExceptionObject & ex) { printf ("ITK exception in ClampCastFilter.\n"); std::cout << ex << std::endl; exit(1); } return caster->GetOutput(); } template UShortImageType::Pointer cast_ushort (T image) { typedef typename T::ObjectType ImageType; typedef itk::ClampCastImageFilter < ImageType, UShortImageType > ClampCastFilterType; typename ClampCastFilterType::Pointer caster = ClampCastFilterType::New(); caster->SetInput(image); try { caster->Update(); } catch (itk::ExceptionObject & ex) { printf ("ITK exception in ClampCastFilter.\n"); std::cout << ex << std::endl; exit(1); } return caster->GetOutput(); } template ShortImageType::Pointer cast_short (T image) { typedef typename T::ObjectType ImageType; typedef itk::ClampCastImageFilter < ImageType, ShortImageType > ClampCastFilterType; typename ClampCastFilterType::Pointer caster = ClampCastFilterType::New(); caster->SetInput(image); try { caster->Update(); } catch (itk::ExceptionObject & ex) { printf ("ITK exception in ClampCastFilter.\n"); std::cout << ex << std::endl; exit(1); } return caster->GetOutput(); } template Int32ImageType::Pointer cast_int32 (T image) { typedef typename T::ObjectType ImageType; typedef itk::ClampCastImageFilter < ImageType, Int32ImageType > ClampCastFilterType; typename ClampCastFilterType::Pointer caster = ClampCastFilterType::New(); caster->SetInput(image); try { caster->Update(); } catch (itk::ExceptionObject & ex) { printf ("ITK exception in ClampCastFilter.\n"); std::cout << ex << std::endl; exit(1); } return caster->GetOutput(); } template UInt32ImageType::Pointer cast_uint32 (T image) { typedef typename T::ObjectType ImageType; typedef itk::ClampCastImageFilter < ImageType, UInt32ImageType > ClampCastFilterType; typename ClampCastFilterType::Pointer caster = ClampCastFilterType::New(); caster->SetInput(image); try { caster->Update(); } catch (itk::ExceptionObject & ex) { printf ("ITK exception in ClampCastFilter.\n"); std::cout << ex << std::endl; exit(1); } return caster->GetOutput(); } template FloatImageType::Pointer cast_float (T image) { typedef typename T::ObjectType ImageType; typedef itk::ClampCastImageFilter < ImageType, FloatImageType > ClampCastFilterType; typename ClampCastFilterType::Pointer caster = ClampCastFilterType::New(); caster->SetInput(image); try { caster->Update(); } catch (itk::ExceptionObject & ex) { printf ("ITK exception in ClampCastFilter.\n"); std::cout << ex << std::endl; exit(1); } return caster->GetOutput(); } template DoubleImageType::Pointer cast_double (T image) { typedef typename T::ObjectType ImageType; typedef itk::ClampCastImageFilter < ImageType, DoubleImageType > ClampCastFilterType; typename ClampCastFilterType::Pointer caster = ClampCastFilterType::New(); caster->SetInput(image); try { caster->Update(); } catch (itk::ExceptionObject & ex) { printf ("ITK exception in ClampCastFilter.\n"); std::cout << ex << std::endl; exit(1); } return caster->GetOutput(); } /* Explicit instantiations */ template PLMBASE_API CharImageType::Pointer cast_char (UCharImageType::Pointer); template PLMBASE_API CharImageType::Pointer cast_char (ShortImageType::Pointer); template PLMBASE_API CharImageType::Pointer cast_char (FloatImageType::Pointer); template PLMBASE_API UCharImageType::Pointer cast_uchar (CharImageType::Pointer); template PLMBASE_API UCharImageType::Pointer cast_uchar (UShortImageType::Pointer); template PLMBASE_API UCharImageType::Pointer cast_uchar (ShortImageType::Pointer); template PLMBASE_API UCharImageType::Pointer cast_uchar (UInt32ImageType::Pointer); template PLMBASE_API UCharImageType::Pointer cast_uchar (Int32ImageType::Pointer); template PLMBASE_API UCharImageType::Pointer cast_uchar (FloatImageType::Pointer); template PLMBASE_API UCharImageType::Pointer cast_uchar (DoubleImageType::Pointer); template PLMBASE_API ShortImageType::Pointer cast_short (UCharImageType::Pointer); template PLMBASE_API ShortImageType::Pointer cast_short (UShortImageType::Pointer); template PLMBASE_API ShortImageType::Pointer cast_short (ShortImageType::Pointer); template PLMBASE_API ShortImageType::Pointer cast_short (Int32ImageType::Pointer); template PLMBASE_API ShortImageType::Pointer cast_short (UInt32ImageType::Pointer); template PLMBASE_API ShortImageType::Pointer cast_short (FloatImageType::Pointer); template PLMBASE_API UShortImageType::Pointer cast_ushort (ShortImageType::Pointer); template PLMBASE_API UShortImageType::Pointer cast_ushort (FloatImageType::Pointer); template PLMBASE_API Int32ImageType::Pointer cast_int32 (ShortImageType::Pointer); template PLMBASE_API Int32ImageType::Pointer cast_int32 (FloatImageType::Pointer); template PLMBASE_API UInt32ImageType::Pointer cast_uint32 (UCharImageType::Pointer); template PLMBASE_API UInt32ImageType::Pointer cast_uint32 (ShortImageType::Pointer); template PLMBASE_API UInt32ImageType::Pointer cast_uint32 (FloatImageType::Pointer); template PLMBASE_API FloatImageType::Pointer cast_float (UCharImageType::Pointer); template PLMBASE_API FloatImageType::Pointer cast_float (CharImageType::Pointer); template PLMBASE_API FloatImageType::Pointer cast_float (UShortImageType::Pointer); template PLMBASE_API FloatImageType::Pointer cast_float (ShortImageType::Pointer); template PLMBASE_API FloatImageType::Pointer cast_float (UInt32ImageType::Pointer); template PLMBASE_API FloatImageType::Pointer cast_float (Int32ImageType::Pointer); template PLMBASE_API FloatImageType::Pointer cast_float (FloatImageType::Pointer); template PLMBASE_API FloatImageType::Pointer cast_float (DoubleImageType::Pointer); template PLMBASE_API DoubleImageType::Pointer cast_double (UCharImageType::Pointer); template PLMBASE_API DoubleImageType::Pointer cast_double (ShortImageType::Pointer); template PLMBASE_API DoubleImageType::Pointer cast_double (UInt32ImageType::Pointer); template PLMBASE_API DoubleImageType::Pointer cast_double (FloatImageType::Pointer); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_cast.h000066400000000000000000000021571321604176500306520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_cast_h_ #define _itk_image_cast_h_ #include "plmbase_config.h" #include "itk_image_type.h" /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ template PLMBASE_API CharImageType::Pointer cast_char (T image); template PLMBASE_API UCharImageType::Pointer cast_uchar (T image); template PLMBASE_API ShortImageType::Pointer cast_short (T image); template PLMBASE_API UShortImageType::Pointer cast_ushort (T image); template PLMBASE_API Int32ImageType::Pointer cast_int32 (T image); template PLMBASE_API UInt32ImageType::Pointer cast_uint32 (T image); template PLMBASE_API FloatImageType::Pointer cast_float (T image); template PLMBASE_API DoubleImageType::Pointer cast_double (T image); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_clone.cxx000066400000000000000000000025351321604176500313730ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itkImage.h" #include "itkImageDuplicator.h" #include "itk_image_clone.h" #include "itk_image_create.h" #include "itk_image_type.h" #include "plm_image_header.h" template T itk_image_clone (T image) { typedef typename T::ObjectType ImageType; typedef itk::ImageDuplicator < ImageType > DuplicatorType; typename DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage (image); duplicator->Update(); return duplicator->GetOutput(); } template T itk_image_clone_empty (T image) { T img = T::ObjectType::New (); img->SetOrigin (image->GetOrigin()); img->SetSpacing (image->GetSpacing()); img->SetDirection (image->GetDirection()); img->SetRegions (image->GetLargestPossibleRegion()); img->Allocate (); img->FillBuffer (static_cast(0)); return img; } /* Explicit instantiations */ template PLMBASE_API FloatImageType::Pointer itk_image_clone (FloatImageType::Pointer); template PLMBASE_API UCharImageType::Pointer itk_image_clone_empty (UCharImageType::Pointer); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_clone.h000066400000000000000000000012121321604176500310070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_clone_h_ #define _itk_image_clone_h_ #include "plmbase_config.h" #include "itk_image_type.h" /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ template PLMBASE_API T itk_image_clone (T image); template PLMBASE_API T itk_image_clone_empty (T image); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_conv.cxx000066400000000000000000000061001321604176500312300ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itkConvolutionImageFilter.h" #include "itk_image_conv.h" #include "itk_image_stats.h" /* ITK convolution is broken. I must be "holding it wrong." GCS 2014-08-27 */ typedef itk::Image ImageType; void CreateKernel(ImageType::Pointer kernel, unsigned int width) { ImageType::IndexType start; start.Fill(0); ImageType::SizeType size; size.Fill(width); ImageType::RegionType region; region.SetSize(size); region.SetIndex(start); kernel->SetRegions(region); kernel->Allocate(); itk::ImageRegionIterator imageIterator(kernel, region); while(!imageIterator.IsAtEnd()) { imageIterator.Set(1); ++imageIterator; } } void garbage () { unsigned int width = 3; ImageType::Pointer image = ImageType::New(); ImageType::Pointer kernel = ImageType::New(); CreateKernel(image, 300); CreateKernel(kernel, width); typedef itk::ConvolutionImageFilter FilterType; // Convolve image with kernel. FilterType::Pointer convolutionFilter = FilterType::New(); convolutionFilter->SetInput(image); #if ITK_VERSION_MAJOR >= 4 convolutionFilter->SetKernelImage(kernel); #else convolutionFilter->SetImageKernelInput(kernel); #endif ImageType::Pointer out_img = convolutionFilter->GetOutput(); ImageType::RegionType region = out_img->GetLargestPossibleRegion(); itk::ImageRegionIterator imageIterator(out_img, region); // ImageType::RegionType region = image->GetLargestPossibleRegion(); // itk::ImageRegionIterator imageIterator(image, region); // ImageType::RegionType region = kernel->GetLargestPossibleRegion(); // itk::ImageRegionIterator imageIterator(kernel, region); printf (".....\n"); while(!imageIterator.IsAtEnd()) { printf ("%g ", (float) imageIterator.Get()); ++imageIterator; } printf (".....\n"); } template T itk_image_conv (T img, T kernel) { typedef typename T::ObjectType ImageType; typedef itk::ConvolutionImageFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); filter->SetInput (img); #if ITK_VERSION_MAJOR >= 4 filter->SetKernelImage(kernel); #else filter->SetImageKernelInput(kernel); #endif garbage(); T out_img = filter->GetOutput(); double min_val, max_val, avg; int non_zero, num_vox; // itk_image_stats (itk_image_out, &min_val, &max_val, itk_image_stats (out_img, &min_val, &max_val, &avg, &non_zero, &num_vox); printf (">> MIN %g AVG %g MAX %g NONZERO: (%d / %d)\n", min_val, avg, max_val, non_zero, num_vox); return filter->GetOutput (); } /* Explicit instantiations */ template PLMBASE_API FloatImageType::Pointer itk_image_conv (FloatImageType::Pointer, FloatImageType::Pointer); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_conv.h000066400000000000000000000011201321604176500306520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_conv_h_ #define _itk_image_conv_h_ #include "plmbase_config.h" #include "itk_image.h" /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ template PLMBASE_API T itk_image_conv ( T img, T ker ); #endif itk_image_create.cxx000066400000000000000000000034001321604176500314470ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itkImage.h" #include "itk_image_type.h" #include "itk_image_create.h" #include "plm_image_header.h" /* ----------------------------------------------------------------------- Create a new image ----------------------------------------------------------------------- */ template typename itk::Image::Pointer itk_image_create (const Plm_image_header& pih) { typename itk::Image::Pointer img = itk::Image::New (); img->SetOrigin (pih.GetOrigin()); img->SetSpacing (pih.GetSpacing()); img->SetDirection (pih.GetDirection()); img->SetRegions (pih.GetRegion()); img->Allocate (); img->FillBuffer (static_cast(0)); return img; } template<> DeformationFieldType::Pointer itk_image_create (const Plm_image_header& pih) { DeformationFieldType::Pointer img = DeformationFieldType::New (); img->SetOrigin (pih.GetOrigin()); img->SetSpacing (pih.GetSpacing()); img->SetDirection (pih.GetDirection()); img->SetRegions (pih.GetRegion()); img->Allocate (); FloatVector3DType v; v.Fill (0); img->FillBuffer (v); return img; } /* Explicit instantiations */ template PLMBASE_API itk::Image::Pointer itk_image_create (const Plm_image_header& pih); template PLMBASE_API itk::Image::Pointer itk_image_create (const Plm_image_header& pih); //template PLMBASE_API itk::Image::Pointer itk_image_create (const Plm_image_header& pih); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_create.h000066400000000000000000000012321321604176500311540ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_create_h_ #define _itk_image_create_h_ #include "plmbase_config.h" #include "itkImage.h" class Plm_image_header; /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ template PLMBASE_API typename itk::Image::Pointer itk_image_create ( const Plm_image_header& pih ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_load.h000066400000000000000000000037741321604176500306450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_load_h_ #define _itk_image_load_h_ #include "plmbase_config.h" #include "itk_image_type.h" #include "plm_image_type.h" /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ PLMBASE_API CharImageType::Pointer itk_image_load_char (const char* fname, Plm_image_type* original_type); PLMBASE_API UCharImageType::Pointer itk_image_load_uchar (const char* fname, Plm_image_type* original_type); PLMBASE_API UCharImageType::Pointer itk_image_load_uchar (const std::string& fname, Plm_image_type* original_type); PLMBASE_API ShortImageType::Pointer itk_image_load_short (const char* fname, Plm_image_type* original_type); PLMBASE_API UShortImageType::Pointer itk_image_load_ushort (const char* fname, Plm_image_type* original_type); PLMBASE_API Int32ImageType::Pointer itk_image_load_int32 (const char* fname, Plm_image_type* original_type); PLMBASE_API UInt32ImageType::Pointer itk_image_load_uint32 (const char* fname, Plm_image_type* original_type); PLMBASE_API FloatImageType::Pointer itk_image_load_float (const char* fname, Plm_image_type* original_type); PLMBASE_API FloatImageType::Pointer itk_image_load_float (const std::string& fname, Plm_image_type* original_type); PLMBASE_API DoubleImageType::Pointer itk_image_load_double (const char* fname, Plm_image_type* original_type); PLMBASE_API DeformationFieldType::Pointer itk_image_load_float_field (const char* fname); PLMBASE_API DeformationFieldType::Pointer itk_image_load_float_field (const std::string& fname); PLMBASE_API UCharVecImageType::Pointer itk_image_load_uchar_vec (const char* fname); template PLMBASE_API void get_image_header (int dim[3], float offset[3], float spacing[3], T image); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_load.txx000066400000000000000000000132651321604176500312350ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_load_txx_ #define _itk_image_load_txx_ #include "plmbase_config.h" #include "itkImage.h" #include "itkCastImageFilter.h" #include "itkImageFileReader.h" #include "itkMetaDataDictionary.h" #include "itkOrientImageFilter.h" #include "file_util.h" #include "itk_dicom_load.h" #include "itk_image.h" #include "itk_image_load.h" #include "plm_image_type.h" #include "print_and_exit.h" #include "string_util.h" /* ----------------------------------------------------------------------- Loading Images ----------------------------------------------------------------------- */ template static typename T::Pointer itk_image_load (const char *fn) { typedef typename itk::ImageFileReader < T > ReaderType; typename ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(fn); try { reader->Update(); } catch(itk::ExceptionObject & ex) { printf ("ITK exception reading image file: %s!\n",fn); std::cout << ex << std::endl; getchar(); exit(1); } typename T::Pointer img = reader->GetOutput(); img->SetMetaDataDictionary (reader->GetMetaDataDictionary()); return img; } template static typename itk::Image< U, 3 >::Pointer load_any_2 (const char* fname, T, U) { typedef typename itk::Image < T, 3 > TImageType; typedef typename itk::Image < U, 3 > UImageType; typedef itk::ImageFileReader < TImageType > TReaderType; typedef typename itk::CastImageFilter < TImageType, UImageType > CastFilterType; /* Load image as type T */ typename TImageType::Pointer input_image = itk_image_load (fname); /* Convert images to type U */ typename CastFilterType::Pointer caster = CastFilterType::New(); caster->SetInput (input_image); typename UImageType::Pointer image = caster->GetOutput(); image->Update(); /* Copy metadata */ image->SetMetaDataDictionary (input_image->GetMetaDataDictionary()); /* Return type U */ return image; } static void set_original_type (Plm_image_type *original_type, Plm_image_type t) { if (original_type) { *original_type = t; } } template static typename itk::Image< U, 3 >::Pointer itk_image_load_any ( const char* fname, Plm_image_type* original_type, U otype) { if (!file_exists (fname) && !string_starts_with (fname, "slicer:")) { print_and_exit ("Can't open file \"%s\" for read\n", fname); } int num_dimensions; itk::ImageIOBase::IOPixelType pixelType; itk::ImageIOBase::IOComponentType componentType; int num_components; try { itk_image_get_props (std::string (fname), &num_dimensions, &pixelType, &componentType, &num_components); switch (componentType) { case itk::ImageIOBase::UCHAR: set_original_type (original_type, PLM_IMG_TYPE_ITK_UCHAR); return load_any_2 (fname, static_cast(0), otype); case itk::ImageIOBase::CHAR: set_original_type (original_type, PLM_IMG_TYPE_ITK_CHAR); return load_any_2 (fname, static_cast(0), otype); case itk::ImageIOBase::USHORT: set_original_type (original_type, PLM_IMG_TYPE_ITK_USHORT); return load_any_2 (fname, static_cast(0), otype); case itk::ImageIOBase::SHORT: set_original_type (original_type, PLM_IMG_TYPE_ITK_SHORT); return load_any_2 (fname, static_cast(0), otype); case itk::ImageIOBase::UINT: set_original_type (original_type, PLM_IMG_TYPE_ITK_ULONG); return load_any_2 (fname, static_cast(0), otype); case itk::ImageIOBase::INT: set_original_type (original_type, PLM_IMG_TYPE_ITK_LONG); return load_any_2 (fname, static_cast(0), otype); case itk::ImageIOBase::ULONG: set_original_type (original_type, PLM_IMG_TYPE_ITK_ULONG); return load_any_2 (fname, static_cast(0), otype); case itk::ImageIOBase::LONG: set_original_type (original_type, PLM_IMG_TYPE_ITK_LONG); return load_any_2 (fname, static_cast(0), otype); case itk::ImageIOBase::FLOAT: set_original_type (original_type, PLM_IMG_TYPE_ITK_FLOAT); return load_any_2 (fname, static_cast(0), otype); case itk::ImageIOBase::DOUBLE: set_original_type (original_type, PLM_IMG_TYPE_ITK_DOUBLE); return load_any_2 (fname, static_cast(0), otype); case itk::ImageIOBase::UNKNOWNCOMPONENTTYPE: default: fprintf (stderr, "Error: unhandled file type for loading image (%d) %s\n", componentType, fname); exit (-1); break; } } catch (itk::ExceptionObject &excep) { std::cerr << "ITK xception loading image: " << fname << std::endl; std::cerr << excep << std::endl; exit (-1); } } template T orient_image (T img) { typedef typename T::ObjectType ImageType; typedef typename itk::OrientImageFilter OrienterType; try { typename OrienterType::Pointer orienter = OrienterType::New(); orienter->UseImageDirectionOn (); orienter->SetDesiredCoordinateOrientation ( itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAI); orienter->SetInput (img); orienter->Update (); T output_img = orienter->GetOutput (); output_img->SetMetaDataDictionary (img->GetMetaDataDictionary()); return output_img; } catch (itk::ExceptionObject &e) { std::cerr << "ITK exception orienting image." << std::endl; std::cerr << e << std::endl; exit (-1); } } template T itk_image_load_postprocess (T img) { // img = orient_image (img); img = itk_image_fix_negative_spacing (img); return img; } #endif itk_image_load_char.cxx000066400000000000000000000012411321604176500321210ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_load.txx" CharImageType::Pointer itk_image_load_char (const char* fname, Plm_image_type* original_type) { CharImageType::Pointer img; /* If it is directory, then must be dicom */ if (is_directory(fname)) { img = load_dicom_char (fname); } else { img = itk_image_load_any (fname, original_type, static_cast(0)); } return itk_image_load_postprocess (img); } itk_image_load_double.cxx000066400000000000000000000012451321604176500324620ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_load.txx" DoubleImageType::Pointer itk_image_load_double (const char* fname, Plm_image_type* original_type) { DoubleImageType::Pointer img; /* If it is directory, then must be dicom */ if (is_directory(fname)) { img = load_dicom_double (fname); } else { img = itk_image_load_any (fname, original_type, static_cast(0)); } return itk_image_load_postprocess (img); } itk_image_load_float.cxx000066400000000000000000000015141321604176500323140ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_load.txx" FloatImageType::Pointer itk_image_load_float (const char* fname, Plm_image_type* original_type) { FloatImageType::Pointer img; /* If it is directory, then must be dicom */ if (is_directory(fname)) { img = load_dicom_float (fname); } else { img = itk_image_load_any (fname, original_type, static_cast(0)); } return itk_image_load_postprocess (img); } FloatImageType::Pointer itk_image_load_float (const std::string& fname, Plm_image_type* original_type) { return itk_image_load_float (fname.c_str(), original_type); } itk_image_load_int32.cxx000066400000000000000000000012421321604176500321440ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_load.txx" Int32ImageType::Pointer itk_image_load_int32 (const char* fname, Plm_image_type* original_type) { Int32ImageType::Pointer img; /* If it is directory, then must be dicom */ if (is_directory(fname)) { img = load_dicom_int32 (fname); } else { img = itk_image_load_any (fname, original_type, static_cast(0)); } return itk_image_load_postprocess (img); } itk_image_load_short.cxx000066400000000000000000000012401321604176500323420ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_load.txx" ShortImageType::Pointer itk_image_load_short (const char* fname, Plm_image_type* original_type) { ShortImageType::Pointer img; /* If it is directory, then must be dicom */ if (is_directory(fname)) { img = load_dicom_short (fname); } else { img = itk_image_load_any (fname, original_type, static_cast(0)); } return itk_image_load_postprocess (img); } itk_image_load_uchar.cxx000066400000000000000000000015321321604176500323110ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_load.txx" UCharImageType::Pointer itk_image_load_uchar (const char* fname, Plm_image_type* original_type) { UCharImageType::Pointer img; /* If it is directory, then must be dicom */ if (is_directory(fname)) { img = load_dicom_uchar (fname); } else { img = itk_image_load_any (fname, original_type, static_cast(0)); } return itk_image_load_postprocess (img); } UCharImageType::Pointer itk_image_load_uchar (const std::string& fname, Plm_image_type* original_type) { return itk_image_load_uchar (fname.c_str(), original_type); } itk_image_load_uint32.cxx000066400000000000000000000012471321604176500323360ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_load.txx" UInt32ImageType::Pointer itk_image_load_uint32 (const char* fname, Plm_image_type* original_type) { UInt32ImageType::Pointer img; /* If it is directory, then must be dicom */ if (is_directory(fname)) { img = load_dicom_uint32 (fname); } else { img = itk_image_load_any (fname, original_type, static_cast(0)); } return itk_image_load_postprocess (img); } itk_image_load_ushort.cxx000066400000000000000000000012551321604176500325350ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_load.txx" UShortImageType::Pointer itk_image_load_ushort (const char* fname, Plm_image_type* original_type) { UShortImageType::Pointer img; /* If it is directory, then must be dicom */ if (is_directory(fname)) { img = load_dicom_ushort (fname); } else { img = itk_image_load_any (fname, original_type, static_cast(0)); } return itk_image_load_postprocess (img); } itk_image_load_vec.cxx000066400000000000000000000015221321604176500317630ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_load.txx" UCharVecImageType::Pointer itk_image_load_uchar_vec (const char* fname) { UCharVecImageType::Pointer img = itk_image_load (fname); return itk_image_load_postprocess (img); } DeformationFieldType::Pointer itk_image_load_float_field (const char* fname) { DeformationFieldType::Pointer img = itk_image_load (fname); return itk_image_load_postprocess (img); } DeformationFieldType::Pointer itk_image_load_float_field (const std::string& fname) { return itk_image_load_float_field (fname.c_str()); } itk_image_origin.cxx000066400000000000000000000050761321604176500315060ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_origin.h" template OriginType itk_image_origin (const T& image) { OriginType origin; image->TransformIndexToPhysicalPoint ( image->GetLargestPossibleRegion().GetIndex(), origin); return origin; } template OriginType itk_image_origin (const T* image) { OriginType origin; image->TransformIndexToPhysicalPoint ( image->GetLargestPossibleRegion().GetIndex(), origin); return origin; } /* GCS FIX: The below does not work, because OriginType is a 4D vector */ //template PLMBASE_API OriginType itk_image_origin (const UCharImage4DType::Pointer& image); /* Explicit instantiations */ template PLMBASE_API OriginType itk_image_origin (const CharImageType::Pointer& image); template PLMBASE_API OriginType itk_image_origin (const UCharImageType::Pointer& image); template PLMBASE_API OriginType itk_image_origin (const ShortImageType::Pointer& image); template PLMBASE_API OriginType itk_image_origin (const UShortImageType::Pointer& image); template PLMBASE_API OriginType itk_image_origin (const Int32ImageType::Pointer& image); template PLMBASE_API OriginType itk_image_origin (const UInt32ImageType::Pointer& image); template PLMBASE_API OriginType itk_image_origin (const FloatImageType::Pointer& image); template PLMBASE_API OriginType itk_image_origin (const DoubleImageType::Pointer& image); template PLMBASE_API OriginType itk_image_origin (const DeformationFieldType::Pointer& image); template PLMBASE_API OriginType itk_image_origin (const UCharVecImageType::Pointer& image); template PLMBASE_API OriginType itk_image_origin (const CharImageType* image); template PLMBASE_API OriginType itk_image_origin (const UCharImageType* image); template PLMBASE_API OriginType itk_image_origin (const ShortImageType* image); template PLMBASE_API OriginType itk_image_origin (const UShortImageType* image); template PLMBASE_API OriginType itk_image_origin (const Int32ImageType* image); template PLMBASE_API OriginType itk_image_origin (const UInt32ImageType* image); template PLMBASE_API OriginType itk_image_origin (const FloatImageType* image); template PLMBASE_API OriginType itk_image_origin (const DoubleImageType* image); template PLMBASE_API OriginType itk_image_origin (const DeformationFieldType* image); template PLMBASE_API OriginType itk_image_origin (const UCharVecImageType* image); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_origin.h000066400000000000000000000006631321604176500312070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_origin_h_ #define _itk_image_origin_h_ #include "itk_image.h" template OriginType itk_image_origin (const T&); template OriginType itk_image_origin (const T*); #endif itk_image_region.cxx000066400000000000000000000047451321604176500315040ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_image_region.h" template RegionType itk_image_region (const T& image) { RegionType region = image->GetLargestPossibleRegion(); IndexType index; index[0] = 0; index[1] = 0; index[2] = 0; region.SetIndex (index); return region; } template RegionType itk_image_region (const T* image) { RegionType region = image->GetLargestPossibleRegion(); IndexType index; index[0] = 0; index[1] = 0; index[2] = 0; region.SetIndex (index); return region; } /* Explicit instantiations */ template PLMBASE_API RegionType itk_image_region (const CharImageType::Pointer& image); template PLMBASE_API RegionType itk_image_region (const UCharImageType::Pointer& image); template PLMBASE_API RegionType itk_image_region (const ShortImageType::Pointer& image); template PLMBASE_API RegionType itk_image_region (const UShortImageType::Pointer& image); template PLMBASE_API RegionType itk_image_region (const Int32ImageType::Pointer& image); template PLMBASE_API RegionType itk_image_region (const UInt32ImageType::Pointer& image); template PLMBASE_API RegionType itk_image_region (const FloatImageType::Pointer& image); template PLMBASE_API RegionType itk_image_region (const DoubleImageType::Pointer& image); template PLMBASE_API RegionType itk_image_region (const DeformationFieldType::Pointer& image); template PLMBASE_API RegionType itk_image_region (const UCharVecImageType::Pointer& image); template PLMBASE_API RegionType itk_image_region (const CharImageType* image); template PLMBASE_API RegionType itk_image_region (const UCharImageType* image); template PLMBASE_API RegionType itk_image_region (const ShortImageType* image); template PLMBASE_API RegionType itk_image_region (const UShortImageType* image); template PLMBASE_API RegionType itk_image_region (const Int32ImageType* image); template PLMBASE_API RegionType itk_image_region (const UInt32ImageType* image); template PLMBASE_API RegionType itk_image_region (const FloatImageType* image); template PLMBASE_API RegionType itk_image_region (const DoubleImageType* image); template PLMBASE_API RegionType itk_image_region (const DeformationFieldType* image); template PLMBASE_API RegionType itk_image_region (const UCharVecImageType* image); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_region.h000066400000000000000000000006631321604176500312030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_region_h_ #define _itk_image_region_h_ #include "itk_image.h" template RegionType itk_image_region (const T&); template RegionType itk_image_region (const T*); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_save.cxx000066400000000000000000000165561321604176500312410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "itkCastImageFilter.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkOrientImageFilter.h" #include "file_util.h" #include "itk_dicom_save.h" #include "itk_image_cast.h" #include "itk_image_save.h" #include "logfile.h" #include "print_and_exit.h" #include "path_util.h" /* ----------------------------------------------------------------------- Writing image files ----------------------------------------------------------------------- */ void itk_image_save (const FloatImageType::Pointer& img_ptr, const std::string& fname, Plm_image_type image_type) { itk_image_save (img_ptr, fname.c_str(), image_type); } void itk_image_save (const FloatImageType::Pointer& img_ptr, const char* fname, Plm_image_type image_type) { switch (image_type) { case PLM_IMG_TYPE_ITK_UCHAR: itk_image_save_uchar (img_ptr, fname); break; case PLM_IMG_TYPE_ITK_SHORT: itk_image_save_short (img_ptr, fname); break; case PLM_IMG_TYPE_ITK_USHORT: itk_image_save_ushort (img_ptr, fname); break; case PLM_IMG_TYPE_ITK_LONG: itk_image_save_int32 (img_ptr, fname); break; case PLM_IMG_TYPE_ITK_ULONG: itk_image_save_uint32 (img_ptr, fname); break; case PLM_IMG_TYPE_ITK_FLOAT: itk_image_save_float (img_ptr, fname); break; case PLM_IMG_TYPE_ITK_DOUBLE: itk_image_save_double (img_ptr, fname); break; default: print_and_exit ("Output type is not supported.\n"); break; } } template void itk_image_save (T image, const char* fname) { typedef typename T::ObjectType ImageType; typedef itk::ImageFileWriter< ImageType > WriterType; logfile_printf ("Trying to write image to %s\n", fname); typename WriterType::Pointer writer = WriterType::New(); writer->SetInput (image); writer->SetFileName (fname); make_parent_directories (fname); if (extension_is (fname, "nrrd")) { writer->SetUseCompression (true); } try { writer->Update(); } catch (itk::ExceptionObject& excp) { printf ("ITK exception writing image file.\n"); std::cout << excp << std::endl; } } template void itk_image_save (T image, const std::string& fname) { itk_image_save (image, fname.c_str()); } template void itk_image_save_char (T image, const char* fname) { CharImageType::Pointer char_img = cast_char (image); itk_image_save (char_img, fname); } template void itk_image_save_uchar (T image, const char* fname) { UCharImageType::Pointer uchar_img = cast_uchar (image); itk_image_save (uchar_img, fname); } template void itk_image_save_short (T image, const char* fname) { ShortImageType::Pointer short_img = cast_short (image); itk_image_save (short_img, fname); } template void itk_image_save_ushort (T image, const char* fname) { UShortImageType::Pointer ushort_img = cast_ushort (image); itk_image_save (ushort_img, fname); } template void itk_image_save_short_dicom ( T image, const char* dir_name, Rt_study_metadata *rsm ) { ShortImageType::Pointer short_img = cast_short (image); itk_dicom_save (short_img, dir_name, rsm); } template void itk_image_save_int32 (T image, const char* fname) { Int32ImageType::Pointer int32_img = cast_int32 (image); itk_image_save (int32_img, fname); } template void itk_image_save_uint32 (T image, const char* fname) { UInt32ImageType::Pointer uint32_img = cast_uint32 (image); itk_image_save (uint32_img, fname); } template void itk_image_save_float (T image, const char* fname) { FloatImageType::Pointer float_img = cast_float (image); itk_image_save (float_img, fname); } template void itk_image_save_double (T image, const char* fname) { DoubleImageType::Pointer double_img = cast_double (image); itk_image_save (double_img, fname); } /* Explicit instantiations */ template PLMBASE_API void itk_image_save(CharImageType::Pointer, const char*); template PLMBASE_API void itk_image_save(UCharImageType::Pointer, const char*); template PLMBASE_API void itk_image_save(ShortImageType::Pointer, const char*); template PLMBASE_API void itk_image_save(UShortImageType::Pointer, const char*); template PLMBASE_API void itk_image_save(Int32ImageType::Pointer, const char*); template PLMBASE_API void itk_image_save(UInt32ImageType::Pointer, const char*); template PLMBASE_API void itk_image_save(FloatImageType::Pointer, const char*); template PLMBASE_API void itk_image_save(DoubleImageType::Pointer, const char*); template PLMBASE_API void itk_image_save(DeformationFieldType::Pointer, const char*); template PLMBASE_API void itk_image_save(UCharImage4DType::Pointer, const char*); template PLMBASE_API void itk_image_save(UCharVecImageType::Pointer, const char*); template PLMBASE_API void itk_image_save(CharImageType::Pointer, const std::string&); template PLMBASE_API void itk_image_save(UCharImageType::Pointer, const std::string&); template PLMBASE_API void itk_image_save(ShortImageType::Pointer, const std::string&); template PLMBASE_API void itk_image_save(UShortImageType::Pointer, const std::string&); template PLMBASE_API void itk_image_save(Int32ImageType::Pointer, const std::string&); template PLMBASE_API void itk_image_save(UInt32ImageType::Pointer, const std::string&); template PLMBASE_API void itk_image_save(FloatImageType::Pointer, const std::string&); template PLMBASE_API void itk_image_save(DoubleImageType::Pointer, const std::string&); template PLMBASE_API void itk_image_save(DeformationFieldType::Pointer, const std::string&); template PLMBASE_API void itk_image_save(UCharImage4DType::Pointer, const std::string&); template PLMBASE_API void itk_image_save(UCharVecImageType::Pointer, const std::string&); template PLMBASE_API void itk_image_save_char (FloatImageType::Pointer, const char*); template PLMBASE_API void itk_image_save_uchar (FloatImageType::Pointer, const char*); template PLMBASE_API void itk_image_save_short (FloatImageType::Pointer, const char*); template PLMBASE_API void itk_image_save_ushort (FloatImageType::Pointer, const char*); template PLMBASE_API void itk_image_save_int32 (FloatImageType::Pointer, const char*); template PLMBASE_API void itk_image_save_uint32 (FloatImageType::Pointer, const char*); template PLMBASE_API void itk_image_save_float (FloatImageType::Pointer, const char*); template PLMBASE_API void itk_image_save_double (FloatImageType::Pointer, const char*); template PLMBASE_API void itk_image_save_short_dicom (UCharImageType::Pointer, const char*, Rt_study_metadata *rsm); template PLMBASE_API void itk_image_save_short_dicom (ShortImageType::Pointer, const char*, Rt_study_metadata *rsm); template PLMBASE_API void itk_image_save_short_dicom (UShortImageType::Pointer, const char*, Rt_study_metadata *rsm); template PLMBASE_API void itk_image_save_short_dicom (UInt32ImageType::Pointer, const char*, Rt_study_metadata *rsm); template PLMBASE_API void itk_image_save_short_dicom (FloatImageType::Pointer, const char*, Rt_study_metadata *rsm); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_save.h000066400000000000000000000034641321604176500306600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_save_h_ #define _itk_image_save_h_ #include "plmbase_config.h" #include "itk_image_type.h" #include "plm_image_type.h" class Metadata; class Rt_study_metadata; /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ PLMBASE_API void itk_image_save (const FloatImageType::Pointer& img_ptr, const std::string& fname, Plm_image_type image_type); PLMBASE_API void itk_image_save (const FloatImageType::Pointer& img_ptr, const char* fname, Plm_image_type image_type); template PLMBASE_API void itk_image_save (T img_ptr, const char* fname); template PLMBASE_API void itk_image_save (T img_ptr, const std::string& fname); template PLMBASE_API void itk_image_save_short_dicom (T image, const char* dir_name, Rt_study_metadata *); template PLMBASE_API void itk_image_save_char (T img_ptr, const char* fname); template PLMBASE_API void itk_image_save_uchar (T img_ptr, const char* fname); template PLMBASE_API void itk_image_save_short (T img_ptr, const char* fname); template PLMBASE_API void itk_image_save_ushort (T img_ptr, const char* fname); template PLMBASE_API void itk_image_save_int32 (T img_ptr, const char* fname); template PLMBASE_API void itk_image_save_uint32 (T img_ptr, const char* fname); template PLMBASE_API void itk_image_save_float (T img_ptr, const char* fname); template PLMBASE_API void itk_image_save_double (T img_ptr, const char* fname); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_scale.cxx000066400000000000000000000014701321604176500313570ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itkImageRegionIterator.h" #include "itk_image_scale.h" template void itk_image_scale (T img, float scale) { typedef typename T::ObjectType ImageType; typedef itk::ImageRegionIterator< ImageType > IteratorType; typename ImageType::RegionType rg = img->GetLargestPossibleRegion (); IteratorType it (img, rg); for (it.GoToBegin(); !it.IsAtEnd(); ++it) { double v = (double) it.Get(); it.Set (v * scale); } } /* Explicit instantiations */ template PLMBASE_API void itk_image_scale (FloatImageType::Pointer, float); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_scale.h000066400000000000000000000011341321604176500310010ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_scale_h_ #define _itk_image_scale_h_ #include "plmbase_config.h" #include "itk_image.h" /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ template PLMBASE_API void itk_image_scale ( T img, float scale ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_stats.cxx000066400000000000000000000033401321604176500314240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itkImage.h" #include "itkOrientImageFilter.h" #include "itk_image_type.h" #include "itk_image_stats.h" /* ----------------------------------------------------------------------- Statistics like min, max, etc. ----------------------------------------------------------------------- */ template void itk_image_stats (T img, double *min_val, double *max_val, double *avg, int *non_zero, int *num_vox) { typedef typename T::ObjectType ImageType; typedef itk::ImageRegionIterator< ImageType > IteratorType; typename ImageType::RegionType rg = img->GetLargestPossibleRegion (); IteratorType it (img, rg); int first = 1; double sum = 0.0; *non_zero = 0; *num_vox = 0; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { double v = (double) it.Get(); if (first) { *min_val = *max_val = v; first = 0; } if (*min_val > v) *min_val = v; if (*max_val < v) *max_val = v; sum += v; (*num_vox) ++; if (v != 0.0) { (*non_zero) ++; } } *avg = sum / (*num_vox); } /* Explicit instantiations */ template PLMBASE_API void itk_image_stats (UCharImageType::Pointer, double*, double*, double*, int*, int*); template PLMBASE_API void itk_image_stats (ShortImageType::Pointer, double*, double*, double*, int*, int*); template PLMBASE_API void itk_image_stats (Int32ImageType::Pointer, double*, double*, double*, int*, int*); template PLMBASE_API void itk_image_stats (FloatImageType::Pointer, double*, double*, double*, int*, int*); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_stats.h000066400000000000000000000013041321604176500310470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_stats_h_ #define _itk_image_stats_h_ #include "plmbase_config.h" #include "itk_image.h" /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ template PLMBASE_API void itk_image_stats ( T img, double *min_val, double *max_val, double *avg, int *non_zero, int *num_vox ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_image_type.h000066400000000000000000000041261321604176500306770ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_image_type_h_ #define _itk_image_type_h_ #include "plmbase_config.h" /* itkImage.h emits warnings on gcc when used with itkKernelTransform */ //#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6) //#pragma GCC diagnostic push //#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" //#endif #include "itkImage.h" //#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6) //#pragma GCC diagnostic pop //#endif #include "itkImageIOBase.h" #include "itkVectorImage.h" #include "itk_point.h" /* 4D images */ typedef itk::Image < unsigned char, 4 > UCharImage4DType; /* 3D images */ typedef itk::Image < char, 3 > CharImageType; typedef itk::Image < unsigned char, 3 > UCharImageType; typedef itk::Image < short, 3 > ShortImageType; typedef itk::Image < unsigned short, 3 > UShortImageType; #if (CMAKE_SIZEOF_UINT == 4) typedef itk::Image < int, 3 > Int32ImageType; typedef itk::Image < unsigned int, 3 > UInt32ImageType; #else typedef itk::Image < long, 3 > Int32ImageType; typedef itk::Image < unsigned long, 3 > UInt32ImageType; #endif typedef itk::Image < float, 3 > FloatImageType; typedef itk::Image < double, 3 > DoubleImageType; typedef itk::VectorImage < unsigned char, 3 > UCharVecImageType; /* 2D images */ typedef itk::Image < unsigned char, 2 > UCharImage2DType; typedef itk::Image < short, 2 > ShortImage2DType; typedef itk::Image < unsigned short, 2 > UShortImage2DType; #if (CMAKE_SIZEOF_UINT == 4) typedef itk::Image < int, 2 > Int32Image2DType; typedef itk::Image < unsigned int, 2 > UInt32Image2DType; #else typedef itk::Image < long, 2 > Int32Image2DType; typedef itk::Image < unsigned long, 2 > UInt32Image2DType; #endif typedef itk::Image < float, 2 > FloatImage2DType; typedef itk::Image < double, 2 > DoubleImage2DType; typedef itk::VectorImage < unsigned char, 2 > UCharVecImage2DType; /* Vector field */ typedef itk::Image < FloatVector3DType, 3 > DeformationFieldType; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_metadata.cxx000066400000000000000000000047251321604176500307140ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "itkImageRegionIterator.h" #include "itkMetaDataDictionary.h" #include "itkMetaDataObject.h" #include "itk_metadata.h" void itk_metadata_set ( itk::MetaDataDictionary *dict, const char *tag, const char *value ) { typedef itk::MetaDataObject< std::string > MetaDataStringType; itk::EncapsulateMetaData ( *dict, std::string (tag), std::string (value)); itk::MetaDataDictionary::ConstIterator itr = dict->Begin(); itk::MetaDataDictionary::ConstIterator end = dict->End(); while ( itr != end ) { itk::MetaDataObjectBase::Pointer entry = itr->second; MetaDataStringType::Pointer entryvalue = dynamic_cast( entry.GetPointer()); if (entryvalue) { std::string tagkey = itr->first; std::string tagvalue = entryvalue->GetMetaDataObjectValue(); std::cout << tagkey << " = " << tagvalue << std::endl; } ++itr; } } void itk_metadata_print_1 ( itk::MetaDataDictionary *dict ) { typedef itk::MetaDataObject< std::string > MetaDataStringType; itk::MetaDataDictionary::ConstIterator itr = dict->Begin(); itk::MetaDataDictionary::ConstIterator end = dict->End(); printf ("ITK Metadata...\n"); while ( itr != end ) { itk::MetaDataObjectBase::Pointer entry = itr->second; MetaDataStringType::Pointer entryvalue = dynamic_cast( entry.GetPointer()); if (entryvalue) { std::string tagkey = itr->first; std::string tagvalue = entryvalue->GetMetaDataObjectValue(); std::cout << tagkey << " = " << tagvalue << std::endl; } ++itr; } } /* This is just another example of how to use the API */ void itk_metadata_print_2 ( itk::MetaDataDictionary *dict ) { typedef itk::MetaDataObject< std::string > MetaDataStringType; std::vector keys = dict->GetKeys(); std::vector::const_iterator key = keys.begin(); std::string meta_string; printf ("ITK Metadata (2)...\n"); while (key != keys.end()) { std::cout << *key << " " << meta_string << std::endl; ++key; } } void itk_metadata_print ( itk::MetaDataDictionary *dict ) { itk_metadata_print_1 (dict); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_metadata.h000066400000000000000000000012571321604176500303360ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_metadata_h_ #define _itk_metadata_h_ #include "plmbase_config.h" /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ PLMBASE_API void itk_metadata_set ( itk::MetaDataDictionary *dict, const char *tag, const char *value ); PLMBASE_API void itk_metadata_print ( itk::MetaDataDictionary *dict ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_point.h000066400000000000000000000014571321604176500277110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_point_h_ #define _itk_point_h_ #include "plmbase_config.h" #include #include "itkPoint.h" #include "itkVector.h" /* Points & vectors */ typedef itk::Point < float, 2 > FloatPoint2DType; typedef itk::Point < double, 2 > DoublePoint2DType; typedef itk::Point < float, 3 > FloatPoint3DType; typedef itk::Point < double, 3 > DoublePoint3DType; typedef itk::Vector < float, 2 > FloatVector2DType; typedef itk::Vector < double, 2 > DoubleVector2DType; typedef itk::Vector < float, 3 > FloatVector3DType; typedef itk::Vector < double, 3 > DoubleVector3DType; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_pointset.cxx000066400000000000000000000157511321604176500310020ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include "itk_pointset.h" #include "pointset.h" #include "print_and_exit.h" #include "raw_pointset.h" #include "xform.h" #include "xform_point.h" /* Don't get confused by the parameterization of the itk pointset. The PixelType is the "color" of the point, whereas the PointType is the type used to represent the coordinate location */ Raw_pointset* raw_pointset_from_itk_float_pointset (FloatPointSetType::Pointer itk_ps) { typedef FloatPointSetType::PointsContainer PointsContainerType; typedef PointsContainerType::Iterator PointsIteratorType; Raw_pointset *ps = pointset_create (); PointsContainerType::Pointer itk_ps_c = itk_ps->GetPoints (); PointsIteratorType it = itk_ps_c->Begin(); PointsIteratorType end = itk_ps_c->End(); unsigned int i = 0; while (it != end) { FloatPoint3DType p = it.Value(); pointset_resize (ps, i + 1); ps->points[i*3+0] = p[0]; ps->points[i*3+1] = p[1]; ps->points[i*3+2] = p[2]; ++it; ++i; } return ps; } FloatPointSetType::Pointer itk_float_pointset_from_raw_pointset (Raw_pointset *ps) { FloatPointSetType::Pointer itk_ps = FloatPointSetType::New (); FloatPointSetType::PointsContainer::Pointer itk_ps_c = itk_ps->GetPoints (); FloatPointIdType id = itk::NumericTraits< FloatPointIdType >::Zero; for (int i = 0; i < ps->num_points; i++) { FloatPoint3DType p1; p1[0] = ps->points[i*3+0]; p1[1] = ps->points[i*3+1]; p1[2] = ps->points[i*3+2]; itk_ps_c->InsertElement (id++, p1); } return itk_ps; } DoublePointSetType::Pointer itk_double_pointset_from_raw_pointset (Raw_pointset *ps) { DoublePointSetType::Pointer itk_ps = DoublePointSetType::New (); DoublePointSetType::PointsContainer::Pointer itk_ps_c = itk_ps->GetPoints (); DoublePointIdType id = itk::NumericTraits< DoublePointIdType >::Zero; for (int i = 0; i < ps->num_points; i++) { DoublePoint3DType p1; p1[0] = ps->points[i*3+0]; p1[1] = ps->points[i*3+1]; p1[2] = ps->points[i*3+2]; itk_ps_c->InsertElement (id++, p1); } return itk_ps; } template FloatPointSetType::Pointer itk_float_pointset_from_pointset (const Pointset *ps) { FloatPointSetType::Pointer itk_ps = FloatPointSetType::New (); FloatPointSetType::PointsContainer::Pointer itk_ps_c = itk_ps->GetPoints (); FloatPointIdType id = itk::NumericTraits< FloatPointIdType >::Zero; for (unsigned int i = 0; i < ps->get_count(); i++) { FloatPoint3DType p1; p1[0] = ps->point_list[i].p[0]; p1[1] = ps->point_list[i].p[1]; p1[2] = ps->point_list[i].p[2]; itk_ps_c->InsertElement (id++, p1); } return itk_ps; } template DoublePointSetType::Pointer itk_double_pointset_from_pointset (const Pointset& ps) { DoublePointSetType::Pointer itk_ps = DoublePointSetType::New (); DoublePointSetType::PointsContainer::Pointer itk_ps_c = itk_ps->GetPoints (); DoublePointIdType id = itk::NumericTraits< DoublePointIdType >::Zero; for (unsigned int i = 0; i < ps.get_count(); i++) { DoublePoint3DType p1; p1[0] = ps.point_list[i].p[0]; p1[1] = ps.point_list[i].p[1]; p1[2] = ps.point_list[i].p[2]; itk_ps_c->InsertElement (id++, p1); } return itk_ps; } Unlabeled_pointset* unlabeled_pointset_from_itk_float_pointset (FloatPointSetType::Pointer itk_ps) { typedef FloatPointSetType::PointsContainer PointsContainerType; typedef PointsContainerType::Iterator PointsIteratorType; Unlabeled_pointset *ps = new Unlabeled_pointset; PointsContainerType::Pointer itk_ps_c = itk_ps->GetPoints (); PointsIteratorType it = itk_ps_c->Begin(); PointsIteratorType end = itk_ps_c->End(); while (it != end) { FloatPoint3DType p = it.Value(); ps->insert_lps ("", p[0], p[1], p[2]); ++it; } return ps; } template void itk_pointset_load (T pointset, const char* fn) { typedef typename T::ObjectType PointSetType; typedef typename PointSetType::PointType PointType; typedef typename PointSetType::PointsContainer PointsContainerType; FILE* fp; const int MAX_LINE = 2048; char line[MAX_LINE]; float p[3]; PointType tp; fp = fopen (fn, "r"); if (!fp) { print_and_exit ("Error loading pointset file: %s\n", fn); } typename PointsContainerType::Pointer points = PointsContainerType::New(); unsigned int i = 0; while (fgets (line, MAX_LINE, fp)) { if (sscanf (line, "%g %g %g", &p[0], &p[1], &p[2]) != 3) { print_and_exit ("Warning: bogus line in pointset file \"%s\"\n", fn); } tp[0] = p[0]; tp[1] = p[1]; tp[2] = p[2]; printf ("Loading: %g %g %g\n", p[0], p[1], p[2]); points->InsertElement (i++, tp); } pointset->SetPoints (points); fclose (fp); } template T itk_pointset_warp (T ps_in, Xform* xf) { typedef typename T::ObjectType PointSetType; typedef typename PointSetType::PointType PointType; typedef typename PointSetType::PixelType PixelType; typedef typename PointSetType::PointsContainer PointsContainerType; typedef typename PointsContainerType::Iterator PointsIteratorType; typename PointSetType::Pointer ps_out = PointSetType::New(); typename PointsContainerType::Pointer points_out = PointsContainerType::New(); typename PointsContainerType::Pointer points_in = ps_in->GetPoints (); PointType tp; PointsIteratorType it = points_in->Begin(); PointsIteratorType end = points_in->End(); unsigned int i = 0; while (it != end) { PointType p = it.Value(); xform_point_transform (&tp, xf, p); points_out->InsertElement (i, tp); ++it; ++i; } ps_out->SetPoints (points_out); return ps_out; } template void itk_pointset_debug (T pointset) { typedef typename T::ObjectType PointSetType; typedef typename PointSetType::PointType PointType; typedef typename PointSetType::PointsContainer PointsContainerType; typedef typename PointsContainerType::Iterator PointsIteratorType; typename PointsContainerType::Pointer points = pointset->GetPoints (); PointsIteratorType it = points->Begin(); PointsIteratorType end = points->End(); while (it != end) { PointType p = it.Value(); printf ("%g %g %g\n", p[0], p[1], p[2]); ++it; } } /* Explicit instantiations */ template PLMBASE_API void itk_pointset_debug (FloatPointSetType::Pointer pointset); template PLMBASE_API void itk_pointset_debug (DoublePointSetType::Pointer pointset); template PLMBASE_API void itk_pointset_load (FloatPointSetType::Pointer pointset, const char* fn); template PLMBASE_API FloatPointSetType::Pointer itk_pointset_warp (FloatPointSetType::Pointer ps_in, Xform* xf); template PLMBASE_API FloatPointSetType::Pointer itk_float_pointset_from_pointset (const Unlabeled_pointset *ps); template PLMBASE_API DoublePointSetType::Pointer itk_double_pointset_from_pointset (const Labeled_pointset& ps); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_pointset.h000066400000000000000000000037331321604176500304240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_pointset_h_ #define _itk_pointset_h_ #include "plmbase_config.h" #include "itkPointSet.h" #include "itkDefaultStaticMeshTraits.h" #include "itk_point.h" class Point; class Xform; template class Pointset; typedef struct raw_pointset Raw_pointset; typedef Pointset Unlabeled_pointset; typedef itk::DefaultStaticMeshTraits< float, 3, 3, float, float > FloatPointSetTraitsType; typedef itk::PointSet< FloatPoint3DType, 3, FloatPointSetTraitsType > FloatPointSetType; typedef FloatPointSetType::PointIdentifier FloatPointIdType; typedef itk::DefaultStaticMeshTraits< double, 3, 3, double, double > DoublePointSetTraitsType; typedef itk::PointSet< DoublePoint3DType, 3, DoublePointSetTraitsType > DoublePointSetType; typedef DoublePointSetType::PointIdentifier DoublePointIdType; typedef itk::PointSet< short, 3 > ShortPointSetType; typedef ShortPointSetType::PointsContainer ShortPointsContainer; template void itk_pointset_load (T pointset, const char* fn); template T itk_pointset_warp (T ps_in, Xform* xf); template void itk_pointset_debug (T pointset); PLMBASE_API FloatPointSetType::Pointer itk_float_pointset_from_raw_pointset (Raw_pointset *ps); PLMBASE_API DoublePointSetType::Pointer itk_double_pointset_from_raw_pointset (Raw_pointset *ps); template PLMBASE_API FloatPointSetType::Pointer itk_float_pointset_from_pointset (const Pointset *ps); template PLMBASE_API DoublePointSetType::Pointer itk_double_pointset_from_pointset (const Pointset& ps); PLMBASE_API Unlabeled_pointset* unlabeled_pointset_from_itk_float_pointset (FloatPointSetType::Pointer itk_ps); PLMBASE_API Raw_pointset* raw_pointset_from_itk_float_pointset (FloatPointSetType::Pointer itk_ps); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_resample.cxx000066400000000000000000000331311321604176500307350ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itkLinearInterpolateImageFunction.h" #include "itkImage.h" #include "itkResampleImageFilter.h" #include "itkAffineTransform.h" #include "itkVectorResampleImageFilter.h" #include "itkNearestNeighborInterpolateImageFunction.h" #include "itk_image_type.h" #include "itk_resample.h" #include "logfile.h" #include "plm_image_header.h" #include "ss_img_extract.h" template T vector_resample_image (const T& vf_image, const Plm_image_header* pih) { typedef typename T::ObjectType VFImageType; typedef itk::VectorResampleImageFilter < VFImageType, VFImageType > FilterType; typedef itk::VectorLinearInterpolateImageFunction< VFImageType, double > InterpolatorType; typename FilterType::Pointer filter = FilterType::New(); filter->SetOutputOrigin (pih->GetOrigin()); filter->SetOutputSpacing (pih->GetSpacing()); filter->SetSize (pih->GetSize()); filter->SetOutputDirection (pih->GetDirection()); typedef itk::AffineTransform< double, 3 > TransformType; TransformType::Pointer transform = TransformType::New(); filter->SetTransform (transform); typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); filter->SetInterpolator (interpolator); FloatVector3DType v; v[0] = v[1] = v[2] = 0; filter->SetDefaultPixelValue (v); filter->SetInput (vf_image); try { filter->Update(); } catch(itk::ExceptionObject & ex) { printf ("Exception running vector resample filter!\n"); std::cout << ex << std::endl; getchar(); exit(1); } T out_image = filter->GetOutput(); return out_image; } template static T resample_image ( T& image, DoublePoint3DType origin, DoubleVector3DType spacing, SizeType size, const DirectionType& direction, float default_val, int interp_lin) { typedef typename T::ObjectType ImageType; typedef typename T::ObjectType::PixelType PixelType; typedef itk::ResampleImageFilter < ImageType, ImageType > FilterType; typedef itk::LinearInterpolateImageFunction< ImageType, double > LinInterpType; typedef itk::NearestNeighborInterpolateImageFunction < ImageType, double > NNInterpType; typename FilterType::Pointer filter = FilterType::New(); filter->SetOutputOrigin (origin); filter->SetOutputSpacing (spacing); filter->SetSize (size); filter->SetOutputDirection (direction); typedef itk::AffineTransform< double, 3 > TransformType; TransformType::Pointer transform = TransformType::New(); filter->SetTransform (transform); typename LinInterpType::Pointer l_interpolator = LinInterpType::New(); typename NNInterpType::Pointer nn_interpolator = NNInterpType::New(); if (interp_lin) { filter->SetInterpolator (l_interpolator); } else { filter->SetInterpolator (nn_interpolator); } filter->SetDefaultPixelValue ((PixelType) default_val); filter->SetInput (image); try { filter->Update(); } catch(itk::ExceptionObject & ex) { printf ("Exception running image resample filter!\n"); std::cout << ex << std::endl; getchar(); exit(1); } T out_image = filter->GetOutput(); return out_image; } template T resample_image ( T& image, const Plm_image_header* pih, float default_val, int interp_lin) { return resample_image (image, pih->GetOrigin(), pih->GetSpacing(), pih->GetSize(), pih->GetDirection(), default_val, interp_lin); } template T resample_image ( T& image, const Plm_image_header& pih, float default_val, int interp_lin) { return resample_image (image, pih.GetOrigin(), pih.GetSpacing(), pih.GetSize(), pih.GetDirection(), default_val, interp_lin); } template T resample_image (T& image, float spacing[3]) { typedef typename T::ObjectType ImageType; typedef typename T::ObjectType::PixelType PixelType; typedef itk::ResampleImageFilter < ImageType, ImageType > FilterType; typedef itk::LinearInterpolateImageFunction< ImageType, double > InterpolatorType; const typename ImageType::SpacingType& old_spacing = image->GetSpacing(); const typename ImageType::PointType& old_origin = image->GetOrigin(); typename ImageType::SizeType old_size = image->GetLargestPossibleRegion().GetSize(); float old_coverage[3]; float coverage[3]; typename ImageType::SpacingType itk_spacing; typename ImageType::SizeType size; typename ImageType::PointType origin; for (int d = 0; d < 3; d++) { itk_spacing[d] = spacing[d]; old_coverage[d] = old_size[d] * old_spacing[d]; size[d] = (unsigned long) (old_coverage[d] / spacing[d]); coverage[d] = size[d] * spacing[d]; origin[d] = old_origin[d]; } lprintf ("New spacing at %f %f %f\n", spacing[0], spacing[1], spacing[2]); lprintf ("Resample size was %ld %ld %ld\n", old_size[0], old_size[1], old_size[2]); lprintf ("Resample size will be %ld %ld %ld\n", size[0], size[1], size[2]); lprintf ("Resample coverage was %g %g %g\n", old_coverage[0], old_coverage[1], old_coverage[2]); lprintf ("Resample coverage will be %g %g %g\n", coverage[0], coverage[1], coverage[2]); typename FilterType::Pointer filter = FilterType::New(); filter->SetSize (size); filter->SetOutputOrigin (origin); filter->SetOutputSpacing (itk_spacing); filter->SetOutputDirection (image->GetDirection()); typedef itk::AffineTransform< double, 3 > TransformType; TransformType::Pointer transform = TransformType::New(); filter->SetTransform (transform); typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); filter->SetInterpolator (interpolator); const PixelType default_val = 0; /* Hard coded... */ filter->SetDefaultPixelValue ((PixelType) default_val); filter->SetInput (image); try { filter->Update(); } catch(itk::ExceptionObject & ex) { printf ("Exception running resample image filter!\n"); std::cout << ex << std::endl; getchar(); exit(1); } T out_image = filter->GetOutput(); return out_image; } UCharVecImageType::Pointer resample_image (UCharVecImageType::Pointer image, float spacing[3]) { typedef UCharVecImageType ImageType; const ImageType::SpacingType& old_spacing = image->GetSpacing(); const ImageType::PointType& old_origin = image->GetOrigin(); ImageType::SizeType old_size = image->GetLargestPossibleRegion().GetSize(); float old_coverage[3]; ImageType::SpacingType itk_spacing; ImageType::SizeType size; ImageType::PointType origin; ImageType::RegionType rg; for (int d = 0; d < 3; d++) { itk_spacing[d] = spacing[d]; old_coverage[d] = old_size[d] * old_spacing[d]; size[d] = (unsigned long) (old_coverage[d] / spacing[d]); origin[d] = old_origin[d]; } rg.SetSize (size); unsigned int num_uchar = image->GetVectorLength(); UCharVecImageType::Pointer im_out = UCharVecImageType::New(); im_out->SetOrigin (origin); im_out->SetSpacing (itk_spacing); im_out->SetRegions (rg); im_out->SetDirection (image->GetDirection()); im_out->SetVectorLength (image->GetVectorLength()); im_out->Allocate (); for (unsigned int uchar_no = 0; uchar_no < num_uchar; uchar_no++) { UCharImageType::Pointer uchar_img = ss_img_extract_uchar (image, uchar_no); UCharImageType::Pointer uchar_img_resampled = resample_image (uchar_img, Plm_image_header (im_out), 0.f, 0); ss_img_insert_uchar (im_out, uchar_img_resampled, uchar_no); } return im_out; } template T subsample_image (T& image, int x_sampling_rate, int y_sampling_rate, int z_sampling_rate, float default_val) { typedef typename T::ObjectType ImageType; typedef typename T::ObjectType::PixelType PixelType; typedef itk::ResampleImageFilter < ImageType, ImageType > FilterType; typename FilterType::Pointer filter = FilterType::New(); typedef itk::LinearInterpolateImageFunction< ImageType, double > InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); int sampling_rate[3]; sampling_rate[0] = x_sampling_rate; sampling_rate[1] = y_sampling_rate; sampling_rate[2] = z_sampling_rate; /* GCS TODO: Separate out default pixel value stuff */ filter->SetInterpolator (interpolator); filter->SetDefaultPixelValue ((PixelType) default_val); const typename ImageType::SpacingType& spacing1 = image->GetSpacing(); const typename ImageType::PointType& origin1 = image->GetOrigin(); const typename ImageType::SizeType size1 = image->GetLargestPossibleRegion().GetSize(); typename ImageType::SpacingType spacing; typename ImageType::SizeType size; typename ImageType::PointType origin; for (int i = 0; i < 3; i++) { spacing[i] = spacing1[i] * sampling_rate[i]; origin[i] = origin1[i] + 0.5 * (sampling_rate[i]-1) * spacing1[i]; size[i] = (int) ceil(((float) size1[i] / sampling_rate[i]) - 0.5); } //compute_origin_and_size (origin, size, spacing, origin1, spacing1, size1); filter->SetOutputOrigin (origin); filter->SetOutputSpacing (spacing); filter->SetSize (size); // GCS FIX: Assume direction cosines orthogonal filter->SetOutputDirection (image->GetDirection()); typedef itk::AffineTransform< double, 3 > TransformType; TransformType::Pointer transform = TransformType::New(); filter->SetTransform( transform ); filter->SetInput( image ); try { filter->Update(); } catch(itk::ExceptionObject & ex) { printf ("Exception running image subsample filter!\n"); std::cout << ex << std::endl; getchar(); exit(1); } T out_image = filter->GetOutput(); return out_image; } /* Explicit instantiations */ template PLMBASE_API DeformationFieldType::Pointer vector_resample_image (const DeformationFieldType::Pointer&, const Plm_image_header*); template PLMBASE_API UCharImageType::Pointer resample_image (UCharImageType::Pointer&, const Plm_image_header*, float default_val, int interp_lin); template PLMBASE_API CharImageType::Pointer resample_image (CharImageType::Pointer&, const Plm_image_header*, float default_val, int interp_lin); template PLMBASE_API UShortImageType::Pointer resample_image (UShortImageType::Pointer&, const Plm_image_header*, float default_val, int interp_lin); template PLMBASE_API ShortImageType::Pointer resample_image (ShortImageType::Pointer&, const Plm_image_header*, float default_val, int interp_lin); template PLMBASE_API UInt32ImageType::Pointer resample_image (UInt32ImageType::Pointer&, const Plm_image_header*, float default_val, int interp_lin); template PLMBASE_API Int32ImageType::Pointer resample_image (Int32ImageType::Pointer&, const Plm_image_header*, float default_val, int interp_lin); template PLMBASE_API FloatImageType::Pointer resample_image (FloatImageType::Pointer&, const Plm_image_header*, float default_val, int interp_lin); template PLMBASE_API DoubleImageType::Pointer resample_image (DoubleImageType::Pointer&, const Plm_image_header*, float default_val, int interp_lin); template PLMBASE_API UCharImageType::Pointer resample_image (UCharImageType::Pointer&, const Plm_image_header&, float default_val, int interp_lin); template PLMBASE_API CharImageType::Pointer resample_image (CharImageType::Pointer&, const Plm_image_header&, float default_val, int interp_lin); template PLMBASE_API UShortImageType::Pointer resample_image (UShortImageType::Pointer&, const Plm_image_header&, float default_val, int interp_lin); template PLMBASE_API ShortImageType::Pointer resample_image (ShortImageType::Pointer&, const Plm_image_header&, float default_val, int interp_lin); template PLMBASE_API UInt32ImageType::Pointer resample_image (UInt32ImageType::Pointer&, const Plm_image_header&, float default_val, int interp_lin); template PLMBASE_API Int32ImageType::Pointer resample_image (Int32ImageType::Pointer&, const Plm_image_header&, float default_val, int interp_lin); template PLMBASE_API FloatImageType::Pointer resample_image (FloatImageType::Pointer&, const Plm_image_header&, float default_val, int interp_lin); template PLMBASE_API DoubleImageType::Pointer resample_image (DoubleImageType::Pointer&, const Plm_image_header&, float default_val, int interp_lin); template PLMBASE_API FloatImageType::Pointer resample_image (FloatImageType::Pointer&, float spacing[3]); template PLMBASE_API UCharImageType::Pointer subsample_image (UCharImageType::Pointer&, int, int, int, float); template PLMBASE_API CharImageType::Pointer subsample_image (CharImageType::Pointer&, int, int, int, float); template PLMBASE_API UShortImageType::Pointer subsample_image (UShortImageType::Pointer&, int, int, int, float); template PLMBASE_API ShortImageType::Pointer subsample_image (ShortImageType::Pointer&, int, int, int, float); template PLMBASE_API UInt32ImageType::Pointer subsample_image (UInt32ImageType::Pointer&, int, int, int, float); template PLMBASE_API Int32ImageType::Pointer subsample_image (Int32ImageType::Pointer&, int, int, int, float); template PLMBASE_API FloatImageType::Pointer subsample_image (FloatImageType::Pointer&, int, int, int, float); template PLMBASE_API DoubleImageType::Pointer subsample_image (DoubleImageType::Pointer&, int, int, int, float); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_resample.h000066400000000000000000000017731321604176500303710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_resample_h_ #define _itk_resample_h_ #include "plmbase_config.h" #include "itk_image_type.h" class Plm_image_header; template T vector_resample_image (const T& vf_image, const Plm_image_header* pih); template T resample_image (T& image, const Plm_image_header* pih, float default_val, int interp_lin); template T resample_image (T& image, const Plm_image_header& pih, float default_val, int interp_lin); template T resample_image (T& image, float spacing[3]); PLMBASE_API UCharVecImageType::Pointer resample_image (UCharVecImageType::Pointer image, float spacing[3]); template T subsample_image (T& image, int x_sampling_rate, int y_sampling_rate, int z_sampling_rate, float default_val); #endif itk_volume_header.cxx000066400000000000000000000115421321604176500316670ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "itkImageRegionIterator.h" #include "bspline_xform.h" #include "itk_directions.h" #include "itk_image.h" #include "itk_volume_header.h" #include "plm_int.h" /* ----------------------------------------------------------------------- prototypes ----------------------------------------------------------------------- */ static void itk_direction_from_gpuit ( DirectionType* itk_direction, float gpuit_direction_cosines[9] ); static void itk_direction_identity (DirectionType* itk_direction); /* ----------------------------------------------------------------------- functions ----------------------------------------------------------------------- */ void Itk_volume_header::set_origin (float origin[3]) { for (unsigned int d = 0; d < 3; d++) { this->m_origin[d] = origin[d]; } } void Itk_volume_header::set_spacing (float spacing[3]) { for (unsigned int d = 0; d < 3; d++) { this->m_spacing[d] = spacing[d]; } } void Itk_volume_header::set_dim (plm_long dim[3]) { SizeType itk_size; IndexType itk_index; for (unsigned int d = 0; d < 3; d++) { itk_index[d] = 0; itk_size[d] = dim[d]; } m_region.SetSize (itk_size); m_region.SetIndex (itk_index); } void Itk_volume_header::set_from_gpuit ( float gpuit_origin[3], float gpuit_spacing[3], plm_long gpuit_dim[3], float gpuit_direction_cosines[9]) { SizeType itk_size; IndexType itk_index; for (unsigned int d1 = 0; d1 < 3; d1++) { m_origin[d1] = gpuit_origin[d1]; m_spacing[d1] = gpuit_spacing[d1]; itk_index[d1] = 0; itk_size[d1] = gpuit_dim[d1]; } if (gpuit_direction_cosines) { itk_direction_from_gpuit (&m_direction, gpuit_direction_cosines); } else { itk_direction_identity (&m_direction); } m_region.SetSize (itk_size); m_region.SetIndex (itk_index); } void Itk_volume_header::set_from_gpuit_bspline (Bspline_xform *bxf) { this->set_from_gpuit ( bxf->img_origin, bxf->img_spacing, bxf->img_dim, 0); } void Itk_volume_header::get_origin (float origin[3]) { for (unsigned int d = 0; d < 3; d++) { origin[d] = m_origin[d]; } } void Itk_volume_header::get_spacing (float spacing[3]) { for (unsigned int d = 0; d < 3; d++) { spacing[d] = m_spacing[d]; } } void Itk_volume_header::get_dim (plm_long dim[3]) { SizeType itk_size = m_region.GetSize (); for (unsigned int d = 0; d < 3; d++) { dim[d] = itk_size[d]; } } void Itk_volume_header::get_direction_cosines (float direction_cosines[9]) { dc_from_itk_direction (direction_cosines, &m_direction); } void Itk_volume_header::print (void) const { SizeType itk_size; itk_size = m_region.GetSize (); printf ("Origin ="); for (unsigned int d = 0; d < 3; d++) { printf (" %g", m_origin[d]); } printf ("\nSize ="); for (unsigned int d = 0; d < 3; d++) { printf (" %lu", itk_size[d]); } printf ("\nSpacing ="); for (unsigned int d = 0; d < 3; d++) { printf (" %g", m_spacing[d]); } printf ("\nDirection ="); for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { printf (" %g", m_direction[d1][d2]); } } printf ("\n"); } void Itk_volume_header::get_image_center (float center[3]) { for (int d1 = 0; d1 < 3; d1++) { center[d1] = this->m_origin[d1]; } for (int d1 = 0; d1 < 3; d1++) { float v = this->m_spacing[d1] * (this->Size(d1) - 1.) / 2; for (int d2 = 0; d2 < 3; d2++) { center[d2] += v * m_direction[d2][d1]; } } } /* Return 1 if the two headers are the same */ int Itk_volume_header::compare (Itk_volume_header *pli1, Itk_volume_header *pli2) { int d; for (d = 0; d < 3; d++) { if (pli1->m_origin[d] != pli2->m_origin[d]) return 0; if (pli1->m_spacing[d] != pli2->m_spacing[d]) return 0; if (pli1->Size(d) != pli2->Size(d)) return 0; } /* GCS FIX: check direction cosines */ return 1; } /* ----------------------------------------------------------------------- global functions ----------------------------------------------------------------------- */ static void itk_direction_from_gpuit ( DirectionType* itk_direction, float gpuit_direction_cosines[9] ) { for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { (*itk_direction)[d1][d2] = gpuit_direction_cosines[d1*3+d2]; } } } static void itk_direction_identity (DirectionType* itk_direction) { for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { (*itk_direction)[d1][d2] = (float) (d1 == d2); } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_volume_header.h000066400000000000000000000047721321604176500314020ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_volume_header_h_ #define _itk_volume_header_h_ #include "plmbase_config.h" #include "itk_image_type.h" class Bspline_xform; class PLMBASE_API Itk_volume_header { public: RegionType m_region; OriginType m_origin; SpacingType m_spacing; DirectionType m_direction; public: Itk_volume_header () {} Itk_volume_header ( float origin[3], float spacing[3], plm_long dim[3]) { this->set_from_gpuit (origin, spacing, dim, 0); } Itk_volume_header ( float origin[3], float spacing[3], plm_long dim[3], float direction_cosines[9]) { this->set_from_gpuit (origin, spacing, dim, direction_cosines); } public: int Size (int d) const { return m_region.GetSize()[d]; } public: /* Return 1 if the two headers are the same */ static int compare (Itk_volume_header *pli1, Itk_volume_header *pli2); public: void set_origin (float origin[3]); void set_spacing (float spacing[3]); void set_dim (plm_long dim[3]); void set_from_gpuit (float gpuit_origin[3], float gpuit_spacing[3], plm_long gpuit_dim[3], float gpuit_direction_cosines[9]); void set_from_gpuit_bspline (Bspline_xform *bxf); template void set_from_itk_image (const T image) { m_origin = image->GetOrigin (); m_spacing = image->GetSpacing (); m_region = image->GetLargestPossibleRegion (); m_direction = image->GetDirection (); } static void clone (Itk_volume_header *dest, Itk_volume_header *src) { dest->m_origin = src->m_origin; dest->m_spacing = src->m_spacing; dest->m_region = src->m_region; dest->m_direction = src->m_direction; } void get_origin (float origin[3]); void get_spacing (float spacing[3]); void get_dim (plm_long dim[3]); void get_direction_cosines ( float direction_cosines[9]); void print (void) const; void get_image_center (float center[3]); }; /* ----------------------------------------------------------------------- Global functions ----------------------------------------------------------------------- */ void direction_cosines_from_itk ( float direction_cosines[9], DirectionType* itk_direction ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_warp.cxx000066400000000000000000000101401321604176500300710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include "itkConfigure.h" #include "itkImage.h" #include "itkLinearInterpolateImageFunction.h" #include "itkNearestNeighborInterpolateImageFunction.h" #include "itkWarpImageFilter.h" #include "itk_image.h" #include "itk_warp.h" #include "ss_img_extract.h" /* Warp the image. im_in: the image which is warped vf: the vector field. output size = vf size. default_val: the value to use for pixels outside the volume */ template T itk_warp_image ( T im_in, DeformationFieldType::Pointer vf, int linear_interp, U default_val) { typedef typename T::ObjectType TBase; typedef typename T::ObjectType::PixelType PixelType; typedef itk::WarpImageFilter < TBase, TBase, DeformationFieldType > T_FilterType; typedef itk::LinearInterpolateImageFunction < TBase, double > T_LinInterpType; typedef itk::NearestNeighborInterpolateImageFunction < TBase, double > T_NNInterpType; T im_out = TBase::New(); typename T_FilterType::Pointer filter = T_FilterType::New(); typename T_LinInterpType::Pointer l_interpolator = T_LinInterpType::New(); typename T_NNInterpType::Pointer nn_interpolator = T_NNInterpType::New(); const typename TBase::PointType& og = vf->GetOrigin(); const typename TBase::SpacingType& sp = vf->GetSpacing(); const typename TBase::DirectionType& di = vf->GetDirection(); if (linear_interp) { filter->SetInterpolator (l_interpolator); } else { filter->SetInterpolator (nn_interpolator); } filter->SetOutputSpacing (sp); filter->SetOutputOrigin (og); filter->SetOutputDirection (di); #if ITK_VERSION_MAJOR == 3 filter->SetDeformationField (vf); #else /* ITK 4 */ filter->SetDisplacementField (vf); #endif filter->SetInput (im_in); filter->SetEdgePaddingValue ((PixelType) default_val); try { filter->Update(); } catch( itk::ExceptionObject & excp ) { std::cerr << "Exception thrown " << std::endl; std::cerr << excp << std::endl; } im_out = filter->GetOutput(); im_out->Update(); return im_out; } UCharVecImageType::Pointer itk_warp_image ( UCharVecImageType::Pointer im_in, DeformationFieldType::Pointer vf, int linear_interp, unsigned char default_val ) { UCharVecImageType::Pointer im_out = UCharVecImageType::New(); itk_image_header_copy (im_out, vf); im_out->SetVectorLength (im_in->GetVectorLength()); im_out->Allocate (); unsigned int num_uchar = im_in->GetVectorLength(); for (unsigned int uchar_no = 0; uchar_no < num_uchar; uchar_no++) { UCharImageType::Pointer uchar_img = ss_img_extract_uchar (im_in, uchar_no); UCharImageType::Pointer uchar_img_warped = itk_warp_image (uchar_img, vf, linear_interp, default_val); ss_img_insert_uchar (im_out, uchar_img_warped, uchar_no); } return im_out; } /* Explicit instantiations */ template PLMBASE_API UCharImageType::Pointer itk_warp_image (UCharImageType::Pointer im_in, DeformationFieldType::Pointer vf, int linear_interp, unsigned char default_val); template PLMBASE_API UShortImageType::Pointer itk_warp_image (UShortImageType::Pointer im_in, DeformationFieldType::Pointer vf, int linear_interp, unsigned short default_val); template PLMBASE_API ShortImageType::Pointer itk_warp_image (ShortImageType::Pointer im_in, DeformationFieldType::Pointer vf, int linear_interp, short default_val); template PLMBASE_API UInt32ImageType::Pointer itk_warp_image (UInt32ImageType::Pointer im_in, DeformationFieldType::Pointer vf, int linear_interp, uint32_t default_val); template PLMBASE_API FloatImageType::Pointer itk_warp_image (FloatImageType::Pointer im_in, DeformationFieldType::Pointer vf, int linear_interp, float default_val); template PLMBASE_API DoubleImageType::Pointer itk_warp_image (DoubleImageType::Pointer im_in, DeformationFieldType::Pointer vf, int linear_interp, double default_val); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/itk_warp.h000066400000000000000000000013111321604176500275160ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_warp_h_ #define _itk_warp_h_ #include "plmbase_config.h" #include "itk_image_type.h" template T PLMBASE_API itk_warp_image ( T im_in, DeformationFieldType::Pointer vf, int linear_interp, U default_val ); PLMBASE_API UCharVecImageType::Pointer itk_warp_image ( UCharVecImageType::Pointer im_in, DeformationFieldType::Pointer vf, int linear_interp, unsigned char default_val ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/make_string.h000066400000000000000000000011721321604176500302060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _make_string_h_ #define _make_string_h_ #include "plmbase_config.h" #include #include template static std::string make_string ( T t, int width = 0, char fill = ' ', std::ios_base & (*f)(std::ios_base&) = std::dec ) { std::stringstream ss; ss << std::setw (width); ss << std::setfill (fill); ss << f << t; return ss.str(); } #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/mc_dose.cxx000066400000000000000000000105411321604176500276670ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "mc_dose.h" #include "plm_image.h" #include "plm_int.h" #include "print_and_exit.h" #include "volume.h" #include "xio_ct.h" #include "xio_ct_transform.h" /* Monte Carlo 3ddose files are generated by DOSXYZ, DPM and probably others. Block 1 - number of voxels in x,y,z directions (nx,ny,nz) Block 2 - voxel boundaries (cm) in x direction (nx+1 values) Block 3 - voxel boundaries (cm) in y direction (ny+1 values) Block 4 - voxel boundaries (cm) in z direction (nz+1 values) Block 5 - dose values 3D array (nx*ny*nz values) Block 6 - error values 3D array (nx*ny*nz values) */ typedef struct mc_dose_header MC_dose_header; struct mc_dose_header { plm_long dim[3]; float origin[3]; float spacing[3]; int header_size; }; static void mc_dose_load_header (MC_dose_header *mcdh, const char *filename) { std::ifstream input(filename); std::vector header; int i; float value; if (!input) { print_and_exit ("Error opening file %s for read\n", filename); } /* Get dimensions */ for (i = 0; i < 3; i++) { if (input >> value) { header.push_back(value); } else { print_and_exit ("Dose file %s header is invalid\n", filename); } } mcdh->dim[0] = header[0]; mcdh->dim[1] = header[1]; mcdh->dim[2] = header[2]; mcdh->header_size = 3 + 3 + mcdh->dim[0] + mcdh->dim[1] + mcdh->dim[2]; /* Read rest of header */ for (i = 0; i < mcdh->header_size - 3; i++) { if (input >> value) { header.push_back(value); } else { print_and_exit ("Dose file %s is invalid\n", filename); } } /* Get origin */ mcdh->origin[0] = header[3] * 10; mcdh->origin[1] = header[3 + 1 + mcdh->dim[0]] * 10; mcdh->origin[2] = header[3 + 2 + mcdh->dim[0] + mcdh->dim[1]] * 10; /* Get element spacing */ /* NOTE: assuming uniform spacing! */ mcdh->spacing[0] = (header[4] - header[3]) * 10; mcdh->spacing[1] = (header[4 + 1 + mcdh->dim[0]] - header[3 + 1 + mcdh->dim[0]]) * 10; mcdh->spacing[2] = (header[4 + 2 + mcdh->dim[0] + mcdh->dim[1]] - header[3 + 2 + mcdh->dim[0] + mcdh->dim[1]]) * 10; input.close(); } static void mc_dose_load_cube ( Plm_image *pli, MC_dose_header *mcdh, const char *filename ) { std::ifstream input(filename); float value; Volume *v; float *cube_img_read; v = pli->get_vol (); cube_img_read = (float*) v->img; if (!input) { print_and_exit ("Error opening file %s for read\n", filename); } /* Skip header */ for (int i=0; i < mcdh->header_size; i++) { if (!(input >> value)) { print_and_exit ("Dose file %s is invalid\n", filename); } } /* Read dose cube */ for (plm_long z=0; z < mcdh->dim[2]; z++) { for (plm_long y=0; y < mcdh->dim[1]; y++) { for (plm_long x=0; x < mcdh->dim[0]; x++) { if (input >> value) { cube_img_read[x + y*mcdh->dim[0] + z*mcdh->dim[0]*mcdh->dim[1]] = value; } else { print_and_exit ("Dose file %s is invalid\n", filename); } } } } input.close(); } static void mc_dose_create_volume ( Plm_image *pli, MC_dose_header *mcdh ) { Volume *v; v = new Volume (mcdh->dim, mcdh->origin, mcdh->spacing, 0, PT_FLOAT, 1); pli->set_volume (v); printf ("img: %p\n", v->img); printf ("Image dim: %u %u %u\n", (unsigned int) v->dim[0], (unsigned int) v->dim[1], (unsigned int) v->dim[2]); } void mc_dose_load (Plm_image *pli, const char *filename) { MC_dose_header mcdh; mc_dose_load_header(&mcdh, filename); mc_dose_create_volume(pli, &mcdh); mc_dose_load_cube(pli, &mcdh, filename); } void mc_dose_apply_transform (Plm_image *pli, Xio_ct_transform *transform) { /* Transform coordinates of MC dose cube to DICOM coordinates */ Volume *v = pli->get_vol (); /* Set origins */ v->origin[0] = (v->origin[0] * transform->direction_cosines[0]) + transform->x_offset; v->origin[1] = (v->origin[1] * transform->direction_cosines[4]) + transform->y_offset; /* Set direction cosines */ v->set_direction_cosines (transform->direction_cosines); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/mc_dose.h000066400000000000000000000007721321604176500273210ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _mc_dose_h_ #define _mc_dose_h_ #include "plmbase_config.h" class Plm_image; class Xio_ct_transform; PLMBASE_API void mc_dose_load (Plm_image *plm, const char *filename); PLMBASE_API void mc_dose_apply_transform (Plm_image *plm, Xio_ct_transform *transform); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/metadata.cxx000066400000000000000000000065721321604176500300470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #if PLM_DCM_USE_DCMTK #include "dcmtk_config.h" #include "dcmtk/dcmdata/dctagkey.h" #endif #include "dicom_util.h" #include "logfile.h" #include "make_string.h" #include "metadata.h" static std::string KEY_NOT_FOUND = ""; Metadata::Metadata () { } Metadata::~Metadata () { } std::string Metadata::make_key (unsigned short key1, unsigned short key2) const { return make_string (key1, 4, '0', std::hex) + ',' + make_string (key2, 4, '0', std::hex); } const std::string& Metadata::get_metadata (const std::string& key) const { std::map::const_iterator it; it = m_data.find (key); if (it == m_data.end()) { /* key not found in map -- check parent */ if (m_parent) { return m_parent->get_metadata (key); } /* key not found */ return KEY_NOT_FOUND; } else { /* key found in map */ return it->second; } } const std::string& Metadata::get_metadata (unsigned short key1, unsigned short key2) const { #if defined (commentout) std::cout << "Getting metadata: " << make_key (key1, key2) << " is " << get_metadata (make_key (key1, key2)) << std::endl; #endif return get_metadata (make_key (key1, key2)); } void Metadata::set_metadata (const std::string& key, const std::string& val) { #if defined (commentout) std::cout << "Setting metadata: " << key << " to " << val << std::endl; #endif m_data[key] = val; } void Metadata::set_metadata (unsigned short key1, unsigned short key2, const std::string& val) { set_metadata (make_key (key1, key2), val); } #if PLM_DCM_USE_DCMTK const std::string& Metadata::get_metadata (const DcmTagKey& key) const { return get_metadata (key.getGroup(), key.getElement()); } void Metadata::set_metadata (const DcmTagKey& key, const std::string& val) { return set_metadata (key.getGroup(), key.getElement(), val); } #endif void Metadata::set_metadata (const std::vector& metadata) { std::vector::const_iterator it = metadata.begin(); while (it < metadata.end()) { const std::string& str = (*it); size_t eq_pos = str.find_first_of ('='); if (eq_pos != std::string::npos) { std::string key = str.substr (0, eq_pos); std::string val = str.substr (eq_pos+1); /* Set newer-style metadata, used by dcmtk */ this->set_metadata (key, val); } ++it; } } void Metadata::remove_metadata (unsigned short key1, unsigned short key2) { m_data.erase (make_key (key1, key2)); } void Metadata::create_anonymous () { /* PatientsName */ this->set_metadata (0x0010, 0x0010, "ANONYMOUS"); /* PatientID */ this->set_metadata (0x0010, 0x0020, dicom_anon_patient_id()); /* PatientSex */ this->set_metadata (0x0010, 0x0040, "O"); /* PatientPosition */ this->set_metadata (0x0018, 0x5100, "HFS"); } void Metadata::print_metadata () const { std::map::const_iterator it; lprintf ("Metadata\n"); for (it = m_data.begin(); it != m_data.end(); it++) { lprintf ("%s | %s\n", it->first.c_str(), it->second.c_str()); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/metadata.h000066400000000000000000000042251321604176500274650ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _metadata_h_ #define _metadata_h_ #include "plmbase_config.h" #include #include #include #if PLM_DCM_USE_DCMTK #include "dcmtk_config.h" #include "dcmtk/dcmdata/dctagkey.h" #endif #include "smart_pointer.h" /*! \brief * The Metadata class encapsulate DICOM metadata for a single series. * It is implemented as a map from string to string, where the * key string is of the form "XXXX,XXXX". */ class PLMBASE_API Metadata { public: SMART_POINTER_SUPPORT (Metadata); Metadata (); ~Metadata (); public: /* GCS: Note use of unsigned short instead of uint16_t, because of broken stdint implementation in gdcm 1.X. */ std::string make_key (unsigned short key1, unsigned short key2) const; const std::string& get_metadata (const std::string& key) const; const std::string& get_metadata (unsigned short key1, unsigned short key2) const; void set_metadata (const std::string& key, const std::string& val); void set_metadata (unsigned short key1, unsigned short key2, const std::string& val); #if PLM_DCM_USE_DCMTK const std::string& get_metadata (const DcmTagKey& key) const; void set_metadata (const DcmTagKey& key, const std::string& val); #endif /*! \brief Copy a list of strings of the form "XXXX,YYYY=string" into the metadata map. */ void set_metadata (const std::vector& metadata); /*! \brief Attach a parent to this metadata set. The parent metadata is used when there is no match in the child metadata. */ void set_parent (const Metadata::Pointer& parent) { m_parent = parent; } /*! \brief Remove a key from the metadata, if the key exists. */ void remove_metadata (unsigned short key1, unsigned short key2); void create_anonymous (); void print_metadata () const; public: Metadata::Pointer m_parent; std::map m_data; public: }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/mha_io.cxx000066400000000000000000000151051321604176500275130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #if (defined(_WIN32) || defined(WIN32)) #include // windows // #endif #include "file_util.h" #include "mha_io.h" #include "plm_endian.h" #include "plm_fwrite.h" #include "print_and_exit.h" #include "string_util.h" #include "volume.h" #define LINELEN 512 /* ----------------------------------------------------------------------- Private functions ----------------------------------------------------------------------- */ static void write_mha_internal ( const char* filename, /* Input: filename to write to */ const Volume* vol /* Input: volume to write */ ) { FILE* fp; char* mha_header = "ObjectType = Image\n" "NDims = 3\n" "BinaryData = True\n" "BinaryDataByteOrderMSB = False\n" "TransformMatrix = %g %g %g %g %g %g %g %g %g\n" "Offset = %g %g %g\n" "CenterOfRotation = 0 0 0\n" "ElementSpacing = %g %g %g\n" "DimSize = %d %d %d\n" "AnatomicalOrientation = RAI\n" "%s" "ElementType = %s\n" "ElementDataFile = LOCAL\n"; char* element_type; if (vol->pix_type == PT_VF_FLOAT_PLANAR) { fprintf (stderr, "Error, PT_VF_FLOAT_PLANAR not implemented\n"); exit (-1); } fp = plm_fopen (filename,"wb"); if (!fp) { fprintf (stderr, "Can't open file %s for write\n", filename); return; } switch (vol->pix_type) { case PT_UCHAR: element_type = "MET_UCHAR"; break; case PT_SHORT: element_type = "MET_SHORT"; break; case PT_UINT32: element_type = "MET_UINT"; break; case PT_FLOAT: element_type = "MET_FLOAT"; break; case PT_VF_FLOAT_INTERLEAVED: element_type = "MET_FLOAT"; break; case PT_VF_FLOAT_PLANAR: default: fprintf (stderr, "Unhandled type in write_mha().\n"); exit (-1); } fprintf (fp, mha_header, vol->direction_cosines[0], vol->direction_cosines[3], vol->direction_cosines[6], vol->direction_cosines[1], vol->direction_cosines[4], vol->direction_cosines[7], vol->direction_cosines[2], vol->direction_cosines[5], vol->direction_cosines[8], vol->origin[0], vol->origin[1], vol->origin[2], vol->spacing[0], vol->spacing[1], vol->spacing[2], vol->dim[0], vol->dim[1], vol->dim[2], (vol->pix_type == PT_VF_FLOAT_INTERLEAVED) ? "ElementNumberOfChannels = 3\n" : "", element_type); fflush (fp); if (vol->pix_type == PT_VF_FLOAT_INTERLEAVED) { plm_fwrite (vol->img, sizeof(float), 3 * vol->npix, fp, true); } else { plm_fwrite (vol->img, vol->pix_size, vol->npix, fp, true); } fclose (fp); } static Volume* read_mha_internal ( const char* filename /* Input: filename to read from */ ) { size_t rc; char linebuf[LINELEN]; Volume* vol; int tmp; FILE* fp; bool have_direction_cosines = false; bool big_endian_input = false; unsigned int a, b, c; float dc[9]; fp = fopen (filename,"rb"); if (!fp) { fprintf (stderr, "File %s not found\n", filename); return 0; } fprintf(stdout, "reading %s\n", filename); vol = new Volume; vol->pix_size = -1; vol->pix_type = PT_UNDEFINED; while (fgets (linebuf, LINELEN, fp)) { string_util_rtrim_whitespace (linebuf); if (strcmp (linebuf, "ElementDataFile = LOCAL") == 0) { break; } if (sscanf (linebuf, "DimSize = %d %d %d", &a, &b, &c) == 3) { vol->dim[0] = a; vol->dim[1] = b; vol->dim[2] = c; vol->npix = vol->dim[0] * vol->dim[1] * vol->dim[2]; continue; } if (sscanf (linebuf, "Offset = %g %g %g", &vol->origin[0], &vol->origin[1], &vol->origin[2]) == 3) { continue; } if (sscanf (linebuf, "ElementSpacing = %g %g %g", &vol->spacing[0], &vol->spacing[1], &vol->spacing[2]) == 3) { continue; } if (sscanf (linebuf, "TransformMatrix = %g %g %g %g %g %g %g %g %g", &dc[0], &dc[3], &dc[6], &dc[1], &dc[4], &dc[7], &dc[2], &dc[5], &dc[8]) == 9) { have_direction_cosines = true; continue; } if (sscanf (linebuf, "ElementNumberOfChannels = %d", &tmp) == 1) { if (vol->pix_type == PT_UNDEFINED || vol->pix_type == PT_FLOAT) { vol->pix_type = PT_VF_FLOAT_INTERLEAVED; vol->pix_size = 3*sizeof(float); } continue; } if (strcmp (linebuf, "ElementType = MET_FLOAT") == 0) { if (vol->pix_type == PT_UNDEFINED) { vol->pix_type = PT_FLOAT; vol->pix_size = sizeof(float); } continue; } if (strcmp (linebuf, "ElementType = MET_SHORT") == 0) { vol->pix_type = PT_SHORT; vol->pix_size = sizeof(short); continue; } if (strcmp (linebuf, "ElementType = MET_UCHAR") == 0) { vol->pix_type = PT_UCHAR; vol->pix_size = sizeof(unsigned char); continue; } if (strcmp (linebuf, "BinaryDataByteOrderMSB = True") == 0) { big_endian_input = true; } } if (vol->pix_size <= 0) { printf ("Oops, couldn't interpret mha data type\n"); exit (-1); } /* Update proj and step matrices */ if (have_direction_cosines) { vol->set_direction_cosines (dc); } else { vol->set_direction_cosines (0); } vol->img = malloc (vol->pix_size*vol->npix); if (!vol->img) { printf ("Oops, out of memory\n"); exit (-1); } rc = fread (vol->img, vol->pix_size, vol->npix, fp); if (rc != (size_t) vol->npix) { printf ("Oops, bad read from file (%u)\n", (unsigned int) rc); exit (-1); } /* Swap endian-ness if necessary */ if (vol->pix_type == PT_VF_FLOAT_INTERLEAVED) { if (big_endian_input) { endian4_big_to_native (vol->img, 3 * vol->npix); } else { endian4_little_to_native (vol->img, 3 * vol->npix); } } else if (vol->pix_size == 2) { if (big_endian_input) { endian2_big_to_native (vol->img, vol->npix); } else { endian2_little_to_native (vol->img, vol->npix); } } else if (vol->pix_size == 4) { if (big_endian_input) { endian4_big_to_native (vol->img, vol->npix); } else { endian4_little_to_native (vol->img, vol->npix); } } else if (vol->pix_size != 1) { print_and_exit ("Unknown pixel size: %u\n", vol->pix_size); } fclose (fp); return vol; } /* ----------------------------------------------------------------------- Public functions ----------------------------------------------------------------------- */ void write_mha (const char* filename, const Volume* vol) { write_mha_internal (filename, vol); } Volume* read_mha (const char* filename) { return read_mha_internal (filename); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/mha_io.h000066400000000000000000000006761321604176500271470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _mha_io_h_ #define _mha_io_h_ #include "plmbase_config.h" class Volume; PLMBASE_C_API Volume* read_mha (const char* filename); PLMBASE_C_API void write_mha (const char* filename, const Volume* vol); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/nki_io.cxx000066400000000000000000000071721321604176500275340ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include "nkidecompress.h" #include "file_util.h" #include "logfile.h" #include "nki_io.h" #include "plm_int.h" #include "volume.h" #define LINELEN 512 Volume* nki_load (const char* filename) { char linebuf[LINELEN]; FILE *fp = fopen (filename,"rb"); if (!fp) { fprintf (stderr, "File %s not found\n", filename); return 0; } fprintf(stdout, "reading %s\n", filename); /* Find file size */ uint64_t fsize = file_size (filename); /* Make a buffer large enough to hold file */ signed char *src = (signed char*) malloc ( fsize * sizeof(signed char)); /* Loop, reading lines from file */ int dim1 = -1, dim2 = -1, dim3 = -1; bool have_start_pos = false; int junk; fpos_t pos; size_t compressed_size = 0; while (fgetpos (fp, &pos), fgets (linebuf, LINELEN, fp)) { if (sscanf (linebuf, "dim1=%d", &dim1) == 1) { continue; } if (sscanf (linebuf, "dim2=%d", &dim2) == 1) { continue; } if (sscanf (linebuf, "dim3=%d", &dim3) == 1) { continue; } if (sscanf (linebuf, "nki_compression=%d", &junk) == 1) { /* End of ascii header, look for beginning of compressed data. */ fsetpos (fp, &pos); int prev = fgetc (fp); do { int curr = fgetc (fp); if (prev == 0x0c && curr == 0x0c) { have_start_pos = true; break; } prev = curr; } while (prev != EOF); /* Found beginning of compressed data, slurp up rest of file into a buffer */ signed char *p = src; while (1) { size_t bytes_read = fread (p, 1, 2048, fp); p += bytes_read; compressed_size += bytes_read; if (bytes_read != 2048) break; } /* Done! */ break; } } fclose (fp); if (dim1 == -1 || dim2 == -1 || dim3 == -1 || !have_start_pos) { lprintf ("Failure to parse NKI header\n"); free (src); return 0; } short int *nki = (short*) malloc (sizeof(short) * dim1 * dim2 * dim3); int rc = nki_private_decompress (nki, src, compressed_size); free (src); if (rc == 0) { /* Decompression failure */ lprintf ("NKI decompression failure.\n"); free (nki); return 0; } Volume *vol = new Volume; vol->pix_size = 2; vol->pix_type = PT_SHORT; vol->spacing[0] = 1; vol->spacing[1] = 1; vol->spacing[2] = 1; vol->set_direction_cosines (0); /* Shuffle pixels */ plm_long nki_dim[3] = {dim1,dim2,dim3}; plm_long tgt_dim[3] = {dim3,dim2,dim1}; short *tgt = (short*) malloc (sizeof(short) * dim1 * dim2 * dim3); for (int k = 0; k < dim1; k++) { for (int j = 0; j < dim2; j++) { for (int i = 0; i < dim3; i++) { tgt[volume_index(tgt_dim,i,j,dim1-k-1)] = nki[volume_index(nki_dim,k,j,i)]; } } } vol->dim[0] = dim3; vol->dim[1] = dim2; vol->dim[2] = dim1; vol->origin[0] = -0.5 * dim3 + 0.5; vol->origin[1] = -0.5 * dim2 + 0.5; vol->origin[2] = -0.5 * dim1 + 0.5; vol->img = (void*) tgt; vol->npix = dim1*dim2*dim3; //bug fixed by YKPark 20131029 free (nki); return vol; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/nki_io.h000066400000000000000000000005661321604176500271610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _nki_io_h_ #define _nki_io_h_ #include "plmbase_config.h" class Volume; PLMBASE_C_API Volume* nki_load (const char* filename); #endif parameter_parser.cxx000066400000000000000000000110351321604176500315320ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include #include "file_util.h" #include "logfile.h" #include "parameter_parser.h" #include "print_and_exit.h" #include "string_util.h" Parameter_parser::Parameter_parser () { key_regularization = true; empty_values_allowed = false; default_index = ""; } Plm_return_code Parameter_parser::parse_config_string ( const char* config_string ) { std::stringstream ss (config_string); std::string buf; std::string buf_ori; /* An extra copy for diagnostics */ std::string section = "GLOBAL"; bool found_first_section = false; while (getline (ss, buf)) { buf_ori = buf; buf = string_trim (buf); buf_ori = string_trim (buf_ori, "\r\n"); if (buf == "") continue; if (buf[0] == '#') continue; /* Process "[SECTION]" */ if (buf[0] == '[') { if (buf[buf.length()-1] != ']') { lprintf ("Parse error: %s\n", buf_ori.c_str()); return PLM_ERROR; } /* Strip off brackets and make upper case */ buf = buf.substr (1, buf.length()-2); std::string new_section = make_uppercase (buf); /* Inform subclass that previous section is ending */ if (found_first_section) { this->end_section (section); } found_first_section = true; /* Inform subclass that a new section is beginning */ section = new_section; Plm_return_code rc = this->begin_section (section); if (rc != PLM_SUCCESS) { lprintf ("Parse error: %s\n", buf_ori.c_str()); return rc; } continue; } /* Process "key=value" */ std::string key; std::string val; if (!split_key_val (buf, key, val) && !this->empty_values_allowed) { lprintf ("Parse error: %s\n", buf_ori.c_str()); return PLM_ERROR; } /* Key becomes lowercase, with "_" & "-" unified */ if (this->key_regularization) { key = regularize_string (key); } /* Handle case of key/value pairs before section */ if (!found_first_section) { this->begin_section (section); } found_first_section = true; /* No key? What to do? */ if (key == "") { continue; } /* Handle key[index]=value */ std::string array; std::string index; if (!split_array_index (key, array, index)) { lprintf ("Parse error: %s\n", buf_ori.c_str()); return PLM_ERROR; } if (index == "") { index = default_index; } Plm_return_code rc = this->set_key_value (section, array, index, val); if (rc != PLM_SUCCESS) { lprintf ("Parse error: %s\n", buf_ori.c_str()); return PLM_ERROR; } } /* Don't forget to end the last section */ this->end_section (section); return PLM_SUCCESS; } void Parameter_parser::enable_key_regularization ( bool enable ) { this->key_regularization = enable; } void Parameter_parser::allow_empty_values ( bool enable ) { this->empty_values_allowed = enable; } void Parameter_parser::set_default_index ( std::string& default_index) { this->default_index = default_index; } void Parameter_parser::set_default_index ( const char *default_index) { this->default_index = std::string(default_index); } Plm_return_code Parameter_parser::parse_config_string ( const std::string& config_string ) { return this->parse_config_string (config_string.c_str()); } Plm_return_code Parameter_parser::parse_config_file ( const char* config_fn ) { /* Confirm file can be read */ if (!file_exists (config_fn)) { print_and_exit ("Error reading config file: %s\n", config_fn); } /* Read file into string */ std::ifstream t (config_fn); std::stringstream buffer; buffer << t.rdbuf(); return this->parse_config_string (buffer.str()); } Plm_return_code Parameter_parser::parse_config_file ( const std::string& config_fn ) { return this->parse_config_file (config_fn.c_str()); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/parameter_parser.h000066400000000000000000000042761321604176500312470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _parameter_parser_h_ #define _parameter_parser_h_ #include "plmbase_config.h" #include "plm_return_code.h" /*! \brief * The Parameter_parser class is an abstract base class which is used * to parse ini-style file formats that control the registration, mabs, * and dose calculation codes. */ class PLMBASE_API Parameter_parser { public: Parameter_parser (); public: bool key_regularization; bool empty_values_allowed; std::string default_index; public: /* Callbacks */ virtual Plm_return_code begin_section ( const std::string& section) = 0; virtual Plm_return_code end_section ( const std::string& section) = 0; virtual Plm_return_code set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val) = 0; /*! \brief Key regularization convert the key field to lowercase and changes hyphens to underscores. Only the key is modified. Pass in "true" to enable key regularization, or "false" to disable it. Default is "true". */ void enable_key_regularization ( bool enable ); /*! \brief If a key does not have an equal sign, it will be considered a syntax error unless empty values are allowed. */ void allow_empty_values ( bool enable ); /*! \brief Choose what index is passed to set_key_value() when no index is found in the file. Default is "". */ void set_default_index (std::string& default_index); void set_default_index (const char *default_index); /* Return zero if config string is correctly parsed */ Plm_return_code parse_config_string ( const char* config_string ); Plm_return_code parse_config_string ( const std::string& config_string ); Plm_return_code parse_config_file ( const char* config_fn ); Plm_return_code parse_config_file ( const std::string& config_fn ); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_file_format.cxx000066400000000000000000000135771321604176500314310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include "dicom_probe.h" #include "file_util.h" #include "gdcm1_dose.h" #include "itk_image.h" #include "path_util.h" #include "plm_file_format.h" #include "string_util.h" #include "xio_dir.h" static bool is_xio_directory (const char* path) { Xio_dir xd (path); if (xd.num_patients () > 0) { return true; } else { return false; } } static bool is_rt_study_directory (const char* path) { std::string img_fn = compose_filename (path, "img.nrrd"); if (file_exists (img_fn)) { return true; } else { return false; } } Plm_file_format plm_file_format_deduce (const char* path) { std::string ext; if (!path || !path[0]) { return PLM_FILE_FMT_NO_FILE; } if (itksys::SystemTools::FileIsDirectory (path)) { if (is_xio_directory (path)) { return PLM_FILE_FMT_XIO_DIR; } if (is_rt_study_directory (path)) { return PLM_FILE_FMT_RT_STUDY_DIR; } return PLM_FILE_FMT_DICOM_DIR; } if (!file_exists (path)) { return PLM_FILE_FMT_NO_FILE; } ext = itksys::SystemTools::GetFilenameLastExtension (std::string (path)); if (!itksys::SystemTools::Strucmp (ext.c_str(), ".fcsv")) { return PLM_FILE_FMT_POINTSET; } if (!itksys::SystemTools::Strucmp (ext.c_str(), ".txt")) { /* Probe for pointset */ int rc; const int MAX_LINE = 2048; char line[MAX_LINE]; float f[4]; FILE* fp = fopen (path, "rb"); if (!fp) return PLM_FILE_FMT_NO_FILE; fgets (line, MAX_LINE, fp); fclose (fp); rc = sscanf (line, "%g %g %g %g", &f[0], &f[1], &f[2], &f[3]); if (rc == 3) { return PLM_FILE_FMT_POINTSET; } /* Not sure, assume image */ return PLM_FILE_FMT_IMG; } if (!itksys::SystemTools::Strucmp (ext.c_str(), ".cxt")) { return PLM_FILE_FMT_CXT; } if (!itksys::SystemTools::Strucmp (ext.c_str(), ".dij")) { return PLM_FILE_FMT_DIJ; } if (!itksys::SystemTools::Strucmp (ext.c_str(), ".pfm")) { return PLM_FILE_FMT_PROJ_IMG; } if (!itksys::SystemTools::Strucmp (ext.c_str(), ".hnd")) { return PLM_FILE_FMT_PROJ_IMG; } if (!itksys::SystemTools::Strucmp (ext.c_str(), ".scan")) { return PLM_FILE_FMT_IMG; } /* Maybe dicom rtss? */ if (dicom_probe_rtss(path)) { return PLM_FILE_FMT_DICOM_RTSS; } /* Maybe dicom dose */ if (dicom_probe_dose(path)) { return PLM_FILE_FMT_DICOM_DOSE; } /* Maybe dicom plan */ if (dicom_probe_rtplan(path)) { return PLM_FILE_FMT_DICOM_RTPLAN; } itk::ImageIOBase::IOPixelType pixel_type; itk::ImageIOBase::IOComponentType component_type; int num_dimensions, num_components; itk_image_get_props (std::string (path), &num_dimensions, &pixel_type, &component_type, &num_components); if (pixel_type == itk::ImageIOBase::VECTOR) { /* Maybe vector field? */ if (component_type == itk::ImageIOBase::FLOAT || component_type == itk::ImageIOBase::DOUBLE) { return PLM_FILE_FMT_VF; } /* Maybe ss_image? */ if (num_components >= 2 && component_type == itk::ImageIOBase::UCHAR) { return PLM_FILE_FMT_SS_IMG_VEC; } /* else fall through */ } return PLM_FILE_FMT_IMG; } Plm_file_format plm_file_format_deduce (const std::string& path) { return plm_file_format_deduce (path.c_str()); } char* plm_file_format_string (Plm_file_format file_type) { switch (file_type) { case PLM_FILE_FMT_NO_FILE: return "No file"; case PLM_FILE_FMT_UNKNOWN: return "Unknown"; case PLM_FILE_FMT_IMG: return "Image"; case PLM_FILE_FMT_VF: return "Vector field"; case PLM_FILE_FMT_DIJ: return "Dij matrix"; case PLM_FILE_FMT_POINTSET: return "Pointset"; case PLM_FILE_FMT_CXT: return "Cxt file"; case PLM_FILE_FMT_DICOM_DIR: return "DICOM directory"; case PLM_FILE_FMT_XIO_DIR: return "XiO directory"; case PLM_FILE_FMT_RTOG_DIR: return "RTOG directory"; case PLM_FILE_FMT_RT_STUDY_DIR: return "RT study directory"; case PLM_FILE_FMT_PROJ_IMG: return "Projection image"; case PLM_FILE_FMT_DICOM_RTSS: return "DICOM-RT SS"; case PLM_FILE_FMT_DICOM_DOSE: return "DICOM-RT dose"; case PLM_FILE_FMT_SS_IMG_VEC: return "Structure set image"; default: return "Unknown/default"; } } Plm_file_format plm_file_format_parse (const char* string) { if (!strcmp (string, "mha")) { return PLM_FILE_FMT_IMG; } else if (!strcmp (string, "vf")) { return PLM_FILE_FMT_VF; } else if (!strcmp (string, "dij")) { return PLM_FILE_FMT_DIJ; } else if (!strcmp (string, "pointset")) { return PLM_FILE_FMT_POINTSET; } else if (!strcmp (string, "cxt")) { return PLM_FILE_FMT_CXT; } else if (!strcmp (string, "dicom") || !strcmp (string, "dicom-dir")) { return PLM_FILE_FMT_DICOM_DIR; } else if (!strcmp (string, "xio")) { return PLM_FILE_FMT_XIO_DIR; } else if (!strcmp (string, "rtog")) { return PLM_FILE_FMT_RTOG_DIR; } else if (!strcmp (string, "rtstudy")) { return PLM_FILE_FMT_RTOG_DIR; } else if (!strcmp (string, "proj")) { return PLM_FILE_FMT_PROJ_IMG; } else if (!strcmp (string, "rtss") || !strcmp (string, "dicom-rtss")) { return PLM_FILE_FMT_DICOM_RTSS; } else if (!strcmp (string, "ssimg")) { return PLM_FILE_FMT_SS_IMG_VEC; } else { return PLM_FILE_FMT_UNKNOWN; } } Plm_file_format plm_file_format_from_extension (const char* filename) { if (extension_is (filename, ".dcm")) { return PLM_FILE_FMT_DICOM_DIR; } else if (extension_is (filename, ".cxt")) { return PLM_FILE_FMT_CXT; } else { return PLM_FILE_FMT_IMG; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_file_format.h000066400000000000000000000022111321604176500310350ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_file_format_h_ #define _plm_file_format_h_ #include "plmbase_config.h" class Pstring; enum Plm_file_format { PLM_FILE_FMT_NO_FILE, PLM_FILE_FMT_UNKNOWN, PLM_FILE_FMT_IMG, PLM_FILE_FMT_VF, PLM_FILE_FMT_DIJ, PLM_FILE_FMT_POINTSET, PLM_FILE_FMT_CXT, PLM_FILE_FMT_DICOM_DIR, PLM_FILE_FMT_XIO_DIR, PLM_FILE_FMT_RTOG_DIR, PLM_FILE_FMT_RT_STUDY_DIR, PLM_FILE_FMT_PROJ_IMG, PLM_FILE_FMT_DICOM_RTSS, PLM_FILE_FMT_DICOM_DOSE, PLM_FILE_FMT_DICOM_RTPLAN, PLM_FILE_FMT_SS_IMG_VEC }; PLMBASE_API Plm_file_format plm_file_format_deduce (const char* path); PLMBASE_API Plm_file_format plm_file_format_deduce (const std::string& path); PLMBASE_API char* plm_file_format_string (Plm_file_format file_type); PLMBASE_API Plm_file_format plm_file_format_parse (const char* string); PLMBASE_API Plm_file_format plm_file_format_from_extension (const char* filename); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_image.cxx000066400000000000000000001241021321604176500302070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "itkImageRegionIterator.h" #include "itkMetaDataDictionary.h" #include "itkMetaDataObject.h" #if PLM_DCM_USE_DCMTK #include "dcmtk_rt_study.h" #endif #include "file_util.h" #include "itk_image_cast.h" #include "itk_image_create.h" #include "itk_image_load.h" #include "itk_image_save.h" #include "itk_image_type.h" #include "itk_metadata.h" #include "logfile.h" #include "mha_io.h" #include "nki_io.h" #include "path_util.h" #include "plm_image.h" #include "plm_image_p.h" #include "plm_image_type.h" #include "plm_image_header.h" #include "print_and_exit.h" #include "string_util.h" #include "volume.h" Plm_image::Plm_image () { this->init (); } Plm_image::Plm_image (const char* fname) { this->init (); this->load_native (fname); } Plm_image::Plm_image (const std::string& fname) { this->init (); this->load_native (fname.c_str()); } Plm_image::Plm_image (const char* fname, Plm_image_type type) { this->init (); this->load (fname, type); } Plm_image::Plm_image (const std::string& fname, Plm_image_type type) { this->init (); this->load (fname.c_str(), type); } Plm_image::Plm_image (UCharImageType::Pointer img) { this->init (); this->set_itk (img); } Plm_image::Plm_image (CharImageType::Pointer img) { this->init (); this->set_itk (img); } Plm_image::Plm_image (ShortImageType::Pointer img) { this->init (); this->set_itk (img); } Plm_image::Plm_image (FloatImageType::Pointer img) { this->init (); this->set_itk (img); } Plm_image::Plm_image (Plm_image_type type, const Plm_image_header& pih) { this->init (); this->create (type, pih); } Plm_image::Plm_image (const Volume::Pointer& vol) { this->init (); this->set_volume (vol); } Plm_image::Plm_image (Volume* vol) { this->init (); this->set_volume (vol); } Plm_image::~Plm_image () { delete d_ptr; } /* ----------------------------------------------------------------------- Creation / Destruction ----------------------------------------------------------------------- */ /* This function can only be called by constructor */ void Plm_image::init () { d_ptr = new Plm_image_private; m_original_type = PLM_IMG_TYPE_UNDEFINED; m_type = PLM_IMG_TYPE_UNDEFINED; } /* This function can be called by anyone */ void Plm_image::free () { d_ptr->m_vol.reset (); d_ptr->m_vol_list.clear (); m_original_type = PLM_IMG_TYPE_UNDEFINED; m_type = PLM_IMG_TYPE_UNDEFINED; m_itk_char = 0; m_itk_uchar = 0; m_itk_short = 0; m_itk_ushort = 0; m_itk_int32 = 0; m_itk_uint32 = 0; m_itk_float = 0; m_itk_double = 0; m_itk_uchar_vec = 0; } void Plm_image::free_volume () { d_ptr->m_vol.reset(); } bool Plm_image::have_image () { return m_type != PLM_IMG_TYPE_UNDEFINED; } /* ----------------------------------------------------------------------- Creating ----------------------------------------------------------------------- */ void Plm_image::create (Plm_image_type type, const Plm_image_header& pih) { switch (type) { case PLM_IMG_TYPE_ITK_UCHAR: case PLM_IMG_TYPE_ITK_SHORT: case PLM_IMG_TYPE_ITK_USHORT: case PLM_IMG_TYPE_ITK_ULONG: print_and_exit ("Unhandled image type in Plm_image::create" " (type = %d)\n", this->m_type); break; case PLM_IMG_TYPE_ITK_FLOAT: this->m_type = type; this->m_original_type = type; this->m_itk_float = itk_image_create (pih); break; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_GPUIT_UINT16: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_GPUIT_FLOAT: case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: default: print_and_exit ("Unhandled image type in Plm_image::create" " (type = %d)\n", this->m_type); break; } } /* ----------------------------------------------------------------------- Cloning ----------------------------------------------------------------------- */ Plm_image::Pointer Plm_image::clone (void) { Plm_image::Pointer pli = Plm_image::New(); if (!pli) return pli; pli->m_original_type = this->m_original_type; pli->m_type = this->m_type; switch (this->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: pli->m_itk_uchar = this->m_itk_uchar; break; case PLM_IMG_TYPE_ITK_SHORT: pli->m_itk_short = this->m_itk_short; break; case PLM_IMG_TYPE_ITK_USHORT: pli->m_itk_ushort = this->m_itk_ushort; break; case PLM_IMG_TYPE_ITK_ULONG: pli->m_itk_uint32 = this->m_itk_uint32; break; case PLM_IMG_TYPE_ITK_FLOAT: pli->m_itk_float = this->m_itk_float; break; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_GPUIT_UINT16: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_GPUIT_FLOAT: case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: pli->d_ptr->m_vol = this->d_ptr->m_vol->clone (); break; default: print_and_exit ("Unhandled image type in Plm_image::clone" " (type = %d)\n", this->m_type); break; } return pli; } Plm_image::Pointer Plm_image::clone (const Plm_image::Pointer& pli) { return pli->clone (); } /* ----------------------------------------------------------------------- Loading ----------------------------------------------------------------------- */ Plm_image::Pointer plm_image_load (const char* fname, Plm_image_type type) { Plm_image::Pointer pli = Plm_image::New(); if (pli->load (fname, type)) { return pli; } else { return Plm_image::Pointer(); } } Plm_image::Pointer plm_image_load (const std::string& fname, Plm_image_type type) { return plm_image_load (fname.c_str(), type); } Plm_image::Pointer plm_image_load_native (const char* fname) { Plm_image::Pointer pli = Plm_image::New(); if (pli->load_native (fname)) { return pli; } else { return Plm_image::Pointer(); } } Plm_image::Pointer plm_image_load_native (const std::string& fname) { return plm_image_load_native (fname.c_str()); } bool Plm_image::load (const char* fname, Plm_image_type type) { this->free (); if (!this->load_native(fname)) { return false; } this->convert (type); return true; } bool Plm_image::load_native (const char* fname) { itk::ImageIOBase::IOPixelType pixel_type; itk::ImageIOBase::IOComponentType component_type; int num_dimensions, num_components; if (is_directory (fname)) { /* GCS FIX: The call to is_directory is redundant -- we already called plm_file_format_deduce() in warp_main() */ return load_native_dicom (fname); } if (!file_exists (fname) && !string_starts_with (fname, "slicer:")) { lprintf ("Couldn't open %s for read\n", fname); return false; } /* Check for NKI filetype, which doesn't use ITK reader */ if (extension_is (fname, "scan") || extension_is (fname, "SCAN")) { return load_native_nki (fname); } std::string fn = fname; itk_image_get_props (fname, &num_dimensions, &pixel_type, &component_type, &num_components); /* Handle RGB images as a special case */ if (pixel_type == itk::ImageIOBase::RGB) { this->m_itk_uchar = itk_image_load_uchar (fname, 0); this->m_original_type = PLM_IMG_TYPE_ITK_UCHAR; this->m_type = PLM_IMG_TYPE_ITK_UCHAR; return true; } /* Handle ss_image as a special case */ if (num_components > 1 && component_type == itk::ImageIOBase::UCHAR) { this->m_itk_uchar_vec = itk_image_load_uchar_vec (fname); this->m_original_type = PLM_IMG_TYPE_ITK_UCHAR_VEC; this->m_type = PLM_IMG_TYPE_ITK_UCHAR_VEC; return true; } switch (component_type) { case itk::ImageIOBase::CHAR: this->m_itk_char = itk_image_load_char (fname, 0); this->m_original_type = PLM_IMG_TYPE_ITK_CHAR; this->m_type = PLM_IMG_TYPE_ITK_CHAR; break; case itk::ImageIOBase::UCHAR: this->m_itk_uchar = itk_image_load_uchar (fname, 0); this->m_original_type = PLM_IMG_TYPE_ITK_UCHAR; this->m_type = PLM_IMG_TYPE_ITK_UCHAR; break; case itk::ImageIOBase::SHORT: this->m_itk_short = itk_image_load_short (fname, 0); this->m_original_type = PLM_IMG_TYPE_ITK_SHORT; this->m_type = PLM_IMG_TYPE_ITK_SHORT; break; case itk::ImageIOBase::USHORT: this->m_itk_ushort = itk_image_load_ushort (fname, 0); this->m_original_type = PLM_IMG_TYPE_ITK_USHORT; this->m_type = PLM_IMG_TYPE_ITK_USHORT; break; #if (CMAKE_SIZEOF_UINT == 4) case itk::ImageIOBase::INT: #endif #if (CMAKE_SIZEOF_ULONG == 4) case itk::ImageIOBase::LONG: #endif this->m_itk_int32 = itk_image_load_int32 (fname, 0); this->m_original_type = PLM_IMG_TYPE_ITK_LONG; this->m_type = PLM_IMG_TYPE_ITK_LONG; break; #if (CMAKE_SIZEOF_UINT == 4) case itk::ImageIOBase::UINT: #endif #if (CMAKE_SIZEOF_ULONG == 4) case itk::ImageIOBase::ULONG: #endif this->m_itk_uint32 = itk_image_load_uint32 (fname, 0); this->m_original_type = PLM_IMG_TYPE_ITK_ULONG; this->m_type = PLM_IMG_TYPE_ITK_ULONG; break; case itk::ImageIOBase::FLOAT: this->m_itk_float = itk_image_load_float (fname, 0); this->m_original_type = PLM_IMG_TYPE_ITK_FLOAT; this->m_type = PLM_IMG_TYPE_ITK_FLOAT; break; case itk::ImageIOBase::DOUBLE: this->m_itk_double = itk_image_load_double (fname, 0); this->m_original_type = PLM_IMG_TYPE_ITK_DOUBLE; this->m_type = PLM_IMG_TYPE_ITK_DOUBLE; break; default: lprintf ("Error, unsupported input type in load_native(): %d\n", component_type); return false; } return true; } bool Plm_image::load_native (const std::string& fn) { return this->load_native (fn.c_str()); } bool Plm_image::load_native_dicom (const char* fname) { #if PLM_DCM_USE_DCMTK Dcmtk_rt_study drs (fname); drs.parse_directory (); this->set (drs.get_image ()); /* GCS FIX: Here we need to set the metadata loaded from DICOM into the Plm_image */ #else /* GCS FIX: We don't yet have a way of getting original pixel type for dicom. Force SHORT */ /* FIX: Patient position / direction cosines not set */ this->m_itk_short = itk_image_load_short (fname, 0); this->m_original_type = PLM_IMG_TYPE_ITK_SHORT; this->m_type = PLM_IMG_TYPE_ITK_SHORT; #endif return true; } bool Plm_image::load_native_nki (const char* fname) { Volume *v = nki_load (fname); if (v) { d_ptr->m_vol.reset(v); this->m_original_type = PLM_IMG_TYPE_ITK_SHORT; this->m_type = PLM_IMG_TYPE_GPUIT_SHORT; return true; } return false; } /* ----------------------------------------------------------------------- Saving ----------------------------------------------------------------------- */ void Plm_image::save_short_dicom ( const char* fname, Rt_study_metadata *rsm ) { switch (this->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: itk_image_save_short_dicom (this->m_itk_uchar, fname, rsm); break; case PLM_IMG_TYPE_ITK_SHORT: itk_image_save_short_dicom (this->m_itk_short, fname, rsm); break; case PLM_IMG_TYPE_ITK_USHORT: itk_image_save_short_dicom (this->m_itk_ushort, fname, rsm); break; case PLM_IMG_TYPE_ITK_ULONG: itk_image_save_short_dicom (this->m_itk_uint32, fname, rsm); break; case PLM_IMG_TYPE_ITK_FLOAT: itk_image_save_short_dicom (this->m_itk_float, fname, rsm); break; case PLM_IMG_TYPE_GPUIT_UCHAR: this->convert_to_itk_uchar (); itk_image_save_short_dicom (this->m_itk_uchar, fname, rsm); break; case PLM_IMG_TYPE_GPUIT_SHORT: this->convert_to_itk_short (); itk_image_save_short_dicom (this->m_itk_short, fname, rsm); break; case PLM_IMG_TYPE_GPUIT_UINT32: this->convert_to_itk_uint32 (); itk_image_save_short_dicom (this->m_itk_uint32, fname, rsm); break; case PLM_IMG_TYPE_GPUIT_FLOAT: this->convert_to_itk_float (); itk_image_save_short_dicom (this->m_itk_float, fname, rsm); break; case PLM_IMG_TYPE_GPUIT_UINT16: default: print_and_exit ("Unhandled image type in Plm_image::save_short_dicom" " (type = %d)\n", this->m_type); break; } } void Plm_image::save_short_dicom ( const std::string& fname, Rt_study_metadata *rsm ) { this->save_short_dicom (fname.c_str(), rsm); } void Plm_image::save_image (const char* fname) { switch (this->m_type) { case PLM_IMG_TYPE_ITK_CHAR: itk_image_save (this->m_itk_char, fname); break; case PLM_IMG_TYPE_ITK_UCHAR: itk_image_save (this->m_itk_uchar, fname); break; case PLM_IMG_TYPE_ITK_SHORT: itk_image_save (this->m_itk_short, fname); break; case PLM_IMG_TYPE_ITK_USHORT: itk_image_save (this->m_itk_ushort, fname); break; case PLM_IMG_TYPE_ITK_LONG: itk_image_save (this->m_itk_int32, fname); break; case PLM_IMG_TYPE_ITK_ULONG: itk_image_save (this->m_itk_uint32, fname); break; case PLM_IMG_TYPE_ITK_FLOAT: itk_image_save (this->m_itk_float, fname); break; case PLM_IMG_TYPE_ITK_DOUBLE: itk_image_save (this->m_itk_double, fname); break; case PLM_IMG_TYPE_GPUIT_UCHAR: this->convert_to_itk_uchar (); itk_image_save (this->m_itk_uchar, fname); break; case PLM_IMG_TYPE_GPUIT_SHORT: this->convert_to_itk_short (); itk_image_save (this->m_itk_short, fname); break; case PLM_IMG_TYPE_GPUIT_UINT32: this->convert_to_itk_uint32 (); itk_image_save (this->m_itk_uint32, fname); break; case PLM_IMG_TYPE_GPUIT_FLOAT: this->convert_to_itk_float (); itk_image_save (this->m_itk_float, fname); break; case PLM_IMG_TYPE_ITK_UCHAR_VEC: itk_image_save (this->m_itk_uchar_vec, fname); break; case PLM_IMG_TYPE_GPUIT_UINT16: default: print_and_exit ("Unhandled image type in Plm_image::save_image" " (type = %s)\n", plm_image_type_string (this->m_type)); break; } } void Plm_image::save_image (const std::string& fname) { this->save_image (fname.c_str()); } /* ----------------------------------------------------------------------- Getting and setting ----------------------------------------------------------------------- */ void Plm_image::set (const Plm_image::Pointer& pli) { switch (pli->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: m_itk_uchar = pli->m_itk_uchar; break; case PLM_IMG_TYPE_ITK_CHAR: m_itk_char = pli->m_itk_char; break; case PLM_IMG_TYPE_ITK_USHORT: m_itk_ushort = pli->m_itk_ushort; break; case PLM_IMG_TYPE_ITK_SHORT: m_itk_short = pli->m_itk_short; break; case PLM_IMG_TYPE_ITK_ULONG: m_itk_uint32 = pli->m_itk_uint32; break; case PLM_IMG_TYPE_ITK_LONG: m_itk_int32 = pli->m_itk_int32; break; case PLM_IMG_TYPE_ITK_FLOAT: m_itk_float = pli->m_itk_float; break; case PLM_IMG_TYPE_ITK_DOUBLE: m_itk_double = pli->m_itk_double; break; case PLM_IMG_TYPE_ITK_UCHAR_VEC: m_itk_uchar_vec = pli->m_itk_uchar_vec; break; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_GPUIT_UINT16: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_GPUIT_INT32: case PLM_IMG_TYPE_GPUIT_FLOAT: case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: d_ptr->m_vol = pli->d_ptr->m_vol; break; default: print_and_exit ("Unhandled image type in Plm_image::set()" " (type = %s)\n", plm_image_type_string (pli->m_type)); break; } this->m_original_type = pli->m_original_type; this->m_type = pli->m_type; } void Plm_image::set_volume (const Volume::Pointer& v, Plm_image_type type) { this->free (); d_ptr->m_vol = v; m_original_type = type; m_type = type; } void Plm_image::set_volume (const Volume::Pointer& v) { switch (v->pix_type) { case PT_UCHAR: this->set_volume (v, PLM_IMG_TYPE_GPUIT_UCHAR); break; case PT_SHORT: this->set_volume (v, PLM_IMG_TYPE_GPUIT_SHORT); break; case PT_UINT16: this->set_volume (v, PLM_IMG_TYPE_GPUIT_UINT16); break; case PT_UINT32: this->set_volume (v, PLM_IMG_TYPE_GPUIT_UINT32); break; case PT_INT32: this->set_volume (v, PLM_IMG_TYPE_GPUIT_INT32); break; case PT_FLOAT: this->set_volume (v, PLM_IMG_TYPE_GPUIT_FLOAT); break; case PT_VF_FLOAT_INTERLEAVED: this->set_volume (v, PLM_IMG_TYPE_GPUIT_FLOAT_FIELD); break; case PT_UCHAR_VEC_INTERLEAVED: this->set_volume (v, PLM_IMG_TYPE_GPUIT_UCHAR_VEC); break; default: print_and_exit ("Undefined conversion in Plm_image::set_volume\n"); break; } } void Plm_image::set_volume (Volume *v, Plm_image_type type) { this->free (); d_ptr->m_vol.reset (v); m_original_type = type; m_type = type; } void Plm_image::set_volume (Volume *v) { switch (v->pix_type) { case PT_UCHAR: this->set_volume (v, PLM_IMG_TYPE_GPUIT_UCHAR); break; case PT_SHORT: this->set_volume (v, PLM_IMG_TYPE_GPUIT_SHORT); break; case PT_UINT16: this->set_volume (v, PLM_IMG_TYPE_GPUIT_UINT16); break; case PT_UINT32: this->set_volume (v, PLM_IMG_TYPE_GPUIT_UINT32); break; case PT_INT32: this->set_volume (v, PLM_IMG_TYPE_GPUIT_INT32); break; case PT_FLOAT: this->set_volume (v, PLM_IMG_TYPE_GPUIT_FLOAT); break; case PT_VF_FLOAT_INTERLEAVED: this->set_volume (v, PLM_IMG_TYPE_GPUIT_FLOAT_FIELD); break; case PT_UCHAR_VEC_INTERLEAVED: this->set_volume (v, PLM_IMG_TYPE_GPUIT_UCHAR_VEC); break; default: print_and_exit ("Undefined conversion in Plm_image::set_volume\n"); break; } } Volume::Pointer& Plm_image::get_volume () { return d_ptr->m_vol; } Volume::Pointer& Plm_image::get_volume_uchar () { convert_to_gpuit_uchar (); return d_ptr->m_vol; } Volume::Pointer& Plm_image::get_volume_short () { convert_to_gpuit_short (); return d_ptr->m_vol; } Volume::Pointer& Plm_image::get_volume_float () { convert_to_gpuit_float (); return d_ptr->m_vol; } Volume::Pointer& Plm_image::get_volume_uchar_vec () { convert_to_gpuit_uchar_vec (); return d_ptr->m_vol; } Volume * Plm_image::get_vol () { return d_ptr->m_vol.get(); } const Volume * Plm_image::get_vol () const { return d_ptr->m_vol.get(); } void Plm_image::set_itk (UCharImageType::Pointer img) { this->free (); m_original_type = PLM_IMG_TYPE_ITK_UCHAR; m_type = PLM_IMG_TYPE_ITK_UCHAR; this->m_itk_uchar = img; } void Plm_image::set_itk (CharImageType::Pointer img) { this->free (); m_original_type = PLM_IMG_TYPE_ITK_CHAR; m_type = PLM_IMG_TYPE_ITK_CHAR; this->m_itk_char = img; } void Plm_image::set_itk (UShortImageType::Pointer img) { this->free (); m_original_type = PLM_IMG_TYPE_ITK_USHORT; m_type = PLM_IMG_TYPE_ITK_USHORT; this->m_itk_ushort = img; } void Plm_image::set_itk (ShortImageType::Pointer img) { this->free (); m_original_type = PLM_IMG_TYPE_ITK_SHORT; m_type = PLM_IMG_TYPE_ITK_SHORT; this->m_itk_short = img; } void Plm_image::set_itk (UInt32ImageType::Pointer img) { this->free (); m_original_type = PLM_IMG_TYPE_ITK_ULONG; m_type = PLM_IMG_TYPE_ITK_ULONG; this->m_itk_uint32 = img; } void Plm_image::set_itk (Int32ImageType::Pointer img) { this->free (); m_original_type = PLM_IMG_TYPE_ITK_LONG; m_type = PLM_IMG_TYPE_ITK_LONG; this->m_itk_int32 = img; } void Plm_image::set_itk (FloatImageType::Pointer img) { this->free (); m_original_type = PLM_IMG_TYPE_ITK_FLOAT; m_type = PLM_IMG_TYPE_ITK_FLOAT; this->m_itk_float = img; } void Plm_image::set_itk (DoubleImageType::Pointer img) { this->free (); m_original_type = PLM_IMG_TYPE_ITK_DOUBLE; m_type = PLM_IMG_TYPE_ITK_DOUBLE; this->m_itk_double = img; } void Plm_image::set_itk (UCharVecImageType::Pointer img) { this->free (); m_original_type = PLM_IMG_TYPE_ITK_UCHAR_VEC; m_type = PLM_IMG_TYPE_ITK_UCHAR_VEC; this->m_itk_uchar_vec = img; } /* ----------------------------------------------------------------------- Conversion ----------------------------------------------------------------------- */ #define CONVERT_ITK_ITK(out_type,in_type) \ (this->m_itk_##out_type = cast_##out_type (this->m_itk_##in_type), \ this->m_itk_##in_type = 0) void Plm_image::convert_to_itk_uchar (void) { switch (this->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: return; case PLM_IMG_TYPE_ITK_CHAR: CONVERT_ITK_ITK (uchar, char); return; case PLM_IMG_TYPE_ITK_USHORT: CONVERT_ITK_ITK (uchar, ushort); break; case PLM_IMG_TYPE_ITK_SHORT: CONVERT_ITK_ITK (uchar, short); break; case PLM_IMG_TYPE_ITK_ULONG: CONVERT_ITK_ITK (uchar, uint32); break; case PLM_IMG_TYPE_ITK_LONG: CONVERT_ITK_ITK (uchar, int32); break; case PLM_IMG_TYPE_ITK_FLOAT: CONVERT_ITK_ITK (uchar, float); break; case PLM_IMG_TYPE_ITK_DOUBLE: CONVERT_ITK_ITK (uchar, double); break; case PLM_IMG_TYPE_GPUIT_UCHAR: this->m_itk_uchar = this->convert_gpuit_to_itk< UCharImageType::Pointer, unsigned char> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_FLOAT: this->m_itk_uchar = this->convert_gpuit_to_itk< UCharImageType::Pointer, float> (this->get_vol()); break; default: print_and_exit ( "Error: unhandled conversion from %s to itk_uchar\n", plm_image_type_string (this->m_type)); return; } this->m_type = PLM_IMG_TYPE_ITK_UCHAR; } void Plm_image::convert_to_itk_char (void) { switch (this->m_type) { case PLM_IMG_TYPE_ITK_CHAR: return; case PLM_IMG_TYPE_ITK_SHORT: CONVERT_ITK_ITK (char, short); break; case PLM_IMG_TYPE_ITK_FLOAT: CONVERT_ITK_ITK (char, float); break; default: print_and_exit ( "Error: unhandled conversion from %s to itk_char\n", plm_image_type_string (this->m_type)); return; } this->m_type = PLM_IMG_TYPE_ITK_CHAR; } void Plm_image::convert_to_gpuit_uchar (void) { switch (this->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: this->convert_itk_to_gpuit ( this->m_itk_uchar); this->m_itk_uchar = 0; break; case PLM_IMG_TYPE_ITK_SHORT: this->convert_itk_to_gpuit ( this->m_itk_short); this->m_itk_short = 0; break; case PLM_IMG_TYPE_ITK_FLOAT: this->convert_itk_to_gpuit ( this->m_itk_float); this->m_itk_float = 0; break; case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_GPUIT_FLOAT: volume_convert_to_uchar (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_UCHAR: return; default: print_and_exit ( "Error: unhandled conversion from %s to itk_uchar\n", plm_image_type_string (this->m_type)); return; } } void Plm_image::convert_to_itk_short (void) { switch (this->m_type) { case PLM_IMG_TYPE_ITK_SHORT: return; case PLM_IMG_TYPE_ITK_ULONG: CONVERT_ITK_ITK (short, uint32); break; case PLM_IMG_TYPE_ITK_LONG: CONVERT_ITK_ITK (short, int32); break; case PLM_IMG_TYPE_ITK_FLOAT: CONVERT_ITK_ITK (short, float); break; case PLM_IMG_TYPE_GPUIT_SHORT: this->m_itk_short = this->convert_gpuit_to_itk< ShortImageType::Pointer, short> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_FLOAT: this->m_itk_short = this->convert_gpuit_to_itk< ShortImageType::Pointer, float> (this->get_vol()); break; default: print_and_exit ( "Error: unhandled conversion from %s to itk_short\n", plm_image_type_string (this->m_type)); return; } this->m_type = PLM_IMG_TYPE_ITK_SHORT; } void Plm_image::convert_to_itk_ushort (void) { switch (this->m_type) { case PLM_IMG_TYPE_ITK_SHORT: CONVERT_ITK_ITK (ushort, short); break; case PLM_IMG_TYPE_ITK_USHORT: return; case PLM_IMG_TYPE_ITK_FLOAT: CONVERT_ITK_ITK (ushort, float); return; case PLM_IMG_TYPE_GPUIT_FLOAT: this->m_itk_ushort = this->convert_gpuit_to_itk< UShortImageType::Pointer, float> (this->get_vol()); break; default: print_and_exit ( "Error: unhandled conversion from %s to itk_ushort\n", plm_image_type_string (this->m_type)); return; } this->m_type = PLM_IMG_TYPE_ITK_USHORT; } void Plm_image::convert_to_itk_int32 (void) { switch (this->m_type) { case PLM_IMG_TYPE_ITK_ULONG: return; case PLM_IMG_TYPE_ITK_FLOAT: CONVERT_ITK_ITK (int32, float); break; case PLM_IMG_TYPE_GPUIT_UCHAR: this->m_itk_int32 = this->convert_gpuit_to_itk< Int32ImageType::Pointer, unsigned char> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_SHORT: this->m_itk_int32 = this->convert_gpuit_to_itk< Int32ImageType::Pointer, short> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_UINT32: this->m_itk_int32 = this->convert_gpuit_to_itk< Int32ImageType::Pointer, uint32_t> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_FLOAT: this->m_itk_int32 = this->convert_gpuit_to_itk< Int32ImageType::Pointer, float> (this->get_vol()); break; default: print_and_exit ( "Error: unhandled conversion from %s to itk_int32\n", plm_image_type_string (this->m_type)); return; } this->m_type = PLM_IMG_TYPE_ITK_ULONG; } void Plm_image::convert_to_itk_uint32 (void) { switch (this->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: CONVERT_ITK_ITK (uint32, uchar); break; case PLM_IMG_TYPE_ITK_SHORT: CONVERT_ITK_ITK (uint32, short); break; case PLM_IMG_TYPE_ITK_ULONG: return; case PLM_IMG_TYPE_ITK_FLOAT: CONVERT_ITK_ITK (uint32, float); break; case PLM_IMG_TYPE_GPUIT_UCHAR: this->m_itk_uint32 = this->convert_gpuit_to_itk< UInt32ImageType::Pointer, unsigned char> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_SHORT: this->m_itk_uint32 = this->convert_gpuit_to_itk< UInt32ImageType::Pointer, short> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_UINT32: this->m_itk_uint32 = this->convert_gpuit_to_itk< UInt32ImageType::Pointer, uint32_t> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_FLOAT: this->m_itk_uint32 = this->convert_gpuit_to_itk< UInt32ImageType::Pointer, float> (this->get_vol()); break; default: print_and_exit ( "Error: unhandled conversion from %s to itk_uint32\n", plm_image_type_string (this->m_type)); return; } this->m_type = PLM_IMG_TYPE_ITK_ULONG; } void Plm_image::convert_to_itk_float () { switch (this->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: CONVERT_ITK_ITK (float, uchar); break; case PLM_IMG_TYPE_ITK_CHAR: CONVERT_ITK_ITK (float, char); break; case PLM_IMG_TYPE_ITK_USHORT: CONVERT_ITK_ITK (float, ushort); break; case PLM_IMG_TYPE_ITK_SHORT: CONVERT_ITK_ITK (float, short); break; case PLM_IMG_TYPE_ITK_ULONG: CONVERT_ITK_ITK (float, uint32); break; case PLM_IMG_TYPE_ITK_LONG: CONVERT_ITK_ITK (float, int32); break; case PLM_IMG_TYPE_ITK_FLOAT: return; case PLM_IMG_TYPE_ITK_DOUBLE: CONVERT_ITK_ITK (float, double); return; case PLM_IMG_TYPE_GPUIT_UCHAR: this->m_itk_float = this->convert_gpuit_to_itk< FloatImageType::Pointer, unsigned char> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_SHORT: this->m_itk_float = this->convert_gpuit_to_itk< FloatImageType::Pointer, short> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_FLOAT: this->m_itk_float = this->convert_gpuit_to_itk< FloatImageType::Pointer, float> (this->get_vol()); break; default: print_and_exit ( "Error: unhandled conversion from %s to itk_float\n", plm_image_type_string (this->m_type)); return; } this->m_type = PLM_IMG_TYPE_ITK_FLOAT; } void Plm_image::convert_to_itk_double () { switch (this->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: CONVERT_ITK_ITK (double, uchar); break; case PLM_IMG_TYPE_ITK_SHORT: CONVERT_ITK_ITK (double, short); break; case PLM_IMG_TYPE_ITK_ULONG: CONVERT_ITK_ITK (double, uint32); break; case PLM_IMG_TYPE_ITK_FLOAT: CONVERT_ITK_ITK (double, float); break; case PLM_IMG_TYPE_ITK_DOUBLE: return; case PLM_IMG_TYPE_GPUIT_UCHAR: this->m_itk_double = this->convert_gpuit_to_itk< DoubleImageType::Pointer, unsigned char> (this->get_vol()); break; case PLM_IMG_TYPE_GPUIT_FLOAT: this->m_itk_double = this->convert_gpuit_to_itk< DoubleImageType::Pointer, float> (this->get_vol()); break; default: print_and_exit ( "Error: unhandled conversion from %s to itk_double\n", plm_image_type_string (this->m_type)); return; } this->m_type = PLM_IMG_TYPE_ITK_DOUBLE; } void Plm_image::convert_to_itk_float_field (void) { switch (m_type) { case PLM_IMG_TYPE_ITK_FLOAT_FIELD: /* do nothing */ break; default: print_and_exit ( "Error: unhandled conversion from %s to itk_float_field\n", plm_image_type_string (this->m_type)); return; } this->m_type = PLM_IMG_TYPE_ITK_FLOAT_FIELD; } void Plm_image::convert_to_itk_uchar_vec (void) { switch (m_type) { case PLM_IMG_TYPE_ITK_UCHAR: lprintf ("Converting from ITK_UCHAR to ITK_UCHAR_VEC\n"); this->convert_itk_uchar_to_itk_uchar_vec (); break; case PLM_IMG_TYPE_ITK_ULONG: lprintf ("Converting from ITK_ULONG to ITK_UCHAR_VEC\n"); this->convert_itk_uint32_to_itk_uchar_vec (); break; case PLM_IMG_TYPE_GPUIT_UINT32: lprintf ("Converting from GPUIT_UINT32 to ITK_UCHAR_VEC\n"); this->convert_gpuit_uint32_to_itk_uchar_vec (); break; case PLM_IMG_TYPE_ITK_UCHAR_VEC: break; case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: lprintf ("Converting from GPUIT_UCHAR_VEC to ITK_UCHAR_VEC\n"); this->convert_gpuit_uchar_vec_to_itk_uchar_vec (); break; default: print_and_exit ( "Error: unhandled conversion from %s to itk_uchar_vec\n", plm_image_type_string (this->m_type)); return; } this->m_type = PLM_IMG_TYPE_ITK_UCHAR_VEC; } void Plm_image::convert_to_itk (void) { switch (m_type) { case PLM_IMG_TYPE_ITK_CHAR: case PLM_IMG_TYPE_ITK_UCHAR: case PLM_IMG_TYPE_ITK_SHORT: case PLM_IMG_TYPE_ITK_USHORT: case PLM_IMG_TYPE_ITK_LONG: case PLM_IMG_TYPE_ITK_ULONG: case PLM_IMG_TYPE_ITK_FLOAT: case PLM_IMG_TYPE_ITK_DOUBLE: case PLM_IMG_TYPE_ITK_FLOAT_FIELD: case PLM_IMG_TYPE_ITK_UCHAR_VEC: /* Do nothing */ break; case PLM_IMG_TYPE_GPUIT_UCHAR: this->convert_to_itk_uchar (); break; case PLM_IMG_TYPE_GPUIT_SHORT: this->convert_to_itk_short (); break; case PLM_IMG_TYPE_GPUIT_UINT32: this->convert_to_itk_uint32 (); break; case PLM_IMG_TYPE_GPUIT_FLOAT: this->convert_to_itk_float (); break; case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: this->convert_to_itk_uchar_vec (); break; case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: default: print_and_exit ( "Error: unhandled conversion in Plm_image::convert_to_itk " " with type %s.\n", plm_image_type_string (this->m_type)); break; } } void Plm_image::convert_to_gpuit_short () { switch (this->m_type) { case PLM_IMG_TYPE_GPUIT_SHORT: return; case PLM_IMG_TYPE_GPUIT_FLOAT: volume_convert_to_short (this->get_vol()); return; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_ITK_UCHAR: case PLM_IMG_TYPE_ITK_SHORT: case PLM_IMG_TYPE_ITK_ULONG: case PLM_IMG_TYPE_ITK_FLOAT: default: print_and_exit ( "Error: unhandled conversion from %s to gpuit_short\n", plm_image_type_string (this->m_type)); return; } } void Plm_image::convert_to_gpuit_uint16 () { switch (this->m_type) { case PLM_IMG_TYPE_GPUIT_SHORT: return; case PLM_IMG_TYPE_GPUIT_FLOAT: volume_convert_to_uint16 (this->get_vol()); return; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_ITK_UCHAR: case PLM_IMG_TYPE_ITK_SHORT: case PLM_IMG_TYPE_ITK_ULONG: case PLM_IMG_TYPE_ITK_FLOAT: default: print_and_exit ( "Error: unhandled conversion from %s to gpuit_uint16\n", plm_image_type_string (this->m_type)); return; } } void Plm_image::convert_to_gpuit_uint32 () { switch (this->m_type) { case PLM_IMG_TYPE_GPUIT_UINT32: return; case PLM_IMG_TYPE_GPUIT_FLOAT: volume_convert_to_uint32 (this->get_vol()); return; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_ITK_UCHAR: case PLM_IMG_TYPE_ITK_SHORT: case PLM_IMG_TYPE_ITK_ULONG: case PLM_IMG_TYPE_ITK_FLOAT: default: print_and_exit ( "Error: unhandled conversion from %s to gpuit_uint32\n", plm_image_type_string (this->m_type)); return; } } void Plm_image::convert_to_gpuit_int32 () { switch (this->m_type) { case PLM_IMG_TYPE_GPUIT_INT32: return; case PLM_IMG_TYPE_GPUIT_FLOAT: volume_convert_to_int32 (this->get_vol()); return; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_ITK_UCHAR: case PLM_IMG_TYPE_ITK_SHORT: case PLM_IMG_TYPE_ITK_ULONG: case PLM_IMG_TYPE_ITK_FLOAT: default: print_and_exit ( "Error: unhandled conversion from %s to gpuit_int32\n", plm_image_type_string (this->m_type)); return; } } void Plm_image::convert_to_gpuit_float () { switch (this->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: this->convert_itk_to_gpuit ( this->m_itk_uchar); /* Free itk data */ this->m_itk_uchar = 0; break; case PLM_IMG_TYPE_ITK_CHAR: this->convert_itk_to_gpuit ( this->m_itk_char); /* Free itk data */ this->m_itk_char = 0; break; case PLM_IMG_TYPE_ITK_USHORT: this->convert_itk_to_gpuit ( this->m_itk_ushort); /* Free itk data */ this->m_itk_ushort = 0; break; case PLM_IMG_TYPE_ITK_SHORT: this->convert_itk_to_gpuit ( this->m_itk_short); /* Free itk data */ this->m_itk_short = 0; break; case PLM_IMG_TYPE_ITK_ULONG: this->convert_itk_to_gpuit ( this->m_itk_uint32); /* Free itk data */ this->m_itk_uint32 = 0; break; case PLM_IMG_TYPE_ITK_LONG: this->convert_itk_to_gpuit ( this->m_itk_int32); /* Free itk data */ this->m_itk_int32 = 0; break; case PLM_IMG_TYPE_ITK_FLOAT: this->convert_itk_to_gpuit ( this->m_itk_float); /* Free itk data */ this->m_itk_float = 0; break; case PLM_IMG_TYPE_ITK_DOUBLE: this->convert_itk_to_gpuit ( this->m_itk_double); /* Free itk data */ this->m_itk_double = 0; break; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_GPUIT_INT32: volume_convert_to_float (this->get_vol()); return; case PLM_IMG_TYPE_GPUIT_FLOAT: return; default: print_and_exit ( "Error: unhandled conversion from %s (%d) to gpuit_float\n", plm_image_type_string (this->m_type), this->m_type); return; } } void Plm_image::convert_to_gpuit_uchar_vec () { switch (this->m_type) { case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: return; case PLM_IMG_TYPE_ITK_UCHAR_VEC: this->convert_itk_uchar_vec_to_gpuit_uchar_vec (); return; default: print_and_exit ( "Error: unhandled conversion from %s to gpuit_uchar_vec\n", plm_image_type_string (this->m_type)); return; } } void Plm_image::convert_to_original_type (void) { this->convert (this->m_original_type); } void Plm_image::convert (Plm_image_type new_type) { switch (new_type) { case PLM_IMG_TYPE_UNDEFINED: /* Do nothing */ return; case PLM_IMG_TYPE_ITK_CHAR: this->convert_to_itk_char (); break; case PLM_IMG_TYPE_ITK_UCHAR: this->convert_to_itk_uchar (); break; case PLM_IMG_TYPE_ITK_SHORT: this->convert_to_itk_short (); break; case PLM_IMG_TYPE_ITK_USHORT: this->convert_to_itk_ushort (); break; case PLM_IMG_TYPE_ITK_LONG: this->convert_to_itk_int32 (); break; case PLM_IMG_TYPE_ITK_ULONG: this->convert_to_itk_uint32 (); break; case PLM_IMG_TYPE_ITK_FLOAT: this->convert_to_itk_float (); break; case PLM_IMG_TYPE_ITK_DOUBLE: this->convert_to_itk_double (); break; case PLM_IMG_TYPE_GPUIT_UCHAR: this->convert_to_gpuit_uchar (); break; case PLM_IMG_TYPE_GPUIT_SHORT: this->convert_to_gpuit_short (); break; case PLM_IMG_TYPE_GPUIT_UINT16: this->convert_to_gpuit_uint16 (); break; case PLM_IMG_TYPE_GPUIT_UINT32: this->convert_to_gpuit_uint32 (); break; case PLM_IMG_TYPE_GPUIT_INT32: this->convert_to_gpuit_int32 (); break; case PLM_IMG_TYPE_GPUIT_FLOAT: this->convert_to_gpuit_float (); break; case PLM_IMG_TYPE_ITK_UCHAR_VEC: this->convert_to_itk_uchar_vec (); break; default: print_and_exit ( "Unhandled image type in Plm_image::convert (%s -> %s)\n", plm_image_type_string (this->m_type), plm_image_type_string (new_type)); break; } this->m_type = new_type; } void Plm_image::convert_and_save (const char* fname, Plm_image_type new_type) { this->convert (new_type); this->save_image (fname); } void Plm_image::convert_and_save (const std::string& fname, Plm_image_type new_type) { this->convert_and_save (fname.c_str(), new_type); } /* geometry */ int Plm_image::planes () { switch (m_type) { case PLM_IMG_TYPE_UNDEFINED: return 0; case PLM_IMG_TYPE_ITK_FLOAT_FIELD: case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: return 3; case PLM_IMG_TYPE_ITK_UCHAR_VEC: return this->m_itk_uchar_vec->GetVectorLength(); case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: return this->get_vol()->vox_planes; default: return 1; } } size_t Plm_image::dim (size_t d1) { int d = (int) d1; switch (m_type) { case PLM_IMG_TYPE_UNDEFINED: return 0; case PLM_IMG_TYPE_ITK_CHAR: return this->m_itk_char->GetLargestPossibleRegion().GetSize()[d]; case PLM_IMG_TYPE_ITK_UCHAR: return this->m_itk_uchar->GetLargestPossibleRegion().GetSize()[d]; case PLM_IMG_TYPE_ITK_SHORT: return this->m_itk_short->GetLargestPossibleRegion().GetSize()[d]; case PLM_IMG_TYPE_ITK_USHORT: return this->m_itk_ushort->GetLargestPossibleRegion().GetSize()[d]; case PLM_IMG_TYPE_ITK_LONG: return this->m_itk_int32->GetLargestPossibleRegion().GetSize()[d]; case PLM_IMG_TYPE_ITK_ULONG: return this->m_itk_uint32->GetLargestPossibleRegion().GetSize()[d]; case PLM_IMG_TYPE_ITK_FLOAT: return this->m_itk_float->GetLargestPossibleRegion().GetSize()[d]; case PLM_IMG_TYPE_ITK_DOUBLE: return this->m_itk_double->GetLargestPossibleRegion().GetSize()[d]; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_GPUIT_UINT16: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_GPUIT_INT32: case PLM_IMG_TYPE_GPUIT_FLOAT: case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: return d_ptr->m_vol->dim[d]; case PLM_IMG_TYPE_ITK_UCHAR_VEC: default: print_and_exit ( "Unhandled call to Plm_image::dim (type = %s)\n", plm_image_type_string (this->m_type)); break; } return 0; } /* GCS FIX: This is inefficient. */ float Plm_image::origin (size_t d1) { int d = (int) d1; switch (m_type) { case PLM_IMG_TYPE_UNDEFINED: return 0; case PLM_IMG_TYPE_ITK_CHAR: return itk_image_origin(this->m_itk_char)[d]; case PLM_IMG_TYPE_ITK_UCHAR: return itk_image_origin(this->m_itk_uchar)[d]; case PLM_IMG_TYPE_ITK_SHORT: return itk_image_origin(this->m_itk_short)[d]; case PLM_IMG_TYPE_ITK_USHORT: return itk_image_origin(this->m_itk_ushort)[d]; case PLM_IMG_TYPE_ITK_LONG: return itk_image_origin(this->m_itk_int32)[d]; case PLM_IMG_TYPE_ITK_ULONG: return itk_image_origin(this->m_itk_uint32)[d]; case PLM_IMG_TYPE_ITK_FLOAT: return itk_image_origin(this->m_itk_float)[d]; case PLM_IMG_TYPE_ITK_DOUBLE: return itk_image_origin(this->m_itk_double)[d]; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_GPUIT_UINT16: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_GPUIT_INT32: case PLM_IMG_TYPE_GPUIT_FLOAT: case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: return d_ptr->m_vol->origin[d]; case PLM_IMG_TYPE_ITK_UCHAR_VEC: default: print_and_exit ( "Unhandled call to Plm_image::origin (type = %s)\n", plm_image_type_string (this->m_type)); break; } return 0.f; } float Plm_image::spacing (size_t d1) { int d = (int) d1; switch (m_type) { case PLM_IMG_TYPE_UNDEFINED: return 0; case PLM_IMG_TYPE_ITK_CHAR: return this->m_itk_char->GetSpacing()[d]; case PLM_IMG_TYPE_ITK_UCHAR: return this->m_itk_uchar->GetSpacing()[d]; case PLM_IMG_TYPE_ITK_SHORT: return this->m_itk_short->GetSpacing()[d]; case PLM_IMG_TYPE_ITK_USHORT: return this->m_itk_ushort->GetSpacing()[d]; case PLM_IMG_TYPE_ITK_LONG: return this->m_itk_int32->GetSpacing()[d]; case PLM_IMG_TYPE_ITK_ULONG: return this->m_itk_uint32->GetSpacing()[d]; case PLM_IMG_TYPE_ITK_FLOAT: return this->m_itk_float->GetSpacing()[d]; case PLM_IMG_TYPE_ITK_DOUBLE: return this->m_itk_double->GetSpacing()[d]; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_GPUIT_UINT16: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_GPUIT_INT32: case PLM_IMG_TYPE_GPUIT_FLOAT: case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: return d_ptr->m_vol->spacing[d]; case PLM_IMG_TYPE_ITK_UCHAR_VEC: default: print_and_exit ( "Unhandled call to Plm_image::spacing (type = %s)\n", plm_image_type_string (this->m_type)); break; } return 0.f; } /* Printing debug information */ void Plm_image::print () { lprintf ("Type = %s\n", plm_image_type_string_simple (this->m_type)); lprintf ("Planes = %d\n", this->planes()); Plm_image_header pih; pih.set_from_plm_image (this); pih.print (); } /* Return 1 if the two headers are the same */ int Plm_image::compare_headers ( const Plm_image::Pointer& pli1, const Plm_image::Pointer& pli2) { Plm_image_header pih1, pih2; pih1.set_from_plm_image (pli1); pih2.set_from_plm_image (pli2); return Plm_image_header::compare (&pih1, &pih2); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_image.h000066400000000000000000000152521321604176500276410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_image_h_ #define _plm_image_h_ #include "plmbase_config.h" #include "compiler_warnings.h" #include "itk_image.h" #include "metadata.h" #include "plm_image_type.h" #include "smart_pointer.h" #include "volume.h" class Plm_image_header; class Plm_image; class Plm_image_private; class Rt_study_metadata; /*! \brief * The Plm_image class represents a three-dimensional volume. * The volume is an abstraction that can contain a volume in either * native format (Volume), or ITK format (itk::Image), in any * type (unsigned char, float, etc.), or in several commonly used * extensions () */ class PLMBASE_API Plm_image { public: SMART_POINTER_SUPPORT (Plm_image); Plm_image_private *d_ptr; public: Plm_image (); Plm_image (const char* fname); Plm_image (const std::string& fname); Plm_image (const char* fname, Plm_image_type type); Plm_image (const std::string& fname, Plm_image_type type); Plm_image (UCharImageType::Pointer img); Plm_image (CharImageType::Pointer img); Plm_image (ShortImageType::Pointer img); Plm_image (FloatImageType::Pointer img); Plm_image (const Volume::Pointer& vol); Plm_image (Volume* vol); Plm_image (Plm_image_type type, const Plm_image_header& pih); ~Plm_image (); public: Plm_image_type m_original_type; Plm_image_type m_type; /* The actual image is one of the following. */ UCharImageType::Pointer m_itk_uchar; CharImageType::Pointer m_itk_char; UShortImageType::Pointer m_itk_ushort; ShortImageType::Pointer m_itk_short; UInt32ImageType::Pointer m_itk_uint32; Int32ImageType::Pointer m_itk_int32; FloatImageType::Pointer m_itk_float; DoubleImageType::Pointer m_itk_double; UCharVecImageType::Pointer m_itk_uchar_vec; private: /* Please don't use copy constructors. They suck. */ Plm_image (Plm_image&) { } /* Please don't use overloaded operators. They suck. */ Plm_image& operator= (Plm_image&) { return *this; } void convert_to_itk_char (); void convert_to_itk_uchar (); void convert_to_itk_short (); void convert_to_itk_ushort (); void convert_to_itk_int32 (void); void convert_to_itk_uint32 (); void convert_to_itk_float (); void convert_to_itk_double (); void convert_to_gpuit_short (); void convert_to_gpuit_uint16 (); void convert_to_gpuit_uint32 (); void convert_to_gpuit_int32 (); void convert_to_gpuit_float (); void convert_to_gpuit_uchar (); void convert_to_gpuit_uchar_vec (); public: /* creation / destruction */ void init (); void free (); bool have_image (); Plm_image::Pointer clone (void); void create (Plm_image_type type, const Plm_image_header& pih); /* Loading */ bool load (const char* fname, Plm_image_type type); bool load_native (const char* fname); bool load_native (const std::string& fn); bool load_native_dicom (const char* fname); bool load_native_nki (const char* fname); /* Saving */ void save_short_dicom (const char* fname, Rt_study_metadata *rsm); void save_short_dicom (const std::string& fname, Rt_study_metadata *rsm); void save_image (const char* fname); void save_image (const std::string& fname); void convert_and_save (const char* fname, Plm_image_type new_type); void convert_and_save (const std::string& fname, Plm_image_type new_type); /* assignment */ void set (const Plm_image::Pointer& pli); void set_volume (const Volume::Pointer& v, Plm_image_type type); void set_volume (const Volume::Pointer& v); void set_volume (Volume *v, Plm_image_type type); void set_volume (Volume *v); void set_itk (UCharImageType::Pointer img); void set_itk (CharImageType::Pointer img); void set_itk (UShortImageType::Pointer img); void set_itk (ShortImageType::Pointer img); void set_itk (UInt32ImageType::Pointer img); void set_itk (Int32ImageType::Pointer img); void set_itk (FloatImageType::Pointer img); void set_itk (DoubleImageType::Pointer img); void set_itk (UCharVecImageType::Pointer img); /* conversion */ FloatImageType::Pointer& itk_float () { convert_to_itk_float (); return m_itk_float; } ShortImageType::Pointer& itk_short () { convert_to_itk_short (); return m_itk_short; } UCharImageType::Pointer& itk_uchar () { convert_to_itk_uchar (); return m_itk_uchar; } UCharVecImageType::Pointer& itk_uchar_vec () { convert_to_itk_uchar_vec (); return m_itk_uchar_vec; } Volume::Pointer& get_volume (); Volume::Pointer& get_volume_uchar (); Volume::Pointer& get_volume_short (); Volume::Pointer& get_volume_float (); Volume::Pointer& get_volume_uchar_vec (); Volume* get_vol (); const Volume* get_vol () const; void convert (Plm_image_type new_type); void convert_to_original_type (void); void convert_to_itk (void); void convert_to_itk_float_field (void); void convert_to_itk_uchar_vec (void); /* geometry */ int planes (); size_t dim (size_t); float origin (size_t); float spacing (size_t); /* debug */ void print (); /* Static functions */ static int compare_headers ( const Plm_image::Pointer& pli1, const Plm_image::Pointer& pli2); static Plm_image::Pointer clone (const Plm_image::Pointer& pli); protected: /* Utility functions */ void free_volume (); /* Specific converters: implemented in plm_image_convert.cxx */ void convert_itk_uchar_to_itk_uchar_vec (); void convert_itk_uint32_to_itk_uchar_vec (); void convert_gpuit_uint32_to_itk_uchar_vec (); void convert_gpuit_uchar_vec_to_itk_uchar_vec (); void convert_itk_uchar_vec_to_gpuit_uchar_vec (); /* Generic converters: implemented in plm_image_convert.cxx */ template T convert_gpuit_to_itk (Volume *vol); template void convert_itk_to_gpuit (T img); }; /* ----------------------------------------------------------------------- Public functions ----------------------------------------------------------------------- */ PLMBASE_API Plm_image::Pointer plm_image_load ( const char* fname, Plm_image_type type); PLMBASE_API Plm_image::Pointer plm_image_load ( const std::string& fname, Plm_image_type type); PLMBASE_API Plm_image::Pointer plm_image_load_native ( const char* fname); PLMBASE_API Plm_image::Pointer plm_image_load_native ( const std::string& fname); #endif plm_image_convert.cxx000066400000000000000000000352041321604176500316740ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "itk_directions.h" #include "itk_image_type.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_p.h" #include "volume.h" /* ----------------------------------------------------------------------- Standard 3D image conversion ----------------------------------------------------------------------- */ template T Plm_image::convert_gpuit_to_itk (Volume *vol) { typedef typename T::ObjectType ImageType; int i, d1, d2; U* img = (U*) vol->img; typename ImageType::SizeType sz; typename ImageType::IndexType st; typename ImageType::RegionType rg; typename ImageType::PointType og; typename ImageType::SpacingType sp; typename ImageType::DirectionType dc; /* Copy header & allocate data for itk */ for (d1 = 0; d1 < 3; d1++) { st[d1] = 0; sz[d1] = vol->dim[d1]; sp[d1] = vol->spacing[d1]; og[d1] = vol->origin[d1]; for (d2 = 0; d2 < 3; d2++) { dc[d1][d2] = vol->direction_cosines[d1*3+d2]; } } rg.SetSize (sz); rg.SetIndex (st); T itk_img = ImageType::New(); itk_img->SetRegions (rg); itk_img->SetOrigin (og); itk_img->SetSpacing (sp); itk_img->SetDirection (dc); itk_img->Allocate(); /* Copy data into itk */ typedef itk::ImageRegionIterator< ImageType > IteratorType; IteratorType it (itk_img, rg); for (it.GoToBegin(), i=0; !it.IsAtEnd(); ++it, ++i) { /* Type conversion: U -> itk happens here */ it.Set (img[i]); } /* Free input volume */ this->free_volume (); /* Return the new image; caller will assign to correct member and set type */ return itk_img; } template void Plm_image::convert_itk_to_gpuit (T img) { typedef typename T::ObjectType ImageType; int i, d1; typename ImageType::RegionType rg = img->GetLargestPossibleRegion (); typename ImageType::PointType og = img->GetOrigin(); typename ImageType::SpacingType sp = img->GetSpacing(); typename ImageType::SizeType sz = rg.GetSize(); typename ImageType::DirectionType dc = img->GetDirection(); typename ImageType::IndexType rgi = rg.GetIndex(); /* Copy header & allocate data for gpuit float */ plm_long dim[3]; plm_long rgidx[3]; float origin[3]; float spacing[3]; float direction_cosines[9]; for (d1 = 0; d1 < 3; d1++) { dim[d1] = sz[d1]; rgidx[d1] = rgi[d1]; origin[d1] = og[d1]; spacing[d1] = sp[d1]; } dc_from_itk_direction (direction_cosines, &dc); /* Choose output data type */ enum Volume_pixel_type pix_type; if (typeid (U) == typeid (unsigned char)){ pix_type = PT_UCHAR; this->m_type = PLM_IMG_TYPE_GPUIT_UCHAR; } else if (typeid (U) == typeid (short)){ pix_type = PT_SHORT; this->m_type = PLM_IMG_TYPE_GPUIT_SHORT; } else if (typeid (U) == typeid (float)) { pix_type = PT_FLOAT; this->m_type = PLM_IMG_TYPE_GPUIT_FLOAT; } else { lprintf ("unknown type conversion from itk to gpuit!\n"); exit (0); } /* Create volume */ Volume* vol = new Volume (dim, origin, spacing, direction_cosines, pix_type, 1); U *vol_img = (U*) vol->img; /* Fix itk images with non-zero region indices */ vol->move_origin_to_idx (rgidx); /* Copy data into gpuit */ typedef typename itk::ImageRegionIterator< ImageType > IteratorType; IteratorType it (img, rg); for (it.GoToBegin(), i=0; !it.IsAtEnd(); ++it, ++i) { vol_img[i] = it.Get(); } /* Fix volume into plm_image */ d_ptr->m_vol.reset (vol); } /* ----------------------------------------------------------------------- UCharVec image conversion ----------------------------------------------------------------------- */ void Plm_image::convert_itk_uchar_to_itk_uchar_vec () { UCharImageType::Pointer itk_uchar = this->m_itk_uchar; /* Create the output image */ UCharVecImageType::Pointer im_out = UCharVecImageType::New(); itk_image_header_copy (im_out, itk_uchar); im_out->SetVectorLength (2); im_out->Allocate (); /* Copy data into itk */ typedef itk::ImageRegionIterator< UCharImageType > UCharIteratorType; const UCharImageType::RegionType rgn_in = itk_uchar->GetLargestPossibleRegion(); UCharIteratorType it_in (itk_uchar, rgn_in); typedef itk::ImageRegionIterator< UCharVecImageType > UCharVecIteratorType; const UCharVecImageType::RegionType rgn_out = im_out->GetLargestPossibleRegion(); UCharVecIteratorType it_out (im_out, rgn_out); itk::VariableLengthVector v_out(2); for (it_in.GoToBegin(), it_out.GoToBegin(); !it_in.IsAtEnd(); ++it_in, ++it_out) { unsigned char v_in = it_in.Get (); v_out[0] = v_in; v_out[1] = 0; it_out.Set (v_out); } /* Free input volume */ this->m_itk_uchar = 0; /* Set output volume */ this->m_itk_uchar_vec = im_out; } void Plm_image::convert_itk_uint32_to_itk_uchar_vec () { UInt32ImageType::Pointer itk_uint32 = this->m_itk_uint32; /* Create the output image */ UCharVecImageType::Pointer im_out = UCharVecImageType::New(); itk_image_header_copy (im_out, itk_uint32); im_out->SetVectorLength (4); im_out->Allocate (); /* Copy data into itk */ typedef itk::ImageRegionIterator< UInt32ImageType > UInt32IteratorType; const UInt32ImageType::RegionType rgn_in = itk_uint32->GetLargestPossibleRegion(); UInt32IteratorType it_in (itk_uint32, rgn_in); typedef itk::ImageRegionIterator< UCharVecImageType > UCharVecIteratorType; const UCharVecImageType::RegionType rgn_out = im_out->GetLargestPossibleRegion(); UCharVecIteratorType it_out (im_out, rgn_out); itk::VariableLengthVector v_out(4); for (it_in.GoToBegin(), it_out.GoToBegin(); !it_in.IsAtEnd(); ++it_in, ++it_out) { uint32_t v_in = it_in.Get (); v_out[0] = v_in & 0x000000FF; v_out[1] = (v_in & 0x0000FF00) >> 8; v_out[2] = (v_in & 0x00FF0000) >> 16; v_out[3] = (v_in & 0xFF000000) >> 24; it_out.Set (v_out); } /* Free input volume */ this->m_itk_uint32 = 0; /* Set output volume */ this->m_itk_uchar_vec = im_out; } void Plm_image::convert_gpuit_uint32_to_itk_uchar_vec () { int i, d; Volume* vol = this->get_vol (); uint32_t* img = (uint32_t*) vol->img; UCharVecImageType::Pointer im_out = UCharVecImageType::New(); UCharVecImageType::RegionType rgn_out; UCharVecImageType::PointType og_out; UCharVecImageType::SpacingType sp_out; UCharVecImageType::RegionType::SizeType sz_out; UCharVecImageType::DirectionType dc; /* Copy header & allocate data for itk */ for (d = 0; d < 3; d++) { sz_out[d] = vol->dim[d]; og_out[d] = vol->origin[d]; sp_out[d] = vol->spacing[d]; } for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { dc[d1][d2] = vol->direction_cosines[d1*3+d2]; } } rgn_out.SetSize (sz_out); im_out->SetRegions (rgn_out); im_out->SetOrigin (og_out); im_out->SetSpacing (sp_out); im_out->SetDirection (dc); /* Choose size of vectors for image */ im_out->SetVectorLength (4); im_out->Allocate (); /* Copy data into itk */ typedef itk::ImageRegionIterator< UCharVecImageType > IteratorType; IteratorType it (im_out, rgn_out); for (it.GoToBegin(), i=0; !it.IsAtEnd(); ++it, ++i) { /* GCS FIX: This is probably inefficient, unless the compiler is very, very smart (which I doubt) */ /* GCS FIX: This puts the planes in the "wrong" order, with uint32_t MSB as first component of vector */ it.Set (itk::VariableLengthVector ( (unsigned char*) &img[i], 4)); } /* Free input volume */ this->free_volume (); /* Set output volume */ this->m_itk_uchar_vec = im_out; } void Plm_image::convert_gpuit_uchar_vec_to_itk_uchar_vec () { int i, d; Volume* vol = this->get_vol (); unsigned char* img = (unsigned char*) vol->img; UCharVecImageType::Pointer im_out = UCharVecImageType::New(); UCharVecImageType::RegionType rgn_out; UCharVecImageType::PointType og_out; UCharVecImageType::SpacingType sp_out; UCharVecImageType::RegionType::SizeType sz_out; UCharVecImageType::DirectionType dc; /* Copy header & allocate data for itk */ for (d = 0; d < 3; d++) { sz_out[d] = vol->dim[d]; og_out[d] = vol->origin[d]; sp_out[d] = vol->spacing[d]; } for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { dc[d1][d2] = vol->direction_cosines[d1*3+d2]; } } rgn_out.SetSize (sz_out); im_out->SetRegions (rgn_out); im_out->SetOrigin (og_out); im_out->SetSpacing (sp_out); im_out->SetDirection (dc); /* Choose size of vectors for image, minimum of 2 planes for itk */ int out_vec_len = vol->vox_planes; if (out_vec_len < 2) out_vec_len = 2; im_out->SetVectorLength (out_vec_len); im_out->Allocate (); /* Copy data into itk */ typedef itk::ImageRegionIterator< UCharVecImageType > IteratorType; IteratorType it (im_out, rgn_out); itk::VariableLengthVector v_out(out_vec_len); for (it.GoToBegin(), i=0; !it.IsAtEnd(); ++it) { for (int j = 0; j < vol->vox_planes; ++j, ++i) { v_out[j] = img[i]; } it.Set (v_out); } /* Free input volume */ this->free_volume (); /* Set output volume */ this->m_itk_uchar_vec = im_out; } void Plm_image::convert_itk_uchar_vec_to_gpuit_uchar_vec () { UCharVecImageType::Pointer itk_uchar_vec = this->m_itk_uchar_vec; /* Copy header & allocate data for gpuit image */ int i; UCharVecImageType::RegionType rg = itk_uchar_vec->GetLargestPossibleRegion (); UCharVecImageType::PointType og = itk_uchar_vec->GetOrigin(); UCharVecImageType::SpacingType sp = itk_uchar_vec->GetSpacing(); UCharVecImageType::SizeType sz = rg.GetSize(); UCharVecImageType::DirectionType itk_dc = itk_uchar_vec->GetDirection(); plm_long dim[3]; float origin[3]; float spacing[3]; float direction_cosines[9]; for (int d = 0; d < 3; d++) { dim[d] = sz[d]; origin[d] = og[d]; spacing[d] = sp[d]; } dc_from_itk_direction (direction_cosines, &itk_dc); int vox_planes = itk_uchar_vec->GetVectorLength (); Volume* vol = new Volume (dim, origin, spacing, direction_cosines, PT_UCHAR_VEC_INTERLEAVED, vox_planes); unsigned char* vol_img = (unsigned char*) vol->img; /* Copy data into gpuit */ typedef itk::ImageRegionIterator< UCharVecImageType > IteratorType; IteratorType it (itk_uchar_vec, rg); for (it.GoToBegin(), i=0; !it.IsAtEnd(); ++it) { itk::VariableLengthVector v = it.Get(); for (int j = 0; j < vox_planes; ++j, ++i) { vol_img[i] = v[j]; } } /* Free input volume */ this->m_itk_uchar_vec = 0; /* Set output volume */ d_ptr->m_vol.reset (vol); this->m_type = PLM_IMG_TYPE_GPUIT_UCHAR_VEC; } /* Explicit instantiations */ template PLMBASE_API UCharImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API UCharImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API ShortImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API ShortImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API UShortImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API Int32ImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API Int32ImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API Int32ImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API Int32ImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API UInt32ImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API UInt32ImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API UInt32ImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API UInt32ImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API FloatImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API FloatImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API FloatImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API DoubleImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API DoubleImageType::Pointer Plm_image::convert_gpuit_to_itk (Volume*); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( UCharImageType::Pointer); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( ShortImageType::Pointer); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( FloatImageType::Pointer); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( UCharImageType::Pointer); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( CharImageType::Pointer); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( UShortImageType::Pointer); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( ShortImageType::Pointer); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( UInt32ImageType::Pointer); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( Int32ImageType::Pointer); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( FloatImageType::Pointer); template PLMBASE_API void Plm_image::convert_itk_to_gpuit ( DoubleImageType::Pointer); plm_image_header.cxx000066400000000000000000000455071321604176500314530ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "itkImageRegionIterator.h" #include #include #include "bspline_xform.h" #include "direction_cosines.h" #include "direction_matrices.h" #include "itk_directions.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "print_and_exit.h" #include "volume.h" #include "volume_header.h" class Plm_image_header_private { public: OriginType m_origin; }; /* ----------------------------------------------------------------------- Constructors, destructors, operator= ----------------------------------------------------------------------- */ Plm_image_header::Plm_image_header () { d_ptr = new Plm_image_header_private; } Plm_image_header::Plm_image_header ( plm_long dim[3], float origin[3], float spacing[3]) { d_ptr = new Plm_image_header_private; this->set_from_gpuit (dim, origin, spacing, 0); } Plm_image_header::Plm_image_header ( plm_long dim[3], float origin[3], float spacing[3], float direction_cosines[9]) { d_ptr = new Plm_image_header_private; this->set_from_gpuit (dim, origin, spacing, direction_cosines); } Plm_image_header::Plm_image_header ( const RegionType& region, const OriginType& origin, const SpacingType& spacing, const DirectionType& direction) { d_ptr = new Plm_image_header_private; this->set (region, origin,spacing, direction); } Plm_image_header::Plm_image_header (Plm_image *pli) { d_ptr = new Plm_image_header_private; this->set_from_plm_image (pli); } Plm_image_header::Plm_image_header (const Plm_image& pli) { d_ptr = new Plm_image_header_private; this->set_from_plm_image (pli); } Plm_image_header::Plm_image_header (const Plm_image::Pointer& pli) { d_ptr = new Plm_image_header_private; this->set_from_plm_image (pli); } Plm_image_header::Plm_image_header (const Volume_header& vh) { d_ptr = new Plm_image_header_private; this->set (vh); } Plm_image_header::Plm_image_header (const Volume::Pointer& vol) { d_ptr = new Plm_image_header_private; this->set (vol); } Plm_image_header::Plm_image_header (const Volume& vol) { d_ptr = new Plm_image_header_private; this->set (vol); } Plm_image_header::Plm_image_header (const Volume* vol) { d_ptr = new Plm_image_header_private; this->set (vol); } Plm_image_header::Plm_image_header (Volume* vol) { d_ptr = new Plm_image_header_private; this->set (vol); } template Plm_image_header::Plm_image_header (T image) { d_ptr = new Plm_image_header_private; this->set_from_itk_image (image); } Plm_image_header::Plm_image_header (const Plm_image_header& other) { d_ptr = new Plm_image_header_private (); this->m_origin = other.m_origin; this->m_spacing = other.m_spacing; this->m_region = other.m_region; this->m_direction = other.m_direction; } Plm_image_header::~Plm_image_header () { delete d_ptr; } const Plm_image_header& Plm_image_header::operator= (const Plm_image_header& other) { this->m_origin = other.m_origin; this->m_spacing = other.m_spacing; this->m_region = other.m_region; this->m_direction = other.m_direction; return *this; } /* ----------------------------------------------------------------------- Getters and Setters ----------------------------------------------------------------------- */ int Plm_image_header::dim (int d) const { return m_region.GetSize()[d]; } float Plm_image_header::origin (int d) const { return m_origin[d]; } float Plm_image_header::spacing (int d) const { return m_spacing[d]; } void Plm_image_header::set_dim (const plm_long dim[3]) { RegionType::SizeType itk_size; RegionType::IndexType itk_index; for (unsigned int d = 0; d < 3; d++) { itk_index[d] = 0; itk_size[d] = dim[d]; } m_region.SetSize (itk_size); m_region.SetIndex (itk_index); } void Plm_image_header::set_origin (const float origin[3]) { for (unsigned int d = 0; d < 3; d++) { this->m_origin[d] = origin[d]; } } void Plm_image_header::set_spacing (const float spacing[3]) { for (unsigned int d = 0; d < 3; d++) { this->m_spacing[d] = spacing[d]; } } void Plm_image_header::set_direction_cosines (const float direction_cosines[9]) { if (direction_cosines) { itk_direction_from_dc (&m_direction, direction_cosines); } else { itk_direction_set_identity (&m_direction); } } void Plm_image_header::set_direction_cosines (const Direction_cosines& dc) { itk_direction_from_dc (&m_direction, dc); } void Plm_image_header::set (const Plm_image_header& src) { this->m_origin = src.m_origin; this->m_spacing = src.m_spacing; this->m_region = src.m_region; this->m_direction = src.m_direction; } void Plm_image_header::set ( const plm_long dim[3], const float origin[3], const float spacing[3], const float direction_cosines[9]) { this->set_dim (dim); this->set_origin (origin); this->set_spacing (spacing); this->set_direction_cosines (direction_cosines); } void Plm_image_header::set ( const plm_long dim[3], const float origin[3], const float spacing[3], const Direction_cosines& dc) { this->set (dim, origin, spacing, dc.get_matrix()); } void Plm_image_header::set_from_gpuit ( const plm_long dim[3], const float origin[3], const float spacing[3], const float direction_cosines[9]) { this->set (dim, origin, spacing, direction_cosines); } void Plm_image_header::set_from_gpuit_bspline (Bspline_xform *bxf) { this->set ( bxf->img_dim, bxf->img_origin, bxf->img_spacing, bxf->dc); } void Plm_image_header::set_from_plm_image (const Plm_image *pli) { switch (pli->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: this->set_from_itk_image (pli->m_itk_uchar); break; case PLM_IMG_TYPE_ITK_SHORT: this->set_from_itk_image (pli->m_itk_short); break; case PLM_IMG_TYPE_ITK_USHORT: this->set_from_itk_image (pli->m_itk_ushort); break; case PLM_IMG_TYPE_ITK_LONG: this->set_from_itk_image (pli->m_itk_int32); break; case PLM_IMG_TYPE_ITK_ULONG: this->set_from_itk_image (pli->m_itk_uint32); break; case PLM_IMG_TYPE_ITK_FLOAT: this->set_from_itk_image (pli->m_itk_float); break; case PLM_IMG_TYPE_ITK_DOUBLE: this->set_from_itk_image (pli->m_itk_double); break; case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_GPUIT_FLOAT: case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: { const Volume* vol = pli->get_vol (); set_from_gpuit (vol->dim, vol->origin, vol->spacing, vol->direction_cosines); break; } case PLM_IMG_TYPE_ITK_UCHAR_VEC: this->set_from_itk_image (pli->m_itk_uchar_vec); break; case PLM_IMG_TYPE_ITK_FLOAT_FIELD: case PLM_IMG_TYPE_ITK_CHAR: default: print_and_exit ("Unhandled image type (%s) in set_from_plm_image\n", plm_image_type_string (pli->m_type)); break; } } void Plm_image_header::set_from_plm_image (const Plm_image& pli) { this->set_from_plm_image (&pli); } void Plm_image_header::set_from_plm_image (const Plm_image::Pointer& pli) { this->set_from_plm_image (pli.get()); } void Plm_image_header::set (const Volume_header& vh) { this->set_from_gpuit (vh.get_dim(), vh.get_origin(), vh.get_spacing(), vh.get_direction_cosines()); } void Plm_image_header::set_from_volume_header (const Volume_header& vh) { this->set (vh); } void Plm_image_header::set (const Volume::Pointer& vol) { this->set_from_gpuit (vol->dim, vol->origin, vol->spacing, vol->direction_cosines); } void Plm_image_header::set (const Volume& vol) { this->set_from_gpuit (vol.dim, vol.origin, vol.spacing, vol.direction_cosines); } void Plm_image_header::set (const Volume* vol) { this->set_from_gpuit (vol->dim, vol->origin, vol->spacing, vol->direction_cosines); } void Plm_image_header::set ( const RegionType& region, const OriginType& origin, const SpacingType& spacing, const DirectionType& direction) { m_region = region; m_origin = origin; m_spacing = spacing; m_direction = direction; /* Adjust origin and set index to zero in case of non-zero ITK region index */ const IndexType& index = region.GetIndex(); for (int d1 = 0; d1 < 3; d1++) { for (int d2 = 0; d2 < 3; d2++) { m_origin[d2] += index[d1] * spacing[d1] * direction[d2][d1]; } } IndexType i2; i2[0] = i2[1] = i2[2] = 0; m_region.SetIndex (i2); } template void Plm_image_header::set_from_itk_image (const T& image) { m_origin = itk_image_origin (image); m_spacing = image->GetSpacing (); m_region = itk_image_region (image); m_direction = image->GetDirection (); } template void Plm_image_header::set_from_itk_image (const T* image) { m_origin = itk_image_origin (image); m_spacing = image->GetSpacing (); m_region = itk_image_region (image); m_direction = image->GetDirection (); } const OriginType& Plm_image_header::GetOrigin () const { return m_origin; } const SpacingType& Plm_image_header::GetSpacing () const { return m_spacing; } const RegionType& Plm_image_header::GetRegion () const { return m_region; } const DirectionType& Plm_image_header::GetDirection () const { return m_direction; } const SizeType& Plm_image_header::GetSize (void) const { return m_region.GetSize (); } void Plm_image_header::get_volume_header (Volume_header *vh) const { this->get_origin (vh->get_origin()); this->get_dim (vh->get_dim()); this->get_spacing (vh->get_spacing()); this->get_direction_cosines (vh->get_direction_cosines()); } void Plm_image_header::get_origin (float origin[3]) const { for (unsigned int d = 0; d < 3; d++) { origin[d] = m_origin[d]; } } void Plm_image_header::get_spacing (float spacing[3]) const { for (unsigned int d = 0; d < 3; d++) { spacing[d] = m_spacing[d]; } } void Plm_image_header::get_dim (plm_long dim[3]) const { RegionType::SizeType itk_size = m_region.GetSize (); for (unsigned int d = 0; d < 3; d++) { dim[d] = itk_size[d]; } } void Plm_image_header::get_direction_cosines (float direction_cosines[9]) const { dc_from_itk_direction (direction_cosines, &m_direction); } /* ----------------------------------------------------------------------- Algorithms ----------------------------------------------------------------------- */ /* static */ void Plm_image_header::clone (Plm_image_header *dest, const Plm_image_header *src) { dest->m_origin = src->m_origin; dest->m_spacing = src->m_spacing; dest->m_region = src->m_region; dest->m_direction = src->m_direction; } void Plm_image_header::expand_to_contain ( const FloatPoint3DType& position) { /* Compute index for this position */ FloatPoint3DType idx = this->get_index (position); /* Get the step & proj matrices */ /* GCS FIX: This is inefficient, already computed in get_index() */ float spacing[3], step[9], proj[9]; Direction_cosines dc (m_direction); this->get_spacing (spacing); compute_direction_matrices (step, proj, dc, spacing); RegionType::SizeType itk_size = m_region.GetSize(); /* Expand the volume to contain the point */ for (int d1 = 0; d1 < 3; d1++) { if (idx[d1] < 0) { float extra = (float) floor ((double) idx[d1]); for (int d2 = 0; d2 < 3; d2++) { m_origin[d2] += extra * step[d2*3+d1]; } itk_size[d1] += (int) -extra; } else if (idx[d1] > itk_size[d1] - 1) { itk_size[d1] = (int) floor ((double) idx[d1]) + 1; } } m_region.SetSize (itk_size); } void Plm_image_header::set_geometry_to_contain ( const Plm_image_header& reference_pih, const Plm_image_header& compare_pih) { /* Initialize to reference image */ this->set (reference_pih); /* Expand to contain all eight corners of compare image */ FloatPoint3DType pos; float idx[3]; idx[0] = 0; idx[1] = 0; idx[2] = 0; pos = compare_pih.get_position (idx); this->expand_to_contain (pos); idx[0] = 0; idx[1] = 0; idx[2] = compare_pih.dim(2) - 1; pos = compare_pih.get_position (idx); this->expand_to_contain (pos); idx[0] = 0; idx[1] = compare_pih.dim(1) - 1; idx[2] = 0; pos = compare_pih.get_position (idx); this->expand_to_contain (pos); idx[0] = 0; idx[1] = compare_pih.dim(1) - 1; idx[2] = compare_pih.dim(2) - 1; pos = compare_pih.get_position (idx); this->expand_to_contain (pos); idx[0] = compare_pih.dim(0) - 1; idx[1] = 0; idx[2] = 0; pos = compare_pih.get_position (idx); this->expand_to_contain (pos); idx[0] = compare_pih.dim(0) - 1; idx[1] = 0; idx[2] = compare_pih.dim(2) - 1; pos = compare_pih.get_position (idx); this->expand_to_contain (pos); idx[0] = compare_pih.dim(0) - 1; idx[1] = compare_pih.dim(1) - 1; idx[2] = 0; pos = compare_pih.get_position (idx); this->expand_to_contain (pos); idx[0] = compare_pih.dim(0) - 1; idx[1] = compare_pih.dim(1) - 1; idx[2] = compare_pih.dim(2) - 1; pos = compare_pih.get_position (idx); this->expand_to_contain (pos); } void Plm_image_header::print (void) const { RegionType::SizeType itk_size; itk_size = m_region.GetSize (); float dc[9]; this->get_direction_cosines (dc); lprintf ("Origin ="); for (unsigned int d = 0; d < 3; d++) { lprintf (" %g", m_origin[d]); } lprintf ("\nSize ="); for (unsigned int d = 0; d < 3; d++) { lprintf (" %lu", itk_size[d]); } lprintf ("\nSpacing ="); for (unsigned int d = 0; d < 3; d++) { lprintf (" %g", m_spacing[d]); } lprintf ("\nDirection ="); for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { lprintf (" %g", dc[d1*3+d2]); } } lprintf ("\n"); } FloatPoint3DType Plm_image_header::get_index (const FloatPoint3DType& pos) const { FloatPoint3DType idx; FloatPoint3DType tmp; float spacing[3], step[9], proj[9]; Direction_cosines dc (m_direction); this->get_spacing (spacing); compute_direction_matrices (step, proj, dc, spacing); for (int d1 = 0; d1 < 3; d1++) { tmp[d1] = pos[d1] - m_origin[d1]; idx[d1] = 0; } for (int d1 = 0; d1 < 3; d1++) { for (int d2 = 0; d2 < 3; d2++) { idx[d1] += tmp[d2] * proj[d1*3+d2]; } } return idx; } FloatPoint3DType Plm_image_header::get_position (const float index[3]) const { FloatPoint3DType pos; for (int d = 0; d < 3; d++) { pos[d] = m_origin[d]; } for (int d = 0; d < 3; d++) { for (int dc = 0; dc < 3; dc++) { pos[dc] += m_spacing[d] * index[d] * m_direction[d][dc]; } } return pos; } void Plm_image_header::get_image_center (float center[3]) const { int d; for (d = 0; d < 3; d++) { center[d] = this->m_origin[d] + this->m_spacing[d] * (this->dim(d) - 1) / 2; } } plm_long Plm_image_header::get_num_voxels (void) const { return this->dim(0) * this->dim(1) * this->dim(2); } void Plm_image_header::get_image_extent (float extent[3]) const { int d; for (d = 0; d < 3; d++) { extent[d] = this->m_spacing[d] * (this->dim(d) - 1); } } /* Return true if the two headers are the same, within tolerance */ bool Plm_image_header::compare (Plm_image_header *pli1, Plm_image_header *pli2, float threshold) { int d; for (d = 0; d < 3; d++) { if (fabs (pli1->m_origin[d] - pli2->m_origin[d]) > threshold) { return false; } if (fabs (pli1->m_spacing[d] - pli2->m_spacing[d]) > threshold) { return false; } if (pli1->dim(d) != pli2->dim(d)) { return false; } } /* GCS FIX: check direction cosines */ return true; } /* Explicit instantiations */ template PLMBASE_API Plm_image_header::Plm_image_header (CharImageType::Pointer image); template PLMBASE_API Plm_image_header::Plm_image_header (UCharImageType::Pointer image); template PLMBASE_API Plm_image_header::Plm_image_header (ShortImageType::Pointer image); template PLMBASE_API Plm_image_header::Plm_image_header (UShortImageType::Pointer image); template PLMBASE_API Plm_image_header::Plm_image_header (Int32ImageType::Pointer image); template PLMBASE_API Plm_image_header::Plm_image_header (UInt32ImageType::Pointer image); template PLMBASE_API Plm_image_header::Plm_image_header (FloatImageType::Pointer image); template PLMBASE_API Plm_image_header::Plm_image_header (DoubleImageType::Pointer image); template PLMBASE_API Plm_image_header::Plm_image_header (DeformationFieldType::Pointer image); template PLMBASE_API Plm_image_header::Plm_image_header (UCharVecImageType::Pointer image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const CharImageType::Pointer& image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const UCharImageType::Pointer& image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const ShortImageType::Pointer& image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const UShortImageType::Pointer& image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const Int32ImageType::Pointer& image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const UInt32ImageType::Pointer& image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const FloatImageType::Pointer& image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const DoubleImageType::Pointer& image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const DeformationFieldType::Pointer& image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const UCharVecImageType::Pointer& image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const CharImageType* image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const UCharImageType* image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const ShortImageType* image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const UShortImageType* image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const Int32ImageType* image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const UInt32ImageType* image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const FloatImageType* image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const DoubleImageType* image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const DeformationFieldType* image); template PLMBASE_API void Plm_image_header::set_from_itk_image (const UCharVecImageType* image); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_image_header.h000066400000000000000000000130211321604176500311410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_image_header_h_ #define _plm_image_header_h_ #include "plmbase_config.h" #include "direction_cosines.h" #include "itk_image.h" #include "itk_image_region.h" #include "itk_image_origin.h" #include "plm_image.h" class Bspline_xform; class Plm_image_header_private; class Volume; class Volume_header; /*! \brief * The Plm_image_header class defines the geometry of an image. * It defines image origin, spacing, dimensions, and direction cosines, * but does not contain image voxels. */ class PLMBASE_API Plm_image_header { public: Plm_image_header_private *d_ptr; private: OriginType m_origin; SpacingType m_spacing; RegionType m_region; DirectionType m_direction; public: Plm_image_header (); Plm_image_header (plm_long dim[3], float origin[3], float spacing[3]); Plm_image_header (plm_long dim[3], float origin[3], float spacing[3], float direction_cosines[9]); Plm_image_header (const RegionType& region, const OriginType& origin, const SpacingType& spacing, const DirectionType& direction); Plm_image_header (Plm_image *pli); Plm_image_header (const Plm_image& pli); Plm_image_header (const Plm_image::Pointer& pli); Plm_image_header (const Volume_header& vh); Plm_image_header (const Volume::Pointer& vol); Plm_image_header (const Volume& vol); Plm_image_header (const Volume* vol); Plm_image_header (Volume* vol); template Plm_image_header (T image); Plm_image_header (const Plm_image_header&); ~Plm_image_header (); public: const Plm_image_header& operator= (const Plm_image_header&); public: /* Getters and Setters */ int dim (int d) const; float origin (int d) const; float spacing (int d) const; void set_dim (const plm_long dim[3]); void set_origin (const float origin[3]); void set_spacing (const float spacing[3]); void set_direction_cosines ( const float direction_cosines[9]); void set_direction_cosines ( const Direction_cosines& dc); void set (const Plm_image_header& src); void set ( const plm_long dim[3], const float origin[3], const float spacing[3], const Direction_cosines& dc); void set ( const plm_long dim[3], const float origin[3], const float spacing[3], const float direction_cosines[9]); void set_from_gpuit ( const plm_long dim[3], const float origin[3], const float spacing[3], const float direction_cosines[9]); void set_from_gpuit_bspline (Bspline_xform *bxf); void set_from_plm_image (const Plm_image *pli); void set_from_plm_image (const Plm_image& pli); void set_from_plm_image (const Plm_image::Pointer& pli); void set_from_volume_header (const Volume_header& vh); void set (const Volume_header& vh); void set (const Volume::Pointer& vol); void set (const Volume& vol); void set (const Volume* vol); void set (const RegionType& region, const OriginType& origin, const SpacingType& spacing, const DirectionType& direction); template void set_from_itk_image (const T& image); template void set_from_itk_image (const T* image); const OriginType& GetOrigin () const; const SpacingType& GetSpacing () const; const RegionType& GetRegion () const; const DirectionType& GetDirection () const; const SizeType& GetSize (void) const; void get_volume_header (Volume_header *vh) const; void get_origin (float origin[3]) const; void get_spacing (float spacing[3]) const; void get_dim (plm_long dim[3]) const; void get_direction_cosines (float direction_cosines[9]) const; /* Algorithms */ static void clone (Plm_image_header *dest, const Plm_image_header *src); /*! \brief Expand existing geometry to contain the specified point. Only origin and dimensions can change, spacing and direction cosines will stay the same. */ void expand_to_contain (const FloatPoint3DType& position); /*! \brief Create a new geometry that can contain both the reference and compare image, with direction cosines and voxel spacing of the reference image */ void set_geometry_to_contain ( const Plm_image_header& reference_pih, const Plm_image_header& compare_pih); void print (void) const; /*! \brief Return true if the two headers are the same. Tolerance on origin and spacing can be specified using the threshold parameter */ static bool compare (Plm_image_header *pli1, Plm_image_header *pli2, float threshold = 1e-5); FloatPoint3DType get_index (const FloatPoint3DType& pos) const; FloatPoint3DType get_position (const float index[3]) const; void get_image_center (float center[3]) const; /*! \brief Get the number of voxels in the image */ plm_long get_num_voxels () const; /*! \brief Get the physical extent (size) of the image, from first voxel center to last voxel center. Extent is zero if only one voxel. */ void get_image_extent (float extent[3]) const; }; /* ----------------------------------------------------------------------- Global functions ----------------------------------------------------------------------- */ void direction_cosines_from_itk ( float direction_cosines[9], DirectionType* itk_direction ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_image_p.h000066400000000000000000000007271321604176500301610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_image_p_h_ #define _plm_image_p_h_ #include "plmbase_config.h" #include "volume.h" class Plm_image_private { public: Metadata::Pointer m_meta; Volume::Pointer m_vol; std::list m_vol_list; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_image_set.cxx000066400000000000000000000010151321604176500310570ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "plm_image.h" #include "plm_image_set.h" class Plm_image_set_private { public: std::list img_list; }; Plm_image_set::Plm_image_set () { d_ptr = new Plm_image_set_private; } Plm_image_set::~Plm_image_set () { delete d_ptr; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_image_set.h000066400000000000000000000015421321604176500305110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_image_set_h_ #define _plm_image_set_h_ #include "plmbase_config.h" #include "compiler_warnings.h" #include "itk_image.h" #include "metadata.h" #include "plm_image_type.h" #include "smart_pointer.h" #include "volume.h" class Plm_image_set_private; /*! \brief * The Plm_image_set class represents a set of * three-dimensional volumes. It is used for importing * DICOM or XiO volumes which are scanned at multiple slice spacings. */ class PLMBASE_API Plm_image_set { public: SMART_POINTER_SUPPORT (Plm_image_set); Plm_image_set_private *d_ptr; public: Plm_image_set (); ~Plm_image_set (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_image_type.cxx000066400000000000000000000111711321604176500312510ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include "plm_image_type.h" Plm_image_type plm_image_type_parse (const std::string& string) { return plm_image_type_parse (string.c_str()); } Plm_image_type plm_image_type_parse (const char* string) { if (!strcmp (string,"auto")) { return PLM_IMG_TYPE_UNDEFINED; } else if (!strcmp (string,"char")) { return PLM_IMG_TYPE_ITK_CHAR; } else if (!strcmp (string,"mask") || !strcmp (string,"uchar")) { return PLM_IMG_TYPE_ITK_UCHAR; } else if (!strcmp (string,"short")) { return PLM_IMG_TYPE_ITK_SHORT; } else if (!strcmp (string,"ushort")) { return PLM_IMG_TYPE_ITK_USHORT; } else if (!strcmp (string,"int") || !strcmp (string,"long") || !strcmp (string,"int32")) { return PLM_IMG_TYPE_ITK_LONG; } else if (!strcmp (string,"uint") || !strcmp (string,"ulong") || !strcmp (string,"uint32")) { return PLM_IMG_TYPE_ITK_ULONG; } else if (!strcmp (string,"float")) { return PLM_IMG_TYPE_ITK_FLOAT; } else if (!strcmp (string,"double")) { return PLM_IMG_TYPE_ITK_DOUBLE; } else if (!strcmp (string,"vf")) { return PLM_IMG_TYPE_ITK_FLOAT_FIELD; } else if (!strcmp (string,"ssimg")) { return PLM_IMG_TYPE_ITK_UCHAR_VEC; } else { return PLM_IMG_TYPE_UNDEFINED; } } char* plm_image_type_string (Plm_image_type type) { switch (type) { case PLM_IMG_TYPE_UNDEFINED: return "PLM_IMG_TYPE_UNDEFINED"; case PLM_IMG_TYPE_ITK_UCHAR: return "PLM_IMG_TYPE_ITK_UCHAR"; case PLM_IMG_TYPE_ITK_CHAR: return "PLM_IMG_TYPE_ITK_CHAR"; case PLM_IMG_TYPE_ITK_USHORT: return "PLM_IMG_TYPE_ITK_USHORT"; case PLM_IMG_TYPE_ITK_SHORT: return "PLM_IMG_TYPE_ITK_SHORT"; case PLM_IMG_TYPE_ITK_ULONG: return "PLM_IMG_TYPE_ITK_ULONG"; case PLM_IMG_TYPE_ITK_LONG: return "PLM_IMG_TYPE_ITK_LONG"; case PLM_IMG_TYPE_ITK_FLOAT: return "PLM_IMG_TYPE_ITK_FLOAT"; case PLM_IMG_TYPE_ITK_DOUBLE: return "PLM_IMG_TYPE_ITK_DOUBLE"; case PLM_IMG_TYPE_ITK_FLOAT_FIELD: return "PLM_IMG_TYPE_ITK_FLOAT_FIELD"; case PLM_IMG_TYPE_ITK_UCHAR_VEC: return "PLM_IMG_TYPE_ITK_UCHAR_VEC"; case PLM_IMG_TYPE_GPUIT_UCHAR: return "PLM_IMG_TYPE_GPUIT_UCHAR"; case PLM_IMG_TYPE_GPUIT_UINT16: return "PLM_IMG_TYPE_GPUIT_UINT16"; case PLM_IMG_TYPE_GPUIT_SHORT: return "PLM_IMG_TYPE_GPUIT_SHORT"; case PLM_IMG_TYPE_GPUIT_UINT32: return "PLM_IMG_TYPE_GPUIT_UINT32"; case PLM_IMG_TYPE_GPUIT_INT32: return "PLM_IMG_TYPE_GPUIT_INT32"; case PLM_IMG_TYPE_GPUIT_FLOAT: return "PLM_IMG_TYPE_GPUIT_FLOAT"; case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: return "PLM_IMG_TYPE_GPUIT_FLOAT_FIELD"; case PLM_IMG_TYPE_GPUIT_LIST: return "PLM_IMG_TYPE_GPUIT_LIST"; case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: return "PLM_IMG_TYPE_GPUIT_UCHAR_VEC"; default: return "(unknown image type)"; } } char* plm_image_type_string_simple (Plm_image_type type) { switch (type) { case PLM_IMG_TYPE_UNDEFINED: return "undefined"; case PLM_IMG_TYPE_ITK_UCHAR: return "unsigned char"; case PLM_IMG_TYPE_ITK_CHAR: return "char"; case PLM_IMG_TYPE_ITK_USHORT: return "unsigned short"; case PLM_IMG_TYPE_ITK_SHORT: return "short"; case PLM_IMG_TYPE_ITK_ULONG: return "unsigned long"; case PLM_IMG_TYPE_ITK_LONG: return "long"; case PLM_IMG_TYPE_ITK_FLOAT: return "float"; case PLM_IMG_TYPE_ITK_DOUBLE: return "double"; case PLM_IMG_TYPE_ITK_FLOAT_FIELD: return "float"; case PLM_IMG_TYPE_ITK_UCHAR_VEC: return "unsigned char"; case PLM_IMG_TYPE_GPUIT_UCHAR: return "unsigned char"; case PLM_IMG_TYPE_GPUIT_UINT16: return "unsigned short"; case PLM_IMG_TYPE_GPUIT_SHORT: return "short"; case PLM_IMG_TYPE_GPUIT_UINT32: return "unsigned long"; case PLM_IMG_TYPE_GPUIT_INT32: return "long"; case PLM_IMG_TYPE_GPUIT_FLOAT: return "float"; case PLM_IMG_TYPE_GPUIT_FLOAT_FIELD: return "float"; case PLM_IMG_TYPE_GPUIT_LIST: return "list (unknown)"; case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: return "unsigned char"; default: return "(unknown)"; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_image_type.h000066400000000000000000000024301321604176500306740ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_image_type_h_ #define _plm_image_type_h_ #include "plmbase_config.h" #include /* We only deal with these kinds of images. */ enum Plm_image_type { PLM_IMG_TYPE_UNDEFINED, PLM_IMG_TYPE_ITK_UCHAR, PLM_IMG_TYPE_ITK_CHAR, PLM_IMG_TYPE_ITK_USHORT, PLM_IMG_TYPE_ITK_SHORT, PLM_IMG_TYPE_ITK_ULONG, PLM_IMG_TYPE_ITK_LONG, PLM_IMG_TYPE_ITK_FLOAT, PLM_IMG_TYPE_ITK_DOUBLE, PLM_IMG_TYPE_ITK_FLOAT_FIELD, PLM_IMG_TYPE_ITK_UCHAR_VEC, PLM_IMG_TYPE_GPUIT_UCHAR, PLM_IMG_TYPE_GPUIT_UINT16, PLM_IMG_TYPE_GPUIT_SHORT, PLM_IMG_TYPE_GPUIT_UINT32, PLM_IMG_TYPE_GPUIT_INT32, PLM_IMG_TYPE_GPUIT_FLOAT, PLM_IMG_TYPE_GPUIT_FLOAT_FIELD, PLM_IMG_TYPE_GPUIT_LIST, PLM_IMG_TYPE_GPUIT_UCHAR_VEC }; PLMBASE_API Plm_image_type plm_image_type_parse (const std::string& string); PLMBASE_API Plm_image_type plm_image_type_parse (const char* string); PLMBASE_API char* plm_image_type_string (Plm_image_type type); PLMBASE_API char* plm_image_type_string_simple (Plm_image_type type); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_itk.h000066400000000000000000000006601321604176500273430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plm_itk_h_ #define __plm_itk_h_ /* ITK 3.20 is missing this */ #if defined __cplusplus #include #endif #if (ITK_FOUND && !PLM_CUDA_COMPILE) #include "itkConfigure.h" #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_uid_prefix.h000066400000000000000000000006331321604176500307120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_uid_prefix_h_ #define _plm_uid_prefix_h_ #define PLM_UID_PREFIX "1.2.826.0.1.3680043.8.274.1.1" #define MONDOSHOT_UID_PREFIX "1.2.826.0.1.3680043.8.274.1.1.200" #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_warp.cxx000066400000000000000000000241611321604176500301020ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include "bspline_warp.h" #include "bspline_xform.h" #include "itk_image_type.h" #include "itk_warp.h" #include "mha_io.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_warp.h" #include "print_and_exit.h" #include "volume.h" #include "xform.h" static void plm_warp_itk ( Plm_image::Pointer& im_warped, /* Output (optional) */ DeformationFieldType::Pointer *vf_out, /* Output (optional) */ const Xform::Pointer& xf_in, /* Input */ Plm_image_header *pih, /* Input */ const Plm_image::Pointer& im_in, /* Input */ float default_val, /* Input: Value for pixels without match */ int interp_lin /* Input: Trilinear (1) or nn (0) */ ) { Xform xform_tmp; DeformationFieldType::Pointer vf; /* Create an itk vector field from xf_in */ printf ("plm_warp_itk: xform_to_itk_vf\n"); xform_to_itk_vf (&xform_tmp, xf_in.get(), pih); vf = xform_tmp.get_itk_vf (); /* If caller wants the vf, we assign it here */ if (vf_out) { *vf_out = vf; } /* If caller only wants the vf, we are done */ if (!im_warped) { return; } /* Convert GPUIT images to ITK */ printf ("plm_warp_itk: convert_to_itk\n"); im_in->convert_to_itk (); /* Warp the image */ printf ("plm_warp_itk: warping...\n"); switch (im_in->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: im_warped->m_itk_uchar = itk_warp_image ( im_in->m_itk_uchar, vf, interp_lin, static_cast(default_val)); im_warped->m_original_type = PLM_IMG_TYPE_ITK_UCHAR; im_warped->m_type = PLM_IMG_TYPE_ITK_UCHAR; break; case PLM_IMG_TYPE_ITK_SHORT: im_warped->m_itk_short = itk_warp_image ( im_in->m_itk_short, vf, interp_lin, static_cast(default_val)); im_warped->m_original_type = PLM_IMG_TYPE_ITK_SHORT; im_warped->m_type = PLM_IMG_TYPE_ITK_SHORT; break; case PLM_IMG_TYPE_ITK_USHORT: im_warped->m_itk_ushort = itk_warp_image ( im_in->m_itk_ushort, vf, interp_lin, static_cast(default_val)); im_warped->m_original_type = PLM_IMG_TYPE_ITK_USHORT; im_warped->m_type = PLM_IMG_TYPE_ITK_USHORT; break; case PLM_IMG_TYPE_ITK_ULONG: im_warped->m_itk_uint32 = itk_warp_image ( im_in->m_itk_uint32, vf, interp_lin, static_cast(default_val)); im_warped->m_original_type = PLM_IMG_TYPE_ITK_ULONG; im_warped->m_type = PLM_IMG_TYPE_ITK_ULONG; break; case PLM_IMG_TYPE_ITK_FLOAT: im_warped->m_itk_float = itk_warp_image ( im_in->m_itk_float, vf, interp_lin, static_cast(default_val)); im_warped->m_original_type = PLM_IMG_TYPE_ITK_FLOAT; im_warped->m_type = PLM_IMG_TYPE_ITK_FLOAT; break; case PLM_IMG_TYPE_ITK_DOUBLE: im_warped->m_itk_double = itk_warp_image ( im_in->m_itk_double, vf, interp_lin, static_cast(default_val)); im_warped->m_original_type = PLM_IMG_TYPE_ITK_DOUBLE; im_warped->m_type = PLM_IMG_TYPE_ITK_DOUBLE; break; case PLM_IMG_TYPE_ITK_UCHAR_VEC: im_warped->m_itk_uchar_vec = itk_warp_image ( im_in->m_itk_uchar_vec, vf, interp_lin, static_cast (default_val)); im_warped->m_original_type = PLM_IMG_TYPE_ITK_UCHAR_VEC; im_warped->m_type = PLM_IMG_TYPE_ITK_UCHAR_VEC; break; case PLM_IMG_TYPE_ITK_CHAR: case PLM_IMG_TYPE_ITK_LONG: default: print_and_exit ("Unhandled case in plm_warp_itk (%s)\n", plm_image_type_string (im_in->m_type)); break; } } /* Native warping (only gpuit bspline + float) */ static void plm_warp_native ( Plm_image::Pointer& im_warped, /* Output */ DeformationFieldType::Pointer *vf, /* Output */ const Xform::Pointer& xf_in, /* Input */ Plm_image_header *pih, /* Input */ const Plm_image::Pointer& im_in, /* Input */ float default_val, /* Input: Value for pixels without match */ int interp_lin /* Input: Trilinear (1) or nn (0) */ ) { Xform xf_tmp; Xform vf_tmp; Bspline_xform* bxf_in = xf_in->get_gpuit_bsp (); Volume *vf_out = 0; /* Output vector field */ Volume *v_out = 0; /* Output warped image */ plm_long dim[3]; float origin[3]; float spacing[3]; float direction_cosines[9]; /* Convert input image to gpuit format */ printf ("Running: plm_warp_native\n"); printf ("Converting input image...\n"); Volume::Pointer v_in = im_in->get_volume_float (); /* Transform input xform to gpuit bspline with correct voxel spacing */ printf ("Converting xform...\n"); xform_to_gpuit_bsp (&xf_tmp, xf_in.get(), pih, bxf_in->grid_spac); /* Create output vf */ pih->get_origin (origin); pih->get_spacing (spacing); pih->get_dim (dim); pih->get_direction_cosines (direction_cosines); if (vf) { printf ("Creating output vf...\n"); vf_out = new Volume (dim, origin, spacing, direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); } /* Create output image */ printf ("Creating output volume...\n"); v_out = new Volume (dim, origin, spacing, direction_cosines, PT_FLOAT, 1); /* Warp using gpuit native warper */ printf ("Running native warper...\n"); bspline_warp (v_out, vf_out, xf_tmp.get_gpuit_bsp(), v_in, interp_lin, default_val); /* Return output image to caller */ if (im_warped) { im_warped->set_volume (v_out); /* Bspline_warp only operates on float. We need to back-convert */ printf ("Back convert to original type...\n"); im_warped->convert (im_in->m_original_type); im_warped->m_original_type = im_in->m_original_type; } else { delete v_out; } /* Return vf to caller */ if (vf) { printf ("> Convert vf to itk\n"); *vf = xform_gpuit_vf_to_itk_vf (vf_out, 0); printf ("> Conversion complete.\n"); delete vf_out; } printf ("plm_warp_native is complete.\n"); } /* Native vector warping (only gpuit bspline + uchar_vec) */ static void plm_warp_native_vec ( Plm_image::Pointer& im_warped, /* Output */ DeformationFieldType::Pointer *vf, /* Output */ const Xform::Pointer& xf_in, /* Input */ Plm_image_header *pih, /* Input */ const Plm_image::Pointer& im_in, /* Input */ float default_val, /* Input: Value for pixels without match */ int interp_lin /* Input: Trilinear (1) or nn (0) */ ) { Xform xf_tmp; Xform vf_tmp; Bspline_xform* bxf_in = xf_in->get_gpuit_bsp (); Volume *vf_out = 0; /* Output vector field */ Volume *v_out = 0; /* Output warped image */ plm_long dim[3]; float origin[3]; float spacing[3]; float direction_cosines[9]; /* Convert input image to gpuit format */ printf ("Running: plm_warp_native_vec\n"); printf ("Converting input image...\n"); Volume::Pointer v_in = im_in->get_volume_uchar_vec (); /* Transform input xform to gpuit bspline with correct voxel spacing */ printf ("Converting xform...\n"); xform_to_gpuit_bsp (&xf_tmp, xf_in.get(), pih, bxf_in->grid_spac); /* Create output vf */ pih->get_origin (origin); pih->get_spacing (spacing); pih->get_dim (dim); pih->get_direction_cosines (direction_cosines); if (vf) { printf ("Creating output vf...\n"); vf_out = new Volume (dim, origin, spacing, direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); } /* Create output image */ printf ("Creating output volume (%d planes)...\n", v_in->vox_planes); v_out = new Volume (dim, origin, spacing, direction_cosines, PT_UCHAR_VEC_INTERLEAVED, v_in->vox_planes); /* Warp using gpuit native warper */ printf ("Running native warper...\n"); bspline_warp (v_out, vf_out, xf_tmp.get_gpuit_bsp(), v_in, interp_lin, default_val); /* Return output image to caller */ if (im_warped) { im_warped->set_volume (v_out); /* Bspline_warp only operates on float. We need to back-convert */ printf ("Back convert to original type...\n"); im_warped->convert (im_in->m_original_type); im_warped->m_original_type = im_in->m_original_type; } else { delete v_out; } /* Return vf to caller */ if (vf) { printf ("> Convert vf to itk\n"); *vf = xform_gpuit_vf_to_itk_vf (vf_out, 0); printf ("> Conversion complete.\n"); delete vf_out; } printf ("plm_warp_native is complete.\n"); } void plm_warp ( Plm_image::Pointer& im_warped, /* Output: Output image (optional) */ DeformationFieldType::Pointer* vf, /* Output: Output vf (optional) */ const Xform::Pointer& xf_in, /* Input: Input image warped by this xform */ Plm_image_header *pih, /* Input: Size of output image */ const Plm_image::Pointer& im_in, /* Input: Input image */ float default_val, /* Input: Value for pixels without match */ int use_itk, /* Input: Force use of itk (1) or not (0) */ int interp_lin /* Input: Trilinear (1) or nn (0) */ ) { /* If user requested ITK-based warping, respect their wish */ if (use_itk) { plm_warp_itk (im_warped, vf, xf_in, pih, im_in, default_val, interp_lin); return; } /* Otherwise, try to do native warping where possible */ if (xf_in->m_type == XFORM_GPUIT_BSPLINE) { switch (im_in->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: case PLM_IMG_TYPE_ITK_SHORT: case PLM_IMG_TYPE_ITK_ULONG: case PLM_IMG_TYPE_ITK_FLOAT: case PLM_IMG_TYPE_GPUIT_UCHAR: case PLM_IMG_TYPE_GPUIT_SHORT: case PLM_IMG_TYPE_GPUIT_UINT32: case PLM_IMG_TYPE_GPUIT_FLOAT: plm_warp_native (im_warped, vf, xf_in, pih, im_in, default_val, interp_lin); break; case PLM_IMG_TYPE_ITK_UCHAR_VEC: case PLM_IMG_TYPE_GPUIT_UCHAR_VEC: plm_warp_native_vec (im_warped, vf, xf_in, pih, im_in, default_val, interp_lin); break; default: plm_warp_itk (im_warped, vf, xf_in, pih, im_in, default_val, interp_lin); break; } } else { plm_warp_itk (im_warped, vf, xf_in, pih, im_in, default_val, interp_lin); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plm_warp.h000066400000000000000000000022141321604176500275220ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_warp_h_ #define _plm_warp_h_ #include "plmbase_config.h" #include "itkBSplineDeformableTransform.h" #include "xform.h" class Plm_image; /* ----------------------------------------------------------------------- Public functions ----------------------------------------------------------------------- */ PLMBASE_API void plm_warp ( Plm_image::Pointer& im_warped, /* Output: Output image (optional) */ DeformationFieldType::Pointer *vf, /* Output: Output vf (optional) */ const Xform::Pointer& xf_in, /* Input: Input image warped by this xform */ Plm_image_header *pih, /* Input: Size of output image */ const Plm_image::Pointer& im_in, /* Input: Input image */ float default_val, /* Input: Value for pixels without match */ int use_itk, /* Input: Force use of itk (1) or not (0) */ int interp_lin /* Input: Trilinear (1) or nn (0) */ ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/plmbase_config.h.in000066400000000000000000000013011321604176500312520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plmbase_config_h__ #define __plmbase_config_h__ #include "plm_config.h" #if ((defined(_WIN32) || defined(WIN32)) && (defined (PLM_BUILD_SHARED_LIBS))) # ifdef plmbase_EXPORTS # define PLMBASE_C_API EXTERNC __declspec(dllexport) # define PLMBASE_API __declspec(dllexport) # else # define PLMBASE_C_API EXTERNC __declspec(dllimport) # define PLMBASE_API __declspec(dllimport) # endif #else # define PLMBASE_C_API EXTERNC # define PLMBASE_API #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/pointset.cxx000066400000000000000000000143031321604176500301230ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include "file_util.h" #include "logfile.h" #include "path_util.h" #include "plm_math.h" #include "pointset.h" #include "print_and_exit.h" #include "string_util.h" template Pointset::Pointset () { } template Pointset::~Pointset () { } template void Pointset::load (const char *fn) { if (extension_is (fn, ".fcsv")) { this->load_fcsv (fn); } else { this->load_txt (fn); } } template void Pointset::load_fcsv (const char *fn) { FILE *fp; fp = fopen (fn, "r"); if (!fp) { print_and_exit ("Error loading file for read: %s\n", fn); } /* Got an fcsv file. Parse it. */ while (!feof(fp)) { float lm[3]; int rc; char s[1024]; fgets (s, 1024, fp); if (feof(fp)) break; if (s[0]=='#') continue; char buf[1024]; rc = sscanf (s, "%1023[^,],%f,%f,%f", buf, &lm[0], &lm[1], &lm[2]); if (rc < 4) { /* Error parsing file */ lprintf ("Error parsing fcsv file: %s\n", fn); point_list.clear(); return; } /* Note: Plastimatch landmarks are in LPS coordinates. Slicer landmarks are in RAS coordinates. Change RAS to LPS (note that LPS == ITK RAI). */ T lp; lp.set_label (buf); lp.p[0] = - lm[0]; lp.p[1] = - lm[1]; lp.p[2] = lm[2]; point_list.push_back (lp); } fclose (fp); } template void Pointset::load_txt (const char *fn) { FILE *fp; char s[1024]; fp = fopen (fn, "r"); if (!fp) { return; } /* Parse as txt file */ while (!feof(fp)) { float lm[3]; int rc; fgets (s, 1024, fp); if (feof(fp)) break; if (s[0]=='#') continue; rc = sscanf (s, "%f , %f , %f\n", &lm[0], &lm[1], &lm[2]); if (rc != 3) { rc = sscanf (s, "%f %f %f\n", &lm[0], &lm[1], &lm[2]); } if (rc != 3) { print_and_exit ("Error parsing landmark file: %s\n", fn); } /* Assume LPS */ T lp; lp.set_label (""); lp.p[0] = lm[0]; lp.p[1] = lm[1]; lp.p[2] = lm[2]; point_list.push_back (lp); } fclose (fp); } template void Pointset::insert_ras (const std::string& p) { size_t loc = 0; while (1) { int rc; float f1, f2, f3; rc = sscanf (p.c_str() + loc, "%f,%f,%f", &f1, &f2, &f3); if (rc != 3) { break; } this->insert_ras ("", f1, f2, f3); loc = p.find (';', loc); if (loc == std::string::npos) { break; } loc ++; /* Skip semicolon */ } } template void Pointset::insert_ras ( const std::string& label, float x, float y, float z ) { /* RAS to LPS adjustment */ this->point_list.push_back (T (label, -x, -y, z)); } template void Pointset::insert_ras ( const float *xyz ) { /* RAS to LPS adjustment */ this->point_list.push_back (T ("", -xyz[0], -xyz[1], xyz[2])); } template void Pointset::insert_lps ( const std::string& label, float x, float y, float z ) { /* No RAS to LPS adjustment */ this->point_list.push_back (T (label, x, y, z)); } template void Pointset::insert_lps ( const std::string& label, const float *xyz ) { /* No RAS to LPS adjustment */ this->point_list.push_back (T (label, xyz[0], xyz[1], xyz[2])); } template void Pointset::insert_lps ( const float *xyz ) { /* No RAS to LPS adjustment */ this->point_list.push_back (T ("", xyz[0], xyz[1], xyz[2])); } template void Pointset::save (const char *fn) { if (extension_is (fn, ".fcsv")) { this->save_fcsv (fn); } else { this->save_txt (fn); } } template void Pointset::save_fcsv (const char *fn) { FILE *fp; printf ("Trying to save: %s\n", (const char*) fn); make_parent_directories (fn); fp = fopen (fn, "w"); if (!fp) return; fprintf (fp, "# Fiducial List file %s\n" "# version = 2\n" "# name = plastimatch-fiducials\n" "# numPoints = %d\n" "# symbolScale = 5\n" "# symbolType = 12\n" "# visibility = 1\n" "# textScale = 4.5\n" "# color = 0.4,1,1\n" "# selectedColor = 1,0.5,0.5\n" "# opacity = 1\n" "# ambient = 0\n" "# diffuse = 1\n" "# specular = 0\n" "# power = 1\n" "# locked = 0\n" "# numberingScheme = 0\n" "# columns = label,x,y,z,sel,vis\n", fn, (int) this->point_list.size()); for (unsigned int i = 0; i < this->point_list.size(); i++) { const T& lp = this->point_list[i]; if (lp.get_label() == "") { fprintf (fp, "p-%03d", i); } else { fprintf (fp, "%s", lp.get_label().c_str()); } /* Note: Plastimatch landmarks are in LPS coordinates. Slicer landmarks are in RAS coordinates. Change LPS to RAS (note that LPS == ITK RAI). */ fprintf (fp, ",%f,%f,%f,1,1\n", - lp.p[0], - lp.p[1], lp.p[2]); } fclose (fp); } template void Pointset::save_fcsv (const std::string& fn) { this->save_fcsv (fn.c_str()); } template void Pointset::save_txt (const char *fn) { FILE *fp; printf ("Trying to save: %s\n", (const char*) fn); make_parent_directories (fn); fp = fopen (fn, "w"); if (!fp) return; for (unsigned int i = 0; i < this->point_list.size(); i++) { const T& lp = this->point_list[i]; fprintf (fp, "%f %f %f\n", lp.p[0], lp.p[1], lp.p[2]); } fclose (fp); } template size_t Pointset::get_count (void) const { return (size_t) this->point_list.size(); } template void Pointset::truncate (size_t new_length) { this->point_list.resize (new_length); } template void Pointset::debug () const { printf ("Pointset:\n"); for (size_t i = 0; i < this->get_count(); i++) { const T& point = this->point(i); printf (" %20s %10f %10f %10f\n", point.get_label().c_str(), point.p[0], point.p[1], point.p[2]); } } template class PLMBASE_API Pointset; template class PLMBASE_API Pointset; plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/pointset.h000066400000000000000000000052741321604176500275570ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pointset_h_ #define _pointset_h_ #include "plmbase_config.h" #include #include #include "compiler_warnings.h" class Pstring; class PLMBASE_API Point { public: Point () {} Point (const std::string& label, float x, float y, float z) { UNUSED_VARIABLE (label); p[0] = x; p[1] = y; p[2] = z; } Point (float x, float y, float z) { p[0] = x; p[1] = y; p[2] = z; } public: float p[3]; public: void set_label (const char* s) { UNUSED_VARIABLE (s); } std::string get_label (void) const { return ""; } }; class PLMBASE_API Labeled_point { public: Labeled_point () {} Labeled_point (const std::string& label, float x, float y, float z) { this->label = label; p[0] = x; p[1] = y; p[2] = z; } public: std::string label; float p[3]; public: void set_label (const char* s) { this->label = s; } const std::string& get_label (void) const { return this->label; } }; template class PLMBASE_API Pointset { public: Pointset(); ~Pointset(); public: std::vector point_list; public: void load (const char *fn); void load_txt (const char *fn); void load_fcsv (const char *fn); void save (const char *fn); void save_fcsv (const char *fn); void save_fcsv (const std::string& fn); void save_txt (const char *fn); /* Insert a list of points of the form "x,y,z;x,y,z;..." */ void insert_ras (const std::string& p); /* Insert single points */ void insert_lps (const std::string& label, float x, float y, float z); void insert_lps (const float* xyz); void insert_lps (const std::string& label, const float* xyz); void insert_ras (const std::string& label, float x, float y, float z); void insert_ras (const float* xyz); /* Return reference to a point */ const T& point (int idx) const { return point_list[idx]; } /* Return coordinate of point */ float point (int idx, int dim) const { return point_list[idx].p[dim]; } /* Return the number of points */ size_t get_count (void) const; /* Truncate points at the end of the list */ void truncate (size_t new_length); void debug () const; private: Pointset (const Pointset&); Pointset& operator= (const Pointset&); }; typedef Pointset Labeled_pointset; typedef Pointset Unlabeled_pointset; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/pointset_warp.cxx000066400000000000000000000115331321604176500311560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "itkContinuousIndex.h" #include "itkImageRegionIterator.h" #include "itkVectorLinearInterpolateImageFunction.h" #include "itk_image.h" #include "itk_image_type.h" #include "pointset_warp.h" void pointset_warp ( Labeled_pointset *warped_pointset, Labeled_pointset *input_pointset, DeformationFieldType::Pointer vf) { float *dist_array = new float[input_pointset->get_count()]; for (size_t i = 0; i < input_pointset->get_count(); i++) { /* Clone pointset (to set labels) */ warped_pointset->insert_lps ( input_pointset->point_list[i].get_label(), input_pointset->point_list[i].p[0], input_pointset->point_list[i].p[1], input_pointset->point_list[i].p[2]); /* Initialize distance array */ dist_array[i] = FLT_MAX; } /* Loop through vector field */ typedef itk::ImageRegionIterator< DeformationFieldType > FieldIterator; FieldIterator fi (vf, vf->GetLargestPossibleRegion()); for (fi.GoToBegin(); !fi.IsAtEnd(); ++fi) { /* Compute location of correspondence in moving image */ DeformationFieldType::IndexType idx = fi.GetIndex (); FloatPoint3DType fixed_location; FloatPoint3DType moving_location; vf->TransformIndexToPhysicalPoint (idx, fixed_location); const FloatVector3DType& dxyz = fi.Get(); moving_location[0] = fixed_location[0] + dxyz[0]; moving_location[1] = fixed_location[1] + dxyz[1]; moving_location[2] = fixed_location[2] + dxyz[2]; /* Loop through landmarks */ for (size_t i = 0; i < input_pointset->get_count(); i++) { /* Get distance from correspondence to landmark */ float dv[3] = { moving_location[0] - input_pointset->point_list[i].p[0], moving_location[1] - input_pointset->point_list[i].p[1], moving_location[2] - input_pointset->point_list[i].p[2] }; float dist = dv[0] * dv[0] + dv[1] * dv[1] + dv[2] * dv[2]; /* Update correspondence if current voxel is closest so far */ if (dist < dist_array[i]) { dist_array[i] = dist; warped_pointset->point_list[i].p[0] = fixed_location[0]; warped_pointset->point_list[i].p[1] = fixed_location[1]; warped_pointset->point_list[i].p[2] = fixed_location[2]; } } } /* Loop through landmarks, refining estimate */ typedef itk::VectorLinearInterpolateImageFunction< DeformationFieldType, float > InterpolatorType; InterpolatorType::Pointer interpolator = InterpolatorType::New (); interpolator->SetInputImage (vf); for (size_t i = 0; i < input_pointset->get_count(); i++) { for (int its = 0; its < 10; its++) { float dv[3]; /* Get current estimate of warped point */ FloatPoint3DType fixed_location; fixed_location[0] = warped_pointset->point_list[i].p[0]; fixed_location[1] = warped_pointset->point_list[i].p[1]; fixed_location[2] = warped_pointset->point_list[i].p[2]; /* Get deformation at current estimate */ itk::ContinuousIndex ci; vf->TransformPhysicalPointToContinuousIndex (fixed_location, ci); FloatVector3DType dxyz = interpolator->EvaluateAtContinuousIndex (ci); /* Get moving image location */ FloatPoint3DType moving_location; moving_location[0] = fixed_location[0] + dxyz[0]; moving_location[1] = fixed_location[1] + dxyz[1]; moving_location[2] = fixed_location[2] + dxyz[2]; /* Get distance from correspondence to landmark */ dv[0] = input_pointset->point_list[i].p[0] - moving_location[0]; dv[1] = input_pointset->point_list[i].p[1] - moving_location[1]; dv[2] = input_pointset->point_list[i].p[2] - moving_location[2]; //float dist_1 = dv[0] * dv[0] + dv[1] * dv[1] + dv[2] * dv[2]; /* Compute update */ float lambda = 0.5; fixed_location[0] += lambda * dv[0]; fixed_location[1] += lambda * dv[1]; fixed_location[2] += lambda * dv[2]; /* GCS TODO: check if the update improves the estimate */ /* Make update */ warped_pointset->point_list[i].p[0] = fixed_location[0]; warped_pointset->point_list[i].p[1] = fixed_location[1]; warped_pointset->point_list[i].p[2] = fixed_location[2]; } } delete[] dist_array; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/pointset_warp.h000066400000000000000000000010051321604176500305740ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pointset_warp_h_ #define _pointset_warp_h_ #include "plmbase_config.h" #include "pointset.h" #include "itk_image_type.h" PLMBASE_API void pointset_warp ( Labeled_pointset *warped_pointset, Labeled_pointset *input_pointset, DeformationFieldType::Pointer vf); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/proj_image.cxx000066400000000000000000000264331321604176500304010ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "file_util.h" #include "hnd_io.h" #include "path_util.h" #include "plm_math.h" #include "proj_image.h" #include "proj_matrix.h" Proj_image::Proj_image () { this->init (); } Proj_image::Proj_image ( const char* img_filename, const double xy_offset[2] ) { this->init (); this->xy_offset[0] = xy_offset[0]; this->xy_offset[1] = xy_offset[1]; this->load (img_filename); } Proj_image::Proj_image ( const char* img_filename, const char* mat_filename ) { this->init (); this->load (img_filename, mat_filename); } Proj_image::Proj_image ( const std::string& img_filename, const std::string& mat_filename ) { this->init (); this->load (img_filename, mat_filename); } Proj_image::~Proj_image () { this->clear (); } void Proj_image::init () { dim[0] = dim[1] = 0; xy_offset[0] = xy_offset[1] = 0; pmat = 0; img = 0; } void Proj_image::clear () { if (this->pmat) { delete pmat; this->pmat = 0; } if (this->img) { free (this->img); this->img = 0; } } bool Proj_image::have_image () { return (this->img != 0); } /* ----------------------------------------------------------------------- Private functions ----------------------------------------------------------------------- */ static void raw_load (Proj_image *proj, const char* img_filename) { FILE* fp; size_t rc; uint64_t fs; if (!proj) return; /* Open file */ fp = fopen (img_filename,"rb"); if (!fp) { fprintf (stderr, "Can't open file %s for read\n", img_filename); exit (-1); } /* Malloc memory */ fs = file_size (img_filename); proj->img = (float*) malloc (fs); if (!proj->img) { fprintf (stderr, "Couldn't malloc memory for input image\n"); exit (-1); } /* Guess image size */ switch (fs) { case (512*384*sizeof(float)): proj->dim[0] = 512; proj->dim[1] = 384; break; case (1024*384*sizeof(float)): proj->dim[0] = 1024; proj->dim[1] = 384; break; case (1024*768*sizeof(float)): proj->dim[0] = 1024; proj->dim[1] = 768; break; case (2048*1536*sizeof(float)): proj->dim[0] = 2048; proj->dim[1] = 1536; break; default: proj->dim[0] = 1024; proj->dim[1] = fs / (1024 * sizeof(float)); break; } /* Load pixels */ rc = fread (proj->img, sizeof(float), proj->dim[0] * proj->dim[1], fp); if (rc != (size_t) (proj->dim[0] * proj->dim[1])) { fprintf (stderr, "Couldn't load raster data for %s\n", img_filename); exit (-1); } fclose (fp); } static void raw_save (Proj_image *proj, const char* img_filename) { FILE* fp; fp = plm_fopen (img_filename, "wb"); if (!fp) { fprintf (stderr, "Can't open file %s for write\n", img_filename); exit (-1); } fwrite (proj->img, sizeof(float), proj->dim[0]*proj->dim[1], fp); fclose (fp); } static void pfm_load (Proj_image *proj, const char* img_filename) { FILE* fp; char buf[1024]; size_t rc; if (!proj) return; fp = fopen (img_filename,"rb"); if (!fp) { fprintf (stderr, "Can't open file %s for read\n", img_filename); exit (-1); } /* Verify that it is pfm */ fgets (buf, 1024, fp); if (strncmp(buf, "Pf", 2)) { fprintf (stderr, "Couldn't parse file %s as an image [1]\n", img_filename); exit (-1); } /* Get image resolution */ fgets (buf, 1024, fp); if (2 != sscanf (buf, "%d %d", &proj->dim[0], &proj->dim[1])) { fprintf (stderr, "Couldn't parse file %s as an image [2]\n", img_filename); exit (-1); } /* Skip third line */ fgets (buf, 1024, fp); /* Malloc memory */ proj->img = (float*) malloc (sizeof(float) * proj->dim[0] * proj->dim[1]); if (!proj->img) { fprintf (stderr, "Couldn't malloc memory for input image\n"); exit (-1); } /* Load pixels */ rc = fread (proj->img, sizeof(float), proj->dim[0] * proj->dim[1], fp); if (rc != (size_t) (proj->dim[0] * proj->dim[1])) { fprintf (stderr, "Couldn't load raster data for %s\n", img_filename); exit (-1); } fclose (fp); } static void pfm_save (Proj_image *proj, const char* img_filename) { FILE* fp; make_parent_directories (img_filename); fp = plm_fopen (img_filename, "wb"); if (!fp) { fprintf (stderr, "Can't open file %s for write\n", img_filename); exit (-1); } fprintf (fp, "Pf\n" "%d %d\n" "-1\n", proj->dim[0], proj->dim[1]); fwrite (proj->img, sizeof(float), proj->dim[0]*proj->dim[1], fp); fclose (fp); } static void pgm_save (Proj_image *proj, const char* img_filename) { FILE* fp; int i; make_parent_directories (img_filename); fp = plm_fopen (img_filename, "wb"); if (!fp) { fprintf (stderr, "Can't open file %s for write\n", img_filename); exit (-1); } fprintf (fp, "P2\n" "# Created by plastimatch\n" "%d %d\n" "65535\n", proj->dim[0], proj->dim[1] ); for (i = 0; i < proj->dim[0]*proj->dim[1]; i++) { float v = proj->img[i]; if (v >= 65535) { v = 65535; } else if (v < 0) { v = 0; } fprintf (fp,"%lu ", ROUND_INT(v)); if (i % 25 == 24) { fprintf (fp,"\n"); } } fclose (fp); } static void mat_load (Proj_image *proj, const char* mat_filename) { FILE* fp; int i; float f; Proj_matrix *pmat; if (!proj) return; /* Allocate memory */ pmat = new Proj_matrix; /* Open file */ fp = fopen (mat_filename,"r"); if (!fp) { fprintf (stderr, "Can't open file %s for read\n", mat_filename); exit (-1); } /* Load image center */ for (i = 0; i < 2; i++) { if (1 != fscanf (fp, "%g", &f)) { fprintf (stderr, "Couldn't parse file %s as a matrix [1,%d]\n", mat_filename, i); exit (-1); } pmat->ic[i] = (double) f; } /* Load projection matrix */ for (i = 0; i < 12; i++) { if (1 != fscanf (fp, "%g", &f)) { fprintf (stderr, "Couldn't parse file %s as a matrix [2,%d]\n", mat_filename, i); exit (-1); } pmat->matrix[i] = (double) f; } /* Load sad */ if (1 != fscanf (fp, "%g", &f)) { fprintf (stderr, "Couldn't load sad from %s\n", mat_filename); exit (-1); } pmat->sad = (double) f; /* Load sid */ if (1 != fscanf (fp, "%g", &f)) { fprintf (stderr, "Couldn't load sad from %s\n", mat_filename); exit (-1); } pmat->sid = (double) f; /* Load nrm vector */ for (i = 0; i < 3; i++) { if (1 != fscanf (fp, "%g", &f)) { fprintf (stderr, "Couldn't parse file %s as a matrix [1,%d]\n", mat_filename, i); exit (-1); } pmat->nrm[i] = (double) f; } fclose (fp); proj->pmat = pmat; } static void mat_load_by_img_filename (Proj_image* proj, const char* img_filename) { /* No mat file, so try to find automatically */ size_t img_filename_len = strlen (img_filename); if (img_filename_len > 4) { char *mat_fn = strdup (img_filename); strcpy (&mat_fn[img_filename_len-4], ".txt"); if (file_exists (mat_fn)) { mat_load (proj, mat_fn); } free (mat_fn); } } void Proj_image::load_pfm (const char* img_filename, const char* mat_filename) { if (!img_filename) return; pfm_load (this, img_filename); if (mat_filename) { mat_load (this, mat_filename); } else { mat_load_by_img_filename (this, img_filename); } } void Proj_image::load_raw (const char* img_filename, const char* mat_filename) { if (!img_filename) return; raw_load (this, img_filename); if (mat_filename) { mat_load (this, mat_filename); } else { mat_load_by_img_filename (this, img_filename); } } void Proj_image::load_hnd (const char* img_filename) { if (!img_filename) return; hnd_load (this, img_filename, this->xy_offset); if (this->img == 0) { this->clear (); } } /* ----------------------------------------------------------------------- Public functions ----------------------------------------------------------------------- */ void proj_image_create_pmat (Proj_image *proj) { /* Allocate memory */ proj->pmat = new Proj_matrix; } void proj_image_create_img (Proj_image *proj, int dim[2]) { proj->dim[0] = dim[0]; proj->dim[1] = dim[1]; proj->img = (float*) malloc (sizeof(float) * proj->dim[0] * proj->dim[1]); } void Proj_image::debug_header () { int i; printf ("Image center: %g %g\n", this->pmat->ic[0], this->pmat->ic[1]); printf ("Projection matrix: "); for (i = 0; i < 12; i++) { printf ("%g ", this->pmat->matrix[i]); } printf ("\n"); } void Proj_image::stats () { int i, num; float min_val, max_val; double sum = 0.0; if (!this) { printf ("No image.\n"); return; } num = this->dim[0]*this->dim[1]; if (!this->img || num == 0) { printf ("No image.\n"); return; } min_val = max_val = this->img[0]; for (i = 0; i < num; i++) { float v = this->img[i]; if (min_val > v) min_val = v; if (max_val < v) max_val = v; sum += v; } printf ("MIN %f AVE %f MAX %f NUM %d\n", min_val, (float) (sum / num), max_val, num); } void Proj_image::load ( const std::string& img_filename, std::string mat_filename ) { /* If not specified, try to guess the mat_filename */ if (mat_filename == "") { std::string tmp = img_filename; tmp = strip_extension (tmp) + ".txt"; if (file_exists (tmp)) { mat_filename = tmp; } } if (extension_is (img_filename, ".pfm")) { load_pfm (img_filename.c_str(), mat_filename.c_str()); } else if (extension_is (img_filename, ".raw")) { load_raw (img_filename.c_str(), mat_filename.c_str()); } else if (extension_is (img_filename, ".hnd")) { load_hnd (img_filename.c_str()); } } void Proj_image::save ( const char *img_filename, const char *mat_filename ) { if (img_filename) { if (extension_is (img_filename, ".pfm")) { pfm_save (this, img_filename); } else if (extension_is (img_filename, ".raw")) { raw_save (this, img_filename); } else if (extension_is (img_filename, ".pgm")) { pgm_save (this, img_filename); } #if defined (commentout) else if (extension_is (img_filename, "mha.")) { mha_save (this, img_filename); } #endif } if (mat_filename) { this->pmat->save (mat_filename); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/proj_image.h000066400000000000000000000030411321604176500300140ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _proj_image_h_ #define _proj_image_h_ #include "plmbase_config.h" #include class Proj_image; class Proj_matrix; class PLMBASE_API Proj_image { public: Proj_image (void); Proj_image (const char* img_filename, const char* mat_filename); Proj_image (const std::string& img_filename, const std::string& mat_filename = ""); Proj_image (const char* img_filename, const double xy_offset[2]); ~Proj_image (void); public: int dim[2]; /* dim[0] = cols, dim[1] = rows */ double xy_offset[2]; /* Offset of center pixel */ Proj_matrix *pmat; /* Geometry of panel and source */ float* img; /* Pixel data */ public: void clear (); bool have_image (); void init (); void save (const char *img_filename, const char *mat_filename); void load (const std::string& img_filename, std::string mat_filename = ""); void load_pfm (const char* img_filename, const char* mat_filename); void load_raw (const char* img_filename, const char* mat_filename); void load_hnd (const char* img_filename); void set_xy_offset (const double xy_offset[2]); void debug_header (); void stats (); }; PLMBASE_C_API void proj_image_create_pmat (Proj_image *proj); PLMBASE_C_API void proj_image_create_img (Proj_image *proj, int dim[2]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/proj_image_dir.cxx000066400000000000000000000131311321604176500312260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "dir_list.h" #include "file_util.h" #include "path_util.h" #include "proj_image.h" #include "proj_image_dir.h" #include "string_util.h" Proj_image_dir::Proj_image_dir (const char *dir) { std::string xml_file; /* Initialize members */ this->dir = 0; this->num_proj_images = 0; this->proj_image_list = 0; this->img_pat = 0; this->mat_pat = 0; this->xy_offset[0] = this->xy_offset[1] = 0; /* Look for ProjectionInfo.xml */ xml_file = string_format ("%s/%s", dir, "ProjectionInfo.xml"); if (file_exists (xml_file)) { this->xml_file = xml_file; } /* Load list of file names */ this->load_filenames (dir); /* If base directory doesn't contain images, look in Scan0 directory */ if (this->num_proj_images == 0) { std::string scan0_dir; scan0_dir = string_format ("%s/%s", dir, "Scan0"); /* Load list of file names */ this->load_filenames (scan0_dir.c_str()); } /* No images in either base directory or Scan 0, so give up. */ if (this->num_proj_images == 0) { return; } /* Found images, try to find pattern */ this->find_pattern (); /* Convert relative paths to absolute paths */ this->harden_filenames (); } Proj_image_dir::~Proj_image_dir () { if (this->img_pat) free (this->img_pat); this->clear_filenames (); } /* ----------------------------------------------------------------------- Private functions ----------------------------------------------------------------------- */ /* This utility function tries to guess the pattern of filenames within a directory. The patterns are of the form: "XXXXYYYY.ZZZ" where XXXX is a prefix, YYYY is a number, and .ZZZ is the extension of a known type (either .hnd, .pfm, or .raw). Returns a pattern which can be used with sprintf, such as: "XXXX%04d.ZZZ" Caller must free patterns. */ void Proj_image_dir::find_pattern () { int i; /* Search for appropriate entry */ for (i = 0; i < this->num_proj_images; i++) { char *entry = this->proj_image_list[i]; int rc; char prefix[2048], num[2048]; /* Look for prefix + number at beginning of filename */ rc = sscanf (entry, "%2047[^0-9]%2047[0-9]", prefix, num); if (rc == 2) { char num_pat[5]; char *suffix; /* Two cases: if num has a leading 0, we format such as %05d. If, we format as %d. */ if (num[0] == '0') { strcpy (num_pat, "%0_d"); num_pat[2] = '0' + ((char) strlen (num)); } else { strcpy (num_pat, "%d"); } /* Find suffix */ suffix = &entry[strlen(prefix) + strlen(num)]; /* Create pattern */ this->img_pat = (char*) malloc ( strlen (this->dir) + 1 + strlen (prefix) + strlen (num_pat) + strlen (suffix) + 1); sprintf (this->img_pat, "%s/%s%s%s", this->dir, prefix, num_pat, suffix); /* Done! */ break; } } return; } void Proj_image_dir::load_filenames ( const char *dir ) { int i; Dir_list dir_list; if (this->dir) { free (this->dir); this->dir = 0; } dir_list.load (dir); this->dir = strdup (dir); this->num_proj_images = 0; this->proj_image_list = 0; for (i = 0; i < dir_list.num_entries; i++) { char *entry = dir_list.entries[i]; if (extension_is (entry, ".hnd") || extension_is (entry, ".pfm") || extension_is (entry, ".raw")) { this->num_proj_images ++; this->proj_image_list = (char**) realloc ( this->proj_image_list, this->num_proj_images * sizeof (char*)); this->proj_image_list[this->num_proj_images-1] = strdup (entry); } } } void Proj_image_dir::harden_filenames () { int i; for (i = 0; i < this->num_proj_images; i++) { char *entry = this->proj_image_list[i]; std::string img_file = string_format ("%s/%s", this->dir, entry); this->proj_image_list[i] = strdup (img_file.c_str()); free (entry); } } void Proj_image_dir::clear_filenames () { int i; for (i = 0; i < this->num_proj_images; i++) { char *entry = this->proj_image_list[i]; free (entry); } if (this->proj_image_list) free (this->proj_image_list); this->num_proj_images = 0; this->proj_image_list = 0; } /* ----------------------------------------------------------------------- Public functions ----------------------------------------------------------------------- */ void Proj_image_dir::set_xy_offset (const double xy_offset[2]) { this->xy_offset[0] = xy_offset[0]; this->xy_offset[1] = xy_offset[1]; } void Proj_image_dir::select (int first, int skip, int last) { int i; if (this->num_proj_images == 0 || !this->img_pat) { return; } this->clear_filenames (); for (i = first; i <= last; i += skip) { std::string img_file = string_format (this->img_pat, i); if (file_exists (img_file)) { this->num_proj_images ++; this->proj_image_list = (char**) realloc ( this->proj_image_list, this->num_proj_images * sizeof (char*)); this->proj_image_list[this->num_proj_images-1] = strdup (img_file.c_str()); } } } Proj_image* Proj_image_dir::load_image (int index) { if (index < 0 || index >= this->num_proj_images) { return 0; } /* mat file load not yet implemented -- Proj_image_dir only works for hnd files */ return new Proj_image (this->proj_image_list[index], this->xy_offset); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/proj_image_dir.h000066400000000000000000000017311321604176500306560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _proj_image_dir_h_ #define _proj_image_dir_h_ #include "plmbase_config.h" #include class Proj_image; class PLMBASE_API Proj_image_dir { public: Proj_image_dir (const char *dir); ~Proj_image_dir (); public: char *dir; /* Dir containing images, maybe not xml file */ int num_proj_images; char **proj_image_list; std::string xml_file; char *img_pat; char *mat_pat; double xy_offset[2]; public: Proj_image* load_image (int index); void select (int first, int skip, int last); void set_xy_offset (const double xy_offset[2]); private: void clear_filenames (); void find_pattern (void); void harden_filenames (); void load_filenames (const char *dir); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/proj_matrix.cxx000077500000000000000000000154121321604176500306210ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "file_util.h" #include "plm_math.h" #include "proj_matrix.h" #include "string_util.h" Proj_matrix::Proj_matrix () { ic[0] = ic[1] = 0.; vec_zero (matrix, 12); sad = sid = 0.; vec_zero (cam, 3); vec_zero (nrm, 3); vec_zero (extrinsic, 16); vec_zero (intrinsic, 12); } Proj_matrix* Proj_matrix::clone () { Proj_matrix *pmat; pmat = new Proj_matrix; if (!pmat) return 0; /* No dynamically allocated memory in proj_matrix */ memcpy (pmat, this, sizeof (Proj_matrix)); return pmat; } std::string Proj_matrix::get () { std::string s; s = PLM_to_string (ic, 2); s += " " + PLM_to_string (matrix, 12); s += " " + PLM_to_string (sad); s += " " + PLM_to_string (sid); s += " " + PLM_to_string (cam, 3); s += " " + PLM_to_string (nrm, 3); s += " " + PLM_to_string (extrinsic, 16); s += " " + PLM_to_string (intrinsic, 12); return s; } void Proj_matrix::set (const std::string& s) { } static void proj_matrix_write ( Proj_matrix *pmat, FILE *fp ) { fprintf (fp, "%18.8e %18.8e\n", pmat->ic[0], pmat->ic[1]); fprintf (fp, "%18.8e %18.8e %18.8e %18.8e\n" "%18.8e %18.8e %18.8e %18.8e\n" "%18.8e %18.8e %18.8e %18.8e\n", pmat->matrix[0], pmat->matrix[1], pmat->matrix[2], pmat->matrix[3], pmat->matrix[4], pmat->matrix[5], pmat->matrix[6], pmat->matrix[7], pmat->matrix[8], pmat->matrix[9], pmat->matrix[10], pmat->matrix[11] ); fprintf (fp, "%18.8e\n%18.8e\n", pmat->sad, pmat->sid); /* NRM */ //fprintf (fp, "%18.8e %18.8e %18.8e\n", nrm[0], nrm[1], nrm[2]); fprintf (fp, "%18.8e %18.8e %18.8e\n", pmat->extrinsic[8], pmat->extrinsic[9], pmat->extrinsic[10]); fprintf (fp, "Extrinsic\n" "%18.8e %18.8e %18.8e %18.8e\n" "%18.8e %18.8e %18.8e %18.8e\n" "%18.8e %18.8e %18.8e %18.8e\n" "%18.8e %18.8e %18.8e %18.8e\n", pmat->extrinsic[0], pmat->extrinsic[1], pmat->extrinsic[2], pmat->extrinsic[3], pmat->extrinsic[4], pmat->extrinsic[5], pmat->extrinsic[6], pmat->extrinsic[7], pmat->extrinsic[8], pmat->extrinsic[9], pmat->extrinsic[10], pmat->extrinsic[11], pmat->extrinsic[12], pmat->extrinsic[13], pmat->extrinsic[14], pmat->extrinsic[15] ); fprintf (fp, "Intrinsic\n" "%18.8e %18.8e %18.8e %18.8e\n" "%18.8e %18.8e %18.8e %18.8e\n" "%18.8e %18.8e %18.8e %18.8e\n", pmat->intrinsic[0], pmat->intrinsic[1], pmat->intrinsic[2], pmat->intrinsic[3], pmat->intrinsic[4], pmat->intrinsic[5], pmat->intrinsic[6], pmat->intrinsic[7], pmat->intrinsic[8], pmat->intrinsic[9], pmat->intrinsic[10], pmat->intrinsic[11] ); } void Proj_matrix::debug () { proj_matrix_write (this, stdout); } void Proj_matrix::save ( const char *fn ) { FILE *fp; if (!fn) return; make_parent_directories (fn); fp = fopen (fn, "w"); if (!fp) { fprintf (stderr, "Error opening %s for write\n", fn); exit (-1); } proj_matrix_write (this, fp); fclose (fp); } void Proj_matrix::set ( const double* cam, const double* tgt, const double* vup, double sid, const double* ic, const double* ps ) { const int cols = 4; double nrm[3]; /* Panel normal */ double plt[3]; /* Panel left (toward first column) */ double pup[3]; /* Panel up (toward top row) */ vec3_copy (this->cam, cam); this->sid = sid; this->sad = vec3_dist (cam, tgt); this->ic[0] = ic[0]; this->ic[1] = ic[1]; /* Compute imager coordinate sys (nrm,pup,plt) --------------- nrm = cam - tgt plt = nrm x vup pup = plt x nrm --------------- */ vec3_sub3 (nrm, cam, tgt); vec3_normalize1 (nrm); vec3_cross (plt, nrm, vup); vec3_normalize1 (plt); vec3_cross (pup, plt, nrm); vec3_normalize1 (pup); #if defined (commentout) printf ("CAM = %g %g %g\n", cam[0], cam[1], cam[2]); printf ("TGT = %g %g %g\n", tgt[0], tgt[1], tgt[2]); printf ("NRM = %g %g %g\n", nrm[0], nrm[1], nrm[2]); printf ("PLT = %g %g %g\n", plt[0], plt[1], plt[2]); printf ("PUP = %g %g %g\n", pup[0], pup[1], pup[2]); #endif /* Build extrinsic matrix - rotation part */ vec_zero (this->extrinsic, 16); vec3_copy (&this->extrinsic[0], plt); vec3_copy (&this->extrinsic[4], pup); vec3_copy (&this->extrinsic[8], nrm); vec3_invert (&this->extrinsic[0]); vec3_invert (&this->extrinsic[4]); vec3_invert (&this->extrinsic[8]); m_idx (this->extrinsic,cols,3,3) = 1.0; /* Build extrinsic matrix - translation part */ this->extrinsic[3] = vec3_dot (plt, tgt); this->extrinsic[7] = vec3_dot (pup, tgt); this->extrinsic[11] = vec3_dot (nrm, tgt) + this->sad; #if defined (commentout) printf ("EXTRINSIC\n%g %g %g %g\n%g %g %g %g\n" "%g %g %g %g\n%g %g %g %g\n", this->extrinsic[0], this->extrinsic[1], this->extrinsic[2], this->extrinsic[3], this->extrinsic[4], this->extrinsic[5], this->extrinsic[6], this->extrinsic[7], this->extrinsic[8], this->extrinsic[9], this->extrinsic[10], this->extrinsic[11], this->extrinsic[12], this->extrinsic[13], this->extrinsic[14], this->extrinsic[15]); #endif /* Build intrinsic matrix */ vec_zero (this->intrinsic, 12); m_idx (this->intrinsic,cols,0,0) = 1 / ps[0]; m_idx (this->intrinsic,cols,1,1) = 1 / ps[1]; m_idx (this->intrinsic,cols,2,2) = 1 / sid; #if defined (commentout) printf ("INTRINSIC\n%g %g %g %g\n%g %g %g %g\n%g %g %g %g\n", this->intrinsic[0], this->intrinsic[1], this->intrinsic[2], this->intrinsic[3], this->intrinsic[4], this->intrinsic[5], this->intrinsic[6], this->intrinsic[7], this->intrinsic[8], this->intrinsic[9], this->intrinsic[10], this->intrinsic[11]); #endif /* Build projection matrix */ mat_mult_mat (this->matrix, this->intrinsic,3,4, this->extrinsic,4,4); } void Proj_matrix::get_nrm ( double nrm[3] ) { vec3_copy (nrm, &this->extrinsic[8]); vec3_invert (nrm); } void Proj_matrix::get_pdn ( double pdn[3] ) { vec3_copy (pdn, &this->extrinsic[4]); } void Proj_matrix::get_prt ( double prt[3] ) { vec3_copy (prt, &this->extrinsic[0]); } void Proj_matrix::project_h (double* ij, const double* xyz) const { mat43_mult_vec4 (ij, this->matrix, xyz); } void Proj_matrix::project (double* ij, const double* xyz) const { ij[0] = vec3_dot(&this->matrix[0], xyz) + this->matrix[3]; ij[1] = vec3_dot(&this->matrix[4], xyz) + this->matrix[7]; double h = vec3_dot(&this->matrix[8], xyz) + this->matrix[11]; ij[0] = this->ic[0] + ij[0] / h; ij[1] = this->ic[1] + ij[1] / h; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/proj_matrix.h000077500000000000000000000033021321604176500302410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _proj_matrix_h_ #define _proj_matrix_h_ #include "plmbase_config.h" #include class PLMBASE_API Proj_matrix { public: Proj_matrix (); public: double ic[2]; /* Image Center: ic[0] = x, ic[1] = y */ double matrix[12]; /* Projection matrix */ double sad; /* Distance: Source To Axis */ double sid; /* Distance: Source to Image */ double cam[3]; /* Location of camera */ double nrm[3]; /* Ray from image center to source */ double extrinsic[16]; double intrinsic[12]; public: std::string get (); void get_nrm (double nrm[3]); void get_pdn (double pdn[3]); void get_prt (double prt[3]); void set ( const double* cam, const double* tgt, const double* vup, double sid, const double* ic, const double* ps ); void set (const std::string& s); /* Project 3D coordinate xyz of cartesian space into 2D coordinate ij coordinate on projection plane. In this version, the inputs and outputs are homogenous, not cartesian. */ void project_h (double* ij, const double* xyz) const; /* Project 3D coordinate xyz of cartesian space into 2D coordinate ij coordinate on projection plane. In this version, the inputs and outputs are cartesian, not homogenous. */ void project (double* ij, const double* xyz) const; void save (const char *fn); void debug (); Proj_matrix* clone (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/proj_volume.cxx000077500000000000000000000273351321604176500306330ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include "file_util.h" #include "logfile.h" #include "path_util.h" #include "plm_image.h" #include "print_and_exit.h" #include "proj_matrix.h" #include "proj_volume.h" #include "string_util.h" #include "volume.h" class Proj_volume_private { public: Proj_volume_private () { vol = Volume::New(); pmat = new Proj_matrix; num_steps = 0; step_length = 0.; for (int d = 0; d < 2; d++) { image_dim[d] = 0; clipping_dist[d] = 0.; } for (int d = 0; d < 3; d++) { nrm[d] = 0.; src[d] = 0.; iso[d] = 0.; ul_room[d] = 0.; incr_c[d] = 0.; incr_r[d] = 0.; } } ~Proj_volume_private () { delete pmat; } public: Volume::Pointer vol; Proj_matrix *pmat; plm_long num_steps; double step_length; plm_long image_dim[2]; double image_spacing[2]; double clipping_dist[2]; double nrm[3]; double src[3]; double iso[3]; double ul_room[3]; double incr_r[3]; double incr_c[3]; }; Proj_volume::Proj_volume () { d_ptr = new Proj_volume_private; } Proj_volume::~Proj_volume () { delete d_ptr; } void Proj_volume::debug () { const double* nrm = this->get_nrm (); printf ("src = %f %f %f\n", d_ptr->src[0], d_ptr->src[1], d_ptr->src[2]); printf ("nrm = %f %f %f\n", nrm[0], nrm[1], nrm[2]); printf ("ul_room = %f %f %f\n", d_ptr->ul_room[0], d_ptr->ul_room[1], d_ptr->ul_room[2]); } void Proj_volume::set_geometry ( const double src[3], // position of source (mm) const double iso[3], // position of isocenter (mm) const double vup[3], // dir to "top" of projection plane double sid, // dist from proj plane to source (mm) const plm_long image_dim[2], // resolution of image const double image_center[2], // image center (pixels) const double image_spacing[2], // pixel size (mm) const double clipping_dist[2], // dist from src to clipping planes (mm) const double step_length // spacing between planes ) { double tmp[3]; /* save input settings */ d_ptr->image_dim[0] = image_dim[0]; d_ptr->image_dim[1] = image_dim[1]; d_ptr->image_spacing[0] = image_spacing[0]; d_ptr->image_spacing[1] = image_spacing[1]; d_ptr->src[0] = src[0]; d_ptr->src[1] = src[1]; d_ptr->src[2] = src[2]; d_ptr->iso[0] = iso[0]; d_ptr->iso[1] = iso[1]; d_ptr->iso[2] = iso[2]; d_ptr->step_length = step_length; /* build projection matrix */ d_ptr->pmat->set ( src, iso, vup, sid, image_center, image_spacing ); /* populate aperture orientation unit vectors */ double nrm[3], pdn[3], prt[3]; d_ptr->pmat->get_nrm (nrm); if (nrm[0] == 0 && nrm[1] == 0) { if (nrm[2] == 0) { printf("source and isocenter are at the same location - no beam created\n"); } else { printf("the vector nrm is parallel to the z axis, pdn is defined by default as x vector and pdr as -y\n"); pdn[0] = 0; pdn[1] = -1; pdn[2] = 0; prt[0] = 1; prt[1] = 0; prt[2] = 0; } } else { d_ptr->pmat->get_pdn (pdn); d_ptr->pmat->get_prt (prt); } /* compute position of aperture in room coordinates */ double ic_room[3]; vec3_scale3 (tmp, nrm, - sid); vec3_add3 (ic_room, src, tmp); /* compute incremental change in 3d position for each change in aperture row/column. */ vec3_scale3 (d_ptr->incr_c, prt, image_spacing[0]); vec3_scale3 (d_ptr->incr_r, pdn, image_spacing[1]); /* get position of upper left pixel on panel */ vec3_copy (d_ptr->ul_room, ic_room); vec3_scale3 (tmp, d_ptr->incr_c, - image_center[0]); vec3_add2 (d_ptr->ul_room, tmp); vec3_scale3 (tmp, d_ptr->incr_r, - image_center[1]); vec3_add2 (d_ptr->ul_room, tmp); } void Proj_volume::set_clipping_dist (const double clipping_dist[2]) { d_ptr->clipping_dist[0] = clipping_dist[0]; d_ptr->clipping_dist[1] = clipping_dist[1]; d_ptr->num_steps = (plm_long) ceil ( (clipping_dist[1] - clipping_dist[0]) / d_ptr->step_length); } void Proj_volume::allocate () { plm_long dim[3] = { d_ptr->image_dim[0], d_ptr->image_dim[1], d_ptr->num_steps }; float origin[3] = { 0, 0, 0 }; float spacing[3] = { 1, 1, 1 }; float direction_cosines[9] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; printf("%lg %lg %lg \n", (float) dim[0], (float) dim[1], (float) dim[2]); d_ptr->vol->create (dim, origin, spacing, direction_cosines, PT_FLOAT, 1); } const plm_long* Proj_volume::get_image_dim () { return d_ptr->image_dim; } plm_long Proj_volume::get_image_dim (int dim) { return d_ptr->image_dim [dim]; } plm_long Proj_volume::get_num_steps () { return d_ptr->num_steps; } const double* Proj_volume::get_incr_c () { return d_ptr->incr_c; } const double* Proj_volume::get_incr_r () { return d_ptr->incr_r; } const double* Proj_volume::get_nrm () { d_ptr->pmat->get_nrm (d_ptr->nrm); return d_ptr->nrm; } Proj_matrix* Proj_volume::get_proj_matrix () { return d_ptr->pmat; } const double* Proj_volume::get_src () const { return d_ptr->src; } const double* Proj_volume::get_iso () { return d_ptr->iso; } const double* Proj_volume::get_clipping_dist () { return d_ptr->clipping_dist; } double Proj_volume::get_step_length () const { return d_ptr->step_length; } const double* Proj_volume::get_ul_room () { return d_ptr->ul_room; } Volume* Proj_volume::get_vol () { return d_ptr->vol.get(); } const Volume* Proj_volume::get_vol () const { return d_ptr->vol.get(); } void Proj_volume::project_h (double* ij, const double* xyz) const { d_ptr->pmat->project_h (ij, xyz); } void Proj_volume::project (double* ij, const double* xyz) const { d_ptr->pmat->project (ij, xyz); } void Proj_volume::save_img (const char *filename) { Plm_image(d_ptr->vol).save_image(filename); } void Proj_volume::save_img (const std::string& filename) { this->save_img (filename.c_str()); } void Proj_volume::save_header (const char *filename) { FILE *fp = plm_fopen (filename, "wb"); if (!fp) { print_and_exit ("Error opening file %s for write\n", filename); } std::string s = d_ptr->pmat->get (); fprintf (fp, "num_steps=%d\n", d_ptr->num_steps); fprintf (fp, "step_length=%g\n", d_ptr->step_length); fprintf (fp, "image_dim=%d %d\n", d_ptr->image_dim[0], d_ptr->image_dim[1]); fprintf (fp, "image_spacing=%g %g\n", d_ptr->image_spacing[0], d_ptr->image_spacing[1]); fprintf (fp, "clipping_dist=%g %g\n", d_ptr->clipping_dist[0], d_ptr->clipping_dist[1]); fprintf (fp, "nrm=%g %g %g\n", d_ptr->nrm[0], d_ptr->nrm[1], d_ptr->nrm[2]); fprintf (fp, "src=%g %g %g\n", d_ptr->src[0], d_ptr->src[1], d_ptr->src[2]); fprintf (fp, "iso=%g %g %g\n", d_ptr->iso[0], d_ptr->iso[1], d_ptr->iso[2]); fprintf (fp, "ul_room=%g %g %g\n", d_ptr->ul_room[0], d_ptr->ul_room[1], d_ptr->ul_room[2]); fprintf (fp, "incr_r=%g %g %g\n", d_ptr->incr_r[0], d_ptr->incr_r[1], d_ptr->incr_r[2]); fprintf (fp, "incr_c=%g %g %g\n", d_ptr->incr_c[0], d_ptr->incr_c[1], d_ptr->incr_c[2]); fprintf (fp, "pmat=%s\n", s.c_str()); fclose (fp); } void Proj_volume::save_header (const std::string& filename) { this->save_header (filename.c_str()); } void Proj_volume::save_projv (const char *filename) { std::string fn_base = strip_extension_if (filename, "projv"); std::string proj_vol_hdr_fn = fn_base + ".projv"; this->save_header (proj_vol_hdr_fn); std::string proj_vol_img_fn = fn_base + ".nrrd"; this->save_img (proj_vol_img_fn); } void Proj_volume::save_projv (const std::string& filename) { this->save_projv (filename.c_str()); } void Proj_volume::load_img (const char *filename) { Plm_image::Pointer plm_image = Plm_image::New (filename); d_ptr->vol = plm_image->get_volume (); } void Proj_volume::load_img (const std::string& filename) { this->load_img (filename.c_str()); } void Proj_volume::load_header (const char* filename) { std::ifstream ifs (filename); if (!ifs.is_open()) { logfile_printf ("Error opening %s for read", filename); return; } while (true) { std::string line; getline (ifs, line); if (!ifs.good()) { /* End of file. */ break; } if (line.find('=') == std::string::npos) { /* No "=" found. */ break; } int a, b; float f, g; int rc; rc = sscanf (line.c_str(), "num_steps = %d\n", &a); d_ptr->num_steps = a; if (rc == 1) continue; rc = sscanf (line.c_str(), "step_length = %f\n", &f); if (rc == 1) { d_ptr->step_length = f; continue; } rc = sscanf (line.c_str(), "image_dim = %d %d\n", &a, &b); if (rc == 3) { d_ptr->image_dim[0] = a; d_ptr->image_dim[1] = b; continue; } rc = sscanf (line.c_str(), "image_spacing = %f %f\n", &f, &g); if (rc == 2) { d_ptr->image_spacing[0] = f; d_ptr->image_spacing[1] = g; continue; } #if defined (commentout) rc = sscanf (line.c_str(), "roi_offset = %d %d %d\n", &a, &b, &c); if (rc == 3) { roi_offset[0] = a; roi_offset[1] = b; roi_offset[2] = c; continue; } rc = sscanf (line.c_str(), "roi_dim = %d %d %d\n", &a, &b, &c); if (rc == 3) { roi_dim[0] = a; roi_dim[1] = b; roi_dim[2] = c; continue; } rc = sscanf (line.c_str(), "vox_per_rgn = %d %d %d\n", &a, &b, &c); if (rc == 3) { vox_per_rgn[0] = a; vox_per_rgn[1] = b; vox_per_rgn[2] = c; continue; } #endif logfile_printf ("Error loading projv file\n%s\n", line.c_str()); return; } #if defined (commentout) fprintf (fp, "clipping_dist=%g %g\n", d_ptr->image_spacing[0], d_ptr->image_spacing[1]); fprintf (fp, "nrm=%g %g %g\n", d_ptr->nrm[0], d_ptr->nrm[1], d_ptr->nrm[2]); fprintf (fp, "src=%g %g %g\n", d_ptr->src[0], d_ptr->src[1], d_ptr->src[2]); fprintf (fp, "iso=%g %g %g\n", d_ptr->iso[0], d_ptr->iso[1], d_ptr->iso[2]); fprintf (fp, "ul_room=%g %g %g\n", d_ptr->ul_room[0], d_ptr->ul_room[1], d_ptr->ul_room[2]); fprintf (fp, "incr_r=%g %g %g\n", d_ptr->incr_r[0], d_ptr->incr_r[1], d_ptr->incr_r[2]); fprintf (fp, "incr_c=%g %g %g\n", d_ptr->incr_c[0], d_ptr->incr_c[1], d_ptr->incr_c[2]); std::string s = d_ptr->pmat->get (); fprintf (fp, "pmat=%s\n", s.c_str()); fclose (fp); #endif } void Proj_volume::load_header (const std::string& filename) { this->load_header (filename.c_str()); } void Proj_volume::load_projv (const char *filename) { std::string fn_base = strip_extension_if (filename, "projv"); std::string proj_vol_hdr_fn = fn_base + ".projv"; this->load_header (proj_vol_hdr_fn); std::string proj_vol_img_fn = fn_base + ".nrrd"; this->load_img (proj_vol_img_fn); } void Proj_volume::load_projv (const std::string& filename) { this->load_projv (filename.c_str()); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/proj_volume.h000077500000000000000000000060351321604176500302520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _proj_volume_h_ #define _proj_volume_h_ #include "plmbase_config.h" #include #include "plm_int.h" class Proj_matrix; class Proj_volume_private; class Volume; /*! \brief * The Proj_volume class represents a three-dimensional volume * on a uniform non-orthogonal grid. The grid is regular within * a rectangular frustum, the geometry of which is specified by * a projection matrix. */ class PLMBASE_API Proj_volume { public: Proj_volume (); ~Proj_volume (); public: Proj_volume_private *d_ptr; public: void set_geometry ( const double src[3], // position of source (mm) const double iso[3], // position of isocenter (mm) const double vup[3], // dir to "top" of projection plane double sid, // dist from proj plane to source (mm) const plm_long image_dim[2], // resolution of image const double image_center[2], // image center (pixels) const double image_spacing[2], // pixel size (mm) const double clipping_dist[2], // dist from src to clipping planes (mm) const double step_length // spacing between planes ); void set_clipping_dist (const double clipping_dist[2]); const plm_long* get_image_dim (); plm_long get_image_dim (int dim); plm_long get_num_steps (); const double* get_incr_c (); const double* get_incr_r (); Proj_matrix *get_proj_matrix (); const double* get_nrm (); const double* get_src () const; const double* get_iso (); const double* get_clipping_dist(); double get_step_length () const; const double* get_ul_room (); Volume *get_vol (); const Volume *get_vol () const; void allocate (); void save_img (const char* filename); void save_img (const std::string& filename); void save_header (const char* filename); void save_header (const std::string& filename); void save_projv (const char* filename); void save_projv (const std::string& filename); void load_img (const char* filename); void load_img (const std::string& filename); void load_header (const char* filename); void load_header (const std::string& filename); void load_projv (const char* filename); void load_projv (const std::string& filename); /* Project 3D coordinate xyz of cartesian space into 2D coordinate ij coordinate on projection plane. In this version, the inputs and outputs are homogenous, not cartesian. */ void project_h (double* ij, const double* xyz) const; /* Project 3D coordinate xyz of cartesian space into 2D coordinate ij coordinate on projection plane. In this version, the inputs and outputs are cartesian, not homogenous. */ void project (double* ij, const double* xyz) const; void debug (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/pwlut.cxx000066400000000000000000000047071321604176500274400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "print_and_exit.h" #include "pwlut.h" Pwlut::Pwlut () { left_slope = 1.0; right_slope = 1.0; } void Pwlut::set_lut (const Float_pair_list& pwlut_fpl) { /* Set the LUT */ this->fpl = pwlut_fpl; /* Initialize some other variables for use during lookup */ left_slope = 1.0; right_slope = 1.0; ait_start = fpl.begin(); ait_end = fpl.end(); if (ait_start->first == -std::numeric_limits::max()) { left_slope = ait_start->second; ait_start++; } if ((--ait_end)->first == std::numeric_limits::max()) { right_slope = ait_end->second; --ait_end; } } void Pwlut::set_lut (const std::string& pwlut_string) { /* Parse the LUT string */ Float_pair_list fpl = parse_float_pairs (pwlut_string); if (fpl.empty()) { print_and_exit ("Error: couldn't parse pwlut string: %s\n", pwlut_string.c_str()); } this->set_lut (fpl); } float Pwlut::lookup (float vin) const { float vout; /* Three possible cases: before first node, between two nodes, and after last node */ /* Case 1 */ if (vin <= ait_start->first) { vout = ait_start->second + (vin - ait_start->first) * left_slope; #if defined (commentout) printf ("[1] < %f (%f -> %f)\n", ait_start->first, vin, vout); #endif return vout; } else if (ait_start != ait_end) { Float_pair_list::const_iterator ait = ait_start; Float_pair_list::const_iterator prev = ait_start; do { ait++; /* Case 2 */ if (vin <= ait->first) { float slope = (ait->second - prev->second) / (ait->first - prev->first); vout = prev->second + (vin - prev->first) * slope; #if defined (commentout) printf ("[2] in (%f,%f) (%f -> %f)\n", prev->first, ait->first, vin, vout); #endif return vout; } prev = ait; } while (ait != ait_end); } /* Case 3 */ vout = ait_end->second + (vin - ait_end->first) * right_slope; #if defined (commentout) printf ("[3] > %f (%f -> %f)\n", ait_end->first, vin, vout); #endif return vout; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/pwlut.h000066400000000000000000000020721321604176500270560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pwlut_h_ #define _pwlut_h_ #include "plmutil_config.h" #include #include #include "itk_image_type.h" #include "float_pair_list.h" /*! \brief * The Pwlut class implements a lookup table with piecewise * linear segments */ class PLMBASE_API Pwlut { public: Pwlut (); protected: Float_pair_list fpl; float left_slope; float right_slope; Float_pair_list::const_iterator ait_start; Float_pair_list::const_iterator ait_end; public: /*! \name Inputs */ ///@{ /*! \brief Set the input/output pairs in the lookup table */ void set_lut (const std::string& pwlut_string); /*! \brief Set the input/output pairs in the lookup table */ void set_lut (const Float_pair_list& pwlut_fpl); /*! \brief Interpolate a lookup value */ float lookup (float vin) const; ///@} }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rasterize_slice.cxx000066400000000000000000000155241321604176500314530ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* This is a native C implementation. See this: http://www.dgp.toronto.edu/~ah/csc418/fall_2001/notes/scanconv.html http://www.cc.gatech.edu/gvu/multimedia/nsfmmedia/graphics/elabor/polyscan/polyscan1.html http://graphics.cs.ucdavis.edu/education/GraphicsNotes/Scan-Conversion/Scan-Conversion.html http://www.cs.berkeley.edu/~sequin/CS184/TEXT/Algorithm.html */ #include "plm_config.h" #include #include #include #include #include "rasterize_slice.h" typedef struct edge Edge; struct edge { int ymax; float x; float xincr; Edge* next; }; void remove_old_edges (Edge** head, int y) { Edge *p, *n; p = *head; while (p && p->ymax < y) p = p->next; *head = p; while (p) { n = p->next; while (n && n->ymax < y) n = n->next; p->next = n; p = n; } } void insert_ordered_by_x (Edge** head, Edge* c) { Edge* p; if ((p = *head)) { if (p->x > c->x) { c->next = p; *head = c; } else { while (p->next && p->next->x < c->x) p = p->next; c->next = p->next; p->next = c; } } else { *head = c; c->next = 0; } } void print_edges (Edge* p) { while (p) { printf ("[%g %g %d] ", p->x, p->xincr, p->ymax); p = p->next; } } /* Returns true if point lies within polygon */ /* I don't use the below algorithm, but it looks interesing: http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm */ bool point_in_polygon ( const float* x_in, /* polygon vertices in mm */ const float* y_in, /* polygon vertices in mm */ int num_vertices, float x_test, float y_test ) { int num_crossings = 0; /* Check if last vertex == first vertex. If so, remove it. */ if (x_in[num_vertices-1] == x_in[0] && y_in[num_vertices-1] == y_in[0]) { num_vertices --; } for (int i = 0; i < num_vertices; i++) { int a = i, b = (i==num_vertices-1 ? 0 : i+1); /* Reorder segment so that y[a] > y[b] */ if (y_in[a] == y_in[b]) continue; if (y_in[a] < y_in[b]) a = b, b = i; /* Reject segments too high or too low */ /* If upper y is exactly equal to query location, reject */ if (y_in[a] <= y_test) continue; if (y_in[b] > y_test) continue; /* Find x coordinate of segment */ float frac = (y_in[a] - y_test) / (y_in[a] - y_in[b]); float x_line_seg = x_in[b] + frac * (x_in[a] - x_in[b]); /* If x_test is to the right x_line_seg, then we have a crossing. Count as inside for left boundaries. */ if (x_test >= x_line_seg) { num_crossings ++; } } return (num_crossings % 2) == 1; } /* Rasterizes a single closed polygon on a slice */ void rasterize_slice ( unsigned char* acc_img, plm_long* dims, float* spacing, float* offset, size_t num_vertices, const float* x_in, /* polygon vertices in mm */ const float* y_in /* polygon vertices in mm */ ) { unsigned char* imgp; Edge** edge_table; Edge* edge_list; /* Global edge list */ Edge* ael; /* Active edge list */ float *x, *y; /* vertices in pixel coordinates */ /* Check if last vertex == first vertex. If so, remove it. */ if (x_in[num_vertices-1] == x_in[0] && y_in[num_vertices-1] == y_in[0]) { num_vertices --; } /* Convert from mm to pixel coordinates */ x = (float*) malloc (sizeof (float) * num_vertices); y = (float*) malloc (sizeof (float) * num_vertices); for (size_t i = 0; i < num_vertices; i++) { x[i] = (x_in[i] - offset[0]) / spacing[0]; y[i] = (y_in[i] - offset[1]) / spacing[1]; } /* Make edge table */ edge_table = (Edge**) malloc (dims[1] * sizeof(Edge*)); edge_list = (Edge*) malloc (num_vertices * sizeof(Edge)); memset (edge_table, 0, dims[1] * sizeof(Edge*)); for (size_t i = 0; i < num_vertices; i++) { int ymin, ymax; size_t a = i, b = (i==num_vertices-1 ? 0 : i+1); /* Reorder segment so that y[a] > y[b] */ if (y[a] == y[b]) continue; if (y[a] < y[b]) a = b, b = i; /* Reject segments too high or too low */ ymin = (int) ceil(y[b]); if (ymin > dims[1]-1) continue; ymax = (int) floor(y[a]); if (ymax < 0) continue; /* If upper y lies on scan line, don't count it as an intersection */ if (y[a] == ymax) ymax --; /* Reject segments that don't intersect a scan line */ if (ymax < ymin) continue; /* Clip segments against image boundary */ if (ymin < 0) ymin = 0; if (ymax > dims[1]-1) ymax = dims[1]-1; /* Shorten the segment & fill in edge data */ edge_list[i].ymax = ymax; edge_list[i].xincr = (x[a] - x[b]) / (y[a] - y[b]); edge_list[i].x = x[b] + (ymin - y[b]) * edge_list[i].xincr; edge_list[i].next = 0; /* Insert into edge_table */ #if defined (commentout) printf ("[y:%g %g, x:%g %g] -> [y:%d %d, x:%g (%g)]\n", y[b], y[a], x[b], x[a], ymin, ymax, edge_list[i].x, edge_list[i].xincr); #endif insert_ordered_by_x (&edge_table[ymin], &edge_list[i]); } /* Debug edge table */ #if defined (commentout) printf ("-------------------------------------------\n"); for (plm_long i = 0; i < dims[1]; i++) { if (edge_table[i]) { printf ("%d: ", i); print_edges (edge_table[i]); printf ("\n"); } } #endif /* Loop through scanline, rendering each */ imgp = acc_img; ael = 0; for (plm_long i = 0; i < dims[1]; i++) { int x, num_crossings; Edge *n, *c; /* Remove old edges from AEL */ remove_old_edges (&ael, i); /* Add new edges to AEL */ c = edge_table[i]; while (c) { n = c->next; insert_ordered_by_x (&ael, c); c = n; } /* Count scan intersections & rasterize */ num_crossings = 0; x = 0; c = ael; #if defined (commentout) printf ("%d ", i); print_edges (ael); #endif while (x < dims[0]) { int next_x; while (1) { if (!c) { next_x = dims[0]; break; } else if (x >= c->x) { c = c->next; num_crossings ++; continue; } else { next_x = (int) floor (c->x) + 1; if (next_x > dims[0]) next_x = dims[0]; break; } } num_crossings = num_crossings % 2; #if defined (commentout) printf ("(%d %c %d)", x, num_crossings?'+':'-', next_x-1); #endif while (x < next_x) { *imgp++ = num_crossings; x++; } } #if defined (commentout) printf ("\n"); getchar(); #endif /* Update x values on AEL */ c = ael; while (c) { c->x += c->xincr; c = c->next; } /* Resort AEL - this could be done more efficiently */ c = ael; while (c) { if (c->next && c->x > c->next->x) { Edge* tmp = c->next; c->next = c->next->next; insert_ordered_by_x (&ael, tmp); c = tmp; } else { c = c->next; } } } /* Free things up */ free (x); free (y); free (edge_table); free (edge_list); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rasterize_slice.h000066400000000000000000000015001321604176500310650ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rasterize_slice_h_ #define _rasterize_slice_h_ #include "plmbase_config.h" #include "plm_int.h" PLMBASE_C_API void rasterize_slice ( unsigned char* acc_img, plm_long* dims, float* spacing, float* offset, size_t num_vertices, const float* x_in, /* polygon vertices in mm */ const float* y_in /* polygon vertices in mm */ ); bool point_in_polygon ( const float* x_in, /* polygon vertices in mm */ const float* y_in, /* polygon vertices in mm */ size_t num_vertices, float x_test, float y_test ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rasterizer.cxx000066400000000000000000000223461321604176500304560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include #include "print_and_exit.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_int.h" #include "plm_math.h" #include "rasterize_slice.h" #include "rasterizer.h" #include "rtss.h" #include "rtss_contour.h" #include "rtss_roi.h" #include "volume.h" Rasterizer::Rasterizer () { want_prefix_imgs = false; want_labelmap = false; want_ss_img = false; acc_img = 0; uchar_vol = 0; labelmap_vol = 0; m_ss_img = 0; m_use_ss_img_vec = true; curr_struct_no = 0; curr_bit = 0; xor_overlapping = false; } Rasterizer::~Rasterizer (void) { if (this->uchar_vol) { delete this->uchar_vol; } if (this->labelmap_vol) { delete this->labelmap_vol; } if (this->m_ss_img) { delete this->m_ss_img; } free (this->acc_img); } void Rasterizer::init ( Rtss *cxt, /* Input */ Plm_image_header *pih, /* Input */ bool want_prefix_imgs, /* Input */ bool want_labelmap, /* Input */ bool want_ss_img, /* Input */ bool use_ss_img_vec, /* Input */ bool xor_overlapping /* Input */ ) { int slice_voxels; pih->get_origin (this->origin); pih->get_spacing (this->spacing); pih->get_dim (this->dim); slice_voxels = this->dim[0] * this->dim[1]; this->want_prefix_imgs = want_prefix_imgs; this->want_labelmap = want_labelmap; this->want_ss_img = want_ss_img; this->xor_overlapping = xor_overlapping; this->m_use_ss_img_vec = use_ss_img_vec; this->acc_img = (unsigned char*) malloc ( slice_voxels * sizeof(unsigned char)); /* Create output volume for mask image. This is reused for each structure */ this->uchar_vol = new Volume (this->dim, this->origin, this->spacing, 0, PT_UCHAR, 1); if (this->uchar_vol == 0) { print_and_exit ("ERROR: failed in allocating the volume"); } /* Create output volume for labelmap */ this->labelmap_vol = 0; if (want_labelmap) { this->labelmap_vol = new Volume (this->dim, this->origin, this->spacing, 0, PT_UINT32, 1); if (this->labelmap_vol == 0) { print_and_exit ("ERROR: failed in allocating the volume"); } } /* Create output volume for ss_img */ if (want_ss_img) { this->m_ss_img = new Plm_image; if (use_ss_img_vec) { UCharVecImageType::Pointer ss_img = UCharVecImageType::New (); itk_image_set_header (ss_img, pih); int num_uchar = 1 + (cxt->num_structures-1) / 8; if (num_uchar < 2) num_uchar = 2; ss_img->SetVectorLength (num_uchar); ss_img->Allocate (); /* Zero out the image */ itk::VariableLengthVector< unsigned char > ZeroPixel (num_uchar); ZeroPixel.Fill (itk::NumericTraits< unsigned char >::Zero); ss_img->FillBuffer (ZeroPixel); this->m_ss_img->set_itk (ss_img); } else { Volume *vol = new Volume (this->dim, this->origin, this->spacing, 0, PT_UINT32, 1); if (vol == 0) { print_and_exit ("ERROR: failed allocating ss_img volume"); } this->m_ss_img->set_volume (vol); } } /* Initialize to start with first structure */ this->curr_struct_no = 0; this->curr_bit = 0; } /* Return true if an image was processed */ bool Rasterizer::process_next ( Rtss *cxt /* In/out */ ) { Rtss_roi* curr_structure; unsigned char* uchar_img = (unsigned char*) this->uchar_vol->img; size_t slice_voxels; /* If done, return false */ if (this->curr_struct_no >= cxt->num_structures) { this->curr_struct_no = cxt->num_structures + 1; return false; } /* If not using ss_img_vec, stop at 32 structures */ if (!this->m_use_ss_img_vec && this->curr_struct_no >= 32) { printf ("Warning: too many structures. Dropping some...\n"); this->curr_struct_no = cxt->num_structures + 1; return false; } curr_structure = cxt->slist[this->curr_struct_no]; slice_voxels = this->dim[0] * this->dim[1]; memset (uchar_img, 0, this->dim[0] * this->dim[1] * this->dim[2] * sizeof(unsigned char)); /* Loop through polylines in this structure */ for (size_t i = 0; i < curr_structure->num_contours; i++) { Rtss_contour* curr_contour; unsigned char* uchar_slice; plm_long slice_no; curr_contour = curr_structure->pslist[i]; if (curr_contour->num_vertices == 0) { continue; } slice_no = ROUND_PLM_LONG( (curr_contour->z[0] - this->origin[2]) / this->spacing[2]); if (slice_no < 0 || slice_no >= this->dim[2]) { continue; } /* Render contour to binary */ memset (this->acc_img, 0, slice_voxels * sizeof(unsigned char)); rasterize_slice ( this->acc_img, this->dim, this->spacing, this->origin, curr_contour->num_vertices, curr_contour->x, curr_contour->y); /* Copy from acc_img into mask image */ if (this->want_prefix_imgs) { uchar_slice = &uchar_img[slice_no * slice_voxels]; for (size_t k = 0; k < slice_voxels; k++) { uchar_slice[k] ^= this->acc_img[k]; } } /* Copy from acc_img into labelmask image */ if (this->want_labelmap) { uint32_t* labelmap_img; uint32_t* uint32_slice; labelmap_img = (uint32_t*) this->labelmap_vol->img; uint32_slice = &labelmap_img[slice_no * slice_voxels]; for (size_t k = 0; k < slice_voxels; k++) { if (this->acc_img[k]) { uint32_slice[k] = this->curr_bit + 1; } } } /* Copy from acc_img into ss_img */ if (this->want_ss_img) { if (this->m_use_ss_img_vec) { UCharVecImageType::Pointer ss_img = this->m_ss_img->m_itk_uchar_vec; /* GCS FIX: This code is replicated in ss_img_extract */ unsigned int uchar_no = this->curr_bit / 8; unsigned int bit_no = this->curr_bit % 8; unsigned char bit_mask = 1 << bit_no; if (uchar_no > ss_img->GetVectorLength()) { print_and_exit ( "Error: bit %d was requested from image of %d bits\n", this->curr_bit, ss_img->GetVectorLength() * 8); } /* GCS FIX: This is inefficient, due to undesirable construct and destruct of itk::VariableLengthVector of each pixel */ UCharVecImageType::IndexType idx = {{0, 0, slice_no}}; size_t k = 0; for (idx.m_Index[1] = 0; idx.m_Index[1] < this->dim[1]; idx.m_Index[1]++) { for (idx.m_Index[0] = 0; idx.m_Index[0] < this->dim[0]; idx.m_Index[0]++) { if (this->acc_img[k]) { itk::VariableLengthVector v = ss_img->GetPixel (idx); if (this->xor_overlapping) { v[uchar_no] ^= bit_mask; } else { v[uchar_no] |= bit_mask; } ss_img->SetPixel (idx, v); } k++; } } } else { uint32_t* ss_img = 0; uint32_t* uint32_slice; uint32_t bit_mask = 1 << this->curr_bit; ss_img = (uint32_t*) this->m_ss_img->get_vol()->img; uint32_slice = &ss_img[slice_no * slice_voxels]; for (size_t k = 0; k < slice_voxels; k++) { if (this->acc_img[k]) { if (this->xor_overlapping) { uint32_slice[k] ^= bit_mask; } else { uint32_slice[k] |= bit_mask; } } } } } } this->curr_struct_no ++; if (curr_structure->num_contours > 0) { curr_structure->bit = this->curr_bit; this->curr_bit ++; } return true; } const char* Rasterizer::current_name ( Rtss *cxt ) { if (this->curr_struct_no < cxt->num_structures + 1) { Rtss_roi *curr_structure; curr_structure = cxt->slist[this->curr_struct_no-1]; return curr_structure->name.c_str(); } else { return ""; } } void Rasterizer::rasterize ( Rtss *cxt, /* Input */ Plm_image_header *pih, /* Input */ bool want_prefix_imgs, /* Input */ bool want_labelmap, /* Input */ bool want_ss_img, /* Input */ bool use_ss_img_vec, /* Input */ bool xor_overlapping /* Input */ ) { this->init (cxt, pih, false, true, true, use_ss_img_vec, xor_overlapping); while (this->process_next (cxt)) {} } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rasterizer.h000066400000000000000000000031201321604176500300700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rasterizer_h_ #define _rasterizer_h_ #include "plmbase_config.h" #include "itk_image_type.h" class Rtss; class Plm_image_header; class PLMBASE_API Rasterizer { public: Rasterizer (); ~Rasterizer (); public: bool want_prefix_imgs; bool want_labelmap; bool want_ss_img; /* The default behavior is to "or" overlapping contours. Set this member to true if you want to "xor" instead */ bool xor_overlapping; float origin[3]; float spacing[3]; plm_long dim[3]; unsigned char* acc_img; Volume* uchar_vol; Volume* labelmap_vol; Plm_image* m_ss_img; bool m_use_ss_img_vec; size_t curr_struct_no; int curr_bit; public: void rasterize ( Rtss *cxt, Plm_image_header *pih, bool want_prefix_imgs, bool want_labelmap, bool want_ss_img, bool use_ss_img_vec, bool xor_overlapping ); private: void init ( Rtss *cxt, /* Input */ Plm_image_header *pih, /* Input */ bool want_prefix_imgs, /* Input */ bool want_labelmap, /* Input */ bool want_ss_img, /* Input */ bool use_ss_img_vec, /* Input */ bool xor_overlapping /* Input */ ); bool process_next ( Rtss *cxt /* In/out */ ); const char* current_name ( Rtss *cxt ); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/raw_pointset.cxx000066400000000000000000000153471321604176500310050ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "file_util.h" #include "path_util.h" #include "plm_math.h" #include "print_and_exit.h" #include "raw_pointset.h" Raw_pointset* pointset_create (void) { Raw_pointset *ps; ps = (Raw_pointset*) malloc (sizeof (Raw_pointset)); memset (ps, 0, sizeof (Raw_pointset)); return ps; } void pointset_destroy (Raw_pointset *ps) { if (ps->points) { free (ps->points); } free (ps); } void pointset_add_point (Raw_pointset *ps, float lm[3]) { ps->num_points ++; pointset_resize (ps, ps->num_points); /* Note: Plastimatch landmarks are in LPS coordinates. Slicer landmarks are in RAS coordinates. Change LPS to RAS (note that LPS == ITK RAI). */ ps->points[(ps->num_points-1)*3 + 0] = - lm[0]; ps->points[(ps->num_points-1)*3 + 1] = - lm[1]; ps->points[(ps->num_points-1)*3 + 2] = lm[2]; } void pointset_add_point_noadjust (Raw_pointset *ps, float lm[3]) { ps->num_points ++; pointset_resize (ps, ps->num_points); /* Note: no RAS to LPS adjustment */ ps->points[(ps->num_points-1)*3 + 0] = lm[0]; ps->points[(ps->num_points-1)*3 + 1] = lm[1]; ps->points[(ps->num_points-1)*3 + 2] = lm[2]; } static Raw_pointset * pointset_load_fcsv (const char *fn) { FILE *fp; Raw_pointset *ps; char s[1024]; fp = fopen (fn, "r"); if (!fp) { return 0; } /* Got an fcsv file. Parse it. */ ps = pointset_create (); while (!feof(fp)) { char *s2; float lm[3]; int land_sel, land_vis; int rc; fgets (s, 1024, fp); if (feof(fp)) break; if (s[0]=='#') continue; // skip the label field assuming it does not contain commas s2 = strchr(s,','); if (!s2) { /* If there is no comma, it is not an fcsv file */ pointset_destroy (ps); fclose (fp); return 0; } rc = sscanf (s2, ",%f,%f,%f,%d,%d\n", &lm[0], &lm[1], &lm[2], &land_sel, &land_vis); if (rc != 5) { /* If there are not 5 numbers, then it is not an fcsv file */ pointset_destroy (ps); fclose (fp); return 0; } ps->num_points ++; pointset_resize (ps, ps->num_points); /* Note: Plastimatch landmarks are in LPS coordinates. Slicer landmarks are in RAS coordinates. Change RAS to LPS (note that LPS == ITK RAI). */ ps->points[(ps->num_points-1)*3 + 0] = - lm[0]; ps->points[(ps->num_points-1)*3 + 1] = - lm[1]; ps->points[(ps->num_points-1)*3 + 2] = lm[2]; } fclose (fp); return ps; } static Raw_pointset * pointset_load_txt (const char *fn) { FILE *fp; Raw_pointset *ps; char s[1024]; fp = fopen (fn, "r"); if (!fp) { return 0; } /* Parse as txt file */ ps = pointset_create (); while (!feof(fp)) { float lm[3]; int rc; fgets (s, 1024, fp); if (feof(fp)) break; if (s[0]=='#') continue; rc = sscanf (s, "%f , %f , %f\n", &lm[0], &lm[1], &lm[2]); if (rc != 3) { rc = sscanf (s, "%f %f %f\n", &lm[0], &lm[1], &lm[2]); } if (rc != 3) { print_and_exit ("Error parsing landmark file: %s\n", fn); } ps->num_points ++; pointset_resize (ps, ps->num_points); /* Assume LPS */ ps->points[(ps->num_points-1)*3 + 0] = lm[0]; ps->points[(ps->num_points-1)*3 + 1] = lm[1]; ps->points[(ps->num_points-1)*3 + 2] = lm[2]; } fclose (fp); return ps; } Raw_pointset* pointset_load (const char *fn) { Raw_pointset *ps; /* First try to load fcsv */ ps = pointset_load_fcsv (fn); if (ps) return ps; /* If that doesn't work, try loading ASCII */ ps = pointset_load_txt (fn); return ps; } static void pointset_save_txt (Raw_pointset* ps, const char *fn) { int i; FILE *fp; fp = fopen (fn, "w"); if (!fp) return; for (i = 0; i < ps->num_points; i++) { fprintf (fp, "%f %f %f\n", ps->points[i*3+0], ps->points[i*3+1], ps->points[i*3+2]); } fclose (fp); } static void pointset_save_fcsv (Raw_pointset* ps, const char *fn) { int i; FILE *fp; fp = fopen (fn, "w"); if (!fp) return; fprintf (fp, "# Fiducial List file %s\n" "# version = 2\n" "# name = plastimatch-fiducials\n" "# numPoints = %d\n" "# symbolScale = 5\n" "# symbolType = 12\n" "# visibility = 1\n" "# textScale = 4.5\n" "# color = 0.4,1,1\n" "# selectedColor = 1,0.5,0.5\n" "# opacity = 1\n" "# ambient = 0\n" "# diffuse = 1\n" "# specular = 0\n" "# power = 1\n" "# locked = 0\n" "# numberingScheme = 0\n" "# columns = label,x,y,z,sel,vis\n", fn, ps->num_points); for (i = 0; i < ps->num_points; i++) { fprintf (fp, "p-%03d,%f,%f,%f,1,1\n", i, - ps->points[i*3+0], - ps->points[i*3+1], ps->points[i*3+2]); } fclose (fp); } void pointset_save_fcsv_by_cluster (Raw_pointset* ps, int *clust_id, int which_cluster, const char *fn) { int i; int symbol; FILE *fp; // symbolType, see //http://www.slicer.org/slicerWiki/index.php/Modules:Fiducials-Documentation-3.4 symbol =which_cluster+2; if (symbol > 13) symbol -=13; fp = fopen (fn, "w"); if (!fp) return; int num_points_in_cluster=0; for (i = 0; i < ps->num_points; i++) { if (clust_id[i] == which_cluster) num_points_in_cluster++; } fprintf (fp, "# Fiducial List file %s\n" "# version = 2\n" "# name = plastimatch-fiducials\n" "# numPoints = %d\n" "# symbolScale = 5\n" "# symbolType = %d\n" "# visibility = 1\n" "# textScale = 4.5\n" "# color = 0.4,1,1\n" "# selectedColor = 1,0.5,0.5\n" "# opacity = 1\n" "# ambient = 0\n" "# diffuse = 1\n" "# specular = 0\n" "# power = 1\n" "# locked = 0\n" "# numberingScheme = 0\n" "# columns = label,x,y,z,sel,vis\n", fn, num_points_in_cluster, symbol); for (i = 0; i < ps->num_points; i++) { if (clust_id[i] == which_cluster) fprintf (fp, "p-%03d-c%02d,%f,%f,%f,1,1\n", i, clust_id[i], - ps->points[i*3+0], - ps->points[i*3+1], ps->points[i*3+2]); } fclose (fp); } void pointset_save (Raw_pointset* ps, const char *fn) { if (extension_is (fn, "fcsv")) { pointset_save_fcsv (ps, fn); } else { pointset_save_txt (ps, fn); } } void pointset_resize (Raw_pointset *ps, int new_size) { ps->num_points = new_size; ps->points = (float*) realloc (ps->points, 3 * (ps->num_points) * sizeof(float)); } void pointset_debug (Raw_pointset* ps) { int i; printf ("Pointset:\n"); for (i = 0; i < ps->num_points; i++) { printf (" %10f %10f %10f\n", ps->points[i*3 + 0], ps->points[i*3 + 1], ps->points[i*3 + 2]); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/raw_pointset.h000066400000000000000000000022071321604176500304210ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _raw_pointset_h_ #define _raw_pointset_h_ #include "plmbase_config.h" typedef struct raw_pointset Raw_pointset; struct raw_pointset { int num_points; float *points; }; PLMBASE_C_API void pointset_add_point ( Raw_pointset *ps, float lm[3] ); PLMBASE_C_API void pointset_add_point_noadjust ( Raw_pointset *ps, float lm[3] ); PLMBASE_C_API Raw_pointset *pointset_create (void); PLMBASE_C_API void pointset_debug (Raw_pointset* ps); PLMBASE_C_API void pointset_destroy (Raw_pointset *ps); PLMBASE_C_API Raw_pointset* pointset_load (const char *fn); PLMBASE_C_API void pointset_resize ( Raw_pointset *ps, int new_size ); PLMBASE_C_API void pointset_save ( Raw_pointset* ps, const char *fn ); PLMBASE_C_API void pointset_save_fcsv_by_cluster ( Raw_pointset* ps, int *clust_id, int which_cluster, const char *fn ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/ray_data.h000066400000000000000000000015701321604176500274710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _ray_data_h_ #define _ray_data_h_ #include "plmbase_config.h" class Ray_data { public: int ap_idx; bool intersects_volume; double ip1[3]; /* Front intersection with volume */ double ip2[3]; /* Back intersection with volume */ double p2[3]; /* Intersection with aperture plane */ double ray[3]; /* Unit vector in direction of ray */ double front_dist; /* Distance from aperture to ip1 */ double back_dist; /* Distance from aperture to ip2 */ double cp[3]; /* Intersection with front clipping plane */ int step_offset; /* Number of steps before reaching k = 0 */ }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/ray_trace.h000066400000000000000000000034731321604176500276620ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _ray_trace_h_ #define _ray_trace_h_ #include "plmbase_config.h" #include "ray_trace_callback.h" class Volume; class Volume_limit; // #define DRR_VERBOSE 1 #define DRR_PLANE_RAY_TOLERANCE 1e-8 #define DRR_STRIDE_TOLERANCE 1e-10 #define DRR_HUGE_DOUBLE 1e10 #define DRR_TOPLANE_TOLERANCE 1e-7 #define DRR_BOUNDARY_TOLERANCE 1e-6 /* GCS FIX: "Temporary" fix against overshooting image boundary when ray tracing. This fix should be replaced with something more robust, such as an explicit bounds check. */ //#define DRR_LEN_TOLERANCE 1e-6 #define DRR_LEN_TOLERANCE 2e-5 #define DRR_MSD_NUM_BINS 60 #define DRR_PREPROCESS_ATTENUATION 1 PLMBASE_C_API void ray_trace_exact ( Volume *vol, /* Input: volume */ Volume_limit *vol_limit, /* Input: min/max coordinates of volume */ Ray_trace_callback callback, /* Input: callback function */ void *callback_data, /* Input: callback function private data */ double *p1in, /* Input: start point for ray */ double *p2in /* Input: end point for ray */ ); PLMBASE_C_API void ray_trace_uniform ( Volume *vol, /* Input: volume */ Volume_limit *vol_limit, /* Input: min/max coordinates of volume */ Ray_trace_callback callback, /* Input: callback function */ void *callback_data, /* Input: callback function private data */ double *p1in, /* Input: start point for ray */ double *p2in, /* Input: end point for ray */ float ray_step /* Input: uniform step size */ ); #endif ray_trace_callback.h000066400000000000000000000007111321604176500314070ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _ray_trace_callback_h_ #define _ray_trace_callback_h_ #include "plmbase_config.h" typedef void (*Ray_trace_callback) ( void *callback_data, size_t vox_index, double vox_len, float vox_value); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/ray_trace_exact.cxx000066400000000000000000000132661321604176500314220ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #if (OPENMP_FOUND) #include #endif #include "plm_math.h" #include "ray_trace.h" #include "volume.h" #include "volume_limit.h" void ray_trace_exact_init_loopvars ( int* ai, /* Output: index */ int* aidir, /* Output: are indices moving up or down? */ double* ao, /* Output: absolute length to next voxel crossing */ double* al, /* Output: length between voxel crossings */ double pt, /* Input: initial intersection of ray with volume */ double ry, /* Input: normalized direction of ray */ double origin, /* Input: origin of volume */ plm_long dim, /* Input: dimension of volume */ double samp /* Input: pixel spacing of volume */ ) { #if DRR_VERBOSE printf ("pt/ry/off/samp: %g %g %g %g\n", pt, ry, origin, samp); #endif *aidir = SIGN (ry) * SIGN (samp); *ai = ROUND_INT ((pt - origin) / samp); *ai = clamp (*ai, 0, (int) dim - 1); *ao = SIGN (ry) * (((*ai) * samp + origin) + (SIGN (ry) * 0.5 * fabs (samp)) - pt); if (fabs(ry) > DRR_STRIDE_TOLERANCE) { *ao = *ao / fabs(ry); *al = fabs(samp) / fabs(ry); } else { *ao = DRR_HUGE_DOUBLE; *al = DRR_HUGE_DOUBLE; } } /* Initialize loop variables. Returns 1 if the segment intersects the volume, and 0 if the segment does not intersect. */ int ray_trace_exact_init ( int *ai_x, int *ai_y, int *ai_z, int *aixdir, int *aiydir, int *aizdir, double *ao_x, double *ao_y, double *ao_z, double *al_x, double *al_y, double *al_z, double *len, Volume* vol, Volume_limit *vol_limit, double* p1, double* p2 ) { double ray[3]; double ip1[3]; double ip2[3]; //double ips[2][4]; /* Test if ray intersects volume */ if (!volume_limit_clip_segment (vol_limit, ip1, ip2, p1, p2)) { return 0; } /* Create the volume intersection points */ vec3_sub3 (ray, p2, p1); vec3_normalize1 (ray); #if defined (DRR_VERBOSE) printf ("ip1 = %g %g %g\n", ip1[0], ip1[1], ip1[2]); printf ("ip2 = %g %g %g\n", ip2[0], ip2[1], ip2[2]); printf ("ray = %g %g %g\n", ray[0], ray[1], ray[2]); #endif /* We'll go from p1 to p2 */ /* Variable notation: ai_x // index of x aixdir // x indices moving up or down? ao_x // absolute length to next voxel crossing al_x // length between voxel crossings */ ray_trace_exact_init_loopvars ( ai_x, aixdir, ao_x, al_x, ip1[0], ray[0], vol->origin[0], vol->dim[0], vol->spacing[0]); ray_trace_exact_init_loopvars ( ai_y, aiydir, ao_y, al_y, ip1[1], ray[1], vol->origin[1], vol->dim[1], vol->spacing[1]); ray_trace_exact_init_loopvars ( ai_z, aizdir, ao_z, al_z, ip1[2], ray[2], vol->origin[2], vol->dim[2], vol->spacing[2]); #if defined (DRR_VERBOSE) printf ("aix = %d aixdir = %d aox = %g alx = %g\n", *ai_x, *aixdir, *ao_x, *al_x); printf ("aiy = %d aiydir = %d aoy = %g aly = %g\n", *ai_y, *aiydir, *ao_y, *al_y); printf ("aiz = %d aizdir = %d aoz = %g alz = %g\n", *ai_z, *aizdir, *ao_z, *al_z); #endif *len = vec3_dist (ip1, ip2); return 1; } void ray_trace_exact ( Volume *vol, /* Input: volume */ Volume_limit *vol_limit, /* Input: min/max coordinates of volume */ Ray_trace_callback callback, /* Input: callback function */ void *callback_data, /* Input: callback function private data */ double *p1in, /* Input: start point for ray */ double *p2in /* Input: end point for ray */ ) { /* Variable notation: ai_x index of x aixdir x indices moving up or down? ao_x absolute length to next voxel crossing al_x length between voxel crossings */ int ai_x, ai_y, ai_z; int aixdir, aiydir, aizdir; double ao_x, ao_y, ao_z; double al_x, al_y, al_z; double len; /* Total length of ray within volume */ double aggr_len = 0.0; /* Length traced so far */ float* img = (float*) vol->img; #if defined (DRR_VERBOSE) printf ("p1in: %f %f %f\n", p1in[0], p1in[1], p1in[2]); printf ("p2in: %f %f %f\n", p2in[0], p2in[1], p2in[2]); #endif if (!ray_trace_exact_init ( &ai_x, &ai_y, &ai_z, &aixdir, &aiydir, &aizdir, &ao_x, &ao_y, &ao_z, &al_x, &al_y, &al_z, &len, vol, vol_limit, p1in, p2in)) { return; } /* We'll go from p1 to p2 */ do { float pix_density; double pix_len; int index = ai_z*vol->dim[0]*vol->dim[1] + ai_y*vol->dim[0] + ai_x; #if defined (DRR_ULTRA_VERBOSE) printf ("(%d %d %d) (%g,%g,%g)\n",ai_x,ai_y,ai_z,ao_x,ao_y,ao_z); printf ("aggr_len = %g, len = %g\n", aggr_len, len); fflush (stdout); #endif pix_density = img[index]; if ((ao_x < ao_y) && (ao_x < ao_z)) { pix_len = ao_x; aggr_len += ao_x; ao_y -= ao_x; ao_z -= ao_x; ao_x = al_x; ai_x += aixdir; } else if ((ao_y < ao_z)) { pix_len = ao_y; aggr_len += ao_y; ao_x -= ao_y; ao_z -= ao_y; ao_y = al_y; ai_y += aiydir; } else { pix_len = ao_z; aggr_len += ao_z; ao_x -= ao_z; ao_y -= ao_z; ao_z = al_z; ai_z += aizdir; } (*callback) (callback_data, index, pix_len, pix_density); } while (aggr_len+DRR_LEN_TOLERANCE < len); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/ray_trace_probe.cxx000066400000000000000000000043761321604176500314270ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #if (OPENMP_FOUND) #include #endif #include "plm_math.h" #include "ray_trace_probe.h" #include "volume.h" #include "volume_limit.h" void ray_trace_probe ( Volume* vol, // INPUT: CT Volume Volume_limit* vol_limit, // INPUT: CT volume bounding box Ray_trace_callback callback, // INPUT: Step Action Function void* callback_data, // INPUT: callback data double* ip1in, // INPUT: Ray Starting Point double* ip2in, // INPUT: Ray Ending Point float ray_depth, // INPUT: depth along ray to probe vol (mm) float ray_idx // INPUT: z-index along ray cast ) { double uv[3]; double ipx[3]; double ps[3]; double ip1[3]; double ip2[3]; int ai[3]; float pix_density; int idx; float* img = (float*) vol->img; /* Test if ray intersects volume */ if (!volume_limit_clip_segment (vol_limit, ip1, ip2, ip1in, ip2in)) { return; } ps[0] = vol->spacing[0]; ps[1] = vol->spacing[1]; ps[2] = vol->spacing[2]; // Get unit vector of ray vec3_sub3 (uv, ip2, ip1); vec3_normalize1 (uv); /* Probe a point along the ray */ // Compute a point along the ray ipx[0] = ip1[0] + uv[0] * ray_depth; ipx[1] = ip1[1] + uv[1] * ray_depth; ipx[2] = ip1[2] + uv[2] * ray_depth; // Compute CT Volume indices @ point ai[0] = (int) floor ((ipx[0] - vol->origin[0] + 0.5 * ps[0]) / ps[0]); ai[1] = (int) floor ((ipx[1] - vol->origin[1] + 0.5 * ps[1]) / ps[1]); ai[2] = (int) floor ((ipx[2] - vol->origin[2] + 0.5 * ps[2]) / ps[2]); if (ai[0] > 0 && ai[0] < vol->dim[0] && ai[1] > 0 && ai[1] < vol->dim[1] && ai[2] > 0 && ai[2] < vol->dim[2]) { idx = ((ai[2]*vol->dim[1] + ai[1]) * vol->dim[0]) + ai[0]; pix_density = img[idx]; (*callback) (callback_data, ray_idx, ray_depth, pix_density); } else { return; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/ray_trace_probe.h000066400000000000000000000017211321604176500310430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _ray_trace_probe_h_ #define _ray_trace_probe_h_ #include "plmbase_config.h" #include "ray_trace_callback.h" class Volume; class Volume_limit; PLMBASE_C_API void ray_trace_probe ( Volume *vol, /* Input: volume */ Volume_limit *vol_limit, /* Input: min/max coordinates of volume */ Ray_trace_callback callback, /* Input: callback function */ void *callback_data, /* Input: callback function private data */ double *p1in, /* Input: start point for ray */ double *p2in, /* Input: end point for ray */ float ray_depth, /* Input: depth along ray to probe */ float ray_idx /* Input: z-idnex along ray cast */ ); #endif ray_trace_uniform.cxx000066400000000000000000000051251321604176500317110ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #if (OPENMP_FOUND) #include #endif #include "interpolate.h" #include "plm_math.h" #include "ray_trace.h" #include "volume.h" #include "volume_limit.h" void ray_trace_uniform ( Volume* vol, // INPUT: CT Volume Volume_limit* vol_limit, // INPUT: CT volume bounding box Ray_trace_callback callback, // INPUT: Step Action Function void* callback_data, // INPUT: callback data double* ip1in, // INPUT: Ray Starting Point double* ip2in, // INPUT: Ray Ending Point float ray_step // INPUT: Uniform ray step size ) { double uv[3]; double ipx[3]; double ps[3]; double ip1[3]; double ip2[3]; double phy_step[3]; float pix_density; double pt; double rlen; int idx; size_t z; float mijk[3]; float li_frac1[3]; float li_frac2[3]; plm_long mijk_f[3]; plm_long mijk_r[3]; float* img = (float*) vol->img; /* Test if ray intersects volume */ if (!volume_limit_clip_segment (vol_limit, ip1, ip2, ip1in, ip2in)) { return; } ps[0] = vol->spacing[0]; ps[1] = vol->spacing[1]; ps[2] = vol->spacing[2]; // Get ray length rlen = vec3_dist (ip1, ip2); // Get unit vector of ray vec3_sub3 (uv, ip2, ip1); vec3_normalize1 (uv); phy_step[0] = uv[0] * ray_step; phy_step[1] = uv[1] * ray_step; phy_step[2] = uv[2] * ray_step; // Trace the ray z = 0; for (pt = 0; pt < rlen; pt += ray_step) { // Compute a point along the ray ipx[0] = ip1[0] + phy_step[0] * z; ipx[1] = ip1[1] + phy_step[1] * z; ipx[2] = ip1[2] + phy_step[2] * z; mijk[0] = (float) ((ipx[0] - vol->origin[0])/ps[0]); mijk[1] = (float) ((ipx[1] - vol->origin[1])/ps[1]); mijk[2] = (float) ((ipx[2] - vol->origin[2])/ps[2]); li_clamp_3d(mijk, mijk_f, mijk_r, li_frac1, li_frac2, vol); idx = volume_index (vol->dim, mijk_f); pix_density = li_value (li_frac1[0], li_frac2[0], li_frac1[1], li_frac2[1], li_frac1[2], li_frac2[2], idx, img, vol); // I am passing the current step along the ray (z) through // vox_index here... not exactly great but not horrible. (*callback) (callback_data, z++, ray_step, pix_density); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rpl_volume.cxx000077500000000000000000002073301321604176500304510ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include "aperture.h" #include "interpolate.h" #include "compiler_warnings.h" #include "file_util.h" #include "logfile.h" #include "mha_io.h" #include "path_util.h" #include "plm_int.h" #include "plm_math.h" #include "plm_image_header.h" #include "proj_matrix.h" #include "proj_volume.h" #include "ray_data.h" #include "ray_trace.h" #include "rpl_volume.h" #include "volume.h" #include "volume_fill.h" #include "volume_limit.h" #include "volume_macros.h" #include "print_and_exit.h" //#define VERBOSE 1 #if VERBOSE static bool global_debug = false; #endif //20140827_YKP //col0 = HU, col1 = Relative stopping power //Table: XiO, ctedproton 2007 provided by Yoost extern const double lookup_PrSTPR_XiO_MGH[][2] ={ -1000.0, 0.01, 0.0, 1.0, 40.0, 1.04, 1000.0, 1.52, 2000.0, 2.02, 3000.0, 2.55, }; extern const double lookup_PrSTPR_XiO_MGH[][2]; static void rpl_callback_accum ( void *callback_data, size_t vox_index, double vox_len, float vox_value); static void rpl_callback_sample ( void *callback_data, size_t vox_index, double vox_len, float vox_value); static void rpl_ray_trace_callback_ct_density ( void *callback_data, size_t vox_index, double vox_len, float vox_value); static void rpl_ray_trace_callback_ct_HU ( void *callback_data, size_t vox_index, double vox_len, float vox_value); static void rpl_ray_trace_callback_PrSTPR ( void *callback_data, size_t vox_index, double vox_len, float vox_value); static void rpl_ray_trace_callback_PrSTPR_XiO_MGH ( void *callback_data, size_t vox_index, double vox_len, float vox_value); static void rpl_ray_trace_callback_range_length ( void *callback_data, size_t vox_index, double vox_len, float vox_value); typedef struct callback_data Callback_data; struct callback_data { Rpl_volume *rpl_vol; /* Radiographic depth volume */ Ray_data *ray_data; /* Data specific to the ray */ int* ires; /* Aperture Dimensions */ int step_offset; /* Number of steps before first ray sample */ double accum; /* Accumulated intensity */ int last_step_completed; /* Last step written to output image */ }; class Rpl_volume_private { public: Proj_volume *proj_vol; Plm_image::Pointer ct; Volume_limit ct_limit; Ray_data *ray_data; // Clipping distances are computed from aperture plane, not from source double front_clipping_dist; double back_clipping_dist; Aperture::Pointer aperture; Rpl_volume_ray_trace_start rvrts; public: Rpl_volume_private () { proj_vol = new Proj_volume; ct = Plm_image::New (); ray_data = 0; front_clipping_dist = DBL_MAX; back_clipping_dist = -DBL_MAX; aperture = Aperture::New (); rvrts = RAY_TRACE_START_AT_RAY_VOLUME_INTERSECTION; } ~Rpl_volume_private () { delete proj_vol; if (ray_data) { delete[] ray_data; } } }; Rpl_volume::Rpl_volume () { d_ptr = new Rpl_volume_private; } Rpl_volume::~Rpl_volume () { delete d_ptr; } void Rpl_volume::set_geometry ( const double src[3], // position of source (mm) const double iso[3], // position of isocenter (mm) const double vup[3], // dir to "top" of projection plane double sid, // dist from proj plane to source (mm) const plm_long image_dim[2], // resolution of image const double image_center[2], // image center (pixels) const double image_spacing[2], // pixel size (mm) const double step_length // spacing between planes ) { double clipping_dist[2] = {sid, sid}; #if defined (commentout) printf ("> src = %f %f %f\n", src[0], src[1], src[2]); printf ("> iso = %f %f %f\n", iso[0], iso[1], iso[2]); printf ("> vup = %f %f %f\n", vup[0], vup[1], vup[2]); printf ("> sid = %f\n", sid); printf ("> idim = %d %d\n", image_dim[0], image_dim[1]); printf ("> ictr = %f %f\n", image_center[0], image_center[1]); printf ("> isp = %f %f\n", image_spacing[0], image_spacing[1]); printf ("> stp = %f\n", step_length); #endif /* This sets everything except the clipping planes. We don't know these until caller tells us the CT volume to compute against. */ d_ptr->proj_vol->set_geometry ( src, iso, vup, sid, image_dim, image_center, image_spacing, clipping_dist, step_length); } void Rpl_volume::clone_geometry (const Rpl_volume *rv) { this->set_geometry ( rv->d_ptr->proj_vol->get_src(), rv->d_ptr->proj_vol->get_iso(), rv->get_aperture()->vup, rv->get_aperture()->get_distance(), rv->get_aperture()->get_dim(), rv->get_aperture()->get_center(), rv->get_aperture()->get_spacing(), rv->d_ptr->proj_vol->get_step_length()); } void Rpl_volume::set_ray_trace_start (Rpl_volume_ray_trace_start rvrts) { printf ("Setting RVRTS = %d\n", (int) rvrts); d_ptr->rvrts = rvrts; } void Rpl_volume::set_ct_volume (Plm_image::Pointer& ct_volume) { d_ptr->ct = ct_volume; /* Compute volume boundary box */ volume_limit_set (&d_ptr->ct_limit, ct_volume->get_volume_float()); } Aperture::Pointer& Rpl_volume::get_aperture () { return d_ptr->aperture; } const Aperture::Pointer& Rpl_volume::get_aperture () const { return d_ptr->aperture; } void Rpl_volume::set_aperture (Aperture::Pointer& ap) { d_ptr->aperture = ap; } const plm_long* Rpl_volume::get_image_dim () { return d_ptr->proj_vol->get_image_dim(); } plm_long Rpl_volume::get_num_steps () { return d_ptr->proj_vol->get_num_steps(); } /* 1D interpolation */ double Rpl_volume::get_value ( plm_long ap_ij[2], /* I: aperture index */ double dist /* I: distance from aperture in mm */ ) const { plm_long idx1, idx2; plm_long ijk[3]; double rg1, rg2, rgdepth, frac; const Proj_volume *proj_vol = this->get_proj_volume (); const Volume *vol = this->get_vol(); float* d_img = (float*) vol->img; if (dist < 0) { return 0.0; } ijk[0] = ap_ij[0]; ijk[1] = ap_ij[1]; ijk[2] = (int) floorf (dist / proj_vol->get_step_length()); /* Depth to step before point */ idx1 = volume_index (vol->dim, ijk); if (idx1 < vol->npix) { rg1 = d_img[idx1]; } else { return 0.0f; } /* Fraction from step before point to point */ frac = (dist - ijk[2] * proj_vol->get_step_length()) / proj_vol->get_step_length(); /* Depth to step after point */ ijk[2]++; idx2 = volume_index (vol->dim, ijk); if (idx2 < vol->npix) { rg2 = d_img[idx2]; } else { rg2 = d_img[idx1]; } /* Radiographic depth, interpolated in depth only */ rgdepth = rg1 + frac * (rg2 - rg1); return rgdepth; } /* 3D interpolation */ double Rpl_volume::get_value ( double ap_ij[2], /* I: aperture index */ double dist /* I: distance from aperture in mm */ ) const { const Proj_volume *proj_vol = this->get_proj_volume (); const Volume *vol = this->get_vol(); if (dist < 0) { return 0.0; } float ijk[3] = { (float) ap_ij[0], (float) ap_ij[1], (float) (dist / proj_vol->get_step_length()) }; float val = vol->get_ijk_value (ijk); return val; } /* Lookup radiological path length to a voxel in world space */ double Rpl_volume::get_value ( const double* ct_xyz /* I: location of voxel in world space */ ) const { int ap_ij[2], ap_idx; double ap_xy[3]; double dist, rgdepth = 0.; bool debug = false; /* A couple of abbreviations */ const plm_long *ires = d_ptr->proj_vol->get_image_dim(); Proj_matrix *pmat = d_ptr->proj_vol->get_proj_matrix(); if (debug) { pmat->debug (); } /* Back project the voxel to the aperture plane */ d_ptr->proj_vol->project (ap_xy, ct_xyz); /* Make sure value is not inf or NaN */ if (!is_number (ap_xy[0]) || !is_number (ap_xy[1])) { return -1; } /* Round to nearest aperture index */ ap_ij[0] = ROUND_INT (ap_xy[0]); ap_ij[1] = ROUND_INT (ap_xy[1]); if (debug) { printf ("ap_xy = %g %g\n", ap_xy[0], ap_xy[1]); } /* Only handle voxels inside the (square) aperture */ if (ap_ij[0] < 0 || ap_ij[0] >= ires[0] || ap_ij[1] < 0 || ap_ij[1] >= ires[1]) { return -1; } /* Look up pre-computed data for this ray */ ap_idx = ap_ij[1] * ires[0] + ap_ij[0]; Ray_data *ray_data = &d_ptr->ray_data[ap_idx]; double *ap_xyz = ray_data->p2; if (debug) { printf ("ap_xyz = %g %g %g\n", ap_xyz[0], ap_xyz[1], ap_xyz[2]); } /* Compute distance from aperture to voxel */ dist = vec3_dist (ap_xyz, ct_xyz); // Subtract off standoff distance. Nearest neighbor aperture index // is used for this calculation. if (d_ptr->rvrts == RAY_TRACE_START_AT_RAY_VOLUME_INTERSECTION) { dist -= ray_data->front_dist; } else { dist -= d_ptr->front_clipping_dist; } /* Retrieve the radiographic depth */ rgdepth = this->get_value (ap_xy, dist); return rgdepth; } void Rpl_volume::set_ct (const Plm_image::Pointer& ct_volume) { d_ptr->ct = ct_volume; } Plm_image::Pointer Rpl_volume::get_ct() { return d_ptr->ct; } void Rpl_volume::set_ct_limit (Volume_limit* ct_limit) { d_ptr->ct_limit.lower_limit[0] = ct_limit->lower_limit[0]; d_ptr->ct_limit.lower_limit[1] = ct_limit->lower_limit[1]; d_ptr->ct_limit.lower_limit[2] = ct_limit->lower_limit[2]; d_ptr->ct_limit.upper_limit[0] = ct_limit->upper_limit[0]; d_ptr->ct_limit.upper_limit[1] = ct_limit->upper_limit[1]; d_ptr->ct_limit.upper_limit[2] = ct_limit->upper_limit[2]; } Volume_limit* Rpl_volume::get_ct_limit() { return &d_ptr->ct_limit; } void Rpl_volume::set_ray_data (Ray_data *ray) { d_ptr->ray_data = ray; } Ray_data* Rpl_volume::get_ray_data() { return d_ptr->ray_data; } void Rpl_volume::set_front_clipping_plane (double front_clip) { d_ptr->front_clipping_dist = front_clip; } double Rpl_volume::get_front_clipping_plane() const { return d_ptr->front_clipping_dist; } void Rpl_volume::set_back_clipping_plane(double back_clip) { d_ptr->back_clipping_dist = back_clip; } double Rpl_volume::get_back_clipping_plane() const { return d_ptr->back_clipping_dist; } double Rpl_volume::get_step_length () const { return d_ptr->proj_vol->get_step_length (); } void Rpl_volume::compute_ray_data () { /* A couple of abbreviations */ Proj_volume *proj_vol = d_ptr->proj_vol; const double *src = proj_vol->get_src(); const double *nrm = proj_vol->get_nrm(); const plm_long *ires = d_ptr->proj_vol->get_image_dim(); Volume *ct_vol = d_ptr->ct->get_vol(); /* Allocate data for each ray */ if (d_ptr->ray_data) delete[] d_ptr->ray_data; d_ptr->ray_data = new Ray_data[ires[0]*ires[1]]; /* Scan through the aperture plane */ for (int r = 0; r < ires[1]; r++) { double r_tgt[3]; double tmp[3]; /* Compute r_tgt = 3d coordinates of first pixel in this row on aperture */ vec3_copy (r_tgt, proj_vol->get_ul_room()); vec3_scale3 (tmp, proj_vol->get_incr_r(), (double) r); vec3_add2 (r_tgt, tmp); for (int c = 0; c < ires[0]; c++) { /* Compute index of aperture pixel */ plm_long ap_idx = r * ires[0] + c; /* Make some aliases */ Ray_data *ray_data = &d_ptr->ray_data[ap_idx]; double *ip1 = ray_data->ip1; double *ip2 = ray_data->ip2; double *p2 = ray_data->p2; double *ray = ray_data->ray; #if VERBOSE global_debug = false; if (r == 49 && (c == 49 || c == 50)) { global_debug = true; } #endif /* Save the aperture index */ ray_data->ap_idx = ap_idx; /* Compute p2 = 3d coordinates of point on aperture */ vec3_scale3 (tmp, proj_vol->get_incr_c(), (double) c); vec3_add3 (p2, r_tgt, tmp); /* Define unit vector in ray direction */ vec3_sub3 (ray, p2, src); vec3_normalize1 (ray); /* Test if ray intersects volume and create intersection points */ ray_data->intersects_volume = false; if (!volume_limit_clip_ray (&d_ptr->ct_limit, ip1, ip2, src, ray)) { continue; } /* If intersect points are before or after aperture. If before, clip them at aperture plane. */ /* First, check the second point */ double tmp[3]; vec3_sub3 (tmp, ip2, p2); if (vec3_dot (tmp, nrm) > 0) { /* If second point is behind aperture, then so is first point, and therefore the ray doesn't intersect the volume. */ continue; } /* OK, by now we know this ray does intersect the volume */ ray_data->intersects_volume = true; #if VERBOSE if (global_debug) { printf ("(%d,%d)\n", r, c); printf ("%d\n", (int) ap_idx); printf ("ap = %f %f %f\n", p2[0], p2[1], p2[2]); printf ("ip1 = %f %f %f\n", ip1[0], ip1[1], ip1[2]); printf ("ip2 = %f %f %f\n", ip2[0], ip2[1], ip2[2]); } #endif /* Compute distance to front intersection point, and set front clipping plane if indicated */ vec3_sub3 (tmp, ip1, p2); if (vec3_dot (tmp, nrm) > 0) { ray_data->front_dist = 0; } else { ray_data->front_dist = vec3_dist (p2, ip1); } if (ray_data->front_dist < d_ptr->front_clipping_dist) { #if defined (commentout) /* GCS FIX. This should not be here. */ // - 0.001 mm to avoid the closest ray to intersect // the volume with a step inferior to its neighbours. // The minimal ray will be the only one to touch // the volume when offset_step = 0. d_ptr->front_clipping_dist = ray_data->front_dist - 0.001; #endif d_ptr->front_clipping_dist = ray_data->front_dist; } /* Compute distance to back intersection point, and set back clipping plane if indicated */ ray_data->back_dist = vec3_dist (p2, ip2); if (ray_data->back_dist > d_ptr->back_clipping_dist) { d_ptr->back_clipping_dist = ray_data->back_dist; } #if VERBOSE if (global_debug) { printf ("fd/bd = %f %f\n", ray_data->front_dist, ray_data->back_dist); } #endif } } } void Rpl_volume::compute_rpl ( bool use_aperture, Ray_trace_callback callback) { /* A couple of abbreviations */ Proj_volume *proj_vol = d_ptr->proj_vol; const double *src = proj_vol->get_src(); int ires[2]; ires[0] = d_ptr->proj_vol->get_image_dim (0); ires[1] = d_ptr->proj_vol->get_image_dim (1); unsigned char *ap_img = 0; if (use_aperture && d_ptr->aperture->have_aperture_image()) { Volume::Pointer ap_vol = d_ptr->aperture->get_aperture_volume (); ap_img = (unsigned char*) ap_vol->img; } Volume *ct_vol = d_ptr->ct->get_vol(); /* Preprocess data by clipping against volume */ this->compute_ray_data (); if (d_ptr->front_clipping_dist == DBL_MAX) { lprintf ("Sorry, total failure intersecting volume\n"); return; } lprintf ("FPD = %f, BPD = %f\n", d_ptr->front_clipping_dist, d_ptr->back_clipping_dist); /* Ahh. Now we can set the clipping planes and allocate the actual volume. */ double clipping_dist[2] = { d_ptr->front_clipping_dist, d_ptr->back_clipping_dist}; d_ptr->proj_vol->set_clipping_dist (clipping_dist); d_ptr->proj_vol->allocate (); /* Scan through the aperture -- second pass */ for (int r = 0; r < ires[1]; r++) { for (int c = 0; c < ires[0]; c++) { /* Compute index of aperture pixel */ plm_long ap_idx = r * ires[0] + c; /* Make some aliases */ Ray_data *ray_data = &d_ptr->ray_data[ap_idx]; /* Compute intersection with front clipping plane */ vec3_scale3 (ray_data->cp, ray_data->ray, d_ptr->front_clipping_dist); vec3_add2 (ray_data->cp, ray_data->p2); #if VERBOSE global_debug = false; if (r == 49 && (c == 49 || c == 50)) { global_debug = true; } if (global_debug) { printf ("Tracing ray (%d,%d)\n", r, c); } #endif /* Check if beamlet is inside aperture, if not we skip ray tracing */ if (ap_img && ap_img[r*ires[0]+c] == 0) { continue; } this->rpl_ray_trace ( ct_vol, ray_data, callback, &d_ptr->ct_limit, src, 0, ires ); } } } void Rpl_volume::compute_rpl_sample (bool use_aperture) { this->compute_rpl (use_aperture, rpl_callback_sample); } void Rpl_volume::compute_rpl_accum (bool use_aperture) { this->compute_rpl (use_aperture, rpl_callback_accum); } /* This function samples the CT into a RPL equivalent geometry. The rpl_volume should be in proj_wed format, not in proj_ct format. */ /* GCS Note: Why do others call compute_ray_data(), but this one does not?*/ void Rpl_volume::compute_rpl_ct_density () { int ires[2]; /* A couple of abbreviations */ Proj_volume *proj_vol = d_ptr->proj_vol; const double *src = proj_vol->get_src(); ires[0] = d_ptr->proj_vol->get_image_dim (0); ires[1] = d_ptr->proj_vol->get_image_dim (1); unsigned char *ap_img = 0; if (d_ptr->aperture->have_aperture_image()) { Volume::Pointer ap_vol = d_ptr->aperture->get_aperture_volume (); ap_img = (unsigned char*) ap_vol->img; } Volume *ct_vol = d_ptr->ct->get_vol(); /* Ahh. Now we can set the clipping planes and allocate the actual volume. */ double clipping_dist[2] = { d_ptr->front_clipping_dist, d_ptr->back_clipping_dist}; d_ptr->proj_vol->set_clipping_dist (clipping_dist); d_ptr->proj_vol->allocate (); /* Scan through the aperture -- second pass */ for (int r = 0; r < ires[1]; r++) { for (int c = 0; c < ires[0]; c++) { /* Compute index of aperture pixel */ plm_long ap_idx = r * ires[0] + c; /* Make some aliases */ Ray_data *ray_data = &d_ptr->ray_data[ap_idx]; /* Compute intersection with front clipping plane */ vec3_scale3 (ray_data->cp, ray_data->ray, d_ptr->front_clipping_dist); vec3_add2 (ray_data->cp, ray_data->p2); #if VERBOSE global_debug = false; if (r == 49 && (c == 49 || c == 50)) { global_debug = true; } if (global_debug) { printf ("Tracing ray (%d,%d)\n", r, c); } #endif /* Check if beamlet is inside aperture, if not we skip ray tracing */ if (ap_img && ap_img[r*ires[0]+c] == 0) { continue; } this->rpl_ray_trace ( ct_vol, /* I: CT volume */ ray_data, /* I: Pre-computed data for this ray */ rpl_ray_trace_callback_ct_density, /* I: callback */ &d_ptr->ct_limit, /* I: CT bounding region */ src, /* I: @ source */ 0, /* I: range compensator thickness */ ires /* I: ray cast resolution */ ); } } } /* This function samples the CT in rpl geometry with HU units */ /* GCS NOTE: It does not check the aperture */ void Rpl_volume::compute_rpl_HU () { int ires[2]; /* A couple of abbreviations */ Proj_volume *proj_vol = d_ptr->proj_vol; const double *src = proj_vol->get_src(); ires[0] = d_ptr->proj_vol->get_image_dim (0); ires[1] = d_ptr->proj_vol->get_image_dim (1); Volume *ct_vol = d_ptr->ct->get_vol(); /* We don't need to do the first pass, as it was already done for the real rpl_volume */ /* Ahh. Now we can set the clipping planes and allocate the actual volume. */ double clipping_dist[2] = { d_ptr->front_clipping_dist, d_ptr->back_clipping_dist}; d_ptr->proj_vol->set_clipping_dist (clipping_dist); d_ptr->proj_vol->allocate (); /* Scan through the aperture -- second pass */ for (int r = 0; r < ires[1]; r++) { for (int c = 0; c < ires[0]; c++) { /* Compute index of aperture pixel */ plm_long ap_idx = r * ires[0] + c; /* Make some aliases */ Ray_data *ray_data = &d_ptr->ray_data[ap_idx]; /* Compute intersection with front clipping plane */ vec3_scale3 (ray_data->cp, ray_data->ray, d_ptr->front_clipping_dist); vec3_add2 (ray_data->cp, ray_data->p2); #if VERBOSE global_debug = false; if (r == 49 && (c == 49 || c == 50)) { global_debug = true; } if (global_debug) { printf ("Tracing ray (%d,%d)\n", r, c); } #endif this->rpl_ray_trace ( ct_vol, /* I: CT volume */ ray_data, /* I: Pre-computed data for this ray */ rpl_ray_trace_callback_ct_HU, /* I: callback */ &d_ptr->ct_limit, /* I: CT bounding region */ src, /* I: @ source */ 0, /* I: range compensator thickness */ ires /* I: ray cast resolution */ ); } } } /* GCS Note: This is different from compute_rpl() functions. It calls compute_ray_data(), allocates, and computes ray_data->cp. */ void Rpl_volume::compute_rpl_void () { /* A couple of abbreviations */ int ires[2]; ires[0] = d_ptr->proj_vol->get_image_dim (0); ires[1] = d_ptr->proj_vol->get_image_dim (1); /* Preprocess data by clipping against volume */ this->compute_ray_data (); if (d_ptr->front_clipping_dist == DBL_MAX) { print_and_exit ("Sorry, total failure intersecting volume (compute_rpl_void)\n"); } lprintf ("FPD = %f, BPD = %f\n", d_ptr->front_clipping_dist, d_ptr->back_clipping_dist); /* Ahh. Now we can set the clipping planes and allocate the actual volume. */ double clipping_dist[2] = { d_ptr->front_clipping_dist, d_ptr->back_clipping_dist}; d_ptr->proj_vol->set_clipping_dist (clipping_dist); d_ptr->proj_vol->allocate (); /* Scan through the aperture -- second pass */ for (int r = 0; r < ires[1]; r++) { for (int c = 0; c < ires[0]; c++) { /* Compute index of aperture pixel */ plm_long ap_idx = r * ires[0] + c; /* Make some aliases */ Ray_data *ray_data = &d_ptr->ray_data[ap_idx]; /* Compute intersection with front clipping plane */ vec3_scale3 (ray_data->cp, ray_data->ray, d_ptr->front_clipping_dist); vec3_add2 (ray_data->cp, ray_data->p2); } } } /* GCS Note: The rgc should be added after ray tracing */ void Rpl_volume::compute_rpl_range_length_rgc () { int ires[2]; /* A couple of abbreviations */ Proj_volume *proj_vol = d_ptr->proj_vol; const double *src = proj_vol->get_src(); ires[0] = d_ptr->proj_vol->get_image_dim (0); ires[1] = d_ptr->proj_vol->get_image_dim (1); float *rc_img = 0; if (d_ptr->aperture->have_range_compensator_image()) { Volume::Pointer rc_vol = d_ptr->aperture->get_range_compensator_volume (); rc_img = (float*) rc_vol->img; } Volume *ct_vol = d_ptr->ct->get_vol(); /* Preprocess data by clipping against volume */ this->compute_ray_data (); if (d_ptr->front_clipping_dist == DBL_MAX) { print_and_exit ("Sorry, total failure intersecting volume\n"); } lprintf ("FPD = %f, BPD = %f\n", d_ptr->front_clipping_dist, d_ptr->back_clipping_dist); /* Ahh. Now we can set the clipping planes and allocate the actual volume. */ double clipping_dist[2] = { d_ptr->front_clipping_dist, d_ptr->back_clipping_dist}; d_ptr->proj_vol->set_clipping_dist (clipping_dist); d_ptr->proj_vol->allocate (); /* Scan through the aperture -- second pass */ for (int r = 0; r < ires[1]; r++) { for (int c = 0; c < ires[0]; c++) { /* Compute index of aperture pixel */ plm_long ap_idx = r * ires[0] + c; /* Make some aliases */ Ray_data *ray_data = &d_ptr->ray_data[ap_idx]; /* Compute intersection with front clipping plane */ vec3_scale3 (ray_data->cp, ray_data->ray, d_ptr->front_clipping_dist); vec3_add2 (ray_data->cp, ray_data->p2); #if VERBOSE global_debug = false; if (r == 49 && (c == 49 || c == 50)) { global_debug = true; } if (global_debug) { printf ("Tracing ray (%d,%d)\n", r, c); } #endif /* Initialize ray trace accum to range compensator thickness */ double rc_thk = 0.; if (rc_img) { rc_thk = rc_img[r*ires[0]+c]; } this->rpl_ray_trace ( ct_vol, /* I: CT volume */ ray_data, /* I: Pre-computed data for this ray */ rpl_ray_trace_callback_range_length, /* I: callback */ &d_ptr->ct_limit, /* I: CT bounding region */ src, /* I: @ source */ rc_thk, /* I: range compensator thickness */ ires /* I: ray cast resolution */ ); } } } /* GCS NOTE: This also does not check the aperture */ void Rpl_volume::compute_rpl_PrSTRP_no_rgc () { /* A couple of abbreviations */ Proj_volume *proj_vol = d_ptr->proj_vol; const double *src = proj_vol->get_src(); int ires[2]; ires[0] = d_ptr->proj_vol->get_image_dim (0); ires[1] = d_ptr->proj_vol->get_image_dim (1); Volume *ct_vol = d_ptr->ct->get_vol(); /* Preprocess data by clipping against volume */ this->compute_ray_data (); if (d_ptr->front_clipping_dist == DBL_MAX) { print_and_exit ("Sorry, total failure intersecting volume (compute_rpl_rglength_wo_rg_compensator)\n"); } lprintf ("FPD = %f, BPD = %f\n", d_ptr->front_clipping_dist, d_ptr->back_clipping_dist); /* Ahh. Now we can set the clipping planes and allocate the actual volume. */ double clipping_dist[2] = { d_ptr->front_clipping_dist, d_ptr->back_clipping_dist}; d_ptr->proj_vol->set_clipping_dist (clipping_dist); d_ptr->proj_vol->allocate (); /* Scan through the aperture -- second pass */ for (int r = 0; r < ires[1]; r++) { for (int c = 0; c < ires[0]; c++) { /* Compute index of aperture pixel */ plm_long ap_idx = r * ires[0] + c; /* Make some aliases */ Ray_data *ray_data = &d_ptr->ray_data[ap_idx]; /* Compute intersection with front clipping plane */ vec3_scale3 (ray_data->cp, ray_data->ray, d_ptr->front_clipping_dist); vec3_add2 (ray_data->cp, ray_data->p2); #if VERBOSE global_debug = false; if (r == 49 && (c == 49 || c == 50)) { global_debug = true; } if (global_debug) { printf ("Tracing ray (%d,%d)\n", r, c); } #endif this->rpl_ray_trace ( ct_vol, /* I: CT volume */ ray_data, /* I: Pre-computed data for this ray */ rpl_ray_trace_callback_PrSTPR, /* I: callback */ &d_ptr->ct_limit, /* I: CT bounding region */ src, /* I: @ source */ 0, /* I: range compensator thickness */ ires /* I: ray cast resolution */ ); } } /* Now we only have a rpl_volume without compensator, from which we need to compute the sigma along this ray */ } double Rpl_volume::compute_farthest_penetrating_ray_on_nrm(float range) { //int dim[3] = { this->get_vol()->dim[0], this->get_vol()->dim[1], this->get_vol()->dim[2]}; const plm_long *dim = this->get_vol()->dim; int idx = 0; double POI[3] = {0.0, 0.0, 0.0}; double tmp[3] = {0.0, 0.0, 0.0}; double dist = 0; double max_dist = 0; double offset = vec3_dist(this->get_proj_volume()->get_src(), this->get_proj_volume()->get_iso()) - this->get_aperture()->get_distance(); float* img = (float*) this->get_vol()->img; for (int apert_idx = 0; apert_idx < dim[0] * dim[1]; apert_idx++) { Ray_data* ray_data = (Ray_data*) &this->get_ray_data()[apert_idx]; for (int s = 0; s < dim[2]; s++) { idx = s * dim[0] * dim[1] + apert_idx; if (s == dim[2]-1 || dim[2] == 0) { max_dist = offset + (double) dim[2] * this->get_vol()->spacing[2]; printf("Warning: Range > ray_length in volume => Some rays might stop outside of the volume image.\n"); printf("position of the maximal range on the z axis: z = %lg\n", max_dist); return max_dist; } if (img[idx] > range) { /* calculation of the length projected on the nrm axis, from the aperture */ vec3_copy(POI, ray_data->cp); vec3_copy(tmp, ray_data->ray); vec3_scale2(tmp, (double)s * this->get_vol()->spacing[2]); vec3_add2(POI, tmp); dist = -vec3_dot(POI, this->get_proj_volume()->get_nrm()); dist = offset + dist; if (dist > max_dist) { max_dist = dist; } break; } } } printf("position of the maximal range on the z axis: z = %lg\n", max_dist); return max_dist; } void Rpl_volume::compute_proj_wed_volume ( Volume *proj_wed_vol, float background) { //A few abbreviations Proj_volume *proj_vol = d_ptr->proj_vol; float *proj_wed_vol_img = (float*) proj_wed_vol->img; /* Get some parameters from the proj volume, calculate src to isocenter distance */ const double *src = proj_vol->get_src(); const double *iso = proj_vol->get_iso(); const double sid_length = proj_vol->get_proj_matrix()->sid; //distance from source to aperture double src_iso_vec[3]; vec3_sub3(src_iso_vec,src,iso); const double src_iso_distance = vec3_len(src_iso_vec); const double ap_iso_distance = src_iso_distance - sid_length; /* Subtract off standoff distance */ //This is the perpendicular "base" distance that we calculate all rgdepths from. double base_rg_dist = ap_iso_distance - d_ptr->front_clipping_dist; //This is the perpendicular "base" distance that we calculate how much //each geometric distance should increase, due to divergence. const double base_dist = proj_vol->get_proj_matrix()->sid; //distance from source to aperture const plm_long *ires = proj_vol->get_image_dim(); plm_long ap_ij[2]; //ray index of rvol plm_long ap_idx = 0; //ray number Ray_data *ray_data; double ray_ap[3]; //vector from src to ray intersection with ap plane double ray_ap_length; //length of vector from src to ray intersection with ap plane double rglength; //length that we insert into get_value for each ray for (ap_ij[1] = 0; ap_ij[1] < ires[1]; ap_ij[1]++) { for (ap_ij[0] = 0; ap_ij[0] < ires[0]; ap_ij[0]++) { /* Ray number */ ap_idx = ap_ij[1] * ires[0] + ap_ij[0]; ray_data = &d_ptr->ray_data[ap_idx]; /* Set each ray to "background", defined in wed_main (default 0) */ proj_wed_vol_img[ap_idx] = background; /* Coordinate of ray intersection with aperture plane */ double *ap_xyz = ray_data->p2; vec3_sub3 (ray_ap, ap_xyz, src); ray_ap_length = vec3_len(ray_ap); rglength = base_rg_dist*(ray_ap_length/base_dist); proj_wed_vol_img[ap_idx] = (float) (this->get_value(ap_ij,rglength)); } } } /* Resample a ct or dose volume into a wed_ct or wed_dose volume */ void Rpl_volume::compute_wed_volume ( Volume *wed_vol, Volume *in_vol, float background) { /* A couple of abbreviations */ Proj_volume *proj_vol = d_ptr->proj_vol; Volume *rvol = proj_vol->get_vol(); float *rvol_img = (float*) rvol->img; float *in_vol_img = (float*) in_vol->img; float *wed_vol_img = (float*) wed_vol->img; const plm_long *ires = proj_vol->get_image_dim(); plm_long wijk[3]; /* Index within wed_volume */ /* Fill the wed_vol with background values */ volume_fill (wed_vol, background); for (wijk[1] = 0; wijk[1] < ires[1]; wijk[1]++) { for (wijk[0] = 0; wijk[0] < ires[0]; wijk[0]++) { /* Compute index of aperture pixel */ plm_long ap_idx = wijk[1] * ires[0] + wijk[0]; bool debug = false; if (ap_idx == (ires[1]/2) * ires[0] + (ires[0] / 2)) { // printf ("DEBUGGING %d %d\n", ires[1], ires[0]); // debug = true; } /* Nothing to do if ray misses volume */ Ray_data *ray_data = &d_ptr->ray_data[ap_idx]; if (!ray_data->intersects_volume) { continue; } /* Keep track of index within rpl_volume */ plm_long rijk[3] = { wijk[0], wijk[1], 0 }; /*Perform the clipping, so the projection volume start points are the same */ double ray_start[3]; double ray_end[3]; /* GCS FIX: Why do this? Is the ray data not already valid? */ if (!volume_limit_clip_segment (&d_ptr->ct_limit, ray_start, ray_end, ray_data->p2, ray_data->ip2)) { printf("Error in ray clipping, exiting...\n"); return; } /* Loop, looking for each output voxel */ for (wijk[2] = 0; wijk[2] < rvol->dim[2]; wijk[2]++) { plm_long widx = volume_index (rvol->dim, wijk); /* Compute the currently required rpl for this step */ double req_rpl = wijk[2] * 1.0; if (debug) printf ("--- (%d,%f)\n", (int) wijk[2], req_rpl); /* Loop through input voxels looking for appropriate value */ double prev_rpl = 0.; while (rijk[2] < rvol->dim[2]) { plm_long ridx = volume_index (rvol->dim, rijk); double curr_rpl = rvol_img[ridx]; if (debug) printf ("(%d,%f)\n", (int) rijk[2], curr_rpl); /* Test if the current input voxel is suitable */ if (curr_rpl > req_rpl) { /* Compute coordinate of matching voxel */ double xyz_init[3]; double xyz[3]; /* Get the distance relative to the reqired rad. length. */ double dist = rijk[2]*proj_vol->get_step_length() - ( (curr_rpl - req_rpl)/(curr_rpl-prev_rpl) ) * proj_vol->get_step_length(); vec3_scale3 (xyz_init, ray_data->ray, dist); vec3_add3 (xyz, xyz_init, ray_start); float in_ijk_f[3]; in_ijk_f[0] = (xyz[0] - in_vol->origin[0]) / in_vol->spacing[0]; in_ijk_f[1] = (xyz[1] - in_vol->origin[1]) / in_vol->spacing[1]; in_ijk_f[2] = (xyz[2] - in_vol->origin[2]) / in_vol->spacing[2]; if (ROUND_PLM_LONG(in_ijk_f[0]) < 0 || ROUND_PLM_LONG(in_ijk_f[0]) >= in_vol->dim[0]) {break;} if (ROUND_PLM_LONG(in_ijk_f[1]) < 0 || ROUND_PLM_LONG(in_ijk_f[1]) >= in_vol->dim[1]) {break;} if (ROUND_PLM_LONG(in_ijk_f[2]) < 0 || ROUND_PLM_LONG(in_ijk_f[2]) >= in_vol->dim[2]) {break;} plm_long ijk_floor[3]; plm_long ijk_round[3]; float li_1[3], li_2[3]; // Compute linear interpolation fractions li_clamp_3d (in_ijk_f, ijk_floor, ijk_round,li_1,li_2,in_vol); plm_long idx_floor; // Find linear indices for moving image idx_floor = volume_index (in_vol->dim, ijk_floor); float value = li_value(li_1[0], li_2[0],li_1[1], li_2[1],li_1[2], li_2[2],idx_floor,in_vol_img,in_vol); /* Write value to output image */ wed_vol_img[widx] = value; /* Suitable voxel found and processed, so move on to the next output voxel */ break; } /* Otherwise, current voxel has insufficient rpl, so move on to the next */ prev_rpl = curr_rpl; rijk[2] ++; } } } } } void Rpl_volume::compute_dew_volume ( Volume *wed_vol, Volume *dew_vol, float background) { double dummy_vec[3] = {0., 0., 0.}; double dummy_length = 0.; double master_coord[2]; //coordinate within a unit box that determines weighting of the final trilinear interpolation double master_square[2][2]; //"box" containing the 4 values used for the final bilinear interpolation //A couple of abbreviations Proj_volume *proj_vol = d_ptr->proj_vol; // Volume *rvol = proj_vol->get_volume(); float *dew_vol_img = (float*) dew_vol->img; float *wed_vol_img = (float*) wed_vol->img; const plm_long *dew_dim = dew_vol->dim; //Get some parameters from the proj volume const plm_long *ires = proj_vol->get_image_dim(); const double *src = proj_vol->get_src(); const double dist = proj_vol->get_proj_matrix()->sid; //distance from source to aperture double src_iso_vec[3]; //vector from source to isocenter proj_vol->get_proj_matrix()->get_nrm(src_iso_vec); vec3_invert(src_iso_vec); // const double *center = proj_vol->get_proj_matrix()->ic; //Contruct aperture "box", in which each voxel's respective //ray intersection must be within. Ray_data *ray_box[4]; ray_box[0] = &d_ptr->ray_data[ 0 ]; ray_box[1] = &d_ptr->ray_data[ ires[0]-1 ]; ray_box[2] = &d_ptr->ray_data[ ires[0]*(ires[1]-1) ]; ray_box[3] = &d_ptr->ray_data[ ires[0]*ires[1]-1 ]; //Compute aperture dimension lengths and normalized axes double ap_axis1[3]; //unit vector of ap. axis 1 double ap_axis2[3]; double ap_res[2]; //resolution of aperture grid vec3_sub3(ap_axis1,ray_box[1]->p2,ray_box[0]->p2); ap_res[0] = vec3_len(ap_axis1)/(ires[0]-1); vec3_normalize1(ap_axis1); vec3_sub3(ap_axis2,ray_box[2]->p2,ray_box[0]->p2); ap_res[1] = vec3_len(ap_axis2)/(ires[1]-1); vec3_normalize1(ap_axis2); Ray_data *ray_adj[4]; //the 4 rays in rpl space that border each coordinate double ray_adj_len; //calculated length each adjacent ray to the voxel double rad_depth_input; //input length to calculate rgdepth double ray_start[3]; double ray_end[3]; plm_long wijk[3]; //index within wed_volume plm_long ap_ij[2]; //ray indox of rvol plm_long dijk[3]; //Index within dew_volume plm_long didx; //image index within dew_volume bool skipflag; double coord[3]; //coordinate within dew_volume double ap_coord[3]; //coordinate in aperture plane from source double ap_coord_plane[2]; //transformed, 2-d aperture coordinate of each voxel ray double coord_vec[3]; //vector along source to coordinate double unit_coord_vec[3]; //unit vector along source to coordinate double ap_coord_vec[3]; //vector along source to coordinate, terminated at ap. plane double adj_ray_coord[3]; //adjacent ray vector, used to compute rad. length double dummy_adj_ray[3]; double coord_ap_len; //distance from coordinate to aperture double dummy_lin_ex; plm_long dummy_index1; plm_long dummy_index2; plm_long ray_lookup[4][2]; //quick lookup table for ray coordinates for rijk input double ray_rad_len[4]; //radiation length of each ray for (dijk[0] = 0; dijk[0] != dew_dim[0]; ++dijk[0]) { coord[0] = dijk[0]*dew_vol->spacing[0]+dew_vol->origin[0]; for (dijk[1] = 0; dijk[1] != dew_dim[1]; ++dijk[1]) { coord[1] = dijk[1]*dew_vol->spacing[1]+dew_vol->origin[1]; for (dijk[2] = 0; dijk[2] != dew_dim[2]; ++dijk[2]) { coord[2] = dijk[2]*dew_vol->spacing[2]+dew_vol->origin[2]; didx = volume_index (dew_dim, dijk); //Set the default to background. dew_vol_img[didx] = background; vec3_sub3(coord_vec,coord,src); //Determine the vector to this voxel from the source vec3_copy(unit_coord_vec,coord_vec); vec3_normalize1(unit_coord_vec); //Get unit vector from source to voxel coord_ap_len = dist/vec3_dot(unit_coord_vec,src_iso_vec); //trig + dot product for distance vec3_copy(ap_coord_vec,unit_coord_vec); vec3_scale2(ap_coord_vec, coord_ap_len); //calculate vector from source to aperture plane vec3_add3(ap_coord,ap_coord_vec,src); //calculate vector from origin to aperture plane //Some math will fail if we try to compute nonsensical values of the volume //between the source and aperture. if (coord_ap_len>=vec3_len(coord_vec)) {continue;} //As ap_coord is on the proj. plane, then check the 6 coord. boundaries //We also don't know which coordinates are larger depending on the orientation of //the projection plane, so account for that. skipflag = false; for (int i=0;i!=3;++i) { if(ray_box[0]->p2[i] >= ray_box[3]->p2[i]) { if ( !( (ap_coord[i] <= ray_box[0]->p2[i]) && (ap_coord[i] >= ray_box[3]->p2[i]) ) ) {skipflag = true; break;} } else { if ( !( (ap_coord[i] >= ray_box[0]->p2[i]) && (ap_coord[i] <= ray_box[3]->p2[i]) ) ) {skipflag = true; break;} } } if (skipflag) {continue;} for (int i=0;i!=4;++i) {master_square[i/2][i%2] = background;} //Now we must find the projection of the point on the two aperture axes //Do this by calculating the closest point along both vec3_sub3(dummy_vec,ap_coord,ray_box[0]->p2); dummy_length = vec3_len(dummy_vec); vec3_normalize1(dummy_vec); ap_coord_plane[0] = vec3_dot(dummy_vec,ap_axis1)*dummy_length; ap_coord_plane[1] = vec3_dot(dummy_vec,ap_axis2)*dummy_length; master_coord[0] = ap_coord_plane[0]/ap_res[0] - floor(ap_coord_plane[0]/ap_res[0]); master_coord[1] = ap_coord_plane[1]/ap_res[1] - floor(ap_coord_plane[1]/ap_res[1]); //Get the 4 adjacent rays relative to the aperature coordinates int base_ap_coord = (int) (floor(ap_coord_plane[1]/ap_res[1])*ires[0] + floor(ap_coord_plane[0]/ap_res[0])); ray_adj[0] = &d_ptr->ray_data[ base_ap_coord ]; ray_adj[1] = &d_ptr->ray_data[ base_ap_coord + 1 ]; ray_adj[2] = &d_ptr->ray_data[ base_ap_coord + ires[0] ]; ray_adj[3] = &d_ptr->ray_data[ base_ap_coord + ires[0] + 1 ]; //Compute ray indices for later rpl calculations. ray_lookup[0][0] = floor(ap_coord_plane[0]/ap_res[0]); ray_lookup[0][1] = floor(ap_coord_plane[1]/ap_res[1]); ray_lookup[1][0] = floor(ap_coord_plane[0]/ap_res[0]); ray_lookup[1][1] = floor(ap_coord_plane[1]/ap_res[1]) + 1; ray_lookup[2][0] = floor(ap_coord_plane[0]/ap_res[0]) + 1; ray_lookup[2][1] = floor(ap_coord_plane[1]/ap_res[1]); ray_lookup[3][0] = floor(ap_coord_plane[0]/ap_res[0]) + 1; ray_lookup[3][1] = floor(ap_coord_plane[1]/ap_res[1]) + 1; //Now compute the distance along each of the 4 rays //Distance chosen to be the intersection of each ray with the plane that both //contains the voxel and is normal to the aperture plane. for (int i=0;i!=4;++i) { //Compute distance along each ray. //Vector along ray from source to aperture vec3_sub3(dummy_adj_ray,ray_adj[i]->p2,src); //Compute length, then ray from "ray start" to target position, using //ratio of coordinate-aperture to coordinate lengths. ray_adj_len = (vec3_len(coord_vec)/coord_ap_len)*vec3_len(dummy_adj_ray); vec3_scale3(adj_ray_coord,ray_adj[i]->ray,ray_adj_len); if (!volume_limit_clip_segment (&d_ptr->ct_limit, ray_start, ray_end, ray_adj[i]->p2, ray_adj[i]->ip2)) { printf("Error in ray clipping, exiting...\n"); return; } vec3_add2(adj_ray_coord,src); vec3_sub2(adj_ray_coord,ray_start); rad_depth_input = vec3_len(adj_ray_coord); //Now look up the radiation length, using the provided function, //knowing the ray and the length along it. ap_ij[0] = ray_lookup[i][0]; ap_ij[1] = ray_lookup[i][1]; /* GCS FIX: I think the ray_lookup stuff is 3D interpolation, should reduce this code to use the 3D interpolated version of get_value() */ ray_rad_len[i] = this->get_value (ap_ij, rad_depth_input); //Set each corner to background. master_square[i/2][i%2] = background; //Now, with the radiation length, extract the two dose values on either side //Check the borders - rvol should have an extra "border" for this purpose. //If any rays are these added borders, it is outside dose and is background if ( (ray_lookup[i][0]==0) || (ray_lookup[i][0]==ires[0]-1) || (ray_lookup[i][1]==0) || (ray_lookup[i][1]==ires[1]-1) ) {continue;} //Set radiation lengths of 0 to background. //While this is a boundary, keeps dose values from being assigned //everywhere that rad depth is 0 (for example, the air before the volume). if (ray_rad_len[i]<=0.) {continue;} else { dummy_lin_ex = ray_rad_len[i]-floor(ray_rad_len[i]); wijk[0] = (ray_lookup[i][0] - 1)/wed_vol->spacing[0]; wijk[1] = (ray_lookup[i][1] - 1)/wed_vol->spacing[1]; //wijk[0] = ray_lookup[i][0] - 1; //wijk[1] = ray_lookup[i][1] - 1; //Needed if dew dimensions are not automatically set by wed in wed_main. //wijk[0] = ((ray_lookup[i][0] - 1) - wed_vol->origin[0])/wed_vol->spacing[0]; //wijk[1] = ((ray_lookup[i][1] - 1) - wed_vol->origin[1])/wed_vol->spacing[1]; if (wijk[0] < 0 || wijk[0] >= wed_vol->dim[0]) {break;} if (wijk[1] < 0 || wijk[1] >= wed_vol->dim[1]) {break;} wijk[2] = (int) ((floor(ray_rad_len[i])) - wed_vol->origin[2])/wed_vol->spacing[2]; if (wijk[2] < 0) {break;} dummy_index1 = volume_index ( wed_vol->dim, wijk ); wijk[2] = (int) ((ceil(ray_rad_len[i])) - wed_vol->origin[2])/wed_vol->spacing[2]; if (wijk[2] >= wed_vol->dim[2]) {break;} dummy_index2 = volume_index ( wed_vol->dim, wijk ); master_square[i/2][i%2] = wed_vol_img[dummy_index1] * (1-dummy_lin_ex) + wed_vol_img[dummy_index2] * dummy_lin_ex; } } //Bilear interpolation from the square of wed dose ray values dew_vol_img[didx] = (float) ( master_square[0][0]*(1-master_coord[0])*(1-master_coord[1]) + master_square[0][1]*(1-master_coord[0])*(master_coord[1]) + master_square[1][0]*(master_coord[0])*(1-master_coord[1]) + master_square[1][1]*(master_coord[0])*(master_coord[1]) ); } } } } void Rpl_volume::compute_volume_aperture(Aperture::Pointer ap) { int dim[3] = {(int) this->get_vol()->dim[0], (int) this->get_vol()->dim[1], (int) this->get_vol()->dim[2]}; float* ap_vol_img = (float*) this->get_vol()->img; Volume::Pointer ap_vol = ap->get_aperture_volume (); unsigned char *ap_img = (unsigned char*) ap_vol->img; int idx = 0; for(int i = 0; i < dim[0] * dim[1]; i++) { for(int j = 0; j < dim[2]; j++) { idx = j * dim[0] * dim[1] + i; if ((float) ap_img[i] == 1) { ap_vol_img[idx] = 1; } else { ap_vol_img[idx] = 0; } } } } // In this new version the range compensator is added later in the code depending on the algorithm void Rpl_volume::apply_beam_modifiers () { Volume::Pointer ap_vol = d_ptr->aperture->get_aperture_volume (); unsigned char *ap_img = (unsigned char*) ap_vol->img; Volume *proj_vol = d_ptr->proj_vol->get_vol(); float *proj_img = (float*) proj_vol->img; /* For each ray in aperture */ const plm_long *ires = d_ptr->proj_vol->get_image_dim(); printf ("ires = %d %d\n", ires[0], ires[1]); printf ("proj_vol dim = %d %d %d\n", (int) proj_vol->dim[0], (int) proj_vol->dim[1], (int) proj_vol->dim[2]); int ap_nvox = ires[0] * ires[1]; for (int r = 0; r < ires[1]; r++) { for (int c = 0; c < ires[0]; c++) { /* Get aperture and rc values */ plm_long ap_idx = r * ires[0] + c; float ap_val = (float) ap_img[ap_idx]; /* For each voxel in ray */ for (int z = 0; z < proj_vol->dim[2]; z++) { /* Adjust value of voxel */ plm_long vol_idx = z * ap_nvox + ap_idx; proj_img[vol_idx] = ap_val * (proj_img[vol_idx]); } } } } Volume* Rpl_volume::get_vol () { return d_ptr->proj_vol->get_vol (); } const Volume* Rpl_volume::get_vol () const { return d_ptr->proj_vol->get_vol (); } Proj_volume* Rpl_volume::get_proj_volume () { return d_ptr->proj_vol; } const Proj_volume* Rpl_volume::get_proj_volume () const { return d_ptr->proj_vol; } void Rpl_volume::save (const char *filename) { std::string fn_base = strip_extension_if (filename, "rpl"); std::string rpl_vol_fn = fn_base + ".rpl"; /* Save proj volume */ std::string proj_vol_fn = fn_base + ".projv"; d_ptr->proj_vol->save_projv (proj_vol_fn); /* Save ray data */ if (d_ptr->ray_data) { std::string raydata_fn = fn_base + ".raydata"; FILE *fp = plm_fopen (raydata_fn, "wb"); const plm_long *ires = d_ptr->proj_vol->get_image_dim(); for (int r = 0; r < ires[1]; r++) { for (int c = 0; c < ires[0]; c++) { int ap_idx = r * ires[0] + c; Ray_data *rd = &d_ptr->ray_data[ap_idx]; fprintf (fp, "%d %g %g %g %g %g %g %g %g %g " "%g %g %g %g %g %g %g %g %d\n", rd->ap_idx, rd->ip1[0], rd->ip1[1], rd->ip1[2], rd->ip2[0], rd->ip2[1], rd->ip2[2], rd->p2[0], rd->p2[1], rd->p2[2], rd->ray[0], rd->ray[1], rd->ray[2], rd->front_dist, rd->back_dist, rd->cp[0], rd->cp[1], rd->cp[2], rd->step_offset); } } fclose (fp); } /* Don't save aperture (right?) */ /* Don't save CT image (right?) */ /* Save remaining private data */ FILE *fp = plm_fopen (rpl_vol_fn, "wb"); fprintf (fp, "front_clipping_dist = %g\n", d_ptr->front_clipping_dist); fprintf (fp, "back_clipping_dist = %g\n", d_ptr->back_clipping_dist); fprintf (fp, "volume_limit = %g %g %g %g %g %g %d %d %d\n", d_ptr->ct_limit.lower_limit[0], d_ptr->ct_limit.lower_limit[1], d_ptr->ct_limit.lower_limit[2], d_ptr->ct_limit.upper_limit[0], d_ptr->ct_limit.upper_limit[1], d_ptr->ct_limit.upper_limit[2], d_ptr->ct_limit.dir[0], d_ptr->ct_limit.dir[1], d_ptr->ct_limit.dir[2]); fclose (fp); } void Rpl_volume::save (const std::string& filename) { this->save (filename.c_str()); } void Rpl_volume::save_img (const char *filename) { d_ptr->proj_vol->save_img (filename); } void Rpl_volume::save_img (const std::string& filename) { this->save_img (filename.c_str()); } void Rpl_volume::load_rpl (const char *filename) { printf ("Loading rpl\n"); std::string fn_base = strip_extension_if (filename, "rpl"); std::string proj_vol_fn = fn_base + ".projv"; printf ("-> %s\n-> %s-> %s\n", filename, fn_base.c_str(), proj_vol_fn.c_str()); d_ptr->proj_vol->load_projv (proj_vol_fn); printf ("Done.\n"); } void Rpl_volume::load_rpl (const std::string& filename) { this->load_rpl (filename.c_str()); } void Rpl_volume::load_img (const char *filename) { d_ptr->proj_vol->load_img (filename); } void Rpl_volume::load_img (const std::string& filename) { this->load_img (filename.c_str()); } float compute_PrSTPR_from_HU(float CT_HU) { return compute_PrSTPR_Schneider_weq_from_HU(CT_HU); } float compute_PrSTPR_Schneider_weq_from_HU (float CT_HU) // From Schneider's paper: Phys. Med. Biol.41 (1996) 111–124 { if (CT_HU <= -1000) { return 0.00106; } else if (CT_HU > -1000 && CT_HU <= 0) { return (1 - 0.00106) / 1000 * CT_HU + 1; } else if (CT_HU > 0 && CT_HU <= 41.46) { return .001174 * CT_HU + 1; } else { return .0005011 * CT_HU + 1.0279; } } float compute_PrSTRP_XiO_MGH_weq_from_HU (float CT_HU) //YKP, Linear interpolation { double minHU = -1000.0; double maxHU = 3000.0; if (CT_HU <= minHU) CT_HU = minHU; else if (CT_HU >= maxHU) CT_HU = maxHU; double CT_HU1 = minHU; double CT_HU2 = minHU; double RSP1 = 0; double RSP2 = 0; double interpolated_RSP = 0.0; int i=0; if (CT_HU >minHU) { while (CT_HU >= CT_HU1) { CT_HU1 = lookup_PrSTPR_XiO_MGH[i][0]; RSP1 = lookup_PrSTPR_XiO_MGH[i][1]; if (CT_HU >= CT_HU1) { CT_HU2 = CT_HU1; RSP2 = RSP1; } i++; } if ((CT_HU1-CT_HU2) == 0) interpolated_RSP = 0.0; else interpolated_RSP = (RSP2+(CT_HU-CT_HU2)*(RSP1-RSP2)/(CT_HU1-CT_HU2)); } else { interpolated_RSP = 0.0; } return interpolated_RSP; } float compute_PrWER_from_HU(float CT_HU) { return compute_PrSTPR_from_HU(CT_HU) / compute_density_from_HU(CT_HU); } float compute_density_from_HU (float CT_HU) // from Schneider's paper: Phys. Med. Biol.41 (1996) 111–124 { if(CT_HU <= -1000) { return 0.001205; } else if (CT_HU > -1000 && CT_HU <= 65.64) { return (1-.001205)/1000 * CT_HU + 1; } else { return .0006481 * CT_HU + 1.0231; } } void Rpl_volume::rpl_ray_trace ( Volume *ct_vol, /* I: CT volume */ Ray_data *ray_data, /* I: Pre-computed data for this ray */ Ray_trace_callback callback, /* I: Callback function */ Volume_limit *vol_limit, /* I: CT bounding region */ const double *src, /* I: @ source */ double rc_thk, /* I: range compensator thickness */ int* ires /* I: ray cast resolution */ ) { Callback_data cd; if (!ray_data->intersects_volume) { return; } /* Initialize callback data for this ray */ cd.rpl_vol = this; cd.ray_data = ray_data; cd.accum = rc_thk; cd.ires = ires; // Figure out location of, and number of steps to first step within volume double first_loc[3]; if (d_ptr->rvrts == RAY_TRACE_START_AT_RAY_VOLUME_INTERSECTION) { ray_data->step_offset = cd.step_offset = 0; } else { ray_data->step_offset = cd.step_offset = (int) floor (ray_data->front_dist - d_ptr->front_clipping_dist) / d_ptr->proj_vol->get_step_length (); } double tmp[3]; vec3_scale3 (tmp, ray_data->ray, cd.step_offset * d_ptr->proj_vol->get_step_length ()); vec3_add3 (first_loc, ray_data->p2, tmp); #if VERBOSE if (global_debug) { printf ("front_dist = %f\n", ray_data->front_dist); printf ("front_clip = %f\n", d_ptr->front_clipping_dist); printf ("dist = %f\n", dist); printf ("step_offset = %d\n", cd.step_offset); printf ("first_loc = (%f, %f, %f)\n", first_loc[0], first_loc[1], first_loc[2]); printf ("ip2 = (%f, %f, %f)\n", ray_data->ip2[0], ray_data->ip2[1], ray_data->ip2[2]); printf ("rlen = %g\n", vec3_dist (first_loc, ray_data->ip2)); } #endif /* get radiographic depth along ray */ ray_trace_uniform ( ct_vol, // INPUT: CT volume vol_limit, // INPUT: CT volume bounding box callback, // INPUT: step action Function &cd, // INPUT: callback data first_loc, // INPUT: ray starting point ray_data->ip2, // INPUT: ray ending point d_ptr->proj_vol->get_step_length()); // INPUT: uniform ray step size /* Ray tracer will stop short of rpl volume for central rays. We should continue padding the remaining voxels */ float *depth_img = (float*) this->get_vol()->img; for (int s = cd.last_step_completed+1; s < this->get_vol()->dim[2]; s++) { int ap_nvox = cd.ires[0] * cd.ires[1]; //printf ("Extending step %d\n", s); depth_img[ap_nvox*s + ray_data->ap_idx] = cd.accum; } } static void rpl_callback_accum ( void *callback_data, size_t vox_index, double vox_len, float vox_value ) { Callback_data *cd = (Callback_data *) callback_data; Rpl_volume *rpl_vol = cd->rpl_vol; Ray_data *ray_data = cd->ray_data; float *depth_img = (float*) rpl_vol->get_vol()->img; int ap_idx = ray_data->ap_idx; int ap_area = cd->ires[0] * cd->ires[1]; size_t step_num = vox_index + cd->step_offset; cd->accum += vox_len * vox_value; #if VERBOSE if (global_debug) { printf ("%d %4d: %20g %20g\n", ap_idx, (int) step_num, vox_value, cd->accum); printf ("dim = %d %d %d\n", (int) rpl_vol->get_vol()->dim[0], (int) rpl_vol->get_vol()->dim[1], (int) rpl_vol->get_vol()->dim[2]); printf ("ap_area = %d, ap_idx = %d, vox_len = %g\n", ap_area, (int) ap_idx, vox_len); } #endif cd->last_step_completed = step_num; /* GCS FIX: I have a rounding error somewhere -- maybe step_num starts at 1? Or maybe proj_vol is not big enough? This is a workaround until I can fix. */ if ((plm_long) step_num >= rpl_vol->get_vol()->dim[2]) { return; } depth_img[ap_area*step_num + ap_idx] = cd->accum; } static void rpl_callback_sample ( void *callback_data, size_t vox_index, double vox_len, float vox_value ) { Callback_data *cd = (Callback_data *) callback_data; Rpl_volume *rpl_vol = cd->rpl_vol; Ray_data *ray_data = cd->ray_data; float *depth_img = (float*) rpl_vol->get_vol()->img; int ap_idx = ray_data->ap_idx; int ap_area = cd->ires[0] * cd->ires[1]; size_t step_num = vox_index + cd->step_offset; cd->accum = 0; #if VERBOSE if (global_debug) { printf ("%d %4d: %20g %20g\n", ap_idx, (int) step_num, vox_value, cd->accum); printf ("dim = %d %d %d\n", (int) rpl_vol->get_vol()->dim[0], (int) rpl_vol->get_vol()->dim[1], (int) rpl_vol->get_vol()->dim[2]); printf ("ap_area = %d, ap_idx = %d, vox_len = %g\n", ap_area, (int) ap_idx, vox_len); } #endif cd->last_step_completed = step_num; /* GCS FIX: I have a rounding error somewhere -- maybe step_num starts at 1? Or maybe proj_vol is not big enough? This is a workaround until I can fix. */ if ((plm_long) step_num >= rpl_vol->get_vol()->dim[2]) { return; } depth_img[ap_area*step_num + ap_idx] = vox_value; } static void rpl_ray_trace_callback_ct_HU ( void *callback_data, size_t vox_index, double vox_len, float vox_value ) { Callback_data *cd = (Callback_data *) callback_data; Rpl_volume *rpl_vol = cd->rpl_vol; Ray_data *ray_data = cd->ray_data; float *depth_img = (float*) rpl_vol->get_vol()->img; int ap_idx = ray_data->ap_idx; int ap_area = cd->ires[0] * cd->ires[1]; size_t step_num = vox_index + cd->step_offset; cd->accum = 0; #if VERBOSE if (global_debug) { printf ("%d %4d: %20g %20g\n", ap_idx, (int) step_num, vox_value, cd->accum); printf ("dim = %d %d %d\n", (int) rpl_vol->get_vol()->dim[0], (int) rpl_vol->get_vol()->dim[1], (int) rpl_vol->get_vol()->dim[2]); printf ("ap_area = %d, ap_idx = %d, vox_len = %g\n", ap_area, (int) ap_idx, vox_len); } #endif cd->last_step_completed = step_num; /* GCS FIX: I have a rounding error somewhere -- maybe step_num starts at 1? Or maybe proj_vol is not big enough? This is a workaround until I can fix. */ if ((plm_long) step_num >= rpl_vol->get_vol()->dim[2]) { return; } depth_img[ap_area*step_num + ap_idx] = vox_value; } static void rpl_ray_trace_callback_ct_density ( void *callback_data, size_t vox_index, double vox_len, float vox_value ) { Callback_data *cd = (Callback_data *) callback_data; Rpl_volume *rpl_vol = cd->rpl_vol; Ray_data *ray_data = cd->ray_data; float *depth_img = (float*) rpl_vol->get_vol()->img; int ap_idx = ray_data->ap_idx; int ap_area = cd->ires[0] * cd->ires[1]; size_t step_num = vox_index + cd->step_offset; cd->accum = 0; #if VERBOSE if (global_debug) { printf ("%d %4d: %20g %20g\n", ap_idx, (int) step_num, vox_value, cd->accum); printf ("dim = %d %d %d\n", (int) rpl_vol->get_vol()->dim[0], (int) rpl_vol->get_vol()->dim[1], (int) rpl_vol->get_vol()->dim[2]); printf ("ap_area = %d, ap_idx = %d, vox_len = %g\n", ap_area, (int) ap_idx, vox_len); } #endif cd->last_step_completed = step_num; /* GCS FIX: I have a rounding error somewhere -- maybe step_num starts at 1? Or maybe proj_vol is not big enough? This is a workaround until I can fix. */ if ((plm_long) step_num >= rpl_vol->get_vol()->dim[2]) { return; } depth_img[ap_area*step_num + ap_idx] = compute_density_from_HU(vox_value); } static void rpl_ray_trace_callback_PrSTPR ( void *callback_data, size_t vox_index, double vox_len, float vox_value ) { Callback_data *cd = (Callback_data *) callback_data; Rpl_volume *rpl_vol = cd->rpl_vol; Ray_data *ray_data = cd->ray_data; float *depth_img = (float*) rpl_vol->get_vol()->img; int ap_idx = ray_data->ap_idx; int ap_area = cd->ires[0] * cd->ires[1]; size_t step_num = vox_index + cd->step_offset; cd->accum += vox_len * compute_PrSTPR_from_HU (vox_value); //vox_value = CT_HU #if VERBOSE if (global_debug) { printf ("%d %4d: %20g %20g\n", ap_idx, (int) step_num, vox_value, cd->accum); printf ("dim = %d %d %d\n", (int) rpl_vol->get_vol()->dim[0], (int) rpl_vol->get_vol()->dim[1], (int) rpl_vol->get_vol()->dim[2]); printf ("ap_area = %d, ap_idx = %d, vox_len = %g\n", ap_area, (int) ap_idx, vox_len); } #endif cd->last_step_completed = step_num; /* GCS FIX: I have a rounding error somewhere -- maybe step_num starts at 1? Or maybe proj_vol is not big enough? This is a workaround until I can fix. */ if ((plm_long) step_num >= rpl_vol->get_vol()->dim[2]) { return; } depth_img[ap_area*step_num + ap_idx] = cd->accum; } static void rpl_ray_trace_callback_range_length ( void *callback_data, size_t vox_index, double vox_len, float vox_value ) { Callback_data *cd = (Callback_data *) callback_data; Rpl_volume *rpl_vol = cd->rpl_vol; Ray_data *ray_data = cd->ray_data; float *depth_img = (float*) rpl_vol->get_vol()->img; int ap_idx = ray_data->ap_idx; int ap_area = cd->ires[0] * cd->ires[1]; size_t step_num = vox_index + cd->step_offset; cd->accum += vox_len * compute_density_from_HU (vox_value); //vox_value = CT_HU #if VERBOSE if (global_debug) { printf ("%d %4d: %20g %20g\n", ap_idx, (int) step_num, vox_value, cd->accum); printf ("dim = %d %d %d\n", (int) rpl_vol->get_vol()->dim[0], (int) rpl_vol->get_vol()->dim[1], (int) rpl_vol->get_vol()->dim[2]); printf ("ap_area = %d, ap_idx = %d, vox_len = %g\n", ap_area, (int) ap_idx, vox_len); } #endif cd->last_step_completed = step_num; /* GCS FIX: I have a rounding error somewhere -- maybe step_num starts at 1? Or maybe proj_vol is not big enough? This is a workaround until I can fix. */ if ((plm_long) step_num >= rpl_vol->get_vol()->dim[2]) { return; } depth_img[ap_area*step_num + ap_idx] = cd->accum; } //Added by YKPark. Relative stopping power-based water eq. path length. Valid for 20 MeV ~ 240 MeV proton beam //t_w = t_m * rel. density * SP ratio(m to w) = t_m*RSP static void rpl_ray_trace_callback_RSP ( void *callback_data, size_t vox_index, double vox_len, float vox_value ) { Callback_data *cd = (Callback_data *) callback_data; Rpl_volume *rpl_vol = cd->rpl_vol; Ray_data *ray_data = cd->ray_data; float *depth_img = (float*) rpl_vol->get_vol()->img; int ap_idx = ray_data->ap_idx; int ap_area = cd->ires[0] * cd->ires[1]; size_t step_num = vox_index + cd->step_offset; cd->accum += vox_len * compute_PrSTRP_XiO_MGH_weq_from_HU (vox_value); //vox_value = CT_HU #if VERBOSE if (global_debug) { printf ("%d %4d: %20g %20g\n", ap_idx, (int) step_num, vox_value, cd->accum); printf ("dim = %d %d %d\n", (int) rpl_vol->get_vol()->dim[0], (int) rpl_vol->get_vol()->dim[1], (int) rpl_vol->get_vol()->dim[2]); printf ("ap_area = %d, ap_idx = %d, vox_len = %g\n", ap_area, (int) ap_idx, vox_len); } #endif cd->last_step_completed = step_num; /* GCS FIX: I have a rounding error somewhere -- maybe step_num starts at 1? Or maybe proj_vol is not big enough? This is a workaround until I can fix. */ if ((plm_long) step_num >= rpl_vol->get_vol()->dim[2]) { return; } depth_img[ap_area*step_num + ap_idx] = cd->accum; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rpl_volume.h000077500000000000000000000116531321604176500300770ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rpl_volume_h_ #define _rpl_volume_h_ #include "plmbase_config.h" #include #include "aperture.h" #include "plm_image.h" #include "ray_trace_callback.h" #include "smart_pointer.h" #define PMMA_DENSITY 1.19 // PMMA density in g #define PMMA_STPR 0.98 // PMMA Stopping Power Ratio, no dim PLMBASE_API float compute_PrSTPR_from_HU(float); PLMBASE_API float compute_PrSTPR_Schneider_weq_from_HU (float CT_HU); // Stopping Power Ratio - Schneider's model PLMBASE_API float compute_PrWER_from_HU(float CT_HU); // WER = STRP / density PLMBASE_API float compute_density_from_HU (float CT_HU); // density VS HU - Schneider's model: broken curve class Proj_volume; class Ray_data; class Rpl_volume_private; class Volume; class Volume_limit; enum Rpl_volume_ray_trace_start { RAY_TRACE_START_AT_RAY_VOLUME_INTERSECTION, RAY_TRACE_START_AT_CLIPPING_PLANE }; class PLMBASE_API Rpl_volume { public: SMART_POINTER_SUPPORT (Rpl_volume); Rpl_volume_private *d_ptr; public: Rpl_volume (); ~Rpl_volume (); public: void set_geometry ( const double src[3], // position of source (mm) const double iso[3], // position of isocenter (mm) const double vup[3], // dir to "top" of projection plane double sid, // dist from proj plane to source (mm) const plm_long image_dim[2], // resolution of image const double image_center[2], // image center (pixels) const double image_spacing[2], // pixel size (mm) const double step_length // spacing between planes ); void clone_geometry (const Rpl_volume *rv); void set_ray_trace_start (Rpl_volume_ray_trace_start rvrtt); Aperture::Pointer& get_aperture (); const Aperture::Pointer& get_aperture () const; void set_aperture (Aperture::Pointer& ap); Volume* get_vol (); const Volume* get_vol () const; Proj_volume* get_proj_volume (); void set_ct_volume (Plm_image::Pointer& ct_volume); const Proj_volume* get_proj_volume () const; const plm_long *get_image_dim (); plm_long get_num_steps (); double get_value (plm_long ap_ij[2], double dist) const; double get_value (double ap_ij[2], double dist) const; double get_value (const double *xyz) const; void set_ct (const Plm_image::Pointer& ct_volume); Plm_image::Pointer get_ct(); void set_ct_limit(Volume_limit* ct_limit); Volume_limit* get_ct_limit(); Ray_data* get_ray_data(); const Ray_data* get_ray_data() const; void set_ray_data (Ray_data *ray); void set_front_clipping_plane(double front_clip); double get_front_clipping_plane () const; void set_back_clipping_plane(double back_clip); double get_back_clipping_plane () const; double get_step_length () const; void compute_rpl_ct_density (); // compute density volume void compute_rpl_HU (); // compute HU volume void compute_rpl_void (); // compute void volume void compute_rpl (bool use_aperture, Ray_trace_callback callback); void compute_rpl_sample (bool use_aperture); void compute_rpl_accum (bool use_aperture); void compute_rpl_range_length_rgc(); // range length volume creation taking into account the range compensator void compute_rpl_PrSTRP_no_rgc (); // compute Proton Stopping Power Ratio volume without considering the range compensator double compute_farthest_penetrating_ray_on_nrm(float range); // return the distance from aperture to the farthest which rg_lenght > range void compute_wed_volume (Volume *wed_vol, Volume *in_vol, float background); void compute_dew_volume (Volume *wed_vol, Volume *dew_vol, float background); void compute_proj_wed_volume (Volume *proj_wed_vol, float background); void compute_volume_aperture(Aperture::Pointer ap); void apply_beam_modifiers (); void save (const char* filename); void save (const std::string& filename); void load_rpl (const char* filename); void load_rpl (const std::string& filename); void load_img (const char *filename); void load_img (const std::string& filename); void compute_ray_data (); protected: void rpl_ray_trace ( Volume *ct_vol, /* I: CT volume */ Ray_data *ray_data, /* I: Pre-computed data for this ray */ Ray_trace_callback callback, /* I: Ray trace callback function */ Volume_limit *vol_limit, /* I: CT bounding region */ const double *src, /* I: @ source */ double rc_thk, /* I: range compensator thickness */ int* ires /* I: ray cast resolution */ ); protected: void save_img (const char* filename); void save_img (const std::string& filename); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rpl_volume_lut.cxx000077500000000000000000000111261321604176500313310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "interpolate.h" #include "proj_volume.h" #include "ray_data.h" #include "rpl_volume.h" #include "rpl_volume_lut.h" #include "volume.h" class Lut_entry { public: Lut_entry() { for (int i = 0; i < 8; i++) { idx[i] = -i; weight[i] = 0.f; } } public: plm_long idx[8]; float weight[8]; }; class PLMBASE_API Rpl_volume_lut_private { public: Rpl_volume_lut_private (Rpl_volume *rv, Volume *vol) : rv(rv), vol(vol), lut(0) { } ~Rpl_volume_lut_private () { delete[] lut; } public: Rpl_volume *rv; Volume *vol; Lut_entry *lut; }; Rpl_volume_lut::Rpl_volume_lut () { d_ptr = new Rpl_volume_lut_private (0, 0); } Rpl_volume_lut::Rpl_volume_lut (Rpl_volume *rv, Volume *vol) { d_ptr = new Rpl_volume_lut_private (rv, vol); } Rpl_volume_lut::~Rpl_volume_lut () { delete d_ptr; } void Rpl_volume_lut::set_lut_entry ( const Ray_data* ray_data, plm_long vox_idx, const float *vox_ray, plm_long ap_idx, float li_frac, float step_length, int lut_entry_idx ) { // Make sure this ray has positive weight if (li_frac <= 0.f) { return; } // Project voxel vector onto unit vector of aperture ray // This assumes that // d_ptr->rvrts == RAY_TRACE_START_AT_RAY_VOLUME_INTERSECTION // We omit the check for speed. const double *ap_ray = ray_data[ap_idx].ray; float dist = vec3_dot (vox_ray, ap_ray); dist -= ray_data->front_dist; if (dist < 0) { return; } // Compute number of steps plm_long steps_f = (plm_long) floorf (dist / step_length); float dist_frac = (dist - steps_f * step_length) / step_length; if (steps_f >= d_ptr->rv->get_num_steps()) { return; } // Compute lut entries const Aperture::Pointer ap = d_ptr->rv->get_aperture (); plm_long lut_idx = ap_idx + steps_f * ap->get_dim(0) * ap->get_dim(1); d_ptr->lut[lut_idx].idx[lut_entry_idx] = lut_idx; d_ptr->lut[lut_idx].weight[lut_entry_idx] = dist_frac * li_frac; if (steps_f >= d_ptr->rv->get_num_steps() - 1) { return; } lut_idx = lut_idx + ap->get_dim(0) * ap->get_dim(1); d_ptr->lut[lut_idx].idx[4+lut_entry_idx] = lut_idx; d_ptr->lut[lut_idx].weight[4+lut_entry_idx] = (1. - dist_frac) * li_frac; } void Rpl_volume_lut::build_lut () { const Proj_volume *pv = d_ptr->rv->get_proj_volume (); const double *src = pv->get_src (); const Aperture::Pointer ap = d_ptr->rv->get_aperture (); const plm_long *ap_dim = ap->get_dim (); const Ray_data* ray_data = d_ptr->rv->get_ray_data(); /* Allocate memory for lut */ d_ptr->lut = new Lut_entry[d_ptr->vol->npix]; plm_long ijk[3]; double xyz[3]; LOOP_Z (ijk, xyz, d_ptr->vol) { LOOP_Y (ijk, xyz, d_ptr->vol) { LOOP_X (ijk, xyz, d_ptr->vol) { plm_long idx = d_ptr->vol->index (ijk); /* Project the voxel to the aperture plane */ double ap_xy[2]; pv->project (ap_xy, xyz); if (!is_number (ap_xy[0]) || !is_number (ap_xy[1])) { continue; } /* Check if voxel is completely outside aperture boundary */ if (ap_xy[0] <= -1.f || ap_xy[0] >= ap_dim[0] || ap_xy[1] <= -1.f || ap_xy[1] >= ap_dim[1]) { continue; } /* Get vector from source to voxel */ float vox_ray[3]; vec3_sub3 (vox_ray, xyz, src); /* Solve for interpolation fractions on aperture planes */ plm_long ijk_f[3]; float li_frac_1[3], li_frac_2[3]; float ap_xy_float[2] = { static_cast(ap_xy[0]), static_cast(ap_xy[1]) }; li_2d (ijk_f, li_frac_1, li_frac_2, ap_xy_float, ap_dim); /* Inspect four interpolant aperture pixels. For each pixel, calculate distance to point on ray closest to voxel center */ plm_long ap_ij[2], ap_idx; ap_ij[0] = ijk_f[0], ap_ij[1] = ijk_f[1]; ap_idx = ap_ij[0] + ap_ij[1] * ap_dim[0]; set_lut_entry (ray_data, idx, vox_ray, ap_idx, li_frac_1[0], li_frac_2[0], 0); } } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rpl_volume_lut.h000077500000000000000000000016701321604176500307610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rpl_volume_lut_h_ #define _rpl_volume_lut_h_ #include "plmbase_config.h" #include "smart_pointer.h" class Rpl_volume; class Rpl_volume_lut_private; class Volume; class PLMBASE_API Rpl_volume_lut { public: SMART_POINTER_SUPPORT (Rpl_volume_lut); Rpl_volume_lut_private *d_ptr; public: Rpl_volume_lut (Rpl_volume *rv, Volume *vol); ~Rpl_volume_lut (); private: /* Should not be called */ Rpl_volume_lut (); public: void build_lut (); protected: void set_lut_entry ( const Ray_data* ray_data, plm_long vox_idx, const float *vox_ray, plm_long ap_idx, float li_frac, float step_length, int lut_entry_idx ); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rt_study.cxx000066400000000000000000000434571321604176500301470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #if PLM_DCM_USE_GDCM1 #include "gdcm1_dose.h" #include "gdcm1_series.h" #endif #include "astroid_dose.h" #include "file_util.h" #include "itk_resample.h" #include "logfile.h" #include "mc_dose.h" #include "path_util.h" #include "plm_image.h" #include "print_and_exit.h" #include "rt_study.h" #include "rt_study_p.h" #include "rtss.h" #include "segmentation.h" #include "string_util.h" #include "volume.h" #include "xio_ct.h" #include "xio_ct_transform.h" #include "xio_demographic.h" #include "xio_dir.h" #include "xio_dose.h" #include "xio_patient.h" #include "xio_structures.h" Rt_study::Rt_study () { d_ptr = new Rt_study_private; } Rt_study::~Rt_study () { delete d_ptr; } void Rt_study::load (const char* input_path, Plm_file_format file_type) { if (file_type == PLM_FILE_FMT_UNKNOWN) { file_type = plm_file_format_deduce (input_path); } switch (file_type) { case PLM_FILE_FMT_NO_FILE: print_and_exit ("Could not open input file %s for read\n", input_path); break; case PLM_FILE_FMT_UNKNOWN: case PLM_FILE_FMT_IMG: this->load_image (input_path); break; case PLM_FILE_FMT_DICOM_DIR: this->load_dicom_dir (input_path); break; case PLM_FILE_FMT_XIO_DIR: this->load_xio (input_path); break; case PLM_FILE_FMT_RT_STUDY_DIR: this->load_rt_study_dir (input_path); break; case PLM_FILE_FMT_DIJ: print_and_exit ( "Warping dij files requires ctatts_in, dif_in files\n"); break; case PLM_FILE_FMT_DICOM_RTSS: this->load_dicom_rtss (input_path); break; case PLM_FILE_FMT_DICOM_DOSE: this->load_dicom_dose (input_path); break; case PLM_FILE_FMT_DICOM_RTPLAN: this->load_dicom_rtplan((const char*)input_path); break; case PLM_FILE_FMT_CXT: this->load_cxt (input_path); break; case PLM_FILE_FMT_SS_IMG_VEC: default: print_and_exit ( "Sorry, don't know how to load/convert/warp/segment " "input type %s (%s)\n", plm_file_format_string (file_type), input_path); break; } } void Rt_study::load (const std::string& path, Plm_file_format file_type) { this->load (path.c_str(), file_type); } void Rt_study::load_image (const char *fn) { d_ptr->m_img = Plm_image::New (fn); } void Rt_study::load_image (const std::string& fn) { this->load_image (fn.c_str()); } void Rt_study::load_dicom_dir (const char *dicom_dir) { const char *dicom_dir_tmp; /* In case dicom_dir is a file, not dir */ if (is_directory (dicom_dir)) { dicom_dir_tmp = dicom_dir; } else { dicom_dir_tmp = file_util_dirname (dicom_dir); } this->load_dicom (dicom_dir_tmp); if (dicom_dir_tmp != dicom_dir) { free ((void*) dicom_dir_tmp); } } void Rt_study::load_dicom (const char *dicom_dir) { if (!dicom_dir) { return; } #if PLM_DCM_USE_DCMTK this->load_dcmtk (dicom_dir); #else this->load_gdcm (dicom_dir); #endif } void Rt_study::load_dicom_rtss (const char *dicom_path) { d_ptr->m_seg.reset (); #if PLM_DCM_USE_DCMTK this->load_dcmtk (dicom_path); #elif PLM_DCM_USE_GDCM1 d_ptr->m_seg = Segmentation::New (); d_ptr->m_seg->load_gdcm_rtss (dicom_path, d_ptr->m_drs.get()); #else /* Do nothing */ #endif } void Rt_study::load_dicom_rtplan(const char *dicom_path) { #if PLM_DCM_USE_DCMTK this->load_dcmtk(dicom_path); #elif PLM_DCM_USE_GDCM1 //not yet implemented #else /* Do nothing */ #endif } void Rt_study::load_dicom_dose (const char *dicom_path) { #if PLM_DCM_USE_DCMTK this->load_dcmtk (dicom_path); #elif PLM_DCM_USE_GDCM1 d_ptr->m_dose.reset (gdcm1_dose_load (0, dicom_path)); #else /* Do nothing */ #endif } void Rt_study::load_xio (const char *xio_dir) { Xio_dir xd (xio_dir); Xio_patient *xpd; std::string xio_studyset_dir; std::string xio_plan_dir; if (xd.num_patients() <= 0) { print_and_exit ("Error, xio num_patient_dir = %d\n", xd.num_patients()); } xpd = xd.patient_dir[0]; if (xd.num_patients() > 1) { printf ("Warning: multiple patients found in xio directory.\n" "Defaulting to first directory: %s\n", xpd->m_path.c_str()); } if (xpd->plan_dirs.empty()) { /* No plans exist, load only studyset */ if (xpd->studyset_dirs.empty()) { print_and_exit ("Error, xio patient has no studyset."); } printf ("Warning: no plans found, only loading studyset."); xio_studyset_dir = xpd->studyset_dirs.front(); if (xpd->studyset_dirs.size() > 1) { printf ( "Warning: multiple studyset found in xio patient directory.\n" "Defaulting to first directory: %s\n", xio_studyset_dir.c_str()); } } else { /* Plans exist, so load the first plan */ const std::string& xio_plan_dir = xpd->plan_dirs.front(); if (xpd->plan_dirs.size() > 1) { printf ("Warning: multiple plans found in xio patient directory.\n" "Defaulting to first directory: %s\n", xio_plan_dir.c_str()); } /* Load the summed XiO dose file */ d_ptr->m_dose = Plm_image::New (); printf ("calling xio_dose_load\n"); d_ptr->m_xio_dose_filename = xio_plan_dir + "/dose.1"; xio_dose_load (d_ptr->m_dose.get(), d_ptr->m_drs->get_dose_metadata (), d_ptr->m_xio_dose_filename.c_str()); /* Find studyset associated with plan */ xio_studyset_dir = xio_plan_dir_get_studyset_dir (xio_plan_dir); } printf("path is :: %s\n", xio_studyset_dir.c_str()); /* Load the XiO studyset slice list */ Xio_studyset xst (xio_studyset_dir); /* Load the XiO studyset CT images */ d_ptr->m_img = Plm_image::New(); xio_ct_load (d_ptr->m_img.get(), &xst); /* Load the XiO studyset structure set */ d_ptr->m_seg = Segmentation::New (); d_ptr->m_seg->load_xio (xst); /* Apply XiO CT geometry to structures */ if (d_ptr->m_seg->have_structure_set()) { Rtss *rtss_ss = d_ptr->m_seg->get_structure_set_raw (); rtss_ss->set_geometry (d_ptr->m_img); } /* Load demographics */ if (xpd->m_demographic_fn != "") { Xio_demographic demographic (xpd->m_demographic_fn.c_str()); if (demographic.m_patient_name != "") { d_ptr->m_drs->set_study_metadata (0x0010, 0x0010, demographic.m_patient_name); } if (demographic.m_patient_id != "") { d_ptr->m_drs->set_study_metadata (0x0010, 0x0020, demographic.m_patient_id); } if (demographic.m_import_date != "") { d_ptr->m_drs->set_study_date (demographic.m_import_date); d_ptr->m_drs->set_study_time (""); } } /* If referenced DICOM CT is provided, the coordinates will be transformed from XiO to DICOM LPS with the same origin as the original CT. Otherwise, the XiO CT will be saved as DICOM and the structures will be associated to those slices. The coordinates will be transformed to DICOM LPS based on the patient position metadata and the origin will remain the same. */ if (d_ptr->m_img) { if (d_ptr->m_drs->slice_list_complete()) { /* Determine transformation based on original DICOM */ d_ptr->m_xio_transform->set_from_rdd (d_ptr->m_img.get(), d_ptr->m_drs.get()); } } if (d_ptr->m_img) { xio_ct_apply_transform (d_ptr->m_img.get(), d_ptr->m_xio_transform); } if (d_ptr->m_seg->have_structure_set()) { xio_structures_apply_transform (d_ptr->m_seg->get_structure_set_raw(), d_ptr->m_xio_transform); } if (d_ptr->m_dose) { xio_dose_apply_transform (d_ptr->m_dose.get(), d_ptr->m_xio_transform); } } void Rt_study::load_rt_study_dir (const char *rt_study_dir) { std::string fn = string_format ("%s/img.nrrd", rt_study_dir); this->load_image (fn); fn = string_format ("%s/structures", rt_study_dir); this->load_prefix (fn); } void Rt_study::load_rt_study_dir (const std::string& rt_study_dir) { load_rt_study_dir (rt_study_dir.c_str()); } void Rt_study::load_ss_img (const char *ss_img, const char *ss_list) { d_ptr->m_seg = Segmentation::New (); d_ptr->m_seg->load (ss_img, ss_list); } void Rt_study::load_dose_img (const char *dose_img) { if (d_ptr->m_dose) { d_ptr->m_dose.reset(); } if (dose_img) { d_ptr->m_dose = plm_image_load_native (dose_img); } } void Rt_study::load_rdd (const char *image_directory) { d_ptr->m_drs = Rt_study_metadata::load (image_directory); /* GCS FIX: I think the below is not needed any more, but there might be some edge cases, such as converting image with referenced ct, which should copy patient name but not slice uids */ #if defined (commentout) Rt_study_metadata *rsm = d_ptr->m_drs.get (); Metadata *meta = rsm->get_study_metadata (); if (rsm->slice_list_complete()) { /* Default to patient position in referenced DICOM */ d_ptr->m_meta->set_metadata(0x0018, 0x5100, si->m_demographics.get_metadata(0x0018, 0x5100)); d_ptr->m_xio_transform->set (d_ptr->m_meta); /* Default to patient name/ID/sex in referenced DICOM */ d_ptr->m_meta->set_metadata(0x0010, 0x0010, si->m_demographics.get_metadata(0x0010, 0x0010)); d_ptr->m_meta->set_metadata(0x0010, 0x0020, si->m_demographics.get_metadata(0x0010, 0x0020)); d_ptr->m_meta->set_metadata(0x0010, 0x0040, si->m_demographics.get_metadata(0x0010, 0x0040)); } #endif } void Rt_study::load_dose_xio (const char *dose_xio) { if (d_ptr->m_dose) { d_ptr->m_dose.reset(); } if (dose_xio) { d_ptr->m_xio_dose_filename = dose_xio; d_ptr->m_dose = Plm_image::New (); Metadata::Pointer& dose_meta = d_ptr->m_drs->get_dose_metadata (); xio_dose_load (d_ptr->m_dose.get(), dose_meta, dose_xio); xio_dose_apply_transform (d_ptr->m_dose.get(), d_ptr->m_xio_transform); } } void Rt_study::load_dose_astroid (const char *dose_astroid) { if (d_ptr->m_dose) { d_ptr->m_dose.reset(); } if (dose_astroid) { d_ptr->m_dose = Plm_image::New (); Metadata::Pointer& dose_meta = d_ptr->m_drs->get_dose_metadata (); astroid_dose_load (d_ptr->m_dose.get(), dose_meta, dose_astroid); astroid_dose_apply_transform (d_ptr->m_dose.get(), d_ptr->m_xio_transform); } } void Rt_study::load_dose_mc (const char *dose_mc) { if (d_ptr->m_dose) { d_ptr->m_dose.reset(); } if (dose_mc) { d_ptr->m_dose = Plm_image::New (); mc_dose_load (d_ptr->m_dose.get(), dose_mc); mc_dose_apply_transform (d_ptr->m_dose.get(), d_ptr->m_xio_transform); } } void Rt_study::load_cxt (const char *input_fn) { d_ptr->m_seg = Segmentation::New (); d_ptr->m_seg->load_cxt (input_fn, d_ptr->m_drs.get()); } void Rt_study::load_prefix (const char *input_fn) { d_ptr->m_seg = Segmentation::New (); d_ptr->m_seg->load_prefix (input_fn); } void Rt_study::load_prefix (const std::string& input_fn) { this->load_prefix (input_fn.c_str()); } void Rt_study::save_dicom (const char *dicom_dir, bool filenames_with_uid) { if (!dicom_dir) { return; } if (d_ptr->m_img) { d_ptr->m_drs->set_image_header (d_ptr->m_img); } if (d_ptr->m_seg) { d_ptr->m_seg->cxt_extract (); } #if PLM_DCM_USE_DCMTK this->save_dcmtk (dicom_dir, filenames_with_uid); #else this->save_gdcm (dicom_dir); #endif } void Rt_study::save_dicom (const std::string& dicom_dir, bool filenames_with_uid) { this->save_dicom (dicom_dir.c_str(), filenames_with_uid); } void Rt_study::save_dicom_dose (const char *dicom_dir) { if (!dicom_dir) { return; } #if PLM_DCM_USE_DCMTK this->save_dcmtk_dose (dicom_dir); #else /* Not yet supported -- this function is only used by topas, which uses dcmtk. */ #endif } void Rt_study::save_image (const std::string& fname) { if (fname != "") { d_ptr->m_img->save_image (fname); } } void Rt_study::save_image (const char* fname) { if (d_ptr->m_img) { d_ptr->m_img->save_image (fname); } } void Rt_study::save_image (const char* fname, Plm_image_type image_type) { if (d_ptr->m_img) { d_ptr->m_img->convert_and_save (fname, image_type); } } void Rt_study::save_dose (const std::string& fname) { if (fname != "") { d_ptr->m_dose->save_image (fname); } } void Rt_study::save_dose (const char* fname) { if (d_ptr->m_dose) { d_ptr->m_dose->save_image (fname); } } void Rt_study::save_dose (const char* fname, Plm_image_type image_type) { if (d_ptr->m_dose) { d_ptr->m_dose->convert_and_save (fname, image_type); } } void Rt_study::save_prefix ( const std::string& output_prefix, const std::string& extension) { d_ptr->m_seg->save_prefix (output_prefix, extension); } const Rt_study_metadata::Pointer& Rt_study::get_rt_study_metadata () const { return d_ptr->m_drs; } Rt_study_metadata::Pointer& Rt_study::get_rt_study_metadata () { return d_ptr->m_drs; } void Rt_study::set_study_metadata (const std::vector& metadata) { Metadata::Pointer& study_metadata = d_ptr->m_drs->get_study_metadata (); study_metadata->set_metadata (metadata); /* GCS FIX. This is the wrong place for this. */ d_ptr->m_xio_transform->set (d_ptr->m_drs->get_image_metadata()); } Metadata::Pointer& Rt_study::get_study_metadata (void) { return d_ptr->m_drs->get_study_metadata(); } void Rt_study::set_image_metadata (const std::vector& metadata) { Metadata::Pointer& image_metadata = d_ptr->m_drs->get_image_metadata (); image_metadata->set_metadata (metadata); } Metadata::Pointer& Rt_study::get_image_metadata (void) { return d_ptr->m_drs->get_image_metadata(); } void Rt_study::set_dose_metadata (const std::vector& metadata) { Metadata::Pointer& dose_metadata = d_ptr->m_drs->get_dose_metadata (); dose_metadata->set_metadata (metadata); } Metadata::Pointer& Rt_study::get_dose_metadata (void) { return d_ptr->m_drs->get_dose_metadata(); } void Rt_study::set_rtstruct_metadata (const std::vector& metadata) { Metadata::Pointer& seg_metadata = d_ptr->m_drs->get_rtstruct_metadata (); seg_metadata->set_metadata (metadata); } Metadata::Pointer& Rt_study::get_rtstruct_metadata (void) { return d_ptr->m_drs->get_rtstruct_metadata(); } void Rt_study::generate_new_study_uids () { d_ptr->m_drs->generate_new_study_uids (); } void Rt_study::force_ct_series_uid (const std::string& series_uid) { d_ptr->m_drs->force_ct_series_uid (series_uid); } bool Rt_study::have_image () { return (bool) d_ptr->m_img && d_ptr->m_img->m_type != PLM_IMG_TYPE_UNDEFINED; } Plm_image::Pointer Rt_study::get_image () { return d_ptr->m_img; } void Rt_study::set_image (ShortImageType::Pointer& itk_image) { d_ptr->m_img = Plm_image::New (itk_image); } void Rt_study::set_image (FloatImageType::Pointer& itk_image) { d_ptr->m_img = Plm_image::New (itk_image); } void Rt_study::set_image (Plm_image* pli) { d_ptr->m_img.reset (pli); } void Rt_study::set_image (const Plm_image::Pointer& pli) { d_ptr->m_img = pli; } bool Rt_study::have_dose () { return (bool) d_ptr->m_dose; } void Rt_study::set_dose (Plm_image *pli) { d_ptr->m_dose.reset (pli); } void Rt_study::set_dose (FloatImageType::Pointer itk_dose) { d_ptr->m_dose.reset (new Plm_image (itk_dose)); } void Rt_study::set_dose (Volume *vol) { if (!vol) return; d_ptr->m_dose = Plm_image::New(); /* GCS FIX: Make a copy */ d_ptr->m_dose->set_volume (vol->clone_raw()); } void Rt_study::set_dose (const Plm_image::Pointer& pli) { d_ptr->m_dose = pli; } Plm_image::Pointer Rt_study::get_dose () { return d_ptr->m_dose; } bool Rt_study::have_segmentation () { return (bool) d_ptr->m_seg; } Segmentation::Pointer Rt_study::get_segmentation () { return d_ptr->m_seg; } void Rt_study::set_segmentation (Segmentation::Pointer seg) { d_ptr->m_seg = seg; } void Rt_study::add_structure ( const UCharImageType::Pointer& itk_image, const char *structure_name, const char *structure_color) { if (!have_segmentation()) { d_ptr->m_seg = Segmentation::New (); } d_ptr->m_seg->add_structure (itk_image, structure_name, structure_color); } Xio_ct_transform* Rt_study::get_xio_ct_transform () { return d_ptr->m_xio_transform; } const std::string& Rt_study::get_xio_dose_filename (void) const { return d_ptr->m_xio_dose_filename; } Volume::Pointer Rt_study::get_image_volume_short () { if (!d_ptr->m_img) { return Volume::Pointer(); } return d_ptr->m_img->get_volume_short (); } Volume::Pointer Rt_study::get_image_volume_float (void) { if (!d_ptr->m_img) { return Volume::Pointer(); } return d_ptr->m_img->get_volume_float (); } bool Rt_study::has_dose () { return (d_ptr->m_dose != 0); } Volume::Pointer Rt_study::get_dose_volume_float () { if (!d_ptr->m_dose) { return Volume::Pointer(); } return d_ptr->m_dose->get_volume_float (); } /* Resample image and ss_img */ void Rt_study::resample (float spacing[3]) { d_ptr->m_img->set_itk (resample_image ( d_ptr->m_img->itk_float(), spacing)); d_ptr->m_seg->resample (spacing); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rt_study.h000066400000000000000000000127201321604176500275610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_study_h_ #define _rt_study_h_ #include "plmbase_config.h" #include #include "itk_image_type.h" #include "plm_file_format.h" #include "plm_image.h" #include "plm_image_type.h" #include "rt_study_metadata.h" #include "segmentation.h" class Metadata; class Plm_image; class Rt_plan; class Rt_study_private; class Volume; class Xio_ct_transform; /*! \brief * The Rt_study class encapsulates the concept of a radiotherapy planning * data set, including image, structure set, and dose. */ class PLMBASE_API Rt_study { public: SMART_POINTER_SUPPORT (Rt_study); public: Rt_study_private *d_ptr; public: Rt_study (); ~Rt_study (); void load (const char* input_path, Plm_file_format file_type = PLM_FILE_FMT_UNKNOWN); void load (const std::string& input_path, Plm_file_format file_type = PLM_FILE_FMT_UNKNOWN); void load_dicom_dir (const char *dicom_dir); void load_dicom (const char *dicom_dir); void load_dicom_dose (const char *dicom_path); void load_dicom_rtss (const char *dicom_path); void load_dicom_rtplan(const char *dicom_path); void load_image (const char *fn); void load_image (const std::string& fn); void load_xio (const char *xio_dir); void load_rt_study_dir (const char *rt_study_dir); void load_rt_study_dir (const std::string& rt_study_dir); void load_ss_img (const char *ss_img, const char *ss_list); void load_dose_img (const char *dose_img); void load_dose_xio (const char *dose_xio); void load_dose_astroid (const char *dose_astroid); void load_dose_mc (const char *dose_mc); void load_rdd (const char *image_directory); void load_dcmtk (const char *dicom_dir); void load_gdcm (const char *dicom_dir); void load_cxt (const char *input_fn); void load_prefix (const char *input_fn); void load_prefix (const std::string& input_fn); void save_dicom (const std::string& output_dir, bool filenames_with_uid = true); void save_dicom (const char *output_dir, bool filenames_with_uid = true); void save_dicom_dose (const char *output_dir); void save_image (const std::string& fname); void save_image (const char* fname); void save_image (const char* fname, Plm_image_type image_type); void save_dose (const std::string& fname); void save_dose (const char* fname); void save_dose (const char* fname, Plm_image_type image_type); void save_prefix (const std::string& output_prefix, const std::string& extension = "mha"); /*! \brief Get the Rt_study_metadata */ const Rt_study_metadata::Pointer& get_rt_study_metadata () const; Rt_study_metadata::Pointer& get_rt_study_metadata (); /*! \brief Set metadata items into study_metadata portion of Rt_study_metadata */ void set_study_metadata (const std::vector& metadata); /*! \brief Get the study_metadata portion of Rt_study_metadata */ Metadata::Pointer& get_study_metadata (); /*! \brief Set metadata items into image portion of Rt_study_metadata */ void set_image_metadata (const std::vector& metadata); /*! \brief Get the image portion of Rt_study_metadata */ Metadata::Pointer& get_image_metadata (); /*! \brief Set metadata items into dose portion of Rt_study_metadata */ void set_dose_metadata (const std::vector& metadata); /*! \brief Get the dose portion of Rt_study_metadata */ Metadata::Pointer& get_dose_metadata (); /*! \brief Set metadata items into rtstruct portion of Rt_study_metadata */ void set_rtstruct_metadata (const std::vector& metadata); /*! \brief Get the rtstruct portion of Rt_study_metadata */ Metadata::Pointer& get_rtstruct_metadata (); /*! \brief Create new StudyInstanceUID and FrameOfReferenceUID for the study */ void generate_new_study_uids (); /*! \brief Force the CT series UID to a certain value when saving */ void force_ct_series_uid (const std::string& series_uid); bool have_image (); void set_image (ShortImageType::Pointer& itk_image); void set_image (FloatImageType::Pointer& itk_image); void set_image (Plm_image* pli); void set_image (const Plm_image::Pointer& pli); Plm_image::Pointer get_image (); bool have_dose (); void set_dose (Plm_image *pli); void set_dose (FloatImageType::Pointer itk_dose); void set_dose (Volume *vol); void set_dose (const Plm_image::Pointer& pli); Plm_image::Pointer get_dose (); bool have_segmentation (); Segmentation::Pointer get_segmentation (); void set_segmentation (Segmentation::Pointer seg); void add_structure ( const UCharImageType::Pointer& itk_image, const char *structure_name = 0, const char *structure_color = 0); const std::string& get_xio_dose_filename () const; Xio_ct_transform* get_xio_ct_transform (); Volume::Pointer get_image_volume_short (); Volume::Pointer get_image_volume_float (); bool has_dose (); Volume::Pointer get_dose_volume_float (); void resample (float spacing[3]); protected: void save_dcmtk (const char *dicom_dir, bool filenames_with_uid); void save_dcmtk_dose (const char *dicom_dir); void save_gdcm (const char *dicom_dir); void convert_ss_img_to_cxt (); }; #endif rt_study_metadata.cxx000066400000000000000000000344001321604176500317140ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "dicom_util.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_uid_prefix.h" #include "plm_version.h" #include "rt_study_metadata.h" #include "slice_list.h" #include "volume.h" class Rt_study_metadata_private { public: std::string date_string; std::string description_string; std::string referring_physician_name_string; std::string accession_number_string; std::string time_string; std::string study_id_string; std::string study_uid; std::string for_uid; std::string position_reference_indicator_string; std::string ct_series_uid; std::string dose_instance_uid; std::string dose_series_uid; std::string plan_instance_uid; std::string rtstruct_instance_uid; std::string rtstruct_series_uid; Slice_list slice_list; bool ct_series_uid_forced; Metadata::Pointer study_metadata; Metadata::Pointer image_metadata; Metadata::Pointer rtstruct_metadata; Metadata::Pointer dose_metadata; Metadata::Pointer rtplan_metadata; Metadata::Pointer sro_metadata; public: Rt_study_metadata_private () { dicom_get_date_time (&date_string, &time_string); study_metadata = Metadata::New (); image_metadata = Metadata::New (); rtstruct_metadata = Metadata::New (); dose_metadata = Metadata::New (); rtplan_metadata = Metadata::New (); sro_metadata = Metadata::New (); study_metadata->create_anonymous (); image_metadata->set_parent (study_metadata); rtstruct_metadata->set_parent (study_metadata); dose_metadata->set_parent (study_metadata); rtplan_metadata->set_parent (study_metadata); sro_metadata->set_parent (study_metadata); ct_series_uid_forced = false; this->generate_new_study_uids (); this->generate_new_series_uids (); } public: void generate_new_study_uids () { study_uid = dicom_uid (PLM_UID_PREFIX); for_uid = dicom_uid (PLM_UID_PREFIX); } void generate_new_series_uids () { if (!ct_series_uid_forced) { ct_series_uid = dicom_uid (PLM_UID_PREFIX); } dose_instance_uid = dicom_uid (PLM_UID_PREFIX); dose_series_uid = dicom_uid (PLM_UID_PREFIX); plan_instance_uid = dicom_uid (PLM_UID_PREFIX); rtstruct_instance_uid = dicom_uid (PLM_UID_PREFIX); rtstruct_series_uid = dicom_uid (PLM_UID_PREFIX); } }; Rt_study_metadata::Rt_study_metadata () { this->d_ptr = new Rt_study_metadata_private; } Rt_study_metadata::~Rt_study_metadata () { delete this->d_ptr; } Rt_study_metadata::Pointer Rt_study_metadata::load (const char* dicom_path) { Rt_study_metadata::Pointer rsm = Rt_study_metadata::New (); dicom_load_rdd (rsm, dicom_path); return rsm; } Rt_study_metadata::Pointer Rt_study_metadata::load (const std::string& dicom_path) { return Rt_study_metadata::load (dicom_path.c_str()); } const char* Rt_study_metadata::get_ct_series_uid () const { return d_ptr->ct_series_uid.c_str(); } void Rt_study_metadata::set_ct_series_uid (const char* uid) { if (!uid) return; d_ptr->ct_series_uid = uid; } void Rt_study_metadata::force_ct_series_uid (const std::string& uid) { if (uid == "") return; d_ptr->ct_series_uid = uid; d_ptr->ct_series_uid_forced = true; } const char* Rt_study_metadata::get_ct_series_description () const { return this->get_image_metadata (0x0008, 0x103E).c_str(); } const std::string& Rt_study_metadata::get_dose_instance_uid () const { return d_ptr->dose_instance_uid; } const char* Rt_study_metadata::get_dose_series_uid () const { return d_ptr->dose_series_uid.c_str(); } const char* Rt_study_metadata::get_frame_of_reference_uid () const { return d_ptr->for_uid.c_str(); } void Rt_study_metadata::set_frame_of_reference_uid (const char* uid) { if (!uid) return; d_ptr->for_uid = uid; } const char* Rt_study_metadata::get_plan_instance_uid () const { return d_ptr->plan_instance_uid.c_str(); } const std::string& Rt_study_metadata::get_rtstruct_instance_uid () const { return d_ptr->rtstruct_instance_uid; } void Rt_study_metadata::set_rtstruct_instance_uid (const char* rtstruct_instance_uid) { if (!rtstruct_instance_uid) return; d_ptr->rtstruct_instance_uid = rtstruct_instance_uid; } const char* Rt_study_metadata::get_rtstruct_series_uid () const { return d_ptr->rtstruct_series_uid.c_str(); } const char* Rt_study_metadata::get_referring_physician_name () const { return d_ptr->referring_physician_name_string.c_str(); } void Rt_study_metadata::set_referring_physician_name (const char* referring_physician_name) { if (!referring_physician_name) return; d_ptr->referring_physician_name_string = referring_physician_name; } void Rt_study_metadata::set_referring_physician_name (const std::string& referring_physician_name) { d_ptr->referring_physician_name_string = referring_physician_name; } const char* Rt_study_metadata::get_position_reference_indicator () const { return d_ptr->position_reference_indicator_string.c_str(); } void Rt_study_metadata::set_position_reference_indicator (const char* position_reference_indicator) { if (!position_reference_indicator) return; d_ptr->position_reference_indicator_string = position_reference_indicator; } void Rt_study_metadata::set_position_reference_indicator (const std::string& position_reference_indicator) { d_ptr->position_reference_indicator_string = position_reference_indicator; } const char* Rt_study_metadata::get_accession_number () const { return d_ptr->accession_number_string.c_str(); } void Rt_study_metadata::set_accession_number (const char* accession_number) { if (!accession_number) return; d_ptr->accession_number_string = accession_number; } void Rt_study_metadata::set_accession_number (const std::string& accession_number) { d_ptr->accession_number_string = accession_number; } const char* Rt_study_metadata::get_study_description () const { return d_ptr->description_string.c_str(); } void Rt_study_metadata::set_study_description (const char* description) { if (!description) return; d_ptr->description_string = description; } void Rt_study_metadata::set_study_description (const std::string& description) { d_ptr->description_string = description; } const char* Rt_study_metadata::get_study_date () const { return d_ptr->date_string.c_str(); } void Rt_study_metadata::set_study_date (const char* date) { if (!date) return; d_ptr->date_string = date; } void Rt_study_metadata::set_study_date (const std::string& date) { d_ptr->date_string = date; } const char* Rt_study_metadata::get_study_time () const { return d_ptr->time_string.c_str(); } void Rt_study_metadata::set_study_time (const char* time) { if (!time) d_ptr->time_string.clear(); else d_ptr->time_string = time; } void Rt_study_metadata::set_study_time (const std::string& time) { d_ptr->time_string = time; } const char* Rt_study_metadata::get_study_uid () const { return d_ptr->study_uid.c_str(); } void Rt_study_metadata::set_study_uid (const char* uid) { if (!uid) return; d_ptr->study_uid = uid; } const char* Rt_study_metadata::get_study_id () const { return d_ptr->study_id_string.c_str(); } void Rt_study_metadata::set_study_id (const char* study_id) { if (!study_id) return; d_ptr->study_id_string = study_id; } void Rt_study_metadata::set_study_id (const std::string& study_id) { d_ptr->study_id_string = study_id; } const std::string& Rt_study_metadata::get_patient_name () { return d_ptr->study_metadata->get_metadata (0x0010, 0x0010); } void Rt_study_metadata::set_patient_name (const char* name) { d_ptr->study_metadata->set_metadata (0x0010, 0x0010, name); /* GCS FIX: Should I remove from child metadata? Logically it seems necessary, but it is an ugly design that it is needed. Existing code does not seem to rely on this, as patient name is not stored within child metadata. */ // d_ptr->image_metadata->remove_metadata (0x0010, 0x0010); } void Rt_study_metadata::set_patient_name (const std::string& name) { set_patient_name (name.c_str()); } const std::string& Rt_study_metadata::get_patient_id () { return d_ptr->study_metadata->get_metadata (0x0010, 0x0020); } void Rt_study_metadata::set_patient_id (const std::string& id) { d_ptr->study_metadata->set_metadata (0x0010, 0x0020, id.c_str()); } const std::string& Rt_study_metadata::get_patient_birth_date () { return d_ptr->study_metadata->get_metadata (0x0010, 0x0030); } void Rt_study_metadata::set_patient_birth_date (const char* birth_date) { d_ptr->study_metadata->set_metadata (0x0010, 0x0030, birth_date); } void Rt_study_metadata::set_patient_birth_date (const std::string& birth_date) { set_patient_birth_date (birth_date.c_str()); } const std::string& Rt_study_metadata::get_patient_sex () { return d_ptr->study_metadata->get_metadata (0x0010, 0x0040); } void Rt_study_metadata::set_patient_sex (const char* sex) { d_ptr->study_metadata->set_metadata (0x0010, 0x0040, sex); } void Rt_study_metadata::set_patient_sex (const std::string& sex) { set_patient_sex (sex.c_str()); } const Plm_image_header* Rt_study_metadata::get_image_header () const { return d_ptr->slice_list.get_image_header (); } void Rt_study_metadata::set_image_header (const Plm_image::Pointer& pli) { d_ptr->slice_list.set_image_header (Plm_image_header (pli.get())); } void Rt_study_metadata::set_image_header (const Plm_image_header& pih) { d_ptr->slice_list.set_image_header (pih); } void Rt_study_metadata::set_image_header (ShortImageType::Pointer img) { d_ptr->slice_list.set_image_header (img); } const Slice_list* Rt_study_metadata::get_slice_list () const { return &d_ptr->slice_list; } void Rt_study_metadata::reset_slice_uids () { return d_ptr->slice_list.reset_slice_uids (); } const char* Rt_study_metadata::get_slice_uid (int index) const { return d_ptr->slice_list.get_slice_uid (index); } void Rt_study_metadata::set_slice_uid (int index, const char* slice_uid) { if (!slice_uid) return; d_ptr->slice_list.set_slice_uid (index, slice_uid); } void Rt_study_metadata::set_slice_list_complete () { d_ptr->slice_list.set_slice_list_complete (); } bool Rt_study_metadata::slice_list_complete () const { return d_ptr->slice_list.slice_list_complete (); } int Rt_study_metadata::num_slices () const { return d_ptr->slice_list.num_slices (); } Metadata::Pointer& Rt_study_metadata::get_study_metadata () { return d_ptr->study_metadata; } const Metadata::Pointer& Rt_study_metadata::get_study_metadata () const { return d_ptr->study_metadata; } void Rt_study_metadata::set_study_metadata ( unsigned short key1, unsigned short key2, const std::string& val ) { d_ptr->study_metadata->set_metadata (key1, key2, val); } Metadata::Pointer& Rt_study_metadata::get_image_metadata () { return d_ptr->image_metadata; } const Metadata::Pointer& Rt_study_metadata::get_image_metadata () const { return d_ptr->image_metadata; } const std::string& Rt_study_metadata::get_image_metadata ( unsigned short key1, unsigned short key2 ) const { return d_ptr->image_metadata->get_metadata (key1, key2); } void Rt_study_metadata::set_image_metadata ( unsigned short key1, unsigned short key2, const std::string& val ) { d_ptr->image_metadata->set_metadata (key1, key2, val); } Metadata::Pointer& Rt_study_metadata::get_rtstruct_metadata () { return d_ptr->rtstruct_metadata; } const Metadata::Pointer& Rt_study_metadata::get_rtstruct_metadata () const { return d_ptr->rtstruct_metadata; } void Rt_study_metadata::set_rtstruct_metadata ( unsigned short key1, unsigned short key2, const std::string& val ) { d_ptr->rtstruct_metadata->set_metadata (key1, key2, val); } Metadata::Pointer& Rt_study_metadata::get_dose_metadata () { return d_ptr->dose_metadata; } const Metadata::Pointer& Rt_study_metadata::get_dose_metadata () const { return d_ptr->dose_metadata; } void Rt_study_metadata::set_dose_metadata ( unsigned short key1, unsigned short key2, const std::string& val ) { d_ptr->dose_metadata->set_metadata (key1, key2, val); } Metadata::Pointer& Rt_study_metadata::get_rtplan_metadata () { return d_ptr->rtplan_metadata; } const Metadata::Pointer& Rt_study_metadata::get_rtplan_metadata () const { return d_ptr->rtplan_metadata; } void Rt_study_metadata::set_rtplan_metadata ( unsigned short key1, unsigned short key2, const std::string& val ) { d_ptr->rtplan_metadata->set_metadata (key1, key2, val); } Metadata::Pointer& Rt_study_metadata::get_sro_metadata () { return d_ptr->sro_metadata; } const Metadata::Pointer& Rt_study_metadata::get_sro_metadata () const { return d_ptr->sro_metadata; } void Rt_study_metadata::set_sro_metadata ( unsigned short key1, unsigned short key2, const std::string& val ) { d_ptr->sro_metadata->set_metadata (key1, key2, val); } #if PLM_DCM_USE_DCMTK const std::string& Rt_study_metadata::get_study_metadata (const DcmTagKey& key) const { return d_ptr->study_metadata->get_metadata (key); } void Rt_study_metadata::set_study_metadata ( const DcmTagKey& key, const std::string& val) { d_ptr->study_metadata->set_metadata (key, val); } const std::string& Rt_study_metadata::get_image_metadata (const DcmTagKey& key) const { return d_ptr->image_metadata->get_metadata (key); } void Rt_study_metadata::set_image_metadata ( const DcmTagKey& key, const std::string& val) { d_ptr->image_metadata->set_metadata (key, val); } const std::string& Rt_study_metadata::get_sro_metadata (const DcmTagKey& key) const { return d_ptr->sro_metadata->get_metadata (key); } void Rt_study_metadata::set_sro_metadata ( const DcmTagKey& key, const std::string& val) { d_ptr->sro_metadata->set_metadata (key, val); } #endif void Rt_study_metadata::generate_new_study_uids () { d_ptr->generate_new_study_uids (); } void Rt_study_metadata::generate_new_series_uids () { d_ptr->generate_new_series_uids (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rt_study_metadata.h000066400000000000000000000137611321604176500314270ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_study_metadata_h_ #define _rt_study_metadata_h_ #include "plmbase_config.h" #include #include "itk_image_type.h" #include "plm_image.h" #include "plm_int.h" #include "smart_pointer.h" class Rt_study_metadata_private; class Metadata; class Plm_image_header; class Slice_list; class Volume; /*! \brief * The Rt_study_metadata encapsulate DICOM metadata for an Rt_study. * The Rt_study_metadata includes separate metadata for image, dose, * and rtstruct, as well as a study_metadata which is * shared by all components. Items such as Patient Name or Study Description * will be held in study_metadata. */ class PLMBASE_API Rt_study_metadata { public: SMART_POINTER_SUPPORT (Rt_study_metadata); public: Rt_study_metadata_private *d_ptr; public: Rt_study_metadata (); ~Rt_study_metadata (); public: static Rt_study_metadata::Pointer load (const std::string& dicom_path); static Rt_study_metadata::Pointer load (const char* dicom_path); public: const char* get_ct_series_uid () const; void set_ct_series_uid (const char* uid); void force_ct_series_uid (const std::string& uid); const char* get_ct_series_description () const; const std::string& get_dose_instance_uid () const; const char* get_dose_series_uid () const; const char* get_frame_of_reference_uid () const; void set_frame_of_reference_uid (const char* uid); const char* get_plan_instance_uid () const; const std::string& get_rtstruct_instance_uid () const; void set_rtstruct_instance_uid (const char* rtstruct_instance_uid); const char* get_rtstruct_series_uid () const; const char* get_position_reference_indicator () const; void set_position_reference_indicator (const char* position_reference_indicator); void set_position_reference_indicator (const std::string& position_reference_indicator); const char* get_referring_physician_name () const; void set_referring_physician_name (const char* referring_physician_name); void set_referring_physician_name (const std::string& referring_physician_name); const char* get_accession_number () const; void set_accession_number (const char* accession_number); void set_accession_number (const std::string& accession_number); const char* get_study_date () const; void set_study_date (const char* date); void set_study_date (const std::string& date); const char* get_study_description () const; void set_study_description (const char* description); void set_study_description (const std::string& description); const char* get_study_time () const; void set_study_time (const char* time); void set_study_time (const std::string& time); const char* get_study_uid () const; void set_study_uid (const char* uid); const char* get_study_id () const; void set_study_id (const char* id); void set_study_id (const std::string& id); const std::string& get_patient_name (); void set_patient_name (const char* name); void set_patient_name (const std::string& name); const std::string& get_patient_id (); void set_patient_id (const std::string& id); const std::string& get_patient_birth_date (); void set_patient_birth_date (const char* birth_date); void set_patient_birth_date (const std::string& birth_date); const std::string& get_patient_sex (); void set_patient_sex (const char* sex); void set_patient_sex (const std::string& sex); const Plm_image_header* get_image_header () const; void set_image_header (const Plm_image::Pointer& pli); void set_image_header (const Plm_image_header& pih); void set_image_header (ShortImageType::Pointer img); const Slice_list *get_slice_list () const; void reset_slice_uids (); const char* get_slice_uid (int index) const; void set_slice_uid (int index, const char* slice_uid); bool slice_list_complete () const; void set_slice_list_complete (); int num_slices () const; Metadata::Pointer& get_study_metadata (); const Metadata::Pointer& get_study_metadata () const; void set_study_metadata (unsigned short key1, unsigned short key2, const std::string& val); Metadata::Pointer& get_image_metadata (); const Metadata::Pointer& get_image_metadata () const; const std::string& get_image_metadata (unsigned short key1, unsigned short key2) const; void set_image_metadata (unsigned short key1, unsigned short key2, const std::string& val); Metadata::Pointer& get_rtstruct_metadata (); const Metadata::Pointer& get_rtstruct_metadata () const; void set_rtstruct_metadata (unsigned short key1, unsigned short key2, const std::string& val); Metadata::Pointer& get_dose_metadata (); const Metadata::Pointer& get_dose_metadata () const; void set_dose_metadata (unsigned short key1, unsigned short key2, const std::string& val); Metadata::Pointer& get_rtplan_metadata (); const Metadata::Pointer& get_rtplan_metadata () const; void set_rtplan_metadata (unsigned short key1, unsigned short key2, const std::string& val); Metadata::Pointer& get_sro_metadata (); const Metadata::Pointer& get_sro_metadata () const; void set_sro_metadata (unsigned short key1, unsigned short key2, const std::string& val); #if PLM_DCM_USE_DCMTK const std::string& get_study_metadata (const DcmTagKey& key) const; void set_study_metadata (const DcmTagKey& key, const std::string& val); const std::string& get_image_metadata (const DcmTagKey& key) const; void set_image_metadata (const DcmTagKey& key, const std::string& val); const std::string& get_sro_metadata (const DcmTagKey& key) const; void set_sro_metadata (const DcmTagKey& key, const std::string& val); #endif void generate_new_study_uids (); void generate_new_series_uids (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rt_study_p.h000066400000000000000000000022441321604176500301000ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_study_p_h_ #define _rt_study_p_h_ #include "plmbase_config.h" #include "metadata.h" #include "rt_study_metadata.h" #include "segmentation.h" #include "xio_ct_transform.h" class PLMBASE_API Rt_study_private { public: Rt_study_metadata::Pointer m_drs; /* UIDs, etc -- used by dcmtk */ std::string m_xio_dose_filename; /* XiO dose file to use as template for saving in XiO format */ Xio_ct_transform *m_xio_transform; /* Transformation from XiO to DICOM coordinates */ Plm_image::Pointer m_img; /* CT image */ Plm_image::Pointer m_dose; /* RT dose */ Segmentation::Pointer m_seg; /* RT structure set */ public: Rt_study_private () { m_drs = Rt_study_metadata::New (); m_xio_transform = new Xio_ct_transform (); } ~Rt_study_private () { delete m_xio_transform; } }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtds_dcmtk.cxx000066400000000000000000000036521321604176500304210ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "compiler_warnings.h" #if PLM_DCM_USE_DCMTK #include "dcmtk_rt_study.h" #endif #include "logfile.h" #include "plm_image.h" #include "rt_study.h" #include "rt_study_p.h" #include "segmentation.h" void Rt_study::load_dcmtk (const char *dicom_path) { #if PLM_DCM_USE_DCMTK Dcmtk_rt_study drs; drs.set_rt_study_metadata (d_ptr->m_drs); drs.load (dicom_path); d_ptr->m_img = drs.get_image (); Rtss::Pointer rtss = drs.get_rtss (); if (rtss) { d_ptr->m_seg = Segmentation::New (); d_ptr->m_seg->set_structure_set (drs.get_rtss ()); } d_ptr->m_dose = drs.get_dose (); #endif } void Rt_study::save_dcmtk (const char *dicom_dir, bool filenames_with_uid) { #if PLM_DCM_USE_DCMTK Dcmtk_rt_study drs; drs.set_rt_study_metadata (d_ptr->m_drs); drs.set_image (d_ptr->m_img); if (d_ptr->m_seg) { /* GCS FIX. This call to prune_empty() is a hack. It should be allowed to write empty structures, but current plastimatch logic sets num_structures to max when performing cxt_extract(). Segmentation class logic should be improved to better keep track of when structure names are valid to avoid this. */ d_ptr->m_seg->prune_empty (); d_ptr->m_seg->keyholize (); drs.set_rtss (d_ptr->m_seg->get_structure_set()); } drs.set_dose (d_ptr->m_dose); drs.set_filenames_with_uid (filenames_with_uid); drs.save (dicom_dir); #endif } void Rt_study::save_dcmtk_dose (const char *dicom_dir) { #if PLM_DCM_USE_DCMTK Dcmtk_rt_study drs; drs.set_rt_study_metadata (d_ptr->m_drs); drs.set_dose (d_ptr->m_dose); drs.save (dicom_dir); #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtds_gdcm.cxx000066400000000000000000000041331321604176500302240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #if PLM_DCM_USE_GDCM1 #include "gdcm1_dose.h" #include "gdcm1_series.h" #endif #include "plm_image.h" #include "rt_study.h" #include "rt_study_p.h" #include "segmentation.h" #include "string_util.h" void Rt_study::load_gdcm (const char *dicom_dir) { if (!dicom_dir) { return; } #if PLM_DCM_USE_GDCM1 Gdcm_series *gdcm_series = new Gdcm_series; gdcm_series->load (dicom_dir); gdcm_series->digest_files (); if (gdcm_series->m_rtdose_file_list) { const std::string& filename = gdcm_series->get_rtdose_filename(); d_ptr->m_dose.reset(gdcm1_dose_load (0, filename.c_str())); } if (gdcm_series->m_rtstruct_file_list) { const std::string& filename = gdcm_series->get_rtstruct_filename(); d_ptr->m_seg = Segmentation::New (); d_ptr->m_seg->load_gdcm_rtss (filename.c_str(), d_ptr->m_drs.get()); } #endif /* Use existing itk reader for the image. This is required because the native dicom reader doesn't yet handle things like MR. */ d_ptr->m_img = Plm_image::New (new Plm_image(dicom_dir)); #if PLM_DCM_USE_GDCM1 /* Use native reader to set meta */ gdcm_series->get_metadata (this->get_study_metadata ()); delete gdcm_series; #endif } void Rt_study::save_gdcm (const char *output_dir) { if (d_ptr->m_img) { printf ("Rt_study::save_dicom: save_short_dicom()\n"); d_ptr->m_img->save_short_dicom (output_dir, d_ptr->m_drs.get()); } #if PLM_DCM_USE_GDCM1 if (d_ptr->m_seg) { printf ("Rt_study::save_dicom: save_gdcm_rtss()\n"); d_ptr->m_seg->save_gdcm_rtss (output_dir, d_ptr->m_drs); } if (this->has_dose()) { std::string fn; printf ("Rt_study::save_dicom: gdcm_save_dose()\n"); fn = string_format ("%s/%s", output_dir, "dose.dcm"); gdcm1_dose_save (d_ptr->m_dose.get(), d_ptr->m_drs.get(), fn.c_str()); } #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtog_io.cxx000066400000000000000000000747701321604176500277360ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* Convert RTOG CT (and DOSE) to MHA ----------------------------------------- Limitations. Not all of these are tested for!!! Only 1 CT scan allowed CT slice spacing must be uniform Anatomy should be RAI, transverse slices Only 1 DOSE allowed CT's must be 2 byte (DOSE must be 2 byte unsigned by specification) Assume DOSE is PHYSICAL & GRAYS Assume INTEL architecture (little endian) ---------------------------------------- Interpretation - based on CORVUS export: For CT: The (x,y) offset is roughly the position of the upper left corner of the upper left pixel, in rtog patient coordinates, which means relative to the center of the image. The z offset (z value of the first slice) seems to be completely arbitrary, but related to the strange first slice thickness value As usual, the pixel size is rounded For DOSE: The offset is the position of the center of the upper left pixel, relative to rtog patient coordinate isocenter. This differs from the CT offset, which is relative to image center. ---------------------------------------- Note about RTOG For CT, dim1 is rows & dim2 is columns, but grid1 is cols & grid2 is rows For DOSE, dim1 is cols & dim2 is rows ---------------------------------------- Implementation based on interpretation Use nominal pixel size, even though it is more highly rounded. No need to flip CT Y positions, because they are already flipped by specification. Verify that CT Z positions are increasing, and flip the position accordingly. So I just set MHA origin at 1/2 pixel for both CT and dose < RMK: This works for (x,y), but not for (z) - NEED TO FIX > For MASK, need to flip Y */ #include "plm_config.h" #include #include #include #include #include #include "exchkeys.h" #include "file_util.h" #define BUFLEN 2048 char mha_header_pat[] = "ObjectType = Image\n" "NDims = 3\n" "BinaryData = True\n" "BinaryDataByteOrderMSB = False\n" "Offset = %f %f %f\n" "ElementSpacing = %f %f %f\n" "DimSize = %d %d %d\n" "AnatomicalOrientation = RAI\n" "ElementType = %s\n" "ElementDataFile = LOCAL\n" ; typedef struct program_parms Program_Parms; struct program_parms { char* indir; char* outdir; }; typedef struct ct_header CT_Header; struct ct_header { int first_image; int last_image; float grid_1_units; float grid_2_units; int size_of_dimension_1; int size_of_dimension_2; float x_offset; float y_offset; float z_offset; float z_spacing; int ct_offset; int ct_air; int ct_water; void* image; }; typedef struct dose_header DOSE_Header; struct dose_header { int imno; int size_of_dimension_1; int size_of_dimension_2; int size_of_dimension_3; float coord_1_of_first_point; float coord_2_of_first_point; float coord_3_of_first_point; float horizontal_grid_interval; float vertical_grid_interval; float depth_grid_interval; float dose_scale; unsigned short* image; float* fimage; }; typedef struct polyline Cxt_polyline; struct polyline { int num_vertices; float* x; float* y; float* z; }; typedef struct polyline_slice Cxt_polyline_Slice; struct polyline_slice { int slice_no; int num_polyline; Cxt_polyline* pllist; }; typedef struct structure STRUCTURE; struct structure { int imno; char name[BUFLEN]; int num_slices; Cxt_polyline_Slice* pslist; }; typedef struct structure_list STRUCTURE_List; struct structure_list { int num_structures; STRUCTURE* slist; int skin_no; unsigned char* skin_image; }; typedef struct rtog_header RTOG_Header; struct rtog_header { CT_Header ct; DOSE_Header dose; STRUCTURE_List structures; }; typedef struct rtog_line RTOG_Line; struct rtog_line { int key; int ival; float fval; }; void print_usage (void) { printf ("Usage: rtog_to_mha [options]\n"); printf (" -d dir input directory\n"); printf (" -o dir output directory\n"); exit (0); } void gs_strncpy (char* dst, char* src, int n) { int i = 0; for (i = 0; i < n; i++) { if (!(dst[i] = src[i])) { return; } } dst[i-1] = 0; } int get_rtog_line (FILE* fp, char* key, char* val) { char buf[BUFLEN]; char* s; while (1) { if (!fgets (buf,BUFLEN,fp)) return 0; s = strstr (buf, ":= "); if (!s) continue; gs_strncpy (key, buf, s-buf); gs_strncpy (val, s+strlen(":= "), BUFLEN); if ((s = strpbrk (val, "\n\r"))) { *s = 0; } return 1; } } int parse_rtog_string (char** list, int list_size, char* str) { char upstr[BUFLEN]; char *u, *s; int i; /* Make str uppercase */ for (u = upstr, s = str; (*u = toupper(*s)); u++, s++); /* Find in list and return enum */ for (i = 0; i < list_size; i++) { char* list_string = list[i]; if (!strncmp (upstr, list_string, strlen(list_string))) { return i; } } return -1; } int parse_rtog_key (char* key) { return parse_rtog_string (key_list_words, RTOG_NUM_KEYS, key); } int parse_rtog_value (char* value) { return parse_rtog_string (key_value_words, RTOG_NUM_KEY_VALS, value); } int parse_rtog_line (RTOG_Line* rtog_line, char* key, char* val) { int rc; rtog_line->key = -1; rtog_line->ival = -1; rtog_line->fval = 0.0; /* Parse key */ rtog_line->key = parse_rtog_key (key); if (rtog_line->key < 0) return -1; /* Parse value */ switch (rtog_line->key) { /* Strings */ case ekIMAGETYPE: rtog_line->ival = parse_rtog_value (val); if (rtog_line->ival < 0) return -1; break; case ekSTRUCTURENAME: /* Leave the data in "val" */ break; /* Integers */ case ekIMAGENUMBER: case ekSIZEOFDIMENSION1: case ekSIZEOFDIMENSION2: case ekSIZEOFDIMENSION3: case ekCTOFFSET: case ekCTAIR: case ekCTWATER: case ekNUMBEROFDIMENSIONS: rc = sscanf (val, "%d", &rtog_line->ival); if (rc < 0) return -1; break; /* floats */ case ekGRID1UNITS: case ekGRID2UNITS: case ekXOFFSET: case ekYOFFSET: case ekZVALUE: case ekCOORD1OFFIRSTPOINT: case ekCOORD2OFFIRSTPOINT: case ekCOORD3OFFIRSTPOINT: case ekHORIZONTALGRIDINTERVAL: case ekVERTICALGRIDINTERVAL: case ekDEPTHGRIDINTERVAL: case ekDOSESCALE: return sscanf (val, "%f", &rtog_line->fval); if (rc < 0) return -1; break; } return 0; } int set_ct_ival (RTOG_Header* rtog_header, RTOG_Line* rtog_line, int imno, int* tgt, char* tgt_comment) { if (rtog_header->ct.first_image == imno) { *tgt = rtog_line->ival; } else { if (*tgt != rtog_line->ival) { printf ("Inconsistent %s\n", tgt_comment); return -1; } } return 0; } int set_ct_fval (RTOG_Header* rtog_header, RTOG_Line* rtog_line, int imno, float* tgt, char* tgt_comment) { if (rtog_header->ct.first_image == imno) { *tgt = rtog_line->fval; } else { if (*tgt != rtog_line->fval) { printf ("Inconsistent %s\n", tgt_comment); return -1; } } return 0; } void load_rtog_header (RTOG_Header* rtog_header, Program_Parms* parms) { FILE* fp; int rc; RTOG_Line rtog_line; int imtype = -1; int imno = -1; float last_z = -100000.0; char fn[BUFLEN]; char key[BUFLEN], val[BUFLEN]; STRUCTURE* curr_struct = 0; /* Open header file */ snprintf (fn, BUFLEN, "%s/aapm0000", parms->indir); fp = fopen (fn, "r"); if (!fp) { printf ("Error: could not open file \"%s\" for read.\n", fn); print_usage (); exit (-1); } /* Initialize rtog_header structure */ rtog_header->ct.first_image = -1; rtog_header->dose.imno = -1; rtog_header->structures.num_structures = 0; rtog_header->structures.slist = 0; /* Loop through file, adding to rtog_header struct */ while (1) { if (!get_rtog_line (fp, key, val)) { break; } if (parse_rtog_line (&rtog_line, key, val) < 0) { printf ("parse_rtog_line() failed\n"); goto error_exit; } switch (parse_rtog_key(key)) { case -1: goto error_exit; case ekIMAGENUMBER: rc = sscanf (val, "%d", &imno); if (rc != 1) goto error_exit; break; case ekIMAGETYPE: imtype = parse_rtog_value (val); switch (imtype) { case -1: goto error_exit; case evCTSCAN: if (rtog_header->ct.first_image < 0) { rtog_header->ct.first_image = imno; } rtog_header->ct.last_image = imno; break; case evDOSE: if (rtog_header->dose.imno == -1) { rtog_header->dose.imno = imno; } else { printf ("Warning, multiple dose sections found.\n"); } break; case evSTRUCTURE: rtog_header->structures.num_structures ++; rtog_header->structures.slist = (STRUCTURE*) realloc (rtog_header->structures.slist, rtog_header->structures.num_structures * sizeof (STRUCTURE)); curr_struct = &rtog_header->structures.slist[rtog_header->structures.num_structures-1]; curr_struct->imno = imno; curr_struct->name[0] = 0; curr_struct->num_slices = 0; curr_struct->pslist = 0; break; default: printf ("Warning: unhandled image type: %s", val); break; } break; case ekZVALUE: if (rtog_header->ct.first_image == imno) { rtog_header->ct.z_offset = rtog_line.fval; } else if (rtog_header->ct.z_offset == last_z) { rtog_header->ct.z_spacing = rtog_line.fval - last_z; if (rtog_header->ct.z_spacing < 0) { printf ("Error, z_spacing is decreasing.\n"); goto error_exit; } } else { double SPACING_TOL = 1e-6; if (fabs(rtog_header->ct.z_spacing - (rtog_line.fval - last_z)) > SPACING_TOL) { printf ("Inconsistent z_spacing: %f\n", rtog_header->ct.z_spacing - (rtog_line.fval - last_z)); goto error_exit; } } last_z = rtog_line.fval; break; case ekGRID1UNITS: if (imtype == evCTSCAN) { rc = set_ct_fval (rtog_header, &rtog_line, imno, &rtog_header->ct.grid_1_units, "grid_1"); if (rc < 0) goto error_exit; } break; case ekGRID2UNITS: if (imtype == evCTSCAN) { rc = set_ct_fval (rtog_header, &rtog_line, imno, &rtog_header->ct.grid_2_units, "grid_2"); if (rc < 0) goto error_exit; } break; case ekSIZEOFDIMENSION1: if (imtype == evCTSCAN) { rc = set_ct_ival (rtog_header, &rtog_line, imno, &rtog_header->ct.size_of_dimension_1, "size 1"); if (rc < 0) goto error_exit; } else if (imtype == evDOSE && imno == rtog_header->dose.imno) { rtog_header->dose.size_of_dimension_1 = rtog_line.ival; } break; case ekSIZEOFDIMENSION2: if (imtype == evCTSCAN) { rc = set_ct_ival (rtog_header, &rtog_line, imno, &rtog_header->ct.size_of_dimension_2, "size 2"); if (rc < 0) goto error_exit; } else if (imtype == evDOSE && imno == rtog_header->dose.imno) { rtog_header->dose.size_of_dimension_2 = rtog_line.ival; } break; case ekSIZEOFDIMENSION3: if (imtype == evDOSE && imno == rtog_header->dose.imno) { rtog_header->dose.size_of_dimension_3 = rtog_line.ival; } case ekXOFFSET: if (imtype == evCTSCAN) { rc = set_ct_fval (rtog_header, &rtog_line, imno, &rtog_header->ct.x_offset, "x_offset"); if (rc < 0) goto error_exit; } break; case ekYOFFSET: if (imtype == evCTSCAN) { rc = set_ct_fval (rtog_header, &rtog_line, imno, &rtog_header->ct.y_offset, "y_offset"); if (rc < 0) goto error_exit; } break; case ekCTOFFSET: if (imtype == evCTSCAN) { rc = set_ct_ival (rtog_header, &rtog_line, imno, &rtog_header->ct.ct_offset, "ct_offset"); if (rc < 0) goto error_exit; } break; case ekCTAIR: if (imtype == evCTSCAN) { rc = set_ct_ival (rtog_header, &rtog_line, imno, &rtog_header->ct.ct_air, "ct_air"); if (rc < 0) goto error_exit; } break; case ekCTWATER: if (imtype == evCTSCAN) { rc = set_ct_ival (rtog_header, &rtog_line, imno, &rtog_header->ct.ct_water, "ct_water"); if (rc < 0) goto error_exit; } break; case ekNUMBEROFDIMENSIONS: if (imtype == evDOSE) { if (rtog_line.ival != 3) { printf ("Error: dose doesn't have 3 dimensions (%d)\n", rtog_line.ival); goto error_exit; } } break; case ekCOORD1OFFIRSTPOINT: if (imtype == evDOSE && imno == rtog_header->dose.imno) { rtog_header->dose.coord_1_of_first_point = rtog_line.fval; } break; case ekCOORD2OFFIRSTPOINT: if (imtype == evDOSE && imno == rtog_header->dose.imno) { rtog_header->dose.coord_2_of_first_point = rtog_line.fval; } break; case ekCOORD3OFFIRSTPOINT: if (imtype == evDOSE && imno == rtog_header->dose.imno) { rtog_header->dose.coord_3_of_first_point = rtog_line.fval; } break; case ekHORIZONTALGRIDINTERVAL: if (imtype == evDOSE && imno == rtog_header->dose.imno) { rtog_header->dose.horizontal_grid_interval = rtog_line.fval; if (rtog_header->dose.horizontal_grid_interval < 0.0) { printf ("Error: dose horizontal_grid_interval is less than zero\n"); goto error_exit; } } break; case ekVERTICALGRIDINTERVAL: if (imtype == evDOSE && imno == rtog_header->dose.imno) { rtog_header->dose.vertical_grid_interval = rtog_line.fval; if (rtog_header->dose.vertical_grid_interval > 0.0) { printf ("Error: dose vertical_grid_interval is greater than zero\n"); goto error_exit; } /* Set to positive */ rtog_header->dose.vertical_grid_interval = -rtog_header->dose.vertical_grid_interval; } break; case ekDEPTHGRIDINTERVAL: if (imtype == evDOSE && imno == rtog_header->dose.imno) { rtog_header->dose.depth_grid_interval = rtog_line.fval; if (rtog_header->dose.depth_grid_interval < 0.0) { printf ("Error: dose depth_grid_interval is less than zero\n"); goto error_exit; } } break; case ekDOSESCALE: if (imtype == evDOSE && imno == rtog_header->dose.imno) { rtog_header->dose.dose_scale = rtog_line.fval; } break; case ekSTRUCTURENAME: if (imtype == evSTRUCTURE) { strncpy (curr_struct->name, val, BUFLEN); } break; default: /* Silently ignore */ break; } } printf ("CT IMAGES: %d - %d\n", rtog_header->ct.first_image, rtog_header->ct.last_image); printf ("Image res: (%d,%d)\n", rtog_header->ct.size_of_dimension_1, rtog_header->ct.size_of_dimension_2); printf ("Pixel size: (%f,%f)\n", rtog_header->ct.grid_1_units, rtog_header->ct.grid_2_units); printf ("Offset: (%f,%f)\n", rtog_header->ct.x_offset, rtog_header->ct.y_offset); printf ("Z (off,spc): (%f,%f)\n", rtog_header->ct.z_offset, rtog_header->ct.z_spacing); printf ("CT (off,air,wat): (%d,%d,%d)\n", rtog_header->ct.ct_offset, rtog_header->ct.ct_air, rtog_header->ct.ct_water); printf ("DOSE IMG: %d\n", rtog_header->dose.imno); printf ("Image res: (%d,%d,%d)\n", rtog_header->dose.size_of_dimension_1, rtog_header->dose.size_of_dimension_2, rtog_header->dose.size_of_dimension_3); printf ("Offset: (%f,%f,%f)\n", rtog_header->dose.coord_1_of_first_point, rtog_header->dose.coord_2_of_first_point, rtog_header->dose.coord_3_of_first_point); printf ("Spacing: (%f,%f,%f)\n", rtog_header->dose.horizontal_grid_interval, rtog_header->dose.vertical_grid_interval, rtog_header->dose.depth_grid_interval); printf ("Dose scale: (%f)\n", rtog_header->dose.dose_scale); fclose (fp); return; error_exit: printf ("Error parsing RTOG header file: %s:= %s", key, val); exit (-1); } void load_ct (RTOG_Header* rtog_header, Program_Parms* parms) { int i; unsigned short* b; int num_slices = rtog_header->ct.last_image - rtog_header->ct.first_image + 1; size_t slice_voxels = rtog_header->ct.size_of_dimension_1 * rtog_header->ct.size_of_dimension_2; int num_voxels = slice_voxels * num_slices; rtog_header->ct.image = (void*) malloc ( sizeof(unsigned short) * num_voxels); if (!rtog_header->ct.image) { printf ("Error: could not malloc ct image\n"); exit (-1); } b = ((unsigned short*) rtog_header->ct.image) + num_voxels; printf ("Reading CT slices...\n"); for (i = 0; i < num_slices; i++) { FILE* fp; char fn[BUFLEN]; int slice_no = rtog_header->ct.first_image + i; snprintf (fn, BUFLEN, "%s/aapm%04d", parms->indir, slice_no); fp = fopen (fn, "rb"); if (!fp) { printf ("Error: could not open file \"%s\" for read.\n", fn); exit (-1); } b -= slice_voxels; size_t rc = fread (b, sizeof(unsigned short), slice_voxels, fp); if (rc != slice_voxels) { printf ("Error reading from file %s (%d bytes read)\n", fn, (int) rc); } fclose (fp); } } /* Just make the output directory without checking if it exists. If the mkdir fails, we'll catch this when we try to write */ void make_output_dir (Program_Parms* parms) { make_directory_recursive (parms->outdir); } void correct_ct (RTOG_Header* rtog_header) { int i; int num_slices = rtog_header->ct.last_image - rtog_header->ct.first_image + 1; int slice_voxels = rtog_header->ct.size_of_dimension_1 * rtog_header->ct.size_of_dimension_2; int num_voxels = slice_voxels * num_slices; unsigned short* ctimg = (unsigned short*) rtog_header->ct.image; for (i = 0; i < num_voxels; i++) { unsigned short raw = ctimg[i]; /* swap bytes */ unsigned short byte1 = (raw & 0xFF00) >> 8; unsigned short byte2 = (raw & 0x00FF) << 8; raw = byte1 | byte2; /* correct for ct offset */ raw = ((short) raw) - rtog_header->ct.ct_offset; ctimg[i] = raw; } } void write_ct (RTOG_Header* rtog_header, Program_Parms* parms) { FILE* fp; char fn[BUFLEN]; int num_slices = rtog_header->ct.last_image - rtog_header->ct.first_image + 1; int slice_voxels = rtog_header->ct.size_of_dimension_1 * rtog_header->ct.size_of_dimension_2; int num_voxels = slice_voxels * num_slices; make_output_dir (parms); printf ("Writing CT volume...\n"); snprintf (fn,BUFLEN,"%s/ct.mha",parms->outdir); fp = fopen (fn, "wb"); if (!fp) { printf ("Error opening %s for write\n", fn); exit (-1); } fprintf (fp, mha_header_pat, #if defined (commentout) /* See file header for offset interpretation */ rtog_header->ct.x_offset, rtog_header->ct.y_offset, rtog_header->ct.z_offset, #endif rtog_header->ct.grid_1_units * 10.0 / 2.0, rtog_header->ct.grid_2_units * 10.0 / 2.0, rtog_header->ct.z_spacing * 10.0 / 2.0, rtog_header->ct.grid_1_units * 10.0, rtog_header->ct.grid_2_units * 10.0, rtog_header->ct.z_spacing * 10.0, rtog_header->ct.size_of_dimension_2, rtog_header->ct.size_of_dimension_1, rtog_header->ct.last_image - rtog_header->ct.first_image + 1, "MET_SHORT" ); fwrite (rtog_header->ct.image, sizeof(unsigned short), num_voxels, fp); fclose (fp); } void free_ct (RTOG_Header* rtog_header) { free (rtog_header->ct.image); } void load_dose (RTOG_Header* rtog_header, Program_Parms* parms) { FILE* fp; char fn[BUFLEN]; size_t num_voxels = rtog_header->dose.size_of_dimension_1 * rtog_header->dose.size_of_dimension_2 * rtog_header->dose.size_of_dimension_3; rtog_header->dose.image = (unsigned short*) malloc (sizeof(unsigned short) * num_voxels); if (!rtog_header->dose.image) { printf ("Error: could not malloc dose image\n"); exit (-1); } rtog_header->dose.fimage = (float*) malloc (sizeof(float) * num_voxels); if (!rtog_header->dose.fimage) { printf ("Error: could not malloc dose fimage\n"); exit (-1); } printf ("Loading dose...\n"); snprintf (fn, BUFLEN, "%s/aapm%04d", parms->indir, rtog_header->dose.imno); fp = fopen (fn, "rb"); if (!fp) { printf ("Error: could not open file \"%s\" for read.\n", fn); exit (-1); } size_t rc = fread (rtog_header->dose.image, sizeof(unsigned short), num_voxels, fp); if (rc != num_voxels) { printf ("Error: could not read dose from file %s (%d bytes read)\n", fn, (int) rc); exit (-1); } fclose (fp); } void correct_dose (RTOG_Header* rtog_header) { int i; unsigned short* dsimg = rtog_header->dose.image; float* dsfimg = rtog_header->dose.fimage; int num_voxels = rtog_header->dose.size_of_dimension_1 * rtog_header->dose.size_of_dimension_2 * rtog_header->dose.size_of_dimension_3; for (i = 0; i < num_voxels; i++) { unsigned short raw = dsimg[i]; /* swap bytes */ unsigned short byte1 = (raw & 0xFF00) >> 8; unsigned short byte2 = (raw & 0x00FF) << 8; raw = byte1 | byte2; /* correct for dose scale */ dsfimg[i] = ((short) raw) * rtog_header->dose.dose_scale; } } void write_dose (RTOG_Header* rtog_header, Program_Parms* parms) { FILE* fp; char fn[BUFLEN]; int i; float* b; int num_slices = rtog_header->dose.size_of_dimension_3; int slice_voxels = rtog_header->dose.size_of_dimension_1 * rtog_header->dose.size_of_dimension_2; int num_voxels = rtog_header->dose.size_of_dimension_1 * rtog_header->dose.size_of_dimension_2 * rtog_header->dose.size_of_dimension_3; make_output_dir (parms); printf ("Writing DOSE volume...\n"); snprintf (fn,BUFLEN,"%s/dose.mha",parms->outdir); fp = fopen (fn, "wb"); if (!fp) { printf ("Error opening %s for write\n", fn); exit (-1); } fprintf (fp, mha_header_pat, #if defined (commentout) /* See file header for offset interpretation */ rtog_header->dose.coord_1_of_first_point, rtog_header->dose.coord_2_of_first_point, rtog_header->dose.coord_3_of_first_point, #endif rtog_header->dose.horizontal_grid_interval * 10 / 2.0, rtog_header->dose.vertical_grid_interval * 10 / 2.0, rtog_header->dose.depth_grid_interval * 10 / 2.0, rtog_header->dose.horizontal_grid_interval * 10, rtog_header->dose.vertical_grid_interval * 10, rtog_header->dose.depth_grid_interval * 10, rtog_header->dose.size_of_dimension_1, rtog_header->dose.size_of_dimension_2, rtog_header->dose.size_of_dimension_3, "MET_FLOAT" ); b = rtog_header->dose.fimage + num_voxels; for (i = 0; i < num_slices; i++) { b -= slice_voxels; fwrite (b, sizeof(float), slice_voxels, fp); } fclose (fp); } void free_dose (RTOG_Header* rtog_header) { free (rtog_header->dose.image); free (rtog_header->dose.fimage); } void load_structure (STRUCTURE* structure, Program_Parms* parms) { int nlev, scan_no, nseg, npts; Cxt_polyline_Slice* curr_ps = 0; Cxt_polyline* curr_pl = 0; int curr_pt = 0; char buf[BUFLEN]; float x, y, z; FILE* fp; char fn[BUFLEN]; snprintf (fn, BUFLEN, "%s/aapm%04d", parms->indir, structure->imno); fp = fopen (fn, "rb"); if (!fp) { printf ("Error: could not open file \"%s\" for read.\n", fn); exit (-1); } /* Parse structure file */ while (fgets (buf,BUFLEN,fp)) { if (1 == sscanf (buf,"\"NUMBER OF LEVELS\" %d",&nlev)) { /* Yeah, whatever */ } else if (1 == sscanf (buf,"\"SCAN # \" %d",&scan_no)) { structure->num_slices ++; structure->pslist = (Cxt_polyline_Slice*) realloc (structure->pslist, structure->num_slices * sizeof (Cxt_polyline_Slice)); curr_ps = &structure->pslist[structure->num_slices-1]; curr_ps->slice_no = scan_no; curr_ps->num_polyline = 0; curr_ps->pllist = 0; } else if (1 == sscanf (buf,"\"NUMBER OF SEGMENTS \" %d",&nseg)) { /* Yeah, whatever */ } else if (1 == sscanf (buf, "\"NUMBER OF POINTS \" %d",&npts)) { curr_ps->num_polyline ++; curr_ps->pllist = (Cxt_polyline*) realloc (curr_ps->pllist, curr_ps->num_polyline * sizeof (Cxt_polyline)); curr_pl = &curr_ps->pllist[curr_ps->num_polyline-1]; curr_pl->num_vertices = npts; curr_pl->x = (float*) malloc (npts * sizeof(float)); curr_pl->y = (float*) malloc (npts * sizeof(float)); curr_pl->z = (float*) malloc (npts * sizeof(float)); curr_pt = 0; } else if (3 == sscanf (buf, "%g, %g, %g", &x, &y, &z)) { if (curr_pt >= npts) { printf ("Error parsing structure file (too many points in polyline)\nfile=%s\n", fn); exit (-1); } curr_pl->x[curr_pt] = x; curr_pl->y[curr_pt] = y; curr_pl->z[curr_pt] = z; curr_pt++; } else { printf ("Error parsing structure file\nfile=%s\nline=%s\n", fn, buf); exit (-1); } } fclose (fp); } void load_skin (RTOG_Header* rtog_header, Program_Parms* parms) { int i; /* Find the skin structure */ for (i = 0; i < rtog_header->structures.num_structures; i++) { if (!strcmp (rtog_header->structures.slist[i].name, "SKIN")) { printf ("Found skin: %d/%d im=%d\n", i, rtog_header->structures.num_structures, rtog_header->structures.slist[i].imno); break; } } if (i == rtog_header->structures.num_structures) { printf ("Error: SKIN structure not found\n"); exit (-1); } /* Load the skin polylines */ load_structure (&rtog_header->structures.slist[i], parms); /* Save the index to skin */ rtog_header->structures.skin_no = i; } void render_slice (RTOG_Header* rtog_header, unsigned char* slice_img, unsigned char* acc_img, Cxt_polyline_Slice* ps) { #if defined (commentout) int i, j; int slice_voxels = rtog_header->ct.size_of_dimension_1 * rtog_header->ct.size_of_dimension_2; float offset[2] = { (float) (rtog_header->ct.grid_1_units / 2.0), (float) (rtog_header->ct.grid_2_units / 2.0) }; float spacing[2] = { rtog_header->ct.grid_1_units, rtog_header->ct.grid_2_units }; plm_long dims[2] = { rtog_header->ct.size_of_dimension_2, rtog_header->ct.size_of_dimension_1 }; for (i = 0; i < ps->num_polyline; i++) { memset (acc_img, 0, dims[0]*dims[1]*sizeof(unsigned char)); rasterize_slice (acc_img, dims, spacing, offset, ps->pllist[i].num_vertices, ps->pllist[i].x, ps->pllist[i].y); for (j = 0; j < slice_voxels; j++) { slice_img[j] ^= acc_img[j]; } } #endif } void render_skin (RTOG_Header* rtog_header, Program_Parms* parms) { int i; int num_slices = rtog_header->ct.last_image - rtog_header->ct.first_image + 1; int slice_voxels = rtog_header->ct.size_of_dimension_1 * rtog_header->ct.size_of_dimension_2; int num_voxels = slice_voxels * num_slices; STRUCTURE* skin = &rtog_header->structures.slist[rtog_header->structures.skin_no]; unsigned char* acc_img = (unsigned char*) malloc (sizeof(unsigned char) * slice_voxels); rtog_header->structures.skin_image = (unsigned char*) malloc (sizeof(unsigned char) * num_voxels); memset (rtog_header->structures.skin_image, 0, sizeof(unsigned char) * num_voxels); for (i = 0; i < skin->num_slices; i++) { int slice_no = skin->pslist[i].slice_no; /* First slice_no is 1 (no slice 0) */ unsigned char* slice_img = &rtog_header->structures.skin_image[(num_slices-slice_no) * slice_voxels]; render_slice (rtog_header, slice_img, acc_img, &skin->pslist[i]); } free (acc_img); } void correct_skin (RTOG_Header* rtog_header) { int i, j, k; int num_slices = rtog_header->ct.last_image - rtog_header->ct.first_image + 1; int slice_voxels = rtog_header->ct.size_of_dimension_1 * rtog_header->ct.size_of_dimension_2; for (i = 0; i < num_slices; i++) { unsigned char* slice_img = &rtog_header->structures.skin_image[i * slice_voxels]; for (j = 0; j < rtog_header->ct.size_of_dimension_1 / 2; j++) { unsigned char* row1 = &slice_img[j*rtog_header->ct.size_of_dimension_2]; unsigned char* row2 = &slice_img[(rtog_header->ct.size_of_dimension_1-j-1)*rtog_header->ct.size_of_dimension_2]; for (k = 0; k < rtog_header->ct.size_of_dimension_2; k++) { unsigned char tmp = row1[k]; row1[k] = row2[k]; row2[k] = tmp; } } } } void write_skin (RTOG_Header* rtog_header, Program_Parms* parms) { FILE* fp; char fn[BUFLEN]; int num_slices = rtog_header->ct.last_image - rtog_header->ct.first_image + 1; int slice_voxels = rtog_header->ct.size_of_dimension_1 * rtog_header->ct.size_of_dimension_2; int num_voxels = slice_voxels * num_slices; make_output_dir (parms); printf ("Writing patient mask...\n"); snprintf (fn,BUFLEN,"%s/mask.mha",parms->outdir); fp = fopen (fn, "wb"); if (!fp) { printf ("Error opening %s for write\n", fn); exit (-1); } fprintf (fp, mha_header_pat, rtog_header->ct.grid_1_units * 10.0 / 2.0, rtog_header->ct.grid_2_units * 10.0 / 2.0, rtog_header->ct.z_spacing * 10.0 / 2.0, rtog_header->ct.grid_1_units * 10.0, rtog_header->ct.grid_2_units * 10.0, rtog_header->ct.z_spacing * 10.0, rtog_header->ct.size_of_dimension_2, rtog_header->ct.size_of_dimension_1, rtog_header->ct.last_image - rtog_header->ct.first_image + 1, "MET_UCHAR" ); fwrite (rtog_header->structures.skin_image, sizeof(unsigned char), num_voxels, fp); fclose (fp); } void free_skin (RTOG_Header* rtog_header) { free (rtog_header->structures.skin_image); } void write_rtog_dose (Program_Parms* parms) { #if defined (commentout) Volume* vol; FILE* fp; plm_long i; int slice_voxels; unsigned short *img_us, *p; float *img_f; vol = read_mha (parms->mha_in_fn); if (!vol) exit (-1); printf ("Scaling and converting (%ld pix)...\n", (long) vol->npix); img_f = (float*) vol->img; img_us = (unsigned short*) malloc (vol->npix * sizeof(unsigned short)); for (i = 0; i < vol->npix; i++) { float raw = img_f[i]; /* correct for scale */ unsigned short raw_us = (unsigned short) (raw / parms->scale); /* swap bytes */ unsigned short byte1 = (raw_us & 0xFF00) >> 8; unsigned short byte2 = (raw_us & 0x00FF) << 8; raw_us = byte1 | byte2; img_us[i] = raw_us; } printf ("Writing...\n"); fp = fopen (parms->rtog_dose_out_fn, "wb"); slice_voxels = vol->dim[0] * vol->dim[1]; p = img_us + vol->npix; for (i = 0; i < vol->dim[2]; i++) { p -= slice_voxels; fwrite (p, sizeof(unsigned short), slice_voxels, fp); } fclose (fp); free (img_us); free (vol->img); free (vol); #endif } #if defined (commentout) int main (int argc, char* argv[]) { Program_Parms parms; RTOG_Header rtog_header; parse_args (&parms, argc, argv); load_rtog_header (&rtog_header, &parms); /* Convert the CT cube */ load_ct (&rtog_header, &parms); correct_ct (&rtog_header); write_ct (&rtog_header, &parms); free_ct (&rtog_header); /* Convert the DOSE cube */ if (rtog_header.dose.imno > 0) { load_dose (&rtog_header, &parms); correct_dose (&rtog_header); write_dose (&rtog_header, &parms); free_dose (&rtog_header); } #if defined (commentout) #endif /* Convert the SKIN contours to a mask image */ load_skin (&rtog_header, &parms); render_skin (&rtog_header, &parms); correct_skin (&rtog_header); write_skin (&rtog_header, &parms); free_skin (&rtog_header); return 0; } #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtplan.cxx000066400000000000000000000057421321604176500275650ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include "plm_image_header.h" #include "plm_int.h" #include "plm_math.h" #include "rtplan_beam.h" #include "rtplan.h" #include "rt_study_metadata.h" #include "string_util.h" Rtplan::Rtplan() { this->number_of_fractions_planned = 0; } Rtplan::~Rtplan() { this->clear (); } void Rtplan::init(void) { this->clear (); } void Rtplan::clear(void) { this->number_of_fractions_planned = 0; this->patient_position = "HFS"; this->snout_id = ""; this->general_accessory_id = ""; this->general_accessory_code = ""; this->range_shifter_id = ""; this->range_shifter_code = ""; this->range_modulator_id = ""; this->range_modulator_code = ""; this->rt_plan_label = ""; this->rt_plan_name = ""; this->rt_plan_date = ""; this->rt_plan_time = ""; this->fraction_group_description = ""; this->number_of_fraction_pattern_digits_per_day = ""; this->repeat_fraction_cycle_length = ""; this->fraction_pattern = ""; this->tolerance_table_label = ""; this->tolerance_gantry_angle = ""; this->tolerance_patient_support_angle = ""; this->tolerance_table_top_vertical = ""; this->tolerance_table_top_longitudinal = ""; this->tolerance_table_top_lateral = ""; this->tolerance_table_top_pitch = ""; this->tolerance_table_top_roll = ""; this->tolerance_snout_position = ""; for (size_t i = 0; i < this->beamlist.size(); i++) { delete this->beamlist[i]; } this->beamlist.clear (); } /* Add structure (if it doesn't already exist) */ Rtplan_beam* Rtplan::add_beam ( const std::string& beam_name, int beam_id) { Rtplan_beam* new_beam; new_beam = this->find_beam_by_id(beam_id); if (new_beam) { return new_beam; } new_beam = new Rtplan_beam; new_beam->name = beam_name; if (beam_name == "") { new_beam->name = "Unknown beam"; } new_beam->name = string_trim (new_beam->name); this->beamlist.push_back (new_beam); return new_beam; } void Rtplan::delete_beam(int index) { delete this->beamlist[index]; this->beamlist.erase (this->beamlist.begin() + index); } Rtplan_beam* Rtplan::find_beam_by_id (size_t index) { if (index < this->beamlist.size()) { return this->beamlist[index]; } return 0; } void Rtplan::set_beam_name (size_t index, const std::string& name) { if (index < this->beamlist.size()) { this->beamlist[index]->name = name; } } std::string Rtplan::get_beam_name(size_t index) { if (index < this->beamlist.size()) { return this->beamlist[index]->name; } else { return ""; } } void Rtplan::debug(void) { } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtplan.h000066400000000000000000000043051321604176500272040ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rtplan_h_ #define _rtplan_h_ #include "plmbase_config.h" #include #include #include "direction_cosines.h" #include "plm_int.h" #include "rt_study_metadata.h" #include "smart_pointer.h" class Plm_image; class Plm_image_header; class Rtplan_beam; class PLMBASE_API Rtplan { public: SMART_POINTER_SUPPORT(Rtplan); public: size_t number_of_fractions_planned; std::string patient_position; std::string snout_id; std::string general_accessory_id; std::string general_accessory_code; std::string number_of_range_shifters; std::string range_shifter_id; std::string range_shifter_number; std::string range_shifter_code; std::string range_shifter_type; std::string range_modulator_id; std::string range_modulator_code; std::string patient_support_id; std::string patient_support_accessory_code; std::string rt_plan_label; std::string rt_plan_name; std::string rt_plan_date; std::string rt_plan_time; std::string fraction_group_description; std::string number_of_fraction_pattern_digits_per_day; std::string repeat_fraction_cycle_length; std::string fraction_pattern; std::string tolerance_table_label; std::string tolerance_gantry_angle; std::string tolerance_patient_support_angle; std::string tolerance_table_top_vertical; std::string tolerance_table_top_longitudinal; std::string tolerance_table_top_lateral; std::string tolerance_table_top_pitch; std::string tolerance_table_top_roll; std::string tolerance_snout_position; std::vector beamlist; public: Rtplan(); ~Rtplan(); void init (void); void clear (void); Rtplan_beam* add_beam ( const std::string& beam_name, int beam_id); void delete_beam (int index); Rtplan_beam* find_beam_by_id (size_t index); std::string get_beam_name (size_t index); void set_beam_name (size_t index, const std::string& name); void debug (void); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtplan_beam.cxx000066400000000000000000000054261321604176500305500ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "plm_math.h" #include "rtplan_control_pt.h" #include "rtplan_beam.h" #include "string_util.h" #include "logfile.h" Rtplan_beam::Rtplan_beam() { this->clear(); } Rtplan_beam::~Rtplan_beam() { this->clear (); } void Rtplan_beam::clear() { this->name = ""; this->description = ""; this->treatment_machine_name = ""; this->treatment_delivery_type = ""; this->final_cumulative_meterset_weight = 0.f; this->snout_position = 0.f; this->gantry_angle = 0.f; this->gantry_rotation_direction = "NONE"; this->beam_limiting_device_angle = 0.f; this->beam_limiting_device_rotation_direction = "NONE"; this->patient_support_angle = 0.f; this->patient_support_rotation_direction = "NONE"; this->table_top_vertical_position = 0.f; this->table_top_longitudinal_position = 0.f; this->table_top_lateral_position = 0.f; this->table_top_pitch_angle = 0.f; this->table_top_pitch_rotation_direction = "NONE"; this->table_top_roll_angle = 0.f; this->table_top_roll_rotation_direction = "NONE"; this->gantry_pitch_angle = 0.f; this->gantry_pitch_rotation_direction = "NONE"; this->isocenter_position[0] = 0.f; this->isocenter_position[1] = 0.f; this->isocenter_position[2] = 0.f; for (size_t i = 0; i < this->cplist.size(); i++) { delete this->cplist[i]; } this->cplist.clear (); } Rtplan_control_pt* Rtplan_beam::add_control_pt () { Rtplan_control_pt* new_control_pt = new Rtplan_control_pt; this->cplist.push_back (new_control_pt); return new_control_pt; } bool Rtplan_beam::check_isocenter_identical() { bool bSame = true; if (this->cplist.size() < 1) { return false; } float *firstIso = this->cplist[0]->get_isocenter(); for (size_t i = 1; i < this->cplist.size(); i++){ float *currIso = this->cplist[i]->get_isocenter(); if (firstIso[0] != currIso[0] || firstIso[1] != currIso[1] || firstIso[2] != currIso[2]) { bSame = false; break; } } /* list isocenter positions */ if (!bSame) { lprintf ("Warning! Isocenter positions are not same across the control points!\n"); for (size_t i = 0; i < this->cplist.size(); i++){ float *iso = this->cplist[i]->get_isocenter(); lprintf ("Control point idx: %d," " isocenter: %3.2f / %3.2f / %3.2f. \n", (int) i, iso[0], iso[1], iso[2]); } } return bSame; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtplan_beam.h000066400000000000000000000041531321604176500301710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rtplan_beam_h_ #define _rtplan_beam_h_ #include "plmbase_config.h" #include class Rtplan_control_pt; /*! \brief * The Rtplan_beam class describes a single beam within an Rtplan. */ class PLMBASE_API Rtplan_beam { public: /*! \brief Beam name */ std::string name; /*! \brief Beam description */ std::string description; /*! \other brief descriptions */ std::string treatment_machine_name; std::string treatment_delivery_type; std::string manufacturer; std::string institution_name; std::string institution_address; std::string institutional_department_name; std::string manufacturer_model_name; std::string virtual_source_axis_distances; /*! \brief Meterset at end of all control points */ float final_cumulative_meterset_weight; /*! \brief Coordiates of point where beam dose is specified */ std::string beam_dose_specification_point; /*! \brief Dose in Gy at beam specification point */ float beam_dose; float snout_position; float gantry_angle; std::string gantry_rotation_direction; float beam_limiting_device_angle; std::string beam_limiting_device_rotation_direction; float patient_support_angle; std::string patient_support_rotation_direction; float table_top_vertical_position; float table_top_longitudinal_position; float table_top_lateral_position; float table_top_pitch_angle; std::string table_top_pitch_rotation_direction; float table_top_roll_angle; std::string table_top_roll_rotation_direction; float gantry_pitch_angle; std::string gantry_pitch_rotation_direction; float isocenter_position[3]; /*! \brief Control point list */ std::vector cplist; public: Rtplan_beam(); ~Rtplan_beam(); void clear (); Rtplan_control_pt* add_control_pt (); bool check_isocenter_identical (); }; #endif rtplan_control_pt.cxx000066400000000000000000000032021321604176500317360ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "logfile.h" #include "plm_math.h" #include "rtplan_control_pt.h" Rtplan_control_pt::Rtplan_control_pt() { this->cumulative_meterset_weight = -1.f; this->nominal_beam_energy = -1.f; this->meterset_rate = 0.f; this->gantry_angle = 0.f; this->gantry_rotation_direction = "NONE"; this->gantry_pitch_angle = 0.f; this->gantry_pitch_rotation_direction = "NONE"; this->beam_limiting_device_angle = 0.f; this->beam_limiting_device_rotation_direction = "NONE"; this->scan_spot_tune_id = "Big Spots V2.3"; this->number_of_scan_spot_positions = 0; this->scan_spot_reordering_allowed = "ALLOWED"; this->number_of_paintings = 1; this->scanning_spot_size[0] = 1.0f; this->scanning_spot_size[1] = 1.0f; this->patient_support_angle = 0.f; this->patient_support_rotation_direction = "NONE"; this->table_top_pitch_angle = 0.f; this->table_top_pitch_rotation_direction = "NONE"; this->table_top_roll_angle = 0.f; this->table_top_roll_rotation_direction = "NONE"; this->table_top_vertical_position = 0.f; this->table_top_longitudinal_position = 0.f; this->table_top_lateral_position = 0.f; this->isocenter_position[0] = 0.f; this->isocenter_position[1] = 0.f; this->isocenter_position[2] = 0.f; } Rtplan_control_pt::~Rtplan_control_pt() { } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtplan_control_pt.h000066400000000000000000000033131321604176500314450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rtplan_control_pt_h_ #define _rtplan_control_pt_h_ #include "plmbase_config.h" #include #include class PLMBASE_API Rtplan_control_pt { public: float cumulative_meterset_weight; float nominal_beam_energy; float meterset_rate; float gantry_angle; std::string gantry_rotation_direction; float gantry_pitch_angle; std::string gantry_pitch_rotation_direction; float beam_limiting_device_angle; std::string beam_limiting_device_rotation_direction; std::string scan_spot_tune_id; size_t number_of_scan_spot_positions; std::string scan_spot_reordering_allowed; std::vector scan_spot_position_map; std::vector scan_spot_meterset_weights; size_t number_of_paintings; float scanning_spot_size[2]; float patient_support_angle; std::string patient_support_rotation_direction; float table_top_pitch_angle; std::string table_top_pitch_rotation_direction; float table_top_roll_angle; std::string table_top_roll_rotation_direction; float table_top_vertical_position; float table_top_longitudinal_position; float table_top_lateral_position; float isocenter_position[3]; public: Rtplan_control_pt(); ~Rtplan_control_pt(); float* get_isocenter () { return isocenter_position; } void set_isocenter (float *iso) { isocenter_position[0] = iso[0]; isocenter_position[1] = iso[1]; isocenter_position[2] = iso[2]; } }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtss.cxx000066400000000000000000000413401321604176500272520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include "logfile.h" #include "plm_image_header.h" #include "plm_int.h" #include "plm_math.h" #include "rtss_contour.h" #include "rtss_roi.h" #include "rtss.h" #include "rt_study_metadata.h" #include "slice_list.h" #include "string_util.h" static std::string assign_random_color () { static int idx = 0; static const char* colors[] = { "255 0 0", "255 255 0", "255 0 255", "0 255 255", "0 255 0", "0 0 255", "255 128 128", "255 255 128", "255 128 255", "128 255 255", "128 255 128", "128 128 255", "200 128 128", "200 200 128", "200 128 200", "128 200 200", "128 200 128", "128 128 200", "200 255 255", "200 200 255", "200 255 200", "255 200 200", "255 200 255", "255 255 200", }; std::string color = std::string (colors[idx]); if (++idx > 23) { idx = 0; } return color; } #define SPACING_TOL 0.2 /* How close you need to be to be on the slice */ Rtss::Rtss () { this->init (); } Rtss::~Rtss () { this->clear (); } void Rtss::init (void) { this->have_geometry = 0; this->num_structures = 0; this->slist = 0; } void Rtss::clear (void) { for (size_t i = 0; i < this->num_structures; i++) { delete (this->slist[i]); } free (this->slist); this->init (); } std::string Rtss::find_unused_structure_name (void) { std::string test_name; for (int n = 1; n < std::numeric_limits::max(); ++n) { bool dup_found = false; test_name = string_format ("%s (%d)", "Unknown structure", n); for (size_t i = 0; i < this->num_structures; ++i) { Rtss_roi* curr_structure = this->slist[i]; if (test_name == curr_structure->name) { dup_found = true; break; } } if (!dup_found) { break; } } return test_name; } /* Add structure (if it doesn't already exist) */ Rtss_roi* Rtss::add_structure ( const std::string& structure_name, const std::string& color, int structure_id, int bit) { Rtss_roi* new_structure; new_structure = this->find_structure_by_id (structure_id); if (new_structure) { return new_structure; } this->num_structures++; this->slist = (Rtss_roi**) realloc (this->slist, this->num_structures * sizeof(Rtss_roi*)); new_structure = this->slist[this->num_structures - 1] = new Rtss_roi; new_structure->name = structure_name; if (structure_name == "" || structure_name == "Unknown structure") { new_structure->name = find_unused_structure_name (); } new_structure->name = string_trim (new_structure->name); new_structure->id = structure_id; new_structure->bit = bit; if (color != "") { new_structure->color = color; } else { new_structure->color = assign_random_color (); } new_structure->num_contours = 0; new_structure->pslist = 0; return new_structure; } void Rtss::delete_structure (int index) { Rtss_roi* curr_structure = this->slist[index]; delete curr_structure; /* Remark: the below two lines are correct but redundant if (index == this->num_structures-1), but this comment to explain it is not worse than adding if statement. */ this->slist[index] = this->slist[this->num_structures-1]; this->num_structures --; } Rtss_roi* Rtss::find_structure_by_id (int structure_id) { for (size_t i = 0; i < this->num_structures; i++) { Rtss_roi* curr_structure; curr_structure = this->slist[i]; if (curr_structure->id == structure_id) { return curr_structure; } } return 0; } void Rtss::set_structure_name (size_t index, const std::string& name) { if (index < this->num_structures) { this->slist[index]->name = name.c_str(); } } std::string Rtss::get_structure_name (size_t index) { if (index < this->num_structures) { return std::string (this->slist[index]->name.c_str()); } else { return ""; } } void Rtss::debug (void) { Rtss_roi* curr_structure; if (this->have_geometry) { lprintf ("rps::dim = %u %u %u\n", (unsigned int) this->m_dim[0], (unsigned int) this->m_dim[1], (unsigned int) this->m_dim[2]); lprintf ("rps::offset = %g %g %g\n", this->m_offset[0], this->m_offset[1], this->m_offset[2]); lprintf ("rps::spacing = %g %g %g\n", this->m_spacing[0], this->m_spacing[1], this->m_spacing[2]); } else { lprintf ("rps has no geometry\n"); } for (size_t i = 0; i < this->num_structures; i++) { curr_structure = this->slist[i]; lprintf ("%u %d %s [%s] (%p) (%d contours)", (unsigned int) i, curr_structure->id, curr_structure->name.c_str(), (curr_structure->color.empty() ? "none" : curr_structure->color.c_str()), curr_structure->pslist, (int) curr_structure->num_contours ); if (curr_structure->num_contours) { if (curr_structure->pslist[0]->num_vertices) { lprintf (" [%f,%f,%f,...]", curr_structure->pslist[0]->x[0], curr_structure->pslist[0]->y[0], curr_structure->pslist[0]->z[0]); } else { lprintf (" "); } } lprintf ("\n"); } } void Rtss::adjust_structure_names (void) { Rtss_roi* curr_structure; for (size_t i = 0; i < this->num_structures; i++) { curr_structure = this->slist[i]; std::string tmp = curr_structure->name; for (size_t j = 0; j < curr_structure->name.length(); j++) { /* GE Adv sim doesn't like names with strange punctuation. */ if (! isalnum (curr_structure->name[j])) { curr_structure->name[j] = '_'; } } } } void Rtss::prune_empty (void) { for (size_t i = 0; i < this->num_structures; i++) { Rtss_roi* curr_structure; curr_structure = this->slist[i]; if (curr_structure->num_contours == 0) { delete curr_structure; /* Remark: the below two lines are correct but redundant if (i == this->num_structures-1), but this comment to explain it is not worse than adding if statement. */ this->slist[i] = this->slist[this->num_structures-1]; i --; this->num_structures --; } } } /* Copy structure name, id, color, but not contents */ Rtss* Rtss::clone_empty ( Rtss* cxt_out, Rtss* cxt_in ) { /* Initialize output cxt */ if (cxt_out) { cxt_out->clear (); } else { cxt_out = new Rtss; } for (size_t i = 0; i < cxt_in->num_structures; i++) { Rtss_roi *old_structure = cxt_in->slist[i]; Rtss_roi *new_structure = cxt_out->add_structure ( old_structure->name, old_structure->color, old_structure->id); /* Copy bit */ new_structure->bit = old_structure->bit; } return cxt_out; } /* Clear the polylines, but keep structure name, id, color */ void Rtss::free_all_polylines (void) { for (size_t i = 0; i < this->num_structures; i++) { Rtss_roi *curr_structure = this->slist[i]; for (size_t j = 0; j < curr_structure->num_contours; j++) { delete curr_structure->pslist[j]; } free (curr_structure->pslist); curr_structure->num_contours = 0; curr_structure->pslist = 0; } } void Rtss::find_rasterization_geometry ( float offset[3], float spacing[3], plm_long dims[3], Direction_cosines& dc ) { int first = 1; float min_x = 0.f, max_x = 0.f; float min_y = 0.f, max_y = 0.f; float min_z = 0.f, max_z = 0.f; std::set z_values; /* GCS TODO: Here is where the direction cosine detector goes */ #if defined (commentout) for (size_t i = 0; i < this->num_structures; i++) { Rtss_roi *curr_structure = this->slist[i]; for (size_t j = 0; j < curr_structure->num_contours; j++) { Rtss_contour *curr_polyline = curr_structure->pslist[j]; curr_polyline->find_direction_cosines (); continue; } } #endif /* Scan points to find image size, spacing */ for (size_t i = 0; i < this->num_structures; i++) { Rtss_roi *curr_structure = this->slist[i]; for (size_t j = 0; j < curr_structure->num_contours; j++) { Rtss_contour *curr_polyline = curr_structure->pslist[j]; for (size_t k = 0; k < curr_polyline->num_vertices; k++) { z_values.insert (curr_polyline->z[k]); if (first) { min_x = max_x = curr_polyline->x[k]; min_y = max_y = curr_polyline->y[k]; min_z = max_z = curr_polyline->z[k]; first = 0; continue; } if (curr_polyline->x[k] < min_x) { min_x = curr_polyline->x[k]; } else if (curr_polyline->x[k] > max_x) { max_x = curr_polyline->x[k]; } if (curr_polyline->y[k] < min_y) { min_y = curr_polyline->y[k]; } else if (curr_polyline->y[k] > max_y) { max_y = curr_polyline->y[k]; } if (curr_polyline->z[k] < min_z) { min_z = curr_polyline->z[k]; } else if (curr_polyline->z[k] > max_z) { max_z = curr_polyline->z[k]; } } } } /* Use heuristics to set (x,y) values */ float range_x = max_x - min_x; float range_y = max_y - min_y; float range = range_x; if (range_y > range) { range = range_y; } range = range * 1.05; spacing[0] = spacing[1] = range / 512; offset[0] = 0.5 * (max_x + min_x - range); offset[1] = 0.5 * (max_y + min_y - range); dims[0] = dims[1] = 512; #if defined (commentout) printf ("----Z VALUES-----\n"); for (std::set::iterator it = z_values.begin(); it != z_values.end(); it++) { printf ("%f\n", *it); } printf ("---------\n"); #endif /* z value should be based on native slice spacing */ int have_spacing = 0; float z_spacing = 0.f; float last_z = min_z; for (std::set::iterator it = z_values.begin(); it != z_values.end(); it++) { float this_z = *it; float diff = this_z - last_z; if (fabs (diff) < SPACING_TOL) { continue; } if (!have_spacing) { z_spacing = this_z - min_z; have_spacing = 1; } else { if (fabs (diff - z_spacing) > SPACING_TOL) { lprintf ("Warning, slice spacing of RTSS may be unequal\n"); lprintf ("%g - %g = %g vs. %g\n", this_z, last_z, diff, z_spacing); } } last_z = this_z; } offset[2] = min_z; if (have_spacing) { dims[2] = ROUND_INT ((max_z - min_z) / z_spacing); spacing[2] = z_spacing; } else { dims[2] = 1; spacing[2] = 1; } } void Rtss::find_rasterization_geometry (Plm_image_header *pih) { /* use some generic default parameters */ plm_long dim[3]; float origin[3]; float spacing[3]; Direction_cosines dc; this->find_rasterization_geometry (origin, spacing, dim, dc); pih->set_from_gpuit (dim, origin, spacing, dc); } void Rtss::set_rasterization_geometry (void) { this->find_rasterization_geometry ( this->rast_offset, this->rast_spacing, this->rast_dim, this->rast_dc ); lprintf ("rast_dim = %u %u %u\n", (unsigned int) this->rast_dim[0], (unsigned int) this->rast_dim[1], (unsigned int) this->rast_dim[2]); lprintf ("rast_offset = %g %g %g\n", this->rast_offset[0], this->rast_offset[1], this->rast_offset[2]); lprintf ("rast_spacing = %g %g %g\n", this->rast_spacing[0], this->rast_spacing[1], this->rast_spacing[2]); } void Rtss::apply_slice_list (const Rt_study_metadata::Pointer& rsm) { this->apply_slice_list (rsm->get_slice_list()); } void Rtss::apply_slice_list (const Slice_list *slice_list) { if (!slice_list->slice_list_complete()) { return; } const Plm_image_header *pih = slice_list->get_image_header (); /* Geometry */ pih->get_dim (this->m_dim); pih->get_origin (this->m_offset); pih->get_spacing (this->m_spacing); /* Slice numbers and slice uids */ for (size_t i = 0; i < this->num_structures; i++) { Rtss_roi *curr_structure = this->slist[i]; for (size_t j = 0; j < curr_structure->num_contours; j++) { Rtss_contour *curr_polyline = curr_structure->pslist[j]; if (curr_polyline->num_vertices <= 0) { continue; } curr_polyline->slice_no = slice_list->get_slice_index ( curr_polyline->z[0]); curr_polyline->ct_slice_uid = slice_list->get_slice_uid ( curr_polyline->slice_no); #if defined (commentout) rdd->get_slice_info ( &curr_polyline->slice_no, &curr_polyline->ct_slice_uid, curr_polyline->z[0]); #endif } } } void Rtss::fix_polyline_slice_numbers (void) { if (!this->have_geometry) return; for (size_t i = 0; i < this->num_structures; i++) { Rtss_roi *curr_structure = this->slist[i]; for (size_t j = 0; j < curr_structure->num_contours; j++) { Rtss_contour *curr_polyline = curr_structure->pslist[j]; if (curr_polyline->num_vertices == 0) { curr_polyline->slice_no = -1; continue; } float z = curr_polyline->z[0]; int slice_idx = ROUND_INT ( (z - this->m_offset[2]) / this->m_spacing[2]); if (slice_idx < 0 || slice_idx >= this->m_dim[2]) { curr_polyline->slice_no = -1; } else { curr_polyline->slice_no = slice_idx; } } } } void Rtss::set_geometry ( const Plm_image_header *pih ) { pih->get_origin (this->m_offset); pih->get_spacing (this->m_spacing); pih->get_dim (this->m_dim); this->have_geometry = 1; this->fix_polyline_slice_numbers (); } void Rtss::set_geometry ( const Plm_image::Pointer& pli ) { Plm_image_header pih; pih.set_from_plm_image (pli); this->set_geometry (&pih); } void Rtss::keyholize (void) { /* Loop through structures */ for (size_t i = 0; i < this->num_structures; i++) { lprintf ("Keyholizing structure %d.\n", i); Rtss_roi *curr_structure = this->slist[i]; /* Find groups of contours which lie on the same slice */ /* GCS FIX: This algorithm does not work on tilted slices */ std::vector used_contours; used_contours.assign (curr_structure->num_contours, false); for (size_t j = 0; j < curr_structure->num_contours; j++) { std::vector group_contours; Rtss_contour *group_polyline = curr_structure->pslist[j]; if (group_polyline->num_vertices == 0) { group_polyline->slice_no = -1; continue; } if (used_contours[j] == true) { continue; } float group_z = group_polyline->z[0]; group_contours.push_back (j); for (size_t k = j+1; k < curr_structure->num_contours; k++) { Rtss_contour *curr_polyline = curr_structure->pslist[k]; if (curr_polyline->num_vertices == 0) { curr_polyline->slice_no = -1; continue; } float curr_z = curr_polyline->z[0]; if (curr_z - group_z < SPACING_TOL) { used_contours[k] = true; group_contours.push_back (k); } } /* We have now found a group */ #if defined (commentout) lprintf ("Keyholizing group:"); for (size_t k = 0; k < group_contours.size(); k++) { lprintf (" %d", group_contours[k]); } lprintf ("\n"); #endif /* Find xmin for each contour in group */ std::vector group_xmin; group_xmin.assign (group_contours.size(), FLT_MAX); for (size_t k = 0; k < group_contours.size(); k++) { int cidx = group_contours[k]; Rtss_contour *curr_polyline = curr_structure->pslist[cidx]; for (size_t l = 0; l < curr_polyline->num_vertices; l++) { if (curr_polyline->x[l] < group_xmin[k]) { group_xmin[k] = curr_polyline->x[l]; } } } /* Find an outermost contour in group */ int cidx_xmin = -1; float xmin = FLT_MAX; for (size_t k = 0; k < group_contours.size(); k++) { int cidx = group_contours[k]; Rtss_contour *curr_polyline = curr_structure->pslist[cidx]; float curr_xmin = FLT_MAX; for (size_t l = 0; l < curr_polyline->num_vertices; l++) { if (curr_polyline->x[l] < curr_xmin) { curr_xmin = curr_polyline->x[l]; } } if (curr_xmin < xmin) { cidx_xmin = cidx; xmin = curr_xmin; } } #if defined (commentout) Rtss_contour *outer_polyline = curr_structure->pslist[ #endif #if defined (commentout) lprintf ("Outermost contour %d, x=%f\n", cidx_xmin, xmin); #endif /* Loop through other contours, find contours contained in this contour */ for (size_t k = 0; k < group_contours.size(); k++) { int cidx = group_contours[k]; Rtss_contour *curr_polyline = curr_structure->pslist[cidx]; if (cidx == cidx_xmin) { continue; } #if defined (commentout) /* Got to make a DAG ... ugh! */ if (contour_in_contour (curr_polyline, ...) #endif for (size_t l = 0; l < curr_polyline->num_vertices; l++) { float x = curr_polyline->x[0]; float y = curr_polyline->y[0]; } } } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtss.h000066400000000000000000000046121321604176500267000ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rtss_h_ #define _rtss_h_ #include "plmbase_config.h" #include #include #include "direction_cosines.h" #include "plm_int.h" #include "rt_study_metadata.h" #include "smart_pointer.h" class Plm_image; class Plm_image_header; class Rtss_roi; class Slice_list; /*! \brief * The Rtss class represents a set of segmentations in polyline format, * analogous to the DICOM-RT RTSTRUCT object. */ class PLMBASE_API Rtss { public: SMART_POINTER_SUPPORT (Rtss); public: /* Output geometry */ int have_geometry; plm_long m_dim[3]; float m_spacing[3]; float m_offset[3]; /* Rasterization geometry */ plm_long rast_dim[3]; float rast_spacing[3]; float rast_offset[3]; Direction_cosines rast_dc; /* Structures */ size_t num_structures; Rtss_roi **slist; public: Rtss (); ~Rtss (); void init (void); void clear (void); Rtss_roi* add_structure ( const std::string& structure_name, const std::string& color, int structure_id, int bit = -1); void delete_structure (int index); Rtss_roi* find_structure_by_id (int structure_id); std::string get_structure_name (size_t index); void set_structure_name (size_t index, const std::string& name); void debug (void); void adjust_structure_names (void); void prune_empty (void); static Rtss* clone_empty (Rtss* cxt_out, Rtss* cxt_in); void find_rasterization_geometry (float offset[3], float spacing[3], plm_long dims[3], Direction_cosines& dc); void find_rasterization_geometry (Plm_image_header *pih); std::string find_unused_structure_name (void); void fix_polyline_slice_numbers (void); /*! \brief Copy slice UIDs from referenced image into the Rtss object. */ void apply_slice_list (const Rt_study_metadata::Pointer& rsm); /*! \brief Copy slice UIDs from referenced image into the Rtss object. */ void apply_slice_list (const Slice_list *slice_list); void free_all_polylines (void); void keyholize (void); void set_rasterization_geometry (void); void set_geometry (const Plm_image_header *pih); void set_geometry (const Plm_image::Pointer& pli); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtss_contour.cxx000066400000000000000000000056061321604176500310300ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "logfile.h" #include "plm_math.h" #include "rtss_contour.h" Rtss_contour::Rtss_contour () { this->slice_no = -1; this->ct_slice_uid = ""; this->num_vertices = 0; this->x = 0; this->y = 0; this->z = 0; } Rtss_contour::~Rtss_contour () { free (this->x); free (this->y); free (this->z); this->slice_no = -1; this->ct_slice_uid = ""; this->num_vertices = 0; this->x = 0; this->y = 0; this->z = 0; } void Rtss_contour::find_direction_cosines () { /* Need at least three points to find slice plane */ if (this->num_vertices < 3) { lprintf ("Failed to find DC, not enough points\n"); return; } /* Find triangle with longest minimum legs using greedy search */ float p1[3], p2[3], p3[3]; p1[0] = this->x[0]; p1[1] = this->y[0]; p1[2] = this->z[0]; p2[0] = this->x[1]; p2[1] = this->y[1]; p2[2] = this->z[1]; p3[0] = this->x[2]; p3[1] = this->y[2]; p3[2] = this->z[2]; float p12_dist = vec3_distsq (p1, p2); float p23_dist = vec3_distsq (p2, p3); float p31_dist = vec3_distsq (p3, p1); printf ("%g %g %g\n", p12_dist, p23_dist, p31_dist); for (size_t k = 3; k < this->num_vertices; k++) { float pk[3]; pk[0] = this->x[k]; pk[1] = this->y[k]; pk[2] = this->z[k]; float p1k_dist = vec3_distsq (p1, pk); float p2k_dist = vec3_distsq (p2, pk); float p3k_dist = vec3_distsq (p3, pk); if (std::min (p1k_dist, p3k_dist) > std::min (p12_dist, p23_dist)) { vec3_copy (p2, pk); p12_dist = p1k_dist; p23_dist = p3k_dist; printf ("%g %g %g\n", p12_dist, p23_dist, p31_dist); continue; } if (std::min (p2k_dist, p3k_dist) > std::min (p12_dist, p31_dist)) { vec3_copy (p1, pk); p12_dist = p2k_dist; p31_dist = p3k_dist; printf ("%g %g %g\n", p12_dist, p23_dist, p31_dist); continue; } if (std::min (p2k_dist, p1k_dist) > std::min (p23_dist, p31_dist)) { vec3_copy (p3, pk); p23_dist = p2k_dist; p31_dist = p1k_dist; printf ("%g %g %g\n", p12_dist, p23_dist, p31_dist); continue; } } p12_dist = vec3_distsq (p1, p2); p23_dist = vec3_distsq (p2, p3); p31_dist = vec3_distsq (p3, p1); printf ("Final: %g %g %g\n", p12_dist, p23_dist, p31_dist); printf ("[%g %g %g]\n[%g %g %g]\n[%g %g %g]\n", p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], p3[0], p3[1], p3[2]); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtss_contour.h000066400000000000000000000011501321604176500304430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rtss_contour_h_ #define _rtss_contour_h_ #include "plmbase_config.h" #include class PLMBASE_API Rtss_contour { public: int slice_no; /* Can be "-1" */ std::string ct_slice_uid; size_t num_vertices; float* x; float* y; float* z; public: Rtss_contour (); ~Rtss_contour (); public: void find_direction_cosines (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtss_roi.cxx000066400000000000000000000055561321604176500301340ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "plm_math.h" #include "rtss_contour.h" #include "rtss_roi.h" #include "string_util.h" Rtss_roi::Rtss_roi () { this->id = -1; this->bit = 0; this->num_contours = 0; this->pslist = 0; } Rtss_roi::~Rtss_roi () { this->clear (); } void Rtss_roi::clear () { for (size_t i = 0; i < this->num_contours; i++) { delete this->pslist[i]; } free (this->pslist); this->name = ""; this->color = ""; this->id = -1; this->bit = 0; this->num_contours = 0; this->pslist = 0; } Rtss_contour* Rtss_roi::add_polyline () { Rtss_contour* new_polyline; this->num_contours++; this->pslist = (Rtss_contour**) realloc (this->pslist, this->num_contours * sizeof(Rtss_contour*)); new_polyline = this->pslist[this->num_contours - 1] = new Rtss_contour; return new_polyline; } Rtss_contour* Rtss_roi::add_polyline (size_t num_vertices) { Rtss_contour* rtss_contour = this->add_polyline(); rtss_contour->num_vertices = num_vertices; rtss_contour->slice_no = -1; rtss_contour->ct_slice_uid = ""; rtss_contour->x = (float*) malloc (num_vertices * sizeof(float)); rtss_contour->y = (float*) malloc (num_vertices * sizeof(float)); rtss_contour->z = (float*) malloc (num_vertices * sizeof(float)); return rtss_contour; } std::string Rtss_roi::adjust_name (const std::string& name_in) { /* GE Adv sim doesn't like names with strange punctuation. */ /* 3D Slicer color table doesn't allow spaces */ std::string name_out = name_in; for (size_t i = 0; i < name_in.length(); i++) { if (isalnum (name_in[i])) { name_out[i] = name_in[i]; } else { name_out[i] = '_'; } } return name_out; } void Rtss_roi::set_color (const char* color_string) { int r = 255, g = 0, b = 0; if (color_string) { if (3 == sscanf (color_string, "%d %d %d", &r, &g, &b)) { /* Parsed OK */ } else if (3 == sscanf (color_string, "%d\\%d\\%d", &r, &g, &b)) { /* Parsed OK */ } else { r = 255; g = 0; b = 0; } } this->color = string_format ("%d %d %d", r, g, b); } std::string Rtss_roi::get_dcm_color_string () const { int r, g, b; this->get_rgb (&r, &g, &b); return string_format ("%d\\%d\\%d", r, g, b); } void Rtss_roi::get_rgb (int *r, int *g, int *b) const { *r = 255; *g = 0; *b = 0; if (this->color.empty()) { return; } /* Ignore return code -- unparsed values will remain unassigned */ sscanf (this->color.c_str(), "%d %d %d", r, g, b); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/rtss_roi.h000066400000000000000000000017361321604176500275550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rtss_roi_h_ #define _rtss_roi_h_ #include "plmbase_config.h" #include class Rtss_contour; class PLMBASE_API Rtss_roi { public: std::string name; std::string color; int id; /* Used for import/export (must be >= 1) */ int bit; /* Used for ss-img (-1 for no bit) */ size_t num_contours; Rtss_contour** pslist; public: Rtss_roi (); ~Rtss_roi (); void clear (); Rtss_contour* add_polyline (); Rtss_contour* add_polyline (size_t num_vertices); void set_color (const char* color_string); std::string get_dcm_color_string () const; void get_rgb (int *r, int *g, int *b) const; static std::string adjust_name (const std::string& name_in); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/segmentation.cxx000066400000000000000000000637341321604176500307670ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionIterator.h" #if PLM_DCM_USE_GDCM1 #include "gdcm1_dose.h" #include "gdcm1_rtss.h" #endif #include "cxt_extract.h" #include "cxt_io.h" #include "dir_list.h" #include "file_util.h" #include "itk_image_save.h" #include "itk_image_type.h" #include "itk_resample.h" #include "logfile.h" #include "path_util.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_warp.h" #include "pointset.h" #include "print_and_exit.h" #include "rasterizer.h" #include "rt_study.h" #include "rt_study_metadata.h" #include "rtss.h" #include "rtss_contour.h" #include "rtss_roi.h" #include "segmentation.h" #include "ss_list_io.h" #include "ss_img_extract.h" #include "ss_img_stats.h" #include "string_util.h" #include "warp_parms.h" #include "xio_structures.h" class Segmentation_private { public: Plm_image::Pointer m_labelmap; /* Structure set lossy bitmap form */ Plm_image::Pointer m_ss_img; /* Structure set in lossless bitmap form */ Rtss::Pointer m_rtss; /* Structure set in polyline form */ bool m_rtss_valid; bool m_ss_img_valid; public: Segmentation_private () { m_rtss_valid = false; m_ss_img_valid = false; } ~Segmentation_private () { } }; static std::string compose_prefix_fn ( const std::string& output_prefix, const std::string& structure_name, const char* extension ) { return string_format ("%s/%s.%s", output_prefix.c_str(), structure_name.c_str(), extension); } Segmentation::Segmentation () { this->d_ptr = new Segmentation_private; } Segmentation::~Segmentation () { clear (); delete this->d_ptr; } void Segmentation::clear () { d_ptr->m_rtss.reset(); d_ptr->m_ss_img.reset(); d_ptr->m_labelmap.reset(); d_ptr->m_rtss_valid = false; d_ptr->m_ss_img_valid = false; } void Segmentation::load (const char *ss_img, const char *ss_list) { /* Load ss_img */ if (d_ptr->m_ss_img) { d_ptr->m_ss_img.reset(); } if (ss_img && file_exists (ss_img)) { d_ptr->m_ss_img = plm_image_load_native (ss_img); } /* Load ss_list */ if (d_ptr->m_rtss) { d_ptr->m_rtss.reset(); } if (ss_list && file_exists (ss_list)) { lprintf ("Trying to load ss_list: %s\n", ss_list); d_ptr->m_rtss.reset (ss_list_load (0, ss_list)); } if (d_ptr->m_rtss) { d_ptr->m_rtss->free_all_polylines (); } d_ptr->m_rtss_valid = false; d_ptr->m_ss_img_valid = true; } void Segmentation::load_prefix (const std::string& prefix_dir) { this->load_prefix (prefix_dir.c_str()); } void Segmentation::load_prefix (const char *prefix_dir) { /* Clear out any existing structures */ this->clear (); /* Load the list of files in the directory */ Dir_list dl; dl.load (prefix_dir); /* Make a quick pass through the directory to find the number of files. This is used to size the ss_img. */ int max_structures = 0; for (int i = 0; i < dl.num_entries; i++) { /* Look at filename, make sure it is an mha or nrrd file */ const char *entry = dl.entries[i]; if (!extension_is (entry, ".mha") && !extension_is (entry, ".nrrd")) { continue; } max_structures++; } int out_vec_len = 1 + (max_structures - 1) / 8; if (out_vec_len < 2) out_vec_len = 2; /* Make a second pass that actually loads the files */ bool first = true; int bit = 0; UCharVecImageType::Pointer ss_img; Plm_image_header ss_img_pih; for (int i = 0; i < dl.num_entries; i++) { /* Look at filename, make sure it is an mha or nrrd file */ const char *entry = dl.entries[i]; if (!extension_is (entry, ".mha") && !extension_is (entry, ".nrrd")) { continue; } /* Grab the structure name from the filename */ char *structure_name = strdup (entry); strip_extension (structure_name); lprintf ("Loading structure: %s\n", structure_name); /* Load the file */ std::string input_fn = string_format ("%s/%s", prefix_dir, entry); Plm_image img (input_fn, PLM_IMG_TYPE_ITK_UCHAR); Plm_image_header pih (img); if (first) { this->initialize_ss_image (pih, out_vec_len); ss_img = d_ptr->m_ss_img->itk_uchar_vec (); Plm_image_header::clone (&ss_img_pih, &pih); first = false; } else { ss_img_pih.print(); if (!Plm_image_header::compare (&pih, &ss_img_pih)) { print_and_exit ("Image size mismatch when loading prefix_dir\n"); } } /* Add name to ss_list */ d_ptr->m_rtss->add_structure ( structure_name, "", d_ptr->m_rtss->num_structures + 1, bit); free (structure_name); /* GCS FIX: This code is replicated in ss_img_extract */ unsigned int uchar_no = bit / 8; unsigned int bit_no = bit % 8; unsigned char bit_mask = 1 << bit_no; if (uchar_no > ss_img->GetVectorLength()) { print_and_exit ("Error. Ss_img vector is too small.\n"); } /* Set up iterators for looping through images */ typedef itk::ImageRegionConstIterator< UCharImageType > UCharIteratorType; typedef itk::ImageRegionIterator< UCharVecImageType > UCharVecIteratorType; UCharImageType::Pointer uchar_img = img.itk_uchar(); UCharIteratorType uchar_img_it (uchar_img, uchar_img->GetLargestPossibleRegion()); UCharVecIteratorType ss_img_it (ss_img, ss_img->GetLargestPossibleRegion()); /* Loop through voxels, or'ing them into ss_img */ /* GCS FIX: This is inefficient, due to undesirable construct and destruct of itk::VariableLengthVector of each pixel */ for ( uchar_img_it.GoToBegin(), ss_img_it.GoToBegin(); !uchar_img_it.IsAtEnd(); ++uchar_img_it, ++ss_img_it ) { unsigned char u = uchar_img_it.Get (); if (!u) continue; itk::VariableLengthVector v = ss_img_it.Get (); v[uchar_no] |= bit_mask; ss_img_it.Set (v); } /* Move to next bit */ bit++; } if (d_ptr->m_rtss) { d_ptr->m_rtss->free_all_polylines (); } d_ptr->m_rtss_valid = false; d_ptr->m_ss_img_valid = true; } void Segmentation::add_structure ( UCharImageType::Pointer itk_image, const char *structure_name, const char *structure_color) { Plm_image_header pih (itk_image); /* Allocate image if this is the first structure */ if (!d_ptr->m_ss_img) { this->initialize_ss_image (pih, 2); } else { /* Make sure image size is the same */ Plm_image_header ss_img_pih (d_ptr->m_ss_img); if (!Plm_image_header::compare (&pih, &ss_img_pih)) { print_and_exit ("Image size mismatch when adding structure\n"); } } /* Figure out basic structure info */ if (!structure_name) { structure_name = ""; } if (!structure_color) { structure_color = ""; } int bit = d_ptr->m_rtss->num_structures; /* GCS FIX: I hope this is ok */ /* Add structure to rtss */ d_ptr->m_rtss->add_structure ( structure_name, structure_color, d_ptr->m_rtss->num_structures + 1, bit); /* Set bit within ss_img */ this->set_structure_image (itk_image, bit); if (d_ptr->m_rtss) { d_ptr->m_rtss->free_all_polylines (); } d_ptr->m_rtss_valid = false; d_ptr->m_ss_img_valid = true; } Rtss_roi * Segmentation::add_rtss_roi ( const char *structure_name, const char *structure_color) { /* Allocate rtss if first time called */ if (!d_ptr->m_rtss_valid) { /* GCS FIX: In principle, I should convert existing ss_image planes into rtss format first */ d_ptr->m_rtss = Rtss::New(); d_ptr->m_ss_img = Plm_image::Pointer(); d_ptr->m_rtss_valid = true; d_ptr->m_ss_img_valid = false; } /* Figure out basic structure info */ if (!structure_name) { structure_name = ""; } if (!structure_color) { structure_color = ""; } int bit = d_ptr->m_rtss->num_structures; /* Add structure to rtss */ Rtss_roi *rtss_roi = d_ptr->m_rtss->add_structure ( structure_name, structure_color, d_ptr->m_rtss->num_structures + 1, bit); return rtss_roi; } void Segmentation::load_cxt (const std::string& input_fn, Rt_study_metadata *rsm) { d_ptr->m_rtss = Rtss::New(); cxt_load (d_ptr->m_rtss.get(), rsm, input_fn.c_str()); d_ptr->m_rtss_valid = true; d_ptr->m_ss_img_valid = false; } void Segmentation::load_gdcm_rtss (const char *input_fn, Rt_study_metadata *rsm) { #if PLM_DCM_USE_GDCM1 d_ptr->m_rtss = Rtss::New(); gdcm_rtss_load (d_ptr->m_rtss.get(), rsm, input_fn); d_ptr->m_rtss_valid = true; d_ptr->m_ss_img_valid = false; #endif } void Segmentation::load_xio (const Xio_studyset& studyset) { d_ptr->m_rtss = Rtss::New(); lprintf ("calling xio_structures_load\n"); xio_structures_load (d_ptr->m_rtss.get(), studyset); d_ptr->m_rtss_valid = true; d_ptr->m_ss_img_valid = false; } size_t Segmentation::get_num_structures () { if (d_ptr->m_rtss) { return d_ptr->m_rtss->num_structures; } return 0; } std::string Segmentation::get_structure_name (size_t index) { if (d_ptr->m_rtss) { return d_ptr->m_rtss->get_structure_name (index); } return 0; } void Segmentation::set_structure_name (size_t index, const std::string& name) { if (!d_ptr->m_rtss) { return; } d_ptr->m_rtss->set_structure_name (index, name); } UCharImageType::Pointer Segmentation::get_structure_image (int index) { if (!d_ptr->m_ss_img) { print_and_exit ( "Error extracting unknown structure image (no ssi %d)\n", index); } if (!d_ptr->m_rtss) { print_and_exit ( "Error extracting unknown structure image (no cxt %d)\n", index); } Rtss_roi *curr_structure = d_ptr->m_rtss->slist[index]; int bit = curr_structure->bit; if (bit == -1) { print_and_exit ( "Error extracting unknown structure image (no bit %d)\n", index); } UCharImageType::Pointer prefix_img = ss_img_extract_bit (d_ptr->m_ss_img, bit); return prefix_img; } void Segmentation::save_colormap (const std::string& colormap_fn) { ss_list_save_colormap (d_ptr->m_rtss.get(), colormap_fn.c_str()); } void Segmentation::save_cxt ( const Rt_study_metadata::Pointer& rsm, const std::string& cxt_fn, bool prune_empty ) { cxt_save (d_ptr->m_rtss.get(), rsm, cxt_fn.c_str(), prune_empty); } void Segmentation::save_gdcm_rtss ( const char *output_dir, const Rt_study_metadata::Pointer& rsm ) { std::string fn; /* Perform destructive keyholization of the cxt. This is necessary because DICOM-RT requires that structures with holes be defined using a single structure */ d_ptr->m_rtss->keyholize (); /* Some systems (GE ADW) do not allow special characters in structure names. */ d_ptr->m_rtss->adjust_structure_names (); if (rsm) { this->apply_dicom_dir (rsm); } fn = string_format ("%s/%s", output_dir, "rtss.dcm"); #if PLM_DCM_USE_GDCM1 gdcm_rtss_save (d_ptr->m_rtss.get(), rsm, fn.c_str()); #else /* GDCM 2 not implemented -- you're out of luck. */ #endif } void Segmentation::save_fcsv ( const Rtss_roi *curr_structure, const std::string& fn ) { Labeled_pointset pointset; for (size_t j = 0; j < curr_structure->num_contours; j++) { Rtss_contour *curr_polyline = curr_structure->pslist[j]; for (size_t k = 0; k < curr_polyline->num_vertices; k++) { pointset.insert_lps ("", curr_polyline->x[k], curr_polyline->y[k], curr_polyline->z[k]); } } pointset.save_fcsv (fn); } void Segmentation::save_prefix_fcsv (const std::string& output_prefix) { if (!d_ptr->m_rtss) { print_and_exit ( "Error: save_prefix_fcsv() tried to save a RTSS without a CXT\n"); } for (size_t i = 0; i < d_ptr->m_rtss->num_structures; i++) { Rtss_roi *curr_structure = d_ptr->m_rtss->slist[i]; std::string fn = compose_prefix_fn (output_prefix, curr_structure->name, "fcsv"); save_fcsv (curr_structure, fn); } } void Segmentation::save_ss_image (const std::string& ss_img_fn) { if (!d_ptr->m_ss_img) { print_and_exit ( "Error: save_ss_image() tried to write a non-existant ss_img\n"); } if (d_ptr->m_ss_img->m_type == PLM_IMG_TYPE_GPUIT_UCHAR_VEC || d_ptr->m_ss_img->m_type == PLM_IMG_TYPE_ITK_UCHAR_VEC) { /* Image type must be uchar vector */ d_ptr->m_ss_img->convert (PLM_IMG_TYPE_ITK_UCHAR_VEC); } else { /* Image type must be uint32_t */ d_ptr->m_ss_img->convert (PLM_IMG_TYPE_ITK_ULONG); } d_ptr->m_ss_img->save_image (ss_img_fn); } void Segmentation::save_labelmap (const std::string& labelmap_fn) { d_ptr->m_labelmap->save_image (labelmap_fn); } void Segmentation::save_prefix (const std::string &output_prefix, const std::string& extension) { if (!d_ptr->m_ss_img) { return; } if (!d_ptr->m_rtss) { printf ("WTF???\n"); } for (size_t i = 0; i < d_ptr->m_rtss->num_structures; i++) { std::string fn; Rtss_roi *curr_structure = d_ptr->m_rtss->slist[i]; int bit = curr_structure->bit; if (bit == -1) continue; UCharImageType::Pointer prefix_img = ss_img_extract_bit (d_ptr->m_ss_img, bit); fn = string_format ("%s/%s.%s", output_prefix.c_str(), curr_structure->name.c_str(), extension.c_str()); itk_image_save (prefix_img, fn.c_str()); } } void Segmentation::save_prefix (const char *output_prefix) { this->save_prefix (std::string (output_prefix)); } void Segmentation::save_ss_list (const std::string& ss_list_fn) { ss_list_save (d_ptr->m_rtss.get(), ss_list_fn.c_str()); } void Segmentation::save_xio ( const Rt_study_metadata::Pointer& rsm, Xio_ct_transform *xio_transform, Xio_version xio_version, const std::string &output_dir ) { xio_structures_save (rsm, d_ptr->m_rtss.get(), xio_transform, xio_version, output_dir.c_str()); } UInt32ImageType::Pointer Segmentation::get_ss_img_uint32 (void) { if (!d_ptr->m_ss_img) { print_and_exit ("Sorry, can't get_ss_img()\n"); } d_ptr->m_ss_img->convert (PLM_IMG_TYPE_ITK_ULONG); return d_ptr->m_ss_img->m_itk_uint32; } UCharVecImageType::Pointer Segmentation::get_ss_img_uchar_vec (void) { if (!d_ptr->m_ss_img) { print_and_exit ("Sorry, can't get_ss_img()\n"); } d_ptr->m_ss_img->convert (PLM_IMG_TYPE_ITK_UCHAR_VEC); return d_ptr->m_ss_img->m_itk_uchar_vec; } void Segmentation::apply_dicom_dir (const Rt_study_metadata::Pointer& rsm) { if (!d_ptr->m_rtss) { return; } if (!rsm || !rsm->slice_list_complete()) { return; } d_ptr->m_rtss->apply_slice_list (rsm); } void Segmentation::convert_ss_img_to_cxt (void) { /* Only convert if ss_img found */ if (!d_ptr->m_ss_img) { return; } /* Allocate memory for cxt */ bool use_existing_bits; if (d_ptr->m_rtss) { use_existing_bits = true; } else { d_ptr->m_rtss = Rtss::New(); use_existing_bits = false; } /* Copy geometry from ss_img to cxt */ d_ptr->m_rtss->set_geometry (d_ptr->m_ss_img); if (d_ptr->m_ss_img->m_type == PLM_IMG_TYPE_GPUIT_UCHAR_VEC || d_ptr->m_ss_img->m_type == PLM_IMG_TYPE_ITK_UCHAR_VEC) { /* Image type must be uchar vector */ d_ptr->m_ss_img->convert (PLM_IMG_TYPE_ITK_UCHAR_VEC); /* Do extraction */ lprintf ("Doing extraction\n"); ::cxt_extract (d_ptr->m_rtss.get(), d_ptr->m_ss_img->m_itk_uchar_vec, -1, use_existing_bits); } else { /* Image type must be uint32_t */ d_ptr->m_ss_img->convert (PLM_IMG_TYPE_ITK_ULONG); /* Do extraction */ lprintf ("Doing extraction\n"); ::cxt_extract (d_ptr->m_rtss.get(), d_ptr->m_ss_img->m_itk_uint32, -1, use_existing_bits); } d_ptr->m_rtss_valid = true; } void Segmentation::convert_to_uchar_vec (void) { if (!d_ptr->m_ss_img) { print_and_exit ( "Error: convert_to_uchar_vec() requires an image\n"); } d_ptr->m_ss_img->convert (PLM_IMG_TYPE_ITK_UCHAR_VEC); } void Segmentation::cxt_extract (void) { if (d_ptr->m_ss_img && !d_ptr->m_rtss_valid) { this->convert_ss_img_to_cxt (); } } void Segmentation::cxt_re_extract (void) { d_ptr->m_rtss->free_all_polylines (); if (d_ptr->m_ss_img->m_type == PLM_IMG_TYPE_GPUIT_UCHAR_VEC || d_ptr->m_ss_img->m_type == PLM_IMG_TYPE_ITK_UCHAR_VEC) { d_ptr->m_ss_img->convert (PLM_IMG_TYPE_ITK_UCHAR_VEC); ::cxt_extract (d_ptr->m_rtss.get(), d_ptr->m_ss_img->m_itk_uchar_vec, d_ptr->m_rtss->num_structures, true); } else { d_ptr->m_ss_img->convert (PLM_IMG_TYPE_ITK_ULONG); ::cxt_extract (d_ptr->m_rtss.get(), d_ptr->m_ss_img->m_itk_uint32, d_ptr->m_rtss->num_structures, true); } d_ptr->m_rtss_valid = true; } void Segmentation::prune_empty (void) { if (d_ptr->m_rtss && d_ptr->m_rtss_valid) { d_ptr->m_rtss->prune_empty (); } } void Segmentation::keyholize () { if (d_ptr->m_rtss && d_ptr->m_rtss_valid) { d_ptr->m_rtss->keyholize (); } } void Segmentation::rasterize ( Plm_image_header *pih, bool want_labelmap, bool xor_overlapping ) { /* Rasterize structure sets */ Rasterizer rasterizer; bool use_ss_img_vec = true; printf ("Rasterizing...\n"); rasterizer.rasterize (d_ptr->m_rtss.get(), pih, false, want_labelmap, true, use_ss_img_vec, xor_overlapping); /* Convert rasterized structure sets from vol to plm_image */ printf ("Converting...\n"); if (want_labelmap) { d_ptr->m_labelmap = Plm_image::New(); d_ptr->m_labelmap->set_volume (rasterizer.labelmap_vol); rasterizer.labelmap_vol = 0; } d_ptr->m_ss_img = Plm_image::New(); if (use_ss_img_vec) { d_ptr->m_ss_img->set_itk (rasterizer.m_ss_img->m_itk_uchar_vec); } else { Volume::Pointer v = rasterizer.m_ss_img->get_volume(); d_ptr->m_ss_img->set_volume (v); } lprintf ("Finished rasterization.\n"); d_ptr->m_ss_img_valid = true; } void Segmentation::set_geometry (const Plm_image_header *pih) { if (d_ptr->m_rtss) { d_ptr->m_rtss->set_geometry (pih); } } void Segmentation::find_rasterization_geometry (Plm_image_header *pih) { if (d_ptr->m_rtss) { d_ptr->m_rtss->find_rasterization_geometry (pih); } } Segmentation::Pointer Segmentation::warp_nondestructive ( const Xform::Pointer& xf, Plm_image_header *pih, bool use_itk) const { Segmentation::Pointer rtss_warped = Segmentation::New (); rtss_warped->d_ptr->m_rtss = Rtss::New ( Rtss::clone_empty (0, d_ptr->m_rtss.get())); rtss_warped->d_ptr->m_rtss_valid = false; if (d_ptr->m_labelmap) { printf ("Warping labelmap.\n"); Plm_image::Pointer tmp = Plm_image::New(); plm_warp (tmp, 0, xf, pih, d_ptr->m_labelmap, 0, use_itk, 0); rtss_warped->d_ptr->m_labelmap = tmp; rtss_warped->d_ptr->m_labelmap->convert (PLM_IMG_TYPE_ITK_ULONG); } if (d_ptr->m_ss_img) { printf ("Warping ss_img.\n"); Plm_image::Pointer tmp = Plm_image::New(); plm_warp (tmp, 0, xf, pih, d_ptr->m_ss_img, 0, use_itk, 0); rtss_warped->d_ptr->m_ss_img = tmp; } return rtss_warped; } void Segmentation::warp ( const Xform::Pointer& xf, Plm_image_header *pih, bool use_itk) { if (d_ptr->m_labelmap) { printf ("Warping labelmap.\n"); Plm_image::Pointer tmp = Plm_image::New(); plm_warp (tmp, 0, xf, pih, d_ptr->m_labelmap, 0, use_itk, 0); d_ptr->m_labelmap = tmp; d_ptr->m_labelmap->convert (PLM_IMG_TYPE_ITK_ULONG); } if (d_ptr->m_ss_img) { printf ("Warping ss_img.\n"); Plm_image::Pointer tmp = Plm_image::New(); plm_warp (tmp, 0, xf, pih, d_ptr->m_ss_img, 0, use_itk, 0); d_ptr->m_ss_img = tmp; } /* The cxt polylines are now obsolete */ if (d_ptr->m_rtss) { d_ptr->m_rtss->free_all_polylines (); } d_ptr->m_rtss_valid = false; } void Segmentation::warp ( const Xform::Pointer& xf, Plm_image_header *pih, Warp_parms *parms) { this->warp (xf, pih, parms->use_itk); } bool Segmentation::have_ss_img () { return d_ptr->m_ss_img != 0; } void Segmentation::set_ss_img (UCharImageType::Pointer ss_img) { d_ptr->m_ss_img = Plm_image::New(); d_ptr->m_ss_img->set_itk (ss_img); if (d_ptr->m_rtss) { d_ptr->m_rtss->free_all_polylines (); } d_ptr->m_rtss_valid = false; d_ptr->m_ss_img_valid = true; } Plm_image::Pointer Segmentation::get_ss_img () { return d_ptr->m_ss_img; } bool Segmentation::have_structure_set () { return d_ptr->m_rtss != 0; } Rtss::Pointer& Segmentation::get_structure_set () { return d_ptr->m_rtss; } Rtss * Segmentation::get_structure_set_raw () { return d_ptr->m_rtss.get(); } void Segmentation::set_structure_set (Rtss::Pointer& rtss_ss) { d_ptr->m_rtss = rtss_ss; d_ptr->m_rtss_valid = true; d_ptr->m_ss_img_valid = false; } void Segmentation::set_structure_set (Rtss *rtss_ss) { d_ptr->m_rtss.reset (rtss_ss); d_ptr->m_rtss_valid = true; d_ptr->m_ss_img_valid = false; } void Segmentation::set_structure_image ( UCharImageType::Pointer uchar_img, unsigned int bit ) { /* Figure out which bit of which byte to change */ unsigned int uchar_no = bit / 8; unsigned int bit_no = bit % 8; unsigned char bit_mask = 1 << bit_no; /* Expand vector length if needed */ UCharVecImageType::Pointer ss_img = d_ptr->m_ss_img->itk_uchar_vec (); if (uchar_no > ss_img->GetVectorLength()) { this->broaden_ss_image (uchar_no); } /* Set up iterators for looping through images */ typedef itk::ImageRegionConstIterator< UCharImageType > UCharIteratorType; typedef itk::ImageRegionIterator< UCharVecImageType > UCharVecIteratorType; UCharIteratorType uchar_img_it (uchar_img, uchar_img->GetLargestPossibleRegion()); UCharVecIteratorType ss_img_it (ss_img, ss_img->GetLargestPossibleRegion()); /* Loop through voxels, or'ing them into ss_img */ /* GCS FIX: This is inefficient, due to undesirable construct and destruct of itk::VariableLengthVector of each pixel */ for (uchar_img_it.GoToBegin(), ss_img_it.GoToBegin(); !uchar_img_it.IsAtEnd(); ++uchar_img_it, ++ss_img_it ) { unsigned char u = uchar_img_it.Get (); if (!u) continue; itk::VariableLengthVector v = ss_img_it.Get (); v[uchar_no] |= bit_mask; ss_img_it.Set (v); } } void Segmentation::resample (float spacing[3]) { d_ptr->m_ss_img->set_itk ( resample_image (d_ptr->m_ss_img->itk_uchar_vec (), spacing)); } /* ----------------------------------------------------------------------- Protected member functions ----------------------------------------------------------------------- */ void Segmentation::initialize_ss_image ( const Plm_image_header& pih, int vector_length) { UCharVecImageType::Pointer ss_img; Plm_image_header ss_img_pih; /* Create ss_image with same resolution as first image */ d_ptr->m_ss_img = Plm_image::New (); ss_img = UCharVecImageType::New (); itk_image_set_header (ss_img, pih); ss_img->SetVectorLength (vector_length); ss_img->Allocate (); /* GCS NOTE: For some reason, ss_img->FillBuffer (0) doesn't do what I want. */ itk::VariableLengthVector v; v.SetSize (vector_length); v.Fill (0); ss_img->FillBuffer (v); d_ptr->m_ss_img->set_itk (ss_img); Plm_image_header::clone (&ss_img_pih, &pih); /* Create ss_list to hold strucure names */ d_ptr->m_rtss = Rtss::New(); d_ptr->m_rtss->set_geometry (d_ptr->m_ss_img); } void Segmentation::broaden_ss_image (int new_vector_length) { /* Get old image */ UCharVecImageType::Pointer old_ss_img = d_ptr->m_ss_img->itk_uchar_vec (); Plm_image_header pih (old_ss_img); /* Create new image */ UCharVecImageType::Pointer new_ss_img = UCharVecImageType::New (); itk_image_set_header (new_ss_img, pih); new_ss_img->SetVectorLength (new_vector_length); new_ss_img->Allocate (); /* Create "pixels" */ itk::VariableLengthVector v_old; itk::VariableLengthVector v_new; int old_vector_length = old_ss_img->GetVectorLength(); v_old.SetSize (old_vector_length); v_new.SetSize (new_vector_length); v_new.Fill (0); /* Loop through image */ typedef itk::ImageRegionIterator< UCharVecImageType > UCharVecIteratorType; UCharVecIteratorType it_old ( old_ss_img, old_ss_img->GetLargestPossibleRegion()); UCharVecIteratorType it_new ( new_ss_img, new_ss_img->GetLargestPossibleRegion()); for (it_old.GoToBegin(), it_new.GoToBegin(); !it_old.IsAtEnd(); ++it_old, ++it_new) { /* Copy old pixel bytes into new */ v_old = it_old.Get(); for (int i = 0; i < old_vector_length; i++) { v_new[i] = v_old[i]; } it_new.Set (v_new); } /* Fixate new image */ d_ptr->m_ss_img->set_itk (new_ss_img); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/segmentation.h000066400000000000000000000077631321604176500304140ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _segmentation_h_ #define _segmentation_h_ #include "plmbase_config.h" #include "itk_image_type.h" #include "metadata.h" #include "rtss.h" #include "xform.h" #include "xio_studyset.h" /* enum Xio_version */ class Plm_image; class Plm_image_header; class Rt_study; class Segmentation_private; class Rtss_roi; class Xio_ct_transform; class Warp_parms; class PLMBASE_API Segmentation { public: SMART_POINTER_SUPPORT (Segmentation); public: Segmentation_private *d_ptr; public: Segmentation (); ~Segmentation (); void clear (); void load (const char *ss_img, const char *ss_list); void load_cxt (const std::string& input_fn, Rt_study_metadata *rsm); void load_prefix (const char *prefix_dir); void load_prefix (const std::string& prefix_dir); void load_xio (const Xio_studyset& xio_studyset); void load_gdcm_rtss (const char *input_fn, Rt_study_metadata *rsm); size_t get_num_structures (); std::string get_structure_name (size_t index); void set_structure_name (size_t index, const std::string& name); UCharImageType::Pointer get_structure_image (int index); void save_colormap (const std::string& colormap_fn); void save_cxt (const Rt_study_metadata::Pointer& rsm, const std::string& cxt_fn, bool prune_empty); void save_gdcm_rtss (const char *output_dir, const Rt_study_metadata::Pointer& rsm); void save_fcsv (const Rtss_roi *curr_structure, const std::string& fn); void save_prefix_fcsv (const std::string& output_prefix); void save_ss_image (const std::string& ss_img_fn); void save_labelmap (const std::string& labelmap_fn); void save_prefix (const std::string& output_prefix, const std::string& extension = "mha"); void save_prefix (const char *output_prefix); void save_ss_list (const std::string& ss_list_fn); void save_xio ( const Rt_study_metadata::Pointer& rsm, Xio_ct_transform *xio_transform, Xio_version xio_version, const std::string& output_dir); UInt32ImageType::Pointer get_ss_img_uint32 (void); UCharVecImageType::Pointer get_ss_img_uchar_vec (void); void apply_dicom_dir (const Rt_study_metadata::Pointer& rsm); void convert_ss_img_to_cxt (void); void convert_to_uchar_vec (void); void cxt_extract (void); void cxt_re_extract (void); void prune_empty (void); void keyholize (); void rasterize (Plm_image_header *pih, bool want_labelmap, bool xor_overlapping); void set_geometry (const Plm_image_header *pih); void find_rasterization_geometry (Plm_image_header *pih); Segmentation::Pointer warp_nondestructive ( const Xform::Pointer& xf, Plm_image_header *pih, bool use_itk = false) const; void warp (const Xform::Pointer& xf, Plm_image_header *pih, bool use_itk = false); void warp (const Xform::Pointer& xf, Plm_image_header *pih, Warp_parms *parms); void add_structure ( UCharImageType::Pointer itk_image, const char *structure_name = 0, const char *structure_color = 0); Rtss_roi* add_rtss_roi ( const char *structure_name = 0, const char *structure_color = 0); bool have_ss_img (); void set_ss_img (UCharImageType::Pointer ss_img); Plm_image::Pointer get_ss_img (); bool have_structure_set (); Rtss::Pointer& get_structure_set (); Rtss* get_structure_set_raw (); void set_structure_set (Rtss::Pointer& rtss_ss); void set_structure_set (Rtss *rtss_ss); void set_structure_image ( UCharImageType::Pointer uchar_img, unsigned int bit ); void resample (float spacing[3]); protected: void initialize_ss_image ( const Plm_image_header& pih, int vector_length); void broaden_ss_image ( int new_vector_length); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/slice_extract.cxx000066400000000000000000000060541321604176500311130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "itkExtractImageFilter.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "slice_extract.h" template typename itk::Image::Pointer slice_extract ( T in_img, int slice_no ) { typedef typename T::ObjectType InImgType; typedef typename T::ObjectType::PixelType PixelType; typedef typename itk::Image OutImgType; typedef typename itk::ExtractImageFilter FilterType; typename FilterType::Pointer extraction = FilterType::New(); #if (ITK_VERSION_MAJOR > 3) extraction->SetDirectionCollapseToGuess(); #endif typename InImgType::RegionType inputRegion = in_img->GetLargestPossibleRegion(); typename InImgType::SizeType size = inputRegion.GetSize(); size[2] = 0; typename InImgType::IndexType start = inputRegion.GetIndex(); start[2]=slice_no; typename InImgType::RegionType desiredRegion; desiredRegion.SetSize(size); desiredRegion.SetIndex(start); extraction->SetExtractionRegion(desiredRegion); extraction->SetInput(in_img); typename OutImgType::Pointer out_img = OutImgType::New(); try { extraction->Update(); out_img = extraction->GetOutput(); } catch (itk::ExceptionObject &err) { std::cout << "ExceptionObject caught a !" << std::endl; std::cout << err << std::endl; } return out_img; } UCharVecImage2DType::Pointer slice_extract ( UCharVecImageType::Pointer in_img, int slice_no ) { typedef UCharVecImageType InImgType; typedef UCharVecImage2DType OutImgType; typedef itk::ExtractImageFilter FilterType; FilterType::Pointer extraction = FilterType::New(); #if (ITK_VERSION_MAJOR > 3) extraction->SetDirectionCollapseToGuess(); #endif InImgType::RegionType inputRegion = in_img->GetLargestPossibleRegion(); InImgType::SizeType size = inputRegion.GetSize(); size[2] = 0; InImgType::IndexType start = inputRegion.GetIndex(); start[2]=slice_no; InImgType::RegionType desiredRegion; desiredRegion.SetSize(size); desiredRegion.SetIndex(start); extraction->SetExtractionRegion(desiredRegion); extraction->SetInput(in_img); OutImgType::Pointer out_img = OutImgType::New(); try { extraction->Update(); out_img = extraction->GetOutput(); } catch (itk::ExceptionObject &err) { std::cout << "ExceptionObject caught a !" << std::endl; std::cout << err << std::endl; } return out_img; } template PLMBASE_API UCharImage2DType::Pointer slice_extract (UCharImageType::Pointer, int); template PLMBASE_API FloatImage2DType::Pointer slice_extract (FloatImageType::Pointer, int); template PLMBASE_API UInt32Image2DType::Pointer slice_extract (UInt32ImageType::Pointer, int); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/slice_extract.h000066400000000000000000000011211321604176500305260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _slice_extract_h #define _slice_extract_h #include "plmbase_config.h" #include "itkImage.h" #include "itk_image_type.h" template PLMBASE_API typename itk::Image::Pointer slice_extract (T in_img, int slice_no); PLMBASE_API UCharVecImage2DType::Pointer slice_extract (UCharVecImageType::Pointer, int); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/slice_list.cxx000066400000000000000000000063251321604176500304150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include "dicom_util.h" #include "logfile.h" #include "plm_image_header.h" #include "plm_math.h" #include "print_and_exit.h" #include "slice_list.h" class Slice_data { public: Slice_data () : z(0.f), uid("") { } public: float z; std::string uid; }; class Slice_group { public: Plm_image_header group_pih; /* Slices are sorted in order, starting with origin slice */ std::list slice_data; }; class Slice_list_private { public: bool m_have_pih; bool m_have_slice_uids; Plm_image_header m_pih; // Sorted slices in "ascending z order", starting with origin slice std::vector sorted_slices; // Slice groups are also sorted in the same order std::list slice_groups; public: Slice_list_private () { this->m_have_pih = false; this->m_have_slice_uids = false; } }; Slice_list::Slice_list () { this->d_ptr = new Slice_list_private; } Slice_list::~Slice_list () { delete this->d_ptr; } const Plm_image_header* Slice_list::get_image_header (void) const { return &d_ptr->m_pih; } void Slice_list::set_image_header (const Plm_image_header& pih) { d_ptr->m_pih = pih; d_ptr->sorted_slices.resize (pih.dim(2)); d_ptr->m_have_pih = true; } void Slice_list::set_image_header (ShortImageType::Pointer img) { Plm_image_header pih (img); this->set_image_header (pih); } const char* Slice_list::get_slice_uid (int index) const { if (!d_ptr->m_have_slice_uids) { return ""; } if (index < 0 || ((size_t) index) >= d_ptr->sorted_slices.size()) { return ""; } return d_ptr->sorted_slices[index].uid.c_str(); } void Slice_list::reset_slice_uids () { d_ptr->sorted_slices.clear(); if (d_ptr->m_have_pih) { d_ptr->sorted_slices.resize (d_ptr->m_pih.dim(2)); } } void Slice_list::set_slice_uid (int index, const char* slice_uid) { if (index >= (int) d_ptr->sorted_slices.size()) { print_and_exit ( "Illegal call to Slice_list::set_slice_uid. " "Index %d > Size %d.\n", index, d_ptr->sorted_slices.size()); } d_ptr->sorted_slices[index].uid = std::string (slice_uid); } bool Slice_list::slice_list_complete () const { /* This is equivalent to the old "m_loaded" flag */ return d_ptr->m_have_pih && d_ptr->m_have_slice_uids; } void Slice_list::set_slice_list_complete () { d_ptr->m_have_slice_uids = true; } int Slice_list::num_slices () { if (!d_ptr->m_have_pih) { return 0; } return d_ptr->m_pih.dim (2); } int Slice_list::get_slice_index (float z) const { if (!this->slice_list_complete()) { return -1; } /* NOTE: This algorithm doesn't work if there are duplicate slices */ int slice_no = ROUND_INT ((z - d_ptr->m_pih.origin(2)) / d_ptr->m_pih.spacing(2)); if (slice_no < 0 || slice_no >= d_ptr->m_pih.dim(2)) { return -1; } return slice_no; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/slice_list.h000066400000000000000000000016511321604176500300370ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _slice_list_h_ #define _slice_list_h_ #include "plmbase_config.h" class Plm_image_header; class Slice_list_private; class PLMBASE_API Slice_list { public: Slice_list_private *d_ptr; public: Slice_list (); ~Slice_list (); const Plm_image_header* get_image_header () const; void set_image_header (const Plm_image_header& pih); void set_image_header (ShortImageType::Pointer img); void reset_slice_uids (); const char* get_slice_uid (int index) const; void set_slice_uid (int index, const char* slice_uid); bool slice_list_complete () const; void set_slice_list_complete (); int num_slices (); int get_slice_index (float z) const; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/ss_img_extract.cxx000066400000000000000000000127311321604176500312740ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "itkImage.h" #include "itkImageRegionIterator.h" #include "itkAndConstantToImageFilter.h" #include "itk_image.h" #include "plm_image.h" #include "print_and_exit.h" #include "ss_img_extract.h" UCharImageType::Pointer ss_img_extract_bit (UInt32ImageType::Pointer image, unsigned int bit) { typedef itk::AndConstantToImageFilter< UInt32ImageType, uint32_t, UCharImageType > AndFilterType; AndFilterType::Pointer and_filter = AndFilterType::New(); and_filter->SetInput (image); and_filter->SetConstant (1 << bit); try { and_filter->Update (); } catch (itk::ExceptionObject &err) { std::cout << "Exception during and operation." << std::endl; std::cout << err << std::endl; exit (1); } return and_filter->GetOutput (); } UCharImageType::Pointer ss_img_extract_bit ( UCharVecImageType::Pointer im_in, unsigned int bit ) { const UCharVecImageType::RegionType rgn_in_alt = im_in->GetLargestPossibleRegion(); UCharImageType::Pointer im_out = UCharImageType::New (); itk_image_header_copy (im_out, im_in); im_out->Allocate (); typedef itk::ImageRegionIterator< UCharVecImageType > UCharVecIteratorType; const UCharVecImageType::RegionType rgn_in = im_in->GetLargestPossibleRegion(); UCharVecIteratorType it_in (im_in, rgn_in); typedef itk::ImageRegionIterator< UCharImageType > UCharIteratorType; const UCharImageType::RegionType rgn_out = im_out->GetLargestPossibleRegion(); UCharIteratorType it_out (im_out, rgn_out); unsigned int uchar_no = bit / 8; unsigned int bit_no = bit % 8; unsigned char bit_mask = 1 << bit_no; if (uchar_no > im_in->GetVectorLength()) { print_and_exit ( "Error: bit %d was requested from image that has %d bits\n", bit, im_in->GetVectorLength() * 8); } for (it_in.GoToBegin(), it_out.GoToBegin(); !it_in.IsAtEnd(); ++it_in, ++it_out) { itk::VariableLengthVector v_in = it_in.Get (); unsigned char v_in_uchar = v_in[uchar_no]; it_out.Set ((v_in_uchar & bit_mask) ? 1 : 0); } return im_out; } UCharImageType::Pointer ss_img_extract_bit ( const Plm_image::Pointer& image, unsigned int bit ) { if (image->m_type == PLM_IMG_TYPE_GPUIT_UCHAR_VEC || image->m_type == PLM_IMG_TYPE_ITK_UCHAR_VEC) { image->convert (PLM_IMG_TYPE_ITK_UCHAR_VEC); return ss_img_extract_bit (image->m_itk_uchar_vec, bit); } else { image->convert (PLM_IMG_TYPE_ITK_ULONG); return ss_img_extract_bit (image->m_itk_uint32, bit); } } template typename itk::Image< typename T::ObjectType::IOPixelType, T::ObjectType::ImageDimension >::Pointer ss_img_extract_uchar ( T im_in, unsigned int uchar_no ) { typedef typename T::ObjectType InImageType; typedef typename itk::Image< typename T::ObjectType::IOPixelType, T::ObjectType::ImageDimension > OutImageType; const typename InImageType::RegionType rgn_in_alt = im_in->GetLargestPossibleRegion(); typename OutImageType::Pointer im_out = OutImageType::New (); itk_image_header_copy (im_out, im_in); im_out->Allocate (); typedef itk::ImageRegionIterator< InImageType > InImageIteratorType; const typename InImageType::RegionType rgn_in = im_in->GetLargestPossibleRegion(); InImageIteratorType it_in (im_in, rgn_in); typedef itk::ImageRegionIterator< OutImageType > OutImageIteratorType; const typename OutImageType::RegionType rgn_out = im_out->GetLargestPossibleRegion(); OutImageIteratorType it_out (im_out, rgn_out); if (uchar_no > im_in->GetVectorLength()) { print_and_exit ( "Error: uchar %d was requested from image that has %d uchars\n", uchar_no, im_in->GetVectorLength()); } for (it_in.GoToBegin(), it_out.GoToBegin(); !it_in.IsAtEnd(); ++it_in, ++it_out) { itk::VariableLengthVector v_in = it_in.Get (); unsigned char v_in_uchar = v_in[uchar_no]; it_out.Set (v_in_uchar); } return im_out; } void ss_img_insert_uchar ( UCharVecImageType::Pointer vec_img, UCharImageType::Pointer uchar_img, unsigned int uchar_no ) { typedef itk::ImageRegionIterator< UCharVecImageType > UCharVecIteratorType; const UCharVecImageType::RegionType vec_rgn = vec_img->GetLargestPossibleRegion(); UCharVecIteratorType vec_it (vec_img, vec_rgn); typedef itk::ImageRegionIterator< UCharImageType > UCharIteratorType; const UCharImageType::RegionType uchar_rgn = uchar_img->GetLargestPossibleRegion(); UCharIteratorType uchar_it (uchar_img, uchar_rgn); if (uchar_no > vec_img->GetVectorLength()) { print_and_exit ( "Error: uchar %d was requested from image that has %d uchars\n", uchar_no, vec_img->GetVectorLength()); } for (vec_it.GoToBegin(), uchar_it.GoToBegin(); !vec_it.IsAtEnd(); ++vec_it, ++uchar_it) { itk::VariableLengthVector vec = vec_it.Get (); unsigned char uch = uchar_it.Get (); vec[uchar_no] = uch; vec_it.Set (vec); } } /* Explicit instantiation */ template PLMBASE_API UCharImageType::Pointer ss_img_extract_uchar (UCharVecImageType::Pointer, unsigned int); template PLMBASE_API UCharImage2DType::Pointer ss_img_extract_uchar (UCharVecImage2DType::Pointer, unsigned int); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/ss_img_extract.h000066400000000000000000000020401321604176500307110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _ss_img_extract_h_ #define _ss_img_extract_h_ #include "plmbase_config.h" #include "itk_image_type.h" #include "plm_image.h" PLMBASE_API UCharImageType::Pointer ss_img_extract_bit ( const Plm_image::Pointer& image, unsigned int bit ); PLMBASE_API UCharImageType::Pointer ss_img_extract_bit ( UInt32ImageType::Pointer image, unsigned int bit ); PLMBASE_API UCharImageType::Pointer ss_img_extract_bit ( UCharVecImageType::Pointer image, unsigned int bit ); template PLMBASE_API typename itk::Image::Pointer ss_img_extract_uchar (T im_in, unsigned int uchar_no); PLMBASE_API void ss_img_insert_uchar ( UCharVecImageType::Pointer vec_img, UCharImageType::Pointer uchar_img, unsigned int uchar_no ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/ss_list_io.cxx000066400000000000000000000066311321604176500304320ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "file_util.h" #include "print_and_exit.h" #include "rtss.h" #include "rtss_roi.h" #include "ss_list_io.h" #define CXT_BUFLEN 2048 Rtss* ss_list_load (Rtss* cxt, const char* ss_list_fn) { FILE* fp; int struct_id; fp = fopen (ss_list_fn, "r"); if (!fp) { print_and_exit ( "Could not open ss_list file for read: %s\n", ss_list_fn); } if (!cxt) { cxt = new Rtss; } /* Part 2: Structures info */ struct_id = 0; while (1) { char color[CXT_BUFLEN]; char name[CXT_BUFLEN]; char buf[CXT_BUFLEN]; char *p; int bit; int rc; p = fgets (buf, CXT_BUFLEN, fp); if (!p) { break; } rc = sscanf (buf, "%d|%[^|]|%[^\r\n]", &bit, color, name); if (rc != 3) { print_and_exit ( "Error. ss_list file not formatted correctly: %s\n", ss_list_fn); } Rtss_roi *curr_structure = cxt->add_structure ( std::string (name), std::string (color), struct_id); curr_structure->bit = bit; struct_id ++; } fclose (fp); return cxt; } void ss_list_save (Rtss* cxt, const char* ss_list_fn) { FILE *fp; make_parent_directories (ss_list_fn); fp = fopen (ss_list_fn, "wb"); if (!fp) { print_and_exit ( "Could not open ss_list file for write: %s\n", ss_list_fn); } for (size_t i = 0; i < cxt->num_structures; i++) { Rtss_roi *curr_structure; curr_structure = cxt->slist[i]; fprintf (fp, "%d|%s|%s\n", curr_structure->bit, (curr_structure->color.empty() ? "255\\0\\0" : curr_structure->color.c_str()), curr_structure->name.c_str()); } fclose (fp); printf ("Done.\n"); } void ss_list_save_colormap (Rtss* cxt, const char* colormap_fn) { int color_no; FILE *fp; make_parent_directories (colormap_fn); fp = fopen (colormap_fn, "wb"); if (!fp) { print_and_exit ( "Could not open colormap file for write: %s\n", colormap_fn); } fprintf (fp, "0 Background 0 0 0 255\n"); /* Colormap should match labelmap. This means that filled structures are numbered before empty structures. We accomplish this by running two passes: filled structures, then empty structures. */ color_no = 0; for (size_t i = 0; i < cxt->num_structures; i++) { int r, g, b; Rtss_roi *curr_structure; curr_structure = cxt->slist[i]; if (curr_structure->bit >= 0) { curr_structure->get_rgb (&r, &g, &b); std::string adjusted_name = Rtss_roi::adjust_name ( curr_structure->name); fprintf (fp, "%d %s %d %d %d 255\n", curr_structure->bit + 1, adjusted_name.c_str(), r, g, b); color_no = curr_structure->bit + 1; } } for (size_t i = 0; i < cxt->num_structures; i++) { int r, g, b; Rtss_roi *curr_structure; curr_structure = cxt->slist[i]; if (curr_structure->bit == -1) { curr_structure->get_rgb (&r, &g, &b); std::string adjusted_name = Rtss_roi::adjust_name ( curr_structure->name); fprintf (fp, "%d %s %d %d %d 255\n", color_no + 1, adjusted_name.c_str(), r, g, b); color_no ++; } } fclose (fp); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/ss_list_io.h000066400000000000000000000011131321604176500300450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _ss_list_io_h_ #define _ss_list_io_h_ #include "plmbase_config.h" class Rtss; PLMBASE_API Rtss* ss_list_load ( Rtss* cxt, const char* ss_list_fn ); PLMBASE_API void ss_list_save ( Rtss* cxt, const char* cxt_fn ); PLMBASE_API void ss_list_save_colormap ( Rtss* cxt, const char* colormap_fn ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/threading.h000066400000000000000000000012641321604176500276520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _threading_h_ #define _threading_h_ #include "plm_config.h" /* GCS: You can't use enum types in mixed C / C++ code, because they are not required to have the same size. Therefore, revert to #defines */ typedef int Threading; #define THREADING_UNKNOWN 0 #define THREADING_CPU_SINGLE 1 #define THREADING_CPU_OPENMP 2 #define THREADING_BROOK 3 #define THREADING_CUDA 4 #define THREADING_OPENCL 5 #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/thumbnail.cxx000066400000000000000000000047531321604176500302510ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "itk_resample.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_int.h" #include "print_and_exit.h" #include "thumbnail.h" #include "volume.h" Thumbnail::Thumbnail () { axis = 2; thumbnail_dim = 16; thumbnail_spacing = 30.0; center[0] = center[1] = center[2] = 0; slice_loc = 0; } void Thumbnail::set_internal_geometry () { for (int d = 0; d < 3; d++) { origin[d] = center[d] - thumbnail_spacing * (thumbnail_dim - 1) / 2; spacing[d] = thumbnail_spacing; dim[d] = thumbnail_dim; } origin[axis] = slice_loc; spacing[axis] = 1; dim[axis] = 1; } void Thumbnail::set_input_image (const Plm_image::Pointer& pli) { this->pli = pli; } void Thumbnail::set_slice_loc (float slice_loc) { this->slice_loc = slice_loc; } void Thumbnail::set_axis (int axis) { if (axis < 0 || axis > 2) { print_and_exit ("Error, thumbnail axis must be between 0 and 2\n"); } this->axis = axis; } void Thumbnail::set_thumbnail_dim (int thumb_dim) { this->thumbnail_dim = thumb_dim; } void Thumbnail::set_thumbnail_spacing (float thumb_spacing) { this->thumbnail_spacing = thumb_spacing; } FloatImageType::Pointer Thumbnail::make_thumbnail () { /* Figure out resampling geometry */ set_internal_geometry (); /* Resample the image */ Plm_image_header pih (dim, origin, spacing); FloatImageType::Pointer itk_resampled_image = resample_image (pli->m_itk_float, &pih, -1000, 1); Plm_image plm_resampled_image (itk_resampled_image); /* Reshuffle dimensions to 2D */ if (axis == 0) { Volume::Pointer vol = plm_resampled_image.get_volume_float (); vol->dim[0] = vol->dim[1]; vol->dim[1] = vol->dim[2]; vol->dim[2] = 1; /* GCS FIX: Do something about spacing here */ /* GCS FIX: Do something about direction cosines here */ } else if (axis == 1) { Volume::Pointer vol = plm_resampled_image.get_volume_float (); vol->dim[1] = vol->dim[2]; vol->dim[2] = 1; /* GCS FIX: Do something about spacing here */ /* GCS FIX: Do something about direction cosines here */ } else { /* Do nothing */ } return plm_resampled_image.itk_float (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/thumbnail.h000066400000000000000000000017261321604176500276730ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _thumbnail_h_ #define _thumbnail_h_ #include "plmbase_config.h" #include "itk_image_type.h" #include "plm_image.h" class PLMBASE_API Thumbnail { public: Plm_image::Pointer pli; float origin[3]; float center[3]; float spacing[3]; plm_long dim[3]; int axis; int thumbnail_dim; float thumbnail_spacing; float slice_loc; bool slice_loc_was_set; public: Thumbnail (); void set_input_image (const Plm_image::Pointer& pli); void set_axis (int axis); void set_slice_loc (float slice_loc); void set_thumbnail_dim (int thumb_dim); void set_thumbnail_spacing (float thumb_spacing); FloatImageType::Pointer make_thumbnail (); private: void set_internal_geometry (void); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/vf.cxx000066400000000000000000000073701321604176500266770ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "interpolate.h" #include "interpolate_macros.h" #include "plm_math.h" #include "plmbase_config.h" #include "volume_macros.h" #include "vf.h" #include "volume.h" Volume* vf_warp (Volume *vout, Volume *vin, Volume *vf) { int d; plm_long ijk[3]; float fxyz[3]; float* vf_img = (float*) vf->img; float* vout_img; float* m_img = (float*) vin->img; const float* vin_proj = vin->get_proj(); const float* vf_proj = vf->get_proj(); const float* vin_step = vin->get_step(); const float* vf_step = vf->get_step(); printf ("Direction cosines: " "vin = %f %f %f ...\n" "vf = %f %f %f ...\n", vin->direction_cosines[0], vin->direction_cosines[1], vin->direction_cosines[2], vf->direction_cosines[0], vf->direction_cosines[1], vf->direction_cosines[2] ); printf ("spac: " "vin = %f %f %f ...\n" "vf = %f %f %f ...\n", vin->spacing[0], vin->spacing[1], vin->spacing[2], vf->spacing[0], vf->spacing[1], vf->spacing[2] ); printf ("proj: " "vin = %f %f %f ...\n" "vf = %f %f %f ...\n", vin_proj[3*0+0], vin_proj[3*0+1], vin_proj[3*0+2], vf_proj[3*0+0], vf_proj[3*0+1], vf_proj[3*0+2] ); printf ("step: " "vin = %f %f %f ...\n" "vf = %f %f %f ...\n", vin_step[3*0+0], vin_step[3*0+1], vin_step[3*0+2], vf_step[3*0+0], vf_step[3*0+1], vf_step[3*0+2] ); if (!vout) { vout = volume_clone_empty (vin); } vout_img = (float*) vout->img; /* Assumes size, spacing of vout same as size, spacing of vf */ for (d = 0; d < 3; d++) { if (vout->dim[d] != vf->dim[d]) { printf("Dimension mismatch between fixed and moving\n"); return 0; } if (vout->spacing[d] != vf->spacing[d]) { printf("Resolutions mismatch between fixed and moving\n"); return 0; } if (vout->origin[d] != vf->origin[d]) { printf("Origin mismatch between fixed and moving\n"); return 0; } } LOOP_Z (ijk, fxyz, vf) { LOOP_Y (ijk, fxyz, vf) { LOOP_X (ijk, fxyz, vf) { /* Compute linear index of voxel */ plm_long fv = volume_index (vf->dim, ijk); float *dxyz = &vf_img[3*fv]; float mo_xyz[3] = { fxyz[0] + dxyz[0] - vin->origin[0], fxyz[1] + dxyz[1] - vin->origin[1], fxyz[2] + dxyz[2] - vin->origin[2] }; float m_val; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float mijk[3]; plm_long mijk_r[3], mijk_f[3]; plm_long mvf; mijk[2] = PROJECT_Z(mo_xyz,vin->proj); mijk[1] = PROJECT_Y(mo_xyz,vin->proj); mijk[0] = PROJECT_X(mo_xyz,vin->proj); if (!vin->is_inside (mijk)) continue; #if defined (commentout) /* Nearest neighbor */ mijk_r[2] = ROUND_INT(mijk[2]); mijk_r[1] = ROUND_INT(mijk[1]); mijk_r[0] = ROUND_INT(mijk[0]); mv = (mk * vin->dim[1] + mj) * vin->dim[0] + mi; if (mk < 0 || mk >= vin->dim[2]) continue; if (mj < 0 || mj >= vin->dim[1]) continue; if (mi < 0 || mi >= vin->dim[0]) continue; vout_img[fv] = vin_img[mv]; #endif /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, vin); /* Find linear index of "corner voxel" in moving image */ mvf = volume_index (vin->dim, mijk_f); /* Compute moving image intensity using linear interpolation */ LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], mvf, m_img, vin); /* Assign the value */ vout_img[fv] = m_val; } } } return vout; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/vf.h000066400000000000000000000006231321604176500263160ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _vf_h_ #define _vf_h_ #include "plmbase_config.h" class Volume; class Volume_limit; PLMBASE_C_API Volume* vf_warp (Volume* vout, Volume* vin, Volume* vf); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/vf_convolve.cxx000066400000000000000000000076001321604176500306060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "plm_int.h" #include "plm_math.h" #include "vf_convolve.h" #include "volume.h" void vf_convolve_x (Volume* vf_out, Volume* vf_in, float* ker, int width) { plm_long v, x, y, z; int half_width; float *in_img = (float*) vf_in->img; float *out_img = (float*) vf_out->img; half_width = width / 2; for (v = 0, z = 0; z < vf_in->dim[2]; z++) { for (y = 0; y < vf_in->dim[1]; y++) { for (x = 0; x < vf_in->dim[0]; x++, v++) { plm_long i, i1; /* i is the offset in the vf */ plm_long j, j1, j2; /* j is the index of the kernel */ int d; /* d is the vector field direction */ float *vout = &out_img[3*v]; if (x < half_width) { i1 = 0; j1 = half_width - x; } else { i1 = x - half_width; j1 = 0; } if (x + half_width > vf_in->dim[0] - 1) { j2 = half_width + (vf_in->dim[0] - x) - 1; } else { j2 = 2 * half_width; } for (d = 0; d < 3; d++) { float ktot = 0.0f; vout[d] = (float) 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { plm_long idx = vf_in->index (i, y, z); vout[d] += ker[j] * in_img [idx*3+d]; ktot += ker[j]; } vout[d] /= ktot; } #if defined (commentout) printf ("%u %u %u | %u | %u %u %u\n", z, y, x, v, i1, j1, j2); #endif } } } } void vf_convolve_y (Volume* vf_out, Volume* vf_in, float* ker, int width) { plm_long v, x, y, z; int half_width; float *in_img = (float*) vf_in->img; float *out_img = (float*) vf_out->img; half_width = width / 2; for (v = 0, z = 0; z < vf_in->dim[2]; z++) { for (y = 0; y < vf_in->dim[1]; y++) { for (x = 0; x < vf_in->dim[0]; x++, v++) { plm_long i, i1; /* i is the offset in the vf */ plm_long j, j1, j2; /* j is the index of the kernel */ int d; /* d is the vector field direction */ float *vout = &out_img[3*v]; if (y < half_width) { i1 = 0; j1 = half_width - y; } else { i1 = y - half_width; j1 = 0; } if (y + half_width > vf_in->dim[1] - 1) { j2 = half_width + (vf_in->dim[1] - y) - 1; } else { j2 = 2 * half_width; } for (d = 0; d < 3; d++) { float ktot = 0.0f; vout[d] = (float) 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { plm_long idx = vf_in->index (x, i, z); vout[d] += ker[j] * in_img [idx*3+d]; ktot += ker[j]; } vout[d] /= ktot; } } } } } void vf_convolve_z (Volume* vf_out, Volume* vf_in, float* ker, int width) { plm_long v, x, y, z; int half_width; float *in_img = (float*) vf_in->img; float *out_img = (float*) vf_out->img; half_width = width / 2; for (v = 0, z = 0; z < vf_in->dim[2]; z++) { for (y = 0; y < vf_in->dim[1]; y++) { for (x = 0; x < vf_in->dim[0]; x++, v++) { plm_long i, i1; /* i is the offset in the vf */ plm_long j, j1, j2; /* j is the index of the kernel */ int d; /* d is the vector field direction */ float *vout = &out_img[3*v]; if (z < half_width) { i1 = 0; j1 = half_width - z; } else { i1 = z - half_width; j1 = 0; } if (z + half_width > vf_in->dim[2] - 1) { j2 = half_width + (vf_in->dim[2] - z) - 1; } else { j2 = 2 * half_width; } for (d = 0; d < 3; d++) { float ktot = 0.0f; vout[d] = (float) 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { plm_long idx = vf_in->index (x, y, i); vout[d] += ker[j] * in_img [idx*3+d]; ktot += ker[j]; } vout[d] /= ktot; } } } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/vf_convolve.h000066400000000000000000000011241321604176500302260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _vf_convolve_h_ #define _vf_convolve_h_ #include "plmbase_config.h" class Volume; PLMBASE_C_API void vf_convolve_x (Volume* vf_out, Volume* vf_in, float* ker, int width); PLMBASE_C_API void vf_convolve_y (Volume* vf_out, Volume* vf_in, float* ker, int width); PLMBASE_C_API void vf_convolve_z (Volume* vf_out, Volume* vf_in, float* ker, int width); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/vf_jacobian.cxx000066400000000000000000000053551321604176500305260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include #include #include #include #include #include "vf_jacobian.h" typedef itk::DisplacementFieldJacobianDeterminantFilter JacobianFilterType; Jacobian::Jacobian () { vf = 0; vfjacstats_fn = " "; jacobian_min = 0; jacobian_max = 0; } void Jacobian::set_output_vfstats_name (const std::string& vfjacstats) { this->vfjacstats_fn = vfjacstats; } void Jacobian::set_input_vf(DeformationFieldType::Pointer vf) { this->vf = vf; } void Jacobian::write_output_statistics(Jacobian_stats *JacoStats) { FILE *fid; fid=fopen(JacoStats->outputstats_fn.c_str(),"w"); if (fid != NULL) { fprintf(fid,"Min Jacobian: %.6f\n",JacoStats->min); fprintf(fid,"Max Jacobian: %.6f\n",JacoStats->max); fclose(fid); } } FloatImageType::Pointer Jacobian::make_jacobian () { DeformationFieldType::Pointer deffield; deffield= this->vf; JacobianFilterType::Pointer jacobianFilter = JacobianFilterType::New(); jacobianFilter->SetInput( deffield ); jacobianFilter->SetUseImageSpacing( true ); jacobianFilter->Update(); typedef itk::MinimumMaximumImageCalculator MinMaxFilterType; MinMaxFilterType::Pointer minmaxfilter = MinMaxFilterType::New(); FloatImageType::Pointer outimg =jacobianFilter->GetOutput(); try { minmaxfilter->SetImage(jacobianFilter->GetOutput()); } catch( itk::ExceptionObject& err ) { std::cout << "Unexpected error." << std::endl; std::cout << err << std::endl; exit( EXIT_FAILURE ); } minmaxfilter->Compute(); std::cout<<"Minimum of the determinant of the Jacobian of the warp: " <GetMinimum()<GetMaximum()<jacobian_min = minmaxfilter->GetMinimum(); this->jacobian_max = minmaxfilter->GetMaximum(); Jacobian_stats JacoStats; JacoStats.min = minmaxfilter->GetMinimum(); JacoStats.max = minmaxfilter->GetMaximum(); JacoStats.outputstats_fn = this->vfjacstats_fn; if (this->vfjacstats_fn != "") { this->write_output_statistics(&JacoStats); } return outimg; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/vf_jacobian.h000066400000000000000000000017441321604176500301510ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _vf_jacobian_h_ #define _vf_jacobian_h_ #include "plmbase_config.h" #include #include "itk_image_type.h" class Plm_image; class PLMBASE_API Jacobian_stats { public: float min; float max; std::string outputstats_fn; public: Jacobian_stats () { outputstats_fn = " "; min=0; max=0; } }; class PLMBASE_API Jacobian { public: /*Xform * */ DeformationFieldType::Pointer vf; std::string vfjacstats_fn; float jacobian_min; float jacobian_max; public: Jacobian(); void set_input_vf (DeformationFieldType::Pointer vf); void set_output_vfstats_name (const std::string& vfjacstats); FloatImageType::Pointer make_jacobian (); private: void write_output_statistics(Jacobian_stats *); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/vf_stats.cxx000066400000000000000000000406331321604176500301140ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- Analyze a vector field for invertibility, smoothness. ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "logfile.h" #include "vf_stats.h" #include "volume.h" void vf_analyze (const Volume* vol, const Volume *mask) { plm_long i, j, k, v; int mask_npixels = 0; float* img = (float*) vol->img; unsigned char* mask_img = 0; if (mask) { mask_img = (unsigned char*) mask->img; } float mean_av[3]; float mean_v[3]; float mins[3]; float maxs[3]; float mask_mean_av[3]; float mask_mean_v[3]; float mask_mins[3]; float mask_maxs[3]; float length_acc; float length_mask_acc; for (int d = 0; d < 3; d++) { mean_av[d] = 0.f; mean_v[d] = 0.f; mins[d] = FLT_MAX; maxs[d] = -FLT_MIN; mask_mean_av[d] = 0.f; mask_mean_v[d] = 0.f; mask_mins[d] = FLT_MAX; mask_maxs[d] = -FLT_MIN; } length_acc = 0.f; length_mask_acc = 0.f; for (v = 0, k = 0; k < vol->dim[2]; k++) { for (j = 0; j < vol->dim[1]; j++) { for (i = 0; i < vol->dim[0]; i++, v++) { float* dxyz = &img[3*v]; float len = 0.f; for (int d = 0; d < 3; d++) { mean_v[d] += dxyz[d]; mean_av[d] += fabs(dxyz[d]); if (dxyz[d] > maxs[d]) { maxs[d] = dxyz[d]; } else if (dxyz[d] < mins[d]) { mins[d] = dxyz[d]; } len += dxyz[d] * dxyz[d]; } len = sqrt(len); length_acc += len; if (mask && mask_img[v]) { mask_npixels ++; for (int d = 0; d < 3; d++) { mask_mean_v[d] += dxyz[d]; mask_mean_av[d] += fabs(dxyz[d]); if (dxyz[d] > mask_maxs[d]) { mask_maxs[d] = dxyz[d]; } else if (dxyz[d] < mask_mins[d]) { mask_mins[d] = dxyz[d]; } } length_mask_acc += len; } } } } if (mask) { lprintf ("Mask enabled. %d / %d voxels inside mask\n", (int) mask_npixels, (int) vol->npix); } for (int d = 0; d < 3; d++) { mean_v[d] /= vol->npix; mean_av[d] /= vol->npix; } lprintf ("Min: %10.3f %10.3f %10.3f\n", mins[0], mins[1], mins[2]); lprintf ("Mean: %10.3f %10.3f %10.3f\n", mean_v[0], mean_v[1], mean_v[2]); lprintf ("Max: %10.3f %10.3f %10.3f\n", maxs[0], maxs[1], maxs[2]); lprintf ("Mean abs: %10.3f %10.3f %10.3f\n", mean_av[0], mean_av[1], mean_av[2]); lprintf ("Ave len: %10.3f\n", length_acc / vol->npix); if (mask) { for (int d = 0; d < 3; d++) { mask_mean_v[d] /= mask_npixels; mask_mean_av[d] /= mask_npixels; } lprintf ("Min (mask): %10.3f %10.3f %10.3f\n", mask_mins[0], mask_mins[1], mask_mins[2]); lprintf ("Mean (mask): %10.3f %10.3f %10.3f\n", mask_mean_v[0], mask_mean_v[1], mask_mean_v[2]); lprintf ("Max (mask): %10.3f %10.3f %10.3f\n", mask_maxs[0], mask_maxs[1], mask_maxs[2]); lprintf ("Mean abs (mask): %10.3f %10.3f %10.3f\n", mask_mean_av[0], mask_mean_av[1], mask_mean_av[2]); lprintf ("Ave len (mask): %10.3f\n", length_mask_acc / mask_npixels); } } /* This is similar to vf_analyze, but works on planar images too */ void vf_print_stats (Volume* vol) { plm_long i, v; int d; float mins[3], maxs[3], mean[3]; mean[0] = mean[1] = mean[2] = (float) 0.0; if (vol->pix_type == PT_VF_FLOAT_INTERLEAVED) { float *img = (float*) vol->img; mins[0] = maxs[0] = img[0]; mins[1] = maxs[1] = img[1]; mins[2] = maxs[2] = img[2]; for (v = 0, i = 0; i < vol->npix; i++) { for (d = 0; d < 3; d++, v++) { if (img[v] > maxs[d]) { maxs[d] = img[v]; } else if (img[v] < mins[d]) { mins[d] = img[v]; } mean[d] += img[v]; } } } else if (vol->pix_type == PT_VF_FLOAT_PLANAR) { float **img = (float**) vol->img; mins[0] = maxs[0] = img[0][0]; mins[1] = maxs[1] = img[1][0]; mins[2] = maxs[2] = img[2][0]; for (i = 0; i < vol->npix; i++) { for (d = 0; d < 3; d++) { if (img[d][i] > maxs[d]) { maxs[d] = img[d][i]; } else if (img[d][i] < mins[d]) { mins[d] = img[d][i]; } mean[d] += img[d][i]; } } } else { printf ("Sorry, vf_print_stats only for vector field volumes\n"); return; } for (d = 0; d < 3; d++) { mean[d] /= vol->npix; } printf ("min, mean, max\n"); for (d = 0; d < 3; d++) { printf ("%g %g %g\n", mins[d], mean[d], maxs[d]); } } void vf_analyze_jacobian (const Volume *vol, const Volume *mask) { plm_long i, j, k; float min_jacobian = FLT_MAX; float max_jacobian = - FLT_MAX; float mask_min_jacobian = FLT_MAX; float mask_max_jacobian = - FLT_MAX; float di = vol->spacing[0]; float dj = vol->spacing[1]; float dk = vol->spacing[2]; float* img = (float*) vol->img; unsigned char* mask_img = 0; if (mask) { mask_img = (unsigned char*) mask->img; } for (k = 1; k < vol->dim[2]-1; k++) { for (j = 1; j < vol->dim[1]-1; j++) { for (i = 1; i < vol->dim[0]-1; i++) { int v = volume_index (vol->dim, i, j, k); int vin = volume_index (vol->dim, i-1, j, k); int vip = volume_index (vol->dim, i+1, j, k); int vjn = volume_index (vol->dim, i, j-1, k); int vjp = volume_index (vol->dim, i, j+1, k); int vkn = volume_index (vol->dim, i, j, k-1); int vkp = volume_index (vol->dim, i, j, k+1); float* din = &img[3*vin]; float* dip = &img[3*vip]; float* djn = &img[3*vjn]; float* djp = &img[3*vjp]; float* dkn = &img[3*vkn]; float* dkp = &img[3*vkp]; // for a zero or constant field u, jacobian must be 1. float dui_di = 1 + (0.5 / di) * (dip[0] - din[0]); float duj_di = (0.5 / di) * (dip[1] - din[1]); float duk_di = (0.5 / di) * (dip[2] - din[2]); float dui_dj = (0.5 / dj) * (djp[0] - djn[0]); float duj_dj = 1 + (0.5 / dj) * (djp[1] - djn[1]); float duk_dj = (0.5 / dj) * (djp[2] - djn[2]); float dui_dk = (0.5 / dk) * (dkp[0] - dkn[0]); float duj_dk = (0.5 / dk) * (dkp[1] - dkn[1]); float duk_dk = 1 + (0.5 / dk) * (dkp[2] - dkn[2]); float jacobian = +dui_di * ( duj_dj * duk_dk - duj_dk * duk_dj ) -dui_dj * ( duj_di * duk_dk - duj_dk * duk_di ) +dui_dk * ( duj_di * duk_dj - duj_dj * duk_di ) ; if (jacobian > max_jacobian) { max_jacobian = jacobian; } if (jacobian < min_jacobian) { min_jacobian = jacobian; } if (mask && mask_img[v]) { if (jacobian > mask_max_jacobian) { mask_max_jacobian = jacobian; } if (jacobian < mask_min_jacobian) { mask_min_jacobian = jacobian; } } } } } lprintf ("Jacobian: MINJAC %g MAXJAC %g\n", min_jacobian, max_jacobian); if (mask) { lprintf ("Jacobian (mask): MINMJAC %g MAXMJAC %g\n", mask_min_jacobian, mask_max_jacobian); } } void vf_analyze_second_deriv (Volume* vol) { plm_long i, j, k; float* img = (float*) vol->img; float min_sec_der = 0.f, max_sec_der = 0.f, total_sec_der = 0.f; int max_sec_der_loc[3] = {0, 0, 0}; float di = vol->spacing[0]; float dj = vol->spacing[1]; float dk = vol->spacing[2]; int first = 1; for (k = 1; k < vol->dim[2]-1; k++) { for (j = 1; j < vol->dim[1]-1; j++) { for (i = 1; i < vol->dim[0]-1; i++) { int v_o = volume_index (vol->dim, i, j, k); int vin = volume_index (vol->dim, i-1, j, k); int vip = volume_index (vol->dim, i+1, j, k); int vjn = volume_index (vol->dim, i, j-1, k); int vjp = volume_index (vol->dim, i, j+1, k); int vkn = volume_index (vol->dim, i, j, k-1); int vkp = volume_index (vol->dim, i, j, k+1); int vijp = volume_index (vol->dim, i+1, j+1, k); int vijn = volume_index (vol->dim, i-1, j-1, k); int vikp = volume_index (vol->dim, i+1, j, k+1); int vikn = volume_index (vol->dim, i-1, j, k-1); int vjkp = volume_index (vol->dim, i, j+1, k+1); int vjkn = volume_index (vol->dim, i, j-1, k-1); float* d_o = &img[3*v_o]; float* din = &img[3*vin]; float* dip = &img[3*vip]; float* djn = &img[3*vjn]; float* djp = &img[3*vjp]; float* dkn = &img[3*vkn]; float* dkp = &img[3*vkp]; float *dijp = &img[3*vijp]; float *dijn = &img[3*vijn]; float *dikp = &img[3*vikp]; float *dikn = &img[3*vikn]; float *djkp = &img[3*vjkp]; float *djkn = &img[3*vjkn]; float d2ui_didi = (1./ di) * ( dip[0] - 2 * d_o[0] + din[0] ); float d2ui_djdj = (1./ dj) * ( djp[0] - 2 * d_o[0] + djn[0] ); float d2ui_dkdk = (1./ dk) * ( dkp[0] - 2 * d_o[0] + dkn[0] ); float d2ui_didj = (0.5 / (di*dj))* ( ( dijp[0] + dijn[0] + 2. * d_o[0] ) - ( dip[0] + din[0] + djp[0] + djn[0]) ); float d2ui_didk = (0.5 / (di*dk))* ( ( dikp[0] + dikn[0] + 2. * d_o[0] ) - ( dip[0] + din[0] + dkp[0] + dkn[0]) ); float d2ui_djdk = (0.5 / (dj*dk))* ( ( djkp[0] + djkn[0] + 2. * d_o[0] ) - ( djp[0] + djn[0] + dkp[0] + dkn[0]) ); float d2uj_didi = (1./ di) * ( dip[1] - 2 * d_o[1] + din[1] ); float d2uj_djdj = (1./ dj) * ( djp[1] - 2 * d_o[1] + djn[1] ); float d2uj_dkdk = (1./ dk) * ( dkp[1] - 2 * d_o[1] + dkn[1] ); float d2uj_didj = (0.5 / (di*dj))* ( ( dijp[1] + dijn[1] + 2. * d_o[1] ) - ( dip[1] + din[1] + djp[1] + djn[1]) ); float d2uj_didk = (0.5 / (di*dk))* ( ( dikp[1] + dikn[1] + 2. * d_o[1] ) - ( dip[1] + din[1] + dkp[1] + dkn[1]) ); float d2uj_djdk = (0.5 / (dj*dk))* ( ( djkp[1] + djkn[1] + 2. * d_o[1] ) - ( djp[1] + djn[1] + dkp[1] + dkn[1]) ); float d2uk_didi = (1./ di) * ( dip[2] - 2 * d_o[2] + din[2] ); float d2uk_djdj = (1./ dj) * ( djp[2] - 2 * d_o[2] + djn[2] ); float d2uk_dkdk = (1./ dk) * ( dkp[2] - 2 * d_o[2] + dkn[2] ); float d2uk_didj = (0.5 / (di*dj))* ( ( dijp[2] + dijn[2] + 2. * d_o[2] ) - ( dip[2] + din[2] + djp[2] + djn[2]) ); float d2uk_didk = (0.5 / (di*dk))* ( ( dikp[2] + dikn[2] + 2. * d_o[2] ) - ( dip[2] + din[2] + dkp[2] + dkn[2]) ); float d2uk_djdk = (0.5 / (dj*dk))* ( ( djkp[2] + djkn[2] + 2. * d_o[2] ) - ( djp[2] + djn[2] + dkp[2] + dkn[2]) ); float second_deriv_sq = d2ui_didi*d2ui_didi + d2ui_djdj*d2ui_djdj + d2ui_dkdk*d2ui_dkdk + 2*(d2ui_didj*d2ui_didj + d2ui_didk*d2ui_didk + d2ui_djdk*d2ui_djdk) + d2uj_didi*d2uj_didi + d2uj_djdj*d2uj_djdj + d2uj_dkdk*d2uj_dkdk + 2*(d2uj_didj*d2uj_didj + d2uj_didk*d2uj_didk + d2uj_djdk*d2uj_djdk) + d2uk_didi*d2uk_didi + d2uk_djdj*d2uk_djdj + d2uk_dkdk*d2uk_dkdk + 2*(d2uk_didj*d2uk_didj + d2uk_didk*d2uk_didk + d2uk_djdk*d2uk_djdk) ; total_sec_der += second_deriv_sq; if (first) { max_sec_der = second_deriv_sq; min_sec_der = second_deriv_sq; max_sec_der_loc[0] = i; max_sec_der_loc[1] = j; max_sec_der_loc[2] = k; first = 0; } else { if (second_deriv_sq > max_sec_der) { max_sec_der = second_deriv_sq; max_sec_der_loc[0] = i; max_sec_der_loc[1] = j; max_sec_der_loc[2] = k; }; if (second_deriv_sq < min_sec_der) min_sec_der = second_deriv_sq; } } } } lprintf ( "Second derivatives: MINSECDER %10.3g MAXSECDER %10.3g\n" " AVESECDER %10.3g INTSECDER %10.3g\n", min_sec_der, max_sec_der, total_sec_der / vol->npix, total_sec_der * (vol->spacing[0]*vol->spacing[1]*vol->spacing[2])); lprintf ("Max second derivative at: (%d %d %d)\n", max_sec_der_loc[0], max_sec_der_loc[1], max_sec_der_loc[2]); } void vf_analyze_strain (const Volume* vol, const Volume* mask) { plm_long i, j, k; float* img = (float*) vol->img; unsigned char* mask_img = 0; if (mask) { mask_img = (unsigned char*) mask->img; } float min_dilation = FLT_MAX; float max_dilation = - FLT_MAX; float total_energy = 0.f; float max_energy = - FLT_MAX; float mask_min_dilation = FLT_MAX; float mask_max_dilation = - FLT_MAX; float mask_total_energy = 0.f; float mask_max_energy = - FLT_MAX; const float LAME_MU = 1.0f; const float LAME_NU = 1.0f; float di = vol->spacing[0]; float dj = vol->spacing[1]; float dk = vol->spacing[2]; for (k = 1; k < vol->dim[2]-1; k++) { for (j = 1; j < vol->dim[1]-1; j++) { for (i = 1; i < vol->dim[0]-1; i++) { int v = volume_index (vol->dim, i, j, k); int vin = volume_index (vol->dim, i-1, j, k); int vip = volume_index (vol->dim, i+1, j, k); int vjn = volume_index (vol->dim, i, j-1, k); int vjp = volume_index (vol->dim, i, j+1, k); int vkn = volume_index (vol->dim, i, j, k-1); int vkp = volume_index (vol->dim, i, j, k+1); float* din = &img[3*vin]; float* dip = &img[3*vip]; float* djn = &img[3*vjn]; float* djp = &img[3*vjp]; float* dkn = &img[3*vkn]; float* dkp = &img[3*vkp]; float dui_di = (0.5 / di) * (dip[0] - din[0]); float duj_di = (0.5 / di) * (dip[1] - din[1]); float duk_di = (0.5 / di) * (dip[2] - din[2]); float dui_dj = (0.5 / dj) * (djp[0] - djn[0]); float duj_dj = (0.5 / dj) * (djp[1] - djn[1]); float duk_dj = (0.5 / dj) * (djp[2] - djn[2]); float dui_dk = (0.5 / dk) * (dkp[0] - dkn[0]); float duj_dk = (0.5 / dk) * (dkp[1] - dkn[1]); float duk_dk = (0.5 / dk) * (dkp[2] - dkn[2]); float e_ii = dui_di; float e_jj = duj_dj; float e_kk = duk_dk; float e_ij = 0.5 * (dui_dj + duj_di); float e_jk = 0.5 * (duj_dk + duk_dj); float e_ki = 0.5 * (duk_di + dui_dk); float dilation = e_ii + e_jj + e_kk; float shear = dilation + 2.0f * (e_ij * e_ij + e_jk * e_jk + e_ki * e_ki); float energy = 0.5 * LAME_NU * dilation * dilation + LAME_MU * shear; total_energy += energy; if (energy > max_energy) { max_energy = energy; } if (dilation < min_dilation) { min_dilation = dilation; } if (dilation > max_dilation) { max_dilation = dilation; } if (!mask) { continue; } unsigned int maskval_in = (unsigned int) mask_img[vin]; unsigned int maskval_ip = (unsigned int) mask_img[vip]; unsigned int maskval_jn = (unsigned int) mask_img[vjn]; unsigned int maskval_jp = (unsigned int) mask_img[vjp]; unsigned int maskval_kn = (unsigned int) mask_img[vkn]; unsigned int maskval_kp = (unsigned int) mask_img[vkp]; if (mask_img[v] && (maskval_in > 0 && maskval_ip > 0) && (maskval_jn > 0 && maskval_jp > 0) && (maskval_kn > 0 && maskval_kp > 0)) { mask_total_energy += energy; if (energy > mask_max_energy) { mask_max_energy = energy; } if (dilation < mask_min_dilation) { mask_min_dilation = dilation; } if (dilation > mask_max_dilation) { mask_max_dilation = dilation; } } } } } lprintf ( "Energy: MINDIL %10.3g MAXDIL %g\n" " MAXSTRAIN %10.3g TOTSTRAIN %g\n", min_dilation, max_dilation, max_energy, total_energy); if (mask) { lprintf ( "Energy (mask): MINDIL %10.3g MAXDIL %g\n" " MAXSTRAIN %10.3g TOTSTRAIN %g\n", mask_min_dilation, mask_max_dilation, mask_max_energy, mask_total_energy); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/vf_stats.h000066400000000000000000000012251321604176500275330ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _vf_stats_h_ #define _vf_stats_h_ #include "plmbase_config.h" class Volume; PLMBASE_C_API void vf_analyze (const Volume* vol, const Volume *mask); PLMBASE_C_API void vf_analyze_jacobian (const Volume* vol, const Volume* mask); PLMBASE_C_API void vf_analyze_second_deriv (Volume* vol); PLMBASE_C_API void vf_analyze_strain (const Volume* vol, const Volume* mask); PLMBASE_C_API void vf_print_stats (Volume* vol); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume.cxx000077500000000000000000000543731321604176500276030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "direction_matrices.h" #include "interpolate.h" #include "interpolate_macros.h" #include "logfile.h" #include "plm_int.h" #include "plm_math.h" #include "print_and_exit.h" #include "volume_header.h" #include "volume.h" template static void convert_raw (T* new_img, const Volume* vol) { U* old_img = (U*) vol->img; if (!new_img) { print_and_exit ("Memory allocation failed.\n"); } for (plm_long v = 0; v < vol->npix; v++) { new_img[v] = (T) old_img[v]; } } template static T* convert_raw (const Volume* vol) { T* new_img = (T*) malloc (sizeof(T) * vol->npix); convert_raw (new_img, vol); return new_img; } #define CONVERT_INPLACE(new_type,old_type,new_type_enum) \ { \ new_type *new_img = convert_raw (ref); \ ref->pix_size = sizeof(new_type); \ ref->pix_type = new_type_enum; \ free (ref->img); \ ref->img = (void*) new_img; \ } Volume::Volume () { init (); } Volume::Volume ( const plm_long dim[3], const float origin[3], const float spacing[3], const float direction_cosines[9], enum Volume_pixel_type vox_type, int vox_planes ) { create (dim, origin, spacing, direction_cosines, vox_type, vox_planes); } Volume::Volume ( const plm_long dim[3], const float origin[3], const float spacing[3], const Direction_cosines& direction_cosines, enum Volume_pixel_type vox_type, int vox_planes ) { create (dim, origin, spacing, direction_cosines.get_matrix(), vox_type, vox_planes); } Volume::Volume ( const Volume_header& vh, enum Volume_pixel_type vox_type, int vox_planes ) { create (vh, vox_type, vox_planes); } Volume::~Volume () { if (this->pix_type == PT_VF_FLOAT_PLANAR) { float** planes = (float**) this->img; free (planes[0]); free (planes[1]); free (planes[2]); } free (this->img); } void Volume::init () { for (int d = 0; d < 3; d++) { dim[d] = 0; origin[d] = 0; spacing[d] = 0; } for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { proj[3*i+j] = 0; step[3*i+j] = 0; } } npix = 0; pix_type = PT_UNDEFINED; vox_planes = 0; pix_size = 0; img = 0; } void Volume::allocate (void) { if (this->pix_type == PT_VF_FLOAT_PLANAR) { float** der = (float**) malloc (3*sizeof(float*)); if (!der) { fprintf (stderr, "Memory allocation failed.\n"); exit(1); } int alloc_size = this->npix; for (int i=0; i < 3; i++) { der[i] = (float*) malloc (alloc_size*sizeof(float)); if (!der[i]) { fprintf (stderr, "Memory allocation failed.\n"); exit(1); } memset (der[i], 0, alloc_size*sizeof(float)); } this->img = (void*) der; } else { this->img = (void*) malloc (this->pix_size * this->npix); if (!this->img) { fprintf (stderr, "Memory allocation failed (alloc size = %u).\n", (int) (this->pix_size * this->npix)); exit(1); } memset (this->img, 0, this->pix_size * this->npix); } } void Volume::create ( const plm_long new_dim[3], const float origin[3], const float spacing[3], const float direction_cosines[9], enum Volume_pixel_type vox_type, int vox_planes ) { init (); for (int i = 0; i < 3; i++) { this->dim[i] = new_dim[i]; this->origin[i] = origin[i]; this->spacing[i] = spacing[i]; } this->npix = this->dim[0] * this->dim[1] * this->dim[2]; this->pix_type = vox_type; this->vox_planes = vox_planes; set_direction_cosines (direction_cosines); switch (vox_type) { case PT_UCHAR: this->pix_size = sizeof(unsigned char); break; case PT_SHORT: this->pix_size = sizeof(short); break; case PT_UINT16: this->pix_size = sizeof(uint16_t); break; case PT_UINT32: this->pix_size = sizeof(uint32_t); break; case PT_INT32: this->pix_size = sizeof(int32_t); break; case PT_FLOAT: this->pix_size = sizeof(float); break; case PT_VF_FLOAT_INTERLEAVED: this->pix_size = 3 * sizeof(float); break; case PT_VF_FLOAT_PLANAR: this->pix_size = sizeof(float); break; case PT_UCHAR_VEC_INTERLEAVED: this->pix_size = this->vox_planes * sizeof(unsigned char); break; default: fprintf (stderr, "Unhandled type in volume_create().\n"); exit (-1); } this->allocate (); } void Volume::create ( const Volume_header& vh, enum Volume_pixel_type vox_type, int vox_planes ) { this->create (vh.get_dim(), vh.get_origin(), vh.get_spacing(), vh.get_direction_cosines(), vox_type, vox_planes); } const float* Volume::get_origin () const { return this->origin; } void Volume::get_origin (float *origin) const { for (int d = 0; d < 3; d++) { origin[d] = this->origin[d]; } } void Volume::set_origin (const float origin[3]) { for (int d = 0; d < 3; d++) { this->origin[d] = origin[d]; } } void Volume::set_direction_cosines ( const float direction_cosines[9] ) { const float identity[9] = {1., 0., 0., 0., 1., 0., 0., 0., 1.}; const float* dc; if (direction_cosines) { dc = direction_cosines; } else { dc = identity; } this->direction_cosines.set (dc); compute_direction_matrices (step, proj, this->direction_cosines, this->spacing); } template T* Volume::get_raw () { return (T*) this->img; } template const T* Volume::get_raw () const { return (const T*) this->img; } const float* Volume::get_step (void) const { return this->step; } const float* Volume::get_proj (void) const { return this->proj; } Volume* volume_clone_empty (Volume* ref) { Volume* vout; vout = new Volume (ref->dim, ref->origin, ref->spacing, ref->direction_cosines, ref->pix_type, ref->vox_planes); return vout; } Volume* volume_clone (const Volume* ref) { Volume* vout; vout = new Volume (ref->dim, ref->origin, ref->spacing, ref->direction_cosines, ref->pix_type, ref->vox_planes); switch (ref->pix_type) { case PT_UCHAR: case PT_SHORT: case PT_UINT16: case PT_UINT32: case PT_INT32: case PT_FLOAT: case PT_VF_FLOAT_INTERLEAVED: case PT_UCHAR_VEC_INTERLEAVED: memcpy (vout->img, ref->img, ref->npix * ref->pix_size); break; case PT_VF_FLOAT_PLANAR: default: fprintf (stderr, "Unsupported clone\n"); exit (-1); break; } return vout; } Volume* Volume::clone_raw () { return volume_clone (this); } Volume::Pointer Volume::clone () { return Volume::New (this->clone_raw ()); } Volume::Pointer Volume::clone_empty () { Volume* vout = volume_clone_empty (this); return Volume::Pointer (vout); } void volume_convert_to_float (Volume* ref) { switch (ref->pix_type) { case PT_UCHAR: CONVERT_INPLACE (float, unsigned char, PT_FLOAT); break; case PT_SHORT: CONVERT_INPLACE (float, short, PT_FLOAT); break; case PT_UINT16: CONVERT_INPLACE (float, uint16_t, PT_FLOAT); break; case PT_UINT32: CONVERT_INPLACE (float, uint32_t, PT_FLOAT); break; case PT_INT32: CONVERT_INPLACE (float, int32_t, PT_FLOAT); break; case PT_FLOAT: /* Nothing to do */ break; case PT_VF_FLOAT_INTERLEAVED: case PT_VF_FLOAT_PLANAR: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ fprintf (stderr, "Sorry, unsupported conversion to FLOAT\n"); exit (-1); break; } } void volume_convert_to_short (Volume* ref) { switch (ref->pix_type) { case PT_UCHAR: fprintf (stderr, "Sorry, UCHAR to SHORT is not implemented\n"); exit (-1); break; case PT_SHORT: /* Nothing to do */ break; case PT_UINT16: case PT_UINT32: case PT_INT32: fprintf (stderr, "Sorry, UINT16/UINT32/INT32 to SHORT is not implemented\n"); exit (-1); break; case PT_FLOAT: CONVERT_INPLACE (short, float, PT_SHORT); break; case PT_VF_FLOAT_INTERLEAVED: case PT_VF_FLOAT_PLANAR: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ fprintf (stderr, "Sorry, unsupported conversion to SHORT\n"); exit (-1); break; } } void volume_convert_to_uchar (Volume* ref) { switch (ref->pix_type) { case PT_UCHAR: /* Nothing to do */ break; case PT_SHORT: CONVERT_INPLACE (unsigned char, short, PT_UCHAR); break; case PT_UINT16: CONVERT_INPLACE (unsigned char, uint16_t, PT_UCHAR); break; case PT_UINT32: CONVERT_INPLACE (unsigned char, uint32_t, PT_UCHAR); break; case PT_INT32: CONVERT_INPLACE (unsigned char, int32_t, PT_UCHAR); break; case PT_FLOAT: CONVERT_INPLACE (unsigned char, float, PT_UCHAR); break; case PT_VF_FLOAT_INTERLEAVED: case PT_VF_FLOAT_PLANAR: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ fprintf (stderr, "Sorry, unsupported conversion to UCHAR\n"); exit (-1); break; } } void volume_convert_to_uint16 (Volume* ref) { switch (ref->pix_type) { case PT_UCHAR: case PT_SHORT: fprintf (stderr, "Sorry, UCHAR/SHORT to UINT16 is not implemented\n"); exit (-1); break; case PT_UINT16: /* Nothing to do */ break; case PT_UINT32: fprintf (stderr, "Sorry, UINT32 to UINT16 is not implemented\n"); break; case PT_INT32: fprintf (stderr, "Sorry, UINT32 to INT32 is not implemented\n"); break; case PT_FLOAT: CONVERT_INPLACE (uint16_t, float, PT_UINT32); break; case PT_VF_FLOAT_INTERLEAVED: case PT_VF_FLOAT_PLANAR: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ fprintf (stderr, "Sorry, unsupported conversion to UINT32\n"); exit (-1); break; } } void volume_convert_to_uint32 (Volume* ref) { switch (ref->pix_type) { case PT_UCHAR: case PT_SHORT: fprintf (stderr, "Sorry, UCHAR/SHORT to UINT32 is not implemented\n"); exit (-1); break; case PT_UINT16: fprintf (stderr, "Sorry, UINT16 to UINT32 is not implemented\n"); exit (-1); break; case PT_UINT32: /* Nothing to do */ break; case PT_INT32: fprintf (stderr, "Sorry, INT32 to UINT32 is not implemented\n"); exit (-1); break; case PT_FLOAT: CONVERT_INPLACE (uint32_t, float, PT_UINT32); break; case PT_VF_FLOAT_INTERLEAVED: case PT_VF_FLOAT_PLANAR: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ fprintf (stderr, "Sorry, unsupported conversion to UINT32\n"); exit (-1); break; } } void volume_convert_to_int32 (Volume* ref) { switch (ref->pix_type) { case PT_UCHAR: case PT_SHORT: fprintf (stderr, "Sorry, UCHAR/SHORT to INT32 is not implemented\n"); exit (-1); break; case PT_UINT16: fprintf (stderr, "Sorry, UINT16 to INT32 is not implemented\n"); exit (-1); break; case PT_INT32: /* Nothing to do */ break; case PT_UINT32: fprintf (stderr, "Sorry, UINT32 to INT32 is not implemented\n"); exit (-1); break; case PT_FLOAT: CONVERT_INPLACE (int32_t, float, PT_INT32); break; case PT_VF_FLOAT_INTERLEAVED: case PT_VF_FLOAT_PLANAR: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ fprintf (stderr, "Sorry, unsupported conversion to INT32\n"); exit (-1); break; } } void vf_convert_to_interleaved (Volume* vf) { switch (vf->pix_type) { case PT_VF_FLOAT_INTERLEAVED: /* Nothing to do */ break; case PT_VF_FLOAT_PLANAR: { plm_long v; float** planar = (float**) vf->img; float* inter = (float*) malloc (3*sizeof(float*)*vf->npix); if (!inter) { fprintf (stderr, "Memory allocation failed.\n"); exit(1); } for (v = 0; v < vf->npix; v++) { inter[3*v + 0] = planar[0][v]; inter[3*v + 1] = planar[1][v]; inter[3*v + 2] = planar[2][v]; } free (planar[0]); free (planar[1]); free (planar[2]); free (planar); vf->img = (void*) inter; vf->pix_type = PT_VF_FLOAT_INTERLEAVED; vf->pix_size = 3*sizeof(float); } break; case PT_UCHAR: case PT_SHORT: case PT_UINT16: case PT_UINT32: case PT_INT32: case PT_FLOAT: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ fprintf (stderr, "Sorry, unsupported conversion to VF\n"); exit (-1); break; } } void vf_convert_to_planar (Volume* ref) { switch (ref->pix_type) { case PT_VF_FLOAT_INTERLEAVED: { float* img = (float*) ref->img; float** der = (float**) malloc (3*sizeof(float*)); if (!der) { printf ("Memory allocation failed.\n"); exit(1); } int alloc_size = ref->npix; for (int i=0; i < 3; i++) { der[i] = (float*) malloc (alloc_size*sizeof(float)); if (!der[i]) { print_and_exit ("Memory allocation failed.\n"); } } for (plm_long i = 0; i < ref->npix; i++) { der[0][i] = img[3*i + 0]; der[1][i] = img[3*i + 1]; der[2][i] = img[3*i + 2]; } free (ref->img); ref->img = (void*) der; ref->pix_type = PT_VF_FLOAT_PLANAR; ref->pix_size = sizeof(float); } break; case PT_VF_FLOAT_PLANAR: /* Nothing to do */ break; case PT_UCHAR: case PT_SHORT: case PT_UINT32: case PT_INT32: case PT_FLOAT: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ fprintf (stderr, "Sorry, unsupportd conversion to VF\n"); exit (-1); break; } } void Volume::convert (Volume_pixel_type new_type) { switch (new_type) { case PT_UCHAR: volume_convert_to_uchar (this); break; case PT_SHORT: volume_convert_to_short (this); break; case PT_UINT16: volume_convert_to_uint16 (this); break; case PT_UINT32: volume_convert_to_uint32 (this); break; case PT_INT32: volume_convert_to_int32 (this); break; case PT_FLOAT: volume_convert_to_float (this); break; case PT_VF_FLOAT_INTERLEAVED: vf_convert_to_interleaved (this); break; case PT_VF_FLOAT_PLANAR: vf_convert_to_planar (this); break; case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ print_and_exit ( "Sorry, unsupported conversion type to %d in Volume::convert()\n", new_type); break; } } template static void clone_inner ( Volume::Pointer& vol_out, const Volume* vol_in) { switch (vol_in->pix_type) { case PT_UCHAR: convert_raw ( vol_out->get_raw(), vol_in); break; case PT_UINT16: convert_raw ( vol_out->get_raw(), vol_in); break; case PT_SHORT: convert_raw ( vol_out->get_raw(), vol_in); break; case PT_UINT32: convert_raw ( vol_out->get_raw(), vol_in); break; case PT_INT32: convert_raw ( vol_out->get_raw(), vol_in); break; case PT_FLOAT: convert_raw ( vol_out->get_raw(), vol_in); break; case PT_VF_FLOAT_INTERLEAVED: case PT_VF_FLOAT_PLANAR: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ fprintf (stderr, "Sorry, unsupported conversion to INT32\n"); exit (-1); break; } } Volume::Pointer Volume::clone (Volume_pixel_type new_type) const { Volume::Pointer vol_out = Volume::New (); vol_out->create ( this->dim, this->origin, this->spacing, this->direction_cosines, new_type, this->vox_planes); switch (new_type) { case PT_UCHAR: clone_inner (vol_out, this); return vol_out; case PT_UINT16: clone_inner (vol_out, this); return vol_out; case PT_SHORT: clone_inner (vol_out, this); return vol_out; case PT_UINT32: clone_inner (vol_out, this); return vol_out; case PT_INT32: clone_inner (vol_out, this); return vol_out; case PT_FLOAT: clone_inner (vol_out, this); return vol_out; case PT_VF_FLOAT_INTERLEAVED: case PT_VF_FLOAT_PLANAR: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ print_and_exit ( "Sorry, unsupported conversion type to %d in Volume::convert_gcs()\n", new_type); return vol_out; } } #if defined (commentout) switch (new_type) { case PT_UCHAR: volume_convert_to_uchar (this); break; case PT_SHORT: volume_convert_to_short (this); break; case PT_UINT16: volume_convert_to_uint16 (this); break; case PT_UINT32: volume_convert_to_uint32 (this); break; case PT_INT32: volume_convert_to_int32 (this); break; case PT_FLOAT: volume_convert_to_float (this); break; case PT_VF_FLOAT_INTERLEAVED: vf_convert_to_interleaved (this); break; case PT_VF_FLOAT_PLANAR: vf_convert_to_planar (this); break; case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ print_and_exit ( "Sorry, unsupported conversion type to %d in Volume::convert()\n", new_type); break; } #endif float Volume::get_ijk_value (const float ijk[3]) const { plm_long ijk_f[3]; plm_long ijk_r[3]; float li_1[3]; float li_2[3]; // Compute linear interpolation fractions li_clamp_3d (ijk, ijk_f, ijk_r, li_1, li_2, this); // Find linear indices of corner voxel plm_long idx_floor = volume_index (this->dim, ijk_f); // Calc. moving voxel intensity via linear interpolation float val; float* img = (float*) this->img; LI_VALUE ( val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], idx_floor, img, this ); return val; } /* GCS FIX: These functions are incorrect, they ignore direction cosines */ void Volume::get_xyz_from_ijk (double xyz[3], const int ijk[3]) { xyz[0] = this->origin[0] + ijk[0] * this->spacing[0]; xyz[1] = this->origin[1] + ijk[1] * this->spacing[1]; xyz[2] = this->origin[2] + ijk[2] * this->spacing[2]; } void Volume::get_ijk_from_xyz (float ijk[3], const float xyz[3], bool* in) { *in = true; for (int i = 0; i < 3; i++) { ijk[i] = (float) (xyz[i]-this->origin[i])/this->spacing[i]; if (ijk[i] < 0 || ijk[i] >= this->dim[i] -1) { *in = false; return; } } return; } void Volume::get_ijk_from_xyz (int ijk[3], const float xyz[3], bool* in) { *in = true; for (int i = 0; i < 3; i++) { ijk[i] = (int) floor(xyz[i]-this->origin[i])/this->spacing[i]; if (ijk[i] < 0 || ijk[i] >= this->dim[i]) { *in = false; return; } } } bool Volume::is_inside (const float ijk[3]) const { if (ijk[0] <= -0.5 || ijk[0] >= this->dim[0] - 0.5) return false; if (ijk[1] <= -0.5 || ijk[1] >= this->dim[1] - 0.5) return false; if (ijk[2] <= -0.5 || ijk[2] >= this->dim[2] - 0.5) return false; return true; } void Volume::move_origin_to_idx (const plm_long ijk[3]) { float new_origin[3]; this->position (new_origin, ijk); this->set_origin (new_origin); } void Volume::scale_inplace (float scale) { float *img; if (this->pix_type != PT_FLOAT) { print_and_exit ("Volume::scale_inplace requires PT_FLOAT type.\n"); } img = (float*) this->img; for (plm_long i = 0; i < this->npix; i++) { img[i] = img[i] * scale; } } void Volume::debug () { lprintf ("dim:%d %d %d\n", (int) dim[0], (int) dim[1], (int) dim[2] ); lprintf ("org:%f %f %f\n", origin[0], origin[1], origin[2] ); lprintf ("spac:%f %f %f\n", spacing[0], spacing[1], spacing[2] ); lprintf ("dc:%8f %8f %8f\n%8f %8f %8f\n%8f %8f %8f\n", direction_cosines[0], direction_cosines[1], direction_cosines[2], direction_cosines[3], direction_cosines[4], direction_cosines[5], direction_cosines[6], direction_cosines[7], direction_cosines[8] ); } void Volume::direction_cosines_debug () { lprintf ("org:%f %f %f\n", origin[0], origin[1], origin[2] ); lprintf ("spac:%f %f %f\n", spacing[0], spacing[1], spacing[2] ); lprintf ("dc:\n%8f %8f %8f\n%8f %8f %8f\n%8f %8f %8f\n", direction_cosines[0], direction_cosines[1], direction_cosines[2], direction_cosines[3], direction_cosines[4], direction_cosines[5], direction_cosines[6], direction_cosines[7], direction_cosines[8] ); lprintf ("step:\n%8f %8f %8f\n%8f %8f %8f\n%8f %8f %8f\n", step[3*0+0], step[3*0+1], step[3*0+2], step[3*1+0], step[3*1+1], step[3*1+2], step[3*2+0], step[3*2+1], step[3*2+2] ); lprintf ("proj:\n%8f %8f %8f\n%8f %8f %8f\n%8f %8f %8f\n", proj[3*0+0], proj[3*0+1], proj[3*0+2], proj[3*1+0], proj[3*1+1], proj[3*1+2], proj[3*2+0], proj[3*2+1], proj[3*2+2] ); } // Computes the intensity differences between two images Volume* volume_difference (Volume* vol, Volume* warped) { plm_long i, j, k; int p = 0; // Voxel index short* temp2; short* temp1; short* temp3; Volume* temp; temp = (Volume*) malloc (sizeof(Volume)); if (!temp) { fprintf (stderr, "Memory allocation failed.\n"); exit(1); } for(i=0;i<3; i++){ temp->dim[i] = vol->dim[i]; temp->origin[i] = vol->origin[i]; temp->spacing[i] = vol->spacing[i]; } temp->npix = vol->npix; temp->pix_type = vol->pix_type; temp->img = (void*) malloc (sizeof(short)*temp->npix); if (!temp->img) { fprintf (stderr, "Memory allocation failed.\n"); exit(1); } memset (temp->img, -1200, sizeof(short)*temp->npix); p = 0; // Voxel index temp2 = (short*)vol->img; temp1 = (short*)warped->img; temp3 = (short*)temp->img; for (i=0; i < vol->dim[2]; i++) { for (j=0; j < vol->dim[1]; j++) { for (k=0; k < vol->dim[0]; k++) { temp3[p] = (temp2[p] - temp1[p]) - 1200; p++; } } } return temp; } /* Explicit instantiations */ template PLMBASE_API unsigned char* Volume::get_raw (); template PLMBASE_API const unsigned char* Volume::get_raw () const; template PLMBASE_API float* Volume::get_raw (); template PLMBASE_API const float* Volume::get_raw () const; plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume.h000077500000000000000000000177311321604176500272250ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_h_ #define _volume_h_ #include "plmbase_config.h" #include "direction_cosines.h" #include "plm_int.h" #include "smart_pointer.h" #include "volume_macros.h" class Volume_header; enum Volume_pixel_type { PT_UNDEFINED, PT_UCHAR, PT_UINT16, PT_SHORT, PT_UINT32, PT_INT32, PT_FLOAT, PT_VF_FLOAT_INTERLEAVED, PT_VF_FLOAT_PLANAR, PT_UCHAR_VEC_INTERLEAVED }; /*! \brief * The Volume class represents a three-dimensional volume on a uniform * grid. The volume can be located at arbitrary positions and orientations * in space, and can represent most voxel types (float, unsigned char, etc.). * A volume can also support multiple planes, which is used to hold * three dimensional vector fields, or three-dimensional bitfields. */ class PLMBASE_API Volume { public: SMART_POINTER_SUPPORT (Volume); public: plm_long dim[3]; // x, y, z Dims plm_long npix; // # of voxels in volume // = dim[0] * dim[1] * dim[2] float origin[3]; float spacing[3]; Direction_cosines direction_cosines; enum Volume_pixel_type pix_type; // Voxel Data type int vox_planes; // # planes per voxel int pix_size; // # bytes per voxel void* img; // Voxel Data public: float step[9]; // direction_cosines * spacing float proj[9]; // inv direction_cosines / spacing public: Volume (); Volume ( const plm_long dim[3], const float origin[3], const float spacing[3], const float direction_cosines[9], enum Volume_pixel_type vox_type, int vox_planes ); Volume ( const plm_long dim[3], const float origin[3], const float spacing[3], const Direction_cosines& direction_cosines, enum Volume_pixel_type vox_type, int vox_planes ); Volume ( const Volume_header& vh, enum Volume_pixel_type vox_type, int vox_planes ); ~Volume (); public: /*! \brief Return a linear index to a voxel */ plm_long index (plm_long i, plm_long j, plm_long k) const { return volume_index (this->dim, i, j, k); } /*! \brief Return a linear index to a voxel */ plm_long index (plm_long ijk[3]) const { return volume_index (this->dim, ijk); } /*! \brief Initialize and allocate memory for the image */ void create ( const plm_long new_dim[3], const float origin[3], const float spacing[3], const float direction_cosines[9], enum Volume_pixel_type vox_type, int vox_planes = 1 ); /*! \brief Initialize and allocate memory for the image */ void create ( const Volume_header& vh, enum Volume_pixel_type vox_type, int vox_planes = 1 ); /*! \brief Make a copy of the volume */ Volume::Pointer clone (); /*! \brief Make a copy of the volume with the same geometry and same voxel values, but converted to a different data type */ Volume::Pointer clone (Volume_pixel_type new_type) const; /*! \brief Make a copy of the volume with the same geometry, but set all the voxel values to zero. */ Volume::Pointer clone_empty (); /*! \brief Convert the image voxels to a new data type */ void convert (Volume_pixel_type new_type); /*! \brief Get a pointer to the origin of the volume. The origin is defined as the location in world coordinates of the center of the first voxel in the volume. */ const float* get_origin (void) const; void get_origin (float *) const; /*! \brief Set the origin. The origin is defined as the location in world coordinates of the center of the first voxel in the volume. */ void set_origin (const float origin[3]); /*! \brief Get a pointer to the volume dimensions */ const plm_long *get_dim (void) { return dim; } /*! \brief Get a pointer to the direction cosines. Direction cosines hold the orientation of a volume. They are defined as the unit length direction vectors of the volume in world space as one traverses the pixels in the raw array of values. */ Direction_cosines& get_direction_cosines (void) { return direction_cosines; } const Direction_cosines& get_direction_cosines (void) const { return direction_cosines; } float* get_direction_matrix (void) { return direction_cosines.get_matrix(); } const float* get_direction_matrix (void) const { return direction_cosines.get_matrix(); } /*! \brief Set the direction cosines. Direction cosines hold the orientation of a volume. They are defined as the unit length direction vectors of the volume in world space as one traverses the pixels in the raw array of values. */ void set_direction_cosines (const float direction_cosines[9]); /*! \brief Get the raw image pointer as specified type. No error checking done. */ template T* get_raw (); template const T* get_raw () const; /*! \brief Get the step matrix. The step matrix encodes the transform from voxel coordinates to world coordinates. */ const float* get_step (void) const; /*! \brief Get the proj matrix. The proj matrix encodes the transform from world coordinates to voxel coordinates. */ const float* get_proj (void) const; /*! \brief Return a world coordinates of a voxel */ void position (float xyz[3], const plm_long ijk[3]) { POSITION_FROM_COORDS (xyz, ijk, this->origin, this->step); } /*! \brief Return coordinates from index */ void coordinates (plm_long ijk[3], plm_long idx) { COORDS_FROM_INDEX(ijk, idx, this->dim); } /*! \brief Get the value at a voxel coordinate, clamped and tri-linearly interpolated. Only applies to float volumes. */ float get_ijk_value (const float xyz[3]) const; void get_xyz_from_ijk (double xyz[3], const int ijk[3]); void get_ijk_from_xyz (int ijk[3], const float xyz[3], bool* in); void get_ijk_from_xyz (float ijk[3], const float xyz[3], bool* in); /*! \brief Return true if continuous index ijk is inside volume */ bool is_inside (const float ijk[3]) const; /*! \brief Move the origin to the coordinate at a given index. This is used to correct itk images which have a non-zero region index. */ void move_origin_to_idx (const plm_long ijk[3]); /*! \brief In-place (destructive) scaling of the image according to the supplied scale factor */ void scale_inplace (float scale); void debug (); void direction_cosines_debug (); protected: void allocate (void); void init (); public: /* Some day, these should become protected */ Volume* clone_raw (); private: Volume (const Volume&); void operator= (const Volume&); }; PLMBASE_C_API void vf_convert_to_interleaved (Volume* ref); PLMBASE_C_API void vf_convert_to_planar (Volume* ref, int min_size); PLMBASE_C_API void vf_pad_planar (Volume* vol, int size); // deprecated? PLMBASE_C_API Volume* volume_clone_empty (Volume* ref); PLMBASE_C_API Volume* volume_clone (const Volume* ref); PLMBASE_C_API void volume_convert_to_float (Volume* ref); PLMBASE_C_API void volume_convert_to_int32 (Volume* ref); PLMBASE_C_API void volume_convert_to_short (Volume* ref); PLMBASE_C_API void volume_convert_to_uchar (Volume* ref); PLMBASE_C_API void volume_convert_to_uint16 (Volume* ref); PLMBASE_C_API void volume_convert_to_uint32 (Volume* ref); PLMBASE_C_API Volume* volume_difference (Volume* vol, Volume* warped); PLMBASE_C_API void volume_matrix3x3inverse (float *out, const float *m); #endif volume_boundary_behavior.h000066400000000000000000000016621321604176500327210ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_boundary_behavior_h_ #define _volume_boundary_behavior_h_ #include "plmbase_config.h" /*! \brief This enum is used to control the algorithm behavior for voxels at the edge of the volume. If ZERO_PADDING is specified, all non-zero voxels at the edge of the volume will be treated as boundary voxels. If EDGE_PADDING is specified, non-zero voxels at the edge of the volume are only treated as boundary voxels if they neighbor a zero voxel. If ADAPTIVE_PADDING, it will use EDGE_PADDING for dimensions of a single voxel, and ZERO_PADDING for dimensions of multiple voxels. */ enum Volume_boundary_behavior { ZERO_PADDING, EDGE_PADDING, ADAPTIVE_PADDING }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_conv.cxx000066400000000000000000000162071321604176500306170ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #if (OPENMP_FOUND) #include #endif #include "clamp.h" #include "logfile.h" #include "plm_int.h" #include "plm_math.h" #include "print_and_exit.h" #include "volume.h" #include "volume_header.h" #include "volume_conv.h" static void pixel_conv ( float* img_out, const float *img_in, const float *img_ker, const plm_long *dim_in, const plm_long *dim_ker, const plm_long *ker_hw, const plm_long *ijk_out) { /* GCS FIX: This could be made faster by adding preamble and postable loops rather than clamping */ plm_long ijk_ker[3]; /* kernel ijk of kernel */ plm_long ijk_in[3]; /* image ijk of kernel overlaid */ plm_long out_v = volume_index (dim_in, ijk_out); for (ijk_ker[2] = 0; ijk_ker[2] < dim_ker[2]; ijk_ker[2]++) { ijk_in[2] = ijk_out[2] + ijk_ker[2] - ker_hw[2]; CLAMP (ijk_in[2], 0, dim_in[2]-1); for (ijk_ker[1] = 0; ijk_ker[1] < dim_ker[1]; ijk_ker[1]++) { ijk_in[1] = ijk_out[1] + ijk_ker[1] - ker_hw[1]; CLAMP (ijk_in[1], 0, dim_in[1]-1); for (ijk_ker[0] = 0; ijk_ker[0] < dim_ker[0]; ijk_ker[0]++) { ijk_in[0] = ijk_out[0] + ijk_ker[0] - ker_hw[0]; CLAMP (ijk_in[0], 0, dim_in[0]-1); plm_long ker_v = volume_index (dim_ker, ijk_ker); plm_long in_v = volume_index (dim_in, ijk_in); img_out[out_v] += img_ker[ker_v] * img_in[in_v]; } } } } Volume::Pointer volume_conv ( const Volume::Pointer& vol_in, const Volume::Pointer& ker_in) { Volume::Pointer vol_out = vol_in->clone_empty(); const float *img_in = vol_in->get_raw (); const float *img_ker = ker_in->get_raw (); float *img_out = vol_out->get_raw (); const plm_long* dim_in = vol_in->dim; const plm_long* dim_ker = ker_in->dim; /* Compute kernel half-width */ plm_long ker_hw[3]; for (int d = 0; d < 3; d++) { ker_hw[d] = dim_ker[d] / 2; } #pragma omp parallel for LOOP_Z_OMP (k, vol_in) { plm_long ijk_out[3]; ijk_out[2] = k; for (ijk_out[1] = 0; ijk_out[1] < vol_in->dim[1]; ijk_out[1]++) { for (ijk_out[0] = 0; ijk_out[0] < vol_in->dim[0]; ijk_out[0]++) { pixel_conv (img_out, img_in, img_ker, dim_in, dim_ker, ker_hw, ijk_out); } } } return vol_out; } void volume_convolve_x ( Volume::Pointer& vol_out, const Volume::Pointer& vol_in, float *ker, int width ) { const float *img_in = vol_in->get_raw (); float *img_out = vol_out->get_raw (); const plm_long* dim_in = vol_in->dim; int half_width = width / 2; #pragma omp parallel for LOOP_Z_OMP (k, vol_in) { plm_long ijk[3]; ijk[2] = k; for (ijk[1] = 0; ijk[1] < dim_in[1]; ijk[1]++) { for (ijk[0] = 0; ijk[0] < dim_in[0]; ijk[0]++) { plm_long i, i1; /* i is the offset in the vol */ plm_long j, j1, j2; /* j is the index of the kernel */ plm_long v = volume_index (dim_in, ijk); if (ijk[0] < half_width) { i1 = 0; j1 = half_width - ijk[0]; } else { i1 = ijk[0] - half_width; j1 = 0; } if (ijk[0] + half_width > dim_in[0] - 1) { j2 = half_width + (dim_in[0] - ijk[0]) - 1; } else { j2 = 2 * half_width; } float ktot = 0.0f; img_out[v] = (float) 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { plm_long idx = vol_in->index (i, ijk[1], ijk[2]); img_out[v] += ker[j] * img_in [idx]; ktot += ker[j]; } img_out[v] /= ktot; #if defined (commentout) printf ("%u %u %u | %u | %u %u %u\n", ijk[2], ijk[1], ijk[0], v, i1, j1, j2); #endif } } } } void volume_convolve_y ( Volume::Pointer& vol_out, const Volume::Pointer& vol_in, float *ker, int width ) { const float *img_in = vol_in->get_raw (); float *img_out = vol_out->get_raw (); const plm_long* dim_in = vol_in->dim; int half_width = width / 2; #pragma omp parallel for LOOP_Z_OMP (k, vol_in) { plm_long ijk[3]; ijk[2] = k; for (ijk[1] = 0; ijk[1] < vol_in->dim[1]; ijk[1]++) { for (ijk[0] = 0; ijk[0] < vol_in->dim[0]; ijk[0]++) { plm_long i, i1; /* i is the offset in the vf */ plm_long j, j1, j2; /* j is the index of the kernel */ plm_long v = volume_index (dim_in, ijk); if (ijk[1] < half_width) { i1 = 0; j1 = half_width - ijk[1]; } else { i1 = ijk[1] - half_width; j1 = 0; } if (ijk[1] + half_width > vol_in->dim[1] - 1) { j2 = half_width + (vol_in->dim[1] - ijk[1]) - 1; } else { j2 = 2 * half_width; } float ktot = 0.0f; img_out[v] = (float) 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { plm_long idx = vol_in->index (ijk[0], i, ijk[2]); img_out[v] += ker[j] * img_in [idx]; ktot += ker[j]; } img_out[v] /= ktot; } } } } void volume_convolve_z ( Volume::Pointer& vol_out, const Volume::Pointer& vol_in, float *ker, int width ) { const float *img_in = vol_in->get_raw (); float *img_out = vol_out->get_raw (); const plm_long* dim_in = vol_in->dim; int half_width = width / 2; #pragma omp parallel for LOOP_Z_OMP (k, vol_in) { plm_long ijk[3]; ijk[2] = k; for (ijk[1] = 0; ijk[1] < vol_in->dim[1]; ijk[1]++) { for (ijk[0] = 0; ijk[0] < vol_in->dim[0]; ijk[0]++) { plm_long i, i1; /* i is the offset in the vf */ plm_long j, j1, j2; /* j is the index of the kernel */ plm_long v = volume_index (dim_in, ijk); if (ijk[2] < half_width) { i1 = 0; j1 = half_width - ijk[2]; } else { i1 = ijk[2] - half_width; j1 = 0; } if (ijk[2] + half_width > vol_in->dim[2] - 1) { j2 = half_width + (vol_in->dim[2] - ijk[2]) - 1; } else { j2 = 2 * half_width; } float ktot = 0.0f; img_out[v] = (float) 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { plm_long idx = vol_in->index (ijk[0], ijk[1], i); img_out[v] += ker[j] * img_in [idx]; ktot += ker[j]; } img_out[v] /= ktot; } } } } Volume::Pointer volume_convolve_separable ( const Volume::Pointer& vol_in, float *ker_i, int width_i, float *ker_j, int width_j, float *ker_k, int width_k ) { Volume::Pointer vol_1 = vol_in->clone_empty(); Volume::Pointer vol_2 = vol_in->clone_empty(); volume_convolve_x (vol_1, vol_in, ker_i, width_i); volume_convolve_y (vol_2, vol_1, ker_j, width_j); volume_convolve_z (vol_1, vol_2, ker_k, width_k); return vol_1; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_conv.h000066400000000000000000000011651321604176500302410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_conv_h_ #define _volume_conv_h_ #include "plmbase_config.h" PLMBASE_API Volume::Pointer volume_conv ( const Volume::Pointer& vol_in, const Volume::Pointer& ker_in ); PLMBASE_API Volume::Pointer volume_convolve_separable ( const Volume::Pointer& vol_in, float *ker_i, int width_i, float *ker_j, int width_j, float *ker_k, int width_k ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_fill.cxx000066400000000000000000000011011321604176500305630ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "string.h" #include "volume_fill.h" template void volume_fill ( Volume* vol, T val ) { T* img = vol->get_raw (); for (plm_long i = 0; i < vol->npix; i++) { img[i] = val; } } /* Explicit instantiations */ template PLMBASE_API void volume_fill (Volume* vol, float val); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_fill.h000066400000000000000000000006371321604176500302250ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_fill_h_ #define _volume_fill_h_ #include "plmbase_config.h" #include "volume.h" template PLMBASE_API void volume_fill ( Volume* vol, T val ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_gaussian.cxx000066400000000000000000000024151321604176500314600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include "gaussian.h" #include "volume.h" #include "volume_conv.h" #include "volume_gaussian.h" PLMBASE_API Volume::Pointer volume_gaussian ( const Volume::Pointer& vol_in, float sigma, float truncation ) { float *kerx, *kery, *kerz; int fw[3]; /* Set the filter widths */ for (int d = 0; d < 3; d++) { int half_width = ROUND_INT (truncation * sigma / vol_in->spacing[d]); if (half_width < 1) { half_width = 1; } fw[d] = 2 * half_width + 1; } /* Create the seperable smoothing kernels for the x, y, and z directions */ kerx = create_ker (sigma / vol_in->spacing[0], fw[0]/2); kery = create_ker (sigma / vol_in->spacing[1], fw[1]/2); kerz = create_ker (sigma / vol_in->spacing[2], fw[2]/2); kernel_stats (kerx, kery, kerz, fw); Volume::Pointer vf_out = volume_convolve_separable ( vol_in, kerx, fw[0], kery, fw[1], kerz, fw[2]); free (kerx); free (kery); free (kerz); return vf_out; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_gaussian.h000066400000000000000000000006751321604176500311130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_gaussian_h_ #define _volume_gaussian_h_ #include "plmbase_config.h" PLMBASE_API Volume::Pointer volume_gaussian ( const Volume::Pointer& vol_in, float width, float truncation ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_grad.cxx000066400000000000000000000111441321604176500305620ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "logfile.h" #include "volume_grad.h" static void volume_calc_grad (Volume* vout, const Volume* vref) { plm_long i, j, k; plm_long i_n, j_n, k_n; /* n is next */ int i_p, j_p, k_p; /* p is prev */ plm_long gi, gj, gk; plm_long idx_p, idx_n; float *out_img, *ref_img; out_img = (float*) vout->img; ref_img = (float*) vref->img; const float *inv_dc = vref->direction_cosines.get_inverse(); plm_long v = 0; for (k = 0; k < vref->dim[2]; k++) { k_p = k - 1; k_n = k + 1; if (k == 0) k_p = 0; if (k == vref->dim[2]-1) k_n = vref->dim[2]-1; for (j = 0; j < vref->dim[1]; j++) { j_p = j - 1; j_n = j + 1; if (j == 0) j_p = 0; if (j == vref->dim[1]-1) j_n = vref->dim[1]-1; for (i = 0; i < vref->dim[0]; i++, v++) { float diff; i_p = i - 1; i_n = i + 1; if (i == 0) i_p = 0; if (i == vref->dim[0]-1) i_n = vref->dim[0]-1; gi = 3 * v + 0; gj = 3 * v + 1; gk = 3 * v + 2; out_img[gi] = 0.f; out_img[gj] = 0.f; out_img[gk] = 0.f; idx_p = volume_index (vref->dim, i_p, j, k); idx_n = volume_index (vref->dim, i_n, j, k); diff = (float) (ref_img[idx_n] - ref_img[idx_p]) / 2.0 / vref->spacing[0]; out_img[gi] += diff * inv_dc[0*3+0]; out_img[gj] += diff * inv_dc[1*3+0]; out_img[gk] += diff * inv_dc[2*3+0]; idx_p = volume_index (vref->dim, i, j_p, k); idx_n = volume_index (vref->dim, i, j_n, k); diff = (float) (ref_img[idx_n] - ref_img[idx_p]) / 2.0 / vref->spacing[1]; out_img[gi] += diff * inv_dc[0*3+1]; out_img[gj] += diff * inv_dc[1*3+1]; out_img[gk] += diff * inv_dc[2*3+1]; idx_p = volume_index (vref->dim, i, j, k_p); idx_n = volume_index (vref->dim, i, j, k_n); diff = (float) (ref_img[idx_n] - ref_img[idx_p]) / 2.0 / vref->spacing[2]; out_img[gi] += diff * inv_dc[0*3+2]; out_img[gj] += diff * inv_dc[1*3+2]; out_img[gk] += diff * inv_dc[2*3+2]; } } } lprintf ("volume_calc_grad complete.\n"); } static void volume_calc_grad_mag (Volume* vout, const Volume* vref) { plm_long i, j, k; plm_long i_n, j_n, k_n; /* n is next */ int i_p, j_p, k_p; /* p is prev */ plm_long idx_p, idx_n; float *out_img, *ref_img; out_img = (float*) vout->img; ref_img = (float*) vref->img; plm_long v = 0; for (k = 0; k < vref->dim[2]; k++) { k_p = k - 1; k_n = k + 1; if (k == 0) k_p = 0; if (k == vref->dim[2]-1) k_n = vref->dim[2]-1; for (j = 0; j < vref->dim[1]; j++) { j_p = j - 1; j_n = j + 1; if (j == 0) j_p = 0; if (j == vref->dim[1]-1) j_n = vref->dim[1]-1; for (i = 0; i < vref->dim[0]; i++, v++) { float diff; i_p = i - 1; i_n = i + 1; if (i == 0) i_p = 0; if (i == vref->dim[0]-1) i_n = vref->dim[0]-1; /* No need to consider direction cosines because we're only computing the magnitude */ out_img[v] = 0.f; idx_p = volume_index (vref->dim, i_p, j, k); idx_n = volume_index (vref->dim, i_n, j, k); diff = (float) (ref_img[idx_n] - ref_img[idx_p]) / 2.0 / vref->spacing[0]; out_img[v] += diff * diff; idx_p = volume_index (vref->dim, i, j_p, k); idx_n = volume_index (vref->dim, i, j_n, k); diff = (float) (ref_img[idx_n] - ref_img[idx_p]) / 2.0 / vref->spacing[1]; out_img[v] += diff * diff; idx_p = volume_index (vref->dim, i, j, k_p); idx_n = volume_index (vref->dim, i, j, k_n); diff = (float) (ref_img[idx_n] - ref_img[idx_p]) / 2.0 / vref->spacing[2]; out_img[v] += diff * diff; out_img[v] = sqrt (out_img[v]); } } } lprintf ("volume_calc_grad_mag complete.\n"); } Volume::Pointer volume_gradient (const Volume::Pointer& ref) { Volume::Pointer grad = Volume::New ( ref->dim, ref->origin, ref->spacing, ref->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); volume_calc_grad (grad.get(), ref.get()); return grad; } Volume* volume_make_gradient (const Volume* ref) { Volume* grad = new Volume ( ref->dim, ref->origin, ref->spacing, ref->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); volume_calc_grad (grad, ref); return grad; } Volume::Pointer volume_gradient_magnitude (const Volume::Pointer& ref) { Volume::Pointer grad = Volume::New ( ref->dim, ref->origin, ref->spacing, ref->direction_cosines, PT_FLOAT, 1); volume_calc_grad_mag (grad.get(), ref.get()); return grad; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_grad.h000066400000000000000000000010601321604176500302030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_grad_h_ #define _volume_grad_h_ #include "plmbase_config.h" #include "volume.h" PLMBASE_API Volume* volume_make_gradient (const Volume* ref); PLMBASE_API Volume::Pointer volume_gradient (const Volume::Pointer& ref); PLMBASE_API Volume::Pointer volume_gradient_magnitude ( const Volume::Pointer& ref); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_header.cxx000066400000000000000000000136761321604176500311110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include "bspline_xform.h" #include "plm_image_header.h" #include "plm_int.h" #include "volume_header.h" class Volume_header_private { public: plm_long m_dim[3]; float m_origin[3]; float m_spacing[3]; Direction_cosines m_direction_cosines; public: Volume_header_private () { for (int d = 0; d < 3; d++) { m_dim[d] = 0; m_origin[d] = 0.; m_spacing[d] = 0.; } m_direction_cosines.set_identity (); } }; Volume_header::Volume_header () { this->d_ptr = new Volume_header_private; } Volume_header::Volume_header ( plm_long dim[3], float origin[3], float spacing[3]) { this->d_ptr = new Volume_header_private; this->set_dim (dim); this->set_origin (origin); this->set_spacing (spacing); this->set_direction_cosines_identity (); } Volume_header::Volume_header ( plm_long dim[3], float origin[3], float spacing[3], float direction_cosines[9]) { this->d_ptr = new Volume_header_private; this->set (dim, origin, spacing, direction_cosines); } Volume_header::Volume_header ( const Volume::Pointer& vol) { this->d_ptr = new Volume_header_private; this->set (vol->dim, vol->origin, vol->spacing, vol->direction_cosines); } Volume_header::Volume_header ( const Plm_image_header *pih) { this->d_ptr = new Volume_header_private; pih->get_dim (d_ptr->m_dim); pih->get_origin (d_ptr->m_origin); pih->get_spacing (d_ptr->m_spacing); d_ptr->m_direction_cosines.set (pih->GetDirection()); } Volume_header::Volume_header ( const Plm_image::Pointer& img) { this->d_ptr = new Volume_header_private; Plm_image_header pih (img); pih.get_dim (d_ptr->m_dim); pih.get_origin (d_ptr->m_origin); pih.get_spacing (d_ptr->m_spacing); d_ptr->m_direction_cosines.set (pih.GetDirection()); } Volume_header::~Volume_header () { delete this->d_ptr; } void Volume_header::set_dim (const plm_long dim[3]) { for (unsigned int d = 0; d < 3; d++) { d_ptr->m_dim[d] = dim[d]; } } plm_long* Volume_header::get_dim () { return d_ptr->m_dim; } const plm_long* Volume_header::get_dim () const { return d_ptr->m_dim; } void Volume_header::set_origin (const float origin[3]) { for (unsigned int d = 0; d < 3; d++) { d_ptr->m_origin[d] = origin[d]; } } float* Volume_header::get_origin () { return d_ptr->m_origin; } const float* Volume_header::get_origin () const { return d_ptr->m_origin; } void Volume_header::set_spacing (const float spacing[3]) { for (unsigned int d = 0; d < 3; d++) { d_ptr->m_spacing[d] = spacing[d]; } } float* Volume_header::get_spacing () { return d_ptr->m_spacing; } const float* Volume_header::get_spacing () const { return d_ptr->m_spacing; } void Volume_header::set_direction_cosines (const float direction_cosines[9]) { d_ptr->m_direction_cosines.set (direction_cosines); } void Volume_header::set_direction_cosines (const Direction_cosines& dc) { d_ptr->m_direction_cosines.set (dc); } void Volume_header::set_direction_cosines_identity () { d_ptr->m_direction_cosines.set_identity (); } Direction_cosines& Volume_header::get_direction_cosines () { return d_ptr->m_direction_cosines; } const Direction_cosines& Volume_header::get_direction_cosines () const { return d_ptr->m_direction_cosines; } void Volume_header::set ( const plm_long dim[3], const float origin[3], const float spacing[3], const float direction_cosines[9]) { this->set_dim (dim); this->set_origin (origin); this->set_spacing (spacing); this->set_direction_cosines (direction_cosines); } void Volume_header::set ( const plm_long dim[3], const float origin[3], const float spacing[3], const Direction_cosines& dc) { this->set_dim (dim); this->set_origin (origin); this->set_spacing (spacing); this->set_direction_cosines (dc); } void Volume_header::set_from_bxf (Bspline_xform *bxf) { this->set ( bxf->img_dim, bxf->img_origin, bxf->img_spacing, 0); } void Volume_header::clone (Volume_header *dest, Volume_header *src) { dest->set (src->get_dim(), src->get_origin(), src->get_spacing(), src->get_direction_cosines()); } void Volume_header::clone (const Volume_header *src) { this->set (src->get_dim(), src->get_origin(), src->get_spacing(), src->get_direction_cosines()); } void Volume_header::get_image_center (float center[3]) { int d; /* GCS FIX: Direction cosines */ for (d = 0; d < 3; d++) { center[d] = d_ptr->m_origin[d] + d_ptr->m_spacing[d] * (d_ptr->m_dim[d] - 1) / 2; } } void Volume_header::print (void) const { printf ("Dim ="); for (unsigned int d = 0; d < 3; d++) { printf (" %ld", (long) d_ptr->m_dim[d]); } printf ("\nOrigin ="); for (unsigned int d = 0; d < 3; d++) { printf (" %g", d_ptr->m_origin[d]); } printf ("\nSpacing ="); for (unsigned int d = 0; d < 3; d++) { printf (" %g", d_ptr->m_spacing[d]); } printf ("\nDirection ="); for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { printf (" %g", d_ptr->m_direction_cosines[d1*3+d2]); } } printf ("\n"); } /* Return 1 if the two headers are the same */ int Volume_header::compare (Volume_header *pli1, Volume_header *pli2) { int d; for (d = 0; d < 3; d++) { if (pli1->get_dim()[d] != pli2->get_dim()[d]) return 0; if (pli1->get_origin()[d] != pli2->get_origin()[d]) return 0; if (pli1->get_spacing()[d] != pli2->get_spacing()[d]) return 0; } for (d = 0; d < 9; d++) { if (pli1->get_direction_cosines()[d] != pli2->get_direction_cosines()[d]) { return 0; } } return 1; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_header.h000066400000000000000000000041751321604176500305300ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_header_h_ #define _volume_header_h_ #include "plmbase_config.h" #include "direction_cosines.h" #include "plm_image.h" #include "volume.h" class Bspline_xform; class Plm_image_header; class Volume; class Volume_header_private; class PLMBASE_API Volume_header { public: Volume_header_private *d_ptr; public: Volume_header (); Volume_header (plm_long dim[3], float origin[3], float spacing[3]); Volume_header (plm_long dim[3], float origin[3], float spacing[3], float direction_cosines[9]); Volume_header (const Volume::Pointer& vol); Volume_header (const Plm_image_header *pih); Volume_header (const Plm_image::Pointer& img); ~Volume_header (); public: void set_dim (const plm_long dim[3]); plm_long* get_dim (); const plm_long* get_dim () const; void set_origin (const float origin[3]); float* get_origin (); const float* get_origin () const; void set_spacing (const float spacing[3]); float* get_spacing (); const float* get_spacing () const; void set_direction_cosines (const float direction_cosines[9]); void set_direction_cosines (const Direction_cosines& dc); void set_direction_cosines_identity (); Direction_cosines& get_direction_cosines (); const Direction_cosines& get_direction_cosines () const; void set (const plm_long dim[3], const float origin[3], const float spacing[3], const float dc[9]); void set (const plm_long dim[3], const float origin[3], const float spacing[3], const Direction_cosines& dc); void set_from_bxf (Bspline_xform *bxf); public: void clone (const Volume_header *src); static void clone (Volume_header *dest, Volume_header *src); public: void get_image_center (float center[3]); void print (void) const; public: /* Return 1 if the two headers are the same */ static int compare (Volume_header *pli1, Volume_header *pli2); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_limit.cxx000066400000000000000000000175351321604176500307750ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include "logfile.h" #include "plm_math.h" #include "ray_trace.h" #include "volume.h" #include "volume_limit.h" // TODO: All the #defines in base/ray_trace.h need to // be rethought/goaway. static Point_location test_boundary (Volume_limit* vol_limit, int d, double x) { if (x < vol_limit->lower_limit[d]) { return POINTLOC_LEFT; } else if (x > vol_limit->upper_limit[d]) { return POINTLOC_RIGHT; } else { return POINTLOC_INSIDE; } } /* Return 1 if ray intersects volume */ int volume_limit_clip_ray ( Volume_limit *vol_limit, /* INPUT: The bounding box to clip to */ double *ip1, /* OUTPUT: Intersection point 1 */ double *ip2, /* OUTPUT: Intersection point 2 */ const double *p1, /* INPUT: Starting point of ray */ const double *ray /* INPUT: Direction of ray */ ) { Point_location ploc[3]; double p2[3]; double alpha[3][2]; double alpha_in, alpha_out; int d; /* Make a second point in direction of ray */ vec3_add3 (p2, p1, ray); /* Compute point location */ for (d = 0; d < 3; d++) { ploc[d] = test_boundary (vol_limit, d, p1[d]); } /* Compute alphas */ for (d = 0; d < 3; d++) { /* If ray is parallel to grid, location must be inside */ if (fabs(ray[d]) < DRR_LEN_TOLERANCE) { if (ploc[d] != POINTLOC_INSIDE) { return 0; } alpha[d][0] = - DBL_MAX; alpha[d][1] = + DBL_MAX; continue; } /* General configuration */ alpha[d][0] = (vol_limit->lower_limit[d] - p1[d]) / ray[d]; alpha[d][1] = (vol_limit->upper_limit[d] - p1[d]) / ray[d]; /* Sort alpha */ if (alpha[d][0] > alpha[d][1]) { double temp = alpha[d][1]; alpha[d][1] = alpha[d][0]; alpha[d][0] = temp; } } /* Check if alpha values overlap in all three dimensions. alpha_in is the minimum alpha, where the ray enters the volume. alpha_out is where it exits the volume. */ alpha_in = alpha[0][0]; alpha_out = alpha[0][1]; for (d = 1; d < 3; d++) { if (alpha_in < alpha[d][0]) alpha_in = alpha[d][0]; if (alpha_out > alpha[d][1]) alpha_out = alpha[d][1]; } #if defined (DRR_VERBOSE) printf ("alpha[*][0] = %g %g %g\n", alpha[0][0], alpha[1][0], alpha[2][0]); printf ("alpha[*][1] = %g %g %g\n", alpha[0][1], alpha[1][1], alpha[2][1]); printf ("alpha in/out = %g %g\n", alpha_in, alpha_out); #endif /* If exit is before entrance, the segment does not intersect the volume */ if (alpha_out - alpha_in < DRR_LEN_TOLERANCE) { return 0; } /* Compute the volume intersection points */ for (d = 0; d < 3; d++) { ip1[d] = p1[d] + alpha_in * ray[d]; ip2[d] = p1[d] + alpha_out * ray[d]; } return 1; } /* Return 1 if line segment intersects volume */ int volume_limit_clip_segment ( Volume_limit *vol_limit, /* INPUT: The bounding box to clip to */ double *ip1, /* OUTPUT: Intersection point 1 */ double *ip2, /* OUTPUT: Intersection point 2 */ double *p1, /* INPUT: Line segment point 1 */ double *p2 /* INPUT: Line segment point 2 */ ) { Point_location ploc[3][2]; double ray[3]; double alpha_lo[3], alpha_hi[3]; double alpha_in, alpha_out; int d; /* Compute the ray */ vec3_sub3 (ray, p2, p1); for (d = 0; d < 3; d++) { ploc[d][0] = test_boundary (vol_limit, d, p1[d]); ploc[d][1] = test_boundary (vol_limit, d, p2[d]); /* Immediately reject segments which don't intersect the volume in this dimension */ if (ploc[d][0] == POINTLOC_LEFT && ploc[d][1] == POINTLOC_LEFT) { return 0; } if (ploc[d][0] == POINTLOC_RIGHT && ploc[d][1] == POINTLOC_RIGHT) { return 0; } } /* If we made it here, all three dimensions have some range of alpha where they intersects the volume. However, these alphas might not overlap. We compute the alphas, then test overlapping alphas to find the segment range within the volume. */ for (d = 0; d < 3; d++) { /* If ray is parallel to grid, location must be inside */ if (fabs(ray[d]) < DRR_LEN_TOLERANCE) { if (ploc[d][0] != POINTLOC_INSIDE) { return 0; } alpha_lo[d] = - DBL_MAX; alpha_hi[d] = + DBL_MAX; continue; } alpha_lo[d] = (vol_limit->lower_limit[d] - p1[d]) / ray[d]; alpha_hi[d] = (vol_limit->upper_limit[d] - p1[d]) / ray[d]; /* Sort alphas */ if (alpha_hi[d] < alpha_lo[d]) { double tmp = alpha_hi[d]; alpha_hi[d] = alpha_lo[d]; alpha_lo[d] = tmp; } /* Clip alphas to segment */ if (alpha_lo[d] < 0.0) alpha_lo[d] = 0.0; if (alpha_lo[d] > 1.0) alpha_lo[d] = 1.0; if (alpha_hi[d] < 0.0) alpha_hi[d] = 0.0; if (alpha_hi[d] > 1.0) alpha_hi[d] = 1.0; } /* alpha_in is the alpha where the segment enters the boundary, and alpha_out is where it exits the boundary. */ alpha_in = alpha_lo[0]; alpha_out = alpha_hi[0]; for (d = 1; d < 3; d++) { if (alpha_in < alpha_lo[d]) alpha_in = alpha_lo[d]; if (alpha_out > alpha_hi[d]) alpha_out = alpha_hi[d]; } #if defined (DRR_VERBOSE) printf ("p1 = %g %g %g\n", p1[0], p1[1], p1[2]); printf ("p2 = %g %g %g\n", p2[0], p2[1], p2[2]); printf ("ray = %g %g %g\n", ray[0], ray[1], ray[2]); printf ("lower_lim = %g %g %g\n", vol_limit->lower_limit[0], vol_limit->lower_limit[1], vol_limit->lower_limit[2]); printf ("upper_lim = %g %g %g\n", vol_limit->upper_limit[0], vol_limit->upper_limit[1], vol_limit->upper_limit[2]); printf ("alpha_lo = %g %g %g\n", alpha_lo[0], alpha_lo[1], alpha_lo[2]); printf ("alpha_hi = %g %g %g\n", alpha_hi[0], alpha_hi[1], alpha_hi[2]); printf ("alpha in/out = %g %g\n", alpha_in, alpha_out); #endif /* If exit is before entrance, the segment does not intersect the volume */ if (alpha_out - alpha_in < DRR_LEN_TOLERANCE) { return 0; } /* Create the volume intersection points */ for (d = 0; d < 3; d++) { ip1[d] = p1[d] + alpha_in * ray[d]; ip2[d] = p1[d] + alpha_out * ray[d]; } return 1; } void volume_limit_set (Volume_limit *vol_limit, const Volume *vol) { int d; /* Compute volume boundary box */ for (d = 0; d < 3; d++) { vol_limit->lower_limit[d] = vol->origin[d] - 0.5 * vol->spacing[d]; vol_limit->upper_limit[d] = vol_limit->lower_limit[d] + vol->dim[d] * vol->spacing[d]; if (vol_limit->lower_limit[d] <= vol_limit->upper_limit[d]) { vol_limit->dir[d] = 1; } else { double tmp; vol_limit->dir[d] = -1; /* Swap limits */ tmp = vol_limit->lower_limit[d]; vol_limit->lower_limit[d] = vol_limit->upper_limit[d]; vol_limit->upper_limit[d] = tmp; } vol_limit->lower_limit[d] += DRR_BOUNDARY_TOLERANCE; vol_limit->upper_limit[d] -= DRR_BOUNDARY_TOLERANCE; } } void volume_limit_set (Volume_limit *vol_limit, const Volume::Pointer& vol) { volume_limit_set (vol_limit, vol.get()); } void Volume_limit::print () { lprintf ("Volume_limit:\n%g %g / %g %g / %g %g\n", lower_limit[0], upper_limit[0], lower_limit[1], upper_limit[1], lower_limit[2], upper_limit[2]); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_limit.h000066400000000000000000000032451321604176500304130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_limit_h_ #define _volume_limit_h_ #include "plmbase_config.h" enum point_location { POINTLOC_LEFT, POINTLOC_INSIDE, POINTLOC_RIGHT, }; typedef enum point_location Point_location; class Volume_limit { public: /* upper and lower limits of volume, including tolerances */ double lower_limit[3]; double upper_limit[3]; /* dir == 0 if lower_limit corresponds to lower index */ int dir[3]; public: void print (); }; PLMBASE_C_API int volume_limit_clip_ray ( Volume_limit *vol_limit, /* INPUT: The bounding box to clip to */ double *ip1, /* OUTPUT: Intersection point 1 */ double *ip2, /* OUTPUT: Intersection point 2 */ const double *p1, /* INPUT: Starting point of ray */ const double *ray /* INPUT: Direction of ray */ ); PLMBASE_C_API int volume_limit_clip_segment ( Volume_limit *vol_limit, /* INPUT: The bounding box to clip to */ double *ip1, /* OUTPUT: Intersection point 1 */ double *ip2, /* OUTPUT: Intersection point 2 */ double *p1, /* INPUT: Line segment point 1 */ double *p2 /* INPUT: Line segment point 2 */ ); PLMBASE_API void volume_limit_set (Volume_limit *vol_limit, const Volume *vol); PLMBASE_API void volume_limit_set (Volume_limit *vol_limit, const Volume::Pointer& volume); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_macros.h000066400000000000000000000121341321604176500305560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_macros_h_ #define _volume_macros_h_ #include "plmbase_config.h" #include "plm_int.h" /* ----------------------------------------------------------------------- Macros ----------------------------------------------------------------------- */ static inline plm_long volume_index (const plm_long dims[3], plm_long i, plm_long j, plm_long k) { return i + (dims[0] * (j + dims[1] * k)); } static inline plm_long volume_index (const plm_long dims[3], const plm_long ijk[3]) { return ijk[0] + (dims[0] * (ijk[1] + dims[1] * ijk[2])); } static inline bool index_in_volume (const plm_long dims[3], const plm_long ijk[3]) { return ijk[0] >= 0 && ijk[0] < dims[0] && ijk[1] >= 0 && ijk[1] < dims[1] && ijk[2] >= 0 && ijk[2] < dims[2]; } #define COORDS_FROM_INDEX(ijk, idx, dim) \ ijk[2] = idx / (dim[0] * dim[1]); \ ijk[1] = (idx - (ijk[2] * dim[0] * dim[1])) / dim[0]; \ ijk[0] = idx - ijk[2] * dim[0] * dim[1] - (ijk[1] * dim[0]); #define LOOP_Z(ijk,fxyz,vol) \ for ( \ ijk[2] = 0, \ fxyz[2] = vol->origin[2]; \ ijk[2] < vol->dim[2]; \ ++ijk[2], \ fxyz[2] = vol->origin[2] + ijk[2]*vol->step[2*3+2] \ ) #define LOOP_Z_OMP(k,vol) \ for ( \ long k = 0; \ k < vol->dim[2]; \ ++k \ ) #define LOOP_Y(ijk,fxyz,vol) \ for ( \ ijk[1] = 0, \ fxyz[1] = vol->origin[1] + ijk[2]*vol->step[1*3+2]; \ ijk[1] < vol->dim[1]; \ ++ijk[1], \ fxyz[2] = vol->origin[2] + ijk[2]*vol->step[2*3+2] \ + ijk[1]*vol->step[2*3+1], \ fxyz[1] = vol->origin[1] + ijk[2]*vol->step[1*3+2] \ + ijk[1]*vol->step[1*3+1] \ ) #define LOOP_X(ijk,fxyz,vol) \ for ( \ ijk[0] = 0, \ fxyz[0] = vol->origin[0] + ijk[2]*vol->step[0*3+2] \ + ijk[1]*vol->step[0*3+1]; \ ijk[0] < vol->dim[0]; \ ++ijk[0], \ fxyz[0] += vol->step[0*3+0], \ fxyz[1] += vol->step[1*3+0], \ fxyz[2] += vol->step[2*3+0] \ ) #define PROJECT_Z(xyz,proj) \ (xyz[0] * proj[2*3+0] + xyz[1] * proj[2*3+1] + xyz[2] * proj[2*3+2]) #define PROJECT_Y(xyz,proj) \ (xyz[0] * proj[1*3+0] + xyz[1] * proj[1*3+1] + xyz[2] * proj[1*3+2]) #define PROJECT_X(xyz,proj) \ (xyz[0] * proj[0*3+0] + xyz[1] * proj[0*3+1] + xyz[2] * proj[0*3+2]) #define POSITION_FROM_COORDS(xyz, ijk, origin, step) \ do { \ xyz[0] = origin[0] \ + ijk[0]*step[3*0+0] \ + ijk[1]*step[3*0+1] \ + ijk[2]*step[3*0+2]; \ xyz[1] = origin[1] \ + ijk[0]*step[3*1+0] \ + ijk[1]*step[3*1+1] \ + ijk[2]*step[3*1+2]; \ xyz[2] = origin[2] \ + ijk[0]*step[3*2+0] \ + ijk[1]*step[3*2+1] \ + ijk[2]*step[3*2+2]; \ } while (0); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_resample.cxx000066400000000000000000000323731321604176500314640ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- The "legacy methods" resample trying to keep the total subtended volume the same. The "new methods" try to keep the origin in the same location. ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "interpolate.h" #include "interpolate_macros.h" #include "plm_int.h" #include "plm_math.h" #include "print_and_exit.h" #include "volume.h" #include "volume_header.h" #include "volume_resample.h" /* Nearest neighbor interpolation */ /* GCS FIX: doesn't respect direction cosines */ static Volume::Pointer volume_resample_float_nn ( const Volume::Pointer& vol_in, const plm_long* dim, const float* origin, const float* spacing) { plm_long i, j, k, v; float x, y, z; float x_in, y_in, z_in; plm_long ijk[3]; Volume::Pointer vol_out; float *in_img, *out_img; float val; float default_val = 0.0f; vol_out = Volume::New( dim, origin, spacing, vol_in->direction_cosines, PT_FLOAT, 1); in_img = (float*) vol_in->img; out_img = (float*) vol_out->img; for (k = 0, v = 0, z = origin[2]; k < dim[2]; k++, z += spacing[2]) { z_in = (z - vol_in->origin[2]) / vol_in->spacing[2]; ijk[2] = ROUND_INT (z_in); for (j = 0, y = origin[1]; j < dim[1]; j++, y += spacing[1]) { y_in = (y - vol_in->origin[1]) / vol_in->spacing[1]; ijk[1] = ROUND_INT (y_in); for (i = 0, x = origin[0]; i < dim[0]; i++, x += spacing[0], v++) { x_in = (x - vol_in->origin[0]) / vol_in->spacing[0]; ijk[0] = ROUND_INT (x_in); if (index_in_volume (vol_in->dim, ijk)) { plm_long idx = volume_index (vol_in->dim, ijk); val = in_img[idx]; } else { val = default_val; } out_img[v] = val; } } } return vol_out; } /* Linear interpolation */ static Volume::Pointer volume_resample_float_li ( const Volume::Pointer& vol_in, const plm_long* dim, const float* origin, const float* spacing) { plm_long i, j, k, v; float x, y, z; //float x_in, y_in, z_in; plm_long xidx, yidx, zidx; Volume::Pointer vol_out; float *in_img, *out_img; float val; float default_val = 0.0f; float ijk[3]; vol_out = Volume::New ( dim, origin, spacing, vol_in->direction_cosines, PT_FLOAT, 1); in_img = (float*) vol_in->img; out_img = (float*) vol_out->img; for (k = 0, v = 0, z = origin[2]; k < dim[2]; k++, z += spacing[2]) { ijk[2] = (z - vol_in->origin[2]) / vol_in->spacing[2]; zidx = ROUND_INT (ijk[2]); for (j = 0, y = origin[1]; j < dim[1]; j++, y += spacing[1]) { ijk[1] = (y - vol_in->origin[1]) / vol_in->spacing[1]; yidx = ROUND_INT (ijk[1]); for (i = 0, x = origin[0]; i < dim[0]; i++, x += spacing[0], v++) { ijk[0] = (x - vol_in->origin[0]) / vol_in->spacing[0]; xidx = ROUND_INT (ijk[0]); if (zidx < 0 || zidx >= vol_in->dim[2] || yidx < 0 || yidx >= vol_in->dim[1] || xidx < 0 || xidx >= vol_in->dim[0]) { val = default_val; } else { plm_long ijk_floor[3]; plm_long ijk_round[3]; float li_1[3], li_2[3]; plm_long idx_floor; // Compute linear interpolation fractions li_clamp_3d (ijk, ijk_floor, ijk_round, li_1, li_2, vol_in.get()); // Find linear indices for moving image idx_floor = volume_index (vol_in->dim, ijk_floor); // Calc. moving voxel intensity via linear interpolation LI_VALUE ( val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], idx_floor, in_img, vol_in ); } out_img[v] = val; } } } return vol_out; } /* Nearest neighbor interpolation */ static Volume::Pointer volume_resample_vf_float_interleaved ( const Volume::Pointer& vol_in, const plm_long* dim, const float* origin, const float* spacing) { plm_long d, i, j, k, v; float x, y, z; float x_in, y_in, z_in; plm_long xidx, yidx, zidx; Volume::Pointer vol_out; float *in_img, *out_img; float* val; float default_val[3] = { 0.0f, 0.0f, 0.0f }; vol_out = Volume::New (dim, origin, spacing, vol_in->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); in_img = (float*) vol_in->img; out_img = (float*) vol_out->img; for (k = 0, v = 0, z = origin[2]; k < dim[2]; k++, z += spacing[2]) { z_in = (z - vol_in->origin[2]) / vol_in->spacing[2]; zidx = ROUND_INT (z_in); for (j = 0, y = origin[1]; j < dim[1]; j++, y += spacing[1]) { y_in = (y - vol_in->origin[1]) / vol_in->spacing[1]; yidx = ROUND_INT (y_in); for (i = 0, x = origin[0]; i < dim[0]; i++, x += spacing[0]) { x_in = (x - vol_in->origin[0]) / vol_in->spacing[0]; xidx = ROUND_INT (x_in); if (zidx < 0 || zidx >= vol_in->dim[2] || yidx < 0 || yidx >= vol_in->dim[1] || xidx < 0 || xidx >= vol_in->dim[0]) { val = default_val; } else { plm_long idx = zidx*vol_in->dim[1]*vol_in->dim[0] + yidx*vol_in->dim[0] + xidx; val = &in_img[idx*3]; } for (d = 0; d < 3; d++, v++) { out_img[v] = val[d]; } } } } return vol_out; } /* Nearest neighbor interpolation */ static Volume::Pointer volume_resample_vf_float_planar ( const Volume::Pointer& vol_in, const plm_long* dim, const float* origin, const float* spacing) { plm_long d, i, j, k, v; float x, y, z; float x_in, y_in, z_in; plm_long xidx, yidx, zidx; Volume::Pointer vol_out; float **in_img, **out_img; vol_out = Volume::New (dim, origin, spacing, vol_in->direction_cosines, PT_VF_FLOAT_PLANAR, 3); in_img = (float**) vol_in->img; out_img = (float**) vol_out->img; for (k = 0, v = 0, z = origin[2]; k < dim[2]; k++, z += spacing[2]) { z_in = (z - vol_in->origin[2]) / vol_in->spacing[2]; zidx = ROUND_INT (z_in); for (j = 0, y = origin[1]; j < dim[1]; j++, y += spacing[1]) { y_in = (y - vol_in->origin[1]) / vol_in->spacing[1]; yidx = ROUND_INT (y_in); for (i = 0, x = origin[0]; i < dim[0]; i++, x += spacing[0], v++) { x_in = (x - vol_in->origin[0]) / vol_in->spacing[0]; xidx = ROUND_INT (x_in); if (zidx < 0 || zidx >= vol_in->dim[2] || yidx < 0 || yidx >= vol_in->dim[1] || xidx < 0 || xidx >= vol_in->dim[0]) { for (d = 0; d < 3; d++) { out_img[d][v] = 0.0; /* Default value */ } } else { for (d = 0; d < 3; d++) { plm_long idx = zidx*vol_in->dim[1]*vol_in->dim[0] + yidx*vol_in->dim[0] + xidx; out_img[d][v] = in_img[d][idx]; } } } } } return vol_out; } Volume::Pointer volume_resample ( const Volume::Pointer& vol_in, const plm_long* dim, const float* origin, const float* spacing) { Volume::Pointer error_volume = Volume::New(); switch (vol_in->pix_type) { case PT_UCHAR: case PT_SHORT: case PT_UINT32: fprintf (stderr, "Error, resampling PT_SHORT, PT_UCHAR, PT_UINT32 is unsupported\n"); return error_volume; case PT_FLOAT: return volume_resample_float_li (vol_in, dim, origin, spacing); case PT_VF_FLOAT_INTERLEAVED: return volume_resample_vf_float_interleaved (vol_in, dim, origin, spacing); case PT_VF_FLOAT_PLANAR: return volume_resample_vf_float_planar (vol_in, dim, origin, spacing); case PT_UCHAR_VEC_INTERLEAVED: fprintf (stderr, "Error, resampling PT_UCHAR_VEC_INTERLEAVED is unsupported\n"); return error_volume; default: print_and_exit ("Error, unknown pix_type: %d\n", vol_in->pix_type); return error_volume; } } Volume::Pointer volume_resample (const Volume::Pointer& vol_in, const Volume_header *vh) { /* GCS FIX: direction cosines */ return volume_resample (vol_in, vh->get_dim(), vh->get_origin(), vh->get_spacing()); } Volume::Pointer volume_resample_nn ( const Volume::Pointer& vol_in, const plm_long* dim, const float* origin, const float* spacing) { Volume::Pointer error_volume = Volume::New(); switch (vol_in->pix_type) { case PT_UCHAR: { Volume::Pointer rvol = vol_in->clone (PT_FLOAT); rvol = volume_resample_float_nn (rvol, dim, origin, spacing); rvol->convert (PT_UCHAR); return rvol; } case PT_SHORT: case PT_UINT32: fprintf (stderr, "Error, resampling PT_SHORT and PT_UINT32 is unsupported\n"); return error_volume; case PT_FLOAT: return volume_resample_float_nn (vol_in, dim, origin, spacing); case PT_VF_FLOAT_INTERLEAVED: return volume_resample_vf_float_interleaved (vol_in, dim, origin, spacing); case PT_VF_FLOAT_PLANAR: return volume_resample_vf_float_planar (vol_in, dim, origin, spacing); case PT_UCHAR_VEC_INTERLEAVED: fprintf (stderr, "Error, resampling PT_UCHAR_VEC_INTERLEAVED is unsupported\n"); return error_volume; default: fprintf (stderr, "Error, unknown pix_type: %d\n", vol_in->pix_type); return error_volume; } } Volume::Pointer volume_subsample_vox ( const Volume::Pointer& vol_in, const float* sampling_rate) { int d; plm_long dim[3]; float origin[3]; float spacing[3]; for (d = 0; d < 3; d++) { plm_long int_rate = ROUND_PLM_LONG (sampling_rate[d]); dim[d] = (vol_in->dim[d] + int_rate - 1) / int_rate; origin[d] = vol_in->origin[d]; spacing[d] = vol_in->spacing[d] * int_rate; } return volume_resample (vol_in, dim, origin, spacing); } Volume::Pointer volume_subsample_vox_nn ( const Volume::Pointer& vol_in, const float* sampling_rate) { int d; plm_long dim[3]; float origin[3]; float spacing[3]; for (d = 0; d < 3; d++) { plm_long int_rate = ROUND_PLM_LONG (sampling_rate[d]); dim[d] = (vol_in->dim[d] + int_rate - 1) / int_rate; origin[d] = vol_in->origin[d]; spacing[d] = vol_in->spacing[d] * int_rate; } return volume_resample_nn (vol_in, dim, origin, spacing); } Volume::Pointer volume_subsample_vox_legacy ( const Volume::Pointer& vol_in, const float* sampling_rate) { int d; plm_long dim[3]; float origin[3]; float spacing[3]; for (d = 0; d < 3; d++) { float in_size = vol_in->dim[d] * vol_in->spacing[d]; dim[d] = vol_in->dim[d] / (plm_long) sampling_rate[d]; if (dim[d] < 1) dim[d] = 1; spacing[d] = in_size / dim[d]; origin[d] = (float) (vol_in->origin[d] - 0.5 * vol_in->spacing[d] + 0.5 * spacing[d]); } return volume_resample (vol_in, dim, origin, spacing); } Volume::Pointer volume_subsample_vox_legacy_nn ( const Volume::Pointer& vol_in, const float* sampling_rate) { int d; plm_long dim[3]; float origin[3]; float spacing[3]; for (d = 0; d < 3; d++) { float in_size = vol_in->dim[d] * vol_in->spacing[d]; dim[d] = vol_in->dim[d] / (plm_long) sampling_rate[d]; if (dim[d] < 1) dim[d] = 1; spacing[d] = in_size / dim[d]; origin[d] = (float) (vol_in->origin[d] - 0.5 * vol_in->spacing[d] + 0.5 * spacing[d]); } return volume_resample_nn (vol_in, dim, origin, spacing); } Volume::Pointer volume_resample_spacing ( const Volume::Pointer& vol_in, const float spacing[3]) { plm_long dim[3]; for (int d = 0; d < 3; d++) { float in_size = (vol_in->dim[d] - 1) * vol_in->spacing[d]; dim[d] = 1 + ROUND_PLM_LONG (in_size / spacing[d]); } return volume_resample (vol_in, dim, vol_in->origin, spacing); } Volume::Pointer volume_resample_percent ( const Volume::Pointer& vol_in, const float percent[3]) { plm_long dim[3]; float spacing[3]; for (int d = 0; d < 3; d++) { float in_size = (vol_in->dim[d] - 1) * vol_in->spacing[d]; dim[d] = 1 + ROUND_PLM_LONG (percent[d] * (vol_in->dim[d] - 1)); if (dim[d] == 1) { spacing[d] = in_size; } else { spacing[d] = in_size / (dim[d] - 1); } } return volume_resample (vol_in, dim, vol_in->origin, spacing); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_resample.h000066400000000000000000000026641321604176500311110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_resample_h_ #define _volume_resample_h_ #include "plmbase_config.h" PLMBASE_API Volume::Pointer volume_resample ( const Volume::Pointer& vol_in, const plm_long* dim, const float* offset, const float* spacing ); PLMBASE_API Volume::Pointer volume_resample ( const Volume::Pointer& vol_in, const Volume_header *vh); PLMBASE_API Volume::Pointer volume_resample_nn ( const Volume::Pointer& vol_in, const plm_long* dim, const float* offset, const float* spacing ); PLMBASE_API Volume::Pointer volume_subsample_vox ( const Volume::Pointer& vol_in, const float* sampling_rate); PLMBASE_API Volume::Pointer volume_subsample_vox_nn ( const Volume::Pointer& vol_in, const float* sampling_rate); PLMBASE_API Volume::Pointer volume_subsample_vox_legacy ( const Volume::Pointer& vol_in, const float* sampling_rate); PLMBASE_API Volume::Pointer volume_subsample_vox_legacy_nn ( const Volume::Pointer& vol_in, const float* sampling_rate); PLMBASE_API Volume::Pointer volume_resample_spacing ( const Volume::Pointer& vol_in, const float spacing[3]); PLMBASE_API Volume::Pointer volume_resample_percent ( const Volume::Pointer& vol_in, const float percent[3]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_stats.cxx000066400000000000000000000042221321604176500310020ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "print_and_exit.h" #include "volume.h" #include "volume_stats.h" /* ----------------------------------------------------------------------- Statistics like min, max, etc. ----------------------------------------------------------------------- */ template void volume_stats_template (const Volume *vol, double *min_val, double *max_val, double *avg, int *non_zero, int *num_vox) { int first = 1; double sum = 0.0; T *img = (T*) vol->img; *non_zero = 0; *num_vox = 0; for (plm_long i = 0; i < vol->npix; i++) { double v = (double) img[i]; if (first) { *min_val = *max_val = v; first = 0; } if (*min_val > v) *min_val = v; if (*max_val < v) *max_val = v; sum += v; (*num_vox) ++; if (v != 0.0) { (*non_zero) ++; } } *avg = sum / (*num_vox); } void volume_stats (const Volume *vol, double *min_val, double *max_val, double *avg, int *non_zero, int *num_vox) { switch (vol->pix_type) { case PT_UCHAR: volume_stats_template ( vol, min_val, max_val, avg, non_zero, num_vox); break; case PT_SHORT: volume_stats_template ( vol, min_val, max_val, avg, non_zero, num_vox); break; case PT_FLOAT: volume_stats_template ( vol, min_val, max_val, avg, non_zero, num_vox); break; case PT_UINT16: case PT_UINT32: case PT_INT32: case PT_VF_FLOAT_INTERLEAVED: case PT_VF_FLOAT_PLANAR: case PT_UCHAR_VEC_INTERLEAVED: default: /* Can't convert this */ print_and_exit ( "Sorry, unsupported type %d for volume_stats()\n", vol->pix_type); break; } } void volume_stats (const Volume::Pointer vol, double *min_val, double *max_val, double *avg, int *non_zero, int *num_vox) { const Volume *v = vol.get(); volume_stats (v, min_val, max_val, avg, non_zero, num_vox); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/volume_stats.h000066400000000000000000000014711321604176500304320ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_stats_h_ #define _volume_stats_h_ #include "plmbase_config.h" class Volume; /* ----------------------------------------------------------------------- Function prototypes ----------------------------------------------------------------------- */ PLMBASE_API void volume_stats ( const Volume *vol, double *min_val, double *max_val, double *avg, int *non_zero, int *num_vox ); PLMBASE_API void volume_stats ( const Volume::Pointer vol, double *min_val, double *max_val, double *avg, int *non_zero, int *num_vox ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xform.cxx000066400000000000000000001761251321604176500274240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "itkArray.h" #include "itkResampleImageFilter.h" #include "itkBSplineResampleImageFunction.h" #if ITK_VERSION_MAJOR > 3 #include "itkTransformFactory.h" #endif #include "itkTransformFileWriter.h" #include "itkTransformFileReader.h" #include "bspline_interpolate.h" #include "bspline_xform.h" #include "bspline_xform_legacy.h" #include "file_util.h" #include "itk_directions.h" #include "itk_image_create.h" #include "itk_image_load.h" #include "itk_image_save.h" #include "itk_resample.h" #include "logfile.h" #include "mha_io.h" #include "plm_image_header.h" #include "plm_math.h" #include "print_and_exit.h" #include "string_util.h" #include "volume.h" #include "volume_header.h" #include "volume_resample.h" #include "xform.h" #include "xform_legacy.h" static void itk_bsp_set_grid_img (Xform *xf, const Plm_image_header* pih, const float* grid_spac); static void load_gpuit_bsp (Xform *xf, const char* fn); static void itk_xform_load (Xform *xf, const char* fn); /* Xform_private is currently a stub... */ class Xform_private { public: Bspline_xform::Pointer m_bsp; Volume::Pointer m_vf; public: Xform_private () { m_bsp = Bspline_xform::New (); m_vf = Volume::New (); } }; Xform::Xform () { d_ptr = new Xform_private; clear (); } Xform::~Xform () { clear (); delete d_ptr; } Xform::Xform (const Xform& xf) { d_ptr = new Xform_private; *this = xf; } Xform& Xform::operator= (const Xform& xf) { d_ptr->m_bsp = xf.d_ptr->m_bsp; d_ptr->m_vf = xf.d_ptr->m_vf; m_type = xf.m_type; m_trn = xf.m_trn; m_vrs = xf.m_vrs; m_quat = xf.m_quat; m_similarity = xf.m_similarity; m_aff = xf.m_aff; m_itk_vf = xf.m_itk_vf; m_itk_bsp = xf.m_itk_bsp; m_itk_tps = xf.m_itk_tps; // m_gpuit = xf.m_gpuit; /* Shallow copy */ return *this; } void Xform::clear () { d_ptr->m_bsp.reset(); d_ptr->m_vf.reset(); m_type = XFORM_NONE; m_trn = 0; m_vrs = 0; m_quat = 0; m_aff = 0; m_similarity= 0; m_itk_bsp = 0; m_itk_tps = 0; m_itk_vf = 0; } /* ----------------------------------------------------------------------- Type casting ----------------------------------------------------------------------- */ TranslationTransformType::Pointer Xform::get_trn () const { if (m_type != XFORM_ITK_TRANSLATION) { print_and_exit ("Typecast error in get_trn()\n"); } return m_trn; } VersorTransformType::Pointer Xform::get_vrs () const { if (m_type != XFORM_ITK_VERSOR) { printf ("Got type = %d\n", m_type); print_and_exit ("Typecast error in get_vrs ()\n"); } return m_vrs; } QuaternionTransformType::Pointer Xform::get_quat () const { if (m_type != XFORM_ITK_QUATERNION) { print_and_exit ("Typecast error in get_quat()\n"); } return m_quat; } AffineTransformType::Pointer Xform::get_aff () const { if (m_type != XFORM_ITK_AFFINE) { print_and_exit ("Typecast error in get_aff()\n"); } return m_aff; } SimilarityTransformType::Pointer Xform::get_similarity() const { if (m_type != XFORM_ITK_SIMILARITY) { print_and_exit ("Typecast error in get_similarity()\n"); } return m_similarity; } BsplineTransformType::Pointer Xform::get_itk_bsp () const { if (m_type != XFORM_ITK_BSPLINE) { print_and_exit ("Typecast error in get_itk_bsp()\n"); } return m_itk_bsp; } TpsTransformType::Pointer Xform::get_itk_tps () const { if (m_type != XFORM_ITK_TPS) { print_and_exit ("Typecast error in get_tps()\n"); } return m_itk_tps; } DeformationFieldType::Pointer Xform::get_itk_vf () const { if (m_type != XFORM_ITK_VECTOR_FIELD) { print_and_exit ("Typecast error in get_itk_vf()\n"); } return m_itk_vf; } Bspline_xform* Xform::get_gpuit_bsp () const { if (m_type != XFORM_GPUIT_BSPLINE) { print_and_exit ("Typecast error in get_gpuit_bsp()\n"); } return d_ptr->m_bsp.get(); } Volume::Pointer& Xform::get_gpuit_vf () const { if (m_type != XFORM_GPUIT_VECTOR_FIELD) { print_and_exit ("Typecast error in get_gpuit_vf()\n"); } return d_ptr->m_vf; } void Xform::set_trn (TranslationTransformType::Pointer trn) { clear (); m_type = XFORM_ITK_TRANSLATION; m_trn = trn; } void Xform::set_trn (const itk::Array& trn) { typedef TranslationTransformType XfType; XfType::Pointer transform = XfType::New (); transform->SetParametersByValue (trn); this->set_trn (transform); } void Xform::set_vrs (VersorTransformType::Pointer vrs) { clear (); m_type = XFORM_ITK_VERSOR; m_vrs = vrs; } void Xform::set_vrs (const itk::Array& vrs) { typedef VersorTransformType XfType; XfType::Pointer transform = XfType::New (); transform->SetParametersByValue (vrs); this->set_vrs (transform); } void Xform::set_quat (QuaternionTransformType::Pointer quat) { clear (); m_type = XFORM_ITK_QUATERNION; m_quat = quat; } void Xform::set_quat (const itk::Array& quat) { typedef QuaternionTransformType XfType; XfType::Pointer transform = XfType::New (); transform->SetParametersByValue (quat); this->set_quat (transform); } void Xform::set_aff (AffineTransformType::Pointer aff) { clear (); m_type = XFORM_ITK_AFFINE; m_aff = aff; } void Xform::set_aff (const itk::Array& aff) { typedef AffineTransformType XfType; XfType::Pointer transform = XfType::New (); transform->SetParametersByValue (aff); this->set_aff (transform); } void Xform::set_similarity(SimilarityTransformType::Pointer sim) { clear (); m_type = XFORM_ITK_SIMILARITY; m_similarity = sim; } void Xform::set_similarity (const itk::Array& sim) { typedef SimilarityTransformType XfType; XfType::Pointer transform = XfType::New (); transform->SetParametersByValue (sim); this->set_similarity (transform); } void Xform::set_itk_bsp (BsplineTransformType::Pointer bsp) { /* Do not clear */ m_type = XFORM_ITK_BSPLINE; m_itk_bsp = bsp; } void Xform::set_itk_tps (TpsTransformType::Pointer tps) { clear (); m_type = XFORM_ITK_TPS; m_itk_tps = tps; } void Xform::set_itk_vf (DeformationFieldType::Pointer vf) { clear (); m_type = XFORM_ITK_VECTOR_FIELD; m_itk_vf = vf; } void Xform::set_gpuit_bsp (Bspline_xform* xgb) { clear (); m_type = XFORM_GPUIT_BSPLINE; //m_gpuit = (void*) xgb; d_ptr->m_bsp.reset (xgb); } void Xform::set_gpuit_vf (const Volume::Pointer& vf) { clear (); m_type = XFORM_GPUIT_VECTOR_FIELD; //m_gpuit = (void*) vf; //d_ptr->m_vf.reset (vf); d_ptr->m_vf = vf; } /* ----------------------------------------------------------------------- Load/save functions ----------------------------------------------------------------------- */ void Xform::load (const char* fn) { char buf[1024]; FILE* fp; fp = fopen (fn, "r"); if (!fp) { print_and_exit ("Error: xf_in file %s not found\n", fn); } if (!fgets(buf,1024,fp)) { print_and_exit ("Error reading from xf_in file.\n"); } if (plm_strcmp (buf, "#Insight Transform File V1.0") == 0) { fclose(fp); itk_xform_load (this, fn); } else if (plm_strcmp (buf,"ObjectType = MGH_XFORM") == 0) { xform_legacy_load (this, fp); fclose(fp); } else if (plm_strcmp(buf,"MGH_GPUIT_BSP ")==0) { fclose (fp); load_gpuit_bsp (this, fn); } else { /* Close the file and try again, it is probably a vector field */ fclose (fp); DeformationFieldType::Pointer vf = DeformationFieldType::New(); vf = itk_image_load_float_field (fn); if (!vf) { print_and_exit ("Unexpected file format for xf_in file.\n"); } this->set_itk_vf (vf); } } void Xform::load (const std::string& fn) { this->load (fn.c_str()); } void xform_load (Xform *xf, const char* fn) { xf->load (fn); } void xform_load (Xform *xf, const std::string& fn) { xf->load (fn); } Xform::Pointer xform_load (const char* fn) { Xform::Pointer xf = Xform::New (); xf->load (fn); return xf; } Xform::Pointer xform_load (const std::string& fn) { return xform_load (fn.c_str()); } static void load_gpuit_bsp (Xform *xf, const char* fn) { Bspline_xform* bxf; #if PLM_CONFIG_LEGACY_BSPLINE_XFORM_IO bxf = bspline_xform_legacy_load ((char*)fn); #else bxf = bspline_xform_load ((char*)fn); #endif if (!bxf) { print_and_exit ("Error loading bxf format file: %s\n", fn); } /* Tell Xform that it is gpuit_bsp */ xf->set_gpuit_bsp (bxf); } template< class T > static void itk_xform_save (T transform, const char *filename) { typedef itk::TransformFileWriter TransformWriterType; TransformWriterType::Pointer outputTransformWriter; make_parent_directories (filename); outputTransformWriter = TransformWriterType::New(); outputTransformWriter->SetFileName(filename); outputTransformWriter->SetInput(transform); try { outputTransformWriter->Update(); } catch (itk::ExceptionObject &err) { std::cerr << err << std::endl; print_and_exit ("Error writing file: %s\n", filename); } } static void itk_xform_load (Xform *xf, const char* fn) { #if (ITK_VERSION_MAJOR > 3) itk::TransformFactory< itk::BSplineDeformableTransform< double, 3, 3 > >::RegisterTransform (); #endif /* Load from file to into reader */ itk::TransformFileReader::Pointer transfReader; transfReader = itk::TransformFileReader::New(); transfReader->SetFileName(fn); try { transfReader->Update(); } catch (itk::ExceptionObject& excp) { std::cerr << excp << std::endl; print_and_exit ("Error reading ITK transform file: %s\n", fn); } /* Confirm that there is only one xform in the file */ typedef itk::TransformFileReader::TransformListType* TransformListType; TransformListType transfList = transfReader->GetTransformList(); if (transfList->size() != 1) { print_and_exit ("Error. ITK transform file has multiple " "(%d) transforms: %s\n", transfList->size(), fn); } /* Deduce transform type, and copy into Xform structure */ itk::TransformFileReader::TransformListType::const_iterator itTrasf = transfList->begin(); if (!strcmp((*itTrasf)->GetNameOfClass(), "TranslationTransform")) { TranslationTransformType::Pointer itk_xf = TranslationTransformType::New(); itk_xf = static_cast( (*itTrasf).GetPointer()); xf->set_trn (itk_xf); } else if (!strcmp((*itTrasf)->GetNameOfClass(), "VersorRigid3DTransform")) { VersorTransformType::Pointer itk_xf = VersorTransformType::New(); VersorTransformType::InputPointType cor; cor.Fill(12); itk_xf->SetCenter(cor); itk_xf = static_cast( (*itTrasf).GetPointer()); xf->set_vrs (itk_xf); } else if (!strcmp((*itTrasf)->GetNameOfClass(), "QuaternionRigidTransform")) { QuaternionTransformType::Pointer quatTransf = QuaternionTransformType::New(); QuaternionTransformType::InputPointType cor; cor.Fill(12); quatTransf->SetCenter(cor); quatTransf = static_cast( (*itTrasf).GetPointer()); //quatTransf->Print(std::cout); xf->set_quat (quatTransf); } else if (!strcmp((*itTrasf)->GetNameOfClass(), "AffineTransform")) { AffineTransformType::Pointer affineTransf = AffineTransformType::New(); AffineTransformType::InputPointType cor; cor.Fill(12); affineTransf->SetCenter(cor); affineTransf = static_cast( (*itTrasf).GetPointer()); //affineTransf->Print(std::cout); xf->set_aff (affineTransf); } else if (!strcmp((*itTrasf)->GetNameOfClass(), "BSplineDeformableTransform")) { BsplineTransformType::Pointer bsp = BsplineTransformType::New(); bsp = static_cast( (*itTrasf).GetPointer()); bsp->Print(std::cout); xf->set_itk_bsp (bsp); } } void Xform::save_gpuit_vf (const char* fn) { //write_mha (fn, this->get_gpuit_vf().get()); DeformationFieldType::Pointer itk_vf = xform_gpuit_vf_to_itk_vf (this->get_gpuit_vf().get(), 0); itk_image_save (itk_vf, fn); } void Xform::save (const char* fn) { switch (this->m_type) { case XFORM_ITK_TRANSLATION: itk_xform_save (this->get_trn(), fn); break; case XFORM_ITK_VERSOR: itk_xform_save (this->get_vrs(), fn); break; case XFORM_ITK_QUATERNION: itk_xform_save (this->get_quat(), fn); break; case XFORM_ITK_AFFINE: itk_xform_save (this->get_aff(), fn); break; case XFORM_ITK_SIMILARITY: itk_xform_save (this->get_similarity(), fn); break; case XFORM_ITK_BSPLINE: itk_xform_save (this->get_itk_bsp(), fn); break; case XFORM_ITK_VECTOR_FIELD: itk_image_save (this->get_itk_vf(), fn); break; case XFORM_GPUIT_BSPLINE: this->get_gpuit_bsp()->save(fn); break; case XFORM_GPUIT_VECTOR_FIELD: this->save_gpuit_vf (fn); break; case XFORM_NONE: print_and_exit ("Error trying to save null transform\n"); break; default: print_and_exit ("Unhandled case trying to save transform\n"); break; } } void Xform::save (const std::string& fn) { this->save (fn.c_str()); } void xform_save (Xform *xf, const char* fn) { xf->save (fn); } void xform_save (Xform *xf, const std::string& fn) { xf->save (fn.c_str()); } /* ----------------------------------------------------------------------- Defaults ----------------------------------------------------------------------- */ void Xform::init_trn () { TranslationTransformType::Pointer trn = TranslationTransformType::New(); this->set_trn (trn); } static void init_versor_default (Xform *xf_out) { VersorTransformType::Pointer vrs = VersorTransformType::New(); xf_out->set_vrs (vrs); } static void init_quaternion_default (Xform *xf_out) { QuaternionTransformType::Pointer quat = QuaternionTransformType::New(); xf_out->set_quat (quat); } static void init_affine_default (Xform *xf_out) { AffineTransformType::Pointer aff = AffineTransformType::New(); xf_out->set_aff (aff); } static void init_similarity_default (Xform *xf_out) { SimilarityTransformType::Pointer sim = SimilarityTransformType::New(); xf_out->set_similarity (sim); } void xform_itk_bsp_init_default (Xform *xf) { BsplineTransformType::Pointer bsp = BsplineTransformType::New(); xf->set_itk_bsp (bsp); } /* ----------------------------------------------------------------------- Conversions for trn, vrs, aff ----------------------------------------------------------------------- */ static void xform_trn_to_vrs (Xform *xf_out, const Xform* xf_in) { init_versor_default (xf_out); xf_out->get_vrs()->SetOffset(xf_in->get_trn()->GetOffset()); } static void xform_trn_to_aff (Xform *xf_out, const Xform* xf_in) { init_affine_default (xf_out); xf_out->get_aff()->SetOffset(xf_in->get_trn()->GetOffset()); } void xform_trn_to_sim (Xform *xf_out, const Xform* xf_in) { init_similarity_default (xf_out); xf_out->get_similarity()->SetOffset(xf_in->get_trn()->GetOffset()); } static void xform_vrs_to_quat (Xform *xf_out, const Xform* xf_in) { init_quaternion_default (xf_out); #if ITK_VERSION_MAJOR == 3 xf_out->get_quat()->SetMatrix(xf_in->get_vrs()->GetRotationMatrix()); #else /* ITK 4 */ xf_out->get_quat()->SetMatrix(xf_in->get_vrs()->GetMatrix()); #endif xf_out->get_quat()->SetOffset(xf_in->get_vrs()->GetOffset()); } static void xform_vrs_to_aff (Xform *xf_out, const Xform* xf_in) { init_affine_default (xf_out); #if ITK_VERSION_MAJOR == 3 xf_out->get_aff()->SetMatrix(xf_in->get_vrs()->GetRotationMatrix()); #else /* ITK 4 */ xf_out->get_aff()->SetMatrix(xf_in->get_vrs()->GetMatrix()); #endif xf_out->get_aff()->SetOffset(xf_in->get_vrs()->GetOffset()); } static void xform_vrs_to_sim (Xform *xf_out, const Xform* xf_in) { init_similarity_default (xf_out); #if ITK_VERSION_MAJOR == 3 xf_out->get_similarity()->SetMatrix(xf_in->get_vrs()->GetRotationMatrix()); #else /* ITK 4 */ xf_out->get_similarity()->SetMatrix(xf_in->get_vrs()->GetMatrix()); #endif xf_out->get_similarity()->SetOffset(xf_in->get_vrs()->GetOffset()); } void xform_sim_to_aff (Xform *xf_out, const Xform* xf_in) { init_affine_default (xf_out); #if ITK_VERSION_MAJOR == 3 xf_out->get_aff()->SetMatrix(xf_in->get_similarity()->GetRotationMatrix()); #else /* ITK 4 */ xf_out->get_aff()->SetMatrix(xf_in->get_similarity()->GetMatrix()); #endif xf_out->get_aff()->SetOffset(xf_in->get_similarity()->GetOffset()); } /* ----------------------------------------------------------------------- Conversion to itk_bsp ----------------------------------------------------------------------- */ /* Initialize using bspline spacing */ void xform_itk_bsp_set_grid ( Xform *xf, const BsplineTransformType::OriginType bsp_origin, const BsplineTransformType::SpacingType bsp_spacing, const BsplineTransformType::RegionType bsp_region, const BsplineTransformType::DirectionType bsp_direction) { /* Set grid specifications to bsp struct */ xf->get_itk_bsp()->SetGridSpacing (bsp_spacing); xf->get_itk_bsp()->SetGridOrigin (bsp_origin); xf->get_itk_bsp()->SetGridRegion (bsp_region); /* Allocate and initialize a buffer for the BSplineTransform */ unsigned int num_parameters = xf->get_itk_bsp()->GetNumberOfParameters(); itk::Array parameters (num_parameters); xf->get_itk_bsp()->SetParametersByValue (parameters); xf->get_itk_bsp()->SetIdentity (); /* GCS FIX: Assume direction cosines orthogonal */ xf->get_itk_bsp()->SetGridDirection (bsp_direction); } /* Initialize using image spacing */ static void bsp_grid_from_img_grid ( BsplineTransformType::OriginType& bsp_origin, /* Output */ BsplineTransformType::SpacingType& bsp_spacing, /* Output */ BsplineTransformType::RegionType& bsp_region, /* Output */ BsplineTransformType::DirectionType& bsp_direction, /* Output */ const Plm_image_header* pih, /* Input */ const float* grid_spac) /* Input */ { BsplineTransformType::RegionType::SizeType bsp_size; /* Convert image specifications to grid specifications */ for (int d=0; d<3; d++) { float img_ext = (pih->dim(d) - 1) * fabs (pih->spacing(d)); bsp_origin[d] = pih->origin(d); bsp_spacing[d] = grid_spac[d]; bsp_size[d] = 4 + (int) floor (img_ext / grid_spac[d]); } bsp_direction = pih->GetDirection(); bsp_region.SetSize (bsp_size); /* Adjust origin based on direction cosines */ for (int d1=0; d1<3; d1++) { for (int d2=0; d2<3; d2++) { bsp_origin[d2] -= grid_spac[d1] * bsp_direction[d1][d2]; } } } /* Initialize using image spacing */ static void itk_bsp_set_grid_img ( Xform *xf, const Plm_image_header* pih, const float* grid_spac) { BsplineTransformType::OriginType bsp_origin; BsplineTransformType::SpacingType bsp_spacing; BsplineTransformType::RegionType bsp_region; BsplineTransformType::DirectionType bsp_direction; /* Compute bspline grid specifications */ bsp_grid_from_img_grid (bsp_origin, bsp_spacing, bsp_region, bsp_direction, pih, grid_spac); /* Set grid specifications into xf structure */ xform_itk_bsp_set_grid (xf, bsp_origin, bsp_spacing, bsp_region, bsp_direction); } static void xform_trn_to_itk_bsp_bulk ( Xform *xf_out, const Xform* xf_in, const Plm_image_header* pih, const float* grid_spac) { xform_itk_bsp_init_default (xf_out); itk_bsp_set_grid_img (xf_out, pih, grid_spac); xf_out->get_itk_bsp()->SetBulkTransform (xf_in->get_trn()); } static void xform_vrs_to_itk_bsp_bulk ( Xform *xf_out, const Xform* xf_in, const Plm_image_header* pih, const float* grid_spac) { xform_itk_bsp_init_default (xf_out); itk_bsp_set_grid_img (xf_out, pih, grid_spac); xf_out->get_itk_bsp()->SetBulkTransform (xf_in->get_vrs()); } static void xform_quat_to_itk_bsp_bulk ( Xform *xf_out, const Xform* xf_in, const Plm_image_header* pih, const float* grid_spac) { xform_itk_bsp_init_default (xf_out); itk_bsp_set_grid_img (xf_out, pih, grid_spac); xf_out->get_itk_bsp()->SetBulkTransform (xf_in->get_quat()); } static void xform_aff_to_itk_bsp_bulk ( Xform *xf_out, const Xform* xf_in, const Plm_image_header* pih, const float* grid_spac) { xform_itk_bsp_init_default (xf_out); itk_bsp_set_grid_img (xf_out, pih, grid_spac); xf_out->get_itk_bsp()->SetBulkTransform (xf_in->get_aff()); } /* Convert xf to vector field to bspline */ static void xform_any_to_itk_bsp_nobulk ( Xform *xf_out, Xform* xf_in, const Plm_image_header* pih, const float* grid_spac) { int d; Xform xf_tmp; Plm_image_header pih_bsp; /* Set bsp grid parameters in xf_out */ xform_itk_bsp_init_default (xf_out); itk_bsp_set_grid_img (xf_out, pih, grid_spac); BsplineTransformType::Pointer bsp_out = xf_out->get_itk_bsp(); /* Create temporary array for output coefficients */ const unsigned int num_parms = bsp_out->GetNumberOfParameters(); BsplineTransformType::ParametersType bsp_coeff; bsp_coeff.SetSize (num_parms); /* Compute bspline grid specifications */ BsplineTransformType::OriginType bsp_origin; BsplineTransformType::SpacingType bsp_spacing; BsplineTransformType::RegionType bsp_region; BsplineTransformType::DirectionType bsp_direction; bsp_grid_from_img_grid (bsp_origin, bsp_spacing, bsp_region, bsp_direction, pih, grid_spac); /* Make a vector field at bspline grid spacing */ pih_bsp.set (bsp_region, bsp_origin, bsp_spacing, bsp_direction); xform_to_itk_vf (&xf_tmp, xf_in, &pih_bsp); /* Vector field is interleaved. We need planar for decomposition. */ FloatImageType::Pointer img = itk_image_create (pih_bsp); /* Loop through planes */ unsigned int counter = 0; DeformationFieldType::Pointer vf = xf_tmp.get_itk_vf(); for (d = 0; d < 3; d++) { /* Copy a single VF plane into img */ typedef itk::ImageRegionIterator< FloatImageType > FloatIteratorType; typedef itk::ImageRegionIterator< DeformationFieldType > VFIteratorType; FloatIteratorType img_it (img, img->GetLargestPossibleRegion()); VFIteratorType vf_it (vf, vf->GetLargestPossibleRegion()); for (img_it.GoToBegin(), vf_it.GoToBegin(); !img_it.IsAtEnd(); ++img_it, ++vf_it) { img_it.Set(vf_it.Get()[d]); } /* Decompose into bpline coefficient image */ typedef itk::BSplineDecompositionImageFilter DecompositionType; DecompositionType::Pointer decomposition = DecompositionType::New(); decomposition->SetSplineOrder (SplineOrder); decomposition->SetInput (img); decomposition->Update (); /* Copy the coefficients into a temporary parameter array */ typedef BsplineTransformType::ImageType ParametersImageType; ParametersImageType::Pointer newCoefficients = decomposition->GetOutput(); typedef itk::ImageRegionIterator Iterator; Iterator co_it (newCoefficients, bsp_out->GetGridRegion()); co_it.GoToBegin(); while (!co_it.IsAtEnd()) { bsp_coeff[counter++] = co_it.Get(); ++co_it; } } /* Finally fixate coefficients into recently created bsp structure */ bsp_out->SetParametersByValue (bsp_coeff); } /* This function extends the B-spline grid, padding with zeros, so that the grid contains the specified Region "roi." This is sometimes needed so that the B-spline can warp an image or be rendered into a vector field. It may sometimes be needed for going from lower resolution to higher resolutions as well. */ static void itk_bsp_extend_to_region ( Xform* xf, const Plm_image_header* pih, const RegionType* roi) { unsigned long i, j, k; int extend_needed = 0; BsplineTransformType::Pointer bsp = xf->get_itk_bsp(); BsplineTransformType::OriginType bsp_origin = bsp->GetGridOrigin(); BsplineTransformType::RegionType bsp_region = bsp->GetGridRegion(); BsplineTransformType::RegionType::SizeType bsp_size = bsp->GetGridRegion().GetSize(); BsplineTransformType::SpacingType bsp_spacing = bsp->GetGridSpacing(); BsplineTransformType::DirectionType bsp_direction = bsp->GetGridDirection(); Plm_image_header bsp_pih (bsp_region, bsp_origin, bsp_spacing, bsp_direction); /* # of control points to "extend before" and "extend after" existing grid */ int eb[3], ea[3]; #if PLM_CONFIG_LEGACY_BSPLINE_EXTEND /* Figure out if we need to extend the bspline grid. If so, compute ea & eb, as well as new values of bsp_region and bsp_origin. */ for (int d = 0; d < 3; d++) { float old_roi_origin = bsp->GetGridOrigin()[d] + bsp->GetGridSpacing()[d]; float old_roi_corner = old_roi_origin + (bsp->GetGridRegion().GetSize()[d] - 3) * bsp->GetGridSpacing()[d]; float new_roi_origin = pih->origin(d) + roi->GetIndex()[d] * pih->spacing(d); float new_roi_corner = new_roi_origin + (roi->GetSize()[d] - 1) * pih->spacing(d); ea[d] = eb[d] = 0; if (old_roi_origin > new_roi_origin) { float diff = old_roi_origin - new_roi_origin; eb[d] = (int) ceil (diff / bsp->GetGridSpacing()[d]); bsp_origin[d] -= eb[d] * bsp->GetGridSpacing()[d]; bsp_size[d] += eb[d]; extend_needed = 1; } if (old_roi_corner < new_roi_corner) { float diff = new_roi_origin - old_roi_origin; ea[d] = (int) ceil (diff / bsp->GetGridSpacing()[d]); bsp_size[d] += ea[d]; extend_needed = 1; } } #else /* Figure out if we need to extend the bspline grid. If so, compute ea & eb, as well as new values of bsp_region and bsp_origin. */ float new_roi_origin_idx[3], new_roi_corner_idx[3]; for (int d = 0; d < 3; d++) { new_roi_origin_idx[d] = 0.f; new_roi_corner_idx[d] = roi->GetSize()[d] - 1; } FloatPoint3DType new_roi_origin = pih->get_position (new_roi_origin_idx); FloatPoint3DType new_roi_corner = pih->get_position (new_roi_corner_idx); FloatPoint3DType new_roi_origin_idx_in_old = bsp_pih.get_index (new_roi_origin); FloatPoint3DType new_roi_corner_idx_in_old = bsp_pih.get_index (new_roi_corner); #if defined (commentout) printf ("-- BSP PIH\n"); bsp_pih.print(); printf ("-- PIH\n"); pih->print(); printf ("New ROI Or Idx: %g %g %g\n", new_roi_origin_idx[0], new_roi_origin_idx[1], new_roi_origin_idx[2]); printf ("New ROI Co Idx: %g %g %g\n", new_roi_corner_idx[0], new_roi_corner_idx[1], new_roi_corner_idx[2]); printf ("New ROI Or: %g %g %g\n", new_roi_origin[0], new_roi_origin[1], new_roi_origin[2]); printf ("New ROI Co: %g %g %g\n", new_roi_corner[0], new_roi_corner[1], new_roi_corner[2]); printf ("New ROI Or Idx (inold): %g %g %g\n", new_roi_origin_idx_in_old[0], new_roi_origin_idx_in_old[1], new_roi_origin_idx_in_old[2]); printf ("New ROI Co Idx (inold): %g %g %g\n", new_roi_corner_idx_in_old[0], new_roi_corner_idx_in_old[1], new_roi_corner_idx_in_old[2]); #endif for (int d = 0; d < 3; d++) { eb[d] = ea[d] = 0; new_roi_origin_idx_in_old[d] = floorf (new_roi_origin_idx_in_old[d]); new_roi_corner_idx_in_old[d] = ceilf (new_roi_corner_idx_in_old[d]); if (new_roi_origin_idx_in_old[d] < 1) { eb[d] = 1 - (int) new_roi_origin_idx_in_old[d]; new_roi_corner_idx[d] -= eb[d]; extend_needed = 1; } if (new_roi_corner_idx_in_old[d] > bsp_size[d] - 2) { ea[d] = new_roi_corner_idx_in_old[d] - (bsp_size[d] - 1); extend_needed = 1; } } if (extend_needed) { /* Figure out new origin */ bsp_origin = bsp_pih.get_position (new_roi_corner_idx); /* Figure out new size */ for (int d = 0; d < 3; d++) { bsp_size[d] += eb[d] + ea[d]; } } #endif if (extend_needed) { /* Allocate new parameter array */ BsplineTransformType::Pointer bsp_new = BsplineTransformType::New(); BsplineTransformType::RegionType old_region = bsp->GetGridRegion(); bsp_region.SetSize (bsp_size); bsp_new->SetGridOrigin (bsp_origin); bsp_new->SetGridRegion (bsp_region); bsp_new->SetGridSpacing (bsp->GetGridSpacing()); bsp_new->SetGridDirection (bsp->GetGridDirection()); /* Copy current parameters in... */ const unsigned int num_parms = bsp_new->GetNumberOfParameters(); BsplineTransformType::ParametersType bsp_coeff; bsp_coeff.SetSize (num_parms); bsp_coeff.Fill (0.f); for (int old_idx = 0, d = 0; d < 3; d++) { for (k = 0; k < old_region.GetSize()[2]; k++) { for (j = 0; j < old_region.GetSize()[1]; j++) { for (i = 0; i < old_region.GetSize()[0]; i++, old_idx++) { int new_idx; new_idx = ((((d * bsp_size[2]) + k + eb[2]) * bsp_size[1] + (j + eb[1])) * bsp_size[0]) + (i + eb[0]); bsp_coeff[new_idx] = bsp->GetParameters()[old_idx]; } } } } /* Copy coefficients into recently created bsp struct */ bsp_new->SetParametersByValue (bsp_coeff); /* Fixate xf with new bsp */ xf->set_itk_bsp (bsp_new); } } static void xform_itk_bsp_to_itk_bsp ( Xform *xf_out, const Xform* xf_in, const Plm_image_header* pih, const float* grid_spac) { BsplineTransformType::Pointer bsp_old = xf_in->get_itk_bsp(); xform_itk_bsp_init_default (xf_out); itk_bsp_set_grid_img (xf_out, pih, grid_spac); /* Need to copy the bulk transform */ BsplineTransformType::Pointer bsp_out = xf_out->get_itk_bsp(); bsp_out->SetBulkTransform (bsp_old->GetBulkTransform()); /* Create temporary array for output coefficients */ const unsigned int num_parms = xf_out->get_itk_bsp()->GetNumberOfParameters(); BsplineTransformType::ParametersType bsp_coeff; bsp_coeff.SetSize (num_parms); /* GCS May 12, 2008. I feel like the below algorithm suggested by ITK is wrong. If BSplineResampleImageFunction interpolates the coefficient image, the resulting resampled B-spline will be smoother than the original. But maybe the algorithm is OK, just a problem with the lack of proper ITK documentation. Need to test this. What this code does is this: 1) Resample coefficient image using B-Spline interpolator 2) Pass resampled image to decomposition filter 3) Copy decomposition filter output into new coefficient image This is the original comment from the ITK code: Now we need to initialize the BSpline coefficients of the higher resolution transform. This is done by first computing the actual deformation field at the higher resolution from the lower resolution BSpline coefficients. Then a BSpline decomposition is done to obtain the BSpline coefficient of the higher resolution transform. */ unsigned int counter = 0; for (unsigned int k = 0; k < 3; k++) { typedef BsplineTransformType::ImageType ParametersImageType; typedef itk::ResampleImageFilter< ParametersImageType, ParametersImageType> ResamplerType; ResamplerType::Pointer resampler = ResamplerType::New(); typedef itk::BSplineResampleImageFunction< ParametersImageType, double> FunctionType; FunctionType::Pointer fptr = FunctionType::New(); typedef itk::IdentityTransform IdentityTransformType; IdentityTransformType::Pointer identity = IdentityTransformType::New(); #if ITK_VERSION_MAJOR == 3 resampler->SetInput (bsp_old->GetCoefficientImage()[k]); #else /* ITK 4 */ resampler->SetInput (bsp_old->GetCoefficientImages()[k]); #endif resampler->SetInterpolator (fptr); resampler->SetTransform (identity); resampler->SetSize (bsp_out->GetGridRegion().GetSize()); resampler->SetOutputSpacing (bsp_out->GetGridSpacing()); resampler->SetOutputOrigin (bsp_out->GetGridOrigin()); resampler->SetOutputDirection (bsp_out->GetGridDirection()); typedef itk::BSplineDecompositionImageFilter< ParametersImageType, ParametersImageType> DecompositionType; DecompositionType::Pointer decomposition = DecompositionType::New(); decomposition->SetSplineOrder (SplineOrder); decomposition->SetInput (resampler->GetOutput()); decomposition->Update(); ParametersImageType::Pointer newCoefficients = decomposition->GetOutput(); // copy the coefficients into a temporary parameter array typedef itk::ImageRegionIterator Iterator; Iterator it (newCoefficients, bsp_out->GetGridRegion()); while (!it.IsAtEnd()) { bsp_coeff[counter++] = it.Get(); ++it; } } /* Finally fixate coefficients into recently created bsp structure */ bsp_out->SetParametersByValue (bsp_coeff); } /* Compute itk_bsp grid specifications from gpuit specifications */ static void gpuit_bsp_grid_to_itk_bsp_grid ( BsplineTransformType::OriginType& bsp_origin, /* Output */ BsplineTransformType::SpacingType& bsp_spacing, /* Output */ BsplineTransformType::RegionType& bsp_region, /* Output */ BsplineTransformType::DirectionType& bsp_direction, /* Output */ Bspline_xform* bxf) /* Input */ { BsplineTransformType::SizeType bsp_size; /* Convert bxf specifications to grid specifications */ for (int d = 0; d < 3; d++) { bsp_size[d] = bxf->cdims[d]; bsp_origin[d] = bxf->img_origin[d]; bsp_spacing[d] = bxf->grid_spac[d]; } itk_direction_from_dc (&bsp_direction, bxf->dc); bsp_region.SetSize (bsp_size); /* Adjust origin based on direction cosines */ for (int d1=0; d1<3; d1++) { for (int d2=0; d2<3; d2++) { bsp_origin[d2] -= bxf->grid_spac[d1] * bsp_direction[d1][d2]; } } } static void gpuit_bsp_to_itk_bsp_raw ( Xform *xf_out, const Xform* xf_in, const Plm_image_header* pih) { typedef BsplineTransformType::ImageType ParametersImageType; typedef itk::ImageRegionIterator Iterator; Bspline_xform* bxf = xf_in->get_gpuit_bsp(); BsplineTransformType::OriginType bsp_origin; BsplineTransformType::SpacingType bsp_spacing; BsplineTransformType::RegionType bsp_region; BsplineTransformType::DirectionType bsp_direction = pih->GetDirection(); /* Convert bspline grid geometry from gpuit to itk */ gpuit_bsp_grid_to_itk_bsp_grid (bsp_origin, bsp_spacing, bsp_region, bsp_direction, bxf); /* Create itk bspline structure */ xform_itk_bsp_init_default (xf_out); xform_itk_bsp_set_grid (xf_out, bsp_origin, bsp_spacing, bsp_region, bsp_direction); /* RMK: bulk transform is Identity (not supported by GPUIT) */ /* Create temporary array for output coefficients */ const unsigned int num_parms = xf_out->get_itk_bsp()->GetNumberOfParameters(); BsplineTransformType::ParametersType bsp_coeff; bsp_coeff.SetSize (num_parms); /* Copy from GPUIT coefficient array to ITK coefficient array */ int k = 0; for (int d = 0; d < 3; d++) { for (int i = 0; i < bxf->num_knots; i++) { bsp_coeff[k] = bxf->coeff[3*i+d]; k++; } } /* Fixate coefficients into bsp structure */ xf_out->get_itk_bsp()->SetParametersByValue (bsp_coeff); } /* If grid_spac is null, then don't resample */ static void xform_gpuit_bsp_to_itk_bsp ( Xform *xf_out, const Xform* xf_in, const Plm_image_header* pih, const float* grid_spac) { Xform xf_tmp; if (grid_spac) { /* Convert to itk data structure */ gpuit_bsp_to_itk_bsp_raw (&xf_tmp, xf_in, pih); /* Then, resample the xform to the desired grid spacing */ xform_itk_bsp_to_itk_bsp (xf_out, &xf_tmp, pih, grid_spac); } else { /* Convert to itk data structure only */ gpuit_bsp_to_itk_bsp_raw (xf_out, xf_in, pih); } } /* ----------------------------------------------------------------------- Conversion to itk_vf ----------------------------------------------------------------------- */ static DeformationFieldType::Pointer xform_itk_any_to_itk_vf ( itk::Transform* xf, const Plm_image_header* pih) { #if defined (commentout) DeformationFieldType::Pointer itk_vf = DeformationFieldType::New(); itk_vf->SetOrigin (pih->m_origin); itk_vf->SetSpacing (pih->m_spacing); itk_vf->SetRegions (pih->m_region); itk_vf->SetDirection (pih->m_direction); itk_vf->Allocate (); #endif DeformationFieldType::Pointer itk_vf = itk_image_create (*pih); typedef itk::ImageRegionIteratorWithIndex< DeformationFieldType > FieldIterator; FieldIterator fi (itk_vf, itk_vf->GetLargestPossibleRegion()); fi.GoToBegin(); DoublePoint3DType fixed_point; DoublePoint3DType moving_point; DeformationFieldType::IndexType index; FloatVector3DType displacement; while (!fi.IsAtEnd()) { index = fi.GetIndex(); itk_vf->TransformIndexToPhysicalPoint (index, fixed_point); moving_point = xf->TransformPoint (fixed_point); for (int r = 0; r < 3; r++) { displacement[r] = moving_point[r] - fixed_point[r]; } fi.Set (displacement); ++fi; } return itk_vf; } /* ITK bsp is different from itk_any, because additional control points might be needed */ static DeformationFieldType::Pointer xform_itk_bsp_to_itk_vf (Xform* xf_in, const Plm_image_header* pih) { int d; Xform xf_tmp; float grid_spac[3]; /* Deep copy of itk_bsp */ for (d = 0; d < 3; d++) { grid_spac[d] = xf_in->get_itk_bsp()->GetGridSpacing()[d]; } xform_itk_bsp_to_itk_bsp (&xf_tmp, xf_in, pih, grid_spac); /* Extend bsp control point grid */ RegionType region = pih->GetRegion(); itk_bsp_extend_to_region (&xf_tmp, pih, ®ion); /* Convert extended bsp to vf */ return xform_itk_any_to_itk_vf (xf_tmp.get_itk_bsp(), pih); } static DeformationFieldType::Pointer xform_itk_vf_to_itk_vf ( const DeformationFieldType::Pointer& vf, Plm_image_header* pih) { return vector_resample_image (vf, (const Plm_image_header*) pih); } /* Here what we're going to do is use GPUIT library to interpolate the B-Spline at its native resolution, then convert gpuit_vf -> itk_vf. GCS: Aug 6, 2008. The above idea doesn't work, because the native resolution might not encompass the image. Here is what we will do: 1) Convert to ITK B-Spline 2) Extend ITK B-Spline to encompass image 3) Render vf. */ static DeformationFieldType::Pointer xform_gpuit_bsp_to_itk_vf (Xform* xf_in, Plm_image_header* pih) { DeformationFieldType::Pointer itk_vf; Xform xf_tmp; OriginType img_origin; SpacingType img_spacing; RegionType img_region; /* Copy from GPUIT coefficient array to ITK coefficient array */ gpuit_bsp_to_itk_bsp_raw (&xf_tmp, xf_in, pih); /* Resize itk array to span image */ RegionType region = pih->GetRegion(); itk_bsp_extend_to_region (&xf_tmp, pih, ®ion); /* Render to vector field */ itk_vf = xform_itk_any_to_itk_vf (xf_tmp.get_itk_bsp(), pih); return itk_vf; } /* 1) convert gpuit -> itk at the native resolution, 2) convert itk -> itk to change resolution. */ DeformationFieldType::Pointer xform_gpuit_vf_to_itk_vf ( Volume* vf, /* Input */ Plm_image_header* pih /* Input, can be null */ ) { DeformationFieldType::Pointer itk_vf = DeformationFieldType::New(); FloatVector3DType displacement; /* Copy header & allocate data for itk */ itk_image_set_header (itk_vf, Plm_image_header (vf)); itk_vf->Allocate(); /* Copy data into itk */ typedef itk::ImageRegionIterator< DeformationFieldType > FieldIterator; FieldIterator fi (itk_vf, itk_vf->GetLargestPossibleRegion()); if (vf->pix_type == PT_VF_FLOAT_INTERLEAVED) { float* img = (float*) vf->img; int i = 0; for (fi.GoToBegin(); !fi.IsAtEnd(); ++fi) { for (int r = 0; r < 3; r++) { displacement[r] = img[i++]; } fi.Set (displacement); } } else if (vf->pix_type == PT_VF_FLOAT_PLANAR) { float** img = (float**) vf->img; int i = 0; for (fi.GoToBegin(); !fi.IsAtEnd(); ++fi, ++i) { for (int r = 0; r < 3; r++) { displacement[r] = img[r][i]; } fi.Set (displacement); } } else { print_and_exit ("Irregular pix_type used converting gpuit_xf -> itk\n"); } /* Resample to requested resolution */ if (pih) { itk_vf = xform_itk_vf_to_itk_vf (itk_vf, pih); } return itk_vf; } /* ----------------------------------------------------------------------- Conversion to gpuit_bsp ----------------------------------------------------------------------- */ static Bspline_xform* create_gpuit_bxf (Plm_image_header* pih, const float* grid_spac) { int d; Bspline_xform* bxf = new Bspline_xform; float img_origin[3]; float img_spacing[3]; plm_long img_dim[3]; plm_long roi_offset[3]; plm_long roi_dim[3]; plm_long vox_per_rgn[3]; float direction_cosines[9]; pih->get_origin (img_origin); pih->get_dim (img_dim); pih->get_spacing (img_spacing); pih->get_direction_cosines (direction_cosines); for (d = 0; d < 3; d++) { /* Old ROI was whole image */ roi_offset[d] = 0; roi_dim[d] = img_dim[d]; /* Compute vox_per_rgn */ vox_per_rgn[d] = ROUND_INT (grid_spac[d] / fabs(img_spacing[d])); if (vox_per_rgn[d] < 4) { lprintf ("Warning: vox_per_rgn was less than 4.\n"); vox_per_rgn[d] = 4; } } bxf->initialize (img_origin, img_spacing, img_dim, roi_offset, roi_dim, vox_per_rgn, direction_cosines); return bxf; } void xform_any_to_gpuit_bsp ( Xform* xf_out, Xform* xf_in, Plm_image_header* pih, const float* grid_spac) { Xform xf_tmp; /* Initialize gpuit bspline data structure */ Bspline_xform* bxf_new = create_gpuit_bxf (pih, grid_spac); if (xf_in->m_type != XFORM_NONE) { /* Output ROI is going to be whole image */ RegionType roi = pih->GetRegion (); /* Create itk_bsp xf using image specifications */ xform_any_to_itk_bsp_nobulk (&xf_tmp, xf_in, pih, bxf_new->grid_spac); /* Copy from ITK coefficient array to gpuit coefficient array */ int k = 0; for (int d = 0; d < 3; d++) { for (int i = 0; i < bxf_new->num_knots; i++) { bxf_new->coeff[3*i+d] = xf_tmp.get_itk_bsp()->GetParameters()[k]; k++; } } } /* Fixate gpuit bsp to xf */ xf_out->set_gpuit_bsp (bxf_new); } void xform_gpuit_bsp_to_gpuit_bsp ( Xform* xf_out, Xform* xf_in, Plm_image_header* pih, const float* grid_spac ) { Xform xf_tmp; /* Initialize gpuit bspline data structure */ Bspline_xform* bxf_new = create_gpuit_bxf (pih, grid_spac); /* Create itk_bsp xf using image specifications */ xform_gpuit_bsp_to_itk_bsp (&xf_tmp, xf_in, pih, bxf_new->grid_spac); /* Copy from ITK coefficient array to gpuit coefficient array */ int k = 0; for (int d = 0; d < 3; d++) { for (int i = 0; i < bxf_new->num_knots; i++) { bxf_new->coeff[3*i+d] = xf_tmp.get_itk_bsp()->GetParameters()[k]; k++; } } /* Fixate gpuit bsp to xf */ xf_out->set_gpuit_bsp (bxf_new); } void xform_gpuit_vf_to_gpuit_bsp ( Xform* xf_out, Xform* xf_in, Plm_image_header* pih, const float* grid_spac ) { /* Convert gpuit_vf to itk_vf, then convert itk_vf to gpuit_bsp */ Xform tmp; xform_to_itk_vf (&tmp, xf_in, pih); xform_any_to_gpuit_bsp (xf_out, &tmp, pih, grid_spac); } /* ----------------------------------------------------------------------- Conversion to gpuit_vf ----------------------------------------------------------------------- */ static Volume::Pointer xform_itk_any_to_gpuit_vf ( itk::Transform* xf, const Plm_image_header* pih) { Volume_header vh (pih); Volume::Pointer vf_out = Volume::New (vh, PT_VF_FLOAT_INTERLEAVED, 3); float* img = (float*) vf_out->img; DoublePoint3DType fixed_point; DoublePoint3DType moving_point; int i = 0; plm_long fijk[3] = {0}; float fxyz[3]; LOOP_Z(fijk,fxyz,vf_out) { LOOP_Y(fijk,fxyz,vf_out) { LOOP_X(fijk,fxyz,vf_out) { fixed_point[0] = fxyz[0]; fixed_point[1] = fxyz[1]; fixed_point[2] = fxyz[2]; moving_point = xf->TransformPoint (fixed_point); for (int r = 0; r < 3; r++) { img[i++] = moving_point[r] - fixed_point[r]; } } } } return vf_out; } static Volume::Pointer xform_gpuit_vf_to_gpuit_vf ( const Volume::Pointer& vf_in, const Plm_image_header *pih) { Volume::Pointer vf_out; Volume_header vh (pih); vf_out = volume_resample (vf_in, &vh); return vf_out; } static Volume::Pointer xform_gpuit_bsp_to_gpuit_vf (const Xform *xf_in, const Plm_image_header *pih) { Bspline_xform* bxf = xf_in->get_gpuit_bsp(); Volume::Pointer vf_out; Volume_header vh (pih); vf_out = Volume::New (vh, PT_VF_FLOAT_INTERLEAVED, 3); bspline_interpolate_vf (vf_out.get(), bxf); return vf_out; } Volume::Pointer xform_itk_vf_to_gpuit_vf ( DeformationFieldType::Pointer itk_vf, const Plm_image_header *pih) { Volume_header vh (pih); Volume::Pointer vf_out = Volume::New (vh, PT_VF_FLOAT_INTERLEAVED, 3); float* img = (float*) vf_out->img; FloatVector3DType displacement; int i = 0; typedef itk::ImageRegionIterator< DeformationFieldType > FieldIterator; FieldIterator fi (itk_vf, itk_vf->GetLargestPossibleRegion()); for (fi.GoToBegin(); !fi.IsAtEnd(); ++fi) { displacement = fi.Get (); for (int r = 0; r < 3; r++) { img[i++] = displacement[r]; } } return vf_out; } /* ----------------------------------------------------------------------- Selection routines to convert from X to Y ----------------------------------------------------------------------- */ void xform_to_trn ( Xform *xf_out, const Xform *xf_in, Plm_image_header *pih) { switch (xf_in->m_type) { case XFORM_NONE: xf_out->init_trn (); break; case XFORM_ITK_TRANSLATION: *xf_out = *xf_in; break; case XFORM_ITK_VERSOR: case XFORM_ITK_QUATERNION: case XFORM_ITK_AFFINE: case XFORM_ITK_BSPLINE: case XFORM_ITK_TPS: case XFORM_ITK_VECTOR_FIELD: print_and_exit ("Sorry, couldn't convert to trn\n"); break; case XFORM_GPUIT_BSPLINE: case XFORM_GPUIT_VECTOR_FIELD: print_and_exit ("Sorry, gpuit xforms not fully implemented\n"); break; default: print_and_exit ("Program error. Bad xform type.\n"); break; } } void xform_to_vrs ( Xform *xf_out, const Xform *xf_in, Plm_image_header *pih) { switch (xf_in->m_type) { case XFORM_NONE: init_versor_default (xf_out); break; case XFORM_ITK_TRANSLATION: xform_trn_to_vrs (xf_out, xf_in); break; case XFORM_ITK_VERSOR: *xf_out = *xf_in; break; case XFORM_ITK_AFFINE: case XFORM_ITK_QUATERNION: case XFORM_ITK_BSPLINE: case XFORM_ITK_TPS: case XFORM_ITK_VECTOR_FIELD: print_and_exit ("Sorry, couldn't convert to vrs\n"); break; case XFORM_GPUIT_BSPLINE: case XFORM_GPUIT_VECTOR_FIELD: print_and_exit ("Sorry, gpuit xforms not fully implemented\n"); break; default: print_and_exit ("Program error. Bad xform type.\n"); break; } } void xform_to_quat ( Xform *xf_out, const Xform *xf_in, Plm_image_header *pih) { switch (xf_in->m_type) { case XFORM_NONE: init_quaternion_default (xf_out); break; case XFORM_ITK_TRANSLATION: print_and_exit ("Sorry, couldn't convert to quaternion\n"); break; case XFORM_ITK_VERSOR: xform_vrs_to_quat (xf_out, xf_in); break; case XFORM_ITK_QUATERNION: *xf_out = *xf_in; break; case XFORM_ITK_AFFINE: case XFORM_ITK_SIMILARITY: case XFORM_ITK_BSPLINE: case XFORM_ITK_TPS: case XFORM_ITK_VECTOR_FIELD: case XFORM_GPUIT_BSPLINE: case XFORM_GPUIT_VECTOR_FIELD: print_and_exit ("Sorry, couldn't convert to quaternion\n"); break; default: print_and_exit ("Program error. Bad xform type.\n"); break; } } void xform_to_aff ( Xform *xf_out, const Xform *xf_in, Plm_image_header *pih) { switch (xf_in->m_type) { case XFORM_NONE: init_affine_default (xf_out); break; case XFORM_ITK_TRANSLATION: xform_trn_to_aff (xf_out, xf_in); break; case XFORM_ITK_VERSOR: xform_vrs_to_aff (xf_out, xf_in); break; case XFORM_ITK_SIMILARITY: xform_sim_to_aff (xf_out, xf_in); break; case XFORM_ITK_QUATERNION: print_and_exit ("Sorry, couldn't convert to aff\n"); break; case XFORM_ITK_AFFINE: *xf_out = *xf_in; break; case XFORM_ITK_BSPLINE: case XFORM_ITK_TPS: case XFORM_ITK_VECTOR_FIELD: print_and_exit ("Sorry, couldn't convert to aff\n"); break; case XFORM_GPUIT_BSPLINE: case XFORM_GPUIT_VECTOR_FIELD: print_and_exit ("Sorry, gpuit xforms not fully implemented\n"); break; default: print_and_exit ("Program error. Bad xform type.\n"); break; } } void xform_to_similarity ( Xform *xf_out, const Xform *xf_in, Plm_image_header *pih) { switch (xf_in->m_type) { case XFORM_NONE: init_similarity_default (xf_out); break; case XFORM_ITK_TRANSLATION: xform_trn_to_sim (xf_out, xf_in); break; case XFORM_ITK_VERSOR: xform_vrs_to_sim(xf_out,xf_in); break; case XFORM_ITK_SIMILARITY: *xf_out = *xf_in; break; case XFORM_ITK_QUATERNION: case XFORM_ITK_AFFINE: case XFORM_ITK_BSPLINE: case XFORM_ITK_TPS: case XFORM_ITK_VECTOR_FIELD: print_and_exit ("Sorry, couldn't convert to aff\n"); break; case XFORM_GPUIT_BSPLINE: case XFORM_GPUIT_VECTOR_FIELD: print_and_exit ("Sorry, gpuit xforms not fully implemented\n"); break; default: print_and_exit ("Program error. Bad xform type.\n"); break; } } void xform_to_itk_bsp ( Xform *xf_out, const Xform *xf_in, Plm_image_header* pih, const float* grid_spac ) { BsplineTransformType::Pointer bsp; switch (xf_in->m_type) { case XFORM_NONE: xform_itk_bsp_init_default (xf_out); itk_bsp_set_grid_img (xf_out, pih, grid_spac); break; case XFORM_ITK_TRANSLATION: xform_trn_to_itk_bsp_bulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_VERSOR: xform_vrs_to_itk_bsp_bulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_QUATERNION: xform_quat_to_itk_bsp_bulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_AFFINE: xform_aff_to_itk_bsp_bulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_BSPLINE: xform_itk_bsp_to_itk_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_TPS: print_and_exit ("Sorry, couldn't convert itk_tps to itk_bsp\n"); break; case XFORM_ITK_VECTOR_FIELD: print_and_exit ("Sorry, couldn't convert itk_vf to itk_bsp\n"); break; case XFORM_GPUIT_BSPLINE: xform_gpuit_bsp_to_itk_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_GPUIT_VECTOR_FIELD: print_and_exit ("Sorry, couldn't convert gpuit_vf to itk_bsp\n"); break; default: print_and_exit ("Program error. Bad xform type.\n"); break; } } Xform::Pointer xform_to_itk_bsp ( const Xform::Pointer& xf_in, Plm_image_header* pih, const float* grid_spac ) { Xform::Pointer xf_out = Xform::New (); xform_to_itk_bsp (xf_out.get(), xf_in.get(), pih, grid_spac); return xf_out; } void xform_to_itk_bsp_nobulk ( Xform *xf_out, Xform *xf_in, Plm_image_header* pih, const float* grid_spac) { switch (xf_in->m_type) { case XFORM_NONE: xform_itk_bsp_init_default (xf_out); itk_bsp_set_grid_img (xf_out, pih, grid_spac); break; case XFORM_ITK_TRANSLATION: xform_any_to_itk_bsp_nobulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_VERSOR: xform_any_to_itk_bsp_nobulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_QUATERNION: xform_any_to_itk_bsp_nobulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_AFFINE: xform_any_to_itk_bsp_nobulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_BSPLINE: xform_any_to_itk_bsp_nobulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_TPS: xform_any_to_itk_bsp_nobulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_VECTOR_FIELD: xform_any_to_itk_bsp_nobulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_GPUIT_BSPLINE: xform_any_to_itk_bsp_nobulk (xf_out, xf_in, pih, grid_spac); break; case XFORM_GPUIT_VECTOR_FIELD: xform_any_to_itk_bsp_nobulk (xf_out, xf_in, pih, grid_spac); break; default: print_and_exit ("Program error. Bad xform type.\n"); break; } } Xform::Pointer xform_to_itk_bsp_nobulk ( const Xform::Pointer& xf_in, Plm_image_header* pih, const float* grid_spac ) { Xform::Pointer xf_out = Xform::New (); xform_to_itk_bsp_nobulk (xf_out.get(), xf_in.get(), pih, grid_spac); return xf_out; } void xform_to_itk_vf (Xform* xf_out, Xform *xf_in, Plm_image_header* pih) { DeformationFieldType::Pointer vf; switch (xf_in->m_type) { case XFORM_NONE: print_and_exit ("Sorry, couldn't convert to vf\n"); break; case XFORM_ITK_TRANSLATION: vf = xform_itk_any_to_itk_vf (xf_in->get_trn(), pih); break; case XFORM_ITK_VERSOR: vf = xform_itk_any_to_itk_vf (xf_in->get_vrs(), pih); break; case XFORM_ITK_QUATERNION: vf = xform_itk_any_to_itk_vf (xf_in->get_quat(), pih); break; case XFORM_ITK_AFFINE: vf = xform_itk_any_to_itk_vf (xf_in->get_aff(), pih); break; case XFORM_ITK_SIMILARITY: vf = xform_itk_any_to_itk_vf (xf_in->get_similarity(), pih); break; case XFORM_ITK_BSPLINE: vf = xform_itk_bsp_to_itk_vf (xf_in, pih); break; case XFORM_ITK_TPS: vf = xform_itk_any_to_itk_vf (xf_in->get_itk_tps(), pih); break; case XFORM_ITK_VECTOR_FIELD: vf = xform_itk_vf_to_itk_vf (xf_in->get_itk_vf(), pih); break; case XFORM_GPUIT_BSPLINE: vf = xform_gpuit_bsp_to_itk_vf (xf_in, pih); break; case XFORM_GPUIT_VECTOR_FIELD: vf = xform_gpuit_vf_to_itk_vf (xf_in->get_gpuit_vf().get(), pih); break; default: print_and_exit ("Program error. Bad xform type.\n"); break; } xf_out->set_itk_vf (vf); } /* Overloaded fn. GCS FIX -- maybe this function is not needed */ void xform_to_itk_vf (Xform* xf_out, Xform *xf_in, FloatImageType::Pointer image) { Plm_image_header pih; pih.set_from_itk_image (image); xform_to_itk_vf (xf_out, xf_in, &pih); } Xform::Pointer xform_to_itk_vf (const Xform::Pointer& xf_in, Plm_image_header* pih) { Xform::Pointer xf_out = Xform::New (); xform_to_itk_vf (xf_out.get(), xf_in.get(), pih); return xf_out; } void xform_to_gpuit_bsp (Xform* xf_out, Xform* xf_in, Plm_image_header* pih, const float* grid_spac) { switch (xf_in->m_type) { case XFORM_NONE: xform_any_to_gpuit_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_TRANSLATION: xform_any_to_gpuit_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_VERSOR: xform_any_to_gpuit_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_QUATERNION: xform_any_to_gpuit_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_AFFINE: xform_any_to_gpuit_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_BSPLINE: xform_any_to_gpuit_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_TPS: xform_any_to_gpuit_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_ITK_VECTOR_FIELD: xform_any_to_gpuit_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_GPUIT_BSPLINE: xform_gpuit_bsp_to_gpuit_bsp (xf_out, xf_in, pih, grid_spac); break; case XFORM_GPUIT_VECTOR_FIELD: xform_gpuit_vf_to_gpuit_bsp (xf_out, xf_in, pih, grid_spac); break; default: print_and_exit ("Program error. Bad xform type.\n"); break; } } Xform::Pointer xform_to_gpuit_bsp ( const Xform::Pointer& xf_in, Plm_image_header* pih, float* grid_spac ) { Xform::Pointer xf_out = Xform::New (); xform_to_gpuit_bsp (xf_out.get(), xf_in.get(), pih, grid_spac); return xf_out; } void xform_to_gpuit_vf ( Xform* xf_out, const Xform *xf_in, const Plm_image_header* pih) { Volume::Pointer vf = Volume::New(); switch (xf_in->m_type) { case XFORM_NONE: print_and_exit ("Sorry, couldn't convert NONE to gpuit_vf\n"); break; case XFORM_ITK_TRANSLATION: vf = xform_itk_any_to_gpuit_vf (xf_in->get_trn(), pih); break; case XFORM_ITK_VERSOR: vf = xform_itk_any_to_gpuit_vf (xf_in->get_vrs(), pih); break; case XFORM_ITK_QUATERNION: vf = xform_itk_any_to_gpuit_vf (xf_in->get_quat(), pih); break; case XFORM_ITK_AFFINE: vf = xform_itk_any_to_gpuit_vf (xf_in->get_aff(), pih); break; case XFORM_ITK_BSPLINE: vf = xform_itk_any_to_gpuit_vf (xf_in->get_itk_bsp(), pih); break; case XFORM_ITK_TPS: vf = xform_itk_any_to_gpuit_vf (xf_in->get_itk_tps(), pih); break; case XFORM_ITK_VECTOR_FIELD: vf = xform_itk_vf_to_gpuit_vf (xf_in->get_itk_vf(), pih); break; case XFORM_GPUIT_BSPLINE: vf = xform_gpuit_bsp_to_gpuit_vf (xf_in, pih); break; case XFORM_GPUIT_VECTOR_FIELD: vf = xform_gpuit_vf_to_gpuit_vf (xf_in->get_gpuit_vf(), pih); break; default: print_and_exit ("Program error. Bad xform type.\n"); break; } //xf_out->set_gpuit_vf (Volume::Pointer(vf)); xf_out->set_gpuit_vf (vf); } Xform::Pointer xform_to_gpuit_vf ( const Xform::Pointer& xf_in, const Plm_image_header* pih) { Xform::Pointer xf_out = Xform::New (); xform_to_gpuit_vf (xf_out.get(), xf_in.get(), pih); return xf_out; } Xform_type Xform::get_type () const { return this->m_type; } void Xform::get_volume_header (Volume_header *vh) { switch (this->m_type) { case XFORM_NONE: case XFORM_ITK_TRANSLATION: case XFORM_ITK_VERSOR: case XFORM_ITK_QUATERNION: case XFORM_ITK_AFFINE: case XFORM_ITK_BSPLINE: case XFORM_ITK_TPS: /* Do nothing */ break; case XFORM_ITK_VECTOR_FIELD: itk_image_get_volume_header (vh, this->get_itk_vf()); break; case XFORM_GPUIT_BSPLINE: { Bspline_xform* bxf = this->get_gpuit_bsp(); bxf->get_volume_header (vh); break; } case XFORM_GPUIT_VECTOR_FIELD: print_and_exit ( "Sorry, didn't implement get_volume_header (type = %d)\n", this->m_type); break; default: print_and_exit ("Sorry, couldn't get_volume_header (type = %d)\n", this->m_type); break; } } Plm_image_header Xform::get_plm_image_header () { Volume_header vh; this->get_volume_header (&vh); return Plm_image_header (vh); } void Xform::get_grid_spacing (float grid_spacing[3]) { switch (this->m_type) { case XFORM_NONE: case XFORM_ITK_TRANSLATION: case XFORM_ITK_VERSOR: case XFORM_ITK_QUATERNION: case XFORM_ITK_AFFINE: /* Do nothing */ break; case XFORM_ITK_BSPLINE: print_and_exit ( "Sorry, didn't implement get_grid_spacing (type = %d)\n", this->m_type); break; case XFORM_ITK_TPS: case XFORM_ITK_VECTOR_FIELD: /* Do nothing */ break; case XFORM_GPUIT_BSPLINE: { Bspline_xform* bxf = this->get_gpuit_bsp(); for (int d = 0; d < 3; d++) { grid_spacing[d] = bxf->grid_spac[d]; } break; } case XFORM_GPUIT_VECTOR_FIELD: /* Do nothing */ break; default: print_and_exit ("Sorry, couldn't get_volume_header (type = %d)\n", this->m_type); break; } } void Xform::print () { switch (this->m_type) { case XFORM_NONE: lprintf ("XFORM_NONE\n"); break; case XFORM_ITK_TRANSLATION: lprintf ("XFORM_ITK_TRANSLATION\n"); std::cout << this->get_trn (); break; case XFORM_ITK_VERSOR: lprintf ("XFORM_ITK_VERSOR\n"); std::cout << this->get_vrs (); break; case XFORM_ITK_QUATERNION: lprintf ("XFORM_ITK_QUATERNION\n"); break; case XFORM_ITK_AFFINE: lprintf ("XFORM_ITK_AFFINE\n"); std::cout << this->get_aff (); break; case XFORM_ITK_BSPLINE: lprintf ("XFORM_ITK_BSPLINE\n"); break; case XFORM_ITK_TPS: lprintf ("XFORM_ITK_TPS\n"); break; case XFORM_ITK_VECTOR_FIELD: lprintf ("XFORM_ITK_VECTOR_FIELD\n"); break; case XFORM_GPUIT_BSPLINE: lprintf ("XFORM_GPUIT_BSPLINE\n"); break; case XFORM_GPUIT_VECTOR_FIELD: lprintf ("XFORM_GPUIT_VECTOR_FIELD\n"); break; default: print_and_exit ("Sorry, couldn't print xform (type = %d)\n", this->m_type); break; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xform.h000066400000000000000000000155701321604176500270450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xform_h_ #define _xform_h_ #include "plmbase_config.h" #include "itkTranslationTransform.h" #include "itkVersorRigid3DTransform.h" #include "itkQuaternionRigidTransform.h" #include "itkAffineTransform.h" #include "itkBSplineDeformableTransform.h" #include "itkThinPlateSplineKernelTransform.h" #include "itkSimilarity3DTransform.h" #include "itk_image_type.h" #include "smart_pointer.h" #include "volume.h" class Bspline_xform; class Plm_image_header; class Volume_header; class Xform; class Xform_private; enum Xform_type { XFORM_NONE = 0, XFORM_ITK_TRANSLATION = 1, XFORM_ITK_VERSOR = 2, XFORM_ITK_QUATERNION = 3, XFORM_ITK_AFFINE = 4, XFORM_ITK_BSPLINE = 5, XFORM_ITK_TPS = 6, XFORM_ITK_VECTOR_FIELD = 7, XFORM_GPUIT_BSPLINE = 8, XFORM_GPUIT_VECTOR_FIELD = 9, XFORM_ITK_SIMILARITY = 10 }; /* itk basic transforms */ typedef itk::TranslationTransform < double, 3 > TranslationTransformType; typedef itk::VersorRigid3DTransform < double > VersorTransformType; typedef itk::QuaternionRigidTransform < double > QuaternionTransformType; typedef itk::AffineTransform < double, 3 > AffineTransformType; typedef itk::Similarity3DTransform SimilarityTransformType; /* itk B-spline transforms */ const unsigned int SplineDimension = 3; const unsigned int SplineOrder = 3; typedef itk::BSplineDeformableTransform < double, SplineDimension, SplineOrder > BsplineTransformType; /* itk thin-plate transforms */ typedef itk::ThinPlateSplineKernelTransform < float, 3 > FloatTpsTransformType; typedef itk::ThinPlateSplineKernelTransform < double, 3 > DoubleTpsTransformType; typedef DoubleTpsTransformType TpsTransformType; class PLMBASE_API Xform { public: SMART_POINTER_SUPPORT (Xform); Xform_private *d_ptr; public: Xform (); ~Xform (); Xform (const Xform& xf); public: Xform_type m_type; /* The actual xform is one of the following. */ TranslationTransformType::Pointer m_trn; VersorTransformType::Pointer m_vrs; AffineTransformType::Pointer m_aff; QuaternionTransformType::Pointer m_quat; DeformationFieldType::Pointer m_itk_vf; BsplineTransformType::Pointer m_itk_bsp; TpsTransformType::Pointer m_itk_tps; SimilarityTransformType::Pointer m_similarity; public: void clear (); void load (const char* fn); void load (const std::string& fn); void save (const char* fn); void save (const std::string& fn); TranslationTransformType::Pointer get_trn () const; VersorTransformType::Pointer get_vrs () const; QuaternionTransformType::Pointer get_quat () const; AffineTransformType::Pointer get_aff () const; SimilarityTransformType::Pointer get_similarity() const; BsplineTransformType::Pointer get_itk_bsp () const; TpsTransformType::Pointer get_itk_tps () const; DeformationFieldType::Pointer get_itk_vf () const; Bspline_xform* get_gpuit_bsp () const; Volume::Pointer& get_gpuit_vf () const; void init_trn (); void set_trn (const itk::Array& trn); void set_trn (TranslationTransformType::Pointer trn); void set_vrs (const itk::Array& vrs); void set_vrs (VersorTransformType::Pointer vrs); void set_quat (const itk::Array& quat); void set_quat (QuaternionTransformType::Pointer quat); void set_aff (const itk::Array& aff); void set_aff (AffineTransformType::Pointer aff); void set_similarity(SimilarityTransformType::Pointer sim); void set_similarity(const itk::Array& sim); void set_itk_bsp (BsplineTransformType::Pointer bsp); void set_itk_tps (TpsTransformType::Pointer tps); void set_itk_vf (DeformationFieldType::Pointer vf); void set_gpuit_bsp (Bspline_xform* xgb); void set_gpuit_vf (const Volume::Pointer& vf); Xform_type get_type () const; void get_volume_header (Volume_header *vh); Plm_image_header get_plm_image_header (); void get_grid_spacing (float grid_spacing[3]); void print (); protected: void save_gpuit_vf (const char* fn); public: Xform& operator= (const Xform& xf); }; PLMBASE_API Xform::Pointer xform_load (const std::string& fn); PLMBASE_API Xform::Pointer xform_load (const char* fn); PLMBASE_API void xform_load (Xform *xf, const std::string& fn); PLMBASE_API void xform_load (Xform *xf, const char* fn); PLMBASE_API void xform_save (Xform *xf, const std::string& fn); PLMBASE_API void xform_save (Xform *xf, const char* fn); PLMBASE_API void xform_itk_bsp_init_default (Xform *xf); PLMBASE_API void xform_itk_bsp_set_grid (Xform *xf, const BsplineTransformType::OriginType bsp_origin, const BsplineTransformType::SpacingType bsp_spacing, const BsplineTransformType::RegionType bsp_region, const BsplineTransformType::DirectionType bsp_direction); PLMBASE_API void xform_to_trn ( Xform *xf_out, const Xform *xf_in, Plm_image_header* pih); PLMBASE_API void xform_to_vrs ( Xform *xf_out, const Xform *xf_in, Plm_image_header* pih); PLMBASE_API void xform_to_quat ( Xform *xf_out, const Xform *xf_in, Plm_image_header* pih); PLMBASE_API void xform_to_aff ( Xform *xf_out, const Xform *xf_in, Plm_image_header* pih); PLMBASE_API void xform_to_similarity ( Xform *xf_out, const Xform *xf_in, Plm_image_header* pih); PLMBASE_API DeformationFieldType::Pointer xform_gpuit_vf_to_itk_vf ( Volume* vf, /* Input */ Plm_image_header* pih /* Input, can be null */ ); PLMBASE_API void xform_to_itk_bsp (Xform *xf_out, const Xform *xf_in, Plm_image_header* pih, const float* grid_spac); PLMBASE_API void xform_to_itk_bsp_nobulk (Xform *xf_out, Xform *xf_in, Plm_image_header* pih, const float* grid_spac); PLMBASE_API void xform_to_itk_vf (Xform* xf_out, Xform *xf_in, Plm_image_header* pih); PLMBASE_API void xform_to_itk_vf (Xform* xf_out, Xform *xf_in, FloatImageType::Pointer image); PLMBASE_API void xform_to_gpuit_bsp (Xform* xf_out, Xform* xf_in, Plm_image_header* pih, const float* grid_spac); PLMBASE_API void xform_to_gpuit_vf (Xform* xf_out, const Xform *xf_in, const Plm_image_header* pih); PLMBASE_API Xform::Pointer xform_to_itk_bsp (const Xform::Pointer& xf_in, Plm_image_header* pih, const float* grid_spac); PLMBASE_API Xform::Pointer xform_to_itk_bsp_nobulk (const Xform::Pointer& xf_in, Plm_image_header* pih, const float* grid_spac); PLMBASE_API Xform::Pointer xform_to_itk_vf (const Xform::Pointer& xf_in, Plm_image_header* pih); PLMBASE_API Xform::Pointer xform_to_gpuit_bsp (const Xform::Pointer& xf_in, Plm_image_header* pih, float* grid_spac); PLMBASE_API Xform::Pointer xform_to_gpuit_vf (const Xform::Pointer& xf_in, const Plm_image_header* pih); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xform_convert.cxx000066400000000000000000000064271321604176500311610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include "plm_image_header.h" #include "plm_int.h" #include "print_and_exit.h" #include "xform.h" #include "xform_convert.h" class Xform_convert_private { public: Xform::Pointer m_xf_out; Xform::Pointer m_xf_in; public: Xform_convert_private () { m_xf_out = Xform::New (); } }; Xform_convert::Xform_convert () { d_ptr = new Xform_convert_private; m_xf_out_type = XFORM_NONE; for (int d = 0; d < 3; d++) { m_grid_spac[d] = 100.f; } m_nobulk = false; } Xform_convert::~Xform_convert () { delete d_ptr; } void Xform_convert::set_input_xform (const Xform::Pointer& xf_in) { d_ptr->m_xf_in = xf_in; } void Xform_convert::run () { Plm_image_header pih; pih.set_from_volume_header (this->m_volume_header); Xform_type xf_in_type = d_ptr->m_xf_in->get_type(); switch (this->m_xf_out_type) { case XFORM_NONE: print_and_exit ("Sorry, couldn't convert to XFORM_NONE\n"); break; case XFORM_ITK_TRANSLATION: print_and_exit ("Sorry, couldn't convert to XFORM_ITK_TRANSLATION\n"); break; case XFORM_ITK_VERSOR: print_and_exit ("Sorry, couldn't convert to XFORM_ITK_VERSOR\n"); break; case XFORM_ITK_AFFINE: print_and_exit ("Sorry, couldn't convert to XFORM_ITK_AFFINE\n"); break; case XFORM_ITK_BSPLINE: if (this->m_grid_spac[0] <= 0.0f) { if (xf_in_type == XFORM_GPUIT_BSPLINE || xf_in_type == XFORM_ITK_BSPLINE) { /* Use grid spacing of input bspline */ if (this->m_nobulk) { d_ptr->m_xf_out = xform_to_itk_bsp_nobulk ( d_ptr->m_xf_in, &pih, 0); } else { printf ("Standard case.\n"); pih.print (); d_ptr->m_xf_out = xform_to_itk_bsp ( d_ptr->m_xf_in, &pih, 0); } } else { print_and_exit ("Sorry, grid spacing cannot be zero\n"); } } else { if (this->m_nobulk) { d_ptr->m_xf_out = xform_to_itk_bsp_nobulk ( d_ptr->m_xf_in, &pih, this->m_grid_spac); } else { d_ptr->m_xf_out = xform_to_itk_bsp ( d_ptr->m_xf_in, &pih, this->m_grid_spac); } } break; case XFORM_ITK_TPS: print_and_exit ("Sorry, couldn't convert to XFORM_ITK_TPS\n"); break; case XFORM_ITK_VECTOR_FIELD: printf ("Converting to (itk) vector field\n"); d_ptr->m_xf_out = xform_to_itk_vf (d_ptr->m_xf_in, &pih); break; case XFORM_GPUIT_BSPLINE: if (this->m_grid_spac[0] <=0.0f) { if (xf_in_type == XFORM_GPUIT_BSPLINE || xf_in_type == XFORM_ITK_BSPLINE) { d_ptr->m_xf_out = xform_to_gpuit_bsp ( d_ptr->m_xf_in, &pih, 0); } else { print_and_exit ("Sorry, grid spacing cannot be zero for conversion to gpuit_bsp\n"); } } else { d_ptr->m_xf_out = xform_to_gpuit_bsp ( d_ptr->m_xf_in, &pih, this->m_grid_spac); } break; case XFORM_GPUIT_VECTOR_FIELD: default: print_and_exit ("Sorry, couldn't convert to xform (type = %d)\n", this->m_xf_out_type); break; } } Xform::Pointer& Xform_convert::get_output_xform () { return d_ptr->m_xf_out; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xform_convert.h000066400000000000000000000013751321604176500306030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xform_convert_h_ #define _xform_convert_h_ #include "plmbase_config.h" #include "volume_header.h" #include "xform.h" class Xform_convert_private; class PLMBASE_API Xform_convert { public: Xform_convert_private *d_ptr; public: Xform_type m_xf_out_type; Volume_header m_volume_header; float m_grid_spac[3]; int m_nobulk; public: Xform_convert (); ~Xform_convert (); public: void run (); void set_input_xform (const Xform::Pointer& xf_in); Xform::Pointer& get_output_xform (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xform_legacy.cxx000066400000000000000000000201751321604176500307410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include "print_and_exit.h" #include "string_util.h" #include "xform.h" #include "xform_legacy.h" /* ----------------------------------------------------------------------- Utility functions ----------------------------------------------------------------------- */ static int get_parms (FILE* fp, itk::Array* parms, int num_parms) { float f; int r, s; s = 0; while ((r = fscanf (fp, "%f",&f))) { (*parms)[s++] = (double) f; if (s == num_parms) break; if (!fp) break; } return s; } /* This is an older xform format that plastimatch used to use. Maybe some users still have some of these, so we can let them load them. */ void xform_legacy_load (Xform *xf, FILE* fp) { char buf[1024]; rewind (fp); fgets (buf,1024,fp); if (plm_strcmp (buf,"ObjectType = MGH_XFORM_TRANSLATION") == 0) { TranslationTransformType::Pointer trn = TranslationTransformType::New(); TranslationTransformType::ParametersType xfp(12); int num_parms; num_parms = get_parms (fp, &xfp, 3); if (num_parms != 3) { print_and_exit ("Wrong number of parameters in xf_in file.\n"); } else { trn->SetParameters(xfp); #if defined (commentout) std::cout << "Initial translation parms = " << trn << std::endl; #endif } xf->set_trn (trn); } else if (plm_strcmp(buf,"ObjectType = MGH_XFORM_VERSOR")==0) { VersorTransformType::Pointer vrs = VersorTransformType::New(); VersorTransformType::ParametersType xfp(6); int num_parms; num_parms = get_parms (fp, &xfp, 6); if (num_parms != 6) { print_and_exit ("Wrong number of parameters in xf_in file.\n"); } else { vrs->SetParameters(xfp); #if defined (commentout) std::cout << "Initial versor parms = " << vrs << std::endl; #endif } xf->set_vrs (vrs); } else if (plm_strcmp(buf,"ObjectType = MGH_XFORM_AFFINE")==0) { AffineTransformType::Pointer aff = AffineTransformType::New(); AffineTransformType::ParametersType xfp(12); int num_parms; num_parms = get_parms (fp, &xfp, 12); if (num_parms != 12) { print_and_exit ("Wrong number of parameters in xf_in file.\n"); } else { aff->SetParameters(xfp); #if defined (commentout) std::cout << "Initial affine parms = " << aff << std::endl; #endif } xf->set_aff (aff); } else if (plm_strcmp (buf, "ObjectType = MGH_XFORM_BSPLINE") == 0) { int s[3]; float p[3]; BsplineTransformType::RegionType::SizeType bsp_size; BsplineTransformType::RegionType bsp_region; BsplineTransformType::SpacingType bsp_spacing; BsplineTransformType::OriginType bsp_origin; BsplineTransformType::DirectionType bsp_direction; /* Initialize direction cosines to identity */ bsp_direction[0][0] = bsp_direction[1][1] = bsp_direction[2][2] = 1.0; /* Create the bspline structure */ xform_itk_bsp_init_default (xf); /* Skip 2 lines */ fgets(buf,1024,fp); fgets(buf,1024,fp); /* Load bulk transform, if it exists */ fgets(buf,1024,fp); if (!strncmp ("BulkTransform", buf, strlen("BulkTransform"))) { TranslationTransformType::Pointer trn = TranslationTransformType::New(); VersorTransformType::Pointer vrs = VersorTransformType::New(); AffineTransformType::Pointer aff = AffineTransformType::New(); itk::Array xfp(12); float f; int n, num_parm = 0; char *p = buf + strlen("BulkTransform = "); while (sscanf (p, " %g%n", &f, &n) > 0) { if (num_parm>=12) { print_and_exit ("Error loading bulk transform\n"); } xfp[num_parm] = f; p += n; num_parm++; } if (num_parm == 12) { aff->SetParameters(xfp); #if defined (commentout) std::cout << "Bulk affine = " << aff; #endif xf->get_itk_bsp()->SetBulkTransform (aff); } else if (num_parm == 6) { vrs->SetParameters(xfp); #if defined (commentout) std::cout << "Bulk versor = " << vrs; #endif xf->get_itk_bsp()->SetBulkTransform (vrs); } else if (num_parm == 3) { trn->SetParameters(xfp); #if defined (commentout) std::cout << "Bulk translation = " << trn; #endif xf->get_itk_bsp()->SetBulkTransform (trn); } else { print_and_exit ("Error loading bulk transform\n"); } fgets(buf,1024,fp); } /* Load origin, spacing, size */ if (3 != sscanf(buf,"Offset = %g %g %g",&p[0],&p[1],&p[2])) { print_and_exit ("Unexpected line in xform_in file.\n"); } bsp_origin[0] = p[0]; bsp_origin[1] = p[1]; bsp_origin[2] = p[2]; fgets(buf,1024,fp); if (3 != sscanf(buf,"ElementSpacing = %g %g %g",&p[0],&p[1],&p[2])) { print_and_exit ("Unexpected line in xform_in file.\n"); } bsp_spacing[0] = p[0]; bsp_spacing[1] = p[1]; bsp_spacing[2] = p[2]; fgets(buf,1024,fp); if (3 != sscanf(buf,"DimSize = %d %d %d",&s[0],&s[1],&s[2])) { print_and_exit ("Unexpected line in xform_in file.\n"); } bsp_size[0] = s[0]; bsp_size[1] = s[1]; bsp_size[2] = s[2]; #if defined (commentout) std::cout << "Offset = " << origin << std::endl; std::cout << "Spacing = " << spacing << std::endl; std::cout << "Size = " << size << std::endl; #endif fgets(buf,1024,fp); if (plm_strcmp (buf, "ElementDataFile = LOCAL")) { print_and_exit ("Error: bspline xf_in failed sanity check\n"); } /* Set the BSpline grid to specified parameters */ bsp_region.SetSize (bsp_size); xform_itk_bsp_set_grid (xf, bsp_origin, bsp_spacing, bsp_region, bsp_direction); /* Read bspline coefficients from file */ const unsigned int num_parms = xf->get_itk_bsp()->GetNumberOfParameters(); BsplineTransformType::ParametersType bsp_coeff; bsp_coeff.SetSize (num_parms); for (unsigned int i = 0; i < num_parms; i++) { float d; if (!fgets(buf,1024,fp)) { print_and_exit ("Missing bspline coefficient from xform_in file.\n"); } if (1 != sscanf(buf,"%g",&d)) { print_and_exit ("Bad bspline parm in xform_in file.\n"); } bsp_coeff[i] = d; } /* Copy into bsp structure */ xf->get_itk_bsp()->SetParametersByValue (bsp_coeff); } else { /* Not a legacy format */ } } /* This is the older xform_save routine for itk b-splines. It is not used */ void xform_legacy_save_itk_bsp ( BsplineTransformType::Pointer transform, const char* filename ) { FILE* fp = fopen (filename,"w"); if (!fp) { printf ("Error: Couldn't open file %s for write\n", filename); return; } fprintf (fp, "ObjectType = MGH_XFORM_BSPLINE\n" "NDims = 3\n" "BinaryData = False\n"); if (transform->GetBulkTransform()) { if ((!strcmp ("TranslationTransform", transform->GetBulkTransform()->GetNameOfClass())) || (!strcmp ("AffineTransform", transform->GetBulkTransform()->GetNameOfClass())) || (!strcmp ("VersorTransform", transform->GetBulkTransform()->GetNameOfClass())) || (!strcmp ("VersorRigid3DTransform", transform->GetBulkTransform()->GetNameOfClass()))) { fprintf (fp, "BulkTransform ="); for (unsigned int i = 0; i < transform->GetBulkTransform()->GetNumberOfParameters(); i++) { fprintf (fp, " %g", transform->GetBulkTransform()->GetParameters()[i]); } fprintf (fp, "\n"); } else if (strcmp("IdentityTransform", transform->GetBulkTransform()->GetNameOfClass())) { printf ("Warning!!! BulkTransform exists. Type=%s\n", transform->GetBulkTransform()->GetNameOfClass()); printf (" # of parameters=%d\n", transform->GetBulkTransform()->GetNumberOfParameters()); printf (" The code currently does not know how to handle this type and will not write the parameters out!\n"); } } fprintf (fp, "Offset = %f %f %f\n" "ElementSpacing = %f %f %f\n" "DimSize = %lu %lu %lu\n" "ElementDataFile = LOCAL\n", transform->GetGridOrigin()[0], transform->GetGridOrigin()[1], transform->GetGridOrigin()[2], transform->GetGridSpacing()[0], transform->GetGridSpacing()[1], transform->GetGridSpacing()[2], transform->GetGridRegion().GetSize()[0], transform->GetGridRegion().GetSize()[1], transform->GetGridRegion().GetSize()[2] ); for (unsigned int i = 0; i < transform->GetNumberOfParameters(); i++) { fprintf (fp, "%g\n", transform->GetParameters()[i]); } fclose (fp); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xform_legacy.h000066400000000000000000000006311321604176500303610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xform_legacy_h_ #define _xform_legacy_h_ #include "plmbase_config.h" #include class Xform; PLMBASE_C_API void xform_legacy_load (Xform *xf, FILE* fp); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xform_point.cxx000066400000000000000000000052411321604176500306230ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "bspline_interpolate.h" #include "itk_image_type.h" #include "itk_point.h" #include "print_and_exit.h" #include "xform.h" #include "xform_point.h" /* ----------------------------------------------------------------------- Transform points ----------------------------------------------------------------------- */ void xform_point_transform_gpuit_bspline ( FloatPoint3DType* itk_point_out, Xform* xf_in, FloatPoint3DType itk_point_in ) { int d; float point_in[3], point_out[3]; for (d = 0; d < 3; d++) { point_in[d] = itk_point_in[d]; } bspline_transform_point (point_out, xf_in->get_gpuit_bsp(), point_in, 1); for (d = 0; d < 3; d++) { (*itk_point_out)[d] = point_out[d]; } } void xform_point_transform_itk_vf ( FloatPoint3DType* point_out, Xform* xf_in, FloatPoint3DType point_in ) { DeformationFieldType::Pointer vf = xf_in->get_itk_vf (); DeformationFieldType::IndexType idx; bool isInside = vf->TransformPhysicalPointToIndex (point_in, idx); if (isInside) { DeformationFieldType::PixelType pixelValue = vf->GetPixel (idx); #if defined (commentout) printf ("pi [%g %g %g]\n", point_in[0], point_in[1], point_in[2]); printf ("idx [%ld %ld %ld]\n", idx[0], idx[1], idx[2]); printf ("vf [%g %g %g]\n", pixelValue[0], pixelValue[1], pixelValue[2]); #endif for (int d = 0; d < 3; d++) { (*point_out)[d] = point_in[d] + pixelValue[d]; } #if defined (commentout) printf ("po [%g %g %g]\n", (*point_out)[0], (*point_out)[1], (*point_out)[2]); #endif } else { (*point_out) = point_in; } } void xform_point_transform ( FloatPoint3DType* point_out, Xform* xf_in, FloatPoint3DType point_in ) { switch (xf_in->m_type) { case XFORM_NONE: case XFORM_ITK_TRANSLATION: case XFORM_ITK_VERSOR: case XFORM_ITK_QUATERNION: case XFORM_ITK_AFFINE: case XFORM_ITK_BSPLINE: case XFORM_ITK_TPS: print_and_exit ( "Sorry, xform_transform_point not defined for type %d\n", xf_in->m_type); break; case XFORM_ITK_VECTOR_FIELD: xform_point_transform_itk_vf (point_out, xf_in, point_in); break; case XFORM_GPUIT_BSPLINE: xform_point_transform_gpuit_bspline (point_out, xf_in, point_in); break; case XFORM_GPUIT_VECTOR_FIELD: default: print_and_exit ( "Sorry, xform_transform_point not defined for type %d\n", xf_in->m_type); break; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xform_point.h000066400000000000000000000007201321604176500302450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xform_point_h_ #define _xform_point_h_ #include "plmbase_config.h" #include "itk_point.h" class Xform; PLMBASE_C_API void xform_point_transform (FloatPoint3DType* point_out, Xform* xf_in, FloatPoint3DType point_in); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_ct.cxx000066400000000000000000000155271321604176500275540ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include #include #include #include "itkDirectory.h" #include "itkRegularExpressionSeriesFileNames.h" #include "metadata.h" #include "plm_endian.h" #include "plm_image.h" #include "print_and_exit.h" #include "volume.h" #include "xio_ct.h" #include "xio_ct_transform.h" #include "xio_studyset.h" typedef struct xio_ct_header Xio_ct_header; struct xio_ct_header { float slice_size[2]; int dim[2]; int bit_depth; float spacing[2]; float z_loc; }; static void xio_ct_load_header (Xio_ct_header *xch, const char *filename) { /* Open file */ std::ifstream ifs (filename, std::ifstream::in); if (ifs.fail()) { print_and_exit ("Error opening file %s for read\n", filename); } /* Get version */ std::string line; getline (ifs, line); int rc, xio_ct_version; rc = sscanf (line.c_str(), "%x", &xio_ct_version); if (rc != 1) { /* Couldn't parse version string -- default to oldest format. */ xio_ct_version = 0x00071015; } /* Skip lines */ getline (ifs, line); getline (ifs, line); getline (ifs, line); getline (ifs, line); /* Get slice location */ if (!getline (ifs, line)) { print_and_exit ("Error reading slice location\n"); } rc = sscanf (line.c_str(), "%g", &xch->z_loc); if (rc != 1) { print_and_exit ("Error parsing slice location (%s)\n", line.c_str()); } /* Skip 3 lines */ getline (ifs, line); getline (ifs, line); getline (ifs, line); /* Get slice width, height */ if (!getline (ifs, line)) { print_and_exit ("Error reading slice width, height"); } rc = sscanf (line.c_str(), "%g,%g", &xch->slice_size[0], &xch->slice_size[1]); if (rc != 2) { print_and_exit ("Error parsing slice width (%s)\n", line.c_str()); } /* Get image resolution */ if (!getline (ifs, line)) { print_and_exit ("Error reading image resolution"); } rc = sscanf (line.c_str(), "%d,%d,%d", &xch->dim[0], &xch->dim[1], &xch->bit_depth); if (rc != 3) { print_and_exit ("Error parsing image resolution (%s)\n", line.c_str()); } /* Skip 9 lines */ getline (ifs, line); getline (ifs, line); getline (ifs, line); getline (ifs, line); getline (ifs, line); getline (ifs, line); getline (ifs, line); getline (ifs, line); getline (ifs, line); /* Get pixel size */ if (!getline (ifs, line)) { print_and_exit ("Error reading pixel size\n"); } rc = sscanf (line.c_str(), "%g,%g", &xch->spacing[0], &xch->spacing[1]); if (rc != 2) { print_and_exit ("Error parsing pixel size (%s)\n", line.c_str()); } /* EPF files have a zero as the second spacing. Fudge these. */ if (xch->spacing[1] == 0.f) { xch->spacing[1] = xch->spacing[0]; } printf ("%g %g %d %d %g %g %g\n", xch->slice_size[0], xch->slice_size[1], xch->dim[0], xch->dim[1], xch->spacing[0], xch->spacing[1], xch->z_loc); } static void xio_ct_load_image ( Plm_image *pli, int slice_no, const char *filename ) { FILE *fp; Volume *v; short *img, *slice_img; int rc1; size_t rc2; v = pli->get_vol (); img = (short*) v->img; slice_img = &img[slice_no * v->dim[0] * v->dim[1]]; fp = fopen (filename, "rb"); if (!fp) { print_and_exit ("Error opening file %s for read\n", filename); } /* Load image */ rc1 = fseek (fp, - v->dim[0] * v->dim[1] * sizeof(short), SEEK_END); if (rc1 == -1) { print_and_exit ("Error seeking backward when reading image file\n"); } rc2 = fread (slice_img, sizeof(short), v->dim[0] * v->dim[1], fp); if (rc2 != (size_t) (v->dim[0] * v->dim[1])) { perror ("File error: "); print_and_exit ( "Error reading xio ct image (%s)\n" " rc = %u, ferror = %d\n", filename, (unsigned int) rc2, ferror (fp)); } /* Switch big-endian to native */ endian2_big_to_native ((void*) slice_img, v->dim[0] * v->dim[1]); /* Some older versions of xio set invalid pixels to -32768, while newer versions use -1030. Seemingly... not enough test data to be sure. Anyway, fudge the values so it looks good. */ for (int i = 0; i < v->dim[0] * v->dim[1]; i++) { if (slice_img[i] < -1030) { slice_img[i] = -1030; } } fclose (fp); } static void xio_ct_create_volume ( Plm_image *pli, Xio_ct_header *xch, int z_dim, float z_origin, float z_spacing ) { Volume *v; plm_long dim[3]; float origin[3]; float spacing[3]; dim[0] = xch->dim[0]; dim[1] = xch->dim[1]; dim[2] = z_dim; origin[0] = - xch->slice_size[0]; origin[1] = - xch->slice_size[1]; origin[2] = z_origin; spacing[0] = xch->spacing[0]; spacing[1] = xch->spacing[1]; spacing[2] = z_spacing; v = new Volume (dim, origin, spacing, 0, PT_SHORT, 1); pli->set_volume (v); printf ("img: %p\n", v->img); printf ("Image dim: %u %u %u\n", (unsigned int) v->dim[0], (unsigned int) v->dim[1], (unsigned int) v->dim[2]); } void xio_ct_load (Plm_image *pli, Xio_studyset *studyset) { int i; Xio_ct_header xch; std::string ct_file; if (studyset->number_slices > 0) { ct_file = studyset->studyset_dir + "/" + studyset->slices[0].filename_scan.c_str(); xio_ct_load_header (&xch, ct_file.c_str()); float z_origin = 0.0; if (studyset->slices.size() > 0) { z_origin = studyset->slices[0].location; } xio_ct_create_volume (pli, &xch, studyset->number_slices, z_origin, studyset->thickness); for (i = 0; i < studyset->number_slices; i++) { ct_file = studyset->studyset_dir + "/" + studyset->slices[i].filename_scan.c_str(); xio_ct_load_image (pli, i, ct_file.c_str()); } } /* The code that loads the structure set needs the ct pixel spacing too, so save that. */ studyset->ct_pixel_spacing[0] = xch.spacing[0]; studyset->ct_pixel_spacing[1] = xch.spacing[1]; } void xio_ct_apply_transform (Plm_image *pli, Xio_ct_transform *transform) { /* Transform coordinates of an XiO CT scan to DICOM coordinates */ Volume *v = pli->get_vol (); /* Set origins */ v->origin[0] = (v->origin[0] * transform->direction_cosines[0]) + transform->x_offset; v->origin[1] = (v->origin[1] * transform->direction_cosines[4]) + transform->y_offset; /* Set direction cosines */ v->set_direction_cosines (transform->direction_cosines); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_ct.h000066400000000000000000000010201321604176500271600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xio_ct_h_ #define _xio_ct_h_ #include "plmbase_config.h" class Plm_image; class Xio_ct_transform; class Xio_studyset; PLMBASE_API void xio_ct_load (Plm_image *plm, Xio_studyset *xio_studyset); PLMBASE_API void xio_ct_apply_transform (Plm_image *plm, Xio_ct_transform *transform); #endif xio_ct_transform.cxx000066400000000000000000000104451321604176500315620ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include #include #include "itkDirectory.h" #include "itkRegularExpressionSeriesFileNames.h" #include "metadata.h" #include "plm_endian.h" #include "plm_image.h" #include "plm_image_header.h" #include "print_and_exit.h" #include "rt_study_metadata.h" #include "volume.h" #include "xio_ct.h" #include "xio_ct_transform.h" #include "xio_studyset.h" Xio_ct_transform::Xio_ct_transform () { this->set ("HFS"); } Xio_ct_transform::Xio_ct_transform (const Metadata::Pointer& meta) { this->set (meta); } void Xio_ct_transform::set (const Metadata::Pointer& meta) { std::string ppos = meta->get_metadata(0x0018, 0x5100); this->set (ppos.c_str()); } void Xio_ct_transform::set (const char* ppos) { /* Use patient position to determine the transformation from XiO coordinates to a valid set of DICOM coordinates. The origin of the DICOM coordinates will be the same as the origin of the XiO coordinates, which is generally not the same as the origin of the original DICOM CT scan. */ /* Offsets */ this->x_offset = 0; this->y_offset = 0; /* Direction cosines */ for (int i = 0; i <= 8; i++) { this->direction_cosines[i] = 0.; } this->direction_cosines[0] = 1.0f; this->direction_cosines[4] = 1.0f; this->direction_cosines[8] = 1.0f; std::string patient_pos = "HFS"; if (ppos) { patient_pos = ppos; } if (patient_pos == "HFS" || patient_pos == "") { this->direction_cosines[0] = 1.0f; this->direction_cosines[4] = 1.0f; this->direction_cosines[8] = 1.0f; } else if (patient_pos == "HFP") { this->direction_cosines[0] = -1.0f; this->direction_cosines[4] = -1.0f; this->direction_cosines[8] = 1.0f; } else if (patient_pos == "FFS") { this->direction_cosines[0] = -1.0f; this->direction_cosines[4] = 1.0f; this->direction_cosines[8] = -1.0f; } else if (patient_pos == "FFP") { this->direction_cosines[0] = 1.0f; this->direction_cosines[4] = -1.0f; this->direction_cosines[8] = -1.0f; } } void Xio_ct_transform::set_from_rdd ( Plm_image *pli, Rt_study_metadata *rsm) { /* Use original XiO CT geometry and a DICOM directory to determine the transformation from XiO coordinates to DICOM coordinates. */ Volume *v = pli->get_vol (); /* Offsets */ this->x_offset = 0; this->y_offset = 0; /* Direction cosines */ for (int i = 0; i <= 8; i++) { this->direction_cosines[i] = 0.; } this->direction_cosines[0] = 1.0f; this->direction_cosines[4] = 1.0f; this->direction_cosines[8] = 1.0f; Metadata::Pointer& meta = rsm->get_image_metadata (); const Plm_image_header *pih = rsm->get_image_header (); std::string patient_pos = meta->get_metadata(0x0018, 0x5100); if (patient_pos == "HFS" || patient_pos == "") { /* Offsets */ this->x_offset = v->origin[0] - pih->origin(0); this->y_offset = v->origin[1] - pih->origin(1); /* Direction cosines */ this->direction_cosines[0] = 1.0f; this->direction_cosines[4] = 1.0f; this->direction_cosines[8] = 1.0f; } else if (patient_pos == "HFP") { /* Offsets */ this->x_offset = v->origin[0] + pih->origin(0); this->y_offset = v->origin[1] + pih->origin(1); /* Direction cosines */ this->direction_cosines[0] = -1.0f; this->direction_cosines[4] = -1.0f; this->direction_cosines[8] = 1.0f; } else if (patient_pos == "FFS") { /* Offsets */ this->x_offset = v->origin[0] + pih->origin(0); this->y_offset = v->origin[1] - pih->origin(1); /* Direction cosines */ this->direction_cosines[0] = -1.0f; this->direction_cosines[4] = 1.0f; this->direction_cosines[8] = -1.0f; } else if (patient_pos == "FFP") { /* Offsets */ this->x_offset = v->origin[0] - pih->origin(0); this->y_offset = v->origin[1] + pih->origin(1); /* Direction cosines */ this->direction_cosines[0] = 1.0f; this->direction_cosines[4] = -1.0f; this->direction_cosines[8] = -1.0f; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_ct_transform.h000066400000000000000000000013661321604176500312700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xio_ct_transform_h_ #define _xio_ct_transform_h_ #include "plmbase_config.h" class Metadata; class Plm_image; class Rt_study_metadata; class PLMBASE_API Xio_ct_transform { public: float direction_cosines[9]; float x_offset; float y_offset; public: Xio_ct_transform (); Xio_ct_transform (const Metadata::Pointer& meta); public: void set (const Metadata::Pointer& meta); void set (const char* ppos); void set_from_rdd ( Plm_image *pli, Rt_study_metadata *rsm); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_demographic.cxx000066400000000000000000000022421321604176500314160ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include "print_and_exit.h" #include "string_util.h" #include "xio_demographic.h" Xio_demographic::Xio_demographic (const char *filename) { std::ifstream ifs (filename); if (ifs.fail()) { print_and_exit ("Error opening file %s for read\n", filename); } /* version string 00011017 - pxio version 4.2 */ std::string version; getline (ifs, version); /* important stuff here */ getline (ifs, m_import_date); m_import_date = string_trim (m_import_date); if (m_import_date.length() >= 8) { m_import_date = m_import_date.substr(0,8); } else { m_import_date = ""; } getline (ifs, m_patient_name); m_patient_name = string_trim (m_patient_name); getline (ifs, m_patient_id); m_patient_id = string_trim (m_patient_id); } Xio_demographic::~Xio_demographic () { } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_demographic.h000066400000000000000000000010551321604176500310440ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xio_demographic_h_ #define _xio_demographic_h_ #include "plmbase_config.h" #include class PLMBASE_API Xio_demographic { public: std::string m_patient_name; std::string m_patient_id; std::string m_import_date; public: Xio_demographic (const char *filename); ~Xio_demographic (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_dir.cxx000066400000000000000000000130701321604176500277130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include #include #include "itkDirectory.h" #include "file_util.h" #include "path_util.h" #include "xio_dir.h" #include "xio_patient.h" #include "xio_plan.h" /* ----------------------------------------------------------------------- Private functions ----------------------------------------------------------------------- */ int Xio_dir::is_xio_patient_dir (std::string dir) { itksys::Directory itk_dir; if (!itk_dir.Load (dir.c_str())) { return 0; } /* A patient directory has either an anatomy or a plan directory */ for (unsigned long i = 0; i < itk_dir.GetNumberOfFiles(); i++) { std::string curr_file = itk_dir.GetFile(i); std::string curr_path = dir + "/" + itk_dir.GetFile(i); if (itksys::SystemTools::FileIsDirectory (curr_path.c_str())) { if (curr_file == "anatomy") return 1; if (curr_file == "plan") return 1; } } return 0; } int Xio_dir::is_xio_studyset_dir (std::string dir) { itksys::Directory itk_dir; if (!itk_dir.Load (dir.c_str())) { return 0; } /* A studyset directory has either a *.CT file or a *.WC file */ for (unsigned long i = 0; i < itk_dir.GetNumberOfFiles(); i++) { std::string curr_file = itk_dir.GetFile(i); std::string curr_path = dir + "/" + itk_dir.GetFile(i); if (itksys::SystemTools::FileIsDirectory (curr_path.c_str())) { continue; } if (extension_is (curr_file.c_str(), ".WC")) return 1; if (extension_is (curr_file.c_str(), ".CT")) return 1; } return 0; } int Xio_dir::is_xio_plan_dir (const std::string& dir) { itksys::Directory itk_dir; if (!itk_dir.Load (dir.c_str())) { return 0; } /* A plan directory has a plan file */ for (unsigned long i = 0; i < itk_dir.GetNumberOfFiles(); i++) { std::string curr_file = itk_dir.GetFile(i); std::string curr_path = dir + "/" + itk_dir.GetFile(i); if (itksys::SystemTools::FileIsDirectory (curr_path.c_str())) { continue; } if (curr_file == "plan") return 1; } return 0; } Xio_patient* Xio_dir::add_patient_dir (std::string dir) { Xio_patient *xpd = new Xio_patient (dir.c_str()); this->patient_dir.push_back (xpd); return xpd; } void Xio_dir::analyze_recursive (std::string dir) { itksys::Directory itk_dir; if (!itk_dir.Load (dir.c_str())) { return; } /* Look for top-level patient directory */ if (is_xio_patient_dir (dir)) { printf ("Found plan dir\n"); Xio_patient *xpd = this->add_patient_dir (dir); xpd->analyze (); std::string demographic_file = dir + "/demographic"; if (file_exists (demographic_file.c_str())) { xpd->m_demographic_fn = demographic_file.c_str(); } return; } /* Look for plan directories. GCS FIX: Each plan counts as a separate patient */ else if (is_xio_plan_dir (dir)) { Xio_patient *xpd = this->add_patient_dir (dir); xpd->add_plan_dir (dir); std::string demographic_file = dir + "/../../demographic"; if (file_exists (demographic_file.c_str())) { xpd->m_demographic_fn = demographic_file.c_str(); } return; } /* Look for studyset directories. GCS FIX: Each studyset counts as a separate patient */ else if (is_xio_studyset_dir (dir)) { Xio_patient *xpd = this->add_patient_dir (dir); xpd->add_studyset_dir (dir); std::string demographic_file = dir + "/../../../demographic"; if (file_exists (demographic_file.c_str())) { xpd->m_demographic_fn = demographic_file.c_str(); } return; } for (unsigned long i = 0; i < itk_dir.GetNumberOfFiles(); i++) { std::string curr_file = itk_dir.GetFile(i); std::string curr_path = dir + "/" + itk_dir.GetFile(i); if (curr_file == "." || curr_file == "..") continue; if (itksys::SystemTools::FileIsDirectory (curr_path.c_str())) { this->analyze_recursive (curr_path); } } } /* ----------------------------------------------------------------------- Public functions ----------------------------------------------------------------------- */ Xio_dir::Xio_dir (const char *input_dir) { this->path = input_dir; this->analyze (); } Xio_dir::~Xio_dir () { std::vector::iterator it; for (it = this->patient_dir.begin(); it < this->patient_dir.end(); ++it) { delete *it; } } void Xio_dir::analyze () { if (!is_directory (this->path)) { return; } this->analyze_recursive (this->path); } int Xio_dir::num_patients () const { return (int) this->patient_dir.size(); } std::string xio_plan_dir_get_studyset_dir (const std::string& xio_plan_dir) { std::string studyset_dir; std::string plan_dir; std::string patient_dir; if (Xio_dir::is_xio_plan_dir (xio_plan_dir)) { /* Get studyset name from plan */ std::string plan_file = xio_plan_dir + "/plan"; printf ("plan_file: %s\n", plan_file.c_str()); studyset_dir = xio_plan_get_studyset (plan_file.c_str()); /* Obtain patient directory from plan directory */ plan_dir = file_util_parent (xio_plan_dir); patient_dir = file_util_parent (plan_dir); printf ("plan_dir: %s\n", plan_file.c_str()); printf ("patient_dir: %s\n", patient_dir.c_str()); /* Set studyset directory */ studyset_dir = std::string(patient_dir) + "/anatomy/studyset/" + studyset_dir; } return studyset_dir; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_dir.h000066400000000000000000000022251321604176500273400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xio_dir_h #define _xio_dir_h #include "plmbase_config.h" #include class Xio_patient; struct Xio_studyset_dir; struct Xio_plan_dir; /* This class represents the input directory, which could be a patient directory, plan directory, or even a directory which contains multiple patients */ class PLMBASE_API Xio_dir { public: std::string path; std::vector patient_dir; public: Xio_dir (const char *input_dir); ~Xio_dir (); void analyze (); void analyze_recursive (std::string dir); Xio_patient* add_patient_dir (std::string dir); int num_patients () const; public: static int is_xio_patient_dir (std::string dir); static int is_xio_studyset_dir (std::string dir); static int is_xio_plan_dir (const std::string& dir); }; PLMBASE_API int xio_dir_num_patients (Xio_dir* xd); PLMBASE_API std::string xio_plan_dir_get_studyset_dir (const std::string& xtpd); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_dose.cxx000066400000000000000000000326761321604176500301040ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include #include #include #include #include "itkDirectory.h" #include "itkRegularExpressionSeriesFileNames.h" #include "file_util.h" #include "metadata.h" #include "plm_endian.h" #include "plm_image.h" #include "print_and_exit.h" #include "volume.h" #include "xio_ct.h" #include "xio_ct_transform.h" #include "xio_dose.h" #include "xio_studyset.h" #define XIO_DATATYPE_UINT32 5 typedef struct xio_dose_header Xio_dose_header; struct xio_dose_header { plm_long dim[3]; float origin[3]; float spacing[3]; double dose_scale_factor; double dose_weight; int header_size; int header_pos_start_geometry; int header_pos_end_geometry; }; static void xio_dose_load_header (Xio_dose_header *xdh, const char *filename) { FILE *fp; int i; int rc; int dummy; /* Header info */ int xio_dose_version; int xio_dose_datatype; int xio_sources; double xio_dose_scalefactor, xio_dose_weight; /* Dose cube definition */ double rx; double ry; double rz; double ox; double oy; double oz; int nx; int ny; int nz; /* Element spacing */ double dx; double dy; double dz; /* Origin */ double topx; double topy; double topz; char line1[1024]; fp = fopen (filename, "rb"); if (!fp) { print_and_exit ("Error opening file %s for read\n", filename); } /* XiO file format version */ fgets (line1, sizeof(line1), fp); rc = sscanf ((const char*) line1, "%x", &xio_dose_version); if (rc != 1) { /* Couldn't parse version string -- default to oldest known format. */ xio_dose_version = 0x0037101e; } /* Skip line */ fgets (line1, sizeof(line1), fp); if (xio_dose_version >= 0x0062101e) { /* Skip line */ fgets (line1, sizeof(line1), fp); } /* Number of subplans or beams */ fgets (line1, sizeof(line1), fp); rc = sscanf (line1, "%d", &xio_sources); if (rc != 1) { print_and_exit ("Error. Cannot parse sources/subplans: %s\n", line1); } printf ("Dose file is a sum of %d sources/subplans:\n", xio_sources); /* One line for each source/subplan */ for (i = 1; i <= xio_sources; i++) { fgets (line1, sizeof(line1), fp); printf ("Source/subplan %d: %s", i, line1); } /* Dose normalization info */ fgets (line1, sizeof(line1), fp); rc = sscanf (line1, "%lf,%lf", &xio_dose_scalefactor, &xio_dose_weight); if (rc != 2) { print_and_exit ("Error. Cannot parse dose normalization: %s\n", line1); } printf ("Dose scale factor = %f\n", xio_dose_scalefactor); printf ("Dose weight = %f\n", xio_dose_weight); /* Skip line */ fgets (line1, sizeof(line1), fp); /* Data type */ fgets (line1, sizeof(line1), fp); rc = sscanf (line1, "%1d", &xio_dose_datatype); if (rc != 1) { print_and_exit ("Error. Cannot parse datatype: %s\n", line1); } if (xio_dose_datatype != XIO_DATATYPE_UINT32) { print_and_exit ("Error. Only unsigned 32-bit integer data is currently supported: %s\n", line1); } /* Set start position of geometry */ xdh->header_pos_start_geometry = ftell(fp); /* Dose cube definition */ fgets (line1, sizeof(line1), fp); rc = sscanf (line1, "%d,%lf,%lf,%lf,%lf,%lf,%lf,%d,%d,%d", &dummy, &rx, &rz, &ry, &ox, &oz, &oy, &nx, &nz, &ny); if (rc != 10) { print_and_exit ("Error. Cannot parse dose cube definition: %s\n", line1); } printf ("rx = %lf, ry = %lf, rz = %lf\n", rx, ry, rz); printf ("ox = %lf, oy = %lf, oz = %lf\n", ox, oy, oz); printf ("nx = %d, ny = %d, nz = %d\n", nx, ny, nz); /* Set end position of geometry */ xdh->header_pos_end_geometry = ftell(fp); /* Calculate element spacing */ dx = rx / (nx - 1); dy = ry / (ny - 1); dz = rz / (nz - 1); /* Calculate origin */ /* ND 12/18/2014 - something does not work for dose placement, there is a * half a voxel origin. The values in the grid geometry are not defined at * the top of the voxel but the center. */ //topx = ox - (rx / 2); //topy = oy - (ry / 2); //topz = -oz - (rz / 2); topx = ox - rx/2 - dx/4; topy = oy - ry/2; topz = -oz - rz/2 - dz/4; /* Put info into header */ xdh->dim[0] = nx; xdh->dim[1] = nz; xdh->dim[2] = ny; xdh->spacing[0] = dx; xdh->spacing[1] = dz; xdh->spacing[2] = dy; xdh->origin[0] = topx; xdh->origin[1] = topz; xdh->origin[2] = topy; xdh->dose_scale_factor = xio_dose_scalefactor; xdh->dose_weight = xio_dose_weight; /* Get size of full header */ rc = fseek(fp, - nx * ny * nz * sizeof (uint32_t), SEEK_END); if (rc == -1) { print_and_exit ("Error seeking backward when reading XiO dose header\n"); } xdh->header_size = ftell(fp); fclose (fp); } static void xio_dose_load_cube ( Plm_image *pli, Xio_dose_header *xdh, const char *filename ) { FILE *fp; Volume *v; uint32_t *cube_img_read; plm_long i, j, k; int rc1; size_t rc2; v = pli->get_vol (); cube_img_read = (uint32_t*) v->img; fp = fopen (filename, "rb"); if (!fp) { print_and_exit ("Error opening file %s for read\n", filename); } /* Read dose cube */ rc1 = fseek (fp, - v->dim[0] * v->dim[1] * v->dim[2] * sizeof(uint32_t), SEEK_END); if (rc1 == -1) { print_and_exit ("Error seeking backward when reading image file\n"); } rc2 = fread (cube_img_read, sizeof(uint32_t), v->dim[0] * v->dim[1] * v->dim[2], fp); if (rc2 != (size_t) (v->dim[0] * v->dim[1] * v->dim[2])) { perror ("File error: "); print_and_exit ( "Error reading xio dose cube (%s)\n" " rc = %u, ferror = %d\n", filename, (unsigned int) rc2, ferror (fp)); } /* Switch big-endian to native */ #if defined (commentout) for (i = 0; i < v->dim[0] * v->dim[1] * v->dim[2]; i++) { char lenbuf[4]; char tmpc; memcpy (lenbuf, (char*) &cube_img_read[i], 4); tmpc = lenbuf[0]; lenbuf[0] = lenbuf[3]; lenbuf[3] = tmpc; tmpc = lenbuf[1]; lenbuf[1] = lenbuf[2]; lenbuf[2] = tmpc; memcpy ((char*) &cube_img_read[i], lenbuf, 4); } #endif endian4_big_to_native ((void*) cube_img_read, v->dim[0] * v->dim[1] * v->dim[2]); /* Flip XiO Z axis */ Volume* vflip; vflip = new Volume (v->dim, v->origin, v->spacing, v->direction_cosines, v->pix_type, 1); for (k=0;kdim[2];k++) { for (j=0;jdim[1];j++) { for (i=0;idim[0];i++) { memcpy ((float*)vflip->img + volume_index (vflip->dim, i, (vflip->dim[1]-1-j), k), (float*)v->img + volume_index (v->dim, i, j, k), v->pix_size); } } } pli->set_volume (vflip); /* GCS 2011-01-24: No need to call volume_destroy(v) because set_gpuit() will destroy an existing volume */ /* Convert volume to float for more accurate normalization */ pli->convert (PLM_IMG_TYPE_GPUIT_FLOAT); /* Normalize dose. Factor 0.01 is to convert from cGy to Gy */ vflip->scale_inplace (xdh->dose_weight * xdh->dose_scale_factor * 0.01); fclose (fp); } static void xio_dose_create_volume ( Plm_image *pli, Xio_dose_header *xdh ) { Volume *v; v = new Volume (xdh->dim, xdh->origin, xdh->spacing, 0, PT_UINT32, 1); pli->set_volume (v); printf ("img: %p\n", v->img); printf ("Image dim: %ld %ld %ld\n", (long) v->dim[0], (long) v->dim[1], (long) v->dim[2]); } void xio_dose_load ( Plm_image *pli, Metadata::Pointer& meta, const char *filename ) { Xio_dose_header xdh; xio_dose_load_header (&xdh, filename); xio_dose_create_volume (pli, &xdh); xio_dose_load_cube (pli, &xdh, filename); /* GCS FIX: The below seems to be hard coded for pXiO? */ /* XiO dose is in Gy RBE */ if (meta->get_metadata(0x3004, 0x0004) == ""){ meta->set_metadata(0x3004, 0x0004, "EFFECTIVE"); } } void xio_dose_save ( const Plm_image::Pointer& pli, Metadata::Pointer& meta, Xio_ct_transform *transform, const char *filename, const char *filename_template ) { /* Because XiO dose files can contain huge amounts of information, most of which is not used by plastimatch, the only feasible saving method is to copy over the header from the input dose file. This means that saving XiO dose is only possible when the input is also XiO dose. The line in the dose header that defines is geometry will be adjusted to the new geometry */ FILE *fp, *fpt; Xio_dose_header xdh; plm_long i, j, k; char header; size_t result; Volume::Pointer v = pli->get_volume_float (); /* Dose cube definition */ double rx; double ry; double rz; double ox; double oy; double oz; int nx; int ny; int nz; make_parent_directories (filename); fp = fopen (filename, "wb"); if (!fp) { print_and_exit ("Error opening file %s for write\n", filename); } fpt = fopen (filename_template, "rb"); if (!fpt) { print_and_exit ("Error opening file %s for read\n", filename_template); } xio_dose_load_header(&xdh, filename_template); /* Write first part of header */ for (i = 0; i < xdh.header_size; i++) { result = fread (&header, sizeof(header), 1, fpt); if (result != 1) { print_and_exit ("Error. Cannot read dose template header (1).\n"); } fwrite (&header, sizeof(header), 1, fp); } /* Write dose cube definition */ rx = v->spacing[0] * (v->dim[0] - 1); ry = v->spacing[2] * (v->dim[2] - 1); rz = v->spacing[1] * (v->dim[1] - 1); ox = (v->origin[0] + (rx / 2)) - transform->x_offset; oy = (v->origin[2] + (ry / 2)) - transform->y_offset; oz = - (v->origin[1] + (rz / 2)); std::string patient_pos = meta->get_metadata(0x0018, 0x5100); if (patient_pos == "HFS" || patient_pos == "") { ox = ox * v->direction_cosines[0]; oy = oy * v->direction_cosines[8]; oz = oz * v->direction_cosines[4]; } else if (patient_pos == "HFP") { ox = - ox * v->direction_cosines[0]; oy = oy * v->direction_cosines[8]; oz = - oz * v->direction_cosines[4]; } else if (patient_pos == "FFS") { ox = - ox * v->direction_cosines[0]; oy = - oy * v->direction_cosines[8]; oz = oz * v->direction_cosines[4]; } else if (patient_pos == "FFP") { ox = ox * v->direction_cosines[0]; oy = - oy * v->direction_cosines[8]; oz = - oz * v->direction_cosines[4]; } nx = v->dim[0]; ny = v->dim[2]; nz = v->dim[1]; fprintf (fp, "%d,%lf,%lf,%lf,%lf,%lf,%lf,%d,%d,%d\n", 0, rx, rz, ry, ox, oz, oy, nx, nz, ny); /* Write second part of header */ fseek (fpt, xdh.header_pos_end_geometry, SEEK_SET); for (i = 0; i < xdh.header_size - xdh.header_pos_end_geometry; i++) { result = fread (&header, sizeof(header), 1, fpt); if (result != 1) { print_and_exit ("Error. Cannot read dose template header (2).\n"); } fwrite (&header, sizeof(header), 1, fp); } /* Create new volume for output */ Volume* v_write; v_write = new Volume (v->dim, v->origin, v->spacing, v->direction_cosines, v->pix_type, v->vox_planes); /* Clone volume and flip XiO Z axis */ for (k = 0; k < v->dim[2]; k++) { for (j=0;jdim[1];j++) { for (i=0;idim[0];i++) { memcpy ((float*)v_write->img + volume_index (v_write->dim, i, (v_write->dim[1]-1-j), k), (float*)v->img + volume_index (v->dim, i, j, k), v->pix_size); } } } /* Convert to floating point */ volume_convert_to_float (v_write); /* Apply normalization backwards */ v_write->scale_inplace ( 1 / (xdh.dose_weight * xdh.dose_scale_factor * 0.01)); /* Convert to unsigned 32-bit integer */ volume_convert_to_uint32 (v_write); uint32_t *cube_img_write = (uint32_t*) v_write->img; /* Switch native to big-endian */ #if defined (commentout) for (i = 0; i < v_write->dim[0] * v_write->dim[1] * v_write->dim[2]; i++) { char lenbuf[4]; char tmpc; memcpy (lenbuf, (char*) &cube_img_write[i], 4); tmpc = lenbuf[0]; lenbuf[0] = lenbuf[3]; lenbuf[3] = tmpc; tmpc = lenbuf[1]; lenbuf[1] = lenbuf[2]; lenbuf[2] = tmpc; memcpy ((char*) &cube_img_write[i], lenbuf, 4); } #endif endian4_native_to_big ((void*) cube_img_write, v->dim[0] * v->dim[1] * v->dim[2]); /* Write dose cube */ /* FIX: Not taking direction cosines into account */ result = fwrite (cube_img_write, sizeof(uint32_t), v_write->dim[0] * v_write->dim[1] * v_write->dim[2], fp); if (result != (size_t) (v_write->dim[0] * v_write->dim[1] * v_write->dim[2])) { print_and_exit ("Error. Cannot write dose cube to %s.\n", filename); } fclose(fp); fclose(fpt); delete v_write; } void xio_dose_apply_transform (Plm_image *pli, Xio_ct_transform *transform) { /* Transform coordinates of XiO dose cube to DICOM coordinates */ Volume *v = pli->get_vol (); /* Set origins */ v->origin[0] = (v->origin[0] * transform->direction_cosines[0]) + transform->x_offset; v->origin[1] = (v->origin[1] * transform->direction_cosines[4]) + transform->y_offset; /* Set direction cosines */ v->set_direction_cosines (transform->direction_cosines); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_dose.h000066400000000000000000000014001321604176500275060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xio_dose_h_ #define _xio_dose_h_ #include "plmbase_config.h" class Metadata; class Plm_image; class Xio_ct_transform; PLMBASE_API void xio_dose_load ( Plm_image *plm, Metadata::Pointer& meta, const char *filename ); PLMBASE_API void xio_dose_save ( const Plm_image::Pointer& plm, Metadata::Pointer& meta, Xio_ct_transform *transform, const char *filename, const char *filename_template ); PLMBASE_API void xio_dose_apply_transform ( Plm_image *plm, Xio_ct_transform *transform ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_patient.cxx000066400000000000000000000035661321604176500306120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include #include #include "itkDirectory.h" #include "xio_dir.h" #include "xio_patient.h" Xio_patient::Xio_patient ( const char* path ) { this->m_path = path; this->m_demographic_fn = ""; } Xio_patient::~Xio_patient () { } void Xio_patient::add_studyset_dir ( const std::string& studyset_path ) { this->studyset_dirs.push_back (studyset_path); } void Xio_patient::add_plan_dir ( const std::string& plan_path ) { this->plan_dirs.push_back (plan_path); } void Xio_patient::analyze () { itksys::Directory itk_dir; std::string plan_path = std::string(this->m_path) + "/plan"; std::string studyset_path = std::string(this->m_path) + "/anatomy/studyset"; if (itk_dir.Load (studyset_path.c_str())) { for (unsigned long i = 0; i < itk_dir.GetNumberOfFiles(); i++) { std::string curr_file = itk_dir.GetFile(i); std::string curr_path = studyset_path + "/" + itk_dir.GetFile(i); if (Xio_dir::is_xio_studyset_dir (curr_path)) { printf ("Adding xsd: %s\n", curr_path.c_str()); this->add_studyset_dir (curr_path); } } } if (itk_dir.Load (plan_path.c_str())) { for (unsigned long i = 0; i < itk_dir.GetNumberOfFiles(); i++) { std::string curr_file = itk_dir.GetFile(i); std::string curr_path = plan_path + "/" + itk_dir.GetFile(i); if (Xio_dir::is_xio_plan_dir (curr_path)) { printf ("Adding xtpd: %s\n", curr_path.c_str()); this->add_plan_dir (curr_path); } } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_patient.h000066400000000000000000000014361321604176500302310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xio_patient_h #define _xio_patient_h #include "plmbase_config.h" #include #include /* This class represents a toplevel patient directory */ class PLMBASE_API Xio_patient { public: Xio_patient (const char* path); ~Xio_patient (); public: std::string m_path; std::string m_demographic_fn; std::list< std::string > studyset_dirs; std::list< std::string > plan_dirs; public: void add_studyset_dir (const std::string& studyset_path); void add_plan_dir (const std::string& plan_path); void analyze (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_plan.cxx000066400000000000000000000026031321604176500300670ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include "print_and_exit.h" #include "xio_plan.h" std::string xio_plan_get_studyset (const char *filename) { /* Open file */ std::ifstream ifs (filename, std::ifstream::in); if (ifs.fail()) { print_and_exit ("Error opening file %s for read\n", filename); } /* Get version string 0062101a - xio version 4.33.02 006d101a - xio version 4.50 */ std::string line; getline (ifs, line); printf ("Version = %s\n", line.c_str()); int rc, version_int; rc = sscanf (line.c_str(), "%x", &version_int); if (rc != 1) { /* Couldn't parse version string -- default to older format. */ version_int = 0x62101a; } printf ("rc = %d, version_int = 0x%x\n", rc, version_int); /* Skip 4 lines for xio 4.33.02, skip 5 lines for xio 4.50. */ getline (ifs, line); getline (ifs, line); getline (ifs, line); getline (ifs, line); if (version_int > 0x62101a) { getline (ifs, line); } /* Read and return studyset name */ getline (ifs, line); return line; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_plan.h000066400000000000000000000005721321604176500275170ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xio_plan_h_ #define _xio_plan_h_ #include "plmbase_config.h" PLMBASE_API std::string xio_plan_get_studyset (const char *filename); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_structures.cxx000066400000000000000000000271121321604176500313620ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include #include #include #include "itkDirectory.h" #include "itkRegularExpressionSeriesFileNames.h" #include "file_util.h" #include "metadata.h" #include "plm_math.h" #include "print_and_exit.h" #include "rt_study_metadata.h" #include "rtss.h" #include "rtss_contour.h" #include "rtss_roi.h" #include "string_util.h" #include "xio_ct.h" #include "xio_ct_transform.h" #include "xio_structures.h" static void add_cms_contournames (Rtss *rtss, const char *filename) { /* Open file */ std::ifstream ifs (filename, std::ifstream::in); if (ifs.fail()) { print_and_exit ("Error opening file %s for read\n", filename); } int skip_lines = 2; /* Read version number */ std::string line; getline (ifs, line); int rc, xio_version; rc = sscanf (line.c_str(), "%x", &xio_version); if (rc != 1) { print_and_exit ("Error parsing contournames: " "could not read version (%s)\n", line.c_str()); } if (xio_version == 0x00061027) { printf ("Version 00061027 found.\n"); skip_lines = 5; } /* Skip line */ getline (ifs, line); while (getline (ifs, line)) { int rc; /* Get structure name */ std::string structure_name = string_trim (line); /* Get structure number */ getline (ifs, line); int structure_id; rc = sscanf (line.c_str(), "%d,", &structure_id); if (rc != 1) { if (xio_version == 0x00061027) { /* This XiO version seems to write corrupted contourfiles when editing files created with previous versions. We'll assume that everything went ok. */ break; } /* GCS 2010-12-27: It's not only that version which does this. What happens it that XiO leaves garbage at the end of the file. The better way to handle this is probably to count the number of structures and then stop. */ #if defined (commentout) print_and_exit ("Error parsing contournames: " "contour id not found (%s)\n", line2->data); #endif } /* Xio structures can be zero. This is possibly not tolerated by dicom. So we modify before inserting into the cxt. */ structure_id ++; if (structure_id <= 0) { print_and_exit ("Error, structure_id was less than zero\n"); } /* Add structure */ rtss->add_structure (structure_name, "", structure_id); /* Skip extra lines */ for (int i = 0; i < skip_lines; i++) { getline (ifs, line); } } } static void add_cms_structure ( Rtss *rtss, const Xio_studyset& studyset, const char *filename, float z_loc) { FILE *fp; char buf[1024]; fp = fopen (filename, "r"); if (!fp) { printf ("Error opening file %s for read\n", filename); exit (-1); } /* Skip first five lines */ fgets (buf, 1024, fp); fgets (buf, 1024, fp); fgets (buf, 1024, fp); fgets (buf, 1024, fp); fgets (buf, 1024, fp); while (1) { int rc; int structure_id, num_points; int point_idx, remaining_points; Rtss_roi *curr_structure; Rtss_contour *curr_polyline; /* Get num points */ fgets (buf, 1024, fp); rc = sscanf (buf, "%d", &num_points); if (rc != 1) { print_and_exit ("Error parsing file %s (num_points)\n", filename); } /* Get structure number */ fgets (buf, 1024, fp); rc = sscanf (buf, "%d", &structure_id); if (rc != 1) { print_and_exit ("Error parsing file %s (structure_id)\n", filename); } /* Xio structures can be zero. This is possibly not tolerated by dicom. So we modify before inserting into the cxt. */ structure_id ++; if (structure_id <= 0) { print_and_exit ("Error, structure_id was less than zero\n"); } /* Can this happen? */ if (num_points == 0) { break; } /* Look up the cxt structure for this id */ curr_structure = rtss->find_structure_by_id (structure_id); if (!curr_structure) { print_and_exit ("Couldn't reference structure with id %d\n", structure_id); } printf ("[%f %d %d]\n", z_loc, structure_id, num_points); curr_polyline = curr_structure->add_polyline (); curr_polyline->slice_no = -1; curr_polyline->num_vertices = num_points; curr_polyline->x = (float*) malloc (num_points * sizeof(float)); curr_polyline->y = (float*) malloc (num_points * sizeof(float)); curr_polyline->z = (float*) malloc (num_points * sizeof(float)); point_idx = 0; remaining_points = num_points; while (remaining_points > 0) { int p, line_points, line_loc; fgets (buf, 1024, fp); if (remaining_points > 5) { line_points = 5; } else { line_points = remaining_points; } line_loc = 0; for (p = 0; p < line_points; p++) { float x, y; int rc, this_loc; rc = sscanf (&buf[line_loc], "%f, %f,%n", &x, &y, &this_loc); if (rc != 2) { print_and_exit ("Error parsing file %s (points) %s\n", filename, &buf[line_loc]); } /* GCS 2014-10-16. As reported by Thomas Botticello and others, the XiO structures are off by 1/2 pixel. This adjustment must be done before coourdinate transformation xio to dicom (e.g. prone). */ /* ND 2014-12-18 intent to provide final fix for this NOTE: There is an inherent residual error that cannot be fixed due to XiO's rounding of values at the time of import. */ curr_polyline->x[point_idx] = x - 0.5 * studyset.ct_pixel_spacing[0]; curr_polyline->y[point_idx] = -y - 0.5 * studyset.ct_pixel_spacing[1]; curr_polyline->z[point_idx] = z_loc; point_idx ++; line_loc += this_loc; } remaining_points -= line_points; } } fclose (fp); } void xio_structures_load ( Rtss *rtss, const Xio_studyset& studyset ) { /* Get the index file */ std::string index_file = std::string(studyset.studyset_dir) + "/" + "contournames"; if (!itksys::SystemTools::FileExists (index_file.c_str(), true)) { print_and_exit ("No xio contournames file found in directory %s\n", studyset.studyset_dir.c_str()); } /* Load the index file */ rtss->init (); add_cms_contournames (rtss, index_file.c_str()); /* Load all .WC files, adding data to CXT */ std::string contour_file; for (int i = 0; i < studyset.number_slices; i++) { contour_file = studyset.studyset_dir + "/" + studyset.slices[i].filename_contours; add_cms_structure ( rtss, studyset, contour_file.c_str(), studyset.slices[i].location); } rtss->debug (); } /* This is idiotic */ static std::string format_xio_filename (const char *output_dir, float z_loc) { int neg; int z_round, z_ones, z_tenths; const char *neg_string; std::string fn; neg = (z_loc < 0); if (neg) z_loc = - z_loc; z_round = ROUND (z_loc * 10); z_ones = z_round / 10; z_tenths = z_round % 10; neg_string = neg ? "-" : ""; if (z_ones == 0 && z_tenths == 0) { fn = string_format ("%s/T.%s0.WC", output_dir, neg_string); } else if (z_ones == 0) { fn = string_format ("%s/T.%s.%d.WC", output_dir, neg_string, z_tenths); } else if (z_tenths == 0) { fn = string_format ("%s/T.%s%d.WC", output_dir, neg_string, z_ones); } else { fn = string_format ("%s/T.%s%d.%d.WC", output_dir, neg_string, z_ones, z_tenths); } return fn; } void xio_structures_save ( const Rt_study_metadata::Pointer& rsm, Rtss *cxt, Xio_ct_transform *transform, Xio_version xio_version, const char *output_dir ) { FILE *fp; std::string fn; printf ("X_S_S: output_dir = %s\n", output_dir); if (!cxt->have_geometry) { print_and_exit ("Sorry, can't output xio format without ct geometry\n"); } /* Write contournames */ fn = string_format ("%s/%s", output_dir, "contournames"); make_parent_directories (fn); fp = fopen (fn.c_str(), "w"); if (!fp) { print_and_exit ("Error opening output file %s\n", fn.c_str()); } if (xio_version == XIO_VERSION_4_2_1) { fprintf (fp, "00031027\n"); } else { fprintf (fp, "00041027\n"); } fprintf (fp, "%lu\n", (unsigned long) cxt->num_structures); for (size_t i = 0; i < cxt->num_structures; i++) { Rtss_roi *curr_structure = cxt->slist[i]; int color = 1 + (i % 8); int pen = 1; /* Class 0 is "patient", class 1 is "Int" */ int structure_class = (i == 0) ? 0 : 1; /* Name */ fprintf (fp, "%s\n", curr_structure->name.c_str()); /* Structure no, density, ??, class [, date] */ fprintf (fp, "%lu,1.000000,0,%d%s\n", (unsigned long) (i+1), structure_class, (xio_version == XIO_VERSION_4_2_1) ? "" : ",19691231.190000"); /* Grouping */ fprintf (fp, "General\n"); /* color, ??, pen, ??, ??, ?? */ fprintf (fp, "%d,5,%d,1,0,0\n", color, pen); } fclose (fp); /* Write WC files */ for (plm_long z = 0; z < cxt->m_dim[2]; z++) { float z_offset = 0.0f; Metadata::Pointer meta = rsm->get_study_metadata (); std::string patient_pos = meta->get_metadata(0x0018, 0x5100); if (patient_pos == "HFS" || patient_pos == "HFP" || patient_pos == "") { z_offset = cxt->m_offset[2]; } else if (patient_pos == "FFS" || patient_pos == "FFP") { z_offset = - cxt->m_offset[2]; } float z_loc = z_offset + z * cxt->m_spacing[2]; fn = format_xio_filename (output_dir, z_loc); fp = fopen (fn.c_str(), "w"); if (!fp) { print_and_exit ("Error opening output file %s\n", fn.c_str()); } fprintf (fp, "00061013\n\n"); fprintf (fp, "0\n0.000,0.000,0.000\n"); /* GCS FIX: These seem to be min/max */ fprintf (fp, "-158.1,-135.6, 147.7, 81.6\n"); for (size_t i = 0; i < cxt->num_structures; i++) { Rtss_roi *curr_structure = cxt->slist[i]; for (size_t j = 0; j < curr_structure->num_contours; j++) { Rtss_contour *curr_polyline = curr_structure->pslist[j]; if (z != curr_polyline->slice_no) { continue; } fprintf (fp, "%d\n", (int) curr_polyline->num_vertices); fprintf (fp, "%lu\n", (unsigned long) (i+1)); for (size_t k = 0; k < curr_polyline->num_vertices; k++) { fprintf (fp, "%6.1f,%6.1f", curr_polyline->x[k] * transform->direction_cosines[0] - transform->x_offset, curr_polyline->y[k] * transform->direction_cosines[4] - transform->y_offset); if ((k+1) % 5 == 0) { fprintf (fp, "\n"); } else if (k < curr_polyline->num_vertices - 1) { fprintf (fp, ","); } else { fprintf (fp, "\n"); } } } } fprintf (fp, "0\n0\n0\nBart\n"); fclose (fp); } } void xio_structures_apply_transform ( Rtss *rtss, Xio_ct_transform *transform ) { /* Set offsets */ rtss->m_offset[0] = (rtss->m_offset[0] * transform->direction_cosines[0]) + transform->x_offset; rtss->m_offset[1] = (rtss->m_offset[1] * transform->direction_cosines[4]) + transform->y_offset; /* Transform structures */ for (size_t i = 0; i < rtss->num_structures; i++) { Rtss_roi *curr_structure = rtss->slist[i]; for (size_t j = 0; j < curr_structure->num_contours; j++) { Rtss_contour *curr_polyline = curr_structure->pslist[j]; for (size_t k = 0; k < curr_polyline->num_vertices; k++) { curr_polyline->x[k] = (curr_polyline->x[k] * transform->direction_cosines[0]) + transform->x_offset; curr_polyline->y[k] = (curr_polyline->y[k] * transform->direction_cosines[4]) + transform->y_offset; } } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_structures.h000066400000000000000000000014511321604176500310050ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xio_structures_h_ #define _xio_structures_h_ #include "plmbase_config.h" #include "xio_studyset.h" class Rtss; class Metadata; class Xio_studyset; PLMBASE_C_API void xio_structures_load ( Rtss *structures, const Xio_studyset& xsl ); PLMBASE_API void xio_structures_save ( const Rt_study_metadata::Pointer& rsm, Rtss *cxt, Xio_ct_transform *transform, Xio_version xio_version, const char *output_dir ); PLMBASE_C_API void xio_structures_apply_transform ( Rtss *structures, Xio_ct_transform *transform ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_studyset.cxx000066400000000000000000000105451321604176500310250ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include #include #include #include #include #include #include #include "print_and_exit.h" #include "xio_studyset.h" int Xio_studyset::gcd(int a, int b) { // Euclidean algorithm while (b != 0) { int t = b; b = a % b; a = t; } return a; } Xio_studyset::Xio_studyset (const std::string& input_dir) { this->studyset_dir = input_dir; // Open index.dat file in input_dir std::string indexdat(input_dir); indexdat += "/index.dat"; std::ifstream index (indexdat.c_str()); int all_number_slices = 0; std::vector all_slices; if (index.is_open()) { // Get total number of slices index >> all_number_slices; // Loop through slices getting filename and location std::string slice_filename_scan; std::string slice_name; float slice_location; for (int i = 0; i < all_number_slices; i++) { index >> slice_filename_scan; index >> slice_location; Xio_studyset_slice slice (slice_filename_scan, slice_location); all_slices.push_back (slice); } // Sort slices in positive direction std::sort (all_slices.begin(), all_slices.end()); } else { all_number_slices = 0; } // Workaround for multiple slice thickness // Create volume with uniform voxel sizes by finding greatest common divisor of slice thicknesses, // and duplicating slices to obtain a uniform Z axis. // Get slices thicknesses from CT files std::vector slice_thickness; for (size_t i = 0; i < all_slices.size(); i++) { std::string ct_file = this->studyset_dir + "/" + all_slices[i].filename_scan; std::string line; // Open file std::ifstream ifs(ct_file.c_str(), std::ifstream::in); if (ifs.fail()) { print_and_exit("Error opening CT file %s for read\n", ct_file.c_str()); } else { // Skip 14 lines for (int i = 0; i < 14; i++) { getline(ifs, line); } getline(ifs, line); int dummy; float highres_thickness; if (sscanf(line.c_str(), "%d,%g", &dummy, &highres_thickness) != 2) { print_and_exit("Error parsing slice thickness (%s)\n", line.c_str()); } slice_thickness.push_back(highres_thickness); } } // Find greatest common divisor std::vector slice_thickness_int; int slice_thickness_gcd = 1; for (size_t i = 0; i < all_slices.size(); i++) { // 1/1000 mm resolution int rounded_thickness = static_cast (slice_thickness[i] * 1000.); if (rounded_thickness == 0) rounded_thickness = 1; slice_thickness_int.push_back(rounded_thickness); } if (all_slices.size() == 1) { slice_thickness_gcd = slice_thickness_int[0]; } else if (all_slices.size() > 0) { slice_thickness_gcd = gcd(slice_thickness_int[0], slice_thickness_int[1]); for (size_t i = 2; i < all_slices.size(); i++) { slice_thickness_gcd = gcd(slice_thickness_gcd, slice_thickness_int[i]); } } // Build new slice list, determining duplication needed for each slice thickness = slice_thickness_gcd / 1000.; number_slices = 0; if (all_slices.size() > 0) { float location = all_slices[0].location - (slice_thickness[0] / 2.) + (thickness / 2.); for (size_t i = 0; i < all_slices.size(); i++) { int duplicate = slice_thickness_int[i] / slice_thickness_gcd; for (int j = 0; j < duplicate; j++) { Xio_studyset_slice slice(all_slices[i].filename_scan, location); slices.push_back(slice); location += thickness; number_slices++; } } } // Initialize pixel spacing to zero. This get set when the // CT is loaded this->ct_pixel_spacing[0] = this->ct_pixel_spacing[1] = 0.f; } Xio_studyset::~Xio_studyset () { } Xio_studyset_slice::Xio_studyset_slice (std::string slice_filename_scan, const float slice_location) { filename_scan = slice_filename_scan; location = slice_location; // Get name from slice filename size_t extension_dot = filename_scan.find_last_of("."); name = filename_scan.substr(0, extension_dot); filename_contours = name + ".WC"; } Xio_studyset_slice::~Xio_studyset_slice () { } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xio_studyset.h000066400000000000000000000024011321604176500304420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xio_studyset_h_ #define _xio_studyset_h_ #include "plmbase_config.h" #include #include enum Xio_version { XIO_VERSION_UNKNOWN, XIO_VERSION_4_2_1, /* MGH proton Xio */ XIO_VERSION_4_33_02, /* Older MGH photon Xio */ XIO_VERSION_4_5_0, /* Current MGH photon Xio */ }; class PLMBASE_API Xio_studyset_slice { public: std::string name; float location; std::string filename_scan; std::string filename_contours; public: Xio_studyset_slice (std::string slice_filename_scan, const float slice_location); ~Xio_studyset_slice (); bool operator < (const Xio_studyset_slice &cmp) const { return location < cmp.location; } }; class PLMBASE_API Xio_studyset { public: std::string studyset_dir; int number_slices; float thickness; float ct_pixel_spacing[2]; std::vector slices; public: Xio_studyset (const std::string& studyset_dir); ~Xio_studyset (); private: int gcd(int, int); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xpm.cxx000066400000000000000000000126651321604176500270730ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "xpm_p.h" #include "xpm.h" /* ----------- Canvas ----------- */ Xpm_canvas::Xpm_canvas (int width, int height, int cpp) { d_ptr = new Xpm_canvas_private; d_ptr->width = width; d_ptr->height = height; d_ptr->num_pix = width * height; d_ptr->num_colors = 0; d_ptr->cpp = cpp; // Allocate memory for pixel data d_ptr->img = (char*)malloc (width*height*sizeof(char)); } Xpm_canvas::~Xpm_canvas () { free (d_ptr->img); free (d_ptr->color_code); free (d_ptr->colors); } void Xpm_canvas::prime (char color_code) { int i; char* img = d_ptr->img; for (i=0; inum_pix; i++) img[i] = color_code; } void Xpm_canvas::add_color (char color_code, int color) { // Increase memory usage as necessary if (!d_ptr->num_colors) { d_ptr->num_colors++; d_ptr->colors = (int*)malloc (sizeof(int)); d_ptr->color_code = (char*)malloc (sizeof(char)); } else { d_ptr->num_colors++; d_ptr->colors = (int*)realloc (d_ptr->colors, d_ptr->num_colors * sizeof(int)); d_ptr->color_code = (char*)realloc (d_ptr->color_code, d_ptr->num_colors * sizeof(char)); } // Insert the color d_ptr->colors[d_ptr->num_colors - 1] = color; d_ptr->color_code[d_ptr->num_colors - 1] = color_code; } // Returns 0 on success // -- " -- 1 on failure // // I don't plan on ever needing this... // but perhaps you will, so here it is. int Xpm_canvas::remove_color (char color_code) { int i; char* code = d_ptr->color_code; // Search for the color code and remove it for(i=0; inum_colors; i++) { if (code[i] == color_code) { // Decrement palette d_ptr->num_colors--; // Did we remove the last color? if (!d_ptr->num_colors){ // We have removed all the colors free (d_ptr->colors); free (d_ptr->color_code); } else { d_ptr->colors = (int*)realloc (d_ptr->colors, d_ptr->num_colors * sizeof(int)); d_ptr->color_code = (char*)realloc (d_ptr->color_code, d_ptr->num_colors * sizeof(char)); } } else { // color code not registered return 1; } } return 0; } int Xpm_canvas::draw (Xpm_brush* brush) { int i, j; int x1,x2,y1,y2; // which brush, son? switch (brush->get_type()) { case XPM_BOX: // define bounds x1 = brush->get_x(); x2 = brush->get_x() + brush->get_width(); y1 = brush->get_y(); y2 = brush->get_y() + brush->get_height(); // bound checking if ( (x1 < 0) || (x2 > d_ptr->width) ) return 1; if ( (y1 < 0) || (y2 > d_ptr->height) ) return 1; // draw the box for (j=y1; jimg[j * d_ptr->width + i] = brush->get_color(); break; case XPM_CIRCLE: /* not implemented */ break; } return 0; } void Xpm_canvas::write (char* xpm_file) { FILE *fp; int i,j,p; char* img = d_ptr->img; // Write the XPM file to disk if ( !(fp = fopen(xpm_file, "w")) ) fprintf(stderr, "Error: Cannot write open XPM file for writing\n"); // Construct the XPM header fprintf(fp, "/* XPM */\n"); fprintf(fp, "static char * plm_xpm[] = {\n"); fprintf(fp, "/* width height colors cpp */\n"); fprintf(fp, "\"%i %i %i %i\",\n\n", d_ptr->width, d_ptr->height, d_ptr->num_colors, d_ptr->cpp); // Construct Palette fprintf(fp, "/* color codes */\n"); for (i=0; inum_colors; i++) fprintf(fp, "\"%c c #%.6x\",\n", d_ptr->color_code[i], d_ptr->colors[i]); // Write Pixel Data fprintf(fp, "\n/* Pixel Data */\n"); p=0; for (j=0; jheight; j++) { fprintf(fp, "\""); for (i=0; iwidth; i++) { fprintf(fp, "%c",img[p++]); } fprintf(fp, "\",\n"); } fprintf(fp, "};"); // Done like dinner. fclose(fp); } /* ----------- Brush ----------- */ Xpm_brush::Xpm_brush () { d_ptr = new Xpm_brush_private; } Xpm_brush::~Xpm_brush () { delete d_ptr; } void Xpm_brush::set_type (xpm_brushes type) { d_ptr->type = type; } void Xpm_brush::set_color (char color) { d_ptr->color = color; } void Xpm_brush::set_pos (int x, int y) { d_ptr->x_pos = x; d_ptr->y_pos = y; } void Xpm_brush::set_width (int width) { d_ptr->width = width; } void Xpm_brush::set_height (int height) { d_ptr->height = height; } void Xpm_brush::set_x (int x) { d_ptr->x_pos = x; } void Xpm_brush::set_y (int y) { d_ptr->y_pos = y; } char Xpm_brush::get_color () { return d_ptr->color; } xpm_brushes Xpm_brush::get_type () { return d_ptr->type; } int Xpm_brush::get_width () { return d_ptr->width; } int Xpm_brush::get_height () { return d_ptr->height; } int Xpm_brush::get_x () { return d_ptr->x_pos; } int Xpm_brush::get_y () { return d_ptr->y_pos; } void Xpm_brush::inc_x (int dx) { d_ptr->x_pos += dx; } void Xpm_brush::inc_y (int dy) { d_ptr->y_pos += dy; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xpm.h000066400000000000000000000023451321604176500265120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xpm_h_ #define _xpm_h_ #include "plmbase_config.h" class Xpm_brush_private; class Xpm_canvas_private; enum xpm_brushes { XPM_BOX, XPM_CIRCLE }; class PLMBASE_API Xpm_brush { public: Xpm_brush (); ~Xpm_brush (); void set_type (xpm_brushes type); void set_color (char color); void set_pos (int x, int y); void set_width (int width); void set_height (int height); void set_x (int x); void set_y (int y); char get_color (); xpm_brushes get_type (); int get_width (); int get_height (); int get_x (); int get_y (); void inc_x (int x); void inc_y (int y); private: Xpm_brush_private *d_ptr; }; class PLMBASE_API Xpm_canvas { public: Xpm_canvas (int width, int height, int cpp); ~Xpm_canvas (); void add_color (char color_code, int color); int draw (Xpm_brush* brush); void prime (char color_code); int remove_color (char color_code); void write (char* xpm_file); private: Xpm_canvas_private *d_ptr; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/base/xpm_p.h000066400000000000000000000023631321604176500270310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _xpm_p_h_ #define _xpm_p_h_ #include "xpm.h" class Xpm_canvas_private { public: int width; /* Image Width */ int height; /* Image Height */ int num_pix; /* Width * Height */ int num_colors; /* Number of Colors in Palette */ int cpp; /* Characters per Pixel */ char* color_code; /* User Defined Color Codes */ int* colors; /* Actual Color Codes */ char* img; /* Pixel Data */ }; class Xpm_brush_private { public: enum xpm_brushes type; /* Type of shape */ char color; /* Color Code */ int x_pos; /* X Postion */ int y_pos; /* Y Postion */ int width; /* Width */ int height; /* Height */ int rad; /* Radius */ int hparm; /* Misc 1 */ int lparm; /* Misc 2 */ }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/000077500000000000000000000000001321604176500253665ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/CMakeLists.txt000066400000000000000000000045441321604176500301350ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_cli) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/plmcli_config.h.in ${CMAKE_BINARY_DIR}/plmcli_config.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (AFTER ${LUA_INCLUDE_DIR}) ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- #set (PLMCLP_LIBRARY_SRC # plm_clp.cxx plm_clp.h # ) set (PLASTIMATCH_SRC pcmd_add.cxx pcmd_adjust.cxx pcmd_autolabel_train.cxx pcmd_autolabel.cxx pcmd_bbox.cxx pcmd_bbox.h pcmd_benchmark.cxx pcmd_boundary.cxx pcmd_boundary.h pcmd_compare.cxx pcmd_compose.cxx pcmd_crop.cxx pcmd_dice.cxx pcmd_diff.cxx pcmd_dmap.cxx pcmd_dose.cxx pcmd_dose.h pcmd_drr.cxx pcmd_dvh.cxx pcmd_filter.cxx pcmd_gamma.cxx pcmd_header.cxx pcmd_jacobian.cxx pcmd_mabs.cxx pcmd_mask.cxx pcmd_maximum.cxx pcmd_ml_convert.cxx pcmd_ml_convert.h pcmd_multiply.cxx pcmd_probe.cxx pcmd_register.cxx pcmd_register.h pcmd_resample.cxx pcmd_scale.cxx # pcmd_script.cxx pcmd_segment.cxx pcmd_sift.cxx pcmd_stats.cxx pcmd_synth.cxx pcmd_synth_vf.cxx pcmd_threshold.cxx pcmd_thumbnail.cxx pcmd_union.cxx pcmd_vf_invert.cxx pcmd_vf_invert.h pcmd_warp.cxx pcmd_warp_dij.cxx pcmd_warp_pointset.cxx pcmd_xio_dvh.cxx pcmd_xf_convert.cxx plastimatch_main.cxx ) set (LANDMARK_WARP_SRC landmark_warp_main.cxx ) set (PLM_CLI_LIBRARIES ${PLASTIMATCH_LIBS} plmclp) ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- #plm_add_library ( # plmclp # "${PLMCLP_LIBRARY_SRC}" # "" # "") #add_library (plmclp STATIC ${PLMCLP_LIBRARY_SRC}) plm_add_executable (plastimatch "${PLASTIMATCH_SRC}" "${PLM_CLI_LIBRARIES}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_ALWAYS}) plm_add_executable (landmark_warp "${LANDMARK_WARP_SRC}" "${PLM_CLI_LIBRARIES}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_ALWAYS}) landmark_warp_main.cxx000066400000000000000000000233441321604176500316670ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include #include #include #include #include "itk_tps.h" #include "landmark_warp.h" #include "path_util.h" #include "plm_clp.h" #include "plm_image.h" #include "plm_math.h" #include "print_and_exit.h" #include "raw_pointset.h" #include "rbf_gauss.h" #include "rbf_wendland.h" #include "string_util.h" #include "volume.h" #include "xform.h" class Landmark_warp_main_parms { public: std::string fixed_lm_fn; std::string moving_lm_fn; std::string input_vf_fn; std::string input_img_fn; std::string output_img_fn; std::string output_vf_fn; std::string output_lm_fn; std::string fixed_img_fn; bool have_dim; plm_long dim[3]; bool have_origin; float origin[3]; bool have_spacing; float spacing[3]; bool have_direction_cosines; float direction_cosines[9]; std::string algorithm; Landmark_warp lw; public: Landmark_warp_main_parms () { have_dim = 0; have_origin = 0; have_spacing = 0; have_direction_cosines = 0; } }; static void do_landmark_warp_itk_tps (Landmark_warp *lw) { itk_tps_warp (lw); } static void do_landmark_warp_wendland (Landmark_warp *lw) { rbf_wendland_warp (lw); } static void do_landmark_warp_gauss (Landmark_warp *lw) { rbf_gauss_warp (lw); } static void load_input_files (Landmark_warp_main_parms *parms) { Landmark_warp *lw = &parms->lw; /* Load the pointsets */ lw->load_pointsets (parms->fixed_lm_fn.c_str(), parms->moving_lm_fn.c_str()); if (!lw) { print_and_exit ("Error, landmarks were not loaded successfully.\n"); } /* Load the input image */ if (parms->input_img_fn != "") { lw->m_input_img = plm_image_load_native (parms->input_img_fn); if (!lw->m_input_img) { print_and_exit ("Error reading input image: %s\n", parms->input_img_fn.c_str()); } /* Default geometry, if unknown, comes from moving image */ lw->m_pih.set_from_plm_image (lw->m_input_img); } /* Set the output geometry. Note: --offset, --spacing, and --dim get priority over --fixed. Therefore, if these options are completely specified, we don't need to load the fixed image. */ if (!parms->have_dim || !parms->have_origin || !parms->have_spacing || !parms->have_direction_cosines) { if (parms->fixed_img_fn != "") { Plm_image::Pointer pli = plm_image_load_native (parms->fixed_img_fn); if (!pli) { print_and_exit ("Error loading fixed image: %s\n", parms->fixed_img_fn.c_str()); } lw->m_pih.set_from_plm_image (pli); } } if (parms->have_dim) { lw->m_pih.set_dim (parms->dim); } if (parms->have_origin) { lw->m_pih.set_origin (parms->origin); } if (parms->have_spacing) { lw->m_pih.set_spacing (parms->spacing); } // if (parms->have_direction_cosines) { // lw->m_pih.set_direction_cosines (parms->direction_cosines); // } } #if defined (commentout) void pointset_save_fcsv_by_cluster (Raw_pointset* ps, int *clust_id, int which_cluster, const char *fn) { int i; int symbol; FILE *fp; // symbolType, see //http://www.slicer.org/slicerWiki/index.php/Modules:Fiducials-Documentation-3.4 symbol =which_cluster+2; if (symbol > 13) symbol -=13; fp = fopen (fn, "w"); if (!fp) return; int num_points_in_cluster=0; for (i = 0; i < ps->num_points; i++) { if (clust_id[i] == which_cluster) num_points_in_cluster++; } fprintf (fp, "# Fiducial List file %s\n" "# version = 2\n" "# name = plastimatch-fiducials\n" "# numPoints = %d\n" "# symbolScale = 5\n" "# symbolType = %d\n" "# visibility = 1\n" "# textScale = 4.5\n" "# color = 0.4,1,1\n" "# selectedColor = 1,0.5,0.5\n" "# opacity = 1\n" "# ambient = 0\n" "# diffuse = 1\n" "# specular = 0\n" "# power = 1\n" "# locked = 0\n" "# numberingScheme = 0\n" "# columns = label,x,y,z,sel,vis\n", fn, num_points_in_cluster, symbol); for (i = 0; i < ps->num_points; i++) { if (clust_id[i] == which_cluster) fprintf (fp, "p-%03d-c%02d,%f,%f,%f,1,1\n", i, clust_id[i], - ps->points[i*3+0], - ps->points[i*3+1], ps->points[i*3+2]); } fclose (fp); } #endif static void save_output_files (Landmark_warp_main_parms *parms) { Landmark_warp *lw = &parms->lw; /* GCS FIX: float output only, and no dicom. */ if (lw->m_warped_img && parms->output_img_fn != "") { lw->m_warped_img->save_image (parms->output_img_fn); } if (lw->m_vf && parms->output_vf_fn != "") { xform_save (lw->m_vf, parms->output_vf_fn); } if (lw->m_vf && parms->output_lm_fn != "") { if ( lw->num_clusters > 0 ) { /* GCS FIX 2015-06-23: If this is ever needed, it can be re-implemented e.g. by specifying a selection mask. N.b. see above code for reference. */ #if defined (commentout) // if clustering required, save each cluster to a separate fcsv for( int ii = 0; iinum_clusters; ii++) { std::string fn_base = strip_extension (parms->output_lm_fn); std::string fn_out = string_format ("%s_cl_%d.fcsv", fn_base.c_str(), ii); //write FIXED landmarks to check for clustering issues pointset_save_fcsv_by_cluster(lw->m_fixed_landmarks, lw->cluster_id, ii, fn_out.c_str()); } #endif } else { lw->m_warped_landmarks.save (parms->output_lm_fn.c_str()); } } } static void do_landmark_warp (Landmark_warp_main_parms *parms) { Landmark_warp *lw = &parms->lw; load_input_files (parms); if (parms->algorithm == "tps") { do_landmark_warp_itk_tps (lw); } else if (parms->algorithm == "gauss") { do_landmark_warp_gauss (lw); } else if (parms->algorithm == "wendland") { do_landmark_warp_wendland (lw); } if (parms->output_lm_fn != "") { calculate_warped_landmarks (lw); } save_output_files (parms); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: landmark_warp [options]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Landmark_warp_main_parms *parms, dlib::Plm_clp *parser, int argc, char* argv[] ) { Landmark_warp *lw = &parms->lw; /* Add --help, --version */ parser->add_default_options (); /* Basic options */ parser->add_long_option ("f", "fixed-landmarks", "Input fixed landmarks", 1, ""); parser->add_long_option ("m", "moving-landmarks", "Output moving landmarks", 1, ""); parser->add_long_option ("v", "input-vf", "Input vector field (applied prior to landmark warping)", 1, ""); parser->add_long_option ("I", "input-image", "Input image to warp", 1, ""); parser->add_long_option ("O", "output-image", "Output warped image", 1, ""); parser->add_long_option ("V", "output-vf", "Output vector field", 1, ""); parser->add_long_option ("L", "output-landmarks", "Output warped landmarks", 1, ""); /* Output geometry options */ parser->add_long_option ("", "origin", "Location of first image voxel in mm \"x y z\"", 1, ""); parser->add_long_option ("", "spacing", "Voxel spacing in mm \"x [y z]\"", 1, ""); parser->add_long_option ("", "dim", "Size of output image in voxels \"x [y z]\"", 1, ""); parser->add_long_option ("F", "fixed", "Fixed image (match output size to this image)", 1, ""); /* Algorithm options */ parser->add_long_option ("a", "algorithm", "RBF warping algorithm {tps,gauss,wendland}", 1, "gauss"); parser->add_long_option ("r", "radius", "Radius of radial basis function (in mm)", 1, "50.0"); parser->add_long_option ("Y", "stiffness", "Young modulus (default = 0.0)", 1, "0.0"); parser->add_long_option ("d", "default-value", "Value to set for pixels with unknown value", 1, "-1000"); parser->add_long_option ("N", "numclusters", "Number of clusters of landmarks", 1, "0"); /* Parse the command line arguments */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that required inputs were given */ parser->check_required ("fixed-landmarks"); parser->check_required ("moving-landmarks"); /* Copy values into output struct */ parms->fixed_lm_fn = parser->get_string("fixed-landmarks"); parms->moving_lm_fn = parser->get_string("moving-landmarks"); parms->input_vf_fn = parser->get_string("input-vf"); parms->input_img_fn = parser->get_string("input-image"); parms->output_img_fn = parser->get_string("output-image"); parms->output_vf_fn = parser->get_string("output-vf"); parms->output_lm_fn = parser->get_string("output-landmarks"); if (parser->option ("origin")) { parms->have_origin = 1; parser->assign_float_13 (parms->origin, "origin"); } if (parser->option ("spacing")) { parms->have_spacing = 1; parser->assign_float_13 (parms->spacing, "spacing"); } if (parser->option ("dim")) { parms->have_dim = 1; parser->assign_plm_long_13 (parms->dim, "dim"); } parms->fixed_img_fn = parser->get_string("fixed"); parms->algorithm = parser->get_string("algorithm"); lw->rbf_radius = parser->get_float("radius"); lw->young_modulus = parser->get_float("stiffness"); lw->default_val = parser->get_float("default-value"); lw->num_clusters = parser->get_float("numclusters"); } int main (int argc, char *argv[]) { Landmark_warp_main_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv); do_landmark_warp (&parms); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_add.cxx000066400000000000000000000147161321604176500276560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "itkAddImageFilter.h" #include "itk_image_type.h" #include "itk_scale.h" #include "plm_clp.h" #include "plm_file_format.h" #include "plm_image.h" #include "print_and_exit.h" #include "xform.h" class Add_parms { public: std::string output_fn; bool average; std::vector weight_vector; std::list input_fns; public: Add_parms () { average = false; } }; static void scale_image (Plm_image::Pointer& img, float weight) { img->set_itk (itk_scale (img->itk_float(), weight)); } static void scale_vf (Xform *xf, float weight) { xf->set_itk_vf (itk_scale (xf->get_itk_vf(), weight)); } void add_vf_main (Add_parms *parms) { typedef itk::AddImageFilter< DeformationFieldType, DeformationFieldType, DeformationFieldType > AddFilterType; AddFilterType::Pointer addition = AddFilterType::New(); /* Load the first input image */ std::list::iterator it = parms->input_fns.begin(); Xform sum; sum.load (*it); ++it; /* Weigh the first input image */ int widx = 0; if (parms->weight_vector.size() > 0) { scale_vf (&sum, parms->weight_vector[widx]); ++widx; } /* Loop through remaining images */ while (it != parms->input_fns.end()) { /* Load the images */ Xform tmp; tmp.load (*it); /* Weigh it */ if (parms->weight_vector.size() > 0) { scale_vf (&tmp, parms->weight_vector[widx]); ++widx; } /* Add it to running sum */ addition->SetInput1 (sum.get_itk_vf()); addition->SetInput2 (tmp.get_itk_vf()); addition->Update(); sum.set_itk_vf (addition->GetOutput ()); ++it; } /* Take average */ if (parms->average) { float avg = 1.0f / parms->input_fns.size(); scale_vf (&sum, avg); } /* Save the sum image */ sum.save (parms->output_fn); } void add_vol_main (Add_parms *parms) { typedef itk::AddImageFilter< FloatImageType, FloatImageType, FloatImageType > AddFilterType; AddFilterType::Pointer addition = AddFilterType::New(); /* Load the first input image */ std::list::iterator it = parms->input_fns.begin(); Plm_image::Pointer sum = plm_image_load (*it, PLM_IMG_TYPE_ITK_FLOAT); ++it; /* Weigh the first input image */ int widx = 0; if (parms->weight_vector.size() > 0) { scale_image (sum, parms->weight_vector[widx]); ++widx; } /* Loop through remaining images */ while (it != parms->input_fns.end()) { /* Load the images */ Plm_image::Pointer tmp = plm_image_load (*it, PLM_IMG_TYPE_ITK_FLOAT); /* Weigh it */ if (parms->weight_vector.size() > 0) { scale_image (tmp, parms->weight_vector[widx]); ++widx; } /* Add it to running sum */ addition->SetInput1 (sum->itk_float()); addition->SetInput2 (tmp->itk_float()); addition->Update(); sum->m_itk_float = addition->GetOutput (); ++it; } /* Take average */ if (parms->average) { float avg = 1.0f / parms->input_fns.size(); scale_image (sum, avg); } /* Save the sum image */ sum->convert_to_original_type (); sum->save_image (parms->output_fn); } void add_main (Add_parms *parms) { /* Make sure we got the same number of input files and weights */ if (parms->weight_vector.size() > 0 && parms->weight_vector.size() != parms->input_fns.size()) { print_and_exit ( "Error, you specified %d input files and %d weights\n", parms->input_fns.size(), parms->weight_vector.size()); } /* What is the input file type? */ std::list::iterator it = parms->input_fns.begin(); Plm_file_format file_format = plm_file_format_deduce (*it); switch (file_format) { case PLM_FILE_FMT_VF: add_vf_main (parms); break; default: add_vol_main (parms); break; } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options] input_file [input_file ...]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Add_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Output files */ parser->add_long_option ("", "output", "output image", 1, ""); /* Weight vector */ parser->add_long_option ("", "weight", "specify a vector of weights; the images are multiplied " "by the weight prior to adding their values", 1, ""); /* Average option */ parser->add_long_option ("", "average", "produce an output file which is the average of the input files " "(if no weights are specified), or multiply the weights by 1/n", 0); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Check that no extraneous options were given */ if (parser->number_of_arguments() == 0) { throw (dlib::error ("Error. You must specify at least one " "file to add.")); } /* Copy input filenames to parms struct */ for (unsigned long i = 0; i < parser->number_of_arguments(); i++) { parms->input_fns.push_back ((*parser)[i]); } /* Average */ if (parser->option ("average")) { parms->average = true; } /* Output files */ parms->output_fn = parser->get_string("output"); if (parser->option ("weight")) { parser->assign_float_vec (&parms->weight_vector, "weight"); } } void do_command_add (int argc, char *argv[]) { Add_parms parms; /* Check if we're doing add or average */ if (!strcmp (argv[1], "add")) { parms.average = false; } else { parms.average = true; } /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); add_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_add.h000066400000000000000000000005411321604176500272720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_add_h_ #define _pcmd_add_h_ #include "plmcli_config.h" void do_command_add (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_adjust.cxx000066400000000000000000000065321321604176500304150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "itkImageRegionIterator.h" #include "itk_adjust.h" #include "itk_image_save.h" #include "plm_clp.h" #include "plm_image.h" #include "plm_math.h" #include "pcmd_adjust.h" #include "print_and_exit.h" static void adjust_main (Adjust_parms* parms) { typedef itk::ImageRegionIterator< FloatImageType > FloatIteratorType; Plm_image::Pointer plm_image = plm_image_load ( parms->img_in_fn, PLM_IMG_TYPE_ITK_FLOAT); FloatImageType::Pointer img = plm_image->m_itk_float; FloatImageType::RegionType rg = img->GetLargestPossibleRegion (); FloatIteratorType it (img, rg); if (parms->have_ab_scale) { it.GoToBegin(); for (it.GoToBegin(); !it.IsAtEnd(); ++it) { float v = it.Get(); float d_per_fx = v / parms->num_fx; v = v * (parms->alpha_beta + d_per_fx) / (parms->alpha_beta + parms->norm_dose_per_fx); it.Set (v); } } if (parms->pw_linear != "") { img = itk_adjust (img, parms->pw_linear); plm_image->set_itk (img); } if (parms->output_dicom) { itk_image_save_short_dicom ( img, parms->img_out_fn.c_str(), 0); } else { if (parms->output_type) { plm_image->convert (parms->output_type); } plm_image->save_image (parms->img_out_fn); } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Adjust_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input", "input directory or filename", 1, ""); /* Output files */ parser->add_long_option ("", "output", "output image", 1, ""); /* Adjustment string */ parser->add_long_option ("", "pw-linear", "a string that forms a piecewise linear map from " "input values to output values, of the form " "\"in1,out1,in2,out2,...\"", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("input")) { throw (dlib::error ("Error. Please specify an input file " "using the --input option")); } /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Copy input filenames to parms struct */ parms->img_in_fn = parser->get_string("input").c_str(); /* Output files */ parms->img_out_fn = parser->get_string("output").c_str(); /* Piecewise linear adjustment string */ if (parser->option ("pw-linear")) { parms->pw_linear = parser->get_string("pw-linear").c_str(); } } void do_command_adjust (int argc, char *argv[]) { Adjust_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); adjust_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_adjust.h000066400000000000000000000016061321604176500300370ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_adjust_h_ #define _pcmd_adjust_h_ #include "plmcli_config.h" #include #include #include #include "plm_image_type.h" class Adjust_parms { public: std::string img_in_fn; std::string img_out_fn; /* Piecewise linear adjustment */ std::string pw_linear; /* Alpha-beta scaling */ float alpha_beta; float num_fx; float norm_dose_per_fx; bool have_ab_scale; bool output_dicom; Plm_image_type output_type; public: Adjust_parms () { have_ab_scale = false; output_dicom = false; output_type = PLM_IMG_TYPE_UNDEFINED; } }; void do_command_adjust (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_autolabel.cxx000066400000000000000000000026731321604176500310750ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "autolabel.h" #include "autolabel_parms.h" #include "plm_clp.h" static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch autolabel [options] command_file\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Autolabel_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Basic options */ parser->add_long_option ("", "train", "Run training on the problem specified in the command file"); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that only one argument was given */ if (parser->number_of_arguments() != 1) { throw (dlib::error ( "Error. Only one configuration file can be used.")); } /* Get filename of command file */ parms->cmd_file_fn = (*parser)[0].c_str(); } void do_command_autolabel (int argc, char *argv[]) { Autolabel_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); autolabel (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_autolabel.h000066400000000000000000000005631321604176500305160ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_autolabel_h_ #define _pcmd_autolabel_h_ #include "plmcli_config.h" void do_command_autolabel (int argc, char *argv[]); #endif pcmd_autolabel_train.cxx000066400000000000000000000035061321604176500322070ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "autolabel_trainer.h" #include "pcmd_autolabel_train.h" #include "plm_clp.h" static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch autolabel-train [options] command_file\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Autolabel_train_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { parser->add_default_options (); /* Basic options */ parser->add_long_option ("", "input", "Input directory (required)", 1, ""); parser->add_long_option ("", "output-dir", "Directory to store training data", 1, ""); parser->add_long_option ("", "task", "Training task (required), choices are " "{la,tsv1,tsv2}", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Check if the -h or --version were given */ parser->check_default_options (); /* Check that an input file was given */ parser->check_required ("input"); /* Check that a csv output was given */ parser->check_required ("output-dir"); /* Check that a task was given */ parser->check_required ("task"); /* Copy values into output struct */ parms->input_dir = parser->get_string("input").c_str(); parms->output_dir = parser->get_string("output-dir").c_str(); parms->task = parser->get_string("task").c_str(); } void do_command_autolabel_train (int argc, char *argv[]) { Autolabel_train_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); autolabel_train (&parms); } pcmd_autolabel_train.h000066400000000000000000000006051321604176500316310ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_autolabel_train_h_ #define _pcmd_autolabel_train_h_ #include "plmcli_config.h" void do_command_autolabel_train (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_bbox.cxx000066400000000000000000000067751321604176500300660ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "itkImageRegionIteratorWithIndex.h" #include "itk_bbox.h" #include "itk_image_clone.h" #include "itk_image_save.h" #include "itk_image_type.h" #include "pcmd_bbox.h" #include "plm_clp.h" #include "plm_image.h" class Bbox_parms { public: std::string input_fn; std::string output_mask_fn; float margin; bool z_only; public: Bbox_parms () { margin = 0.f; z_only = false; } }; void do_bbox (const Bbox_parms *parms) { Plm_image pli (parms->input_fn); UCharImageType::Pointer img = pli.itk_uchar(); float bbox[6]; itk_bbox (img, bbox); bbox[0] -= parms->margin; bbox[1] += parms->margin; bbox[2] -= parms->margin; bbox[3] += parms->margin; bbox[4] -= parms->margin; bbox[5] += parms->margin; printf ("%f %f %f %f %f %f\n", bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]); if (parms->output_mask_fn != "") { UCharImageType::Pointer img_out = itk_image_clone_empty (img); itk::ImageRegionIteratorWithIndex< UCharImageType > it (img_out, img_out->GetLargestPossibleRegion()); for (it.GoToBegin(); !it.IsAtEnd(); ++it) { FloatPoint3DType point; UCharImageType::RegionType::IndexType idx = it.GetIndex(); img_out->TransformIndexToPhysicalPoint (idx, point); if (point[2] < bbox[2*2+0] || point[2] > bbox[2*2+1]) { continue; } if ((parms->z_only) || (point[0] > bbox[0*2+0] && point[0] < bbox[0*2+1] && point[1] > bbox[1*2+0] && point[1] < bbox[1*2+1])) { it.Set (1); } } itk_image_save (img_out, parms->output_mask_fn); } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch bbox [options] input-file\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Bbox_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Basic options */ parser->add_long_option ("", "output", "Location of output image", 1, ""); parser->add_long_option ("", "margin", "Expand bounding box by margin (mm, may be negative)", 1, "0"); parser->add_long_option ("", "z-only", "When creating output image, only consider z axis", 0); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that all necessary inputs are given */ if (parser->number_of_arguments() != 1) { throw (dlib::error ( "Error. A single input file must be given.")); } /* Get input file */ parms->input_fn = (*parser)[0]; /* Copy remaining values into parameter struct */ parms->margin = parser->get_float ("margin"); if (parser->have_option ("output")) { parms->output_mask_fn = parser->get_string ("output"); } if (parser->have_option ("z-only")) { parms->z_only = true; } } void do_command_bbox (int argc, char *argv[]) { Bbox_parms bbox_parms; plm_clp_parse (&bbox_parms, &parse_fn, &usage_fn, argc, argv, 1); do_bbox (&bbox_parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_bbox.h000066400000000000000000000005101321604176500274700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_bbox_h_ #define _pcmd_bbox_h_ void do_command_bbox (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_benchmark.cxx000066400000000000000000000036011321604176500310470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "pcmd_benchmark.h" #include "plm_clp.h" class Benchmark_parms { public: std::string output_fn; std::string input_fn; }; static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options] input_file\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Benchmark_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Output files */ parser->add_long_option ("", "output", "filename for output image", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Check that one, and only one, input file was given */ if (parser->number_of_arguments() == 0) { throw (dlib::error ("Error. You must specify an input file")); } else if (parser->number_of_arguments() > 1) { std::string extra_arg = (*parser)[1]; throw (dlib::error ("Error. Unknown option " + extra_arg)); } /* Copy input filenames to parms struct */ parms->input_fn = (*parser)[0]; /* Output files */ parms->output_fn = parser->get_string("output"); } void do_command_benchmark (int argc, char *argv[]) { Benchmark_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_benchmark.h000066400000000000000000000005631321604176500305000ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_benchmark_h_ #define _pcmd_benchmark_h_ #include "plmcli_config.h" void do_command_benchmark (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_boundary.cxx000066400000000000000000000042231321604176500307410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "image_boundary.h" #include "itk_image_load.h" #include "itk_image_save.h" #include "plm_clp.h" class Boundary_parms { public: std::string output_fn; std::string input_fn; }; static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options] input_file\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Boundary_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Output files */ parser->add_long_option ("", "output", "filename for output image", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Check that one, and only one, input file was given */ if (parser->number_of_arguments() == 0) { throw (dlib::error ("Error. You must specify an input file")); } else if (parser->number_of_arguments() > 1) { std::string extra_arg = (*parser)[1]; throw (dlib::error ("Error. Unknown option " + extra_arg)); } /* Copy input filenames to parms struct */ parms->input_fn = (*parser)[0]; /* Output files */ parms->output_fn = parser->get_string("output"); } void do_command_boundary (int argc, char *argv[]) { Boundary_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); UCharImageType::Pointer input_image = itk_image_load_uchar ( parms.input_fn, 0); UCharImageType::Pointer output_image = do_image_boundary (input_image); itk_image_save (output_image, parms.output_fn); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_boundary.h000066400000000000000000000005601321604176500303660ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_boundary_h_ #define _pcmd_boundary_h_ #include "plmcli_config.h" void do_command_boundary (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_compare.cxx000066400000000000000000000132161321604176500305460ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "itkSubtractImageFilter.h" #include "itkImageRegionIterator.h" #include "itk_image_type.h" #include "mha_io.h" #include "pcmd_compare.h" #include "plm_file_format.h" #include "plm_image.h" #include "print_and_exit.h" #include "volume.h" void vf_analyze (Volume* vol1, Volume* vol2) { int d, i, j, k, v; float* img1 = (float*) vol1->img; float* img2 = (float*) vol2->img; float max_vlen2 = 0.0f; int max_vlen_idx_lin = 0; int max_vlen_idx[3] = { 0, 0, 0 }; for (v = 0, k = 0; k < vol1->dim[2]; k++) { for (j = 0; j < vol1->dim[1]; j++) { for (i = 0; i < vol1->dim[0]; i++, v++) { float* dxyz1 = &img1[3*v]; float* dxyz2 = &img2[3*v]; float diff[3]; float vlen2 = 0.0f; for (d = 0; d < 3; d++) { diff[d] = dxyz2[d] - dxyz1[d]; vlen2 += diff[d] * diff[d]; } if (vlen2 > max_vlen2) { max_vlen2 = vlen2; max_vlen_idx_lin = v; max_vlen_idx[0] = i; max_vlen_idx[1] = j; max_vlen_idx[2] = k; } } } } printf ("Max diff idx: %4d %4d %4d [%d]\n", max_vlen_idx[0], max_vlen_idx[1], max_vlen_idx[2], max_vlen_idx_lin); printf ("Vol 1: %10.3f %10.3f %10.3f\n", img1[3*max_vlen_idx_lin], img1[3*max_vlen_idx_lin+1], img1[3*max_vlen_idx_lin+2]); printf ("Vol 2: %10.3f %10.3f %10.3f\n", img2[3*max_vlen_idx_lin], img2[3*max_vlen_idx_lin+1], img2[3*max_vlen_idx_lin+2]); printf ("Vec len diff: %10.3f\n", sqrt(max_vlen2)); } static void vf_compare (Compare_parms* parms) { int d; Volume *vol1, *vol2; vol1 = read_mha (parms->img_in_1_fn.c_str()); if (!vol1) { fprintf (stderr, "Sorry, couldn't open file \"%s\" for read.\n", parms->img_in_1_fn.c_str()); exit (-1); } if (vol1->pix_type != PT_VF_FLOAT_INTERLEAVED) { fprintf (stderr, "Sorry, file \"%s\" is not an " "interleaved float vector field.\n", parms->img_in_1_fn.c_str()); fprintf (stderr, "Type = %d\n", vol1->pix_type); exit (-1); } vol2 = read_mha (parms->img_in_2_fn.c_str()); if (!vol2) { fprintf (stderr, "Sorry, couldn't open file \"%s\" for read.\n", parms->img_in_2_fn.c_str()); exit (-1); } if (vol2->pix_type != PT_VF_FLOAT_INTERLEAVED) { fprintf (stderr, "Sorry, file \"%s\" is not an " "interleaved float vector field.\n", parms->img_in_2_fn.c_str()); fprintf (stderr, "Type = %d\n", vol2->pix_type); exit (-1); } for (d = 0; d < 3; d++) { if (vol1->dim[d] != vol2->dim[d]) { fprintf (stderr, "Can't compare. " "Files have different dimensions.\n"); exit (-1); } } vf_analyze (vol1, vol2); delete vol1; delete vol2; } static void img_compare (Compare_parms* parms) { Plm_image::Pointer img1, img2; img1 = plm_image_load_native (parms->img_in_1_fn); if (!img1) { print_and_exit ("Error: could not open '%s' for read\n", parms->img_in_1_fn.c_str()); } img2 = plm_image_load_native (parms->img_in_2_fn); if (!img2) { print_and_exit ("Error: could not open '%s' for read\n", parms->img_in_2_fn.c_str()); } if (!Plm_image::compare_headers (img1, img2)) { print_and_exit ("Error: image sizes do not match\n"); } FloatImageType::Pointer fi1 = img1->itk_float (); FloatImageType::Pointer fi2 = img2->itk_float (); typedef itk::SubtractImageFilter< FloatImageType, FloatImageType, FloatImageType > SubtractFilterType; SubtractFilterType::Pointer sub_filter = SubtractFilterType::New(); sub_filter->SetInput1 (fi1); sub_filter->SetInput2 (fi2); try { sub_filter->Update(); } catch (itk::ExceptionObject & excep) { std::cerr << "ITK exception caught: " << excep << std::endl; exit (-1); } FloatImageType::Pointer diff = sub_filter->GetOutput (); typedef itk::ImageRegionConstIterator < FloatImageType > FloatIteratorType; FloatIteratorType it (diff, diff->GetRequestedRegion ()); int first = 1; float min_val = 0.0; float max_val = 0.0; int num = 0, num_dif = 0; double ave = 0.0; double mae = 0.0; double mse = 0.0; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { float v = it.Get(); if (first) { min_val = v; max_val = v; first = 0; } if (min_val > v) min_val = v; if (max_val < v) max_val = v; if (v != 0.0) num_dif ++; ave += v; mae += fabs (v); mse += (v * v); num ++; } printf ("MIN %f AVE %f MAX %f\n" "MAE %f MSE %f\n" "DIF %d NUM %d\n", min_val, (float) (ave / num), max_val, (float) (mae / num), (float) (mse / num), num_dif, num); } static void compare_main (Compare_parms* parms) { Plm_file_format file_type_1, file_type_2; /* What is the input file type? */ file_type_1 = plm_file_format_deduce (parms->img_in_1_fn); file_type_2 = plm_file_format_deduce (parms->img_in_2_fn); if (file_type_1 == PLM_FILE_FMT_VF && file_type_2 == PLM_FILE_FMT_VF) { vf_compare (parms); } else { img_compare (parms); } } static void compare_print_usage (void) { printf ("Usage: plastimatch compare file_1 file_2\n" ); exit (-1); } static void compare_parse_args (Compare_parms* parms, int argc, char* argv[]) { if (argc != 4) { compare_print_usage (); } parms->img_in_1_fn = argv[2]; parms->img_in_2_fn = argv[3]; } void do_command_compare (int argc, char *argv[]) { Compare_parms parms; compare_parse_args (&parms, argc, argv); compare_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_compare.h000066400000000000000000000007611321604176500301740ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_compare_h_ #define _pcmd_compare_h_ #include "plmcli_config.h" #include #include class Compare_parms { public: std::string img_in_1_fn; std::string img_in_2_fn; }; void do_command_compare (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_compose.cxx000066400000000000000000000106371321604176500305710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include #include "itkImageRegionIterator.h" #include "itkVectorLinearInterpolateImageFunction.h" #include "itk_image_save.h" #include "itk_image_type.h" #include "pcmd_compose.h" #include "plm_image_header.h" #include "print_and_exit.h" #include "xform.h" void vf_compose ( DeformationFieldType::Pointer vf1, DeformationFieldType::Pointer vf2, DeformationFieldType::Pointer vf_out ) { vf_out->SetRegions (vf1->GetBufferedRegion()); vf_out->SetOrigin (vf1->GetOrigin()); vf_out->SetSpacing (vf1->GetSpacing()); vf_out->Allocate(); /* No one should ever have to write code like this */ typedef itk::ImageRegionIterator< DeformationFieldType > FieldIterator; FieldIterator vf1_it (vf1, vf1->GetRequestedRegion()); FieldIterator vf_out_it (vf_out, vf_out->GetRequestedRegion()); DeformationFieldType::IndexType index; FloatPoint3DType point_1, point_2, point_3; FloatVector3DType displacement_1; typedef itk::VectorLinearInterpolateImageFunction < DeformationFieldType, float > VectorInterpolatorType; VectorInterpolatorType::Pointer interpolator = VectorInterpolatorType::New(); interpolator->SetInputImage (vf2); VectorInterpolatorType::OutputType displacement_2; FloatVector3DType displacement_3; vf1_it.GoToBegin(); vf_out_it.GoToBegin(); while (!vf1_it.IsAtEnd()) { index = vf1_it.GetIndex(); vf1->TransformIndexToPhysicalPoint (index, point_1); displacement_1 = vf1_it.Get (); for (int r = 0; r < 3; r++) { point_2[r] = point_1[r] + displacement_1[r]; } if (interpolator->IsInsideBuffer (point_2)) { displacement_2 = interpolator->Evaluate (point_2); for (int r = 0; r < 3; r++) { point_3[r] = point_2[r] + displacement_2[r]; displacement_3[r] = point_3[r] - point_1[r]; } vf_out_it.Set (displacement_3); } else { for (int r = 0; r < 3; r++) { displacement_3[r] = 0.0; } vf_out_it.Set (displacement_3); } ++vf_out_it; ++vf1_it; } } static void convert_to_itk_vf ( Xform *this_xf, /* I/O: The xform to convert */ Xform *another_xf /* I: The other xform, which helps guessing size */ ) { Plm_image_header pih; /* Guess size for rendering vector field */ switch (this_xf->m_type) { case XFORM_ITK_TRANSLATION: case XFORM_ITK_VERSOR: case XFORM_ITK_QUATERNION: case XFORM_ITK_AFFINE: case XFORM_ITK_BSPLINE: switch (another_xf->m_type) { case XFORM_ITK_VECTOR_FIELD: pih.set_from_itk_image (another_xf->get_itk_vf()); break; case XFORM_GPUIT_BSPLINE: pih.set_from_gpuit_bspline (another_xf->get_gpuit_bsp()); break; default: print_and_exit ( "Sorry, couldn't guess size to render vf.\n"); break; } break; case XFORM_ITK_VECTOR_FIELD: /* Do nothing */ return; case XFORM_GPUIT_BSPLINE: pih.set_from_gpuit_bspline (this_xf->get_gpuit_bsp()); break; case XFORM_ITK_TPS: case XFORM_GPUIT_VECTOR_FIELD: default: /* Not yet handled */ print_and_exit ( "Sorry, couldn't convert xf to vf.\n"); break; } xform_to_itk_vf (this_xf, this_xf, &pih); } static void compose_main (Compose_parms* parms) { Xform xf1, xf2; xform_load (&xf1, parms->xf_in_1_fn); xform_load (&xf2, parms->xf_in_2_fn); convert_to_itk_vf (&xf1, &xf2); convert_to_itk_vf (&xf2, &xf1); DeformationFieldType::Pointer vf_out = DeformationFieldType::New(); vf_compose (xf1.get_itk_vf(), xf2.get_itk_vf(), vf_out); itk_image_save (vf_out, parms->xf_out_fn); } static void print_usage (void) { printf ( "Usage: plastimatch compose file_1 file_2 outfile\n" "\n" "Note: file_1 is applied first, and then file_2.\n" " outfile = file_2 o file_1\n" " x -> x + file_2(x + file_1(x))\n" ); exit (-1); } static void compose_parse_args (Compose_parms* parms, int argc, char* argv[]) { if (argc != 5) { print_usage (); } parms->xf_in_1_fn = argv[2]; parms->xf_in_2_fn = argv[3]; parms->xf_out_fn = argv[4]; } void do_command_compose (int argc, char *argv[]) { Compose_parms parms; compose_parse_args (&parms, argc, argv); compose_main (&parms); printf ("Finished!\n"); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_compose.h000066400000000000000000000014241321604176500302100ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_compose_h_ #define _pcmd_compose_h_ #include "plmcli_config.h" #include #include #include "plm_image_type.h" class Compose_parms { public: std::string xf_in_1_fn; std::string xf_in_2_fn; std::string xf_out_fn; bool negate_mask; float mask_value; bool output_dicom; Plm_image_type output_type; public: Compose_parms () { negate_mask = false; mask_value = 0.; output_dicom = false; output_type = PLM_IMG_TYPE_UNDEFINED; } }; void do_command_compose (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_crop.cxx000066400000000000000000000065621321604176500300710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "itk_crop.h" #include "pcmd_crop.h" #include "plm_clp.h" #include "plm_image.h" #include "print_and_exit.h" class Crop_parms { public: std::string img_in_fn; std::string img_out_fn; int crop_vox[6]; public: Crop_parms () { img_in_fn = ""; img_out_fn = ""; for (int i = 0; i < 6; i++) { crop_vox[i] = 0; } } }; static void crop_main (Crop_parms* parms) { Plm_image plm_image; plm_image.load_native (parms->img_in_fn); switch (plm_image.m_type) { case PLM_IMG_TYPE_ITK_UCHAR: plm_image.m_itk_uchar = itk_crop (plm_image.m_itk_uchar, parms->crop_vox); break; case PLM_IMG_TYPE_ITK_SHORT: plm_image.m_itk_short = itk_crop (plm_image.m_itk_short, parms->crop_vox); break; case PLM_IMG_TYPE_ITK_ULONG: plm_image.m_itk_uint32 = itk_crop (plm_image.m_itk_uint32, parms->crop_vox); break; case PLM_IMG_TYPE_ITK_FLOAT: plm_image.m_itk_float = itk_crop (plm_image.m_itk_float, parms->crop_vox); break; default: print_and_exit ("Unhandled image type in resample_main()\n"); break; } plm_image.convert_and_save (parms->img_out_fn, plm_image.m_type); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Crop_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input", "input directory or filename", 1, ""); /* Output files */ parser->add_long_option ("", "output", "output image", 1, ""); /* Adjustment string */ parser->add_long_option ("", "voxels", "a string that specifies the voxels in the six corners " "of the region to be cropped, in the form " "\"x1 x2 y1 y2 z1 z2\"", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("input")) { throw (dlib::error ("Error. Please specify an input file " "using the --input option")); } /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Check that an output file was given */ if (!parser->option ("voxels")) { throw (dlib::error ("Error. Please specify the voxels to be " "cropped using the --voxels option")); } /* Input files */ parms->img_in_fn = parser->get_string("input").c_str(); /* Output files */ parms->img_out_fn = parser->get_string("output").c_str(); /* Voxels option */ parser->assign_int_6 (parms->crop_vox, "voxels"); } void do_command_crop (int argc, char *argv[]) { Crop_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); crop_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_crop.h000066400000000000000000000005441321604176500275100ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_crop_h_ #define _pcmd_crop_h_ #include "plmcli_config.h" void do_command_crop (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_dice.cxx000066400000000000000000000063441321604176500300300ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "dice_statistics.h" #include "hausdorff_distance.h" #include "itk_image_load.h" #include "itk_resample.h" #include "plm_clp.h" #include "plm_image_header.h" class Pcmd_dice_parms { public: bool commands_were_requested; bool have_dice_option; bool have_hausdorff_option; std::string reference_image_fn; std::string test_image_fn; public: Pcmd_dice_parms () { commands_were_requested = false; have_dice_option = false; have_hausdorff_option = false; } }; static void usage_fn (dlib::Plm_clp *parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch dice [options] reference-image test-image\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Pcmd_dice_parms *parms, dlib::Plm_clp *parser, int argc, char *argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Commands to execute */ parser->add_long_option ("", "all", "Compute both Dice and Hausdorff distances (equivalent" " to --dice --hausdorff)", 0); parser->add_long_option ("", "dice", "Compute Dice coefficient (default)", 0); parser->add_long_option ("", "hausdorff", "Compute Hausdorff distances (max, average, boundary, etc.)", 0); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); if (parser->option("dice")) { parms->commands_were_requested = true; parms->have_dice_option = true; } if (parser->option("hausdorff")) { parms->commands_were_requested = true; parms->have_hausdorff_option = true; } if (parser->option("all")) { parms->commands_were_requested = true; parms->have_dice_option = true; parms->have_hausdorff_option = true; } if (!parms->commands_were_requested) { parms->have_dice_option = true; } /* Check that two input files were given */ if (parser->number_of_arguments() < 2) { throw (dlib::error ("Error. You must specify two input files")); } else if (parser->number_of_arguments() > 2) { std::string extra_arg = (*parser)[1]; throw (dlib::error ("Error. Extra argument " + extra_arg)); } /* Copy values into output struct */ parms->reference_image_fn = (*parser)[0]; parms->test_image_fn = (*parser)[1]; } void do_command_dice (int argc, char *argv[]) { Pcmd_dice_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); UCharImageType::Pointer image_1 = itk_image_load_uchar ( parms.reference_image_fn, 0); UCharImageType::Pointer image_2 = itk_image_load_uchar ( parms.test_image_fn, 0); if (parms.have_dice_option) { Dice_statistics ds; ds.set_reference_image (image_1); ds.set_compare_image (image_2); ds.run (); ds.debug (); } if (parms.have_hausdorff_option) { do_hausdorff (image_1, image_2); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_dice.h000066400000000000000000000005101321604176500274420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_dice_h_ #define _pcmd_dice_h_ void do_command_dice (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_diff.cxx000066400000000000000000000015211321604176500300240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include #include "diff.h" #include "pcmd_diff.h" static void diff_print_usage (void) { printf ("Usage: plastimatch diff image_in_1 image_in_2 image_out\n" ); exit (-1); } static void diff_parse_args (Diff_parms* parms, int argc, char* argv[]) { if (argc != 5) { diff_print_usage (); } parms->img_in_1_fn = argv[2]; parms->img_in_2_fn = argv[3]; parms->img_out_fn = argv[4]; } void do_command_diff (int argc, char *argv[]) { Diff_parms parms; diff_parse_args (&parms, argc, argv); diff_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_diff.h000066400000000000000000000005441321604176500274550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_diff_h_ #define _pcmd_diff_h_ #include "plmcli_config.h" void do_command_diff (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_dmap.cxx000066400000000000000000000076641321604176500300530ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "distance_map.h" #include "itk_image_save.h" #include "pcmd_dmap.h" #include "plm_clp.h" #include "plm_image.h" #include "print_and_exit.h" class Dmap_parms { public: std::string img_in_fn; std::string img_out_fn; std::string algorithm; bool squared_distance; bool have_maximum_distance; float maximum_distance; bool inside_positive; public: Dmap_parms () { inside_positive = false; have_maximum_distance = false; maximum_distance = FLT_MAX; squared_distance = false; } }; static void dmap_main (Dmap_parms* parms) { Distance_map dmap; dmap.set_input_image (parms->img_in_fn); dmap.set_algorithm (parms->algorithm); dmap.set_inside_is_positive (parms->inside_positive); dmap.set_use_squared_distance (parms->squared_distance); if (parms->have_maximum_distance) { dmap.set_maximum_distance (parms->maximum_distance); } dmap.run (); FloatImageType::Pointer dmap_image = dmap.get_output_image(); itk_image_save (dmap_image, parms->img_out_fn.c_str()); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Dmap_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input", "input directory or filename", 1, ""); /* Output files */ parser->add_long_option ("", "output", "output image", 1, ""); /* Algorithm options */ parser->add_long_option ("", "algorithm", "a string that specifies the algorithm used for distance " "map calculation, either " "\"maurer\", " "\"danielsson\", " " or \"itk-danielsson\" " "(default is \"danielsson\")", 1, "maurer"); parser->add_long_option ("", "squared-distance", "return the squared distance instead of distance", 0); parser->add_long_option ("", "inside-positive", "voxels inside the structure should be positive" " (by default they are negative)", 0); parser->add_long_option ("", "maximum-distance", "voxels with distances greater than this number will have the " "distance truncated to this number", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("input")) { throw (dlib::error ("Error. Please specify an input file " "using the --input option")); } /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Input files */ parms->img_in_fn = parser->get_string("input"); /* Output files */ parms->img_out_fn = parser->get_string("output"); /* Algorithm options */ parms->algorithm = parser->get_string("algorithm"); if (parser->option("squared-distance")) { parms->squared_distance = true; } if (parser->option("inside-positive")) { parms->inside_positive = true; } if (parser->option("maximum-distance")) { parms->have_maximum_distance = true; parms->maximum_distance = parser->get_float ("maximum-distance"); } } void do_command_dmap (int argc, char *argv[]) { Dmap_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); dmap_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_dmap.h000066400000000000000000000005441321604176500274660ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_dmap_h_ #define _pcmd_dmap_h_ #include "plmcli_config.h" void do_command_dmap (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_dose.cxx000066400000000000000000000015561321604176500300560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "logfile.h" #include "pcmd_dose.h" #include "plm_return_code.h" #include "plm_timer.h" #include "rt_plan.h" void do_command_dose (int argc, char* argv[]) { if (argc < 3) { lprintf ("Usage: plastimatch dose command_file\n"); exit (1); } char *command_file = argv[2]; Plm_timer timer; Rt_plan plan; timer.start (); if (plan.set_command_file (command_file) != PLM_SUCCESS) { lprintf ("Error parsing command file.\n"); return; } plan.compute_plan (); lprintf ("Total execution time : %f secondes.\n", timer.report ()); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_dose.h000066400000000000000000000005441321604176500274770ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_dose_h_ #define _pcmd_dose_h_ #include "plmcli_config.h" void do_command_dose (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_drr.cxx000066400000000000000000000050601321604176500277050ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "pcmd_drr.h" #include "plm_clp.h" class Drr_parms { public: std::string input_fn; std::string output_fn; std::string output_dicom; }; static void do_drr (Drr_parms *parms) { } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch drr [options] [infile]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Drr_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); #if defined (commentout) /* Basic options */ parser->add_long_option ("", "output-img", "Output image filename", 1, ""); parser->add_long_option ("", "input", "Input image filename (required)", 1, ""); parser->add_long_option ("", "bottom", "Bottom of patient (top of couch)", 1, ""); parser->add_long_option ("", "lower-threshold", "Lower threshold (include voxels above this value)", 1, ""); parser->add_long_option ("", "debug", "Create debug images", 0); parser->add_long_option ("", "fast", "Use reduced image size", 0); #endif /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); #if defined (commentout) /* Check that an input file was given */ parser->check_required ("input"); parser->check_required ("output-img"); Segment_body *sb = &parms->sb; /* Copy values into output struct */ parms->output_fn = parser->get_string("output-img"); #if defined (commentout) parms->output_dicom = parser->get_string("output-dicom"); #endif parms->input_fn = parser->get_string("input"); if (parser->option ("lower-threshold")) { sb->m_lower_threshold = parser->get_float("lower-threshold"); } #if defined (commentout) parms->upper_threshold = parser->get_float("upper-threshold"); #endif if (parser->option ("bottom")) { sb->m_bot_given = true; sb->m_bot = parser->get_float ("bottom"); } if (parser->option ("fast")) { sb->m_fast = true; } if (parser->option ("debug")) { sb->m_debug = true; } #endif } void do_command_drr (int argc, char *argv[]) { Drr_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); do_drr (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_drr.h000066400000000000000000000005051321604176500273310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_drr_h_ #define _pcmd_drr_h_ void do_command_drr (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_dvh.cxx000066400000000000000000000116761321604176500277110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "dvh.h" #include "pcmd_dvh.h" #include "plm_clp.h" class Dvh_parms_pcmd { public: std::string input_ss_img_fn; std::string input_ss_list_fn; std::string input_dose_fn; std::string output_csv_fn; Dvh::Dvh_units dose_units; Dvh::Dvh_normalization normalization; Dvh::Histogram_type histogram_type; int num_bins; float bin_width; public: Dvh_parms_pcmd () { dose_units = Dvh::default_dose_units (); normalization = Dvh::default_normalization (); histogram_type = Dvh::default_histogram_type (); num_bins = Dvh::default_histogram_num_bins (); bin_width = Dvh::default_histogram_bin_width (); } }; static void usage_fn (dlib::Plm_clp *parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch dvh [options]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Dvh_parms_pcmd *parms, dlib::Plm_clp *parser, int argc, char *argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input-ss-img", "structure set image file", 1, ""); parser->add_long_option ("", "input-ss-list", "structure set list file containing names and colors", 1, ""); parser->add_long_option ("", "input-dose", "dose image file", 1, ""); /* Parameters */ parser->add_long_option ("", "dose-units", "specify units of dose in input file as either cGy as \"cgy\" " "or Gy as \"gy\" (default=\"gy\")", 1, ""); parser->add_long_option ("", "cumulative", "create a cumulative DVH (this is the default)", 0); parser->add_long_option ("", "differential", "create a differential DVH instead of a cumulative DVH", 0); parser->add_long_option ("", "normalization", "specify histogram values as either voxels \"vox\" or percent " "\"pct\" (default=\"pct\")", 1, ""); parser->add_long_option ("", "num-bins", "specify number of bins in the histogram (default=256)", 1, ""); parser->add_long_option ("", "bin-width", "specify bin width in the histogram in units of Gy " "(default=0.5)", 1, ""); /* Output files */ parser->add_long_option ("", "output-csv", "file to save dose volume histogram data in csv format", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that input file were given */ if (!parser->have_option ("input-dose")) { throw (dlib::error ("Error. You must specify an input dose " " with --input-dose")); } if (!parser->have_option ("input-ss-img")) { throw (dlib::error ("Error. You must specify an input structure " "set with --input-ss-img image")); } /* Check that an output file was given */ if (!parser->have_option ("output-csv")) { throw (dlib::error ( "Error. You must specify an output file with --output-csv")); } /* Copy values into output struct */ parms->input_ss_img_fn = parser->get_string("input-ss-img"); if (parser->have_option ("input-ss-list")) { parms->input_ss_list_fn = parser->get_string("input-ss-list"); } parms->input_dose_fn = parser->get_string("input-dose"); parms->output_csv_fn = parser->get_string("output-csv"); if (parser->have_option ("dose-units")) { if (parser->get_string("dose-units") == "cGy" || parser->get_string("dose-units") == "cgy") { parms->dose_units = Dvh::DVH_UNITS_CGY; } } if (parser->have_option ("normalization")) { if (parser->get_string("normalization") == "vox") { parms->normalization = Dvh::DVH_NORMALIZATION_VOX; } } if (parser->have_option ("differential")) { parms->histogram_type = Dvh::DVH_DIFFERENTIAL_HISTOGRAM; } if (parser->have_option ("num-bins")) { parms->num_bins = parser->get_int ("num-bins"); } if (parser->have_option ("bin-width")) { parms->bin_width = parser->get_float ("bin-width"); } } void do_command_dvh (int argc, char *argv[]) { Dvh_parms_pcmd parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); Dvh dvh; dvh.set_structure_set_image ( parms.input_ss_img_fn.c_str(), parms.input_ss_list_fn.c_str()); dvh.set_dose_image ( parms.input_dose_fn.c_str()); dvh.set_dose_units (parms.dose_units); dvh.set_dvh_parameters ( parms.normalization, parms.histogram_type, parms.num_bins, parms.bin_width); dvh.run (); dvh.save_csv (parms.output_csv_fn.c_str()); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_dvh.h000066400000000000000000000005411321604176500273230ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_dvh_h_ #define _pcmd_dvh_h_ #include "plmcli_config.h" void do_command_dvh (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_filter.cxx000066400000000000000000000167231321604176500304130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "itk_image_stats.h" #include "logfile.h" #include "plm_clp.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_math.h" #include "pcmd_filter.h" #include "print_and_exit.h" #include "rt_study.h" #include "synthetic_mha.h" #include "volume_conv.h" #include "volume_gaussian.h" #include "volume_grad.h" static Plm_image::Pointer create_gabor_kernel (const Filter_parms *parms, const Plm_image::Pointer& img) { Rt_study rt_study; Synthetic_mha_parms smp; Plm_image_header pih (img); int ker_width[3], ker_half_width[3]; for (int i = 0; i < 3; i++) { ker_half_width[i] = 2 * parms->gauss_width / pih.spacing(i); ker_width[i] = 2 * ker_half_width[i] + 1; smp.dim[i] = ker_width[i]; smp.origin[i] = - pih.spacing(i) * ker_half_width[i]; smp.spacing[i] = pih.spacing(i); smp.gauss_center[i] = 0.f; smp.gauss_std[i] = parms->gauss_width; } smp.gabor_use_k_fib = parms->gabor_use_k_fib; smp.gabor_k_fib[0] = parms->gabor_k_fib[0]; smp.gabor_k_fib[1] = parms->gabor_k_fib[1]; smp.pattern = PATTERN_GABOR; smp.background = 0; smp.foreground = 1; smp.image_normalization = Synthetic_mha_parms::NORMALIZATION_GABOR; smp.m_want_ss_img = false; smp.m_want_dose_img = false; synthetic_mha (&rt_study, &smp); return rt_study.get_image(); } static Plm_image::Pointer create_gauss_kernel (const Filter_parms *parms, const Plm_image::Pointer& img) { Rt_study rt_study; Synthetic_mha_parms smp; Plm_image_header pih (img); int ker_width[3], ker_half_width[3]; for (int i = 0; i < 3; i++) { ker_half_width[i] = 2 * parms->gauss_width / pih.spacing(i); ker_width[i] = 2 * ker_half_width[i] + 1; smp.dim[i] = ker_width[i]; smp.origin[i] = - pih.spacing(i) * ker_half_width[i]; smp.spacing[i] = pih.spacing(i); smp.gauss_center[i] = 0.f; smp.gauss_std[i] = parms->gauss_width; } smp.pattern = PATTERN_GAUSS; smp.background = 0; smp.foreground = 1; smp.image_normalization = Synthetic_mha_parms::NORMALIZATION_SUM_ONE; smp.m_want_ss_img = false; smp.m_want_dose_img = false; synthetic_mha (&rt_study, &smp); return rt_study.get_image(); } static void filter_main (Filter_parms* parms) { Plm_image::Pointer img = Plm_image::New (parms->in_image_fn); if (!img) { print_and_exit ("Sorry, couldn't load input image\n"); } Plm_image::Pointer ker; Volume::Pointer volume_out; if (parms->filter_type == Filter_parms::FILTER_TYPE_GABOR) { ker = create_gabor_kernel (parms, img); } else if (parms->filter_type == Filter_parms::FILTER_TYPE_GAUSSIAN_COMBINED) { ker = create_gauss_kernel (parms, img); } else if (parms->filter_type == Filter_parms::FILTER_TYPE_GAUSSIAN_SEPARABLE) { volume_out = volume_gaussian ( img->get_volume_float(), parms->gauss_width, 2.0); } else if (parms->filter_type == Filter_parms::FILTER_TYPE_GRADIENT_MAGNITUDE) { volume_out = volume_gradient_magnitude ( img->get_volume_float()); } else if (parms->filter_type == Filter_parms::FILTER_TYPE_KERNEL) { /* Not yet implemented */ } /* For kernel-style filters, do the actual filtering here */ if (ker) { lprintf ("kernel size: %d %d %d\n", ker->dim(0), ker->dim(1), ker->dim(2)); if (parms->out_kernel_fn != "") { ker->save_image (parms->out_kernel_fn); } volume_out = volume_conv ( img->get_volume_float(), ker->get_volume_float()); } Plm_image::Pointer img_out = Plm_image::New (volume_out); double min_val, max_val, avg; int non_zero, num_vox; itk_image_stats (img_out->itk_float(), &min_val, &max_val, &avg, &non_zero, &num_vox); lprintf ("Filter result: MIN %g AVG %g MAX %g NONZERO: (%d / %d)\n", min_val, avg, max_val, non_zero, num_vox); if (parms->out_image_fn == "") { lprintf ("Warning: No output file specified.\n"); } else { img_out->save_image (parms->out_image_fn); } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options] input_image\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Filter_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Output files */ parser->add_long_option ("", "output", "output image filename", 1, ""); parser->add_long_option ("", "output-kernel", "output kernel filename", 1, ""); /* Main pattern */ parser->add_long_option ("", "pattern", "filter type: {" "gabor, gauss, gm, kernel" "}, default is gauss", 1, "gauss"); /* Filter options */ parser->add_long_option ("", "kernel", "kernel image filename", 1, ""); parser->add_long_option ("", "gauss-width", "the width (in mm) of a uniform Gaussian smoothing filter", 1, ""); parser->add_long_option ("", "gabor-k-fib", "choose gabor direction at index i within fibonacci spiral " "of length n; specified as \"i n\" where i and n are integers, " "and i is between 0 and n-1", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that two input files were given */ if (parser->number_of_arguments() != 1) { throw (dlib::error ("Error. You must specify one input file")); } /* Input files */ parms->in_image_fn = (*parser)[0].c_str(); /* Output files */ if (parser->option ("output")) { parms->out_image_fn = parser->get_string("output"); } if (parser->option ("output-kernel")) { parms->out_kernel_fn = parser->get_string("output-kernel"); } /* Main pattern */ std::string arg = parser->get_string ("pattern"); if (arg == "gabor") { parms->filter_type = Filter_parms::FILTER_TYPE_GABOR; } else if (arg == "gauss-slow") { parms->filter_type = Filter_parms::FILTER_TYPE_GAUSSIAN_COMBINED; } else if (arg == "gauss") { parms->filter_type = Filter_parms::FILTER_TYPE_GAUSSIAN_SEPARABLE; } else if (arg == "gm") { parms->filter_type = Filter_parms::FILTER_TYPE_GRADIENT_MAGNITUDE; } else if (arg == "kernel") { parms->filter_type = Filter_parms::FILTER_TYPE_KERNEL; } else { throw (dlib::error ("Error. Unknown --pattern argument: " + arg)); } /* Filter options */ if (parser->option ("kernel")) { parms->out_image_fn = parser->get_string("kernel"); } if (parser->option ("gauss-width")) { parms->gauss_width = parser->get_float("gauss-width"); } if (parser->option ("gabor-k-fib")) { parms->gabor_use_k_fib = true; parser->assign_int_2 (parms->gabor_k_fib, "gabor-k-fib"); } } void do_command_filter (int argc, char *argv[]) { Filter_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); filter_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_filter.h000066400000000000000000000020441321604176500300270ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_filter_h_ #define _pcmd_filter_h_ #include "plmcli_config.h" class Filter_parms { public: enum Filter_type { FILTER_TYPE_UNDEFINED, FILTER_TYPE_GABOR, FILTER_TYPE_GAUSSIAN_COMBINED, FILTER_TYPE_GAUSSIAN_SEPARABLE, FILTER_TYPE_GRADIENT_MAGNITUDE, FILTER_TYPE_KERNEL }; public: std::string in_image_fn; std::string in_kernel_fn; std::string out_image_fn; std::string out_kernel_fn; Filter_type filter_type; float gauss_width; bool gabor_use_k_fib; int gabor_k_fib[2]; public: Filter_parms () { filter_type = FILTER_TYPE_UNDEFINED; gauss_width = 10.f; gabor_use_k_fib = false; gabor_k_fib[0] = 0; gabor_k_fib[1] = 1; } }; void do_command_filter (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_gamma.cxx000066400000000000000000000227071321604176500302070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "gamma_dose_comparison.h" #include "logfile.h" #include "plm_clp.h" #include "plm_image.h" #include "plm_math.h" #include "pcmd_gamma.h" #include "print_and_exit.h" #include "plm_file_format.h" #include "rt_study.h" static void gamma_main (Gamma_parms* parms) { Gamma_dose_comparison gdc; //DICOM_RD compatible (added by YK, Feb 2015) //In the prev version, RD couldn't be read directly due to the scale factor inside of the DICOM file. //work-around was to use (plastimatch convert ...) //here, that feature has been integrated into plastimatch gamma Plm_file_format file_type_ref, file_type_comp; Rt_study rt_study_ref, rt_study_comp; file_type_ref = plm_file_format_deduce(parms->ref_image_fn.c_str()); file_type_comp = plm_file_format_deduce(parms->cmp_image_fn.c_str()); if (file_type_ref == PLM_FILE_FMT_DICOM_DOSE) { rt_study_ref.load(parms->ref_image_fn.c_str(), file_type_ref); if (rt_study_ref.has_dose()) { gdc.set_reference_image (rt_study_ref.get_dose()); } else { gdc.set_reference_image (parms->ref_image_fn.c_str()); } } else { gdc.set_reference_image (parms->ref_image_fn.c_str()); } if (file_type_comp == PLM_FILE_FMT_DICOM_DOSE) { rt_study_comp.load(parms->cmp_image_fn.c_str(), file_type_comp); if (rt_study_comp.has_dose()) { gdc.set_compare_image (rt_study_comp.get_dose()); } else { gdc.set_compare_image (parms->cmp_image_fn.c_str()); } } else { gdc.set_compare_image (parms->cmp_image_fn.c_str()); } //End DICOM-RD if (parms->mask_image_fn != "") { gdc.set_mask_image (parms->mask_image_fn); } gdc.set_spatial_tolerance (parms->dta_tolerance); gdc.set_dose_difference_tolerance (parms->dose_tolerance); if (parms->have_reference_dose) { gdc.set_reference_dose (parms->reference_dose); } gdc.set_gamma_max (parms->gamma_max); /*Extended by YK*/ gdc.set_interp_search(parms->b_interp_search);//default: false gdc.set_local_gamma(parms->b_local_gamma);//default: false gdc.set_compute_full_region(parms->b_compute_full_region);//default: false gdc.set_resample_nn(parms->b_resample_nn); //default: false //gdc.set_include_high_dose_in_comp(parms->b_include_high_dose_comp); //default: false gdc.set_ref_only_threshold(parms->b_ref_only_threshold); //default: false if (parms->f_inherent_resample_mm > 0.0) { gdc.set_inherent_resample_mm(parms->f_inherent_resample_mm); } if (parms->f_analysis_threshold > 0) { gdc.set_analysis_threshold(parms->f_analysis_threshold);//0.1 = 10% } gdc.run (); if (parms->out_image_fn != "") { Plm_image::Pointer gamma_image = gdc.get_gamma_image (); gamma_image->save_image (parms->out_image_fn); } if (parms->out_failmap_fn != "") { gdc.get_fail_image()->save_image(parms->out_failmap_fn); } if (parms->out_report_fn != "") { //Export output text using gdc.get_report_string(); std::ofstream fout; fout.open(parms->out_report_fn.c_str()); if (!fout.fail()){ fout << "Reference_file_name\t" << parms->ref_image_fn.c_str() << std::endl; fout << "Compare_file_name\t" << parms->cmp_image_fn.c_str() << std::endl; fout << gdc.get_report_string(); fout.close(); } } lprintf ("Pass rate = %2.6f %%\n", gdc.get_pass_fraction() * 100.0); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options] image_1 image_2\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Gamma_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Output files */ parser->add_long_option ("", "output", "Output image", 1, ""); /* Input files */ parser->add_long_option ("", "mask", "File name for input mask image, which controls which voxels " "are used in the gamma calculation", 1, ""); /* Gamma options */ parser->add_long_option ("", "dose-tolerance", "The scaling coefficient for dose difference. (e.g. put 0.02 if you want to apply 2% dose difference criterion) " "(default is 0.03)", 1, "0.03"); parser->add_long_option ("", "dta-tolerance", "The distance-to-agreement (DTA) scaling coefficient in mm " "(default is 3)", 1, "3"); parser->add_long_option ("", "reference-dose", "The prescription dose (Gy) used to compute dose tolerance; if not " "specified, then maximum dose in reference volume is used", 1, ""); parser->add_long_option ("", "gamma-max", "The maximum value of gamma to compute; smaller values run faster " "(default is 2.0)", 1, "2.0"); /* extended by YK*/ parser->add_long_option("", "ref-only-threshold", "With this option, analysis threshold is applied only to ref dose, regardless of the corresponding dose of compare image. ", 0); parser->add_long_option("", "interp-search", "With this option, smart interpolation search will be used in points near the reference point. This will eliminate the needs of fine resampling. However, it will take longer time to compute. ", 0); parser->add_long_option("", "local-gamma", "With this option, dose difference is calculated based on local dose difference. Otherwise, a given reference dose will be used, which is called global-gamma. ",0); parser->add_long_option("", "compute-full-region", "With this option, full gamma map will be generated over the entire image region (even for low-dose region). It is recommended not to use this option to speed up the computation. It has no effect on gamma pass-rate. ", 0); parser->add_long_option("", "resample-nn", "With this option, Nearest Neighbor will be used instead of linear interpolation in resampling the compare-image to the reference image. Not recommended for better results. ", 0); parser->add_long_option("", "inherent-resample", "Spacing value in [mm]. The reference image itself will be resampled by this value (Note: resampling compare-image to ref-image is inherent already). If arg < 0, this option is disabled. " "(default is -1.0)", 1, "-1.0"); parser->add_long_option("", "analysis-threshold", "Analysis threshold for dose in float (for example, input 0.1 to apply 10% of the reference dose). The final threshold dose (Gy) is calculated by multiplying this value and a given reference dose (or maximum dose if not given). " "(default is 0.1)", 1, "0.1"); parser->add_long_option("", "output-text", "Text file path for gamma evaluation result. ", 1, ""); parser->add_long_option("", "output-failmap", "File path for binary gamma evaluation result. ", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that two input files were given */ if (parser->number_of_arguments() < 2) { throw (dlib::error ("Error. You must specify two input files")); } else if (parser->number_of_arguments() > 2) { std::string extra_arg = (*parser)[1]; throw (dlib::error ("Error. Extra argument " + extra_arg)); } /* Input files */ parms->ref_image_fn = (*parser)[0].c_str(); parms->cmp_image_fn = (*parser)[1].c_str(); if (parser->option ("mask")) { parms->mask_image_fn = parser->get_string("mask"); } /* Output files */ if (parser->option ("output")) { parms->out_image_fn = parser->get_string("output"); } if (parser->option("output-failmap")) { parms->out_failmap_fn = parser->get_string("output-failmap"); } /* Gamma options */ parms->dose_tolerance = parser->get_float("dose-tolerance"); parms->dta_tolerance = parser->get_float("dta-tolerance"); parms->gamma_max = parser->get_float("gamma-max"); if (parser->option("reference-dose")) { parms->have_reference_dose = true; parms->reference_dose = parser->get_float("reference-dose"); } if (parser->option("interp-search")) { parms->b_interp_search = true; } if (parser->option("ref-only-threshold")) { parms->b_ref_only_threshold = true; } if (parser->option("local-gamma")) { parms->b_local_gamma = true; } if (parser->option("compute-full-region")) { parms->b_compute_full_region = true; } if (parser->option("resample-nn")) { parms->b_resample_nn = true; } if (parser->option("inherent-resample")) { parms->f_inherent_resample_mm = parser->get_float("inherent-resample"); } if (parser->option("analysis-threshold")) { parms->f_analysis_threshold = parser->get_float("analysis-threshold"); } /* Output file for text report */ if (parser->option("output-text")) { parms->out_report_fn = parser->get_string("output-text"); } } void do_command_gamma (int argc, char *argv[]) { Gamma_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); gamma_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_gamma.h000066400000000000000000000037211321604176500276270ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_gamma_h_ #define _pcmd_gamma_h_ #include "plmcli_config.h" #include #include #include "plm_image_type.h" class Gamma_parms { public: std::string ref_image_fn; std::string cmp_image_fn; std::string mask_image_fn; std::string out_image_fn; std::string out_failmap_fn; /* Gamma options */ float dose_tolerance; float dta_tolerance; bool have_reference_dose; float reference_dose; float gamma_max; /* Extended Gamma options by YK*/ std::string out_report_fn; //YK: text file name bool b_local_gamma; // If true, local dose difference will be used. bool b_compute_full_region; // If true, gamma will not be calculated for points below the threshold dose e.g. <10% float f_inherent_resample_mm; //if -1.0, no resample will be carried out. float f_analysis_threshold; //if -1.0, no threshold will be applied. typical value = 0.1 (10%) bool b_resample_nn; //with this on, nearest resample will be used for comp-to-ref image resampling (as well as inherent resampling for ref image) bool b_interp_search; /*With this option, analysis threshold is applied only to ref dose, regardless of the corresponding dose of compare image.*/ bool b_ref_only_threshold; public: Gamma_parms () { dose_tolerance = .03f; dta_tolerance = 3.f; have_reference_dose = false; reference_dose = 0.f; gamma_max = 2.0f; b_local_gamma = false; b_compute_full_region = false; f_inherent_resample_mm = -1.0; f_analysis_threshold = 0.1; b_resample_nn = false; b_interp_search = false; b_ref_only_threshold = false; } }; void do_command_gamma (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_header.cxx000066400000000000000000000033631321604176500303520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "pcmd_header.h" #include "plm_clp.h" #include "plm_image.h" class Header_parms { public: std::list input_fns; }; static void header_main (Header_parms* parms) { Plm_image pli; std::list::iterator it = parms->input_fns.begin(); while (it != parms->input_fns.end()) { pli.load_native (*it); pli.print (); ++it; } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ( "Usage: plastimatch header [options] input_file [input_file ...]\n"); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Header_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that no extraneous options were given */ if (parser->number_of_arguments() == 0) { throw (dlib::error ("Error. You must specify at least one " "file for printing header.")); } /* Copy input filenames to parms struct */ for (unsigned long i = 0; i < parser->number_of_arguments(); i++) { parms->input_fns.push_back ((*parser)[i]); } } void do_command_header (int argc, char *argv[]) { Header_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); header_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_header.h000066400000000000000000000005521321604176500277740ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_header_h_ #define _pcmd_header_h_ #include "plmcli_config.h" void do_command_header (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_jacobian.cxx000066400000000000000000000064071321604176500306720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "itk_image_load.h" #include "itk_image_type.h" #include "pcmd_jacobian.h" #include "plm_clp.h" #include "plm_image.h" #include "vf_jacobian.h" class Jacobian_parms { public: std::string input_fn; std::string outputimg_fn; std::string outputstats_fn; public: Jacobian_parms () { outputimg_fn = " "; outputstats_fn = " "; } }; static void jacobian_main (Jacobian_parms* parms) { //Xform vol; FloatImageType::Pointer jacimage; std::cout << "file name: " << parms->input_fn; //xform_load (&vol, (const char*) parms->input_fn); DeformationFieldType::Pointer vol = itk_image_load_float_field ( parms->input_fn); std::cout << "...loaded xf!" << std::endl; /* Make jacobian */ Jacobian jacobian; jacobian.set_input_vf (vol); jacobian.set_output_vfstats_name (parms->outputstats_fn); jacimage=jacobian.make_jacobian(); Plm_image img; img.init(); img.set_itk( jacimage); img.save_image(parms->outputimg_fn); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Jacobian_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input", "input directory or filename of image", 1, ""); /* Output files */ parser->add_long_option ("", "output-img", "output image; can be mha, mhd, nii, nrrd, or other format " "supported by ITK", 1, ""); /* Output files */ parser->add_long_option ("", "output-stats", "output stats file; .txt format", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an input file was given */ if (!parser->option ("input")) { throw (dlib::error ("Error. Please specify an input file ")); } /* Check that an output file was given */ if (!parser->option ("output-img")) { throw (dlib::error ("Error. Please specify an output image file ")); } /* Check that no extraneous options were given */ if (parser->number_of_arguments() != 0) { std::string extra_arg = (*parser)[0]; throw (dlib::error ("Error. Unknown option " + extra_arg)); } /* Input/output files */ parms->input_fn = parser->get_string("input").c_str(); parms->outputimg_fn = parser->get_string("output-img").c_str(); parms->outputstats_fn = parser->get_string("output-stats").c_str(); /* Other options */ std::string arg = parser->get_string ("output-stats"); } void do_command_jacobian (int argc, char *argv[]) { Jacobian_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); /* Run the jacobianer */ jacobian_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_jacobian.h000066400000000000000000000006301321604176500303070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_jacobian_h_ #define _pcmd_jacobian_h_ #include "plmcli_config.h" #include #include void do_command_jacobian (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_mabs.cxx000066400000000000000000000132571321604176500300470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "mabs.h" #include "mabs_parms.h" #include "pcmd_mabs.h" #include "plm_clp.h" class Mabs_parms_pcmd { public: bool atlas_selection; bool train_atlas_selection; bool convert; bool prealign; bool train_registration; bool train; bool segment; std::string cmd_file_fn; std::string input_fn; std::string input_roi_fn; std::string output_dir; std::string output_dicom_dir; public: Mabs_parms_pcmd () { atlas_selection = false; train_atlas_selection = false; convert = false; prealign = false; train = false; train_registration = false; segment = false; } }; static void usage_fn (dlib::Plm_clp *parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch mabs [options] command_file\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Mabs_parms_pcmd *parms, dlib::Plm_clp *parser, int argc, char *argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Parameters */ parser->add_long_option ("", "atlas-selection", "run just atlas selection", 1, ""); parser->add_long_option ("", "train-atlas-selection", "run just train atlas selection", 0); parser->add_long_option ("", "convert", "pre-process atlas", 0); parser->add_long_option ("", "pre-align", "pre-process atlas", 0); parser->add_long_option ("", "train", "perform full training to find the best registration " " and segmentation parameters", 0); parser->add_long_option ("", "train-registration", "perform limited training to find the best registration " "parameters only", 0); parser->add_long_option ("", "segment", "use mabs to segment the specified image or directory", 1, ""); parser->add_long_option ("", "input-roi", "input mask used to prealign the center of gravity", 1, ""); parser->add_long_option ("", "output", "output (non-dicom) directory when doing a segmentation", 1, ""); parser->add_long_option ("", "output-dicom", "output dicom directory when doing a segmentation", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that only one argument was given */ if (parser->number_of_arguments() != 1) { throw (dlib::error ( "Error. Only one configuration file can be used.")); } /* Get filename of command file */ parms->cmd_file_fn = (*parser)[0].c_str(); /* Parameters */ if (parser->have_option ("atlas-selection")) { parms->atlas_selection = true; parms->input_fn = parser->get_string ("atlas-selection"); } if (parser->have_option ("train-atlas-selection")) { parms->train_atlas_selection = true; } if (parser->have_option ("convert")) { parms->convert = true; } if (parser->have_option ("pre-align")) { parms->prealign = true; } if (parser->have_option ("train")) { parms->train = true; } if (parser->have_option ("train-registration")) { parms->train_registration = true; } if (parser->have_option ("segment")) { parms->segment = true; parms->input_fn = parser->get_string ("segment"); } if (parser->have_option ("input-roi")) { parms->input_roi_fn = parser->get_string ("input-roi"); } if (parser->have_option ("output")) { parms->output_dir = parser->get_string ("output"); } if (parser->have_option ("output-dicom")) { parms->output_dicom_dir = parser->get_string ("output-dicom"); } } void do_command_mabs (int argc, char *argv[]) { Mabs_parms_pcmd parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); Mabs_parms mabs_parms; mabs_parms.parse_config (parms.cmd_file_fn.c_str()); Mabs mabs; mabs.set_parms (&mabs_parms); /* If defined set input ROI file name */ if (parms.input_roi_fn != "") { mabs.set_prealign_roi_cmd_name (parms.input_roi_fn); } /* Run the right function */ if (parms.train_atlas_selection) { mabs.set_executed_command("train_atlas_selection"); mabs.train_atlas_selection (); } else if (parms.convert) { mabs.set_executed_command("convert"); mabs.atlas_convert (); } else if (parms.prealign) { mabs.set_executed_command("prealign"); mabs.atlas_prealign (); } else if (parms.train_registration) { mabs.set_executed_command("train_registration"); mabs.train_registration (); } else if (parms.train) { mabs.set_executed_command("train"); mabs.train (); } else { // can be mabs.atlas_selection() or mabs.segment() /* Set parameters */ if (parms.input_fn != "") { mabs.set_segment_input (parms.input_fn); } if (parms.output_dir != "") { mabs.set_segment_output (parms.output_dir); } if (parms.output_dicom_dir != "") { mabs.set_segment_output_dicom (parms.output_dicom_dir); } /* Run function */ if (parms.atlas_selection) { mabs.set_executed_command("atlas_selection"); mabs.atlas_selection (); } else { mabs.set_executed_command("segment"); mabs.segment (); } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_mabs.h000066400000000000000000000005441321604176500274670ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_mabs_h_ #define _pcmd_mabs_h_ #include "plmcli_config.h" void do_command_mabs (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_mask.cxx000066400000000000000000000115571321604176500300610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "itk_image_load.h" #include "itk_mask.h" #include "pcmd_mask.h" #include "plm_clp.h" #include "plm_image.h" #include "plm_image_type.h" #include "print_and_exit.h" class Mask_parms { public: std::string input_fn; std::string output_fn; std::string mask_fn; enum Mask_operation mask_operation; float mask_value; bool output_dicom; Plm_image_type output_type; public: Mask_parms () { mask_operation = MASK_OPERATION_FILL; mask_value = 0.; output_dicom = false; output_type = PLM_IMG_TYPE_UNDEFINED; } }; static void mask_main (Mask_parms* parms) { Plm_image::Pointer img = plm_image_load_native (parms->input_fn); if (!img) { print_and_exit ("Error: could not open '%s' for read\n", parms->input_fn.c_str()); } UCharImageType::Pointer mask = itk_image_load_uchar (parms->mask_fn, 0); switch (img->m_type) { case PLM_IMG_TYPE_ITK_UCHAR: img->m_itk_uchar = mask_image (img->m_itk_uchar, mask, parms->mask_operation, parms->mask_value); break; case PLM_IMG_TYPE_ITK_SHORT: img->m_itk_short = mask_image (img->m_itk_short, mask, parms->mask_operation, parms->mask_value); break; case PLM_IMG_TYPE_ITK_USHORT: img->m_itk_ushort = mask_image (img->m_itk_ushort, mask, parms->mask_operation, parms->mask_value); break; case PLM_IMG_TYPE_ITK_ULONG: img->m_itk_uint32 = mask_image (img->m_itk_uint32, mask, parms->mask_operation, parms->mask_value); break; case PLM_IMG_TYPE_GPUIT_FLOAT: case PLM_IMG_TYPE_ITK_FLOAT: img->m_itk_float = mask_image (img->itk_float(), mask, parms->mask_operation, parms->mask_value); break; default: print_and_exit ("Unhandled conversion in mask_main\n"); break; } if (parms->output_dicom) { img->save_short_dicom (parms->output_fn, 0); } else { if (parms->output_type) { img->convert (parms->output_type); } img->save_image (parms->output_fn); } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Mask_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input", "input directory or filename; " "can be an image or dicom directory", 1, ""); parser->add_long_option ("", "mask", "input filename for mask image", 1, ""); parser->add_long_option ("", "output", "output filename (for image file) or " "directory (for dicom)", 1, ""); /* Output options */ parser->add_long_option ("", "output-format", "arg should be \"dicom\" for dicom output", 1, ""); parser->add_long_option ("", "output-type", "type of output image, one of {uchar, short, float, ...}", 1, ""); /* Algorithm options */ parser->add_long_option ("", "mask-value", "value to set for pixels with mask (for \"fill\"), " "or outside of mask (for \"mask\"", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check for required options */ parser->check_required ("input"); parser->check_required ("mask"); parser->check_required ("output"); /* Input files */ parms->input_fn = parser->get_string("input"); parms->output_fn = parser->get_string("output"); parms->mask_fn = parser->get_string("mask"); /* Output options */ if (parser->option("output-format")) { std::string arg = parser->get_string ("output-format"); if (arg != "dicom") { throw (dlib::error ("Error. Unknown --output-format argument: " + arg)); } parms->output_dicom = true; } if (parser->option("output-type")) { std::string arg = parser->get_string ("output-type"); parms->output_type = plm_image_type_parse (arg.c_str()); if (parms->output_type == PLM_IMG_TYPE_UNDEFINED) { throw (dlib::error ("Error. Unknown --output-type argument: " + arg)); } } /* Algorithm options */ if (parser->option("mask-value")) { parms->mask_value = parser->get_float("mask-value"); } } void do_command_mask (int argc, char *argv[]) { Mask_parms parms; /* Check if we're doing fill or mask */ if (!strcmp (argv[1], "mask")) { parms.mask_operation = MASK_OPERATION_MASK; } else { parms.mask_operation = MASK_OPERATION_FILL; } /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); /* Do the masking */ mask_main (&parms); printf ("Finished!\n"); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_mask.h000066400000000000000000000005441321604176500275000ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_mask_h_ #define _pcmd_mask_h_ #include "plmcli_config.h" void do_command_mask (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_maximum.cxx000066400000000000000000000070001321604176500305670ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "pcmd_maximum.h" #include #include "itkMaximumImageFilter.h" #include "itk_image_type.h" #include "itk_scale.h" #include "plm_clp.h" #include "plm_file_format.h" #include "plm_image.h" #include "print_and_exit.h" #include "xform.h" class Maximum_parms { public: std::string output_fn; std::list input_fns; public: Maximum_parms () {} }; void maximum_vol_main (Maximum_parms *parms) { typedef itk::MaximumImageFilter< FloatImageType, FloatImageType, FloatImageType > MaximumFilterType; MaximumFilterType::Pointer maxfilter = MaximumFilterType::New(); /* Load the first input image */ std::list::iterator it = parms->input_fns.begin(); Plm_image::Pointer max = plm_image_load (*it, PLM_IMG_TYPE_ITK_FLOAT); ++it; /* Loop through remaining images */ while (it != parms->input_fns.end()) { /* Load the images */ Plm_image::Pointer tmp = plm_image_load (*it, PLM_IMG_TYPE_ITK_FLOAT); /* Add it to running max */ maxfilter->SetInput1 (max->itk_float()); maxfilter->SetInput2 (tmp->itk_float()); maxfilter->Update(); max->m_itk_float = maxfilter->GetOutput (); ++it; } /* Save the max image */ max->convert_to_original_type (); max->save_image (parms->output_fn); } void maximum_main (Maximum_parms *parms) { /* What is the input file type? */ std::list::iterator it = parms->input_fns.begin(); Plm_file_format file_format = plm_file_format_deduce (*it); if (file_format == PLM_FILE_FMT_IMG) maximum_vol_main (parms); else print_and_exit ( "Sorry, can only compute input images, given type %s\n", plm_file_format_string (file_format)); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options] input_image [input_image ...]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Maximum_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Output files */ parser->add_long_option ("", "output", "output image", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Check that no extraneous options were given */ if (parser->number_of_arguments() == 0) { throw (dlib::error ("Error. You must specify at least one " "file to maximize (makes no sense).")); } /* Copy input filenames to parms struct */ for (unsigned long i = 0; i < parser->number_of_arguments(); i++) { parms->input_fns.push_back ((*parser)[i]); } /* Output files */ parms->output_fn = parser->get_string("output"); } void do_command_maximum (int argc, char *argv[]) { Maximum_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); maximum_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_maximum.h000066400000000000000000000005551321604176500302240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_maximum_h_ #define _pcmd_maximum_h_ #include "plmcli_config.h" void do_command_maximum (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_ml_convert.cxx000066400000000000000000000102161321604176500312650ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "ml_convert.h" #include "pcmd_ml_convert.h" #include "plm_clp.h" static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch ml_convert [options] feature-path [feature-path ...]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Ml_convert* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Basic options */ parser->add_long_option ("", "append", "Location of an existing input text file, to which additional " "features will be appended", 1, ""); parser->add_long_option ("", "labelmap", "Location of labelmap file", 1, ""); parser->add_long_option ("", "mask", "Location of mask file", 1, ""); parser->add_long_option ("", "input-ml-results", "Location of the file containing the results in text format", 1, ""); parser->add_long_option ("", "output", "Location of output file to be written; if --input-ml-results " "is specified, an image will be written, otherwise a text file " "will be written", 1, ""); parser->add_long_option ("", "output-type", "Data type of output image file (either \"uchar\" or \"float\")", 1, "uchar"); parser->add_long_option ("", "output-format", "Output format, either \"libsvm\" or \"vw\", default is \"vw\"", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that all necessary inputs are given */ if (!parser->have_option("input-ml-results") && !parser->have_option("labelmap") && !parser->have_option("append")) { throw (dlib::error ("Error. Must specify either " "--labelmap or --append option")); } if (parser->have_option("input-ml-results") && !parser->have_option("output")) { throw (dlib::error ("Error. When --input-ml-results is used, " "you must also include --output")); } if (parser->have_option("input-ml-results") && parser->have_option("append")) { throw (dlib::error ("Error. When --input-ml-results is used, " "you must not include --append")); } if (parser->have_option("labelmap") && parser->have_option("append")) { throw (dlib::error ("Error. Do not specify both --labelmap and " "--append option")); } if (!parser->have_option("output") && !parser->have_option("append")) { throw (dlib::error ("Error. You must specify either --output or " "--append option")); } if (parser->have_option("input-ml-results") && !parser->have_option("mask") && !parser->have_option("labelmap")) { throw (dlib::error ("Error. When --input-ml-results is used, " "you must also include --labelmap or --mask")); } /* Copy values into output struct */ parms->set_append_filename (parser->get_string ("append")); parms->set_input_ml_results_filename ( parser->get_string ("input-ml-results")); parms->set_label_filename (parser->get_string ("labelmap")); parms->set_mask_filename (parser->get_string ("mask")); if (parser->have_option ("output")) { parms->set_output_filename (parser->get_string ("output")); } else { parms->set_output_filename (parser->get_string ("append")); } parms->set_output_type (parser->get_string ("output-type")); parms->set_output_format (parser->get_string ("output-format")); /* Copy input filenames to parms struct */ for (unsigned long i = 0; i < parser->number_of_arguments(); i++) { parms->add_feature_path ((*parser)[i]); } } void do_command_ml_convert (int argc, char *argv[]) { Ml_convert ml_convert; plm_clp_parse (&ml_convert, &parse_fn, &usage_fn, argc, argv, 1); ml_convert.run(); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_ml_convert.h000066400000000000000000000005321321604176500307120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_ml_convert_h_ #define _pcmd_ml_convert_h_ void do_command_ml_convert (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_multiply.cxx000066400000000000000000000103641321604176500310000ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "pcmd_multiply.h" #include #include "itkMultiplyImageFilter.h" #include "itk_image_type.h" #include "itk_scale.h" #include "plm_clp.h" #include "plm_file_format.h" #include "plm_image.h" #include "print_and_exit.h" #include "xform.h" class Multiply_parms { public: std::string output_fn; std::list input_fns; public: Multiply_parms () {} }; void multiply_vf_main (Multiply_parms *parms) { typedef itk::MultiplyImageFilter< DeformationFieldType, DeformationFieldType, DeformationFieldType > MultiplyFilterType; MultiplyFilterType::Pointer mulfilter = MultiplyFilterType::New(); /* Load the first input image */ std::list::iterator it = parms->input_fns.begin(); Xform mult; mult.load (*it); ++it; /* Loop through remaining images */ while (it != parms->input_fns.end()) { /* Load the images */ Xform tmp; tmp.load (*it); /* Add it to running mult */ mulfilter->SetInput1 (mult.get_itk_vf()); mulfilter->SetInput2 (tmp.get_itk_vf()); mulfilter->Update(); mult.set_itk_vf (mulfilter->GetOutput ()); ++it; } /* Save the mult image */ mult.save (parms->output_fn); } void multiply_vol_main (Multiply_parms *parms) { typedef itk::MultiplyImageFilter< FloatImageType, FloatImageType, FloatImageType > MultiplyFilterType; MultiplyFilterType::Pointer mulfilter = MultiplyFilterType::New(); /* Load the first input image */ std::list::iterator it = parms->input_fns.begin(); Plm_image::Pointer mult = plm_image_load (*it, PLM_IMG_TYPE_ITK_FLOAT); ++it; /* Loop through remaining images */ while (it != parms->input_fns.end()) { /* Load the images */ Plm_image::Pointer tmp = plm_image_load (*it, PLM_IMG_TYPE_ITK_FLOAT); /* Add it to running mult */ mulfilter->SetInput1 (mult->itk_float()); mulfilter->SetInput2 (tmp->itk_float()); mulfilter->Update(); mult->m_itk_float = mulfilter->GetOutput (); ++it; } /* Save the mult image */ mult->convert_to_original_type (); mult->save_image (parms->output_fn); } void multiply_main (Multiply_parms *parms) { /* What is the input file type? */ std::list::iterator it = parms->input_fns.begin(); Plm_file_format file_format = plm_file_format_deduce (*it); switch (file_format) { case PLM_FILE_FMT_VF: multiply_vf_main (parms); break; default: multiply_vol_main (parms); break; } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options] input_file [input_file ...]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Multiply_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Output files */ parser->add_long_option ("", "output", "output image", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Check that no extraneous options were given */ if (parser->number_of_arguments() == 0) { throw (dlib::error ("Error. You must specify at least one " "file to multiply.")); } /* Copy input filenames to parms struct */ for (unsigned long i = 0; i < parser->number_of_arguments(); i++) { parms->input_fns.push_back ((*parser)[i]); } /* Output files */ parms->output_fn = parser->get_string("output"); } void do_command_multiply (int argc, char *argv[]) { Multiply_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); multiply_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_multiply.h000066400000000000000000000005601321604176500304220ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_multiply_h_ #define _pcmd_multiply_h_ #include "plmcli_config.h" void do_command_multiply (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_probe.cxx000066400000000000000000000157211321604176500302320ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "itkLinearInterpolateImageFunction.h" #include "itkVectorLinearInterpolateImageFunction.h" #include "itkContinuousIndex.h" #include "itk_image_load.h" #include "itk_image_type.h" #include "pcmd_probe.h" #include "plm_clp.h" #include "plm_file_format.h" #include "string_util.h" class Probe_parms { public: std::string input_fn; std::string index_string; std::string location_string; public: Probe_parms () { } }; static void probe_img_main (Probe_parms *parms) { FloatImageType::Pointer img = itk_image_load_float ( parms->input_fn, 0); FloatImageType::RegionType rg = img->GetLargestPossibleRegion (); typedef itk::LinearInterpolateImageFunction < FloatImageType, float > InterpolatorType; InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetInputImage (img); std::vector index_list = parse_float3_string ( parms->index_string); for (unsigned int i = 0; i < index_list.size() / 3; i++) { itk::ContinuousIndex cindex; cindex[0] = index_list[i*3+0]; cindex[1] = index_list[i*3+1]; cindex[2] = index_list[i*3+2]; FloatPoint3DType point; img->TransformContinuousIndexToPhysicalPoint (cindex, point); printf ("%4d: %7.2f, %7.2f, %7.2f; %7.2f, %7.2f, %7.2f; ", i, cindex[0], cindex[1], cindex[2], point[0], point[1], point[2]); if (cindex[0] < 0 || cindex[0] >= (int) rg.GetSize(0) || cindex[1] < 0 || cindex[1] >= (int) rg.GetSize(1) || cindex[2] < 0 || cindex[2] >= (int) rg.GetSize(2)) { printf ("N/A\n"); } else { InterpolatorType::OutputType pixel_value = interpolator->EvaluateAtContinuousIndex (cindex); printf ("%f\n", pixel_value); } } std::vector location_list = parse_float3_string ( parms->location_string); for (unsigned int i = 0; i < location_list.size() / 3; i++) { FloatPoint3DType point; point[0] = location_list[i*3+0]; point[1] = location_list[i*3+1]; point[2] = location_list[i*3+2]; itk::ContinuousIndex cindex; img->TransformPhysicalPointToContinuousIndex (point, cindex); printf ("%4d: %7.2f, %7.2f, %7.2f; %7.2f, %7.2f, %7.2f; ", (int) (index_list.size() / 3) + i, cindex[0], cindex[1], cindex[2], point[0], point[1], point[2]); if (cindex[0] < 0 || cindex[0] >= (int) rg.GetSize(0) || cindex[1] < 0 || cindex[1] >= (int) rg.GetSize(1) || cindex[2] < 0 || cindex[2] >= (int) rg.GetSize(2)) { printf ("N/A\n"); } else { InterpolatorType::OutputType pixel_value = interpolator->EvaluateAtContinuousIndex (cindex); printf ("%f\n", pixel_value); } } } static void probe_vf_main (Probe_parms *parms) { DeformationFieldType::Pointer img = itk_image_load_float_field ( parms->input_fn); DeformationFieldType::RegionType rg = img->GetLargestPossibleRegion (); typedef itk::VectorLinearInterpolateImageFunction < DeformationFieldType, float > InterpolatorType; InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetInputImage (img); std::vector index_list = parse_float3_string ( parms->index_string); for (unsigned int i = 0; i < index_list.size() / 3; i++) { itk::ContinuousIndex cindex; cindex[0] = index_list[i*3+0]; cindex[1] = index_list[i*3+1]; cindex[2] = index_list[i*3+2]; FloatPoint3DType point; img->TransformContinuousIndexToPhysicalPoint (cindex, point); printf ("%4d: %7.2f, %7.2f, %7.2f; %7.2f, %7.2f, %7.2f; ", i, cindex[0], cindex[1], cindex[2], point[0], point[1], point[2]); if (cindex[0] < 0 || cindex[0] >= (int) rg.GetSize(0) || cindex[1] < 0 || cindex[1] >= (int) rg.GetSize(1) || cindex[2] < 0 || cindex[2] >= (int) rg.GetSize(2)) { printf ("N/A\n"); } else { InterpolatorType::OutputType pixel_value = interpolator->EvaluateAtContinuousIndex (cindex); printf ("%f %f %f\n", pixel_value[0], pixel_value[1], pixel_value[2]); } } std::vector location_list = parse_float3_string ( parms->location_string); for (unsigned int i = 0; i < location_list.size() / 3; i++) { FloatPoint3DType point; point[0] = location_list[i*3+0]; point[1] = location_list[i*3+1]; point[2] = location_list[i*3+2]; itk::ContinuousIndex cindex; img->TransformPhysicalPointToContinuousIndex (point, cindex); printf ("%4d: %7.2f, %7.2f, %7.2f; %7.2f, %7.2f, %7.2f; ", (int) (index_list.size() / 3) + i, cindex[0], cindex[1], cindex[2], point[0], point[1], point[2]); if (cindex[0] < 0 || cindex[0] >= (int) rg.GetSize(0) || cindex[1] < 0 || cindex[1] >= (int) rg.GetSize(1) || cindex[2] < 0 || cindex[2] >= (int) rg.GetSize(2)) { printf ("N/A\n"); } else { InterpolatorType::OutputType pixel_value = interpolator->EvaluateAtContinuousIndex (cindex); printf ("%f %f %f\n", pixel_value[0], pixel_value[1], pixel_value[2]); } } } static void do_probe (Probe_parms *parms) { switch (plm_file_format_deduce (parms->input_fn)) { case PLM_FILE_FMT_VF: probe_vf_main (parms); break; case PLM_FILE_FMT_IMG: default: probe_img_main (parms); break; } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch probe [options] file\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Probe_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Basic options */ parser->add_long_option ("i", "index", "List of voxel indices, such as \"i j k;i j k;...\"", 1, ""); parser->add_long_option ("l", "location", "List of spatial locations, such as \"i j k;i j k;...\"", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an index or location was given */ if (!parser->have_option ("index") && !parser->have_option("location")) { throw (dlib::error ("Error. Please specify either an index " "or a location option")); } /* Check that an input file was given */ if (parser->number_of_arguments() == 0) { throw (dlib::error ("Error. You must specify an input file")); } else if (parser->number_of_arguments() > 1) { std::string extra_arg = (*parser)[1]; throw (dlib::error ("Error. Unknown option " + extra_arg)); } /* Copy values into output struct */ parms->input_fn = (*parser)[0]; parms->index_string = parser->get_string("index"); parms->location_string = parser->get_string("location"); } void do_command_probe (int argc, char *argv[]) { Probe_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); do_probe (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_probe.h000066400000000000000000000005131321604176500276500ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_probe_h_ #define _pcmd_probe_h_ void do_command_probe (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_register.cxx000066400000000000000000000017421321604176500307450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "logfile.h" #include "pcmd_register.h" #include "plm_return_code.h" #include "registration.h" void do_command_register (int argc, char* argv[]) { char *command_filename; if (!strcmp (argv[1], "register")) { if (argc > 2) { command_filename = argv[2]; } else { printf ("Usage: plastimatch register command_file\n"); exit (1); } } else { command_filename = argv[1]; } Registration reg; Plm_return_code rc = reg.set_command_file (command_filename); if (rc != PLM_SUCCESS) { logfile_printf ("Error. Could not load %s as command file.\n", command_filename); exit (1); } reg.do_registration (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_register.h000066400000000000000000000005601321604176500303670ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_register_h_ #define _pcmd_register_h_ #include "plmcli_config.h" void do_command_register (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_resample.cxx000066400000000000000000000227241321604176500307340ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "direction_cosines.h" #include "geometry_chooser.h" #include "itk_image_load.h" #include "itk_image_save.h" #include "itk_resample.h" #include "pcmd_resample.h" #include "plm_clp.h" #include "plm_file_format.h" #include "plm_int.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_image_type.h" #include "print_and_exit.h" class Resample_parms { public: std::string input_fn; std::string output_fn; std::string fixed_fn; Plm_image_type output_type; plm_long dim[3]; bool m_have_dim; float origin[3]; bool m_have_origin; float spacing[3]; bool m_have_spacing; int subsample[3]; bool m_have_subsample; Direction_cosines m_dc; bool m_have_direction_cosines; float default_val; bool have_default_val; int adjust; bool interp_lin; Geometry_chooser gchooser; public: Resample_parms () { output_type = PLM_IMG_TYPE_UNDEFINED; for (int i = 0; i < 3; i++) { origin[i] = 0.0; spacing[i] = 0.0; dim[i] = 0; subsample[i] = 0; } m_have_dim = false; m_have_origin = false; m_have_spacing = false; m_have_subsample = false; m_have_direction_cosines = false; default_val = 0.0; have_default_val = false; adjust = 0; interp_lin=true; } }; /* Return true if geometry was deduced, else false */ static bool deduce_geometry (Resample_parms* parms) { bool have_geometry = false; /* use the spacing of user-supplied fixed image */ if (parms->fixed_fn != "") { parms->gchooser.set_fixed_image (parms->fixed_fn); have_geometry = true; } /* use user specified geometry */ if (parms->m_have_dim) { parms->gchooser.set_dim (parms->dim); have_geometry = true; } if (parms->m_have_origin) { parms->gchooser.set_origin (parms->origin); have_geometry = true; } if (parms->m_have_spacing) { parms->gchooser.set_spacing (parms->spacing); have_geometry = true; } if (parms->m_have_direction_cosines) { parms->gchooser.set_direction_cosines (parms->m_dc); } return have_geometry; } template T do_resample_itk (Resample_parms* parms, T img) { if (parms->m_have_subsample) { return subsample_image (img, parms->subsample[0], parms->subsample[1], parms->subsample[2], parms->default_val); } if (deduce_geometry (parms)) { /* Return resampled image */ parms->gchooser.set_reference_image (img); return resample_image (img, parms->gchooser.get_geometry(), parms->default_val, parms->interp_lin); } else { /* Return original image */ return img; } } void resample_main_itk_vf (Resample_parms* parms) { DeformationFieldType::Pointer vector_field = itk_image_load_float_field (parms->input_fn); if (parms->m_have_subsample) { print_and_exit ("Error. Subsample not supported for vector field.\n"); exit (-1); } if (deduce_geometry (parms)) { /* Resample image */ parms->gchooser.set_reference_image (vector_field); vector_field = vector_resample_image (vector_field, parms->gchooser.get_geometry()); } itk_image_save (vector_field, parms->output_fn); } void resample_main (Resample_parms* parms) { Plm_image plm_image; Plm_file_format file_format; file_format = plm_file_format_deduce (parms->input_fn); /* Vector fields are templated differently, so do them separately */ if (file_format == PLM_FILE_FMT_VF) { resample_main_itk_vf (parms); return; } plm_image.load_native (parms->input_fn); if (parms->output_type == PLM_IMG_TYPE_UNDEFINED) { parms->output_type = plm_image.m_type; } switch (plm_image.m_type) { case PLM_IMG_TYPE_ITK_UCHAR: plm_image.m_itk_uchar = do_resample_itk (parms, plm_image.m_itk_uchar); break; case PLM_IMG_TYPE_ITK_CHAR: plm_image.m_itk_char = do_resample_itk (parms, plm_image.m_itk_char); break; case PLM_IMG_TYPE_ITK_USHORT: plm_image.m_itk_ushort = do_resample_itk (parms, plm_image.m_itk_ushort); break; case PLM_IMG_TYPE_ITK_SHORT: plm_image.m_itk_short = do_resample_itk (parms, plm_image.m_itk_short); break; case PLM_IMG_TYPE_ITK_ULONG: plm_image.m_itk_uint32 = do_resample_itk (parms, plm_image.m_itk_uint32); break; case PLM_IMG_TYPE_ITK_LONG: plm_image.m_itk_int32 = do_resample_itk (parms, plm_image.m_itk_int32); break; case PLM_IMG_TYPE_ITK_FLOAT: plm_image.m_itk_float = do_resample_itk (parms, plm_image.m_itk_float); break; case PLM_IMG_TYPE_ITK_DOUBLE: plm_image.m_itk_double = do_resample_itk (parms, plm_image.m_itk_double); break; default: print_and_exit ("Unhandled image type in resample_main()\n"); break; } plm_image.convert_and_save (parms->output_fn, parms->output_type); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Resample_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input", "input directory or filename; " "can be an image or vector field", 1, ""); /* Output files */ parser->add_long_option ("", "output", "output image or vector field", 1, ""); /* Output options */ parser->add_long_option ("", "output-type", "type of output image, one of {uchar, short, float, ...}", 1, ""); /* Algorithm options */ parser->add_long_option ("", "default-value", "value to set for pixels with unknown value, default is 0", 1, ""); parser->add_long_option ("", "interpolation", "interpolation type, either \"nn\" or \"linear\", " "default is linear", 1, "linear"); /* Geometry options */ parser->add_long_option ("F", "fixed", "fixed image (match output size to this image)", 1, ""); parser->add_long_option ("", "origin", "location of first image voxel in mm \"x y z\"", 1, ""); parser->add_long_option ("", "dim", "size of output image in voxels \"x [y z]\"", 1, ""); parser->add_long_option ("", "spacing", "voxel spacing in mm \"x [y z]\"", 1, ""); parser->add_long_option ("", "direction-cosines", "oriention of x, y, and z axes; Specify either preset value," " {identity,rotated-{1,2,3},sheared}," " or 9 digit matrix string \"a b c d e f g h i\"", 1, ""); parser->add_long_option ("", "subsample", "bin voxels together at integer subsampling rate \"x [y z]\"", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an input file was given */ if (!parser->option ("input")) { throw (dlib::error ("Error. Please specify an input file " "using the --input option")); } /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Check that no extraneous options were given */ if (parser->number_of_arguments() != 0) { std::string extra_arg = (*parser)[0]; throw (dlib::error ("Error. Unknown option " + extra_arg)); } /* Input files */ parms->input_fn = parser->get_string("input").c_str(); /* Output files */ parms->output_fn = parser->get_string("output").c_str(); /* Output options */ if (parser->option("output-type")) { std::string arg = parser->get_string ("output-type"); parms->output_type = plm_image_type_parse (arg.c_str()); if (parms->output_type == PLM_IMG_TYPE_UNDEFINED) { throw (dlib::error ("Error. Unknown --output-type argument: " + parser->get_string("output-type"))); } } /* Algorithm options */ if (parser->option("default-value")) { parms->default_val = parser->get_float("default-value"); } std::string arg = parser->get_string ("interpolation"); if (arg == "nn") { parms->interp_lin = 0; } else if (arg == "linear") { parms->interp_lin = 1; } else { throw (dlib::error ("Error. Unknown --interpolation argument: " + arg)); } /* Geometry options */ if (parser->option ("dim")) { parms->m_have_dim = 1; parser->assign_plm_long_13 (parms->dim, "dim"); } if (parser->option ("origin")) { parms->m_have_origin = 1; parser->assign_float_13 (parms->origin, "origin"); } if (parser->option ("spacing")) { parms->m_have_spacing = 1; parser->assign_float_13 (parms->spacing, "spacing"); } if (parser->option ("subsample")) { parms->m_have_subsample = 1; parser->assign_int13 (parms->subsample, "subsample"); } /* Direction cosines */ if (parser->option ("direction-cosines")) { parms->m_have_direction_cosines = true; std::string arg = parser->get_string("direction-cosines"); if (!parms->m_dc.set_from_string (arg)) { throw (dlib::error ("Error parsing --direction-cosines " "(should have nine numbers)\n")); } } parms->fixed_fn = parser->get_string("fixed").c_str(); } void do_command_resample (int argc, char *argv[]) { Resample_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); resample_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_resample.h000066400000000000000000000005601321604176500303530ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_resample_h_ #define _pcmd_resample_h_ #include "plmcli_config.h" void do_command_resample (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_scale.cxx000066400000000000000000000066211321604176500302110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "itk_scale.h" #include "plm_clp.h" #include "plm_image.h" #include "plm_file_format.h" #include "xform.h" class Scale_parms { public: std::string output_fn; std::string input_fn; float weight; public: Scale_parms () { weight = 1.0; } }; static void scale_image (Plm_image::Pointer& img, float weight) { img->set_itk (itk_scale (img->itk_float(), weight)); } static void scale_vf (Xform *xf, float weight) { xf->set_itk_vf (itk_scale (xf->get_itk_vf(), weight)); } void scale_vf_main (Scale_parms *parms) { /* Load the input */ Xform xf; xf.load (parms->input_fn); /* Weigh it */ scale_vf (&xf, parms->weight); /* Save it */ xf.save (parms->output_fn); } void scale_vol_main (Scale_parms *parms) { /* Load the input */ Plm_image::Pointer img = plm_image_load (parms->input_fn, PLM_IMG_TYPE_ITK_FLOAT); /* Weigh it */ scale_image (img, parms->weight); /* Save it */ img->convert_to_original_type (); img->save_image (parms->output_fn); } void scale_main (Scale_parms *parms) { /* What is the input file type? */ Plm_file_format file_format = plm_file_format_deduce (parms->input_fn); switch (file_format) { case PLM_FILE_FMT_VF: scale_vf_main (parms); break; default: scale_vol_main (parms); break; } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options] input_file\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Scale_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Output files */ parser->add_long_option ("", "output", "filename for output image or vector field", 1, ""); /* Weight vector */ parser->add_long_option ("", "weight", "scale the input image or vector field by this value (float)", 1, "1.0"); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Check that one, and only one, input file was given */ if (parser->number_of_arguments() == 0) { throw (dlib::error ("Error. You must specify an input file")); } else if (parser->number_of_arguments() > 1) { std::string extra_arg = (*parser)[1]; throw (dlib::error ("Error. Unknown option " + extra_arg)); } /* Copy input filenames to parms struct */ parms->input_fn = (*parser)[0]; /* Scaling factor */ if (parser->option ("weight")) { parms->weight = parser->get_float("weight"); } /* Output files */ parms->output_fn = parser->get_string("output"); } void do_command_scale (int argc, char *argv[]) { Scale_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); scale_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_scale.h000066400000000000000000000005471321604176500276370ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_scale_h_ #define _pcmd_scale_h_ #include "plmcli_config.h" void do_command_scale (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_script.cxx000066400000000000000000000060501321604176500304220ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include #include extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #include "pcmd_script.h" #include "lua_class_image.h" #include "lua_class_register.h" #include "lua_class_stage.h" #include "lua_class_structs.h" #include "lua_class_xform.h" #include "lua_cli_glue.h" #if 0 #include "lua_iface_add.h" #include "lua_iface_crop.h" #include "lua_iface_mask.h" /* also contains fill() */ #include "lua_iface_register.h" #include "lua_iface_resample.h" #include "lua_iface_synth.h" #endif #include "lua_tty.h" #include "lua_util.h" #include "file_util.h" void print_usage () { printf ("Usage: plastimatch script [ script_file | -i | - ]\n\n" \ " script_file execute specified script_file\n" \ " -i run in interactive mode\n" \ " - execute commands piped from stdin\n" \ "\n"); exit (1); } /* JAS 2012.04.27 * interfaces depricated in favor of classes */ #if 0 /* Register your LUA interface here */ static void register_lua_interfaces (lua_State* L) { lua_register (L, "add", LUAIFACE_add); lua_register (L, "crop", LUAIFACE_crop); lua_register (L, "mask", LUAIFACE_mask); lua_register (L, "fill", LUAIFACE_fill); // lua_register (L, "register", LUAIFACE_register); lua_register (L, "resample", LUAIFACE_resample); lua_register (L, "synth", LUAIFACE_synth); } #endif static void register_lua_objects (lua_State* L) { register_lua_class_image (L); register_lua_class_register (L); register_lua_class_stage (L); register_lua_class_ss (L); register_lua_class_xform (L); } /* Hook into plastmatch commandline */ void do_command_script (int argc, char *argv[]) { lua_State *L; char *script_fn = NULL; bool tty_mode = false; bool stdin_mode = false; if (!strcmp (argv[1], "script")) { if (argc > 2) { if (!strcmp (argv[2], "-i")) { tty_mode = true; } else if (!strcmp (argv[2], "-")) { stdin_mode = true; } else { script_fn = argv[2]; } } else { print_usage (); } } L = lua_open(); luaL_openlibs(L); // register_lua_interfaces (L); register_lua_objects (L); if (tty_mode) { do_tty (L); } else if (stdin_mode) { do_stdin (L); } else if (script_fn) { if (file_exists (script_fn)) { printf ("-- running script : %s\n\n", script_fn); luaL_dofile (L, script_fn); } else { printf ("unable to load script: %s\n", script_fn); } } else { print_usage (); } lua_close (L); printf ("\n[Script Terminated]\n\n"); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_script.h000066400000000000000000000006451321604176500300530ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_script_h_ #define _pcmd_script_h_ #include "plmcli_config.h" #include "lua.h" #include "lualib.h" #include "lauxlib.h" void do_command_script (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_segment.cxx000066400000000000000000000070771321604176500305720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "pcmd_segment.h" #include "plm_clp.h" #include "plm_image.h" #include "segment_body.h" class Segment_parms { public: std::string input_fn; std::string output_fn; std::string output_dicom; Segment_body sb; }; static void do_segment (Segment_parms *parms) { Plm_image in; Plm_image out; Segment_body *sb = &parms->sb; /* Load the input image */ in.load_native (parms->input_fn); sb->img_in = ∈ sb->img_out = &out; /* Do segmentation */ sb->do_segmentation (); /* Save output file */ sb->img_out->save_image (parms->output_fn); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch segment [options]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Segment_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Basic options */ parser->add_long_option ("", "output-img", "Output image filename", 1, ""); #if defined (commentout) parser->add_long_option ("", "output-dicom", "Output dicom directory (for RTSTRUCT)", 1, ""); #endif parser->add_long_option ("", "input", "Input image filename (required)", 1, ""); parser->add_long_option ("", "bottom", "Bottom of patient (top of couch)", 1, ""); parser->add_long_option ("", "lower-threshold", "Lower threshold (include voxels above this value)", 1, ""); #if defined (commentout) parser->add_long_option ("", "upper-threshold", "Upper threshold (include voxels below this value)", 1, ""); #endif parser->add_long_option ("", "debug", "Create debug images", 0); parser->add_long_option ("", "fast", "Use reduced image size", 0); parser->add_long_option ("", "fill-holes", "Fill the holes inside the mask (can be slow)", 0); parser->add_long_option ("", "fill-options", "Set fill holes options as radius1, radius2, radius3, itr1, itr2, itr3", 1); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an input file was given */ parser->check_required ("input"); parser->check_required ("output-img"); Segment_body *sb = &parms->sb; /* Copy values into output struct */ parms->output_fn = parser->get_string("output-img"); #if defined (commentout) parms->output_dicom = parser->get_string("output-dicom"); #endif parms->input_fn = parser->get_string("input"); if (parser->option ("lower-threshold")) { sb->m_lower_threshold = parser->get_float("lower-threshold"); } #if defined (commentout) parms->upper_threshold = parser->get_float("upper-threshold"); #endif if (parser->option ("bottom")) { sb->m_bot_given = true; sb->m_bot = parser->get_float ("bottom"); } if (parser->option ("fast")) { sb->m_fast = true; } if (parser->option ("fill-holes")) { sb->m_fill_holes = true; } if (parser->option("fill-options")){ parser->assign_int_6(sb->m_fill_parms, "fill-options"); } if (parser->option ("debug")) { sb->m_debug = true; } } void do_command_segment (int argc, char *argv[]) { Segment_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); do_segment (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_segment.h000066400000000000000000000005211321604176500302020ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_segment_h_ #define _pcmd_segment_h_ void do_command_segment (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_sift.cxx000066400000000000000000000571321321604176500300720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include #include #include #include #include #include #include #include "pcmd_sift.h" #include "plm_clp.h" #include "sift.h" #if defined (commentout) #define VERBOSE #define DIMENSION 3 // Command Line Arguments int ARG_IMG1=2; int ARG_IMG2=3; int main( int argc, char *argv[] ) { const unsigned int Dimension = DIMENSION; // ---- DEFAULT PARAMETERS: bool image_doubled = false; //false: no doubling; true: doubling unsigned int octave = 3; //number of octave float initial_sigma1 = 2; //float initial_sigma_sy = 1.5; float initial_sigma2 = 2; float descriptor_dimension = 8; float contrast = 0.03; //if we assume image pixel value in the range [0,1] float curvature = 172.3025; //if we assume image pixel value in the range [0,1] bool flag_curve = true; //1: curvature; 0: no curvature; bool normalization = true; //true: normalization of input image for //contrast&curvature thresholds definition float match_ratio = 0.9; //from 0 (no matches) to 1 (all matches) double test_scale = 1.0; // Default scale is 1.0 float test_rotate = 0.0; // 0 degrees float test_translate = 0.0; //0 mm //float test_rotate = 0.0874; // 5 degrees //float test_rotate = 0.1748; // 10 degrees int mode = 'i'; /* defaults to comparing 2 images */; int transform_middle=0; /* defaults to applying transformations around the origin */ //output: char *point_match1="phy_match1.fcsv"; char *point_match2="phy_match2.fcsv"; char *point_max1="phy_max1.fcsv"; char *point_max2="phy_max2.fcsv"; char *point_min1="phy_min1.fcsv"; char *point_min2="phy_min2.fcsv"; // ---- OPTIONS: #define OPT_OCTAVE 'o' #define OPT_DOUBLING 'di' #define OPT_INITIAL_SIGMA1 'z1' #define OPT_INITIAL_SIGMA2 'z2' #define OPT_DESCRIPTOR 'de' #define OPT_CONTRAST 'co' #define OPT_CURVATURE 'cu' #define OPT_MATCH 'm' #define OPT_SCALE 'x' #define OPT_ROTATE 'r' #define OPT_TRANSLATE 't' //#define OPT_DIM 'd' while(1) { static struct option long_options[] = { // Modalities (These options set a flag). {"synthetic", 0, &mode, 's'}, {"image", 0, &mode, 'i'}, {"transform-middle", 0, &transform_middle, 1}, // Parameters (These options don't set a flag) {"double", required_argument, 0, OPT_DOUBLING}, {"octave", required_argument, 0, OPT_OCTAVE}, {"initial-sigma1", required_argument, 0, OPT_INITIAL_SIGMA1}, {"initial-sigma2", required_argument, 0, OPT_INITIAL_SIGMA2}, {"contrast", required_argument, 0, OPT_CONTRAST}, {"curvature", required_argument, 0, OPT_CURVATURE}, {"descr-dim", required_argument, 0, OPT_DESCRIPTOR}, {"match-ratio", required_argument, 0, OPT_MATCH}, //{"dimension", required_argument, 0, OPT_DIM}, {"scale", required_argument, 0, OPT_SCALE}, {"rotate", required_argument, 0, OPT_ROTATE}, {"translate", required_argument, 0, OPT_TRANSLATE}, //Output {"out-match1", required_argument, 0, 1}, {"out-match2", required_argument, 0, 2}, {"out-max1", required_argument, 0, 3}, {"out-min1", required_argument, 0, 4}, {"out-max2", required_argument, 0, 5}, {"out-min2", required_argument, 0, 6}, {0, 0, 0, 0} }; int optindex; int val = getopt_long(argc, argv, "", long_options, &optindex); if (val == -1) break; switch(val) { case OPT_DOUBLING: image_doubled = atof(optarg); break; case OPT_OCTAVE: octave = atof(optarg); break; case OPT_INITIAL_SIGMA1: initial_sigma1 = atof(optarg); break; case OPT_INITIAL_SIGMA2: initial_sigma2 = atof(optarg); break; case OPT_CONTRAST: contrast = atof(optarg); if(contrast<0.0|| contrast>1.0) {normalization=false; flag_curve=false;} break; case OPT_CURVATURE: if(atof(optarg)==0) flag_curve=false; if(!normalization && atof(optarg)!=0) flag_curve=true; curvature = atof(optarg); break; case OPT_DESCRIPTOR: descriptor_dimension = atof(optarg); break; case OPT_MATCH: match_ratio = atof(optarg); break; //case OPT_DIM: // Dimension = atoi(optarg); // break; case OPT_SCALE: test_scale = atof(optarg); break; case OPT_ROTATE: if (atof(optarg) >= 0.0 && atof(optarg) <= 360.0) test_rotate = atof(optarg) * PI * 2.0 / 360.0; break; case OPT_TRANSLATE: test_translate = atof(optarg); break; //Output: case 1: point_match1=optarg; break; case 2: point_match2=optarg; break; case 3: point_max1=optarg; break; case 4: point_min1=optarg; break; case 5: point_max2=optarg; break; case 6: point_min2=optarg; break; } } ARG_IMG1 = optind; ARG_IMG2 = optind+1; FILE* match1=0;match1=fopen(point_match1,"w");fclose(match1); FILE* match2=0;match2=fopen(point_match2,"w");fclose(match2); FILE* max1=0;max1=fopen(point_max1,"w");fclose(max1); FILE* min1=0;min1=fopen(point_min1,"w");fclose(min1); FILE* max2=0;max2=fopen(point_max2,"w");fclose(max2); FILE* min2=0;min2=fopen(point_min2,"w");fclose(min2); typedef float PixelType; typedef itk::Image< PixelType, Dimension > FixedImageType; typedef itk::ScaleInvariantFeatureImageFilter SiftFilterType; typedef itk::ImageSource< FixedImageType > ImageSourceType; ImageSourceType::Pointer fixedImageReader, fixedImageReader2; // ---- USAGE: if( argc <= ARG_IMG1 || (mode == 'i' && argc <= ARG_IMG2)) { std::cerr << "Incorrect number of parameters " << std::endl; std::cerr << std::endl; std::cerr << "USAGE: \n"; std::cerr << argv[0] << " [options] ImageFile [ImageFile2]\n"; std::cerr << "This program takes as input 3D images and generates Scale Invariant Feature Transform" << std::endl; std::cerr << std::endl; std::cerr << "**IMAGE PROCESSING OPTIONS (Choose ONE):" << std::endl; std::cerr << "--image " << std::endl; std::cerr << " compare ImageFile.mha and ImageFile2.mha" << std::endl; std::cerr << "OR\n" << std::endl; std::cerr << "--synthetic " << std::endl; std::cerr << " compare ImageFile to synthetically generated version" << std::endl; std::cerr << " return the synthetic image as output (image_transform.mha)" << std::endl; std::cerr << " Synthetic Image Options:" << std::endl; std::cerr << " --rotate " << std::endl; std::cerr << " rotate synthetic image on first axis [degree]" << std::endl; std::cerr << " --translate " << std::endl; std::cerr << " translate synthetic image [mm]" << std::endl; std::cerr << " --scale " << std::endl; std::cerr << " scale all axes of synthetic image" << std::endl; std::cerr << " --transform-middle"<< std::endl; std::cerr << " center of transformation: center of the image (default origin)" << std::endl; std::cerr << "\n**PARAMETERS:\n" << std::endl; /*std::cerr << "--dimension " << std::endl; std::cerr << " image dimension (default 3)" << std::endl;*/ std::cerr << "--double " << std::endl; std::cerr << " image doubling -> yes:1 or no:0 (default 0)" << std::endl; std::cerr << "--octave " << std::endl; std::cerr << " set number of octaves (default 3)" << std::endl; //the number of octave is a function of the image dimension! std::cerr << "--initial-sigma1 " << std::endl; std::cerr << " set Gaussian blur initial sigma for ImageFile (default 2mm)" << std::endl; std::cerr << "--initial-sigma2 " << std::endl; std::cerr << " set Gaussian blur initial sigma for ImageFile2/synthetic version" << std::endl; std::cerr << " (default 2mm)" << std::endl; std::cerr << "--contrast " << std::endl; std::cerr << " threshold on image contrast (default 0.03 for image value in [0,1])" << std::endl; std::cerr << " if contrast value is 0, the contrast threshold is not performed" << std::endl; std::cerr << " if contrast value is greater than 1, the curvature threshold" << std::endl; std::cerr << " is not performed in default modality" << std::endl; std::cerr << "--curvature " << std::endl; std::cerr << " threshold on image curvature (default 172.3 for image value in [0,1])" << std::endl; std::cerr << " if curvature value is 0, the curvature threshold is not performed" << std::endl; std::cerr << "--descr-dim " << std::endl; std::cerr << " half of the keypoint descriptor region size" << std::endl; std::cerr << " (default 8 voxels -> 16x16x16 region size)" << std::endl; std::cerr << "--match-ratio " << std::endl; std::cerr << " set matching ratio in the range [0,1] (default 0.9)" << std::endl; std::cerr << "\n**OUTPUT:\n" << std::endl; std::cerr << "Default: Feature in physical coordinates in RAS system (file format .fcsv)" << std::endl; std::cerr << "--out-max1 " << std::endl; std::cerr << " maxima keypoints of ImageFile (default phy_max1.fcsv)" << std::endl; std::cerr << "--out-min1 " << std::endl; std::cerr << " minima keypoints of ImageFile (default phy_min1.fcsv)" << std::endl; std::cerr << "--out-max2 " << std::endl; std::cerr << " maxima keypoints of ImageFile2 (default phy_max2.fcsv)" << std::endl; std::cerr << "--out-min2 " << std::endl; std::cerr << " minima keypoints of ImageFile2 (default phy_max2.fcsv)" << std::endl; std::cerr << "--out-match1 " << std::endl; std::cerr << " matching keypoints of ImageFile (default point_match1.fcsv)" << std::endl; std::cerr << "--out-match2 " << std::endl; std::cerr << " matching keypoints of ImageFile2 (default point_match2.fcsv)" << std::endl; std::cerr << std::endl; return 1; } std::cerr << "Dimension = " << Dimension << "\n"; /*std::cerr << "Test Scale = " << test_scale << "\n"; std::cerr << "Test Rotate = " << test_rotate << "\n"; std::cerr << "Test Translate = " << test_translate << "\n";*/ std::cerr << "Mode = " << (char) mode << "\n"; std::cerr << "ImageFile1 = " << argv[optind] << "\n"; /*std::cerr << "curvature = " << curvature << "\n"; std::cerr << "flag_curve = " << flag_curve << "\n"; std::cerr << "contrast = " << contrast << "\n"; std::cerr << "normalization = " << normalization << "\n";*/ std::cerr << "SIFT Feature\n" << std::endl; //Read Input Image1 typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType; FixedImageReaderType::Pointer tmpImageReader = FixedImageReaderType::New(); tmpImageReader = FixedImageReaderType::New(); tmpImageReader->SetFileName( argv[ARG_IMG1] ); fixedImageReader=tmpImageReader; fixedImageReader->Update(); FixedImageType::Pointer fixedImage= FixedImageType::New(); try{ fixedImage = fixedImageReader->GetOutput(); } catch (itk::ExceptionObject &err) { std::cout << "ExceptionObject caught !" << std::endl; std::cout << err << std::endl; return -1; } SiftFilterType::PointSetTypePointer keypoints1, keypoints2; SiftFilterType siftFilter1, siftFilter2; //siftFilter1.writeImage(fixedImage, "InputImage1.mha"); //set parameters: siftFilter1.SetDoubling(image_doubled); siftFilter1.SetNumScales(octave); siftFilter1.SetInitialSigma(initial_sigma1); siftFilter1.SetContrast(contrast); siftFilter1.SetCurvature(curvature); siftFilter1.SetDescriptorDimension(descriptor_dimension); siftFilter1.SetMatchRatio(match_ratio); //output keypoints from first Image keypoints1 = siftFilter1.getSiftFeatures(fixedImage, flag_curve,normalization, point_max1,point_min1,"imagecoord_max1.txt","imagecoord_min1.txt","point_rej_contrast1.fcsv","point_rej_curvature1.fcsv"); typedef itk::AffineTransform< double, Dimension > TestTransformType; typedef TestTransformType::InputVectorType VectorType; typedef TestTransformType::ParametersType ParametersType; TestTransformType::Pointer test_transform = TestTransformType::New(); test_transform->SetIdentity(); FixedImageType::Pointer scaledImage = FixedImageType::New(); // ---- SYNTHETIC TEST IMAGE: if (mode=='s') { std::cerr << std::endl << "Synthetic image mode\n"; const unsigned int np = test_transform->GetNumberOfParameters(); ParametersType parameters( np ); // Number of parameters TestTransformType::InputPointType translate_vector; FixedImageType::PointType origin = fixedImage->GetOrigin(); FixedImageType::SpacingType spacing = fixedImage->GetSpacing(); FixedImageType::SizeType size = fixedImage->GetLargestPossibleRegion().GetSize(); if (transform_middle) { std::cerr << "Transformation centred at middle of image." << std::endl; /* Cycle through each dimension and shift by half, taking into account the element spacing*/ for (int k = 0; k < Dimension; ++k) translate_vector[k] = origin[k]+(size[k]/2.0)*spacing[k]; test_transform->SetCenter(translate_vector); std::cout<<"Center of Transformation: "<GetOrigin()<SetCenter( origin ); std::cout<<"Center of Transformation: "<GetCenter()<GetOrigin()<Rotate(0,1,test_rotate); test_transform->Rotate3D(rot,test_rotate); //TRANSLATION: TestTransformType::OutputVectorType tr; tr[0]=tr[1]=tr[2]=test_translate; test_transform->Translate(tr); //SCALING: TestTransformType::OutputVectorType scaling; scaling[0]=scaling[1]=scaling[2]= test_scale; test_transform->Scale(scaling); std::cout << "Transform Parms: " << std::endl; std::cout << test_transform->GetParameters() << std::endl; /*std::cout << "MATRIX: " << std::endl; std::cout << test_transform->GetMatrix() << std::endl;*/ FixedImageType::Pointer scaledImage; typedef itk::ResampleImageFilter ResampleFilterType; ResampleFilterType::Pointer scaler = ResampleFilterType::New(); scaler->SetInput(fixedImage); //scaler->SetSize(size); //scaler->SetOutputSpacing(spacing); //scaler->SetOutputOrigin(origin); //scaler->SetOutputDirection( fixedImage->GetDirection() ); FixedImageType::SizeType newsize; FixedImageType::PointType offset; for (int k = 0; k < Dimension; ++k) newsize[k] = (unsigned int) size[k] / test_scale; scaler->SetSize( newsize ); std::cout << "New size: " << newsize << std::endl; scaler->SetOutputSpacing(spacing); if(newsize!=size && transform_middle) //scaling centred at middle of image { for (int k = 0; k < Dimension; ++k) offset[k]=translate_vector[k]-(newsize[k]/2.0)*spacing[k]; std::cout<<"New Origin: "<SetOutputOrigin(offset); } else {scaler->SetOutputOrigin(origin);} scaler->SetOutputDirection( fixedImage->GetDirection() ); //INTERPOLATION: // Linear Interpolation: typedef itk::LinearInterpolateImageFunction< FixedImageType, double > InterpolatorType; InterpolatorType::Pointer interpolator = InterpolatorType::New(); // B-spline Interpolation: /* typedef itk::BSplineInterpolateImageFunction< FixedImageType, double > InterpolatorType; InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetSplineOrder(3); interpolator->SetInputImage(fixedImage); interpolator->UseImageDirectionOn();*/ scaler->SetInterpolator( interpolator ); scaler->SetDefaultPixelValue( (PixelType) -1200 ); scaler->SetTransform(test_transform); scaler->Update(); scaledImage = scaler->GetOutput(); //set parameters for synthetic image siftFilter2.SetDoubling(image_doubled); siftFilter2.SetNumScales(octave); siftFilter2.SetDescriptorDimension(descriptor_dimension); siftFilter2.SetInitialSigma(initial_sigma2); siftFilter2.SetContrast(contrast); siftFilter2.SetCurvature(curvature); siftFilter2.SetMatchRatio(match_ratio); siftFilter2.writeImage(scaledImage, "image_transform.mha"); //output keypoints of synthetic image keypoints2 = siftFilter2.getSiftFeatures(scaledImage,flag_curve,normalization,point_max2,point_min2,"imagecoord_max2.txt","imagecoord_min2.txt","point_rej_contrast2.fcsv","point_rej_curvature2.fcsv"); /*std::cerr << "Test Image Scale: " << test_scale << std::endl; std::cerr << "Test Translate: " << test_translate << std::endl; std::cerr << "Test Image Rotate: " << test_rotate << std::endl;*/ } // ---- IMAGE COMPARISON MODE: else if (mode == 'i') { std::cerr << std::endl << "Image Comparison mode\n"; //Read ImageFile2 typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType; FixedImageReaderType::Pointer tmpImageReader = FixedImageReaderType::New(); tmpImageReader = FixedImageReaderType::New(); tmpImageReader->SetFileName( argv[ARG_IMG2] ); fixedImageReader2 = tmpImageReader; fixedImageReader2->Update(); FixedImageType::Pointer fixedImage2 = fixedImageReader2->GetOutput(); //set parameters for ImageFile2 siftFilter2.SetDoubling(image_doubled); siftFilter2.SetNumScales(octave); siftFilter2.SetDescriptorDimension(descriptor_dimension); siftFilter2.SetInitialSigma(initial_sigma2); siftFilter2.SetContrast(contrast); siftFilter2.SetCurvature(curvature); siftFilter2.SetMatchRatio(match_ratio); //output keypoints from ImageFile2 keypoints2 = siftFilter2.getSiftFeatures(fixedImage2,flag_curve,normalization,point_max2,point_min2,"imagecoord_max2.txt","imagecoord_min2.txt","point_rej_contrast2.fcsv","point_rej_curvature2.fcsv"); } // ---- MATCHING: std::cerr << std::endl << "Matching Keypoints\n"; siftFilter2.MatchKeypointsFeatures(keypoints1, keypoints2, point_match1, point_match2); return 0; } #endif class Sift_parms_pcmd { public: std::string image_fn_1; std::string image_fn_2; std::string output_pointset_1; std::string output_pointset_2; std::string output_match_1; std::string output_match_2; float contrast_threshold; float curvature_threshold; public: Sift_parms_pcmd () { contrast_threshold = 0.f; curvature_threshold = 0.f; } }; static void usage_fn (dlib::Plm_clp *parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch sift [options] image_1 [image_2]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Sift_parms_pcmd *parms, dlib::Plm_clp *parser, int argc, char *argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Sift options */ parser->add_long_option ("", "contrast-threshold", "threshold on image curvature (default is 0.03)", 1, "0.03"); parser->add_long_option ("", "curvature-threshold", "threshold on image curvature (default is 172.3)", 1, "172.3025"); /* Output files */ parser->add_long_option ("", "output-ps-1", "output all detected SIFT features of image_1 in fcsv format", 1, ""); parser->add_long_option ("", "output-ps-2", "output all detected SIFT features of image_2 in fcsv format", 1, ""); parser->add_long_option ("", "output-match-1", "output matching SIFT features of image_1 in fcsv format", 1, ""); parser->add_long_option ("", "output-match-2", "output matching SIFT features of image_2 in fcsv format", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that either one or two input image argument were given */ if (parser->number_of_arguments() < 1 || parser->number_of_arguments() > 2) { throw (dlib::error ( "Error. Please specify either one or two image files.")); } /* Sift options */ parms->contrast_threshold = parser->get_float("contrast-threshold"); parms->curvature_threshold = parser->get_float("curvature-threshold"); /* Output files */ parms->output_pointset_1 = parser->get_string("output-ps-1").c_str(); parms->output_pointset_2 = parser->get_string("output-ps-2").c_str(); parms->output_match_1 = parser->get_string("output-match-1").c_str(); parms->output_match_2 = parser->get_string("output-match-2").c_str(); /* Get filename of input image files */ parms->image_fn_1 = (*parser)[0].c_str(); if (parser->number_of_arguments() == 2) { parms->image_fn_2 = (*parser)[1].c_str(); } } void do_command_sift (int argc, char *argv[]) { Sift_parms_pcmd parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); Sift sift1, sift2; /* Get keypoints */ sift1.set_image (parms.image_fn_1); sift1.set_contrast_threshold (parms.contrast_threshold); sift1.set_curvature_threshold (parms.curvature_threshold); sift1.run (); if (parms.output_pointset_1 != "") { sift1.save_pointset (parms.output_pointset_1.c_str()); } if (parms.image_fn_2 != "") { /* Get keypoints */ sift2.set_image (parms.image_fn_2); sift2.set_contrast_threshold (parms.contrast_threshold); sift2.set_curvature_threshold (parms.curvature_threshold); sift2.run (); if (parms.output_pointset_2 != "") { sift2.save_pointset (parms.output_pointset_2.c_str()); } /* Match them */ Sift::match_features ( sift1, sift2, parms.output_match_1.c_str(), parms.output_match_2.c_str(), 0.9); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_sift.h000066400000000000000000000005441321604176500275120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_sift_h_ #define _pcmd_sift_h_ #include "plmcli_config.h" void do_command_sift (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_stats.cxx000066400000000000000000000156211321604176500302600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "gdcm1_dose.h" #include "itk_image_load.h" #include "itk_image_stats.h" #include "logfile.h" #include "mha_io.h" #include "pcmd_stats.h" #include "plm_clp.h" #include "plm_file_format.h" #include "plm_image.h" #include "plm_image_header.h" #include "pointset.h" #include "print_and_exit.h" #include "proj_image.h" #include "rt_study.h" #include "ss_img_stats.h" #include "vf_stats.h" #include "volume.h" #include "xform.h" class Stats_parms { public: bool structure; std::string mask_fn; std::list input_fns; }; static void stats_vf_main (Stats_parms* parms, const std::string& current_fn) { Volume *vol = 0; Xform xf1, xf2; xf1.load (current_fn); if (xf1.m_type == XFORM_GPUIT_VECTOR_FIELD) { vol = xf1.get_gpuit_vf().get(); } else if (xf1.m_type == XFORM_ITK_VECTOR_FIELD) { /* GCS FIX: This logic should be moved inside of xform class */ Plm_image_header pih; pih.set_from_itk_image (xf1.get_itk_vf ()); xform_to_gpuit_vf (&xf2, &xf1, &pih); vol = xf2.get_gpuit_vf().get(); } else { print_and_exit ("Error: input file %s is not a vector field\n", current_fn.c_str()); } if (vol->pix_type != PT_VF_FLOAT_INTERLEAVED) { fprintf (stderr, "Sorry, file \"%s\" is not an interleaved float vector field.\n", current_fn.c_str()); fprintf (stderr, "Type = %d\n", vol->pix_type); delete vol; exit (-1); } if (parms->mask_fn.length() == 0) { vf_analyze (vol, 0); vf_analyze_jacobian (vol, 0); vf_analyze_strain (vol, 0); vf_analyze_second_deriv (vol); } else { Plm_image::Pointer pli = Plm_image::New (new Plm_image( parms->mask_fn)); pli->convert (PLM_IMG_TYPE_GPUIT_UCHAR); Volume* mask = pli->get_vol(); vf_analyze (vol, mask); vf_analyze_jacobian (vol, mask); vf_analyze_strain (vol, mask); vf_analyze_second_deriv (vol); } } static void stats_pointset_main (Stats_parms* parms, const std::string& current_fn) { Labeled_pointset ps; ps.load (current_fn.c_str()); lprintf ("Pointset has %d points\n", ps.get_count()); } static void stats_proj_image_main (Stats_parms* parms, const std::string& current_fn) { Proj_image *proj; proj = new Proj_image (current_fn, ""); proj->debug_header (); proj->stats (); delete proj; } static void stats_ss_image_main (Stats_parms* parms, const std::string& current_fn) { Plm_image plm (current_fn); if (plm.m_type != PLM_IMG_TYPE_ITK_UCHAR_VEC) { print_and_exit ("Failure loading file %s as ss_image.\n", current_fn.c_str()); } UCharVecImageType::Pointer img = plm.m_itk_uchar_vec; ss_img_stats (img); } static void stats_structure_main (Stats_parms* parms, const std::string& current_fn) { Rt_study rt_study; rt_study.load (current_fn); } static void stats_img_main (Stats_parms* parms, const std::string& current_fn) { Plm_image pli (current_fn); FloatImageType::Pointer img = pli.itk_float(); double min_val, max_val, avg; int non_zero, num_vox; itk_image_stats (img, &min_val, &max_val, &avg, &non_zero, &num_vox); printf ("MIN %f AVE %f MAX %f NONZERO %d NUMVOX %d\n", (float) min_val, (float) avg, (float) max_val, non_zero, num_vox); } static void stats_dicom_dose (Stats_parms* parms, const std::string& current_fn) { #if PLM_DCM_USE_DCMTK /* Sorry, not yet supported */ #elif PLM_DCM_USE_GDCM1 Plm_image *dose = gdcm1_dose_load (0, current_fn.c_str()); FloatImageType::Pointer img = dose->itk_float (); double min_val, max_val, avg; int non_zero, num_vox; itk_image_stats (img, &min_val, &max_val, &avg, &non_zero, &num_vox); printf ("MIN %f AVE %f MAX %f NONZERO %d NUMVOX %d\n", (float) min_val, (float) avg, (float) max_val, non_zero, num_vox); delete dose; #endif } static void stats_main (Stats_parms* parms) { std::list::iterator it = parms->input_fns.begin(); while (it != parms->input_fns.end()) { std::string current_fn = *it; if (parms->structure) { stats_structure_main (parms, current_fn); ++it; continue; } Plm_file_format file_format = plm_file_format_deduce (current_fn); switch (file_format) { case PLM_FILE_FMT_IMG: stats_img_main (parms, current_fn); break; case PLM_FILE_FMT_VF: stats_vf_main (parms, current_fn); break; case PLM_FILE_FMT_POINTSET: stats_pointset_main (parms, current_fn); break; case PLM_FILE_FMT_PROJ_IMG: stats_proj_image_main (parms, current_fn); break; case PLM_FILE_FMT_DICOM_DOSE: stats_dicom_dose (parms, current_fn); break; case PLM_FILE_FMT_SS_IMG_VEC: stats_ss_image_main (parms, current_fn); break; default: printf ("Warning, stats requested for file type: %s\n", plm_file_format_string (file_format)); stats_img_main (parms, current_fn); break; } ++it; } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ( "Usage: plastimatch stats [options] input_file [input_file ...]\n"); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Stats_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Weight vector */ parser->add_long_option ("", "mask", "A binary image (usually unsigned char) where only non-zero voxels " "are considered for statistics", 1, ""); parser->add_long_option ("", "structure", "Compute structure statistics rather than image statistics", 0); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); if (parser->option ("mask")) { parms->mask_fn = parser->get_string ("mask"); } if (parser->option ("structure")) { parms->structure = true; } else { parms->structure = false; } /* Check that no extraneous options were given */ if (parser->number_of_arguments() == 0) { throw (dlib::error ("Error. You must specify at least one " "file for printing stats.")); } /* Copy input filenames to parms struct */ for (unsigned long i = 0; i < parser->number_of_arguments(); i++) { parms->input_fns.push_back ((*parser)[i]); } } void do_command_stats (int argc, char *argv[]) { Stats_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); stats_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_stats.h000066400000000000000000000005471321604176500277060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_stats_h_ #define _pcmd_stats_h_ #include "plmcli_config.h" void do_command_stats (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_synth.cxx000066400000000000000000000445641321604176500302770ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include #include #include #include "itk_image_save.h" #include "plm_clp.h" #include "plm_image.h" #include "plm_math.h" #include "print_and_exit.h" #include "rt_study.h" #include "string_util.h" #include "synthetic_mha.h" class Synthetic_mha_main_parms { public: std::string output_fn; std::string output_dose_img_fn; std::string output_prefix; std::string output_ss_img_fn; std::string output_ss_list_fn; std::string output_dicom; Synthetic_mha_parms sm_parms; bool dicom_with_uids; std::vector m_metadata; public: Synthetic_mha_main_parms () { dicom_with_uids = true; } }; void do_synthetic_mha (Synthetic_mha_main_parms *parms) { Synthetic_mha_parms *sm_parms = &parms->sm_parms; /* Create image */ Rt_study rtds; if (parms->output_dicom != "" || parms->output_prefix != "" || parms->output_ss_img_fn != "" || parms->output_ss_list_fn != "") { sm_parms->m_want_ss_img = true; } if (parms->output_dicom != "" || parms->output_dose_img_fn != "") { sm_parms->m_want_dose_img = true; } synthetic_mha (&rtds, sm_parms); /* metadata */ rtds.set_study_metadata (parms->m_metadata); /* Save to file */ FloatImageType::Pointer img = rtds.get_image()->itk_float(); if (parms->output_fn != "") { itk_image_save (img, parms->output_fn, sm_parms->output_type); } /* ss_img */ if (parms->output_ss_img_fn != "") { rtds.get_segmentation()->convert_to_uchar_vec (); rtds.get_segmentation()->save_ss_image (parms->output_ss_img_fn); } /* prefix */ if (parms->output_prefix != "") { rtds.get_segmentation()->save_prefix (parms->output_prefix); } /* dose_img */ if (parms->output_dose_img_fn != "") { rtds.save_dose (parms->output_dose_img_fn); } /* list of structure names */ if (parms->output_ss_list_fn != "") { printf ("save_ss_img: save_ss_list\n"); rtds.get_segmentation()->save_ss_list (parms->output_ss_list_fn); } if (parms->output_dicom != "") { rtds.get_segmentation()->convert_ss_img_to_cxt (); rtds.save_dicom (parms->output_dicom.c_str(), parms->dicom_with_uids); } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch synth [options]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Synthetic_mha_main_parms *parms, dlib::Plm_clp *parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input", "input image (add synthetic pattern onto existing image)", 1, ""); parser->add_long_option ("", "fixed", "fixed image (match output size to this image)", 1, ""); /* Output files */ parser->add_long_option ("", "output", "output filename", 1, ""); parser->add_long_option ("", "output-dicom", "output dicom directory", 1, ""); parser->add_long_option ("", "output-dose-img", "filename for output dose image", 1, ""); parser->add_long_option ("", "output-prefix", "create a directory with a separate image for each structure", 1, ""); parser->add_long_option ("", "output-ss-img", "filename for output structure set image", 1, ""); parser->add_long_option ("", "output-ss-list", "filename for output file containing structure names", 1, ""); parser->add_long_option ("", "output-type", "data type for output image: {uchar, short, ushort, ulong, float}," " default is float", 1, "float"); parser->add_long_option ("", "dicom-with-uids", "set to false to remove uids from created dicom filenames, " "default is true", 1, "true"); /* Main pattern */ parser->add_long_option ("", "pattern", "synthetic pattern to create: {" "cylinder, donut, dose, gabor, gauss, grid, lung, noise, " "rect, sphere, xramp, yramp, zramp" "}, default is gauss", 1, "gauss"); /* Image size */ parser->add_long_option ("", "origin", "location of first image voxel in mm \"x y z\"", 1, "0 0 0"); parser->add_long_option ("", "dim", "size of output image in voxels \"x [y z]\"", 1, "100"); parser->add_long_option ("", "spacing", "voxel spacing in mm \"x [y z]\"", 1, "5"); parser->add_long_option ("", "direction-cosines", "oriention of x, y, and z axes; Specify either preset value," " {identity,rotated-{1,2,3},sheared}," " or 9 digit matrix string \"a b c d e f g h i\"", 1, ""); parser->add_long_option ("", "volume-size", "size of output image in mm \"x [y z]\"", 1, "500"); /* Image intensities */ parser->add_long_option ("", "background", "intensity of background region", 1, "-1000"); parser->add_long_option ("", "foreground", "intensity of foreground region", 1, "0"); /* Donut options */ parser->add_long_option ("", "donut-center", "location of donut center in mm \"x [y z]\"", 1, "0 0 0"); parser->add_long_option ("", "donut-radius", "size of donut in mm \"x [y z]\"", 1, "50 50 20"); parser->add_long_option ("", "donut-rings", "number of donut rings (2 rings for traditional donut)", 1, "2"); /* Gabor options */ parser->add_long_option ("", "gabor-k-fib", "choose gabor direction at index i within fibonacci spiral " "of length n; specified as \"i n\" where i and n are integers, " "and i is between 0 and n-1", 1, ""); /* Gaussian options */ parser->add_long_option ("", "gauss-center", "location of Gaussian center in mm \"x [y z]\"", 1, "0 0 0"); parser->add_long_option ("", "gauss-std", "width of Gaussian in mm \"x [y z]\"", 1, "100"); /* Rect options */ parser->add_long_option ("", "rect-size", "width of rectangle in mm \"x [y z]\"," " or locations of rectangle corners in mm" " \"x1 x2 y1 y2 z1 z2\"", 1, "-50 50 -50 50 -50 50"); /* Sphere options */ parser->add_long_option ("", "sphere-center", "location of sphere center in mm \"x y z\"", 1, "0 0 0"); parser->add_long_option ("", "sphere-radius", "radius of sphere in mm \"x [y z]\"", 1, "50"); /* Grid pattern options */ parser->add_long_option ("", "grid-pattern", "grid pattern spacing in voxels \"x [y z]\"", 1, "10"); /* Dose pattern options */ parser->add_long_option ("", "penumbra", "width of dose penumbra in mm", 1, "5"); parser->add_long_option ("", "dose-center", "location of dose center in mm \"x y z\"", 1, "0 0 0"); parser->add_long_option ("", "dose-size", "dimensions of dose aperture in mm \"x [y z]\"," " or locations of rectangle corners in mm" " \"x1 x2 y1 y2 z1 z2\"", 1, "-50 50 -50 50 -50 50"); /* Lung options */ parser->add_long_option ("", "lung-tumor-pos", "position of tumor in mm \"z\" or \"x y z\"", 1, "0"); /* Noise options */ parser->add_long_option ("", "noise-mean", "mean intensity of gaussian noise", 1, "0.0"); parser->add_long_option ("", "noise-std", "standard deviation of gaussian noise", 1, "1.0"); /* Cylinder options */ parser->add_long_option ("", "cylinder-center", "location of cylinder center in mm \"x [y z]\"", 1, "0 0 0"); parser->add_long_option ("", "cylinder-radius", "size of cylinder in mm \"x [y z]\"", 1, "50 50 0"); /* Metadata options */ parser->add_long_option ("", "metadata", "patient metadata (you may use this option multiple times)", 1, ""); parser->add_long_option ("", "patient-id", "patient id metadata: string", 1); parser->add_long_option ("", "patient-name", "patient name metadata: string", 1); parser->add_long_option ("", "patient-pos", "patient position metadata: one of {hfs,hfp,ffs,ffp}", 1, "hfs"); /* Parse the command line arguments */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option("output") && !parser->option("output-dicom")) { throw dlib::error ( "Error, you must specify either --output or --output-dicom.\n" ); } /* Copy values into output struct */ Synthetic_mha_parms *sm_parms = &parms->sm_parms; /* Basic options */ parms->output_fn = parser->get_string("output"); parms->output_dicom = parser->get_string("output-dicom"); parms->output_dose_img_fn = parser->get_string("output-dose-img"); parms->output_prefix = parser->get_string("output-prefix"); parms->output_ss_img_fn = parser->get_string("output-ss-img"); parms->output_ss_list_fn = parser->get_string("output-ss-list"); sm_parms->output_type = plm_image_type_parse ( parser->get_string("output-type")); if (sm_parms->output_type == PLM_IMG_TYPE_UNDEFINED) { throw dlib::error ("Error, unknown output-type\n"); } if (parser->option("dicom-with-uids")) { parms->dicom_with_uids = string_value_true ( parser->get_string ("dicom-with-uids")); } /* Main pattern */ std::string arg = parser->get_string ("pattern"); if (arg == "gauss") { sm_parms->pattern = PATTERN_GAUSS; } else if (arg == "rect") { sm_parms->pattern = PATTERN_RECT; } else if (arg == "sphere") { sm_parms->pattern = PATTERN_SPHERE; } else if (arg == "multi-sphere") { sm_parms->pattern = PATTERN_MULTI_SPHERE; } else if (arg == "donut") { sm_parms->pattern = PATTERN_DONUT; } else if (arg == "dose") { sm_parms->pattern = PATTERN_DOSE; } else if (arg == "grid") { sm_parms->pattern = PATTERN_GRID; } else if (arg == "lung") { sm_parms->pattern = PATTERN_LUNG; } else if (arg == "xramp") { sm_parms->pattern = PATTERN_XRAMP; } else if (arg == "yramp") { sm_parms->pattern = PATTERN_YRAMP; } else if (arg == "zramp") { sm_parms->pattern = PATTERN_ZRAMP; } else if (arg == "noise") { sm_parms->pattern = PATTERN_NOISE; } else if (arg == "cylinder") { sm_parms->pattern = PATTERN_CYLINDER; } else if (arg == "gabor") { sm_parms->pattern = PATTERN_GABOR; } else { throw (dlib::error ("Error. Unknown --pattern argument: " + arg)); } /* Input files */ sm_parms->fixed_fn = parser->get_string("fixed"); sm_parms->input_fn = parser->get_string("input"); /* Image size */ parser->assign_int13 (sm_parms->dim, "dim"); /* Direction cosines */ if (parser->option ("direction-cosines")) { std::string arg = parser->get_string("direction-cosines"); if (!sm_parms->dc.set_from_string (arg)) { throw (dlib::error ("Error parsing --direction-cosines " "(should have nine numbers)\n")); } } /* If origin not specified, volume is centered about size */ float volume_size[3]; parser->assign_float_13 (volume_size, "volume-size"); if (parser->option ("origin")) { parser->assign_float_13 (sm_parms->origin, "origin"); } else { for (int d = 0; d < 3; d++) { /* GCS FIX: This should include direction cosines */ sm_parms->origin[d] = - 0.5 * volume_size[d] + 0.5 * volume_size[d] / sm_parms->dim[d]; } } /* If spacing not specified, set spacing from size and resolution */ if (parser->option ("spacing")) { parser->assign_float_13 (sm_parms->spacing, "spacing"); } else { for (int d = 0; d < 3; d++) { sm_parms->spacing[d] = volume_size[d] / ((float) sm_parms->dim[d]); } } /* Correct negative spacing */ for (int d = 0; d < 3; d++) { if (sm_parms->spacing[d] < 0) { sm_parms->spacing[d] = -sm_parms->spacing[d]; for (int dd = 0; dd < 3; dd++) { sm_parms->dc[d*3+dd] = -sm_parms->dc[d*3+dd]; } } } /* Image intensities */ sm_parms->background = parser->get_float ("background"); sm_parms->foreground = parser->get_float ("foreground"); /* Donut options */ parser->assign_float_13 (sm_parms->donut_center, "donut-center"); parser->assign_float_13 (sm_parms->donut_radius, "donut-radius"); sm_parms->donut_rings = parser->get_int ("donut-rings"); /* Gaussian options */ parser->assign_float_13 (sm_parms->gauss_center, "gauss-center"); parser->assign_float_13 (sm_parms->gauss_std, "gauss-std"); /* Rect options */ int rc = sscanf (parser->get_string("rect-size").c_str(), "%g %g %g %g %g %g", &(sm_parms->rect_size[0]), &(sm_parms->rect_size[1]), &(sm_parms->rect_size[2]), &(sm_parms->rect_size[3]), &(sm_parms->rect_size[4]), &(sm_parms->rect_size[5])); if (rc == 1) { sm_parms->rect_size[0] = - 0.5 * sm_parms->rect_size[0]; sm_parms->rect_size[1] = - sm_parms->rect_size[0]; sm_parms->rect_size[2] = + sm_parms->rect_size[0]; sm_parms->rect_size[3] = - sm_parms->rect_size[0]; sm_parms->rect_size[4] = + sm_parms->rect_size[0]; sm_parms->rect_size[5] = - sm_parms->rect_size[0]; } else if (rc == 3) { sm_parms->rect_size[4] = - 0.5 * sm_parms->rect_size[2]; sm_parms->rect_size[2] = - 0.5 * sm_parms->rect_size[1]; sm_parms->rect_size[0] = - 0.5 * sm_parms->rect_size[0]; sm_parms->rect_size[1] = - sm_parms->rect_size[0]; sm_parms->rect_size[3] = - sm_parms->rect_size[2]; sm_parms->rect_size[5] = - sm_parms->rect_size[4]; } else if (rc != 6) { throw (dlib::error ("Error. Option --rect_size must have " "one, three, or six arguments\n")); } /* Sphere options */ parser->assign_float_13 (sm_parms->sphere_center, "sphere-center"); parser->assign_float_13 (sm_parms->sphere_radius, "sphere-radius"); /* Grid pattern options */ parser->assign_int13 (sm_parms->grid_spacing, "grid-pattern"); /* Dose options */ sm_parms->penumbra = parser->get_float ("penumbra"); parser->assign_float_13 (sm_parms->dose_center, "dose-center"); rc = sscanf (parser->get_string("dose-size").c_str(), "%g %g %g %g %g %g", &(sm_parms->dose_size[0]), &(sm_parms->dose_size[1]), &(sm_parms->dose_size[2]), &(sm_parms->dose_size[3]), &(sm_parms->dose_size[4]), &(sm_parms->dose_size[5])); if (rc == 1) { sm_parms->dose_size[0] = - 0.5 * sm_parms->dose_size[0]; sm_parms->dose_size[1] = - sm_parms->dose_size[0]; sm_parms->dose_size[2] = + sm_parms->dose_size[0]; sm_parms->dose_size[3] = - sm_parms->dose_size[0]; sm_parms->dose_size[4] = + sm_parms->dose_size[0]; sm_parms->dose_size[5] = - sm_parms->dose_size[0]; } else if (rc == 3) { sm_parms->dose_size[4] = - 0.5 * sm_parms->dose_size[2]; sm_parms->dose_size[2] = - 0.5 * sm_parms->dose_size[1]; sm_parms->dose_size[0] = - 0.5 * sm_parms->dose_size[0]; sm_parms->dose_size[1] = - sm_parms->dose_size[0]; sm_parms->dose_size[3] = - sm_parms->dose_size[2]; sm_parms->dose_size[5] = - sm_parms->dose_size[4]; } else if (rc != 6) { throw (dlib::error ("Error. Option --dose_size must have " "one, three, or six arguments\n")); } /* Lung options */ rc = sscanf (parser->get_string("lung-tumor-pos").c_str(), "%g %g %g", &(sm_parms->lung_tumor_pos[0]), &(sm_parms->lung_tumor_pos[1]), &(sm_parms->lung_tumor_pos[2])); if (rc == 1) { sm_parms->lung_tumor_pos[2] = sm_parms->lung_tumor_pos[0]; sm_parms->lung_tumor_pos[0] = 0; sm_parms->lung_tumor_pos[1] = 0; } else if (rc != 3) { throw (dlib::error ("Error. Option --lung-tumor-pos must have " "one or three arguments\n")); } /* Noise options */ rc = sscanf (parser->get_string("noise-mean").c_str(), "%g", &sm_parms->noise_mean); if (rc != 1) { throw (dlib::error ("Error. Option --noise-mean must have " "a floating point argument\n")); } rc = sscanf (parser->get_string("noise-std").c_str(), "%g", &sm_parms->noise_std); if (rc != 1) { throw (dlib::error ("Error. Option --noise-std must have " "a floating point argument\n")); } /* Cylinder options */ parser->assign_float_13 (sm_parms->cylinder_center, "cylinder-center"); parser->assign_float_13 (sm_parms->cylinder_radius, "cylinder-radius"); /* Gabor options */ if (parser->option ("gabor-k-fib")) { sm_parms->gabor_use_k_fib = true; parser->assign_int_2 (sm_parms->gabor_k_fib, "gabor-k-fib"); } /* Metadata options */ for (unsigned int i = 0; i < parser->option("metadata").count(); i++) { parms->m_metadata.push_back ( parser->option("metadata").argument(0,i)); } if (parser->option ("patient-name")) { std::string arg = parser->get_string ("patient-name"); std::string metadata_string = "0010,0010=" + arg; parms->m_metadata.push_back (metadata_string); } if (parser->option ("patient-id")) { std::string arg = parser->get_string ("patient-id"); std::string metadata_string = "0010,0020=" + arg; parms->m_metadata.push_back (metadata_string); } if (parser->option ("patient-pos")) { std::string arg = parser->get_string ("patient-pos"); std::transform (arg.begin(), arg.end(), arg.begin(), (int(*)(int)) toupper); std::string metadata_string = "0018,5100=" + arg; parms->m_metadata.push_back (metadata_string); } } void do_command_synth (int argc, char* argv[]) { Synthetic_mha_main_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); do_synthetic_mha (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_synth.h000066400000000000000000000005471321604176500277150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_synth_h_ #define _pcmd_synth_h_ #include "plmcli_config.h" void do_command_synth (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_synth_vf.cxx000066400000000000000000000155031321604176500307610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include #include #include #include "itk_image_load.h" #include "itk_image_save.h" #include "plm_clp.h" #include "plm_math.h" #include "synthetic_vf.h" #include "volume_header.h" typedef struct synthetic_vf_main_parms Synthetic_vf_main_parms; struct synthetic_vf_main_parms { std::string output_fn; std::string fixed_fn; Synthetic_vf_parms sv_parms; }; static void deduce_geometry ( Plm_image_header *pih, /* Output */ Synthetic_vf_main_parms *parms /* Input */ ) { /* Try to guess the proper dimensions and spacing for output image */ if (parms->fixed_fn != "") { /* use the spacing of user-supplied fixed image */ printf ("Setting PIH from FIXED\n"); FloatImageType::Pointer fixed = itk_image_load_float ( parms->fixed_fn, 0); pih->set_from_itk_image (fixed); } else { /* use user-supplied or default values, which are already set */ } } void do_synthetic_vf (Synthetic_vf_main_parms *parms) { Synthetic_vf_parms *sv_parms = &parms->sv_parms; /* Deduce output geometry */ deduce_geometry (&sv_parms->pih, parms); /* Create vf */ DeformationFieldType::Pointer vf = synthetic_vf (sv_parms); /* Save to file */ itk_image_save (vf, parms->output_fn); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch synth-vf [options]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Synthetic_vf_main_parms *parms, dlib::Plm_clp *parser, int argc, char* argv[] ) { Volume_header vh; plm_long *dim = vh.get_dim(); /* Add --help, --version */ parser->add_default_options (); /* Output files */ parser->add_long_option ("", "output", "output filename", 1, ""); /* Image size */ parser->add_long_option ("", "origin", "location of first image voxel in mm \"x y z\"", 1, "0 0 0"); parser->add_long_option ("", "dim", "size of output image in voxels \"x [y z]\"", 1, "100"); parser->add_long_option ("", "spacing", "voxel spacing in mm \"x [y z]\"", 1, "5"); parser->add_long_option ("", "direction-cosines", "oriention of x, y, and z axes; Specify either preset value," " {identity, rotated-{1,2,3}, sheared}," " or 9 digit matrix string \"a b c d e f g h i\"", 1, ""); parser->add_long_option ("", "volume-size", "size of output image in mm \"x [y z]\"", 1, "500"); parser->add_long_option ("", "fixed", "An input image used to set the size of the output ", 1, ""); /* Patterns */ parser->add_long_option ("", "xf-gauss", "gaussian warp"); parser->add_long_option ("", "xf-radial", "radial expansion (or contraction)"); parser->add_long_option ("", "xf-trans", "uniform translation in mm \"x y z\"", 1); parser->add_long_option ("", "xf-zero", "Null transform"); /* Pattern options */ parser->add_long_option ("", "gauss-center", "location of center of gaussian warp \"x [y z]\"", 1, "0 0 0"); parser->add_long_option ("", "gauss-mag", "displacment magnitude for gaussian warp in mm \"x [y z]\"", 1, "10"); parser->add_long_option ("", "gauss-std", "width of gaussian std in mm \"x [y z]\"", 1, "10"); parser->add_long_option ("", "radial-center", "location of center of radial warp \"x [y z]\"", 1, "0 0 0"); parser->add_long_option ("", "radial-mag", "displacement magnitude for radial warp in mm \"x [y z]\"", 1, "10"); /* Parse the command line arguments */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option("output")) { throw dlib::error ( "Error, you must specify an --output option.\n" ); } /* Check that a xf option was given */ if (!parser->option("xf-gauss") && !parser->option("xf-radial") && !parser->option("xf-trans") && !parser->option("xf-zero")) { std::cout << "Error, you must specify one of the --xf-*** options.\n"; usage_fn (parser, argc, argv); exit (1); } /* Copy values into output struct */ Synthetic_vf_parms *sv_parms = &parms->sv_parms; /* Basic options */ parms->output_fn = parser->get_string("output"); /* Patterns */ if (parser->option("xf-zero")) { sv_parms->pattern = Synthetic_vf_parms::PATTERN_ZERO; } else if (parser->option("xf-trans")) { sv_parms->pattern = Synthetic_vf_parms::PATTERN_TRANSLATION; parser->assign_float_13 (sv_parms->translation, "xf-trans"); } else if (parser->option("xf-radial")) { sv_parms->pattern = Synthetic_vf_parms::PATTERN_RADIAL; } else if (parser->option("xf-gauss")) { sv_parms->pattern = Synthetic_vf_parms::PATTERN_GAUSSIAN; } else { throw (dlib::error ("Error. Unknown --xf argument.")); } /* Fixed */ if (parser->option ("fixed")) { parms->fixed_fn = parser->get_string("fixed"); } /* Image size */ parser->assign_plm_long_13 (dim, "dim"); /* Direction cosines */ if (parser->option ("direction-cosines")) { std::string arg = parser->get_string("direction-cosines"); if (!vh.get_direction_cosines().set_from_string (arg)) { throw (dlib::error ("Error parsing --direction-cosines " "(should have nine numbers)\n")); } } /* If origin not specified, volume is centered about size */ float volume_size[3]; parser->assign_float_13 (volume_size, "volume-size"); if (parser->option ("origin")) { parser->assign_float_13 (vh.get_origin(), "origin"); } else { for (int d = 0; d < 3; d++) { /* GCS FIX: This should include direction cosines */ vh.get_origin()[d] = - 0.5 * volume_size[d] + 0.5 * volume_size[d] / dim[d]; } } /* If spacing not specified, set spacing from size and resolution */ if (parser->option ("spacing")) { parser->assign_float_13 (vh.get_spacing(), "spacing"); } else { for (int d = 0; d < 3; d++) { vh.get_spacing()[d] = volume_size[d] / ((float) dim[d]); } } /* Set the pih */ sv_parms->pih.set (vh); /* Radial options */ parser->assign_float_13 (sv_parms->radial_center, "radial-center"); parser->assign_float_13 (sv_parms->radial_mag, "radial-mag"); /* Gaussian options */ parser->assign_float_13 (sv_parms->gaussian_center, "gauss-center"); parser->assign_float_13 (sv_parms->gaussian_mag, "gauss-mag"); parser->assign_float_13 (sv_parms->gaussian_std, "gauss-std"); } void do_command_synth_vf (int argc, char* argv[]) { Synthetic_vf_main_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); do_synthetic_vf (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_synth_vf.h000066400000000000000000000005601321604176500304030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_synth_vf_h_ #define _pcmd_synth_vf_h_ #include "plmcli_config.h" void do_command_synth_vf (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_threshold.cxx000066400000000000000000000102701321604176500311110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "itk_threshold.h" #include "itk_image_save.h" #include "plm_clp.h" #include "plm_image.h" #include "plm_math.h" #include "pcmd_threshold.h" #include "print_and_exit.h" #include "string_util.h" static void threshold_main (Pcmd_threshold* parms) { Plm_image::Pointer plm_image = plm_image_load ( parms->img_in_fn, PLM_IMG_TYPE_ITK_FLOAT); FloatImageType::Pointer img_in = plm_image->m_itk_float; UCharImageType::Pointer img_out; if (parms->range_string != "") { img_out = itk_threshold (img_in, parms->range_string); } if (parms->output_dicom) { itk_image_save_short_dicom ( img_out, parms->img_out_fn.c_str(), 0); } else { Plm_image pli (img_out); if (parms->output_type) { pli.convert (parms->output_type); } pli.save_image (parms->img_out_fn); } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Pcmd_threshold* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input", "input directory or filename", 1, ""); /* Output files */ parser->add_long_option ("", "output", "output image", 1, ""); /* Different ways to specify threshold range */ parser->add_long_option ("", "above", "value above which output has value high", 1, ""); parser->add_long_option ("", "below", "value below which output has value high", 1, ""); parser->add_long_option ("", "range", "a string that forms a list of threshold ranges of the form " "\"r1-lo,r1-hi,r2-lo,r2-hi,...\", " "such that voxels with intensities within any of the ranges " "([r1-lo,r1-hi], [r2-lo,r2-hi], ...) have output value high", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("input")) { throw (dlib::error ("Error. Please specify an input file " "using the --input option")); } /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Parse range options. Check that one and only one range option was given */ bool have_range = false; bool range_error = false; if (parser->option ("above")) { parms->range_string = string_format ("%f,inf", parser->get_float ("above")); have_range = true; } if (parser->option ("below")) { if (have_range) { range_error = true; } else { parms->range_string = string_format ("-inf,%f", parser->get_float ("below")); have_range = true; } } if (parser->option ("range")) { if (have_range) { range_error = true; } else { parms->range_string = parser->get_string ("range"); have_range = true; } } if (have_range == false) { throw (dlib::error ("Error. Please specify a range with the " "--above, --below, or --range option")); } if (range_error == true) { throw (dlib::error ("Error. Only one range option (--above, " "--below, or --range) may be specified")); } /* Copy input filenames to parms struct */ parms->img_in_fn = parser->get_string("input").c_str(); /* Output files */ parms->img_out_fn = parser->get_string("output").c_str(); } void do_command_threshold (int argc, char *argv[]) { Pcmd_threshold parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); threshold_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_threshold.h000066400000000000000000000013711321604176500305400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_threshold_h_ #define _pcmd_threshold_h_ #include "plmcli_config.h" #include #include #include #include "plm_image_type.h" class Pcmd_threshold { public: std::string img_in_fn; std::string img_out_fn; /* threshold string */ std::string range_string; bool output_dicom; Plm_image_type output_type; public: Pcmd_threshold () { output_dicom = false; output_type = PLM_IMG_TYPE_UNDEFINED; } }; void do_command_threshold (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_thumbnail.cxx000066400000000000000000000106731321604176500311070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "file_util.h" #include "itk_adjust.h" #include "path_util.h" #include "pcmd_thumbnail.h" #include "plm_clp.h" #include "plm_image.h" #include "thumbnail.h" class Thumbnail_parms { public: std::string input_fn; std::string output_fn; int axis; int dim; float spacing; float loc; bool auto_adjust; public: Thumbnail_parms () { output_fn = "thumb.mhd"; dim = 16; spacing = 30.0; axis = 2; loc = 0.0; auto_adjust = false; } }; static void thumbnail_main (Thumbnail_parms* parms) { Plm_image::Pointer pli; /* Load image */ pli = plm_image_load (parms->input_fn, PLM_IMG_TYPE_ITK_FLOAT); /* Make thumbnail */ Thumbnail thumbnail; thumbnail.set_input_image (pli); thumbnail.set_thumbnail_dim (parms->dim); thumbnail.set_thumbnail_spacing (parms->spacing); thumbnail.set_axis (parms->axis); thumbnail.set_slice_loc (parms->loc); pli->m_itk_float = thumbnail.make_thumbnail (); /* Adjust the intensities */ if (parms->auto_adjust) { printf ("Auto-adjusting intensities...\n"); pli->set_itk (itk_auto_adjust (pli->m_itk_float)); } /* Can't write float for these types... */ if (extension_is (parms->output_fn, "png") || extension_is (parms->output_fn, "tif") || extension_is (parms->output_fn, "tiff")) { pli->convert (PLM_IMG_TYPE_ITK_UCHAR); } /* Save the output file */ pli->save_image (parms->output_fn); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Thumbnail_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input", "input directory or filename of image", 1, ""); /* Output files */ parser->add_long_option ("", "output", "output image; can be mha, mhd, nii, nrrd, or other format " "supported by ITK", 1, ""); /* Geometry options */ parser->add_long_option ("", "dim", "size of output image in voxels", 1, "16"); parser->add_long_option ("", "spacing", "voxel spacing in mm", 1, "30"); parser->add_long_option ("", "axis", "either \"x\", \"y\", or \"z\"", 1, "z"); parser->add_long_option ("", "loc", "location of thumbnail along axis", 1, "0"); parser->add_long_option ("", "auto-adjust", "adjust the intensities", 0); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an input file was given */ if (!parser->option ("input")) { throw (dlib::error ("Error. Please specify an input file ")); } /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file ")); } /* Check that no extraneous options were given */ if (parser->number_of_arguments() != 0) { std::string extra_arg = (*parser)[0]; throw (dlib::error ("Error. Unknown option " + extra_arg)); } /* Input/output files */ parms->input_fn = parser->get_string("input").c_str(); parms->output_fn = parser->get_string("output").c_str(); /* Other options */ std::string arg = parser->get_string ("axis"); if (arg == "z") { parms->axis = 2; } else if (arg == "y") { parms->axis = 1; } else if (arg == "x") { parms->axis = 0; } else { throw (dlib::error ("Error. Unknown --axis argument: " + arg)); } parms->loc = parser->get_int ("loc"); parms->spacing = parser->get_float("spacing"); parms->dim = parser->get_int ("dim"); if (parser->option ("auto-adjust")) { parms->auto_adjust = true; } } void do_command_thumbnail (int argc, char *argv[]) { Thumbnail_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); /* Run the thumbnailer */ thumbnail_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_thumbnail.h000066400000000000000000000006331321604176500305270ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_thumbnail_h_ #define _pcmd_thumbnail_h_ #include "plmcli_config.h" #include #include void do_command_thumbnail (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_union.cxx000066400000000000000000000044061321604176500302510ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "itk_union.h" #include "plm_clp.h" #include "plm_image.h" #include "plm_file_format.h" #include "xform.h" class Union_parms { public: std::string input_1_fn; std::string input_2_fn; std::string output_fn; }; void union_main (Union_parms *parms) { /* Load the inputs */ Plm_image img_1 (parms->input_1_fn, PLM_IMG_TYPE_ITK_UCHAR); Plm_image img_2 (parms->input_2_fn, PLM_IMG_TYPE_ITK_UCHAR); /* Make the union */ UCharImageType::Pointer itk_out = itk_union ( img_1.itk_uchar(), img_2.itk_uchar()); /* Save it */ Plm_image img_out (itk_out); img_out.save_image (parms->output_fn); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options] input_1 input_2\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Union_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Output files */ parser->add_long_option ("", "output", "filename for output image", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output option")); } /* Copy input filenames to parms struct. Two input files must be specified. */ if (parser->number_of_arguments() != 2) { throw (dlib::error ("Error. You must specify two input files")); } parms->input_1_fn = (*parser)[0]; parms->input_2_fn = (*parser)[1]; /* Output files */ parms->output_fn = parser->get_string("output").c_str(); } void do_command_union (int argc, char *argv[]) { Union_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); union_main (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_union.h000066400000000000000000000005471321604176500277000ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_union_h_ #define _pcmd_union_h_ #include "plmcli_config.h" void do_command_union (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_vf_invert.cxx000066400000000000000000000234731321604176500311300ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "itk_image_load.h" #include "mha_io.h" #include "plm_clp.h" #include "plm_image.h" #include "plm_image_header.h" #include "vf_convolve.h" #include "vf_invert.h" class Vf_invert_parms { public: std::string vf_in_fn; std::string vf_out_fn; std::string fixed_img_fn; bool have_dim; bool have_origin; bool have_spacing; plm_long dim[3]; float origin[3]; float spacing[3]; bool old_algorithm; int iterations; public: Vf_invert_parms () { vf_in_fn = ""; vf_out_fn = ""; fixed_img_fn = ""; for (int d = 0; d < 3; d++) { dim[d] = 0; origin[d] = 0.f; spacing[d] = 1.f; } have_dim = false; have_origin = false; have_spacing = false; old_algorithm = false; iterations = 20; } }; void do_vf_invert_old (Vf_invert_parms* parms) { plm_long i, j, k, v; int its; float x, y, z; Plm_image_header pih; Volume *mask, *vf_in, *vf_inv, *vf_smooth, *vf_out; float *img_in, *img_inv, *img_smooth, *img_out; unsigned char *img_mask; float ker[3] = { 0.3, 0.4, 0.3 }; if (parms->fixed_img_fn != "") { /* if given, use the parameters from user-supplied fixed image */ FloatImageType::Pointer fixed = itk_image_load_float ( parms->fixed_img_fn.c_str(), 0); pih.set_from_itk_image (fixed); pih.get_origin (parms->origin); pih.get_spacing (parms->spacing); pih.get_dim (parms->dim); pih.set_from_gpuit (parms->dim, parms->origin, parms->spacing, 0); } /* GCS FIX: Need direction cosines */ /* Create mask volume */ mask = new Volume (parms->dim, parms->origin, parms->spacing, 0, PT_UCHAR, 1); /* GCS FIX: Need direction cosines */ /* Create tmp volume */ vf_inv = new Volume (parms->dim, parms->origin, parms->spacing, 0, PT_VF_FLOAT_INTERLEAVED, 1); /* Load input vf */ vf_in = read_mha (parms->vf_in_fn.c_str()); vf_convert_to_interleaved (vf_in); /* Populate mask & tmp volume */ img_mask = (unsigned char*) mask->img; img_in = (float*) vf_in->img; img_inv = (float*) vf_inv->img; for (z = vf_in->origin[2], k = 0, v = 0; k < vf_in->dim[2]; k++, z+=vf_in->spacing[2]) { for (y = vf_in->origin[1], j = 0; j < vf_in->dim[1]; j++, y+=vf_in->spacing[1]) { for (x = vf_in->origin[0], i = 0; i < vf_in->dim[0]; v++, i++, x+=vf_in->spacing[0]) { plm_long mijk[3], midx; float mxyz[3]; mxyz[0] = x + img_in[3*v+0]; mijk[0] = ROUND_INT ((mxyz[0] - vf_inv->origin[0]) / vf_inv->spacing[0]); mxyz[1] = y + img_in[3*v+1]; mijk[1] = (mxyz[1] - vf_inv->origin[1]) / vf_inv->spacing[1]; mxyz[2] = z + img_in[3*v+2]; mijk[2] = (mxyz[2] - vf_inv->origin[2]) / vf_inv->spacing[2]; if (mijk[0] < 0 || mijk[0] >= vf_inv->dim[0]) continue; if (mijk[1] < 0 || mijk[1] >= vf_inv->dim[1]) continue; if (mijk[2] < 0 || mijk[2] >= vf_inv->dim[2]) continue; midx = (mijk[2] * vf_inv->dim[1] + mijk[1]) * vf_inv->dim[0] + mijk[0]; img_inv[3*midx+0] = -img_in[3*v+0]; img_inv[3*midx+1] = -img_in[3*v+1]; img_inv[3*midx+2] = -img_in[3*v+2]; img_mask[midx] ++; } } } /* We're done with input volume now. */ delete vf_in; /* GCS FIX: Need direction cosines */ /* Create tmp & output volumes */ vf_out = new Volume (parms->dim, parms->origin, parms->spacing, 0, PT_VF_FLOAT_INTERLEAVED, 3); img_out = (float*) vf_out->img; /* GCS FIX: Need direction cosines */ vf_smooth = new Volume (parms->dim, parms->origin, parms->spacing, 0, PT_VF_FLOAT_INTERLEAVED, 3); img_smooth = (float*) vf_smooth->img; /* Iterate, pasting and smoothing */ printf ("Paste and smooth loop\n"); for (its = 0; its < parms->iterations; its++) { printf ("Iteration %d/%d\n", its, parms->iterations); /* Paste */ for (v = 0, k = 0; k < vf_out->dim[2]; k++) { for (j = 0; j < vf_out->dim[1]; j++) { for (i = 0; i < vf_out->dim[0]; i++, v++) { if (img_mask[v]) { img_smooth[3*v+0] = img_inv[3*v+0]; img_smooth[3*v+1] = img_inv[3*v+1]; img_smooth[3*v+2] = img_inv[3*v+2]; } else { img_smooth[3*v+0] = img_out[3*v+0]; img_smooth[3*v+1] = img_out[3*v+1]; img_smooth[3*v+2] = img_out[3*v+2]; } } } } /* Smooth the estimate into vf_out. The volumes are ping-ponged. */ printf ("Convolving\n"); vf_convolve_x (vf_out, vf_smooth, ker, 3); vf_convolve_y (vf_smooth, vf_out, ker, 3); vf_convolve_z (vf_out, vf_smooth, ker, 3); } printf ("Done.\n"); /* We're done with the mask & smooth image. */ delete mask; delete vf_smooth; /* Write the output */ write_mha (parms->vf_out_fn.c_str(), vf_out); delete vf_out; } void do_vf_invert_new (Vf_invert_parms* parms) { Vf_invert vf_invert; vf_invert.set_input_vf (parms->vf_in_fn.c_str()); if (parms->fixed_img_fn != "") { vf_invert.set_fixed_image (parms->fixed_img_fn.c_str()); } if (parms->have_dim) { vf_invert.set_dim (parms->dim); } if (parms->have_origin) { vf_invert.set_origin (parms->origin); } if (parms->have_spacing) { vf_invert.set_spacing (parms->spacing); } #if defined (commentout) /* GCS FIX: direction cosines */ if (parms->have_direction_cosines) { vf_invert.set_direction_cosines (parms->direction_cosines); } #endif vf_invert.set_iterations (parms->iterations); /* Invert the vf */ vf_invert.run (); /* Write the output */ write_mha (parms->vf_out_fn.c_str(), vf_invert.get_output_volume()); #if defined (commentout) plm_image_save_vol (parms->vf_out_fn.c_str(), vf_invert.get_output_volume()); #endif } void do_vf_invert (Vf_invert_parms* parms) { if (parms->old_algorithm) { do_vf_invert_old (parms); } else { do_vf_invert_new (parms); } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options] input_file [input_file ...]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Vf_invert_parms *parms, dlib::Plm_clp *parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Basic options */ parser->add_long_option ("", "input", "input vector field file name", 1, ""); parser->add_long_option ("", "output", "output vector field file name", 1, ""); parser->add_long_option ("", "dim", "size of output vector field in voxels \"x [y z]\"", 1, ""); parser->add_long_option ("", "origin", "location of first voxel of output vector field in mm \"x y z\"", 1, ""); parser->add_long_option ("", "spacing", "voxel spacing of output vector field in mm \"x [y z]\"", 1, ""); parser->add_long_option ("", "fixed", "fixed image (match output vector field size to this image)", 1, ""); parser->add_long_option ("", "old-algorithm", "use the old algorithm", 0); parser->add_long_option ("", "iterations", "number of iterations to run (default = 20)", 1, ""); /* Parse the command line arguments */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an input file was given */ if (!parser->option ("input")) { throw (dlib::error ("Error. Please specify an input file " "using the --input options")); } /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output options")); } /* Check that output dimensions are known */ if (!parser->option ("dim") || !parser->option("origin") || !parser->option("spacing")) { if (!parser->option ("fixed")) { throw (dlib::error ("Error. Please specify either dim, origin, " " and spacing -or- a fixed file")); } } /* Copy values into parameter struct */ parms->vf_in_fn = parser->get_string("input"); parms->vf_out_fn = parser->get_string("output"); if (parser->option ("fixed")) { parms->fixed_img_fn = parser->get_string("fixed"); } if (parser->option ("dim")) { parms->have_dim = true; parser->assign_plm_long_13 (parms->dim, "dim"); } if (parser->option ("origin")) { parms->have_origin = true; parser->assign_float_13 (parms->origin, "origin"); } if (parser->option ("spacing")) { parms->have_spacing = true; parser->assign_float_13 (parms->spacing, "spacing"); } if (parser->option ("old-algorithm")) { parms->old_algorithm = true; } if (parser->option ("iterations")) { parser->get_value (parms->iterations, "iterations"); } } void do_command_vf_invert (int argc, char *argv[]) { Vf_invert_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); /* Do the work */ do_vf_invert (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_vf_invert.h000066400000000000000000000005631321604176500305500ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_vf_invert_h_ #define _pcmd_vf_invert_h_ #include "plmcli_config.h" void do_command_vf_invert (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_warp.cxx000066400000000000000000000431421321604176500300720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include #include #include "pcmd_warp.h" #include "plm_clp.h" #include "plm_file_format.h" #include "print_and_exit.h" #include "rt_study.h" #include "rt_study_warp.h" #include "string_util.h" #include "warp_parms.h" static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: plastimatch %s [options]\n", argv[1]); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Warp_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files */ parser->add_long_option ("", "input", "input directory or filename; " "can be an image, structure set file (cxt or dicom-rt), " "dose file (dicom-rt, monte-carlo or xio), " "dicom directory, or xio directory", 1, ""); parser->add_long_option ("", "xf", "input transform used to warp image(s)", 1, ""); parser->add_long_option ("", "referenced-ct", "dicom directory used to set UIDs and metadata", 1, ""); parser->add_long_option ("", "input-cxt", "input a cxt file", 1, ""); parser->add_long_option ("", "input-prefix", "input a directory of structure set images (one image per file)", 1, ""); parser->add_long_option ("", "input-ss-img", "input a structure set image file", 1, ""); parser->add_long_option ("", "input-ss-list", "input a structure set list file containing names and colors", 1, ""); parser->add_long_option ("", "input-dose-img", "input a dose volume", 1, ""); parser->add_long_option ("", "input-dose-xio", "input an xio dose volume", 1, ""); parser->add_long_option ("", "input-dose-ast", "input an astroid dose volume", 1, ""); parser->add_long_option ("", "input-dose-mc", "input an monte carlo volume", 1, ""); parser->add_long_option ("", "dif", "dif file (used by dij warper)", 1, ""); /* Output files */ parser->add_long_option ("", "output-img", "output image; can be mha, mhd, nii, nrrd, or other format " "supported by ITK", 1, ""); parser->add_long_option ("", "output-cxt", "output a cxt-format structure set file", 1, ""); parser->add_long_option ("", "output-dicom", "create a directory containing dicom and dicom-rt files", 1, ""); parser->add_long_option ("", "output-dij", "create a dij matrix file", 1, ""); parser->add_long_option ("", "output-dose-img", "create a dose image volume", 1, ""); parser->add_long_option ("", "output-labelmap", "create a structure set image with each voxel labeled as " "a single structure", 1, ""); parser->add_long_option ("", "output-colormap", "create a colormap file that can be used with 3d slicer", 1, ""); parser->add_long_option ("", "output-pointset", "create a pointset file that can be used with 3d slicer", 1, ""); parser->add_long_option ("", "output-prefix", "create a directory with a separate image for each structure", 1, ""); parser->add_long_option ("", "output-prefix-fcsv", "create a directory with a separate fcsv pointset file for " "each structure", 1, ""); parser->add_long_option ("", "output-ss-img", "create a structure set image which allows overlapping structures", 1, ""); parser->add_long_option ("", "output-ss-list", "create a structure set list file containing names and colors", 1, ""); parser->add_long_option ("", "output-vf", "create a vector field from the input xf", 1, ""); parser->add_long_option ("", "output-xio", "create a directory containing xio-format files", 1, ""); /* Output options */ parser->add_long_option ("", "output-type", "type of output image, one of {uchar, short, float, ...}", 1, ""); parser->add_long_option ("", "prefix-format", "file format of rasterized structures, either \"mha\" or \"nrrd\"", 1, "mha"); parser->add_long_option ("", "dicom-with-uids", "set to false to remove uids from created dicom filenames, " "default is true", 1, "true"); parser->add_long_option ("", "dij-dose-volumes", "set to true to output nrrd files corresponding to Dij matrix " " beamlets, default is false", 1, "true"); /* Algorithm options */ parser->add_long_option ("", "algorithm", "algorithm to use for warping, either \"itk\" or \"native\", " "default is native", 1, "native"); parser->add_long_option ("", "force-resample", "resample the transformed image even when transform is linear", 0); parser->add_long_option ("", "dose-scale", "scale the dose by this value", 1, ""); parser->add_long_option ("", "interpolation", "interpolation to use when resampling, either \"nn\" for " "nearest neighbors or \"linear\" for tri-linear, default is linear", 1, "linear"); parser->add_long_option ("", "default-value", "value to set for pixels with unknown value, default is 0", 1, ""); parser->add_long_option ("", "prune-empty", "delete empty structures from output", 0); parser->add_long_option ("", "simplify-perc", "delete percent of the vertices from output polylines", 1, "0"); parser->add_long_option ("", "xor-contours", "overlapping contours should be xor'd instead of or'd", 0); /* Geometry options */ parser->add_long_option ("F", "fixed", "fixed image (match output size to this image)", 1, ""); parser->add_long_option ("", "origin", "location of first image voxel in mm \"x y z\"", 1, ""); parser->add_long_option ("", "dim", "size of output image in voxels \"x [y z]\"", 1, ""); parser->add_long_option ("", "spacing", "voxel spacing in mm \"x [y z]\"", 1, ""); parser->add_long_option ("", "direction-cosines", "oriention of x, y, and z axes; Specify either preset value," " {identity,rotated-{1,2,3},sheared}," " or 9 digit matrix string \"a b c d e f g h i\"", 1, ""); /* Metadata options */ parser->add_long_option ("", "metadata", "patient metadata (you may use this option multiple times), " "option written as \"XXXX,YYYY=string\"", 1, ""); parser->add_long_option ("", "modality", "modality metadata: such as {CT, MR, PT}, default is CT", 1, "CT"); parser->add_long_option ("", "patient-id", "patient id metadata: string", 1); parser->add_long_option ("", "patient-name", "patient name metadata: string", 1); parser->add_long_option ("", "patient-pos", "patient position metadata: one of {hfs,hfp,ffs,ffp}", 1, "hfs"); parser->add_long_option ("", "study-description", "study description: string", 1); parser->add_long_option ("", "series-description", "series description for image metadata: string", 1); parser->add_long_option ("", "dose-series-description", "series description for dose metadata: string", 1); parser->add_long_option ("", "rtss-series-description", "series description for structure metadata: string", 1); parser->add_long_option ("", "series-number", "series number for image metadata: integer", 1); parser->add_long_option ("", "dose-series-number", "series number for dose metadata: integer", 1); parser->add_long_option ("", "rtss-series-number", "series number for structure metadata: integer", 1); parser->add_long_option ("", "series-uid", "series UID for image metadata: string", 1); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an input file was given */ if (!parser->option ("input") && !parser->option("input-cxt") && !parser->option("input-prefix") && !parser->option("input-ss-img") && !parser->option("input-ss-list") && !parser->option("input-dose-img") && !parser->option("input-dose-xio") && !parser->option("input-dose-ast") && !parser->option("input-dose-mc")) { throw (dlib::error ("Error. Please specify an input file " "using one of the --input options")); } /* Check that no extraneous options were given */ if (parser->number_of_arguments() != 0) { std::string extra_arg = (*parser)[0]; throw (dlib::error ("Error. Unknown option " + extra_arg)); } /* Input files */ parms->input_fn = parser->get_string("input").c_str(); parms->xf_in_fn = parser->get_string("xf").c_str(); parms->referenced_dicom_dir = parser->get_string("referenced-ct").c_str(); parms->input_cxt_fn = parser->get_string("input-cxt").c_str(); parms->input_prefix = parser->get_string("input-prefix").c_str(); parms->input_ss_img_fn = parser->get_string("input-ss-img").c_str(); parms->input_ss_list_fn = parser->get_string("input-ss-list").c_str(); parms->input_dose_img_fn = parser->get_string("input-dose-img").c_str(); parms->input_dose_xio_fn = parser->get_string("input-dose-xio").c_str(); parms->input_dose_ast_fn = parser->get_string("input-dose-ast").c_str(); parms->input_dose_mc_fn = parser->get_string("input-dose-mc").c_str(); /* Dij input files */ parms->dif_in_fn = parser->get_string("dif").c_str(); /* Output files */ parms->output_img_fn = parser->get_string("output-img").c_str(); parms->output_cxt_fn = parser->get_string("output-cxt").c_str(); parms->output_dicom = parser->get_string("output-dicom").c_str(); parms->output_dij_fn = parser->get_string("output-dij").c_str(); parms->output_dose_img_fn = parser->get_string("output-dose-img").c_str(); parms->output_labelmap_fn = parser->get_string("output-labelmap").c_str(); parms->output_colormap_fn = parser->get_string("output-colormap").c_str(); parms->output_pointset_fn = parser->get_string("output-pointset").c_str(); parms->output_prefix = parser->get_string("output-prefix").c_str(); parms->output_prefix_fcsv = parser->get_string("output-prefix-fcsv").c_str(); parms->output_ss_img_fn = parser->get_string("output-ss-img"); parms->output_ss_list_fn = parser->get_string("output-ss-list"); parms->output_vf_fn = parser->get_string("output-vf").c_str(); parms->output_xio_dirname = parser->get_string("output-xio").c_str(); /* Output options */ if (parser->option("output-type")) { std::string arg = parser->get_string ("output-type"); parms->output_type = plm_image_type_parse (arg.c_str()); if (parms->output_type == PLM_IMG_TYPE_UNDEFINED) { throw (dlib::error ("Error. Unknown --output-type argument: " + parser->get_string("output-type"))); } } if (parser->option("prefix-format")) { parms->prefix_format = parser->get_string ("prefix-format"); } else { parms->prefix_format = "mha"; } if (parser->option("dicom-with-uids")) { parms->dicom_with_uids = string_value_true ( parser->get_string ("dicom-with-uids")); } if (parser->option("dij-dose-volumes")) { parms->output_dij_dose_volumes = string_value_true ( parser->get_string ("dij-dose-volumes")); } /* Algorithm options */ std::string arg = parser->get_string ("algorithm"); if (arg == "itk") { parms->use_itk = 1; } else if (arg == "native") { parms->use_itk = 0; } else { throw (dlib::error ("Error. Unknown --algorithm argument: " + arg)); } if (parser->option("force-resample")) { parms->force_resample = true; } if (parser->option("default-value")) { parms->default_val = parser->get_float("default-value"); } parms->have_dose_scale = false; if (parser->option("dose-scale")) { parms->have_dose_scale = true; parms->dose_scale = parser->get_float("dose-scale"); } arg = parser->get_string ("interpolation"); if (arg == "nn") { parms->interp_lin = 0; } else if (arg == "linear") { parms->interp_lin = 1; } else { throw (dlib::error ("Error. Unknown --interpolation argument: " + arg)); } if (parser->option("prune-empty")) { parms->prune_empty = 1; } parms->simplify_perc = parser->get_float("simplify-perc"); if (parser->option("xor-contours")) { parms->xor_contours = true; } /* Geometry options */ if (parser->option ("dim")) { parms->m_have_dim = true; parser->assign_plm_long_13 (parms->m_dim, "dim"); } if (parser->option ("origin")) { parms->m_have_origin = true; parser->assign_float_13 (parms->m_origin, "origin"); } if (parser->option ("spacing")) { parms->m_have_spacing = true; parser->assign_float_13 (parms->m_spacing, "spacing"); } parms->fixed_img_fn = parser->get_string("fixed").c_str(); /* Direction cosines */ if (parser->option ("direction-cosines")) { parms->m_have_direction_cosines = true; std::string arg = parser->get_string("direction-cosines"); if (!parms->m_dc.set_from_string (arg)) { throw (dlib::error ("Error parsing --direction-cosines " "(should have nine numbers)\n")); } } /* Metadata options */ for (unsigned int i = 0; i < parser->option("metadata").count(); i++) { parms->m_study_metadata.push_back ( parser->option("metadata").argument(0,i)); } if (parser->option ("modality")) { std::string arg = parser->get_string ("modality"); std::string metadata_string = "0008,0060=" + arg; parms->m_image_metadata.push_back (metadata_string); } if (parser->option ("patient-name")) { std::string arg = parser->get_string ("patient-name"); std::string metadata_string = "0010,0010=" + arg; parms->m_study_metadata.push_back (metadata_string); } if (parser->option ("patient-id")) { std::string arg = parser->get_string ("patient-id"); std::string metadata_string = "0010,0020=" + arg; parms->m_study_metadata.push_back (metadata_string); } if (parser->option ("patient-pos")) { std::string arg = parser->get_string ("patient-pos"); std::transform (arg.begin(), arg.end(), arg.begin(), (int(*)(int)) toupper); std::string metadata_string = "0018,5100=" + arg; parms->m_study_metadata.push_back (metadata_string); } if (parser->option ("study-description")) { std::string arg = parser->get_string ("study-description"); std::string metadata_string = "0008,1030=" + arg; parms->m_study_metadata.push_back (metadata_string); } if (parser->option ("series-description")) { std::string arg = parser->get_string ("series-description"); std::string metadata_string = "0008,103e=" + arg; parms->m_image_metadata.push_back (metadata_string); } if (parser->option ("dose-series-description")) { std::string arg = parser->get_string ("dose-series-description"); std::string metadata_string = "0008,103e=" + arg; parms->m_dose_metadata.push_back (metadata_string); } if (parser->option ("rtss-series-description")) { std::string arg = parser->get_string ("rtss-series-description"); std::string metadata_string = "0008,103e=" + arg; parms->m_rtstruct_metadata.push_back (metadata_string); } if (parser->option ("series-number")) { std::string arg = parser->get_string ("series-number"); std::string metadata_string = "0020,0011=" + arg; parms->m_image_metadata.push_back (metadata_string); } if (parser->option ("dose-series-number")) { std::string arg = parser->get_string ("dose-series-number"); std::string metadata_string = "0020,0011=" + arg; parms->m_dose_metadata.push_back (metadata_string); } if (parser->option ("rtss-series-number")) { std::string arg = parser->get_string ("rtss-series-number"); std::string metadata_string = "0020,0011=" + arg; parms->m_rtstruct_metadata.push_back (metadata_string); } if (parser->option ("series-uid")) { std::string arg = parser->get_string ("series-uid"); std::string metadata_string = "0020,000e=" + arg; parms->m_image_metadata.push_back (metadata_string); parms->image_series_uid_forced = true; } } void do_command_warp (int argc, char* argv[]) { Warp_parms parms; Plm_file_format file_type; Rt_study rt_study; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); /* Dij matrices are a special case */ if (parms.output_dij_fn != "") { if (parms.dif_in_fn != "") { warp_dij_main (&parms); return; } else { print_and_exit ("Sorry, you need to specify --dif for dij warping.\n"); } } /* What is the input file type? */ file_type = plm_file_format_deduce (parms.input_fn.c_str()); /* Pointsets are a special case */ if (file_type == PLM_FILE_FMT_POINTSET) { warp_pointset_main (&parms); return; } /* Process warp */ rt_study_warp (&rt_study, file_type, &parms); printf ("Finished!\n"); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_warp.h000066400000000000000000000007661321604176500275240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_warp_h_ #define _pcmd_warp_h_ #include "plmcli_config.h" class Warp_parms; void do_command_warp (int argc, char* argv[]); void warp_image_main (Warp_parms* parms); void warp_dij_main (Warp_parms* parms); void warp_pointset_main (Warp_parms* parms); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_warp_dij.cxx000066400000000000000000000304651321604176500307240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* Warp one or more dij matrices based on a vector field */ #include "plmcli_config.h" #include #include #include #include "itkImage.h" #include "itkImageRegionIteratorWithIndex.h" #include "itkInterpolateImagePointsFilter.h" #include "itkLinearInterpolateImageFunction.h" #include "itkVectorLinearInterpolateImageFunction.h" #include "itk_image_create.h" #include "itk_image_save.h" #include "itk_image_type.h" #include "itk_warp.h" #include "logfile.h" #include "pcmd_warp.h" #include "plm_image_header.h" #include "print_and_exit.h" #include "string_util.h" #include "warp_parms.h" #include "xform.h" typedef unsigned short ushort; typedef unsigned long ulong; class Dij_header { public: plm_long dose_dim[3]; float dose_origin[3]; float dose_spacing[3]; public: Dij_header () { for (int d = 0; d < 3; d++) { dose_dim[d] = 0; dose_origin[d] = 0.; dose_spacing[d] = 0.; } } }; typedef struct __Pencil_Beam Pencil_Beam; struct __Pencil_Beam { float energy; float spot_x; float spot_y; int nvox; ushort* vox; }; typedef struct __Dij_Matrix Dij_Matrix; struct __Dij_Matrix { float gantry_angle; float table_angle; float collimator_angle; float spot_spacing_dx; float spot_spacing_dy; float voxel_size_dx; float voxel_size_dy; float voxel_size_dz; int dose_cube_size[3]; int num_pencil_beams; float absolute_dose_coefficient; }; void dij_parse_error (void) { fprintf (stderr, "Parse error in reading dij_matrix\n"); exit (-1); } void dij_write_error (void) { fprintf (stderr, "Error writing dij_matrix\n"); exit (-1); } void ctatts_parse_error (void) { fprintf (stderr, "Parse error in reading ctatts file\n"); exit (-1); } void dif_parse_error (void) { fprintf (stderr, "Parse error in reading dif file\n"); exit (-1); } void load_dif (Dij_header* dijh, const char* dif_in) { int i; float f; FILE* fp; const int BUFLEN = 1024; char buf[BUFLEN]; fp = fopen (dif_in, "rt"); if (!fp) { fprintf (stderr, "Error opening dif file for read: %s\n", dif_in); exit (-1); } /* GCS FIX: I should give an error if not all lines are found */ /* N.b. This converts from IEC coordinats to DICOM coordinates during read */ while (1) { if (!fgets (buf, BUFLEN, fp)) { break; } if (buf[0] == '\0' || buf[0] == '\n') { /* Empty lines are ok */ } else if (sscanf (buf, "Delta-X %f", &f)) { dijh->dose_spacing[0] = f; } else if (sscanf (buf, "Delta-Y %f", &f)) { dijh->dose_spacing[2] = f; } else if (sscanf (buf, "Delta-Z %f", &f)) { dijh->dose_spacing[1] = f; } else if (sscanf (buf, "Dimension-Dose-X %d", &i)) { dijh->dose_dim[0] = i; } else if (sscanf (buf, "Dimension-Dose-Y %d", &i)) { dijh->dose_dim[2] = i; } else if (sscanf (buf, "Dimension-Dose-Z %d", &i)) { dijh->dose_dim[1] = i; } else if (sscanf (buf, "Position-Dose-X %f", &f)) { dijh->dose_origin[0] = f; } else if (sscanf (buf, "Position-Dose-Y %f", &f)) { dijh->dose_origin[2] = f; } else if (sscanf (buf, "Position-Dose-Z %f", &f)) { dijh->dose_origin[1] = -f; } else { /* Ignore other lines */ } } fclose (fp); } FloatImageType::Pointer make_dose_image ( Dij_header *dijh, Dij_Matrix *dij_matrix) { /* GCS FIX: Should check that this value matches the one in the dij header */ #if defined (commentout) FloatImageType::SizeType size; size[0] = dij_matrix->dose_cube_size[0]; size[1] = dij_matrix->dose_cube_size[1]; size[2] = dij_matrix->dose_cube_size[2]; #endif return itk_image_create (Plm_image_header ( dijh->dose_dim, dijh->dose_origin, dijh->dose_spacing)); } void set_pencil_beam_to_image ( FloatImageType::Pointer& img, const Pencil_Beam *pb) { typedef itk::ImageRegionIteratorWithIndex< FloatImageType > ImageIterator; /* Clear image */ ImageIterator it1 (img, img->GetBufferedRegion()); it1.GoToBegin(); while (!it1.IsAtEnd()) { FloatImageType::IndexType idx = it1.GetIndex(); //it1.Set ((float) idx[0]); it1.Set (0.0); ++it1; } /* Set non-zero voxels into image */ SizeType sz = img->GetLargestPossibleRegion().GetSize(); FloatImageType::IndexType itk_index; for (long i = 0; i < pb->nvox; i++) { /* Get index and value; convert index to DICOM */ long pb_index = (pb->vox[i*3+1] << 16) + pb->vox[i*3]; ushort value = pb->vox[i*3+2]; long iec_index[3]; iec_index[0] = pb_index % sz[0]; long tmp = pb_index / sz[0]; iec_index[1] = tmp % sz[2]; iec_index[2] = tmp / sz[2]; /* Convert index to DICOM */ itk_index[2] = (sz[2] - iec_index[1] - 1); itk_index[1] = iec_index[2]; itk_index[0] = iec_index[0]; #if defined (commentout) printf ("%d -> %d %d %d\n", pb_index, itk_index[0], itk_index[1], itk_index[2]); break; #endif /* Set voxel */ img->SetPixel (itk_index, (float) value); } } void read_pencil_beam (Pencil_Beam* pb, FILE* fp) { int rc; rc = fread (&pb->energy, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&pb->spot_x, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&pb->spot_y, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&pb->nvox, sizeof(int), 1, fp); if (rc != 1) dij_parse_error(); pb->vox = (ushort*) malloc (3*pb->nvox*sizeof(ushort)); rc = fread (pb->vox, sizeof(ushort), 3*pb->nvox, fp); if (rc != 3*pb->nvox) dij_parse_error(); } void write_pencil_beam (Pencil_Beam* pb, FloatImageType::Pointer img, FILE* fp) { int rc; int nvox = 0; long index = 0; long nvox_loc, eob_loc; rc = fwrite (&pb->energy, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&pb->spot_x, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&pb->spot_y, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); nvox_loc = ftell (fp); rc = fwrite (&pb->nvox, sizeof(int), 1, fp); if (rc != 1) dij_write_error(); SizeType sz = img->GetLargestPossibleRegion().GetSize(); typedef itk::ImageRegionIteratorWithIndex< FloatImageType > ImageIterator; ImageIterator it1 (img, img->GetBufferedRegion()); it1.GoToBegin(); while (!it1.IsAtEnd()) { ushort vox[3]; vox[2] = (ushort) it1.Get(); if (vox[2] > 0) { ImageIterator::IndexType idx = it1.GetIndex(); long iec_index = idx[1]*sz[2]*sz[0] + (sz[2]-idx[2]-1)*sz[0] + idx[0]; vox[0] = (ushort) (iec_index & 0xFFFF); vox[1] = (ushort) (iec_index >> 16); #if defined (commentout) printf ("%d %d %d -> %d, 0x%x -> 0x%02x 0x%02x\n", idx[0], idx[1], idx[2], iec_index, iec_index, vox[0], vox[1]); break; #endif rc = fwrite (vox, sizeof(ushort), 3, fp); if (rc != 3) dij_write_error(); nvox++; } ++index; ++it1; } eob_loc = ftell (fp); fseek (fp, nvox_loc, SEEK_SET); rc = fwrite (&nvox, sizeof(int), 1, fp); if (rc != 1) dij_write_error(); fseek (fp, eob_loc, SEEK_SET); } void read_dij_header (Dij_Matrix* dij_matrix, FILE* fp) { int rc; rc = fread (&dij_matrix->gantry_angle, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&dij_matrix->table_angle, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&dij_matrix->collimator_angle, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&dij_matrix->spot_spacing_dx, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&dij_matrix->spot_spacing_dy, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&dij_matrix->voxel_size_dx, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&dij_matrix->voxel_size_dy, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&dij_matrix->voxel_size_dz, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&dij_matrix->dose_cube_size, sizeof(int), 3, fp); if (rc != 3) dij_parse_error(); rc = fread (&dij_matrix->num_pencil_beams, sizeof(int), 1, fp); if (rc != 1) dij_parse_error(); rc = fread (&dij_matrix->absolute_dose_coefficient, sizeof(float), 1, fp); if (rc != 1) dij_parse_error(); } void write_dij_header (Dij_Matrix* dij_matrix, FILE* fp) { int rc; rc = fwrite (&dij_matrix->gantry_angle, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&dij_matrix->table_angle, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&dij_matrix->collimator_angle, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&dij_matrix->spot_spacing_dx, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&dij_matrix->spot_spacing_dy, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&dij_matrix->voxel_size_dx, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&dij_matrix->voxel_size_dy, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&dij_matrix->voxel_size_dz, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&dij_matrix->dose_cube_size, sizeof(int), 3, fp); if (rc != 3) dij_write_error(); rc = fwrite (&dij_matrix->num_pencil_beams, sizeof(int), 1, fp); if (rc != 1) dij_write_error(); rc = fwrite (&dij_matrix->absolute_dose_coefficient, sizeof(float), 1, fp); if (rc != 1) dij_write_error(); } FloatImageType::Pointer warp_pencil_beam ( DeformationFieldType::Pointer& vf, FloatImageType::Pointer& pb_img, Dij_Matrix *dij_matrix, Dij_header *dijh, Pencil_Beam *pb) { return itk_warp_image (pb_img, vf, 1, 0.f); } void convert_vector_field ( Xform::Pointer& xf, Dij_header* dijh, Warp_parms *parms) { int i; FILE *fp_in, *fp_out; Dij_Matrix dij_matrix; Pencil_Beam pb; fp_in = fopen (parms->input_fn.c_str(), "rb"); if (!fp_in) { fprintf (stderr, "Error opening dij file for read: %s\n", parms->input_fn.c_str()); exit (-1); } fp_out = fopen (parms->output_dij_fn.c_str(), "wb"); if (!fp_out) { fprintf (stderr, "Error opening dij file for write: %s\n", parms->output_dij_fn.c_str()); exit (-1); } /* Load the header */ read_dij_header (&dij_matrix, fp_in); printf ("Found %d pencil beams\n", dij_matrix.num_pencil_beams); write_dij_header (&dij_matrix, fp_out); /* Create a new image to hold the input_image (gets re-used for each pencil beam) */ FloatImageType::Pointer pb_img = make_dose_image ( dijh, &dij_matrix); /* Resample vector field to match dose image */ printf ("Resampling vector field (please be patient)\n"); Plm_image_header pih (pb_img); Xform::Pointer xf2 = xform_to_itk_vf (xf, &pih); DeformationFieldType::Pointer vf = xf2->get_itk_vf (); /* For each pencil beam, load, warp, and write warped */ for (i = 0; i < dij_matrix.num_pencil_beams; i++) { printf ("Warping PB %03d\n", i); read_pencil_beam (&pb, fp_in); set_pencil_beam_to_image (pb_img, &pb); if (parms->output_dij_dose_volumes) { std::string fn = string_format ("PB_%03d.nrrd", i); itk_image_save (pb_img, fn); } FloatImageType::Pointer warped_pb_img = warp_pencil_beam (vf, pb_img, &dij_matrix, dijh, &pb); if (parms->output_dij_dose_volumes) { std::string fn = string_format ("PBw_%03d.nrrd", i); itk_image_save (warped_pb_img, fn); } write_pencil_beam (&pb, warped_pb_img, fp_out); free (pb.vox); } /* Done! */ fclose (fp_in); fclose (fp_out); } void warp_dij_main (Warp_parms* parms) { lprintf ("Loading xf...\n"); Xform::Pointer xf = xform_load (parms->xf_in_fn); lprintf ("Loading dif...\n"); Dij_header dijh; load_dif (&dijh, parms->dif_in_fn.c_str()); convert_vector_field (xf, &dijh, parms); } pcmd_warp_pointset.cxx000066400000000000000000000031071321604176500317350ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "itk_point.h" #include "itk_pointset.h" #include "pcmd_warp.h" #include "pointset.h" #include "warp_parms.h" #include "xform.h" void warp_pointset_main (Warp_parms* parms) { Xform xf; //FloatPointSetType::Pointer ps_in = FloatPointSetType::New (); //itk_pointset_load (ps_in, (const char*) parms->input_fn); //itk_pointset_debug (ps_in); //Raw_pointset *ps = pointset_load ((const char*) parms->input_fn); Unlabeled_pointset ps; ps.load (parms->input_fn.c_str()); xform_load (&xf, parms->xf_in_fn); //FloatPointSetType::Pointer itk_ps_in //= itk_float_pointset_from_raw_pointset (ps); FloatPointSetType::Pointer itk_ps_in = itk_float_pointset_from_pointset (&ps); //pointset_debug (ps); //printf ("---\n"); //itk_pointset_debug (itk_ps_in); //printf ("---\n"); FloatPointSetType::Pointer itk_ps_out = itk_pointset_warp (itk_ps_in, &xf); //itk_pointset_debug (itk_ps_out); if (parms->output_pointset_fn != "") { //Raw_pointset *ps_out = raw_pointset_from_itk_float_pointset (itk_ps_out); //pointset_save (ps_out, (const char*) parms->output_pointset_fn); //pointset_destroy (ps_out); Unlabeled_pointset *ps_out = unlabeled_pointset_from_itk_float_pointset (itk_ps_out); ps_out->save (parms->output_pointset_fn.c_str()); delete ps_out; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_xf_convert.cxx000066400000000000000000000226741321604176500313050ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include "bspline_xform.h" #include "dcmtk_sro.h" #include "logfile.h" #include "pcmd_xf_convert.h" #include "plm_clp.h" #include "print_and_exit.h" #include "rt_study.h" #include "rt_study_metadata.h" #include "volume_header.h" #include "xform.h" #include "xform_convert.h" class Xf_convert_parms { public: std::string input_fn; std::string output_type; std::string output_fn; std::string output_dicom_dir; std::string fixed_image; std::string moving_image; std::string fixed_rcs; std::string moving_rcs; std::string series_description; /* Geometry options */ bool m_have_dim; bool m_have_origin; bool m_have_spacing; Volume_header m_vh; bool m_have_grid_spacing; float m_grid_spacing[3]; Xform_convert xfc; public: Xf_convert_parms () { m_have_dim = false; m_have_origin = false; m_have_spacing = false; m_have_grid_spacing = false; } }; void set_output_xform_type (Xform_convert *xfc, const std::string& output_type) { if (output_type == "vf") { xfc->m_xf_out_type = XFORM_ITK_VECTOR_FIELD; } else if (output_type == "bspline") { xfc->m_xf_out_type = XFORM_GPUIT_BSPLINE; } else if (output_type == "itk_bsp" || output_type == "itk_bspline") { xfc->m_xf_out_type = XFORM_ITK_BSPLINE; } else if (output_type == "none") { xfc->m_xf_out_type = XFORM_NONE; } else { print_and_exit ("Sorry, can't convert output type\n"); } } static void do_xf_convert (Xf_convert_parms *parms) { Xform_convert *xfc = &parms->xfc; /* Set up inputs */ Xform::Pointer xf_in = xform_load (parms->input_fn); Xform::Pointer xf_out = Xform::New (); set_output_xform_type (xfc, parms->output_type); /* Set grid spacing as needed */ xf_in->get_grid_spacing (xfc->m_grid_spac); if (parms->m_have_grid_spacing) { for (int d = 0; d < 3; d++) { xfc->m_grid_spac[d] = parms->m_grid_spacing[d]; } } if (xf_in->get_type() == XFORM_GPUIT_BSPLINE) { Bspline_xform* bxf = xf_in->get_gpuit_bsp(); printf ("vox_per_rgn = %u %u %u\n", (unsigned int) bxf->vox_per_rgn[0], (unsigned int) bxf->vox_per_rgn[1], (unsigned int) bxf->vox_per_rgn[2] ); printf ("grid_spac = %g %g %g\n", bxf->grid_spac[0], bxf->grid_spac[1], bxf->grid_spac[2] ); printf ("grid_spac = %g %g %g\n", xfc->m_grid_spac[0], xfc->m_grid_spac[1], xfc->m_grid_spac[2] ); } /* Set volume header as needed */ xf_in->get_volume_header (&xfc->m_volume_header); if (parms->m_have_dim) { xfc->m_volume_header.set_dim (parms->m_vh.get_dim()); } if (parms->m_have_origin) { xfc->m_volume_header.set_origin (parms->m_vh.get_origin()); } if (parms->m_have_spacing) { xfc->m_volume_header.set_spacing (parms->m_vh.get_spacing()); } /* Do conversion */ /* GCS FIX: This is not quite right. Probably one should be allowed to run xf-convert e.g. on a B-spline, and regrid the b-spline, with the expectation that the xform type will be read from the input file. */ if (xfc->m_xf_out_type == XFORM_NONE) { /* Copy input to output */ xf_out = xf_in; } else { printf ("about to xform_convert\n"); xfc->set_input_xform (xf_in); xfc->run (); xf_out = xfc->get_output_xform (); printf ("did xform_convert\n"); } /* Save output file */ if (!parms->output_fn.empty()) { xf_out->save (parms->output_fn); } /* Save output dicom */ if (!parms->output_dicom_dir.empty()) { /* Load referenced image sets */ #if PLM_DCM_USE_DCMTK Rt_study_metadata::Pointer rtm_fixed; Rt_study_metadata::Pointer rtm_moving; /* Fixed image */ if (!parms->fixed_image.empty()) { lprintf ("Loading fixed...\n"); Rt_study::Pointer rtds = Rt_study::New (); rtds->load_image (parms->fixed_image); std::string fixed_path = parms->output_dicom_dir + "/fixed"; rtds->save_dicom (fixed_path); rtm_fixed = rtds->get_rt_study_metadata(); } else if (!parms->moving_rcs.empty()) { lprintf ("Loading fixed...\n"); rtm_fixed = Rt_study_metadata::load (parms->fixed_rcs); } /* Moving image */ if (!parms->moving_image.empty()) { lprintf ("Loading moving...\n"); Rt_study::Pointer rtds = Rt_study::New (); rtds->load_image (parms->moving_image); std::string moving_path = parms->output_dicom_dir + "/moving"; rtds->save_dicom (moving_path); rtm_moving = rtds->get_rt_study_metadata(); } else if (!parms->fixed_rcs.empty()) { lprintf ("Loading moving...\n"); rtm_moving = Rt_study_metadata::load (parms->moving_rcs); } lprintf ("Saving sro\n"); Dcmtk_sro::save ( xf_out, rtm_fixed, rtm_moving, parms->output_dicom_dir, true); lprintf ("Done saving sro\n"); #endif } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: plastimatch xf-convert [options]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Xf_convert_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Basic options */ parser->add_long_option ("", "input", "Input xform filename (required)", 1, ""); parser->add_long_option ("", "output", "Output xform filename", 1, ""); parser->add_long_option ("", "output-type", "Type of xform to create (required), choose from " "{bspline, itk_bspline, vf}", 1, "none"); parser->add_long_option ("", "output-dicom", "Directory for output of dicom spatial registration IOD", 1, ""); parser->add_long_option ("", "dim", "Size of output image in voxels \"x [y z]\"", 1, ""); parser->add_long_option ("", "origin", "Location of first image voxel in mm \"x y z\"", 1, ""); parser->add_long_option ("", "spacing", "Voxel spacing in mm \"x [y z]\"", 1, ""); parser->add_long_option ("", "grid-spacing", "B-spline grid spacing in mm \"x [y z]\"", 1, ""); parser->add_long_option ("", "nobulk", "Omit bulk transform for itk_bspline", 0); /* DICOM spatial registration */ parser->add_long_option ("", "fixed-image", "Fixed image, to be converted to dicom", 1, ""); parser->add_long_option ("", "moving-image", "Moving image, to be converted to dicom", 1, ""); parser->add_long_option ("", "fixed-rcs", "Directory containing DICOM image with reference " "coordinate system of fixed image", 1, ""); parser->add_long_option ("", "moving-rcs", "Directory containing DICOM image with reference " "coordinate system of moving image", 1, ""); parser->add_long_option ("", "series-description", "DICOM Series Description", 1, ""); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Input files */ parser->check_required ("input"); parms->input_fn = parser->get_string("input"); /* Output files */ if (parser->option ("output")) { parms->output_fn = parser->get_string("output"); } if (parser->option ("output-dicom")) { parms->output_dicom_dir = parser->get_string("output-dicom"); } if (parms->output_dicom_dir.empty() && parms->output_fn.empty()) { throw (dlib::error ("Error. You must specify either the --output " "or the --output-dicom option")); } /* DICOM spatial registration */ parms->fixed_image = parser->get_string("fixed-image"); parms->moving_image = parser->get_string("moving-image"); parms->fixed_rcs = parser->get_string("fixed-rcs"); parms->moving_rcs = parser->get_string("moving-rcs"); Xform_convert *xfc = &parms->xfc; /* Copy values into output struct */ parms->output_type = parser->get_string("output-type").c_str(); /* Geometry options */ if (parser->option ("dim")) { parms->m_have_dim = true; parser->assign_plm_long_13 (parms->m_vh.get_dim(), "dim"); } if (parser->option ("origin")) { parms->m_have_origin = true; parser->assign_float_13 (parms->m_vh.get_origin(), "origin"); } if (parser->option ("spacing")) { parms->m_have_spacing = true; parser->assign_float_13 (parms->m_vh.get_spacing(), "spacing"); } if (parser->option ("grid-spacing")) { parms->m_have_grid_spacing = true; parser->assign_float_13 (parms->m_grid_spacing, "grid-spacing"); } if (parser->option ("nobulk")) { xfc->m_nobulk = true; } } void do_command_xf_convert (int argc, char *argv[]) { Xf_convert_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 1); do_xf_convert (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_xf_convert.h000066400000000000000000000005321321604176500307170ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pcmd_xf_convert_h_ #define _pcmd_xf_convert_h_ void do_command_xf_convert (int argc, char *argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/pcmd_xio_dvh.cxx000066400000000000000000000054111321604176500305560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include #include #include #include #include "file_util.h" #define NBUF 10000 static double x[NBUF], y[NBUF], sum[NBUF]; static void usage() { printf("Usage: plastimatch xio-dvh rtog_dvh_file output_directory\n"); } void do_command_xio_dvh(int argc, char *argv[]) { FILE *fp, *fpout; int n; double s; char buf[255]; char structurename[255]; char patientid[255]; char outfilename[255]; char output_dir[255]; char input_fn[255]; int rc; if (argc!=4) { usage(); return; } strcpy(input_fn, argv[2]); strcpy(output_dir, argv[3]); fp = fopen(input_fn, "r"); if (!fp) {fprintf(stderr, "cannot open input file %s\n", input_fn); exit(1);} /* If mkdir fails, write will fail too and throw an error later on */ make_directory (output_dir); while(!feof(fp)) { fgets(buf, 200, fp); //XiO Dose Volume Histogram if (feof(fp)) break; fgets(patientid, 200, fp); // patient ID, abcde1234 fgets(buf, 200, fp); // plan fgets(structurename, 200, fp); // structure name fgets(buf, 200, fp); // N.NN mm resolution fgets(buf, 200, fp); // number of bins rc = sscanf(buf, "%d bins", &n); if (rc!=1) {fprintf(stderr, "sscanf failed, reading number of bins from %s\n", buf); exit(1);} if (n >=NBUF) {fprintf(stderr, "too many bins in file (%d), limit %d\n", n, NBUF); exit(1);} fgets(buf, 200, fp); // date fgets(buf, 200, fp); // table header: min bin dose (cGy), bin volume (cc) //remove \n after fgets patientid[strlen(patientid)-1]=0; structurename[strlen(structurename)-1]=0; // change white space and dot to underscore to avoid problems with filenames for (unsigned int i=0; i #include #include "file_util.h" #include "pcmd_add.h" #include "pcmd_adjust.h" #include "pcmd_autolabel.h" #include "pcmd_autolabel_train.h" #include "pcmd_bbox.h" #include "pcmd_benchmark.h" #include "pcmd_boundary.h" #include "pcmd_compare.h" #include "pcmd_compose.h" #include "pcmd_crop.h" #include "pcmd_dice.h" #include "pcmd_diff.h" #include "pcmd_dmap.h" #include "pcmd_dose.h" #include "pcmd_drr.h" #include "pcmd_dvh.h" #include "pcmd_filter.h" #include "pcmd_gamma.h" #include "pcmd_header.h" #include "pcmd_jacobian.h" #include "pcmd_mabs.h" #include "pcmd_mask.h" #include "pcmd_maximum.h" #include "pcmd_ml_convert.h" #include "pcmd_multiply.h" #include "pcmd_probe.h" #include "pcmd_register.h" #include "pcmd_resample.h" #include "pcmd_scale.h" //#include "pcmd_script.h" #include "pcmd_segment.h" #include "pcmd_sift.h" #include "pcmd_stats.h" #include "pcmd_synth.h" #include "pcmd_synth_vf.h" #include "pcmd_threshold.h" #include "pcmd_thumbnail.h" #include "pcmd_union.h" #include "pcmd_vf_invert.h" #include "pcmd_warp.h" #include "pcmd_xf_convert.h" #include "pcmd_xio_dvh.h" #include "plm_exception.h" #include "plm_version.h" #include "print_and_exit.h" static void print_version (void) { printf ("plastimatch version %s\n", PLASTIMATCH_VERSION_STRING); } static void print_usage (int return_code) { printf ("plastimatch version %s\n", PLASTIMATCH_VERSION_STRING); printf ( "Usage: plastimatch command [options]\n" "Commands:\n" " add " " adjust " // " autolabel " " average " " bbox " // " benchmark " " boundary " "\n" " crop " " compare " " compose " " convert " " dice " "\n" " diff " " dmap " " dose " // " drr " " dvh " " fill " "\n" " filter " " gamma " " header " " jacobian " " mabs " "\n" " mask " " maximum " " ml-convert " " multiply " " probe " "\n" " register " " resample " " scale " " segment " // " sift " " stats " "\n" " synth " " synth-vf " " threshold " " thumbnail " " union " "\n" " vf-invert " " warp " // " xio-dvh " " xf-convert " "\n" "\n" "For detailed usage of a specific command, type:\n" " plastimatch command\n" ); exit (return_code); } void do_command (int argc, char* argv[]) { char* command; if (argc == 1) { print_usage (0); } command = argv[1]; if (!strcmp (command, "--version")) { print_version (); } else if (!strcmp (command, "add")) { /* add and average are the same */ do_command_add (argc, argv); } else if (!strcmp (command, "adjust")) { do_command_adjust (argc, argv); } else if (!strcmp (command, "average")) { /* add and average are the same */ do_command_add (argc, argv); } else if (!strcmp (command, "autolabel")) { do_command_autolabel (argc, argv); } else if (!strcmp (command, "autolabel-train")) { do_command_autolabel_train (argc, argv); } else if (!strcmp (command, "bbox")) { do_command_bbox (argc, argv); } else if (!strcmp (command, "benchmark")) { do_command_benchmark (argc, argv); } else if (!strcmp (command, "boundary")) { do_command_boundary (argc, argv); } else if (!strcmp (command, "compare")) { do_command_compare (argc, argv); } else if (!strcmp (command, "compose")) { do_command_compose (argc, argv); } else if (!strcmp (command, "convert")) { /* convert and warp are the same */ do_command_warp (argc, argv); } else if (!strcmp (command, "crop")) { do_command_crop (argc, argv); } else if (!strcmp (command, "dice")) { do_command_dice (argc, argv); } else if (!strcmp (command, "diff")) { do_command_diff (argc, argv); } else if (!strcmp (command, "dose")) { do_command_dose (argc, argv); } else if (!strcmp (command, "drr")) { do_command_drr (argc, argv); } else if (!strcmp (command, "dmap")) { do_command_dmap (argc, argv); } else if (!strcmp (command, "dvh")) { do_command_dvh (argc, argv); } else if (!strcmp (command, "fill")) { /* fill and mask are the same */ do_command_mask (argc, argv); } else if (!strcmp (command, "filter")) { do_command_filter (argc, argv); } else if (!strcmp (command, "gamma")) { do_command_gamma (argc, argv); } else if (!strcmp (command, "header")) { do_command_header (argc, argv); } else if (!strcmp (command, "jacobian")) { do_command_jacobian (argc, argv); } else if (!strcmp (command, "mabs")) { do_command_mabs (argc, argv); } else if (!strcmp (command, "mask")) { /* fill and mask are the same */ do_command_mask (argc, argv); } else if (!strcmp (command, "maximum")) { do_command_maximum (argc, argv); } else if (!strcmp (command, "ml-convert")) { do_command_ml_convert (argc, argv); } else if (!strcmp (command, "multiply")) { do_command_multiply (argc, argv); } else if (!strcmp (command, "probe")) { do_command_probe (argc, argv); } else if (!strcmp (command, "register")) { do_command_register (argc, argv); } else if (!strcmp (command, "resample")) { do_command_resample (argc, argv); } else if (!strcmp (command, "scale")) { do_command_scale (argc, argv); } #if defined (commentout) else if (!strcmp (command, "script")) { do_command_script (argc, argv); } #endif else if (!strcmp (command, "segment")) { do_command_segment (argc, argv); } else if (!strcmp (command, "sift")) { do_command_sift (argc, argv); } else if (!strcmp (command, "slice")) { print_and_exit ("Error: slice command is now called thumbnail.\n"); } else if (!strcmp (command, "stats")) { do_command_stats (argc, argv); } else if (!strcmp (command, "synth")) { do_command_synth (argc, argv); } else if (!strcmp (command, "synth-vf")) { do_command_synth_vf (argc, argv); } else if (!strcmp (command, "threshold")) { do_command_threshold (argc, argv); } else if (!strcmp (command, "thumbnail")) { do_command_thumbnail (argc, argv); } else if (!strcmp (command, "union")) { do_command_union (argc, argv); } else if (!strcmp (command, "vf-invert")) { do_command_vf_invert (argc, argv); } else if (!strcmp (command, "warp")) { /* convert and warp are the same */ do_command_warp (argc, argv); } else if (!strcmp (command, "xf-convert")) { do_command_xf_convert (argc, argv); } else if (!strcmp (command, "xio-dvh")) { do_command_xio_dvh (argc, argv); } else if (argc == 2) { if (!file_exists (argv[1])) { print_usage (1); } /* Older usage, just "plastimatch parms.txt" */ do_command_register (argc, argv); } else { print_usage (1); } } int main (int argc, char *argv[]) { try { do_command (argc, argv); } catch (const Plm_exception& pe) { //fprintf (stderr, "%s", pe.what()); return 1; } return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cli/plmcli_config.h.in000066400000000000000000000004761321604176500307600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plmcli_config_h__ #define __plmcli_config_h__ #include "plm_config.h" #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/clp/000077500000000000000000000000001321604176500253755ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/clp/CMakeLists.txt000066400000000000000000000015251321604176500301400ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_clp) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (PLMCLP_LIBRARY_SRC plm_clp.cxx plm_clp.h ) ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- #plm_add_library ( # plmclp # "${PLMCLP_LIBRARY_SRC}" # "" # "") add_library (plmclp STATIC ${PLMCLP_LIBRARY_SRC}) plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/clp/plm_clp.cxx000066400000000000000000000164151321604176500275560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmcli_config.h" #include "plm_clp.h" namespace dlib { void Plm_clp::add_default_options (void) { this->add_long_option ("h", "help", "display this help message"); this->add_long_option ("", "version", "display the program version"); } void Plm_clp::check_default_options (void) { /* Check if the -h option was given */ if (this->option("h") || this->option("help")) { if (this->number_of_arguments()) { /* Secret option. If you use "--help something", then you get a help with narrower format, which can be pasted into sphinx documentation. */ this->wrap_len = 73; usage_fn (this, argc, argv); } else { usage_fn (this, argc, argv); } exit (0); } if (this->option("version")) { std::cout << "Plastimatch version " << PLASTIMATCH_VERSION_STRING << std::endl; exit (0); } } void Plm_clp::add_long_option ( const string_type& short_name, const string_type& long_name, const string_type& description, unsigned long number_of_arguments, const string_type& default_value) { if (short_name == "" && long_name == "") return; std::string key; std::string option_val; std::string description_val; if (long_name == "") { /* Only short */ key = short_name; option_val = " -" + short_name; this->add_option_with_default (short_name, description, number_of_arguments, default_value); } else if (short_name == "") { /* Only long */ key = long_name; option_val = " --" + long_name; this->add_option_with_default (long_name, description, number_of_arguments, default_value); } else { /* Both long and short */ key = long_name; option_val = " -" + short_name + ", --" + long_name; this->add_option_with_default (short_name, description, number_of_arguments, ""); this->add_option_with_default (long_name, description, number_of_arguments, default_value); this->long_to_short_map.insert ( std::pair (long_name, short_name)); this->short_to_long_map.insert ( std::pair (short_name, long_name)); } option_map.insert ( std::pair (key, option_val)); description_map.insert ( std::pair (key, description)); } void Plm_clp::assign_int13 (int *arr, const string_type& name) { int rc; rc = sscanf (get_string(name).c_str(), "%d %d %d", &arr[0], &arr[1], &arr[2]); if (rc == 1) { arr[1] = arr[2] = arr[0]; } else if (rc != 3) { string_type error_string = "Error. Option " + get_option_string (name) + " takes one or three integer arguments."; throw dlib::error (error_string); } } void Plm_clp::assign_int_2 ( int *arr, const string_type& name) { int rc; int a, b; rc = sscanf (get_string(name).c_str(), "%d %d", &a, &b); if (rc == 2) { arr[0] = a; arr[1] = b; } else { string_type error_string = "Error. Option " + get_option_string (name) + " takes two integer arguments."; throw dlib::error (error_string); } } void Plm_clp::assign_int_6 ( int *arr, const string_type& name) { int rc; int a, b, c, d, e, f; rc = sscanf (get_string(name).c_str(), "%d %d %d %d %d %d", &a, &b, &c, &d, &e, &f); if (rc == 6) { arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; } else { string_type error_string = "Error. Option " + get_option_string (name) + " takes six integer arguments."; throw dlib::error (error_string); } } void Plm_clp::assign_plm_long_13 ( plm_long *arr, const string_type& name) { int rc; unsigned int a, b, c; rc = sscanf (get_string(name).c_str(), "%d %d %d", &a, &b, &c); if (rc == 1) { arr[0] = a; arr[1] = a; arr[2] = a; } else if (rc == 3) { arr[0] = a; arr[1] = b; arr[2] = c; } else { string_type error_string = "Error. Option " + get_option_string (name) + " takes one or three integer arguments."; throw dlib::error (error_string); } } void Plm_clp::assign_plm_long_6 ( plm_long *arr, const string_type& name) { int rc; int a, b, c, d, e, f; rc = sscanf (get_string(name).c_str(), "%d %d %d %d %d %d", &a, &b, &c, &d, &e, &f); if (rc == 6) { arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; } else { string_type error_string = "Error. Option " + get_option_string (name) + " takes six integer arguments."; throw dlib::error (error_string); } } void Plm_clp::assign_float_13 (float *arr, const string_type& name) { float rc; rc = sscanf (get_string(name).c_str(), "%g %g %g", &arr[0], &arr[1], &arr[2]); if (rc == 1) { arr[1] = arr[2] = arr[0]; } else if (rc != 3) { string_type error_string = "Error. Option " + get_option_string (name) + " takes one or three float arguments."; throw dlib::error (error_string); } } void Plm_clp::assign_float_2 (float *arr, const string_type& name) { float rc; rc = sscanf (get_string(name).c_str(), "%g %g", &arr[0], &arr[1]); if (rc != 2) { string_type error_string = "Error. Option " + get_option_string (name) + " takes two float arguments."; throw dlib::error (error_string); } } void Plm_clp::assign_float_9 (float *arr, const string_type& name) { float rc; rc = sscanf (get_string(name).c_str(), "%g %g %g %g %g %g %g %g %g", &arr[0], &arr[1], &arr[2], &arr[3], &arr[4], &arr[5], &arr[6], &arr[7], &arr[8]); if (rc != 9) { string_type error_string = "Error. Option " + get_option_string (name) + " takes nine float arguments."; throw dlib::error (error_string); } } void Plm_clp::assign_float_vec ( std::vector* float_vec, const string_type& name) { std::istringstream str (get_string (name)); str.exceptions(std::ios::badbit | std::ios::failbit); try { float fv; while (str >> fv) { float_vec->push_back(fv); } } catch (std::ios_base::failure e) { if (str.fail() && !str.eof()) { string_type error_string = "Error parsing option " + get_option_string (name) + ", it contains non-float values."; throw dlib::error (error_string); } } } } /* end namespace */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/clp/plm_clp.h000066400000000000000000000276051321604176500272060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- This file is derived from dlib source code, http://dlib.net, and is licensed under the "Boost Software License - Version 1.0". Modifications by Greg Sharp ----------------------------------------------------------------------- */ #ifndef _plm_dlib_clp_h_ #define _plm_dlib_clp_h_ #include "plmcli_config.h" #include #include #include #include #include #include "dlib/cmd_line_parser.h" #include "sys/plm_int.h" #include "plm_version.h" typedef dlib::cmd_line_parser::check_1a_c Clp; namespace dlib { class Plm_clp : public cmd_line_parser::check_1a_c { public: std::map default_value_map; std::map option_map; std::map description_map; std::map short_to_long_map; std::map long_to_short_map; void (*usage_fn) (dlib::Plm_clp*,int,char*[]); int argc; char **argv; unsigned long wrap_len; public: void add_default_options (void); void check_default_options (void); void add_long_option ( const string_type& short_name, const string_type& long_name, const string_type& description, unsigned long number_of_arguments = 0, const string_type& default_value = "" ); const string_type& long_option_name (const string_type& name) { std::map::iterator it; it = this->short_to_long_map.find (name); if (it != this->short_to_long_map.end()) { return it->second; } else { return name; } } const string_type& short_option_name (const string_type& name) { std::map::iterator it; it = this->long_to_short_map.find (name); if (it != this->long_to_short_map.end()) { return it->second; } else { return name; } } void add_option_with_default ( const string_type& name, const string_type& description, unsigned long number_of_arguments = 0, const string_type& default_value = "" ) { this->add_option (name, description, number_of_arguments); if (default_value != "") { default_value_map.insert ( std::pair (name, default_value)); } } bool have_option (const string_type& name) { if (option (long_option_name (name))) { return true; } if (option (short_option_name (name))) { return true; } return false; } /* Get command line arg specified with either long or short option */ string_type get_value_base (const string_type& name) { /* Option specified as long name */ const string_type& long_name = long_option_name (name); if (option (long_name)) { return this->option(long_name).argument(); } /* Option specified as short name */ const string_type& short_name = short_option_name (name); if (option (short_name)) { return this->option(short_name).argument(); } /* Not specified on command line */ return ""; } /* Get string value from either long or short option, filling in default value if no option specified */ string_type get_value ( const string_type& name ) { /* Option specified on command line */ if (this->have_option(name)) { return this->get_value_base (name); } /* Default value */ const string_type& long_name = long_option_name (name); std::map::iterator it; it = this->default_value_map.find (long_name); if (it != this->default_value_map.end()) { return it->second; } /* Not specified on command line, and no default value */ return ""; } /* Get non-string value, either long or short option, filling in default value if no option specified */ template void get_value ( T& dest, const string_type& name ) { try { dest = dlib::sa = this->get_value (name); } catch (...) { string_type error_string = "Error. Option " + get_option_string (name) + " had an illegal or missing argument."; throw dlib::error (error_string); } } /* Shorthand functions for specific well-known types */ void assign_int13 (int *arr, const string_type& name); void assign_int_2 (int *arr, const string_type& name); void assign_int_6 (int *arr, const string_type& name); void assign_plm_long_13 (plm_long *arr, const string_type& name); void assign_plm_long_6 (plm_long *arr, const string_type& name); void assign_float_13 (float *arr, const string_type& name); void assign_float_2 (float *arr, const string_type& name); void assign_float_9 (float *arr, const string_type& name); void assign_float_vec ( std::vector* float_vec, const string_type& name); int get_int (const string_type& name) { int out; get_value (out, name); return out; } float get_float (const string_type& name) { float out; get_value (out, name); return out; } std::string get_string (const string_type& name) { return get_value (name); } void print_options ( std::basic_ostream& out ) { typedef char ct; typedef std::basic_string string; typedef string::size_type size_type; try { out << _dT(ct,"Options:"); // this loop here is just the bottom loop but without the print // statements. I'm doing this to figure out what len should be. size_type max_len = 0; this->reset(); while (this->move_next()) { /* Skip past options which aren't in the map */ const std::string name = this->element().name(); std::map::iterator it; it = this->option_map.find (name); if (it == this->option_map.end()) { continue; } size_type len = 0; len = it->second.size(); if (this->element().number_of_arguments() == 1) { len += 6; } else { for (unsigned long i = 0; i < this->element().number_of_arguments(); ++i) { len += 7; if (i+1 > 9) ++len; } } len += 3; if (len < 33) max_len = std::max(max_len,len); } this->reset(); while (this->move_next()) { /* Skip past options which aren't in the map */ const std::string name = this->element().name(); std::map::iterator it; it = this->option_map.find (name); if (it == this->option_map.end()) { continue; } size_type len = 0; out << _dT(ct,"\n"); out << it->second; len = it->second.size(); if (this->element().number_of_arguments() == 1) { out << _dT(ct," "); len += 6; } else { for (unsigned long i = 0; i < this->element().number_of_arguments(); ++i) { out << _dT(ct," "); len += 7; if (i+1 > 9) ++len; } } out << " "; len += 3; while (len < max_len) { ++len; out << " "; } const unsigned long ml = static_cast(max_len); // now print the description but make it wrap around // nicely if it is to long to fit on one line. if (len <= max_len) out << wrap_string(this->element().description(), 0, ml+1, wrap_len); else out << "\n" << wrap_string(this->element().description(), ml, ml+1, wrap_len); } this->reset(); } catch (...) { this->reset(); throw; } } void check_help (void) { if (this->option("h") || this->option("help")) { usage_fn (this, argc, argv); exit (0); } } string_type get_option_string (const string_type& name) { if (name.length() == 1) { return "-" + name; } else { return "--" + name; } } void check_required (const string_type& name) { if (!this->have_option(name)) { string_type error_string = "Error, you must specify the " + get_option_string(name) + " option.\n"; throw dlib::error (error_string); } } /* Throws an exception if none of the arguments are specified on the command line. The last argument should be zero, to satisfy variable argument list macros. */ void check_required_any (const char* first_opt, ...) { int option_exists = 0; va_list argptr; const char *opt; va_start (argptr, first_opt); opt = first_opt; do { if (this->option(opt)) { option_exists = 1; break; } } while ((opt = va_arg(argptr, char*))); va_end (argptr); if (!option_exists) { string_type error_string = "Error, you must specify one of the following options: "; va_start (argptr, first_opt); opt = first_opt; do { if (opt != first_opt) { error_string += ", "; } error_string += get_option_string(opt); } while ((opt = va_arg(argptr, char*))); va_end (argptr); error_string += ".\n"; throw dlib::error (error_string); } } }; /* end class */ } /* end namespace */ /* This is a helper function designed to remove clutter caused by exception catching broilerplate. The optional swallow argument deletes the leading arguments, for ease of use by the plastimatch program. For example if you set swallow = 1, then the following command: plastimatch autolabel [options] gets parsed as if it were the following: autolabel [options] */ template static void plm_clp_parse ( T arg, void (*parse_fn) (T,dlib::Plm_clp*,int,char*[]), void (*usage_fn) (dlib::Plm_clp*,int,char*[]), int argc, char* argv[], int swallow = 0) { dlib::Plm_clp parser; parser.usage_fn = usage_fn; parser.argc = argc; parser.argv = argv; parser.wrap_len = 79; try { (*parse_fn) (arg, &parser, argc - swallow, argv + swallow); } catch (std::exception& e) { /* Catch cmd_line_parse_error exceptions and print usage message. */ std::cout << e.what() << std::endl; (*usage_fn) (&parser, argc, argv); exit (1); } catch (...) { std::cerr << "An unspecified error occurred.\n"; exit (1); } } #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cmake/000077500000000000000000000000001321604176500256775ustar00rootroot00000000000000PlastimatchBuildTreeSettings.cmake.in000077500000000000000000000032411321604176500350240ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cmakeset (PLM_CONFIG_LIBRARY_BUILD "@PLM_CONFIG_LIBRARY_BUILD@") set (PLMLIB_CONFIG_ENABLE_CLI "@PLMLIB_CONFIG_ENABLE_CLI@") set (PLMLIB_CONFIG_ENABLE_CUDA "@PLMLIB_CONFIG_ENABLE_CUDA@") set (PLMLIB_CONFIG_ENABLE_DOSE "@PLMLIB_CONFIG_ENABLE_DOSE@") set (PLMLIB_CONFIG_ENABLE_OPENCL "@PLMLIB_CONFIG_ENABLE_OPENCL@") set (PLMLIB_CONFIG_ENABLE_QT "@PLMLIB_CONFIG_ENABLE_QT@") set (PLMLIB_CONFIG_ENABLE_RECONSTRUCT "@PLMLIB_CONFIG_ENABLE_RECONSTRUCT@") set (PLMLIB_CONFIG_ENABLE_REGISTER "@PLMLIB_CONFIG_ENABLE_REGISTER@") set (PLMLIB_CONFIG_ENABLE_SCRIPT "@PLMLIB_CONFIG_ENABLE_SCRIPT@") set (PLMLIB_CONFIG_ENABLE_SEGMENT "@PLMLIB_CONFIG_ENABLE_SEGMENT@") set (PLMLIB_CONFIG_ENABLE_STANDALONE "@PLMLIB_CONFIG_ENABLE_STANDALONE@") set (PLMLIB_CONFIG_ENABLE_TEST "@PLMLIB_CONFIG_ENABLE_TEST@") set (PLASTIMATCH_INCLUDE_DIRS "@CMAKE_SOURCE_DIR@/src/plastimatch" "@CMAKE_SOURCE_DIR@/src/plastimatch/sys" "@CMAKE_SOURCE_DIR@/src/plastimatch/base" "@CMAKE_SOURCE_DIR@/src/plastimatch/util" "@CMAKE_SOURCE_DIR@/libs" "@CMAKE_SOURCE_DIR@/libs/devillard" "@DLIB_INCLUDE_DIR@" "@CMAKE_SOURCE_DIR@/libs/dlib-18.7" "@CMAKE_BINARY_DIR@") if (PLMLIB_CONFIG_ENABLE_DOSE) set (PLASTIMATCH_INCLUDE_DIRS ${PLASTIMATCH_INCLUDE_DIRS} "@CMAKE_SOURCE_DIR@/src/plastimatch/dose") endif () if (PLMLIB_CONFIG_ENABLE_REGISTER) set (PLASTIMATCH_INCLUDE_DIRS ${PLASTIMATCH_INCLUDE_DIRS} "@CMAKE_SOURCE_DIR@/src/plastimatch/register" "@CMAKE_SOURCE_DIR@/libs/liblbfgs-1.9/include") endif () if (PLMLIB_CONFIG_ENABLE_SEGMENT) set (PLASTIMATCH_INCLUDE_DIRS ${PLASTIMATCH_INCLUDE_DIRS} "@CMAKE_SOURCE_DIR@/src/plastimatch/segment") endif () set (PLASTIMATCH_ITK_DIR "@ITK_DIR@") PlastimatchConfig-Legacy.cmake.in000077500000000000000000000020701321604176500340320ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cmake##----------------------------------------------------------------------------- ## PlastimatchConfig.cmake - configuration file for external projects ##----------------------------------------------------------------------------- ## See: ## http://www.vtk.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file get_filename_component (PLASTIMATCH_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) if (EXISTS "${PLASTIMATCH_CMAKE_DIR}/CMakeCache.txt") # In build tree include("${PLASTIMATCH_CMAKE_DIR}/PlastimatchBuildTreeSettings.cmake") else() # In install tree set (PLASTIMATCH_INCLUDE_DIRS "${PLASTIMATCH_CMAKE_DIR}/@CONF_REL_INCLUDE_DIR@") endif() # Our library dependencies (contains definitions for IMPORTED targets) include("${PLASTIMATCH_CMAKE_DIR}/PlastimatchLibraryDepends.cmake") # These are IMPORTED targets created by PlastimatchDepends.cmake set (PLASTIMATCH_LIBRARIES @EXPORT_TARGET_LIST@) # You need to set these to link with a plastimatch static library set (PLASTIMATCH_LDFLAGS "@PLASTIMATCH_LDFLAGS@") set (PLASTIMATCH_FOUND ON) PlastimatchConfig.cmake.in000077500000000000000000000013001321604176500326230ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cmake##----------------------------------------------------------------------------- ## PlastimatchConfig.cmake - configuration file for external projects ##----------------------------------------------------------------------------- # Our library dependencies (contains definitions for IMPORTED targets) include("${CMAKE_CURRENT_LIST_DIR}/PlastimatchLibraryDepends.cmake") # These are IMPORTED targets created by PlastimatchDepends.cmake set (PLASTIMATCH_LIBRARIES @EXPORT_TARGET_LIST@) set (Plastimatch_LIBRARIES @EXPORT_TARGET_LIST@) # You need to set these to link with a plastimatch static library set (PLASTIMATCH_LDFLAGS "@PLASTIMATCH_LDFLAGS@") set (Plastimatch_LDFLAGS "@PLASTIMATCH_LDFLAGS@") plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/000077500000000000000000000000001321604176500255335ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/CMakeLists.txt000066400000000000000000000041561321604176500303010ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_cuda) set_directory_properties (PROPERTIES INCLUDE_DIRECTORIES "") set_directory_properties (PROPERTIES COMPILE_DEFINITIONS "") include_directories (BEFORE ${CMAKE_BINARY_DIR}) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/base) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/cuda) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/register) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/sys) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/util) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (AFTER ${MSINTTYPES_INCLUDE_DIR}) ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (PLMCUDA_LIBRARY_SRC cuda_kernel_util.cu cuda_mem.cu cuda_probe.cu cuda_util.cu ) ##----------------------------------------------------------------------------- ## LIBRARY DEPENDENCIES ##----------------------------------------------------------------------------- set (PLMCUDA_LIBRARY_DEPENDENCIES plmsys ${CUDA_LIBRARIES} ) ##----------------------------------------------------------------------------- ## SPECIAL BUILD RULES: CUDA ##----------------------------------------------------------------------------- if (CUDA_FOUND) if (PLM_USE_GPU_PLUGINS) plm_add_gpu_plugin_library (plmcuda "${PLMCUDA_LIBRARY_SRC}") target_link_libraries (plmcuda ${PLMCUDA_LIBRARY_DEPENDENCIES} ) else () cuda_compile (CUDA_WRAPPERS ${PLMCUDA_LIBRARY_SRC}) set (PLMCUDA_LIBRARY_SRC ${PLMCUDA_LIBRARY_SRC} ${CUDA_WRAPPERS} ) plm_add_library ( plmcuda "${PLMCUDA_LIBRARY_SRC}" "${PLMCUDA_LIBRARY_DEPENDENCIES}" "" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "") endif () endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/cuda_kernel_util.cu000066400000000000000000000136301321604176500314000ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "cuda_kernel_util.h" #include "cuda_util.h" // NOTE: Helper functions in this file accept parameters that use CUDA specific // types (dim3, float4, etc). As a result, these helper functions can // only be called from within other CUDA files (.cu) // // The file 'cuda_util.cu' provides utility functions that do not use CUDA // specific types as parameters; and can, therefore, be used from // standard C or C++ files. // // __device__ functions cannot be placed in here due to nvcc limitations. // Please place __device__ functions in cuda_kernel_util.inc void CUDA_array2vec_int3 ( int3* vec, plm_long* array ) { vec->x = array[0]; vec->y = array[1]; vec->z = array[2]; } void CUDA_array2vec_float3 ( float3* vec, float* array ) { vec->x = array[0]; vec->y = array[1]; vec->z = array[2]; } // Builds execution configurations for kernels that // assign one thread per element (1tpe). int CUDA_exec_conf_1tpe ( dim3 *dimGrid, // OUTPUT: Grid dimensions dim3 *dimBlock, // OUTPUT: Block dimensions int num_threads, // INPUT: Total # of threads int threads_per_block, // INPUT: Threads per block bool negotiate // INPUT: Is threads per block negotiable? ) { int i; int Grid_x = 0; int Grid_y = 0; int sqrt_num_blocks; int num_blocks = (num_threads + threads_per_block - 1) / threads_per_block; if (negotiate) { int found_flag = 0; int j = 0; // Search for a valid execution configuration for the required # of blocks. // Block size has been specified as changable. This helps if the // number of blocks required is a prime number > 65535. Changing the // # of threads per block will change the # of blocks... which hopefully // won't be prime again. for (j = threads_per_block; j > 32; j -= 32) { num_blocks = (num_threads + j - 1) / j; sqrt_num_blocks = (int)sqrt((float)num_blocks); for (i = sqrt_num_blocks; i < GRID_LIMIT_X; i++) { if (num_blocks % i == 0) { Grid_x = i; Grid_y = num_blocks / Grid_x; found_flag = 1; break; } } if (found_flag == 1) { threads_per_block = j; break; } } } else { // Search for a valid execution configuration for the required # of blocks. // The calling algorithm has specifed that # of threads per block // is non negotiable. sqrt_num_blocks = (int)sqrt((float)num_blocks); for (i = sqrt_num_blocks; i < GRID_LIMIT_X; i++) { if (num_blocks % i == 0) { Grid_x = i; Grid_y = num_blocks / Grid_x; break; } } } // Were we able to find a valid exec config? if (Grid_x == 0) { printf ("\n"); printf ("[GPU KERNEL PANIC] Unable to find suitable execution configuration!"); printf ("Terminating...\n"); exit (0); } else { // callback function could be added // to arguments and called here if you need // to do something fancy upon success. #if VERBOSE printf ("Grid [%i,%i], %d threads_per_block.\n", Grid_x, Grid_y, threads_per_block); #endif } // Pass configuration back by reference dimGrid->x = Grid_x; dimGrid->y = Grid_y; dimGrid->z = 1; dimBlock->x = threads_per_block; dimBlock->y = 1; dimBlock->z = 1; // Return the # of blocks we decided on just // in case we need it later to allocate shared memory, etc. return num_blocks; } // Builds execution configurations for kernels that // assign one block per element (1bpe). void CUDA_exec_conf_1bpe ( dim3 *dimGrid, // OUTPUT: Grid dimensions dim3 *dimBlock, // OUTPUT: Block dimensions int num_blocks, // INPUT: Number of blocks int threads_per_block) // INPUT: Threads per block { int i; int Grid_x = 0; int Grid_y = 0; // Search for a valid execution configuration for the required # of blocks. int sqrt_num_blocks = (int)sqrt((float)num_blocks); for (i = sqrt_num_blocks; i < 65535; i++) { if (num_blocks % i == 0) { Grid_x = i; Grid_y = num_blocks / Grid_x; break; } } // Were we able to find a valid exec config? if (Grid_x == 0) { printf ("\n"); printf ("[GPU KERNEL PANIC] Unable to find suitable execution configuration!"); printf ("Terminating...\n"); exit (0); } else { // callback function could be added // to arguments and called here if you need // to do something fancy upon success. #if VERBOSE printf ("Grid [%i,%i], %d threads_per_block.\n", Grid_x, Grid_y, threads_per_block); #endif } // Pass configuration back by reference dimGrid->x = Grid_x; dimGrid->y = Grid_y; dimGrid->z = 1; dimBlock->x = threads_per_block; dimBlock->y = 1; dimBlock->z = 1; } void CUDA_timer_start (cuda_timer *timer) { cudaEventCreate (&timer->start); cudaEventCreate (&timer->stop); cudaEventRecord (timer->start, 0); } // Returns time in milliseconds float CUDA_timer_report (cuda_timer *timer) { float time; cudaEventRecord (timer->stop, 0); cudaEventSynchronize (timer->stop); cudaEventElapsedTime (&time, timer->start, timer->stop); cudaEventDestroy (timer->start); cudaEventDestroy (timer->stop); return time; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/cuda_kernel_util.h000066400000000000000000000052031321604176500312150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _cuda_kernel_util_h_ #define _cuda_kernel_util_h_ // // NOTE: Cannot be included in C or C++ files due to // special CUDA types such as int4, dim3, etc. // Can only be included in CUDA files. // // NOTE: __device__ function definitions live in // cuda_kernel_util.inc due to nvcc limitations. #include "plm_config.h" #include #include "plm_int.h" #define GRID_LIMIT_X 65535 #define GRID_LIMIT_Y 65535 // JAS 2010.12.09 // Frequently used thread based indexing methods // My attempt at standardizing CUDA threading across plastimatch (pls use these!) #define block_size (blockDim.x * blockDim.y * blockDim.z) #define block_idx ((gridDim.x * blockIdx.y) + blockIdx.x) #define thread_idx_local ((((blockDim.y * threadIdx.z) + threadIdx.y) * blockDim.x) + threadIdx.x) #define thread_idx_global ((block_idx * block_size) + thread_idx_local) typedef struct cuda_timer_struct cuda_timer; struct cuda_timer_struct { cudaEvent_t start; cudaEvent_t stop; }; template __device__ inline void shared_memset (T* s, T c, int n); __device__ inline void atomic_add_float ( float* addr, float val ); template __device__ inline void stog_memcpy ( T* global, T* shared, int set_size ); #if defined __cplusplus extern "C" { #endif plmcuda_EXPORT ( void CUDA_array2vec_int3, int3* vec, plm_long* array ); plmcuda_EXPORT ( void CUDA_array2vec_float3, float3* vec, float* array ); plmcuda_EXPORT ( int CUDA_exec_conf_1tpe, dim3 *dimGrid, /* OUTPUT: Grid dimensions */ dim3 *dimBlock, /* OUTPUT: Block dimensions */ int num_threads, /* INPUT: Total # of threads */ int threads_per_block, /* INPUT: Threads per block */ bool negotiate /* INPUT: Is threads per block negotiable? */ ); plmcuda_EXPORT ( void CUDA_exec_conf_1bpe, dim3 *dimGrid, /* OUTPUT: Grid dimensions */ dim3 *dimBlock, /* OUTPUT: Block dimensions */ int num_blocks, /* INPUT: Number of blocks */ int threads_per_block /* INPUT: Threads per block */ ); plmcuda_EXPORT ( void CUDA_timer_start, cuda_timer *timer ); plmcuda_EXPORT ( float CUDA_timer_report, cuda_timer *timer ); #if defined __cplusplus } #endif #endif cuda_kernel_util.inc000066400000000000000000000054601321604176500314650ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ // JAS 2010.11.04 // nvcc has the nasty limitation of not being able to // use functions from other object files. So in order // to share __device__ functions amongst multiple .cu // files, we resort to writing them in this somewhat // kludgy "inc" file. // Add the line: // #include "cuda_kernel_util.inc" // // to the bottom of your CUDA .cu file to use these // helper __device__ functions. // ---------------------- // Note: n is the # of elements (NOT size_t) template __device__ inline void shared_memset ( T* s, T c, int n ) { int b = (n + block_size - 1) / block_size; for (int i=0; i= 120 __device__ inline void atomic_add_float ( float* addr, float val ) { #if __CUDA_ARCH__ >= 200 atomicAdd (addr, val); #elif __CUDA_ARCH__ >= 110 && __CUDA_ARCH__ < 200 float old; bool success = false; while (!success) { old = atomicExch(addr, -1.0f); if (old != -1.0f) { success = true; old += val; atomicExch(addr, old); } __threadfence(); } #else /* cannot be done on old CUDA devices * this is just here to make the compiler happy */ ; #endif } // JAS 2010.11.13 // This is a useful function for copying the contents of shared memory to // global memory. This sort of thing is incredibly useful because you can // organize your output within shared memory (which has no coalescence // requirements) and then copy the ordered output to global memory as a // series of blocks. The global memory output will be the contents of each // thread block's shared memory -- one after another. template __device__ inline void stog_memcpy ( T* global, T* shared, int set_size ) { int idx; int chunks = (set_size + block_size - 1) / block_size; int offset = set_size * block_idx; for (int i=0; i #include #include "cuda_mem.h" #include "cuda_util.h" void CUDA_alloc_copy ( void** gpu_addr, void** cpu_addr, size_t mem_size ) { // Allcoated some global memory on the GPU cudaMalloc ((void**)gpu_addr, mem_size); CUDA_check_error ("Out of GPU memory."); // Populate the allocated global GPU memory cudaMemcpy (*gpu_addr, *cpu_addr, mem_size, cudaMemcpyHostToDevice); CUDA_check_error ("Failed to copy data to GPU"); } // If you plan on using CUDA_alloc_vmem() to extend // the GPU memory, then you must first call this. void CUDA_init_vmem (Vmem_Entry** head) { *head = NULL; } // This function should only be used to supplement the GPU's // available "Global Memory" with pinned CPU memory. Currently, // the GPU address bus is 32-bit, so using this function we are // only able to supplement the GPU global memory *up to* 4GB. // Cards already equiped with 4GB of global memory have a full // memory map and can therefore be extended no further! void CUDA_alloc_vmem ( void** gpu_addr, size_t mem_size, Vmem_Entry** head ) { void* pinned_host_mem; Vmem_Entry* new_entry; // Allocate some pinned CPU memory for zero paging cudaHostAlloc ((void **)&pinned_host_mem, mem_size, cudaHostAllocMapped); CUDA_check_error ("Failed to allocate pinned memory."); // Clear out new pinned CPU memory memset (pinned_host_mem, 0, mem_size); // Get the address of the pinned page in the GPU memory map. cudaHostGetDevicePointer ((void **)gpu_addr, (void *)pinned_host_mem, 0); CUDA_check_error ("Failed to map CPU memory to GPU."); // Now we will register this allocation with my gpu "virtual memory" // system. CUDA requires that we free pinned CPU memory with the CPU // pointer; NOT the GPU pointer. This can be troublesome if you are only // tracking GPU pointers and have no need to access the CPU side memory // with the CPU. So, every time we pin CPU memory, we register the pair of // pointers (CPU & GPU) in a linked list. This allows us to only track // track one and look up the other. It also allows us to free all pinned // memory without knowing the pointers by simply cycling through the linked // list and freeing everything. // create a new vmem entry new_entry = (Vmem_Entry*) malloc (sizeof(Vmem_Entry)); // initialize the new entry new_entry->gpu_pointer = *gpu_addr; new_entry->cpu_pointer = pinned_host_mem; new_entry->size = mem_size; // insert new entry @ the head new_entry->next = *head; *head = new_entry; } // Returns the total amount of "virtual global" // (i.e. pinned CPU) memory. Perhaps useful. size_t CUDA_tally_vmem (Vmem_Entry** head) { size_t total_vmem = 0; Vmem_Entry* curr = *head; while (curr != NULL) { total_vmem += curr->size; curr = curr->next; } return total_vmem; } // For debugging. Just prints out the virtual // memory pointer association list. void CUDA_print_vmem (Vmem_Entry** head) { int i = 0; Vmem_Entry* curr = *head; while (curr != NULL) { printf ("Entry #%i:\n", i); printf (" gpu_pointer: %p\n", curr->gpu_pointer); printf (" cpu_pointer: %p\n\n", curr->cpu_pointer); curr = curr->next; i++; } } // Free GPU "virtual memory" via GPU mapped address. int CUDA_free_vmem ( void* gpu_pointer, Vmem_Entry** head ) { Vmem_Entry* curr = *head; Vmem_Entry* prev = NULL; while (curr != NULL) { if (curr->gpu_pointer == gpu_pointer) { cudaFreeHost (curr->cpu_pointer); CUDA_check_error ("Failed to free virtual GPU memory."); if (prev == NULL) { // we are removing the head *head = curr->next; free (curr); return 0; } else { // removing past the head prev->next = curr->next; free (curr); return 0; } } prev = curr; curr = curr->next; } // Failed to free virtual GPU memory. return 1; } // Frees *ALL* GPU "virtual memory" // Returns number of freed entries int CUDA_freeall_vmem ( Vmem_Entry** head ) { int i = 0; Vmem_Entry* curr = *head; while (curr != NULL) { cudaFreeHost (curr->cpu_pointer); CUDA_check_error ("Failed to free virtual GPU memory."); *head = curr->next; free (curr); curr = *head; i++; } return i; } int CUDA_alloc_zero ( void** gpu_addr, size_t mem_size, cuda_alloc_fail_mode fail_mode ) { // Allcoated some global memory on the GPU cudaMalloc ((void**)gpu_addr, mem_size); if (fail_mode == cudaAllocStern) { CUDA_check_error ("Out of GPU memory."); } else { if (CUDA_detect_error()) { return 1; } } // Zero out the allocated global GPU memory cudaMemset (*gpu_addr, 0, mem_size); if (fail_mode == cudaAllocStern) { CUDA_check_error ("Failed to zero out GPU memory."); } else { if (CUDA_detect_error()) { return 1; } } // Success return 0; } int CUDA_zero_copy_check (int gpuid) { cudaDeviceProp props; cudaGetDeviceProperties(&props, gpuid); if (props.canMapHostMemory) { // GPU supports zero copy return 1; } else { // GPU doest not support zero copy return 0; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/cuda_mem.h000066400000000000000000000025061321604176500274610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _cuda_mem_h_ #define _cuda_mem_h_ #include "plm_config.h" typedef struct vmem_entry Vmem_Entry; struct vmem_entry { void* gpu_pointer; void* cpu_pointer; size_t size; Vmem_Entry* next; }; enum cuda_alloc_fail_mode { cudaAllocStern, cudaAllocCasual }; #if defined __cplusplus extern "C" { #endif plmcuda_EXPORT ( void CUDA_alloc_copy, void** gpu_addr, void** cpu_addr, size_t mem_size ); plmcuda_EXPORT ( void CUDA_init_vmem, Vmem_Entry** head ); plmcuda_EXPORT ( void CUDA_alloc_vmem, void** gpu_addr, size_t mem_size, Vmem_Entry** head ); plmcuda_EXPORT ( size_t CUDA_tally_vmem, Vmem_Entry** head ); plmcuda_EXPORT ( void CUDA_print_vmem, Vmem_Entry** head ); plmcuda_EXPORT ( int CUDA_free_vmem, void* gpu_pointer, Vmem_Entry** head ); plmcuda_EXPORT ( int CUDA_freeall_vmem, Vmem_Entry** head ); plmcuda_EXPORT ( int CUDA_alloc_zero, void** gpu_addr, size_t mem_size, enum cuda_alloc_fail_mode fail_mode ); plmcuda_EXPORT ( int CUDA_zero_copy_check, int gpuid ); #if defined __cplusplus } #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/cuda_probe.cu000077500000000000000000000043301321604176500301720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "cuda_probe.h" int cuda_probe (void) { int devicecount = -1; printf ("Testing for CUDA...\n"); cudaError_t rc = cudaGetDeviceCount (&devicecount); if (rc != cudaSuccess) { printf("Call to cudaGetDeviceCount() returned failure (%d)\n", (int) rc); return 0; } if (devicecount == 0) { printf("Suitable CUDA environment not detected!\n"); return 0; } printf ("Devices found: %d\n", devicecount); // It is possible at this point that devicecount = 1 and still be // without an actual CUDA device. CUDA 2.0 and 2.1 exhibit this // behavior. Apparently 2.x will detect an emulator device and // throw a 1 by reference when you call cudaGetDeviceCount(). // You are apparently able to distinguish between an actual // CUDA device and the emulator by checking the major and minor // revision numbers on the compute capability. Emulated devices // are supposed to return 9999 for both major and minor revision // numbers. Some, however, report that while this is the behavior // for CUDA 2.0, CUDA 2.1 returns different nonsensical numbers // when the detected device is emulated. Therefore, the best // solution (until the behavior is standardised across releases) // is to specifically check for compute capabilities we KNOW are // working with Plastimatch. // // Get CUDA device properties. cudaDeviceProp props; cudaGetDeviceProperties (&props, 0); printf ("Compute Capability %d.%d\n", props.major, props.minor); if (props.major == 1 || props.major == 2 || props.major == 3) { /* GCS: Cuda 2.2 with Tesla returns compatibility 1.3 */ /* JAS: Tesla C2050 is compute capability 2.0 */ printf ("Device is presumed cuda capable.\n"); return 1; } // Unless proven otherwise, we assume no CUDA. printf ("Device is presumed NOT cuda capable.\n"); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/cuda_probe.h000066400000000000000000000007411321604176500300110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _cuda_probe_h_ #define _cuda_probe_h_ #include "plm_config.h" #include "delayload.h" #if defined __cplusplus extern "C" { #endif //int cuda_probe (void); plmcuda_EXPORT ( int cuda_probe, void ); #if defined __cplusplus } #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/cuda_util.cu000066400000000000000000000074111321604176500300400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "cuda_util.h" // NOTE: This file provides utility functions that do not use CUDA specific // types as parameters; and can, therefore, be used from standard C or // C++ files. // // Helper functions that require parameters that use CUDA specific // types (dim3, float4, etc) should be placed in 'cuda_kernel_util.cu' void CUDA_check_error (const char *msg) { cudaError_t err = cudaGetLastError(); if (cudaSuccess != err) { fprintf (stderr, "CUDA ERROR: %s (%s).\n", msg, cudaGetErrorString(err)); exit (EXIT_FAILURE); } } int CUDA_detect_error () { cudaError_t err = cudaGetLastError(); if (cudaSuccess != err) { return 1; } return 0; } void CUDA_listgpu () { int num_gpus, i; int cores_per_sm; cudaDeviceProp props; cudaGetDeviceCount(&num_gpus); for (i = 0; i < num_gpus; i++) { cudaGetDeviceProperties(&props, i); if (props.major == 1) { cores_per_sm = 8; } else if (props.major == 2) { cores_per_sm = 32; } else if (props.major == 3) { cores_per_sm = 192; } else { printf ("GPU Compute Capability: Unknown to Platimatch!\n"); return; } printf ("GPU ID %i:\n", i); printf (" Name: %s (%.2f GB)\n", props.name, props.totalGlobalMem / (float)(1024 * 1024 * 1024)); printf ("Compute Capability: %d.%d\n", props.major, props.minor); printf (" Shared Memory: %.1f MB\n", props.sharedMemPerBlock / (float)1024); printf (" Registers: %i\n", props.regsPerBlock); printf (" Clock Rate: %.2f MHz\n", props.clockRate / (float)(1024)); printf (" # Cores: %d\n", props.multiProcessorCount * cores_per_sm); printf ("\n"); } } // Selects the best GPU or the user specified // GPU as defiend on command line void CUDA_selectgpu (int gpuid) { int num_gpus; int cores_per_sm; cudaDeviceProp props; cudaGetDeviceCount(&num_gpus); if (gpuid < num_gpus) { cudaGetDeviceProperties(&props, gpuid); if (props.major == 1) { cores_per_sm = 8; } else if (props.major == 2) { cores_per_sm = 32; } else if (props.major == 3) { cores_per_sm = 192; } else { printf ("Compute Capability: Unknown to Platimatch!\n"); return; } printf ("Using %s (%.2f GB)\n", props.name, props.totalGlobalMem / (float)(1024 * 1024 * 1024)); printf (" - Compute Capability: %d.%d\n", props.major, props.minor); printf (" - # Multi-Processors: %d\n", props.multiProcessorCount); printf (" - Number of Cores: %d\n", props.multiProcessorCount * cores_per_sm); cudaSetDevice (gpuid); } else { printf ("\nInvalid GPU ID specified. Choices are:\n\n"); CUDA_listgpu (); exit (0); } } // Returns the value held in __CUDA_ARCH__ // __CUDA_ARCH__ is only accessable as a #define // *inside* of CUDA kernels. This allows us to // use the compute capability in CPU code. int CUDA_getarch (int gpuid) { int num_gpus; cudaDeviceProp props; cudaGetDeviceCount(&num_gpus); if (gpuid < num_gpus) { cudaGetDeviceProperties(&props, gpuid); return 100*props.major + 10*props.minor; } else { /* Invalid GPU ID specified */ return -1; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/cuda_util.h000066400000000000000000000020741321604176500276600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _cuda_util_h_ #define _cuda_util_h_ #include "plm_config.h" #include #include "delayload.h" // NOTE: This file provides utility functions that do not use CUDA specific // types as parameters; and can, therefore, be used from standard C or // C++ files. // // Helper functions that require parameters that use CUDA specific // types (dim3, float4, etc) should be placed in 'cuda_kernel_util.h' #define GRID_LIMIT_X 65535 #define GRID_LIMIT_Y 65535 #if defined __cplusplus extern "C" { #endif plmcuda_EXPORT ( void CUDA_check_error, const char *msg ); plmcuda_EXPORT ( int CUDA_detect_error, void ); plmcuda_EXPORT ( void CUDA_listgpu, void ); plmcuda_EXPORT ( void CUDA_selectgpu, int gpuid ); plmcuda_EXPORT ( int CUDA_getarch, int gpuid ); #if defined __cplusplus } #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/cuda/plm_cuda_math.h000066400000000000000000000064351321604176500305110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_cuda_math_h_ #define _plm_cuda_math_h_ #include "plm_config.h" #include #include "plm_int.h" /* Host to device operators */ #if defined (commentout) inline __host__ int3 make_int3 (int *a) { return make_int3 (a[0], a[1], a[2]); } #endif inline __host__ int3 make_int3 (plm_long *a) { return make_int3 (a[0], a[1], a[2]); } inline __host__ int3 make_int3 (size_t *a) { return make_int3 ((int) a[0], (int) a[1], (int) a[2]); } inline __host__ int4 make_int4 (int *a) { return make_int4 (a[0], a[1], a[2], a[3]); } inline __host__ float2 make_float2 (float *a) { return make_float2 (a[0], a[1]); } inline __host__ float2 make_float2 (double *a) { return make_float2 (a[0], a[1]); } inline __host__ float3 make_float3 (float *a) { return make_float3 (a[0], a[1], a[2]); } inline __host__ float3 make_float3 (double *a) { return make_float3 (a[0], a[1], a[2]); } inline __host__ float4 make_float4 (float *a) { return make_float4 (a[0], a[1], a[2], a[3]); } inline __host__ float4 make_float4 (double *a) { return make_float4 (a[0], a[1], a[2], a[3]); } /* Device type conversion */ inline __device__ int3 make_int3 (float3 a) { return make_int3 (a.x, a.y, a.z); } /* Overloaded operators */ inline __host__ __device__ float3 operator+ (float3 a, float3 b) { return make_float3(a.x + b.x, a.y + b.y, a.z + b.z); } inline __host__ __device__ float3 operator- (float3 a, float3 b) { return make_float3(a.x - b.x, a.y - b.y, a.z - b.z); } inline __host__ __device__ float3 operator* (float a, float3 b) { return make_float3(a * b.x, a * b.y, a * b.z); } inline __host__ __device__ float3 operator* (float3 a, float3 b) { return make_float3(a.x * b.x, a.y * b.y, a.z * b.z); } inline __host__ __device__ float3 operator/ (float a, float3 b) { return make_float3(a / b.x, a / b.y, a / b.z); } inline __host__ __device__ int3 operator< (int3 a, int3 b) { return make_int3 (a.x < b.x, a.y < b.y, a.z < b.z); } inline __host__ __device__ int3 operator< (float3 a, float3 b) { return make_int3 (a.x < b.x, a.y < b.y, a.z < b.z); } inline __host__ __device__ int3 operator< (float3 a, float b) { return make_int3 (a.x < b, a.y < b, a.z < b); } /* Misc functions */ inline __host__ __device__ float dot (float3 a, float3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } inline __host__ __device__ float3 normalize (float3 v) { float inv_len = 1.0f / sqrtf(dot(v, v)); return inv_len * v; } inline __host__ __device__ float3 fabsf3 (float3 a) { return make_float3 (fabsf(a.x), fabsf(a.y), fabsf(a.z)); } inline __host__ __device__ float3 floorf3 (float3 a) { return make_float3 (floorf(a.x), floorf(a.y), floorf(a.z)); } inline __host__ __device__ void swapf (float *a, float *b) { float c = *a; *a = *b; *b = c; } inline __host__ __device__ void sortf (float *a, float *b) { if (*a > *b) { swapf (a, b); } } inline __host__ __device__ void sortf3 (float3 *a, float3 *b) { sortf (&a->x, &b->x); sortf (&a->y, &b->y); sortf (&a->z, &b->z); } #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/000077500000000000000000000000001321604176500255515ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/CMakeLists.txt000077500000000000000000000030561321604176500303200ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_dose) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/plmdose_config.h.in ${CMAKE_BINARY_DIR}/plmdose_config.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (PLMDOSE_LIBRARY_SRC bragg_curve.cxx bragg_curve.h dose_volume_functions.cxx dose_volume_functions.h particle_type.cxx particle_type.h rt_beam.cxx rt_beam.h rt_beam_model.cxx rt_beam_model.h rt_depth_dose.cxx rt_depth_dose.h rt_dij.cxx rt_dij.h rt_dose.cxx rt_dose.h rt_dose_timing.h rt_lut.cxx rt_lut.h rt_spot_map.cxx rt_spot_map.h rt_mebs.cxx rt_mebs.h rt_parms.cxx rt_parms.h rt_plan.cxx rt_plan.h rt_sigma.cxx rt_sigma.h wed_parms.cxx wed_parms.h ) set (PLMDOSE_LIBRARY_DEPENDENCIES plmbase plmutil plmsys ) set (PLMDOSE_LIBRARY_DEPENDENCIES ${PLMDOSE_LIBRARY_DEPENDENCIES} specfun) ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- plm_add_library ( plmdose "${PLMDOSE_LIBRARY_SRC}" "${PLMDOSE_LIBRARY_DEPENDENCIES}" "" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "") plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/bragg_curve.cxx000066400000000000000000000042611321604176500305660ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include "bragg_curve.h" #include "rt_lut.h" typedef double doublereal; /* unmangled symbol in specfun */ // PBDV(V,X,DV,DP,PDF,PDD) extern "C" void pbdv_ ( doublereal* v, doublereal* x, doublereal* dv, doublereal* dp, doublereal* pdf, doublereal* pdd); /* Note: Inputs to this function are in mm, but internal computations are done in cm. */ double bragg_curve ( double E_0, /* in MeV */ double sigma_E0, /* in MeV */ double z /* in mm */ ) { doublereal v, x, dv[100], dp[100], pdd; doublereal D_v_1, D_v_2; double p = particle_parameters[0][1]; double alpha = particle_parameters[0][0]; double R_0 = alpha * pow (E_0, p); double sigma_mono = 0.012 * pow (R_0, 0.935); double epsilon = 0.1; double sigma_squared = sigma_mono * sigma_mono + (sigma_E0 * sigma_E0 * alpha * alpha * p * p * pow (E_0 * E_0, (p - 2))); double sigma = sqrt (sigma_squared); double rr; double bragg; /* Convert z from mm to cm */ z = 0.1 * z; /* Compute residual range (rr) */ rr = R_0 - z; /* Use approximation Dhat in plateau region due to instability of computing parabolic cylinder function for large x */ if (rr > 10.0 * sigma) { bragg = 1 / (1 + 0.012 * R_0) * (17.93 * pow (rr, -0.435) + (0.444 + 31.7 * epsilon / R_0) * pow (rr, 0.565)); return bragg; } /* Term 1 of eqn 29 */ bragg = exp (- (rr * rr) / (4 * sigma * sigma)) * pow (sigma, 0.565) / (1 + 0.012 * R_0); /* D_v of -0.565 */ v = - 0.565; x = - rr / sigma; pbdv_ (&v, &x, dv, dp, &D_v_1, &pdd); /* D_v of -1.565 */ v = - 1.565; x = - rr / sigma; pbdv_ (&v, &x, dv, dp, &D_v_2, &pdd); /* Term 2 of eqn 29 */ bragg = bragg * ((11.26 / sigma) * D_v_1 + (0.157 + 11.26 * epsilon / R_0) * D_v_2); return bragg; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/bragg_curve.h000066400000000000000000000007161321604176500302140ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bragg_curve_h_ #define _bragg_curve_h_ #include "plmdose_config.h" PLMDOSE_C_API double bragg_curve ( double E_0, /* in MeV */ double sigma_E0, /* in MeV */ double z /* in mm */ ); #endif dose_volume_functions.cxx000077500000000000000000000273121321604176500326370ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include "dose_volume_functions.h" #include "proj_volume.h" #include "ray_data.h" #include "rt_lut.h" void dose_volume_create ( Volume* dose_volume, float* sigma_max, Rpl_volume* volume, double range) { /* we want to add extra margins around our volume take into account the dose that will be scattered outside of the rpl_volume */ /* A 3 sigma margin is applied to the front_back volume, and the size of our volume will be the projection of this shape on the back_clipping_plane */ float ap_ul_pixel[3]; // coordinates in the BEV (rpl_volume) volume float proj_pixel[3]; // coordinates of the ap_ul_pixel + 3 sigma margins on the back clipping plane float first_pixel[3]; // coordinates of the first_pixel of the volume to be created plm_long dim[3] = {0,0,0}; float origin[3] = {0,0,0}; float spacing[3] = {0,0,0}; const float dc[9] = { dose_volume->get_direction_cosines()[0], dose_volume->get_direction_cosines()[1], dose_volume->get_direction_cosines()[2], dose_volume->get_direction_cosines()[3], dose_volume->get_direction_cosines()[4], dose_volume->get_direction_cosines()[5], dose_volume->get_direction_cosines()[6], dose_volume->get_direction_cosines()[7], dose_volume->get_direction_cosines()[8]}; float sigma_margins = 3 * *sigma_max; double back_clip_useful = volume->compute_farthest_penetrating_ray_on_nrm(range) +5; // after this the volume will be void, the particules will not go farther + 2mm of margins ap_ul_pixel[0] = -volume->get_aperture()->get_center()[0]*volume->get_aperture()->get_spacing()[0]; ap_ul_pixel[1] = -volume->get_aperture()->get_center()[1]*volume->get_aperture()->get_spacing()[1]; ap_ul_pixel[2] = volume->get_aperture()->get_distance(); proj_pixel[0] = (ap_ul_pixel[0] - sigma_margins)*(back_clip_useful + volume->get_aperture()->get_distance()) / volume->get_aperture()->get_distance(); proj_pixel[1] = (ap_ul_pixel[1] - sigma_margins)*(back_clip_useful + volume->get_aperture()->get_distance()) / volume->get_aperture()->get_distance(); proj_pixel[2] = back_clip_useful + volume->get_aperture()->get_distance(); /* We build a matrix that starts from the proj_pixel projection on the front_clipping_plane */ first_pixel[0] = floor(proj_pixel[0]); first_pixel[1] = floor(proj_pixel[1]); first_pixel[2] = floor(volume->get_front_clipping_plane() +volume->get_aperture()->get_distance()); for (int i = 0; i < 3; i++) { origin[i] = first_pixel[i]; if (i != 2) { spacing[i] = 1; //spacing[i] = volume->get_aperture()->get_spacing(i); // MD Fix dim[i] = (plm_long) (2*abs(first_pixel[i]/spacing[i])+1); } else { spacing[i] = 1; //volume->get_proj_volume()->get_step_length(); dim[i] = (plm_long) ((back_clip_useful - volume->get_front_clipping_plane())/spacing[i] + 1); } } dose_volume->create(dim, origin, spacing, dc, PT_FLOAT,1); } void calculate_rpl_coordinates_xyz ( std::vector >* xyz_coordinates_volume, Rpl_volume* rpl_volume) { double aperture[3] = {0.0,0.0,0.0}; double entrance[3] = {0.0,0.0,0.0}; double ray_bev[3] = {0.0,0.0,0.0}; double vec_antibug_prt[3] = {0.0,0.0,0.0}; const plm_long *dim = rpl_volume->get_vol()->dim; int idx2d = 0; int idx3d = 0; for (int i = 0; i < rpl_volume->get_vol()->dim[0];i++){ for (int j = 0; j < rpl_volume->get_vol()->dim[1];j++){ idx2d = j * dim[0] + i; Ray_data* ray_data = &rpl_volume->get_ray_data()[idx2d]; vec3_cross(vec_antibug_prt, rpl_volume->get_aperture()->pdn, rpl_volume->get_proj_volume()->get_nrm()); ray_bev[0] = vec3_dot(ray_data->ray, vec_antibug_prt); ray_bev[1] = vec3_dot(ray_data->ray, rpl_volume->get_aperture()->pdn); ray_bev[2] = -vec3_dot(ray_data->ray, rpl_volume->get_proj_volume()->get_nrm()); // ray_beam_eye_view is already normalized find_xyz_center(aperture, ray_bev, rpl_volume->get_aperture()->get_distance(),0, rpl_volume->get_vol()->spacing[2]); find_xyz_center_entrance(entrance, ray_bev, rpl_volume->get_front_clipping_plane()); vec3_add2(entrance, aperture); for (int k = 0; k < rpl_volume->get_vol()->dim[2]; k++){ idx3d = k*dim[0]*dim[1] + idx2d; for (int l = 0; l < 3; l++) { (*xyz_coordinates_volume)[idx3d][l] = entrance[l] + (double) k * ray_bev[l]; } } } } } void dose_volume_reconstruction ( Rpl_volume* dose_rv, Volume::Pointer dose_vol ) { /* scan through patient CT Volume */ plm_long ct_ijk[3]; double ct_xyz[4]; plm_long idx = 0; double dose = 0; float* dose_img = (float*) dose_vol->img; bool first = true; for (ct_ijk[2] = 0; ct_ijk[2] < dose_vol->dim[2]; ct_ijk[2]++) { for (ct_ijk[1] = 0; ct_ijk[1] < dose_vol->dim[1]; ct_ijk[1]++) { for (ct_ijk[0] = 0; ct_ijk[0] < dose_vol->dim[0]; ct_ijk[0]++) { dose = 0.0; /* Transform vol index into space coords */ ct_xyz[0] = (double) (dose_vol->origin[0] + ct_ijk[0] * dose_vol->spacing[0]); ct_xyz[1] = (double) (dose_vol->origin[1] + ct_ijk[1] * dose_vol->spacing[1]); ct_xyz[2] = (double) (dose_vol->origin[2] + ct_ijk[2] * dose_vol->spacing[2]); ct_xyz[3] = (double) 1.0; idx = volume_index (dose_vol->dim, ct_ijk); dose = dose_rv->get_value(ct_xyz); if (dose <= 0) { continue; } /* Insert the dose into the dose volume */ dose_img[idx] += dose; } } } } void build_hong_grid ( std::vector* area, std::vector* xy_grid, int radius_sample, int theta_sample) { double dr = 1.0 / (double) radius_sample; double dt = 2.0 * M_PI / (double) theta_sample; for (int i = 0; i < radius_sample; i++) { (*area)[i] = M_PI * dr * dr * ( 2 * i + 1 ) / (double) theta_sample; // [(i+1)^2 - i^2] * dr^2 for (int j = 0; j < theta_sample; j++) { (*xy_grid)[2*(i*theta_sample+j)] = ((double) i + 0.5)* dr * sin ((double) j * dt); (*xy_grid)[2*(i*theta_sample+j)+1] = ((double) i + 0.5) * dr * cos ((double) j * dt); } } } void find_ijk_pixel(int* ijk_idx, double* xyz_ray_center, Volume* dose_volume) { ijk_idx[0] = (int) floor((xyz_ray_center[0] - dose_volume->origin[0]) / dose_volume->spacing[0] + 0.5); ijk_idx[1] = (int) floor((xyz_ray_center[1] - dose_volume->origin[1]) / dose_volume->spacing[1] + 0.5); ijk_idx[2] = (int) floor((xyz_ray_center[2] - dose_volume->origin[2]) / dose_volume->spacing[2] + 0.5); } void find_ijk_pixel(int* ijk_idx, double* xyz_ray_center, Volume::Pointer dose_volume) { ijk_idx[0] = (int) floor((xyz_ray_center[0] - dose_volume->origin[0]) / dose_volume->spacing[0] + 0.5); ijk_idx[1] = (int) floor((xyz_ray_center[1] - dose_volume->origin[1]) / dose_volume->spacing[1] + 0.5); ijk_idx[2] = (int) floor((xyz_ray_center[2] - dose_volume->origin[2]) / dose_volume->spacing[2] + 0.5); } void find_xyz_center_entrance(double* xyz_ray_center, double* ray, float z_axis_offset) { xyz_ray_center[0] = z_axis_offset * ray[0]; xyz_ray_center[1] = z_axis_offset * ray[1]; xyz_ray_center[2] = z_axis_offset * ray[2]; } void find_xyz_center(double* xyz_ray_center, double* ray, float z_axis_offset, int k, float z_spacing) { float alpha = 0.0f; xyz_ray_center[2] = z_axis_offset+(double)k * z_spacing; alpha = xyz_ray_center[2] /(double) ray[2]; xyz_ray_center[0] = alpha * ray[0]; xyz_ray_center[1] = alpha * ray[1]; } void find_xyz_from_ijk(double* xyz, Volume* volume, int* ijk) { xyz[0] = volume->origin[0] + ijk[0]*volume->spacing[0]; xyz[1] = volume->origin[1] + ijk[1]*volume->spacing[1]; xyz[2] = volume->origin[2] + ijk[2]*volume->spacing[2]; } double erf_gauss (double x) { int sign = 1; if (x < 0) {sign = -1;} x = fabs(x); /* erf interpolation */ double t = 1.0/(1.0 + ERF_P*x); double y = 1.0 - (((((ERF_A5*t + ERF_A4)*t) + ERF_A3)*t + ERF_A2)*t + ERF_A1)*t*exp(-x*x); return sign*y; } double double_gaussian_interpolation ( double* gaussian_center, double* pixel_center, double sigma, double* spacing) { double x1 = pixel_center[0] - 0.5 * spacing[0]; double x2 = x1 + spacing[0]; double y1 = pixel_center[1] - 0.5 * spacing[1]; double y2 = y1 + spacing[1]; double z = .25 * (erf_gauss((x2-gaussian_center[0])/(sigma*M_SQRT2)) - erf_gauss((x1-gaussian_center[0])/(sigma*M_SQRT2))) * (erf_gauss((y2-gaussian_center[1])/(sigma*M_SQRT2)) - erf_gauss((y1-gaussian_center[1])/(sigma*M_SQRT2))); return z; } double get_off_axis(double radius, double dr, double sigma) { return M_PI / 8.0 * sigma * ( exp(- (radius - dr)*(radius -dr) / (2 * sigma * sigma)) - exp(- (radius + dr)*(radius + dr) / (2 * sigma * sigma))); } /* MD Fix: don't consider any cosines directions */ void dose_normalization_to_dose(Volume::Pointer dose_volume, double dose, Rt_beam* beam) { int idx = 0; double norm = 0; int ijk_max[3] = {0,0,0}; float* img = (float*) dose_volume->img; for(int i = 0; i < dose_volume->dim[0]; i++) { for(int j = 0; j < dose_volume->dim[1]; j++) { for(int k = 0; k < dose_volume->dim[2]; k++) { idx = i + (dose_volume->dim[0] * (j + dose_volume->dim[1] * k)); if (img[idx] > norm) { norm = img[idx]; ijk_max[0] = i; ijk_max[1] = j; ijk_max[2] = k; } } } } if (norm > 0) { for (int i = 0; i < dose_volume->dim[0] * dose_volume->dim[1] * dose_volume->dim[2]; i++) { img[i] = img[i] / norm * dose; } const plm_long *ap_dim = beam->get_aperture_dim(); beam->get_mebs()->scale_num_part(dose/norm, ap_dim); printf("Raw dose at the maximum (%lg, %lg, %lg) : %lg A.U.\nDose normalized at the maximum to ", dose_volume->origin[0] + ijk_max[0] * dose_volume->spacing[0], dose_volume->origin[1] + ijk_max[1] * dose_volume->spacing[1], dose_volume->origin[2] + ijk_max[2] * dose_volume->spacing[2], norm); } else { printf("Dose is null in the entire volume. Please check your input conditions.\n"); } } /* MD Fix: don't consider any cosines directions */ void dose_normalization_to_dose_and_point(Volume::Pointer dose_volume, double dose, const float* rdp_ijk, const float* rdp, Rt_beam* beam) { double norm = dose_volume->get_ijk_value(rdp_ijk); float* img = (float*) dose_volume->img; if (norm > 0) { for (int i = 0; i < dose_volume->dim[0] * dose_volume->dim[1] * dose_volume->dim[2]; i++) { img[i] = img[i] / norm * dose; } const plm_long *ap_dim = beam->get_aperture_dim(); beam->get_mebs()->scale_num_part (dose/norm, ap_dim); printf("Raw dose at the reference dose point (%lg, %lg, %lg) : %lg A.U.\nDose normalized at the reference dose point to ", rdp[0], rdp[1], rdp[2], norm); } else { printf("Dose null at the reference dose point.\nDose normalized to the dose maximum in the volume.\n"); dose_normalization_to_dose(dose_volume, dose,beam); } } dose_volume_functions.h000077500000000000000000000031611321604176500322600ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dose_volume_functions_h_ #define _dose_volume_functions_h_ #include "rpl_volume.h" #include "rt_beam.h" #include "volume.h" void dose_volume_create(Volume* dose_volume, float* sigma_max, Rpl_volume* volume, double range); void calculate_rpl_coordinates_xyz(std::vector >* xyz_coordinates_volume, Rpl_volume* rpl_volume); void dose_volume_reconstruction(Rpl_volume* dose_rv, Volume::Pointer dose_vol); void build_hong_grid(std::vector* area, std::vector* xy_grid, int radius_sample, int theta_sample); void find_ijk_pixel(int* ijk_idx, double* xyz_ray_center, Volume* dose_volume); void find_ijk_pixel(int* ijk_idx, double* xyz_ray_center, Volume::Pointer dose_volume); void find_xyz_center_entrance(double* xyz_ray_center, double* ray, float z_axis_offset); void find_xyz_center(double* xyz_ray_center, double* ray, float z_axis_offset, int k, float z_spacing); void find_xyz_from_ijk(double* xyz, Volume* volume, int* ijk); double erf_gauss(double x); double double_gaussian_interpolation(double* gaussian_center, double* pixel_center, double sigma, double* spacing); double get_off_axis(double radius, double dr, double sigma); void dose_normalization_to_dose(Volume::Pointer dose_volume, double dose, Rt_beam* beam); void dose_normalization_to_dose_and_point(Volume::Pointer dose_volume, double dose, const float* rdp_ijk, const float* rdp, Rt_beam* beam); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/particle_type.cxx000066400000000000000000000031651321604176500311460ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include "particle_type.h" Particle_type particle_type_parse (const std::string& s) { if (s == "X") { return PARTICLE_TYPE_X; } else if (s == "P") { return PARTICLE_TYPE_P; } else if (s == "HE") { return PARTICLE_TYPE_HE; } else if (s == "LI") { return PARTICLE_TYPE_LI; } else if (s == "P") { return PARTICLE_TYPE_P; } else if (s == "BE") { return PARTICLE_TYPE_BE; } else if (s == "B") { return PARTICLE_TYPE_B; } else if (s == "C") { return PARTICLE_TYPE_C; } else if (s == "N") { return PARTICLE_TYPE_N; } else if (s == "O") { return PARTICLE_TYPE_O; } else { return PARTICLE_TYPE_UNKNOWN; } } const char* particle_type_string (Particle_type p) { switch (p) { case PARTICLE_TYPE_P: // proton return "Proton"; case PARTICLE_TYPE_HE: // helium return "Helium"; case PARTICLE_TYPE_LI: // lithium return "Lithium"; case PARTICLE_TYPE_BE: // berilium return "Berillium"; case PARTICLE_TYPE_B: // bore return "Boron"; case PARTICLE_TYPE_C: // carbon return "Carbon"; case PARTICLE_TYPE_N: // nitrogen return "Nitrogen"; case PARTICLE_TYPE_O: // oxygen return "Oxygen"; default: return "Unknown"; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/particle_type.h000066400000000000000000000015611321604176500305710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _particle_type_h_ #define _particle_type_h_ #include "plmdose_config.h" #include /* Particle type: 0=photon, 1= proton, ions: 2= helium, 3=lithium, 4=beryllium, 5=bore, 6=carbon, 7= nitrogen(not used), 8=oxygen */ enum Particle_type { PARTICLE_TYPE_UNKNOWN=-20, PARTICLE_TYPE_X=0, PARTICLE_TYPE_P=1, PARTICLE_TYPE_HE=2, PARTICLE_TYPE_LI=3, PARTICLE_TYPE_BE=4, PARTICLE_TYPE_B=5, PARTICLE_TYPE_C=6, PARTICLE_TYPE_N=7, // Not used for particle therapy PARTICLE_TYPE_O=8 }; Particle_type particle_type_parse (const std::string& s); const char* particle_type_string (Particle_type p); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/plmdose_config.h.in000066400000000000000000000013011321604176500313120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plmdose_config_h__ #define __plmdose_config_h__ #include "plm_config.h" #if ((defined(_WIN32) || defined(WIN32)) && (defined (PLM_BUILD_SHARED_LIBS))) # ifdef plmdose_EXPORTS # define PLMDOSE_C_API EXTERNC __declspec(dllexport) # define PLMDOSE_API __declspec(dllexport) # else # define PLMDOSE_C_API EXTERNC __declspec(dllimport) # define PLMDOSE_API __declspec(dllimport) # endif #else # define PLMDOSE_C_API EXTERNC # define PLMDOSE_API #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_beam.cxx000077500000000000000000001327161321604176500277230ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include #include #include #include #include #include "bragg_curve.h" #include "plm_math.h" #include "proj_volume.h" #include "rt_beam.h" #include "rt_dose_timing.h" #include "rt_plan.h" #include "rt_spot_map.h" static void save_vector_as_image ( const std::vector& v, const int dim2d[2], const std::string& filename) { plm_long dim[3] = { dim2d[0], dim2d[1], 1 }; float origin[3] = { 0.f, 0.f, 0.f }; float spacing[3] = { 1.f, 1.f, 1.f }; Volume::Pointer vol = Volume::New ( dim, origin, spacing, (float*) 0, PT_FLOAT, 1); float *vol_img = vol->get_raw (); for (plm_long i = 0; i < vol->npix; i++) { if (std::isnan(v[i]) || std::isinf(v[i]) || v[i] == NLMAX(double)) { vol_img[i] = -1; } else { vol_img[i] = (float) v[i]; } } Plm_image::Pointer img = Plm_image::New (vol); img->save_image (filename); } class Rt_beam_private { public: /* dose volume */ Plm_image::Pointer dose_vol; double source[3]; double isocenter[3]; std::string flavor; char homo_approx; float beamWeight; Rt_spot_map::Pointer spot_map; Rt_mebs::Pointer mebs; std::string debug_dir; float smearing; char rc_MC_model; float source_size; float step_length; double max_wed; double min_wed; Plm_image::Pointer ct_hu; Plm_image::Pointer ct_psp; Plm_image::Pointer target; Aperture::Pointer aperture; Rt_dose_timing::Pointer rt_dose_timing; std::string aperture_in; std::string range_compensator_in; std::string aperture_out; std::string proj_dose_out; std::string proj_img_out; std::string proj_target_out; std::string range_compensator_out; std::string sigma_out; std::string wed_out; std::string beam_dump_out; std::string dij_out; std::string beam_line_type; public: Rt_beam_private () { this->dose_vol = Plm_image::New(); this->source[0] = -1000.f; this->source[1] = 0.f; this->source[2] = 0.f; this->isocenter[0] = 0.f; this->isocenter[1] = 0.f; this->isocenter[2] = 0.f; this->flavor = "a"; this->homo_approx = 'n'; this->beamWeight = 1.f; this->spot_map = Rt_spot_map::New(); this->mebs = Rt_mebs::New(); this->debug_dir = ""; this->smearing = 0.f; this->rc_MC_model = 'n'; this->source_size = 0.f; this->step_length = 1.f; this->min_wed = 0.; this->max_wed = 0.; aperture = Aperture::New(); rt_dose_timing = Rt_dose_timing::New(); this->aperture_in = ""; this->range_compensator_in = ""; this->aperture_out = ""; this->proj_dose_out = ""; this->proj_img_out = ""; this->proj_target_out = ""; this->range_compensator_out = ""; this->sigma_out = ""; this->wed_out = ""; this->beam_line_type = "active"; } Rt_beam_private (const Rt_beam_private* rtbp) { this->dose_vol = Plm_image::New(); this->source[0] = rtbp->source[0]; this->source[1] = rtbp->source[1]; this->source[2] = rtbp->source[2]; this->isocenter[0] = rtbp->isocenter[0]; this->isocenter[1] = rtbp->isocenter[1]; this->isocenter[2] = rtbp->isocenter[2]; this->flavor = rtbp->flavor; this->homo_approx = rtbp->homo_approx; this->beamWeight = rtbp->beamWeight; // Clear the spot map this->spot_map = Rt_spot_map::New(); // Copy the mebs object (?) this->mebs = Rt_mebs::New(rtbp->mebs); this->debug_dir = rtbp->debug_dir; this->smearing = rtbp->smearing; this->source_size = rtbp->source_size; this->step_length = rtbp->step_length; this->min_wed = rtbp->min_wed; this->max_wed = rtbp->max_wed; /* Copy the aperture object */ aperture = Aperture::New (rtbp->aperture); /* Share same timing object */ rt_dose_timing = rtbp->rt_dose_timing; this->aperture_in = rtbp->aperture_in; this->range_compensator_in = rtbp->range_compensator_in; this->aperture_out = rtbp->aperture_out; this->proj_dose_out = rtbp->proj_dose_out; this->proj_img_out = rtbp->proj_img_out; this->proj_target_out = rtbp->proj_target_out; this->range_compensator_out = rtbp->range_compensator_out; this->sigma_out = rtbp->sigma_out; this->wed_out = rtbp->wed_out; this->beam_line_type = rtbp->beam_line_type; } }; Rt_beam::Rt_beam () { this->d_ptr = new Rt_beam_private(); /* Creation of the volumes useful for dose calculation */ this->rsp_accum_vol = new Rpl_volume(); this->hu_samp_vol = 0; this->sigma_vol = 0; this->rpl_vol_lg = 0; this->rpl_vol_samp_lg = 0; this->sigma_vol_lg = 0; this->dose_rv = 0; } Rt_beam::Rt_beam (const Rt_beam* rt_beam) { /* Copy all the private settings (?) */ this->d_ptr = new Rt_beam_private (rt_beam->d_ptr); /* The below calculation volumes don't need to be copied from input beam */ this->rsp_accum_vol = 0; this->hu_samp_vol = 0; this->sigma_vol = 0; this->rpl_vol_lg = 0; this->rpl_vol_samp_lg = 0; this->sigma_vol_lg = 0; this->dose_rv = 0; } Rt_beam::~Rt_beam () { delete this->d_ptr; } bool Rt_beam::load (const char* fn) { FILE* fp = fopen (fn, "r"); char linebuf[128]; if (!fp) { return false; } fgets (linebuf, 128, fp); fclose (fp); if (!strncmp (linebuf, "00001037", strlen ("00001037"))) { return this->load_xio (fn); } else { return this->load_txt (fn); } } const double* Rt_beam::get_source_position () const { return d_ptr->source; } double Rt_beam::get_source_position (int dim) const { return d_ptr->source[dim]; } void Rt_beam::set_source_position (const float* position) { for (int d = 0; d < 3; d++) { d_ptr->source[d] = position[d]; } } void Rt_beam::set_source_position (const double* position) { for (int d = 0; d < 3; d++) { d_ptr->source[d] = position[d]; } } const double* Rt_beam::get_isocenter_position () const { return d_ptr->isocenter; } double Rt_beam::get_isocenter_position (int dim) const { return d_ptr->isocenter[dim]; } void Rt_beam::set_isocenter_position (const float* position) { for (int d = 0; d < 3; d++) { d_ptr->isocenter[d] = position[d]; } } void Rt_beam::set_isocenter_position (const double* position) { for (int d = 0; d < 3; d++) { d_ptr->isocenter[d] = position[d]; } } double Rt_beam::get_source_distance () const { return vec3_dist (d_ptr->isocenter, d_ptr->source); } const std::string& Rt_beam::get_flavor (void) const { return d_ptr->flavor; } void Rt_beam::set_flavor (const std::string& flavor) { d_ptr->flavor = flavor; } char Rt_beam::get_homo_approx () const { return d_ptr->homo_approx; } void Rt_beam::set_homo_approx (char homo_approx) { d_ptr->homo_approx = homo_approx; } Rt_mebs::Pointer Rt_beam::get_mebs() { return d_ptr->mebs; } float Rt_beam::get_beam_weight (void) const { return d_ptr->beamWeight; } void Rt_beam::set_beam_weight (float beamWeight) { d_ptr->beamWeight = beamWeight; } void Rt_beam::set_rc_MC_model (char rc_MC_model) { d_ptr->rc_MC_model = rc_MC_model; } char Rt_beam::get_rc_MC_model (void) const { return d_ptr->rc_MC_model; } void Rt_beam::set_source_size(float source_size) { d_ptr->source_size = source_size; } float Rt_beam::get_source_size() const { return d_ptr->source_size; } void Rt_beam::set_debug (const std::string& dir) { d_ptr->debug_dir = dir; } void Rt_beam::dump (const char* dir) { d_ptr->mebs->dump (dir); } void Rt_beam::dump (const std::string& dir) { this->dump (dir.c_str()); } void Rt_beam::add_spot ( float xpos, float ypos, float energy, float sigma, float weight) { d_ptr->spot_map->add_spot (xpos, ypos, energy, sigma, weight); } bool Rt_beam::prepare_for_calc ( Plm_image::Pointer& ct_hu, Plm_image::Pointer& ct_psp, Plm_image::Pointer& target) { if (!ct_hu) return false; if (!ct_psp) return false; d_ptr->ct_hu = ct_hu; d_ptr->ct_psp = ct_psp; d_ptr->target = target; if (this->get_aperture()->get_distance() > this->get_source_distance ()) { lprintf ("Source distance must be greater than aperture distance"); return false; } Rpl_volume_ray_trace_start rvrts = RAY_TRACE_START_AT_CLIPPING_PLANE; // Create rsp_accum_vol */ if (!this->rsp_accum_vol) { this->rsp_accum_vol = new Rpl_volume; } if (!this->rsp_accum_vol) return false; this->rsp_accum_vol->set_geometry ( this->get_source_position(), this->get_isocenter_position(), this->get_aperture()->vup, this->get_aperture()->get_distance(), this->get_aperture()->get_dim(), this->get_aperture()->get_center(), this->get_aperture()->get_spacing(), this->get_step_length()); this->rsp_accum_vol->set_aperture (this->get_aperture()); this->rsp_accum_vol->set_ray_trace_start (rvrts); this->rsp_accum_vol->set_ct_volume (ct_psp); if (!this->rsp_accum_vol->get_ct() || !this->rsp_accum_vol->get_ct_limit()) { lprintf ("ray_data or clipping planes missing from rpl volume\n"); return false; } this->rsp_accum_vol->compute_rpl_accum (false); // Create ct projective volume // GCS FIX: The old code re-used the ray data. Is that really faster? this->hu_samp_vol = new Rpl_volume; if (!this->hu_samp_vol) return false; this->hu_samp_vol->clone_geometry (this->rsp_accum_vol); this->hu_samp_vol->set_ray_trace_start (rvrts); this->hu_samp_vol->set_aperture (this->get_aperture()); this->hu_samp_vol->set_ct_volume (d_ptr->ct_hu); this->hu_samp_vol->compute_rpl_sample (false); // Prepare, but don't compute the sigma volume yet if (this->get_flavor() == "d") { this->sigma_vol = new Rpl_volume; if (!this->sigma_vol) return false; this->sigma_vol->clone_geometry (this->rsp_accum_vol); this->sigma_vol->set_aperture (this->get_aperture()); this->sigma_vol->set_ct_volume (d_ptr->ct_hu); this->sigma_vol->set_ct_limit(this->rsp_accum_vol->get_ct_limit()); this->sigma_vol->compute_ray_data(); this->sigma_vol->set_front_clipping_plane(this->rsp_accum_vol->get_front_clipping_plane()); this->sigma_vol->set_back_clipping_plane(this->rsp_accum_vol->get_back_clipping_plane()); this->sigma_vol->compute_rpl_void(); } // Create target projective volume */ if (d_ptr->target) { this->target_rv = Rpl_volume::New(); if (!this->target_rv) return false; this->target_rv->clone_geometry (this->rsp_accum_vol); this->target_rv->set_ray_trace_start (rvrts); this->target_rv->set_aperture (this->get_aperture()); this->target_rv->set_ct_volume (d_ptr->target); this->target_rv->compute_rpl_sample (false); } // Create and fill in rpl_dose_volume (actually proj dose) if (this->get_flavor() == "b" || this->get_flavor() == "ray_trace_dij_a" || this->get_flavor() == "ray_trace_dij_b" || this->get_flavor() == "d") { this->dose_rv = new Rpl_volume; if (!this->dose_rv) return false; this->dose_rv->clone_geometry (this->rsp_accum_vol); this->dose_rv->set_ray_trace_start (rvrts); this->dose_rv->set_aperture (this->get_aperture()); this->dose_rv->set_ct_volume (d_ptr->ct_hu); this->dose_rv->set_ct_limit(this->rsp_accum_vol->get_ct_limit()); this->dose_rv->compute_ray_data(); this->dose_rv->set_front_clipping_plane(this->rsp_accum_vol->get_front_clipping_plane()); this->dose_rv->set_back_clipping_plane(this->rsp_accum_vol->get_back_clipping_plane()); this->dose_rv->compute_rpl_void(); } /* The priority how to generate dose is: 1. manual beamlet map 2. manual spot map 3. manual peaks 4. dose prescription 5. target 6. 100 MeV sample beam */ if (d_ptr->mebs->get_have_particle_number_map() == true) { lprintf ("Beamlet map file detected: Any manual peaks set, depth prescription, target or range compensator will not be considered.\n"); this->compute_beam_data_from_beamlet_map (); return true; } if (d_ptr->spot_map->num_spots() > 0) { lprintf ("Beam specified by spot map\n"); this->get_mebs()->set_have_manual_peaks(false); this->get_mebs()->set_have_prescription(false); this->compute_beam_data_from_spot_map (); return true; } if (d_ptr->mebs->get_have_manual_peaks() == true) { lprintf("Manual peaks detected [PEAKS]: Any prescription or target depth will not be considered.\n"); this->get_mebs()->set_have_manual_peaks (true); this->compute_beam_data_from_manual_peaks (target); return true; } if (d_ptr->mebs->get_have_prescription() == true) { lprintf ("Prescription depths detected. Any target depth will not be considered.\n"); this->get_mebs()->set_have_prescription(true); /* Apply margins */ this->get_mebs()->set_target_depths (d_ptr->mebs->get_prescription_min(), d_ptr->mebs->get_prescription_max()); this->compute_beam_data_from_prescription (target); return true; } if (target && target->get_vol()) { lprintf("Target detected.\n"); this->get_mebs()->set_have_manual_peaks(false); this->get_mebs()->set_have_prescription(false); this->compute_beam_data_from_target(target); return true; } /* If we arrive to this point, it is because no beam was defined Creation of a default beam: 100 MeV */ lprintf("***WARNING*** No beamlet map, manual peaks, depth prescription or target detected.\n"); lprintf("Beam set to a 100 MeV mono-energetic beam. Proximal and distal margins not considered.\n"); this->compute_default_beam (); return true; } void Rt_beam::compute_beam_data_from_beamlet_map() { this->get_mebs()->clear_depth_dose (); this->get_mebs()->load_beamlet_map (this->get_aperture()); /* the automatic aperture and range compensator are erased and the ones defined in the input file are considered */ this->update_aperture_and_range_compensator (); } void Rt_beam::compute_beam_data_from_spot_map() { this->get_mebs()->set_from_spot_map (d_ptr->spot_map); } void Rt_beam::compute_beam_data_from_manual_peaks (Plm_image::Pointer& target) { /* The beamlet map will be identical for passive or scanning beam lines */ const plm_long* ap_dim = this->get_aperture()->get_dim(); this->get_mebs()->generate_part_num_from_weight(ap_dim); if ((target && (d_ptr->aperture_in =="" || d_ptr->range_compensator_in =="")) && (d_ptr->mebs->get_have_manual_peaks() == true || d_ptr->mebs->get_have_prescription() == true)) // we build the associate range compensator and aperture { if (d_ptr->beam_line_type == "active") { this->compute_beam_modifiers_active_scanning ( target->get_vol(), d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin()); } else { this->compute_beam_modifiers_passive_scattering ( target->get_vol(), d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin()); } } /* the automatic aperture and range compensator are erased and the ones defined in the input file are considered */ this->update_aperture_and_range_compensator(); } void Rt_beam::compute_beam_data_from_manual_peaks() { /* The beamlet map will be identical for passive or scanning beam lines */ const plm_long *ap_dim = this->get_aperture()->get_dim(); this->get_mebs()->generate_part_num_from_weight(ap_dim); /* the automatic aperture and range compensator are erased and the ones defined in the input file are considered */ this->update_aperture_and_range_compensator(); } void Rt_beam::compute_beam_data_from_prescription(Plm_image::Pointer& target) { /* The beamlet map will be identical for passive or scanning beam lines */ /* Identic to compute from manual peaks, with a preliminary optimization */ d_ptr->mebs->optimize_sobp(); this->compute_beam_data_from_manual_peaks(target); } void Rt_beam::compute_beam_data_from_target(Plm_image::Pointer& target) { /* Compute beam aperture, range compensator + SOBP for passively scattered beam lines */ if (this->get_beam_line_type() == "passive") { this->compute_beam_modifiers ( d_ptr->target->get_vol(), this->get_mebs()->get_min_wed_map(), this->get_mebs()->get_max_wed_map()); this->compute_beam_data_from_prescription (target); } else { std::vector wepl_min; std::vector wepl_max; this->compute_beam_modifiers_active_scanning ( target->get_vol(), d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin(), wepl_min, wepl_max); d_ptr->mebs->compute_particle_number_matrix_from_target_active ( this->rsp_accum_vol, wepl_min, wepl_max); } } void Rt_beam::compute_default_beam() { /* Computes a default 100 MeV peak */ this->get_mebs()->add_peak (100, 1, 1); this->compute_beam_data_from_manual_peaks (); } void Rt_beam::compute_beam_modifiers (Volume *seg_vol) { if (d_ptr->beam_line_type == "active") { this->compute_beam_modifiers_active_scanning (seg_vol, d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin()); } else { this->compute_beam_modifiers_passive_scattering (seg_vol, d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin()); } d_ptr->mebs->set_prescription_depths (d_ptr->min_wed, d_ptr->max_wed); this->rsp_accum_vol->apply_beam_modifiers (); } void Rt_beam::compute_beam_modifiers (Volume *seg_vol, std::vector& map_wed_min, std::vector& map_wed_max) { if (d_ptr->beam_line_type == "active") { this->compute_beam_modifiers_active_scanning ( seg_vol, d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin(), map_wed_min, map_wed_max); } else { this->compute_beam_modifiers_passive_scattering (seg_vol, d_ptr->smearing, d_ptr->mebs->get_proximal_margin(), d_ptr->mebs->get_distal_margin(), map_wed_min, map_wed_max); } d_ptr->mebs->set_prescription_depths (d_ptr->min_wed, d_ptr->max_wed); this->rsp_accum_vol->apply_beam_modifiers (); } void Rt_beam::compute_beam_modifiers_active_scanning ( Volume *seg_vol, float smearing, float proximal_margin, float distal_margin) { std::vector map_wed_min; std::vector map_wed_max; this->compute_beam_modifiers_core (seg_vol, true, smearing, proximal_margin, distal_margin, map_wed_min, map_wed_max); } void Rt_beam::compute_beam_modifiers_passive_scattering ( Volume *seg_vol, float smearing, float proximal_margin, float distal_margin) { std::vector map_wed_min; std::vector map_wed_max; this-> compute_beam_modifiers_core (seg_vol, false, smearing, proximal_margin, distal_margin, map_wed_min, map_wed_max); } void Rt_beam::compute_beam_modifiers_active_scanning ( Volume *seg_vol, float smearing, float proximal_margin, float distal_margin, std::vector& map_wed_min, std::vector& map_wed_max) { this->compute_beam_modifiers_core (seg_vol, true, smearing, proximal_margin, distal_margin, map_wed_min, map_wed_max); } void Rt_beam::compute_beam_modifiers_passive_scattering ( Volume *seg_vol, float smearing, float proximal_margin, float distal_margin, std::vector& map_wed_min, std::vector& map_wed_max) { this-> compute_beam_modifiers_core (seg_vol, false, smearing, proximal_margin, distal_margin, map_wed_min, map_wed_max); } void Rt_beam::compute_beam_modifiers_core ( Volume *seg_vol, bool active, float smearing, float proximal_margin, float distal_margin, std::vector& map_wed_min, std::vector& map_wed_max) { printf("Compute target wepl_min_max...\n"); this->compute_target_wepl_min_max (map_wed_min, map_wed_max); #if defined (commentout) save_vector_as_image ( map_wed_min, d_ptr->aperture->get_dim(), "debug-min-a.nrrd"); save_vector_as_image ( map_wed_max, d_ptr->aperture->get_dim(), "debug-max-a.nrrd"); #endif printf ("Apply lateral smearing to the target...\n"); /* widen the min/max distance maps */ if (smearing > 0) { this->apply_smearing_to_target (smearing, map_wed_min, map_wed_max); } #if defined (commentout) save_vector_as_image ( map_wed_min, d_ptr->aperture->get_dim(), "debug-min-b.nrrd"); save_vector_as_image ( map_wed_max, d_ptr->aperture->get_dim(), "debug-max-b.nrrd"); #endif printf ("Apply proximal and distal ...\n"); /* add the margins */ for (size_t i = 0; i < map_wed_min.size(); i++) { map_wed_min[i] -= proximal_margin; if (map_wed_min[i] < 0) { map_wed_min[i] = 0; } if (map_wed_max[i] > 0) { map_wed_max[i] += distal_margin; } } #if defined (commentout) save_vector_as_image ( map_wed_min, d_ptr->aperture->get_dim(), "debug-min-c.nrrd"); save_vector_as_image ( map_wed_max, d_ptr->aperture->get_dim(), "debug-max-c.nrrd"); #endif /* Compute max wed, used by range compensator */ int idx = 0; double max_wed = 0; int i[2] = {0, 0}; printf("Compute max wed...\n"); for (i[1] = 0; i[1] < d_ptr->aperture->get_aperture_volume()->dim[1]; i[1]++) { for (i[0] = 0; i[0] < d_ptr->aperture->get_aperture_volume()->dim[0]; i[0]++) { idx = i[0] + i[1] * d_ptr->aperture->get_aperture_volume()->dim[0]; if (map_wed_max[idx] > max_wed) { max_wed = map_wed_max[idx]; } } } printf("Compute the aperture...\n"); /* compute the aperture */ /* This assumes that dim & spacing are correctly set in aperture */ d_ptr->aperture->allocate_aperture_images (); Volume::Pointer aperture_vol = d_ptr->aperture->get_aperture_volume (); unsigned char *aperture_img = (unsigned char*) aperture_vol->img; for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++) { if (map_wed_min[i] > 0) { aperture_img[i] = 1; } else { aperture_img[i] = 0; } } /* compute the range compensator if passive beam line with PMMA range compensator */ Volume::Pointer range_comp_vol = d_ptr->aperture->get_range_compensator_volume (); float *range_comp_img = (float*) range_comp_vol->img; if (active == false) { printf("Compute range compensator...\n"); } for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++) { if (active == true) { range_comp_img[i] = 0; } else { range_comp_img[i] = (max_wed - map_wed_max[i]) / (PMMA_STPR * PMMA_DENSITY); } } /* compute the max/min wed of the entire target + margins + range_comp*/ double total_min_wed = 0; double total_max_wed = 0; // Max should be the same as the max in the target as for this ray rgcomp is null for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++) { if (range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i] > total_max_wed) { // if active beam line, range comp is null total_max_wed = range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i]; } } total_min_wed = total_max_wed; for (int i = 0; i < aperture_vol->dim[0] * aperture_vol->dim[1]; i++) { if ((range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_max[i] > 0) && (range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_min[i] < total_min_wed)) { total_min_wed = range_comp_img[i] * PMMA_STPR * PMMA_DENSITY + map_wed_min[i]; } } printf("Max wed in the target is %lg mm.\n", total_max_wed); printf("Min wed in the target is %lg mm.\n", total_min_wed); /* Save these values in private data store */ // GCS FIX: To be revisited d_ptr->max_wed = total_max_wed; d_ptr->min_wed = total_min_wed; } void Rt_beam::compute_target_wepl_min_max ( std::vector& map_wed_min, std::vector& map_wed_max) { Rpl_volume *wepl_rv = this->rsp_accum_vol; Volume *wepl_vol = wepl_rv->get_vol (); float *wepl_img = wepl_vol->get_raw (); Rpl_volume::Pointer target_rv = this->target_rv; Volume *target_vol = target_rv->get_vol (); float *target_img = target_vol->get_raw (); const plm_long *target_dim = target_vol->get_dim (); map_wed_min.resize (target_dim[0]*target_dim[1], NLMAX(double)); map_wed_max.resize (target_dim[0]*target_dim[1], 0.); int ij[2] = {0, 0}; int num_steps = this->target_rv->get_num_steps(); for (ij[1] = 0; ij[1] < target_dim[1]; ij[1]++) { for (ij[0] = 0; ij[0] < target_dim[0]; ij[0]++) { int map_idx = ij[0] + ij[1] * target_dim[0]; for (int s = 0; s < num_steps; s++) { int rv_index = target_vol->index (ij[0],ij[1],s); float tgt = target_img[rv_index]; float wepl = wepl_img[rv_index]; if (tgt < 0.2) { continue; } if (map_wed_min[map_idx] > wepl) { map_wed_min[map_idx] = wepl; } if (map_wed_max[map_idx] < wepl) { map_wed_max[map_idx] = wepl; } } } } } void Rt_beam::apply_smearing_to_target ( float smearing, std::vector & map_min_distance, std::vector & map_max_distance) { // GCS FIX. It appears that the reason for computing geometric // distance in the previous version of the code was to make the // smearing code act at the minimum target distance. This is unnecessary; // it is easier/better to apply at isocenter plane. // Convert smearing from isocenter to aperture plane const Aperture::Pointer& ap = d_ptr->aperture; float smearing_ap = smearing * ap->get_distance() / this->get_source_distance(); printf ("Smearing = %f, Smearing_ap = %f\n", smearing, smearing_ap); /* Create a structured element of the right size */ int strel_half_size[2]; int strel_size[2]; strel_half_size[0] = ROUND_INT (smearing_ap / ap->get_spacing()[0]); strel_half_size[1] = ROUND_INT (smearing_ap / ap->get_spacing()[1]); strel_size[0] = 1 + 2 * strel_half_size[0]; strel_size[1] = 1 + 2 * strel_half_size[1]; printf ("Strel size = (%d,%d), (%d,%d)\n", strel_half_size[0], strel_half_size[1], strel_size[0], strel_size[1]); int *strel = new int[strel_size[0]*strel_size[1]]; /* (rf, cf) center of the smearing */ for (int r = 0; r < strel_size[1]; r++) { float rf = (float) (r - strel_half_size[1]) * ap->get_spacing()[0]; for (int c = 0; c < strel_size[0]; c++) { float cf = (float) (c - strel_half_size[0]) * ap->get_spacing()[1]; int idx = r*strel_size[0] + c; strel[idx] = 0; if ((rf*rf + cf*cf) <= smearing_ap*smearing_ap) { strel[idx] = 1; } } } /* Debugging information */ for (int r = 0; r < strel_size[1]; r++) { for (int c = 0; c < strel_size[0]; c++) { int idx = r*strel_size[0] + c; printf ("%d ", strel[idx]); } printf ("\n"); } // GCS FIX. This is also in error. The smearing should be done // in WEPL rather than in geometric distance. /* Apply smear to target maps */ double distance_min; double distance_max; std::vector min_distance_tmp (map_min_distance.size(), 0); std::vector max_distance_tmp (map_max_distance.size(), 0); for (int ar = 0; ar < d_ptr->aperture->get_dim()[1]; ar++) { for (int ac = 0; ac < d_ptr->aperture->get_dim()[0]; ac++) { int aidx = ar * d_ptr->aperture->get_dim()[0] + ac; /* Reset the limit values */ distance_min = DBL_MAX; distance_max = 0; for (int sr = 0; sr < strel_size[1]; sr++) { int pr = ar + sr - strel_half_size[1]; if (pr < 0 || pr >= d_ptr->aperture->get_dim()[1]) { continue; } for (int sc = 0; sc < strel_size[0]; sc++) { int pc = ac + sc - strel_half_size[0]; if (pc < 0 || pc >= d_ptr->aperture->get_dim()[0]) { continue; } int sidx = sr * strel_size[0] + sc; if (strel[sidx] == 0) { continue; } int pidx = pr * d_ptr->aperture->get_dim()[0] + pc; if (map_min_distance[pidx] > 0 && map_min_distance[pidx] < distance_min) { distance_min = map_min_distance[pidx]; } if (map_max_distance[pidx] > distance_max) { distance_max = map_max_distance[pidx]; } } } if (distance_min == DBL_MAX) { min_distance_tmp[aidx] = 0; } else { min_distance_tmp[aidx] = distance_min; } max_distance_tmp[aidx] = distance_max; } } /* update the initial distance map */ for (size_t i = 0; i < map_min_distance.size(); i++) { map_min_distance[i] = min_distance_tmp[i]; map_max_distance[i] = max_distance_tmp[i]; } /* Clean up */ delete[] strel; } void Rt_beam::update_aperture_and_range_compensator () { // GCS FIX. The below logic is no longer valid #if defined (commentout) /* The aperture is copied from rpl_vol the range compensator and/or the aperture are erased if defined in the input file */ if (d_ptr->aperture_in != "") { Plm_image::Pointer ap_img = Plm_image::New (d_ptr->aperture_in, PLM_IMG_TYPE_ITK_UCHAR); this->get_aperture()->set_aperture_image(d_ptr->aperture_in.c_str()); this->get_aperture()->set_aperture_volume(ap_img->get_volume_uchar()); if (this->rsp_accum_vol->get_minimum_distance_target() == 0) // means that there is no target defined { printf("Smearing applied to the aperture. The smearing width is defined in the aperture frame.\n"); d_ptr->aperture->apply_smearing_to_aperture(d_ptr->smearing, d_ptr->aperture->get_distance()); } else { printf("Smearing applied to the aperture. The smearing width is defined at the target minimal distance.\n"); d_ptr->aperture->apply_smearing_to_aperture(d_ptr->smearing, this->rsp_accum_vol->get_minimum_distance_target()); } } /* Set range compensator */ if (d_ptr->range_compensator_in != "" && d_ptr->beam_line_type != "active") { Plm_image::Pointer rgc_img = Plm_image::New (d_ptr->range_compensator_in, PLM_IMG_TYPE_ITK_FLOAT); this->get_aperture()->set_range_compensator_image(d_ptr->range_compensator_in.c_str()); this->get_aperture()->set_range_compensator_volume(rgc_img->get_volume_float()); if (this->rsp_accum_vol->get_minimum_distance_target() == 0) // means that there is no target defined { printf("Smearing applied to the range compensator. The smearing width is defined in the aperture frame.\n"); d_ptr->aperture->apply_smearing_to_range_compensator(d_ptr->smearing, d_ptr->aperture->get_distance()); } else { printf("Smearing applied to the range compensator. The smearing width is defined at the target minimal distance.\n"); d_ptr->aperture->apply_smearing_to_range_compensator(d_ptr->smearing, this->rsp_accum_vol->get_minimum_distance_target()); } } #endif } Plm_image::Pointer& Rt_beam::get_ct_psp () { return d_ptr->ct_psp; } const Plm_image::Pointer& Rt_beam::get_ct_psp () const { return d_ptr->ct_psp; } void Rt_beam::set_ct_psp (Plm_image::Pointer& ct_psp) { d_ptr->ct_psp = ct_psp; } Plm_image::Pointer& Rt_beam::get_target () { return d_ptr->target; } const Plm_image::Pointer& Rt_beam::get_target () const { return d_ptr->target; } void Rt_beam::set_target (Plm_image::Pointer& target) { d_ptr->target = target; } void Rt_beam::set_rt_dose_timing (Rt_dose_timing::Pointer& rt_dose_timing) { d_ptr->rt_dose_timing = rt_dose_timing; } Rt_dose_timing::Pointer& Rt_beam::get_rt_dose_timing () { return d_ptr->rt_dose_timing; } Plm_image::Pointer& Rt_beam::get_dose () { return d_ptr->dose_vol; } const Plm_image::Pointer& Rt_beam::get_dose () const { return d_ptr->dose_vol; } void Rt_beam::set_dose(Plm_image::Pointer& dose) { d_ptr->dose_vol = dose; } Aperture::Pointer& Rt_beam::get_aperture () { return d_ptr->aperture; } const Aperture::Pointer& Rt_beam::get_aperture () const { return d_ptr->aperture; } Plm_image::Pointer& Rt_beam::get_aperture_image () { return d_ptr->aperture->get_aperture_image (); } const Plm_image::Pointer& Rt_beam::get_aperture_image () const { return d_ptr->aperture->get_aperture_image (); } const plm_long* Rt_beam::get_aperture_dim () const { return d_ptr->aperture->get_dim (); } Plm_image::Pointer& Rt_beam::get_range_compensator_image () { return d_ptr->aperture->get_range_compensator_image (); } const Plm_image::Pointer& Rt_beam::get_range_compensator_image () const { return d_ptr->aperture->get_range_compensator_image (); } void Rt_beam::set_aperture_vup (const float vup[]) { d_ptr->aperture->set_vup (vup); } void Rt_beam::set_aperture_distance (float ap_distance) { d_ptr->aperture->set_distance (ap_distance); } void Rt_beam::set_aperture_origin (const float ap_origin[]) { this->get_aperture()->set_origin (ap_origin); } void Rt_beam::set_aperture_resolution (const plm_long ap_resolution[]) { this->get_aperture()->set_dim (ap_resolution); } void Rt_beam::set_aperture_spacing (const float ap_spacing[]) { this->get_aperture()->set_spacing (ap_spacing); } void Rt_beam::set_step_length(float step) { d_ptr->step_length = step; } float Rt_beam::get_step_length() { return d_ptr->step_length; } void Rt_beam::set_smearing (float smearing) { d_ptr->smearing = smearing; } float Rt_beam::get_smearing() { return d_ptr->smearing; } void Rt_beam::set_aperture_in (const std::string& str) { d_ptr->aperture_in = str; } std::string Rt_beam::get_aperture_in() { return d_ptr->aperture_in; } void Rt_beam::set_range_compensator_in (const std::string& str) { d_ptr->range_compensator_in = str; } std::string Rt_beam::get_range_compensator_in() { return d_ptr->range_compensator_in; } void Rt_beam::set_aperture_out(std::string str) { d_ptr->aperture_out = str; } std::string Rt_beam::get_aperture_out() { return d_ptr->aperture_out; } void Rt_beam::set_proj_dose_out(std::string str) { d_ptr->proj_dose_out = str; } std::string Rt_beam::get_proj_dose_out() { return d_ptr->proj_dose_out; } void Rt_beam::set_proj_img_out(std::string str) { d_ptr->proj_img_out = str; } std::string Rt_beam::get_proj_img_out() { return d_ptr->proj_img_out; } void Rt_beam::set_range_compensator_out(std::string str) { d_ptr->range_compensator_out = str; } std::string Rt_beam::get_range_compensator_out() { return d_ptr->range_compensator_out; } void Rt_beam::set_sigma_out(std::string str) { d_ptr->sigma_out = str; } std::string Rt_beam::get_sigma_out() { return d_ptr->sigma_out; } void Rt_beam::set_beam_dump_out(std::string str) { d_ptr->beam_dump_out = str; } std::string Rt_beam::get_beam_dump_out() { return d_ptr->beam_dump_out; } void Rt_beam::set_dij_out (const std::string& str) { d_ptr->dij_out = str; } const std::string& Rt_beam::get_dij_out() { return d_ptr->dij_out; } void Rt_beam::set_wed_out(std::string str) { d_ptr->wed_out = str; } std::string Rt_beam::get_wed_out() { return d_ptr->wed_out; } void Rt_beam::set_proj_target_out(std::string str) { d_ptr->proj_target_out = str; } std::string Rt_beam::get_proj_target_out() { return d_ptr->proj_target_out; } void Rt_beam::set_beam_line_type(std::string str) { if (str == "active") { d_ptr->beam_line_type = str; } else { d_ptr->beam_line_type = "passive"; } } std::string Rt_beam::get_beam_line_type() { return d_ptr->beam_line_type; } bool Rt_beam::load_xio (const char* fn) { #if defined (commentout) int i, j; char* ptoken; char linebuf[128]; FILE* fp = fopen (fn, "r"); // Need to check for a magic number (00001037) here? /* skip the first 4 lines */ for (i=0; i<4; i++) { fgets (linebuf, 128, fp); } /* line 5 contains the # of samples */ fgets (linebuf, 128, fp); sscanf (linebuf, "%i", &this->num_samples); this->d_lut = (float*)malloc (this->num_samples*sizeof(float)); this->e_lut = (float*)malloc (this->num_samples*sizeof(float)); memset (this->d_lut, 0, this->num_samples*sizeof(float)); memset (this->e_lut, 0, this->num_samples*sizeof(float)); /* load in the depths (10 samples per line) */ for (i=0, j=0; i<(this->num_samples/10)+1; i++) { fgets (linebuf, 128, fp); ptoken = strtok (linebuf, ",\n\0"); while (ptoken) { this->d_lut[j++] = (float) strtod (ptoken, NULL); ptoken = strtok (NULL, ",\n\0"); } } this->dmax = this->d_lut[j-1]; /* load in the energies (10 samples per line) */ for (i=0, j=0; i<(this->num_samples/10)+1; i++) { fgets (linebuf, 128, fp); ptoken = strtok (linebuf, ",\n\0"); while (ptoken) { this->e_lut[j] = (float) strtod (ptoken, NULL); ptoken = strtok (NULL, ",\n\0"); j++; } } fclose (fp); #endif return true; } bool Rt_beam::load_txt (const char* fn) { #if defined (commentout) char linebuf[128]; FILE* fp = fopen (fn, "r"); while (fgets (linebuf, 128, fp)) { float range, dose; if (2 != sscanf (linebuf, "%f %f", &range, &dose)) { break; } this->num_samples++; this->d_lut = (float*) realloc ( this->d_lut, this->num_samples * sizeof(float)); this->e_lut = (float*) realloc ( this->e_lut, this->num_samples * sizeof(float)); this->d_lut[this->num_samples-1] = range; this->e_lut[this->num_samples-1] = dose; this->dmax = range; /* Assume entries are sorted */ } fclose (fp); #endif return true; } bool Rt_beam::get_intersection_with_aperture ( double* idx_ap, plm_long* idx, double* rest, double* ct_xyz) { double ray[3] = {0,0,0}; double length_on_normal_axis = 0; vec3_copy(ray, ct_xyz); vec3_sub2(ray, d_ptr->source); length_on_normal_axis = -vec3_dot(ray, hu_samp_vol->get_proj_volume()->get_nrm()); // MD Fix: why is the aperture not updated at this point? and why proj vol is? if (length_on_normal_axis < 0) { return false; } vec3_scale2(ray, this->get_aperture()->get_distance()/length_on_normal_axis); vec3_add2(ray, d_ptr->source); vec3_sub2(ray, hu_samp_vol->get_proj_volume()->get_ul_room()); idx_ap[0] = vec3_dot(ray, hu_samp_vol->get_proj_volume()->get_incr_c()) / (this->get_aperture()->get_spacing(0) * this->get_aperture()->get_spacing(0)); idx_ap[1] = vec3_dot(ray, hu_samp_vol->get_proj_volume()->get_incr_r()) / (this->get_aperture()->get_spacing(1) * this->get_aperture()->get_spacing(1)); idx[0] = (int) floor(idx_ap[0]); idx[1] = (int) floor(idx_ap[1]); rest[0] = idx_ap[0] - (double) idx[0]; rest[1] = idx_ap[1] - (double) idx[1]; return true; } bool Rt_beam::is_ray_in_the_aperture ( const plm_long* idx, const unsigned char* ap_img) { if ((float) ap_img[idx[0] + idx[1] * this->get_aperture()->get_dim(0)] == 0) {return false;} if (idx[0] + 1 < this->get_aperture()->get_dim(0)) { if ((float) ap_img[idx[0] + 1 + idx[1] * this->get_aperture()->get_dim(0)] == 0) {return false;} } if (idx[1] + 1 < this->get_aperture()->get_dim(1)) { if ((float) ap_img[idx[0] + (idx[1] + 1) * this->get_aperture()->get_dim(0)] == 0) {return false;} } if (idx[0] + 1 < this->get_aperture()->get_dim(0) && idx[1] + 1 < this->get_aperture()->get_dim(1)) { if ((float) ap_img[idx[0] + 1 + (idx[1] + 1) * this->get_aperture()->get_dim(0)] == 0) {return false;} } return true; } float Rt_beam::compute_minimal_target_distance(Volume* target_vol, float background) { float* target_img = (float*) target_vol->img; float min = FLT_MAX; int idx = 0; const plm_long *dim = target_vol->dim; float target_image_origin[3] = {target_vol->origin[0], target_vol->origin[1], target_vol->origin[2]}; float target_image_spacing[3] = {target_vol->spacing[0], target_vol->spacing[1], target_vol->spacing[2]}; float source[3] = {(float) this->get_source_position(0), (float) this->get_source_position(1), (float) this->get_source_position(2)}; float voxel_xyz[3] = {0, 0, 0}; float min_tmp; for (int k = 0; k < dim[2]; k++) { for (int j = 0; j < dim[1]; j++) { for (int i = 0; i < dim[0]; i++) { idx = i + (dim[0] * (j + dim[1] * k)); if (target_img[idx] > background) { voxel_xyz[0] = target_image_origin[0] + (float) i * target_image_spacing[0]; voxel_xyz[1] = target_image_origin[1] + (float) j * target_image_spacing[1]; voxel_xyz[2] = target_image_origin[2] + (float) k * target_image_spacing[2]; min_tmp = vec3_dist(voxel_xyz, source); if (min_tmp < min) {min = min_tmp;} } } } } return min; } void Rt_beam::set_energy_resolution (float eres) { d_ptr->mebs->set_energy_resolution (eres); } float Rt_beam::get_energy_resolution () const { return d_ptr->mebs->get_energy_resolution (); } void Rt_beam::set_proximal_margin (float proximal_margin) { d_ptr->mebs->set_proximal_margin (proximal_margin); } float Rt_beam::get_proximal_margin () const { return d_ptr->mebs->get_proximal_margin (); } void Rt_beam::set_distal_margin (float distal_margin) { d_ptr->mebs->set_distal_margin (distal_margin); } float Rt_beam::get_distal_margin () const { return d_ptr->mebs->get_distal_margin (); } void Rt_beam::set_prescription (float prescription_min, float prescription_max) { d_ptr->mebs->set_prescription (prescription_min, prescription_max); } void Rt_beam::save_beam_output () { /* Save beam modifiers */ if (this->get_aperture_out() != "") { Rpl_volume *rpl_vol = this->rsp_accum_vol; Plm_image::Pointer& ap = rpl_vol->get_aperture()->get_aperture_image(); ap->save_image (this->get_aperture_out().c_str()); } if (this->get_range_compensator_out() != "" && this->get_beam_line_type() == "passive") { Rpl_volume *rpl_vol = this->rsp_accum_vol; Plm_image::Pointer& rc = rpl_vol->get_aperture()->get_range_compensator_image(); rc->save_image (this->get_range_compensator_out().c_str()); } /* Save projected density volume */ if (d_ptr->proj_img_out != "") { Rpl_volume* proj_img = this->hu_samp_vol; if (proj_img) { proj_img->save (d_ptr->proj_img_out); } } /* Save projected dose volume */ if (this->get_proj_dose_out() != "") { Rpl_volume* dose_rv = this->dose_rv; if (dose_rv) { dose_rv->save (this->get_proj_dose_out()); } } /* Save wed volume */ if (this->get_wed_out() != "") { Rpl_volume* rpl_vol = this->rsp_accum_vol; if (rpl_vol) { rpl_vol->save (this->get_wed_out()); } } /* Save projected target volume */ if (this->get_proj_target_out() != "") { Rpl_volume::Pointer rpl_vol = this->target_rv; if (rpl_vol) { rpl_vol->save (this->get_proj_target_out()); } } /* Save the beamlet map */ if (this->get_mebs()->get_particle_number_out() != "") { this->get_mebs()->export_as_txt (this->get_aperture()); } /* Dump beam information */ if (this->get_beam_dump_out() != "") { this->dump (this->get_beam_dump_out()); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_beam.h000077500000000000000000000237251321604176500273470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_beam_h_ #define _rt_beam_h_ #include "file_util.h" #include "plmdose_config.h" #include #include #include "aperture.h" #include "particle_type.h" #include "rpl_volume.h" #include "rt_dose_timing.h" #include "rt_mebs.h" #include "smart_pointer.h" class Rt_beam_private; class Rt_mebs; /*! \brief * The Rt_beam class encapsulates a single SOBP Rt beam, including * its associated aperture and range compensator. */ class PLMDOSE_API Rt_beam { public: SMART_POINTER_SUPPORT (Rt_beam); Rt_beam_private *d_ptr; public: Rt_beam (); Rt_beam (const Rt_beam* rt_beam); ~Rt_beam (); public: /*! \name Inputs */ /*! \brief Load PDD from XiO or txt file */ bool load (const char* fn); /*! \brief Get the position of the beam source in world coordinates. */ const double* get_source_position () const; /*! \brief Get the x, y, or z coordinate of the beam source in world coordinates. */ double get_source_position (int dim) const; /*! \brief Set the position of the beam source in world coordinates. */ void set_source_position (const float position[3]); /*! \brief Set the position of the beam source in world coordinates. */ void set_source_position (const double position[3]); /*! \brief Get the position of the beam isocenter in world coordinates. */ const double* get_isocenter_position () const; /*! \brief Get the x, y, or z coordinate of the beam source in world coordinates. */ double get_isocenter_position (int dim) const; /*! \brief Set the position of the beam isocenter in world coordinates. */ void set_isocenter_position (const float position[3]); /*! \brief Set the position of the beam isocenter in world coordinates. */ void set_isocenter_position (const double position[3]); /*! \brief Get the source distance. */ double get_source_distance () const; /*! \brief Get "flavor" parameter of dose calculation algorithm */ const std::string& get_flavor () const; /*! \brief Set "flavor" parameter of dose calculation algorithm */ void set_flavor (const std::string& flavor); /*! \brief Get "homo_approx" parameter of dose calculation algorithm */ char get_homo_approx () const; /*! \brief Set "homo_approx" parameter of dose calculation algorithm */ void set_homo_approx (char homo_approx); /*! \brief Get mebs */ Rt_mebs::Pointer get_mebs(); /*! \brief Get "beam_weight" parameter of dose calculation algorithm */ float get_beam_weight () const; /*! \brief Set "beam_weight" parameter of dose calculation algorithm */ void set_beam_weight (float beam_weight); /*! \brief Get "rc_MC_model" for the model of the range compensator, y = Monte Carlo, n = Highland */ char get_rc_MC_model () const; /*! \brief Set "rc_MC_model" for the model of the range compensator, y = Monte Carlo, n = Highland */ void set_rc_MC_model (char rc_MC_model); /* Set source size in mm */ void set_source_size(float source_size); /* Get source size in mm */ float get_source_size() const; /*! \brief Request debugging information to be written to directory */ void set_debug (const std::string& dir); /*! \name Outputs */ void dump (const char* dir); void dump (const std::string& dir); /* Spot scanning */ void add_spot ( float xpos, float ypos, float energy, float sigma, float weight); /* Compute beam modifiers, SOBP etc. according to the teatment strategy */ bool prepare_for_calc ( Plm_image::Pointer& ct_hu, Plm_image::Pointer& ct_psp, Plm_image::Pointer& target); /* Different strategies preparation */ void compute_beam_data_from_beamlet_map(); void compute_beam_data_from_spot_map(); void compute_beam_data_from_manual_peaks(); void compute_beam_data_from_manual_peaks(Plm_image::Pointer& target); void compute_beam_data_from_prescription(Plm_image::Pointer& target); void compute_beam_data_from_target(Plm_image::Pointer& target); void compute_default_beam(); /* This computes the aperture and range compensator */ void compute_beam_modifiers (Volume *seg_vol); void compute_beam_modifiers (Volume *seg_vol, std::vector& map_wed_min, std::vector& map_wed_max); void compute_beam_modifiers_active_scanning ( Volume *seg_vol, float smearing, float proximal_margin, float distal_margin); void compute_beam_modifiers_passive_scattering ( Volume *seg_vol, float smearing, float proximal_margin, float distal_margin); void compute_beam_modifiers_active_scanning ( Volume *seg_vol, float smearing, float proximal_margin, float distal_margin, std::vector& map_wed_min, std::vector& map_wed_max); void compute_beam_modifiers_passive_scattering ( Volume *seg_vol, float smearing, float proximal_margin, float distal_margin, std::vector& map_wed_min, std::vector& map_wed_max); void compute_beam_modifiers_core ( Volume *seg_vol, bool active, float smearing, float proximal_margin, float distal_margin, std::vector& map_wed_min, std::vector& map_wed_max); void apply_smearing_to_target ( float smearing, std::vector & map_min_distance, std::vector & map_max_distance); void compute_target_wepl_min_max ( std::vector& map_wed_min, std::vector& map_wed_max); /* copy the aperture and range compensator from the rpl_vol if not defined in the input file */ void update_aperture_and_range_compensator(); /* Set/ Get ct_psp */ Plm_image::Pointer& get_ct_psp (); const Plm_image::Pointer& get_ct_psp () const; void set_ct_psp(Plm_image::Pointer& ct_psp); /* Set/ Get target */ Plm_image::Pointer& get_target (); const Plm_image::Pointer& get_target () const; void set_target(Plm_image::Pointer& target); /* Set/ Get timer */ Rt_dose_timing::Pointer& get_rt_dose_timing (); void set_rt_dose_timing (Rt_dose_timing::Pointer& rt_dose_timing); /* Set/ Get dose_volume*/ Plm_image::Pointer& get_dose (); const Plm_image::Pointer& get_dose () const; void set_dose(Plm_image::Pointer& dose); /* Get aperture and range compensator */ Aperture::Pointer& get_aperture (); const Aperture::Pointer& get_aperture () const; Plm_image::Pointer& get_aperture_image (); const Plm_image::Pointer& get_aperture_image () const; const plm_long* get_aperture_dim () const; Plm_image::Pointer& get_range_compensator_image (); const Plm_image::Pointer& get_range_compensator_image () const; void set_aperture_vup (const float[]); void set_aperture_distance (float); void set_aperture_origin (const float[]); void set_aperture_resolution (const plm_long[]); void set_aperture_spacing (const float[]); void set_step_length(float step); float get_step_length(); /* Set smearing */ void set_smearing (float smearing); float get_smearing(); /* Set/Get intput file names */ void set_aperture_in (const std::string& str); std::string get_aperture_in(); void set_range_compensator_in (const std::string& str); std::string get_range_compensator_in(); /* Set/Get output file names */ void set_aperture_out(std::string str); std::string get_aperture_out(); void set_proj_dose_out(std::string str); std::string get_proj_dose_out(); void set_proj_img_out(std::string str); std::string get_proj_img_out(); void set_range_compensator_out(std::string str); std::string get_range_compensator_out(); void set_sigma_out(std::string str); std::string get_sigma_out(); void set_beam_dump_out(std::string str); std::string get_beam_dump_out(); void set_dij_out (const std::string& str); const std::string& get_dij_out(); void set_wed_out(std::string str); std::string get_wed_out(); void set_proj_target_out(std::string str); std::string get_proj_target_out(); void set_beam_line_type(std::string str); std::string get_beam_line_type(); bool get_intersection_with_aperture ( double* idx_ap, plm_long* idx, double* rest, double* ct_xyz); bool is_ray_in_the_aperture ( const plm_long* idx, const unsigned char* ap_img); /* computes the minimal geometric distance of the target for this beam -- used for smearing */ float compute_minimal_target_distance(Volume* target_vol, float background); /* functions that pass through to mebs object */ void set_energy_resolution (float eres); float get_energy_resolution () const; void set_proximal_margin (float proximal_margin); float get_proximal_margin() const; void set_distal_margin (float distal_margin); float get_distal_margin() const; void set_prescription (float prescription_min, float prescription_max); /* Save beam-specific output files to disk */ void save_beam_output (); public: /*** Volumes useful for dose calculation */ /* contains the target */ Rpl_volume::Pointer target_rv; /* contains the radiologic path length along a ray, according to stopping power */ Rpl_volume* rsp_accum_vol; /* contains HU, sampled at each point on the ray */ Rpl_volume* hu_samp_vol; // contains the sigma (lateral spread of the pencil beam, // used to calculate the off-axis term) along the ray Rpl_volume* sigma_vol; /* larger volumes for Hong and divergent geometry algorithms */ Rpl_volume* rpl_vol_lg; Rpl_volume* rpl_vol_samp_lg; Rpl_volume* sigma_vol_lg; Rpl_volume* dose_rv; private: bool load_xio (const char* fn); bool load_txt (const char* fn); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_beam_model.cxx000077500000000000000000000007251321604176500310750ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include "rt_beam_model.h" class Rt_beam_model_private { public: int i; }; Rt_beam_model::Rt_beam_model () { d_ptr = new Rt_beam_model_private; } Rt_beam_model::~Rt_beam_model () { delete d_ptr; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_beam_model.h000077500000000000000000000010461321604176500305170ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_beam_model_h_ #define _rt_beam_model_h_ #include "plmdose_config.h" #include "smart_pointer.h" class Rt_beam_model_private; class PLMDOSE_API Rt_beam_model { public: SMART_POINTER_SUPPORT (Rt_beam_model); Rt_beam_model_private *d_ptr; public: Rt_beam_model (); ~Rt_beam_model (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_depth_dose.cxx000066400000000000000000000221261321604176500311230ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include #include #include #include #include "bragg_curve.h" #include "rt_depth_dose.h" Rt_depth_dose::Rt_depth_dose () { this->d_lut = NULL; this->e_lut = NULL; this->f_lut = NULL; this->E0 = 100.0; this->spread = 1.0; this->dres = .01; this->dend = 400.0; this->index_of_dose_max = 0; this->num_samples = 40000; } Rt_depth_dose::Rt_depth_dose ( double E0, double spread, double dres, double dmax) { this->d_lut = NULL; this->e_lut = NULL; this->f_lut = NULL; this->E0 = E0; this->spread = spread; this->dres = dres; this->generate(); } Rt_depth_dose::~Rt_depth_dose () { if (this->d_lut) { free (this->d_lut); } if (this->e_lut) { free (this->e_lut); } if (this->f_lut) { free (this->f_lut); } } bool Rt_depth_dose::load (const char* fn) { FILE* fp = fopen (fn, "r"); char linebuf[128]; if (!fp) { return false; } fgets (linebuf, 128, fp); fclose (fp); if (!strncmp (linebuf, "00001037", strlen ("00001037"))) { return this->load_xio (fn); } else { return this->load_txt (fn); } } bool Rt_depth_dose::load_xio (const char* fn) { int i, j; char* ptoken; char linebuf[128]; FILE* fp = fopen (fn, "r"); // Need to check for a magic number (00001037) here? /* skip the first 4 lines */ for (i=0; i<4; i++) { fgets (linebuf, 128, fp); } /* line 5 contains the # of samples */ fgets (linebuf, 128, fp); sscanf (linebuf, "%i", &this->num_samples); this->d_lut = (float*)malloc (this->num_samples*sizeof(float)); this->e_lut = (float*)malloc (this->num_samples*sizeof(float)); this->f_lut = (float*)malloc (this->num_samples*sizeof(float)); memset (this->d_lut, 0, this->num_samples*sizeof(float)); memset (this->e_lut, 0, this->num_samples*sizeof(float)); memset (this->f_lut, 0, this->num_samples*sizeof(float)); /* load in the depths (10 samples per line) */ for (i=0, j=0; i<(this->num_samples/10)+1; i++) { fgets (linebuf, 128, fp); ptoken = strtok (linebuf, ",\n\0"); while (ptoken) { this->d_lut[j++] = (float) strtod (ptoken, NULL); ptoken = strtok (NULL, ",\n\0"); } } this->dend = this->d_lut[j-1]; /* load in the energies (10 samples per line) */ for (i=0, j=0; i<(this->num_samples/10)+1; i++) { fgets (linebuf, 128, fp); ptoken = strtok (linebuf, ",\n\0"); while (ptoken) { this->e_lut[j] = (float) strtod (ptoken, NULL); ptoken = strtok (NULL, ",\n\0"); j++; } } /* load in the energies (10 samples per line) */ for (i=0, j=0; i<(this->num_samples/10)+1; i++) { fgets (linebuf, 128, fp); ptoken = strtok (linebuf, ",\n\0"); while (ptoken) { this->f_lut[j] = (float) strtod (ptoken, NULL); ptoken = strtok (NULL, ",\n\0"); j++; } } fclose (fp); return true; } bool Rt_depth_dose::load_txt (const char* fn) { char linebuf[128]; FILE* fp = fopen (fn, "r"); while (fgets (linebuf, 128, fp)) { float range, dose; float dose_int =0; if (2 != sscanf (linebuf, "%f %f", &range, &dose)) { break; } dose_int += dose; this->num_samples++; this->d_lut = (float*) realloc ( this->d_lut, this->num_samples * sizeof(float)); this->e_lut = (float*) realloc ( this->e_lut, this->num_samples * sizeof(float)); this->f_lut = (float*) realloc ( this->f_lut, this->num_samples * sizeof(float)); this->d_lut[this->num_samples-1] = range; this->e_lut[this->num_samples-1] = dose; this->f_lut[this->num_samples-1] = dose_int; this->dend = range; /* Assume entries are sorted */ } fclose (fp); return true; } bool Rt_depth_dose::generate () { int i; double d; float max_prep = -1; float depth = -1; if (this->E0 > 190) {depth = 240;} // To accelerate the process and avoid the region where the dose decreases in the first mm (mathematic model) when E>190... float bragg = 0; while (bragg > max_prep) { max_prep = bragg; depth++; bragg = bragg_curve(this->E0, this->spread, depth); } this->dend = depth + 20; // 2 cm margins after the Bragg peak #if SPECFUN_FOUND if (!this->E0) { printf ("ERROR: Failed to generate beam -- energy not specified.\n"); return false; } if (!this->spread) { printf ("ERROR: Failed to generate beam -- energy spread not specified.\n"); return false; } if (!this->dend) { printf ("ERROR: Failed to generate beam -- max depth not specified.\n"); return false; } this->num_samples = (int) ceilf (this->dend / this->dres)+1; this->d_lut = (float*) malloc (this->num_samples*sizeof(float)); this->e_lut = (float*) malloc (this->num_samples*sizeof(float)); this->f_lut = (float*) malloc (this->num_samples*sizeof(float)); memset (this->d_lut, 0, this->num_samples*sizeof(float)); memset (this->e_lut, 0, this->num_samples*sizeof(float)); memset (this->f_lut, 0, this->num_samples*sizeof(float)); for (d=0, i=0; inum_samples; d+=this->dres, i++) { d_lut[i] = d; e_lut[i] = bragg_curve (this->E0, this->spread, d); } float max = 0; if (this->num_samples > 0) { max = e_lut[0]; for (int k = 1; k < this->num_samples; k++) { if (e_lut[k] > max) { max = e_lut[k]; this->index_of_dose_max = k; } } /* normalization and creation of the accumulated dose curve */ if (max > 0) { e_lut[0] /= max; f_lut[0] = e_lut[0] * this->dres; for (int k = 1; k < this->num_samples; k++) { e_lut[k] /= max; f_lut[k] = f_lut[k-1] + e_lut[k]*this->dres; } } else { printf("Error: Depth dose curve must have at least one value > 0.\n"); return false; } } return true; #else printf ("ERROR: No specfun found.\n"); return false; #endif } void Rt_depth_dose::dump (const char* fn) const { FILE* fp = fopen (fn, "w"); for (int i=0; inum_samples; i++) { fprintf (fp, "%3.2f %3.2f\n", this->d_lut[i], this->e_lut[i]); } fclose (fp); } int Rt_depth_dose::get_index_of_dose_max() { return index_of_dose_max; } float Rt_depth_dose::lookup_energy_integration (float depth, float dz) const { int i = 0; int j = 0; float energy = 0.0f; float dmin = depth - dz/2.0; float dmax = depth + dz/2.0; /* Sanity check */ if (depth + dz/2.0 < 0) { return 0.0f; } /* Find index into profile arrays */ for (i = 0; i < this->num_samples-1; i++) { if (this->d_lut[i]> dmin) { i--; break; } } for (j = i; j < this->num_samples; j++) { if (this->d_lut[j] > dmax) { j--; break; } } /* Use index to lookup and interpolate energy */ if (j >= 0 && j < this->num_samples-1) { // linear interpolation energy = this->f_lut[j] + (dmax - this->d_lut[j]) * ((this->f_lut[j+1] - this->f_lut[j]) / (this->d_lut[j+1] - this->d_lut[j])); } else { energy = this->f_lut[num_samples-1]; } if (i >= 0 && i < this->num_samples-1) { // linear interpolation energy -= this->f_lut[i] + (dmin - this->d_lut[i]) * ((this->f_lut[i+1] - this->f_lut[i]) / (this->d_lut[i+1] - this->d_lut[i])); } else if (i == num_samples-1) { energy -= this->f_lut[num_samples-1]; } return energy; } float Rt_depth_dose::lookup_energy (float depth) const { int i = 0; float energy = 0.0f; /* Sanity check */ if (depth < 0 || depth > dend) { return 0.0f; } /* Find index into profile arrays */ for (i = (int) floor(depth / dres); i < num_samples-1; i++) { if (d_lut[i] > depth) { i--; break; } } /* Clip input depth to maximum in lookup table */ if (i == num_samples-1) { depth = d_lut[i]; } /* Use index to lookup and interpolate energy */ if (i >= 0 || i < num_samples-1) { // linear interpolation energy = e_lut[i] + (depth - d_lut[i]) * ((e_lut[i+1] - e_lut[i]) / (d_lut[i+1] - d_lut[i])); } else { // we wen't past the end of the lookup table energy = 0.0f; } return energy; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_depth_dose.h000077500000000000000000000027751321604176500305630ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_depth_dose_h_ #define _rt_depth_dose_h_ #include "plmdose_config.h" class PLMDOSE_API Rt_depth_dose { public: Rt_depth_dose (); Rt_depth_dose (double E0, double spread, double dres, double dend); ~Rt_depth_dose (); bool load (const char* fn); /* load from file */ bool generate (); /* generate analytically */ /* debug: print bragg curve to file */ void dump (const char* fn) const; /* Get dose maximum information */ int get_index_of_dose_max(); float lookup_energy_integration(float depth, float dz) const; float lookup_energy (float depth) const; private: bool load_xio (const char* fn); bool load_txt (const char* fn); public: float* d_lut; /* depth array (mm) */ float* e_lut; /* energy array (MeV) */ float* f_lut; /* integrated energy array (MeV) */ float E0; /* initial ion energy (MeV) */ double spread; /* beam energy sigma (MeV) */ double dres; /* spatial resolution of bragg curve (mm)*/ double dend; /* maximum w.e.d. (mm) */ int num_samples; /* # of discrete bragg curve samples */ int index_of_dose_max; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_dij.cxx000077500000000000000000000032641321604176500275600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include #include "file_util.h" #include "string_util.h" #include "rpl_volume.h" #include "rt_dij.h" #include "volume_macros.h" void Rt_dij::set_from_dose_rv ( const plm_long ij[2], size_t energy_index, const Rpl_volume *dose_rv, const Volume::Pointer& dose_vol) { this->rows.push_back (Rt_dij_row ( float (ij[0]), float (ij[1]), float (energy_index))); Rt_dij_row& rt_dij_row = this->rows.back (); const Volume *dose = dose_vol.get(); plm_long ijk[3]; double xyz[3]; LOOP_Z (ijk, xyz, dose) { LOOP_Y (ijk, xyz, dose) { LOOP_X (ijk, xyz, dose) { plm_long idx = dose->index (ijk); float val = dose_rv->get_value (xyz); if (val > 0.f) { rt_dij_row.dose.push_back (Rt_dij_dose (idx, val)); } } } } } void Rt_dij::dump (const std::string& dir) const { int i = 0; std::list::const_iterator r = rows.begin(); while (r != rows.end()) { std::string fn = string_format ("%s/dij_%04d.txt", dir.c_str(), i++); FILE *fp = plm_fopen (fn, "w"); fprintf (fp, "%f %f %f\n", r->xpos, r->ypos, r->energy); std::list::const_iterator c = r->dose.begin(); while (c != r->dose.end()) { fprintf (fp, "%d %f\n", c->index, c->dose); c++; } fclose (fp); ++r; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_dij.h000077500000000000000000000021121321604176500271740ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_dij_h_ #define _rt_dij_h_ #include "plmdose_config.h" #include "smart_pointer.h" #include "volume.h" class Rpl_volume; class Rt_dij_private; class PLMDOSE_API Rt_dij_dose { public: Rt_dij_dose (size_t index, float dose) : index(index), dose(dose) {} public: size_t index; float dose; }; class PLMDOSE_API Rt_dij_row { public: Rt_dij_row ( float xpos, float ypos, float energy) : xpos(xpos), ypos(ypos), energy(energy) {} public: float xpos; float ypos; float energy; std::list dose; }; class PLMDOSE_API Rt_dij { public: std::list rows; public: void set_from_dose_rv ( const plm_long ij[2], size_t energy_index, const Rpl_volume *dose_rv, const Volume::Pointer& dose_vol); void dump (const std::string& dir) const; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_dose.cxx000077500000000000000000000476431321604176500277550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include #include #include #include "aperture.h" #include "dose_volume_functions.h" #include "interpolate.h" #include "plm_image.h" #include "plm_math.h" #include "print_and_exit.h" #include "proj_matrix.h" #include "proj_volume.h" #include "ray_data.h" #include "ray_trace.h" #include "rpl_volume.h" #include "rpl_volume_lut.h" #include "rt_beam.h" #include "rt_depth_dose.h" #include "rt_dij.h" #include "rt_dose.h" #include "rt_lut.h" #include "rt_mebs.h" #include "rt_plan.h" #include "rt_sigma.h" #include "string_util.h" #include "threading.h" #include "volume.h" /* Ray Tracer */ double energy_direct ( float rgdepth, /* voxel to dose */ Rt_beam* beam, int beam_idx ) { /* The voxel was not hit directly by the beam */ if (rgdepth <= 0.0f) { return 0.0f; } /* return the dose at this radiographic depth */ return (double) beam->get_mebs()->get_depth_dose()[beam_idx]->lookup_energy(rgdepth); } void compute_dose_a ( Volume::Pointer dose_vol, Rt_beam* beam, const Volume::Pointer ct_vol ) { float* dose_img = (float*) dose_vol->img; Aperture::Pointer& ap = beam->get_aperture (); Volume *ap_vol = 0; const unsigned char *ap_img = 0; if (ap->have_aperture_image()) { ap_vol = ap->get_aperture_vol (); ap_img = ap_vol->get_raw (); } /* Dose D(POI) = Dose(z_POI) but z_POI = rg_comp + depth in CT, if there is a range compensator */ if (ap->have_range_compensator_image()) { add_rcomp_length_to_rpl_volume(beam); } /* scan through patient CT Volume */ plm_long ct_ijk[3]; double ct_xyz[4]; plm_long idx = 0; double idx_ap[2] = {0,0}; plm_long idx_ap_int[2] = {0,0}; double rest[2] = {0,0}; double particle_number = 0; float WER = 0; float rgdepth = 0; for (ct_ijk[2] = 0; ct_ijk[2] < ct_vol->dim[2]; ct_ijk[2]++) { for (ct_ijk[1] = 0; ct_ijk[1] < ct_vol->dim[1]; ct_ijk[1]++) { for (ct_ijk[0] = 0; ct_ijk[0] < ct_vol->dim[0]; ct_ijk[0]++) { double dose = 0.0; /* Transform vol index into space coords */ ct_xyz[0] = (double) (ct_vol->origin[0] + ct_ijk[0] * ct_vol->spacing[0]); ct_xyz[1] = (double) (ct_vol->origin[1] + ct_ijk[1] * ct_vol->spacing[1]); ct_xyz[2] = (double) (ct_vol->origin[2] + ct_ijk[2] * ct_vol->spacing[2]); ct_xyz[3] = (double) 1.0; if (beam->get_intersection_with_aperture(idx_ap, idx_ap_int, rest, ct_xyz) == false) { continue; } /* Check that the ray cross the aperture */ if (idx_ap[0] < 0 || idx_ap[0] > (double) beam->hu_samp_vol->get_proj_volume()->get_image_dim(0)-1 || idx_ap[1] < 0 || idx_ap[1] > (double) beam->hu_samp_vol->get_proj_volume()->get_image_dim(1)-1) { continue; } /* Check that the ray cross the active part of the aperture */ if (ap_img && beam->is_ray_in_the_aperture(idx_ap_int, ap_img) == false) { continue; } dose = 0; rgdepth = beam->rsp_accum_vol->get_value (ct_xyz); WER = compute_PrWER_from_HU (beam->hu_samp_vol->get_value(ct_xyz)); const Rt_mebs::Pointer& mebs = beam->get_mebs(); for (size_t dd_idx = 0; dd_idx < mebs->get_depth_dose().size(); dd_idx++) { particle_number = mebs->get_particle_number_xyz (idx_ap_int, rest, dd_idx, beam->get_aperture()->get_dim()); if (particle_number != 0 && rgdepth >=0 && rgdepth < mebs->get_depth_dose()[dd_idx]->dend) { dose += particle_number * WER * energy_direct (rgdepth, beam, dd_idx); } } /* Insert the dose into the dose volume */ idx = volume_index (dose_vol->dim, ct_ijk); dose_img[idx] = dose; } } } } void compute_dose_b ( Rt_beam* beam, size_t energy_index, const Volume::Pointer ct_vol ) { Rpl_volume *wepl_rv = beam->rsp_accum_vol; Volume *wepl_vol = wepl_rv->get_vol(); float *wepl_img = wepl_vol->get_raw (); Rpl_volume *dose_rv = beam->dose_rv; Volume *dose_rv_vol = dose_rv->get_vol(); float *dose_rv_img = dose_rv_vol->get_raw (); Rt_mebs::Pointer mebs = beam->get_mebs(); const Rt_depth_dose *depth_dose = mebs->get_depth_dose()[energy_index]; std::vector& num_part = mebs->get_num_particles(); /* scan through rpl volume */ Aperture::Pointer& ap = beam->get_aperture (); Volume *ap_vol = 0; const unsigned char *ap_img = 0; if (ap->have_aperture_image()) { ap_vol = ap->get_aperture_vol (); ap_img = ap_vol->get_raw (); } const plm_long *dim = wepl_rv->get_image_dim(); int num_steps = wepl_rv->get_num_steps(); plm_long ij[2] = {0,0}; for (ij[1] = 0; ij[1] < dim[1]; ij[1]++) { for (ij[0] = 0; ij[0] < dim[0]; ij[0]++) { if (ap_img && ap_img[ap_vol->index(ij[0],ij[1],0)] == 0) { continue; } size_t np_index = energy_index * dim[0] * dim[1] + ij[1] * dim[0] + ij[0]; float np = num_part[np_index]; if (np == 0.f) { continue; } for (int s = 0; s < num_steps; s++) { int dose_index = ap_vol->index(ij[0],ij[1],s); float wepl = wepl_img[dose_index]; dose_rv_img[dose_index] += np * depth_dose->lookup_energy(wepl); } } } } void compute_dose_ray_trace_dij_a ( Rt_beam* beam, size_t energy_index, const Volume::Pointer ct_vol, Volume::Pointer& dose_vol ) { float* dose_img = (float*) dose_vol->img; /* Dose D(POI) = Dose(z_POI) but z_POI = rg_comp + depth in CT, if there is a range compensator */ if (beam->get_aperture()->have_range_compensator_image()) { add_rcomp_length_to_rpl_volume(beam); } /* scan through patient CT Volume */ plm_long ct_ijk[3]; double ct_xyz[4]; plm_long idx = 0; double idx_ap[2] = {0,0}; plm_long idx_ap_int[2] = {0,0}; double rest[2] = {0,0}; unsigned char* ap_img = (unsigned char*) beam->get_aperture()->get_aperture_volume()->img; double particle_number = 0; float WER = 0; float rgdepth = 0; for (ct_ijk[2] = 0; ct_ijk[2] < ct_vol->dim[2]; ct_ijk[2]++) { for (ct_ijk[1] = 0; ct_ijk[1] < ct_vol->dim[1]; ct_ijk[1]++) { for (ct_ijk[0] = 0; ct_ijk[0] < ct_vol->dim[0]; ct_ijk[0]++) { double dose = 0.0; /* Transform vol index into space coords */ ct_xyz[0] = (double) (ct_vol->origin[0] + ct_ijk[0] * ct_vol->spacing[0]); ct_xyz[1] = (double) (ct_vol->origin[1] + ct_ijk[1] * ct_vol->spacing[1]); ct_xyz[2] = (double) (ct_vol->origin[2] + ct_ijk[2] * ct_vol->spacing[2]); ct_xyz[3] = (double) 1.0; if (beam->get_intersection_with_aperture (idx_ap, idx_ap_int, rest, ct_xyz) == false) { continue; } /* Check that the ray cross the aperture */ if (idx_ap[0] < 0 || idx_ap[0] > (double) beam->hu_samp_vol->get_proj_volume()->get_image_dim(0)-1 || idx_ap[1] < 0 || idx_ap[1] > (double) beam->hu_samp_vol->get_proj_volume()->get_image_dim(1)-1) { continue; } /* Check that the ray cross the active part of the aperture */ if (beam->get_aperture()->have_aperture_image() && beam->is_ray_in_the_aperture (idx_ap_int, ap_img) == false) { continue; } dose = 0; rgdepth = beam->rsp_accum_vol->get_value (ct_xyz); WER = compute_PrWER_from_HU (beam->hu_samp_vol->get_value(ct_xyz)); const Rt_mebs::Pointer& mebs = beam->get_mebs(); for (size_t dd_idx = 0; dd_idx < mebs->get_depth_dose().size(); dd_idx++) { particle_number = mebs->get_particle_number_xyz (idx_ap_int, rest, dd_idx, beam->get_aperture()->get_dim()); if (particle_number != 0 && rgdepth >=0 && rgdepth < mebs->get_depth_dose()[dd_idx]->dend) { dose += particle_number * WER * energy_direct (rgdepth, beam, dd_idx); } } /* Insert the dose into the dose volume */ idx = volume_index (dose_vol->dim, ct_ijk); dose_img[idx] = dose; } } } } void compute_dose_ray_trace_dij_b ( Rt_beam* beam, const Volume::Pointer ct_vol, Volume::Pointer& dose_vol ) { Rpl_volume *wepl_rv = beam->rsp_accum_vol; Volume *wepl_vol = wepl_rv->get_vol(); float *wepl_img = wepl_vol->get_raw (); Rpl_volume *dose_rv = beam->dose_rv; Volume *dose_rv_vol = dose_rv->get_vol(); float *dose_rv_img = dose_rv_vol->get_raw (); Rt_mebs::Pointer mebs = beam->get_mebs(); const std::vector depth_dose = mebs->get_depth_dose(); std::vector& num_part = mebs->get_num_particles(); /* Create the beamlet dij matrix */ Rt_dij rt_dij; /* Create geometry map from volume to rpl_volume */ Rpl_volume_lut rpl_volume_lut (dose_rv, dose_vol.get()); rpl_volume_lut.build_lut (); /* scan through rpl volume */ Aperture::Pointer& ap = beam->get_aperture (); Volume *ap_vol = 0; const unsigned char *ap_img = 0; if (ap->have_aperture_image()) { ap_vol = ap->get_aperture_vol (); ap_img = ap_vol->get_raw (); } const plm_long *dim = wepl_rv->get_image_dim(); int num_steps = wepl_rv->get_num_steps(); plm_long ij[2] = {0,0}; for (ij[1] = 0; ij[1] < dim[1]; ij[1]++) { for (ij[0] = 0; ij[0] < dim[0]; ij[0]++) { if (ap_img && ap_img[ap_vol->index(ij[0],ij[1],0)] == 0) { continue; } for (size_t energy_index = 0; energy_index < depth_dose.size(); energy_index++) { // Get beamlet weight size_t np_index = energy_index * dim[0] * dim[1] + ij[1] * dim[0] + ij[0]; float np = num_part[np_index]; if (np == 0.f) { continue; } // Fill in dose const Rt_depth_dose *dd = depth_dose[energy_index]; for (int s = 0; s < num_steps; s++) { int dose_index = ap_vol->index(ij[0],ij[1],s); float wepl = wepl_img[dose_index]; dose_rv_img[dose_index] = np * dd->lookup_energy(wepl); } // Create beamlet dij rt_dij.set_from_dose_rv ( ij, energy_index, dose_rv, ct_vol); // Zero out again for (int s = 0; s < num_steps; s++) { int dose_index = ap_vol->index(ij[0],ij[1],s); dose_rv_img[dose_index] = 0.f; } } } } // Write beamlet dij if (beam->get_dij_out() != "") { rt_dij.dump (beam->get_dij_out()); } } void compute_dose_d ( Rt_beam* beam, size_t energy_index, const Volume::Pointer ct_vol ) { beam->get_rt_dose_timing()->timer_dose_calc.resume (); Rpl_volume *wepl_rv = beam->rsp_accum_vol; Volume *wepl_vol = wepl_rv->get_vol(); float *wepl_img = wepl_vol->get_raw (); Rpl_volume *dose_rv = beam->dose_rv; Volume *dose_rv_vol = dose_rv->get_vol(); float *dose_rv_img = dose_rv_vol->get_raw (); Rt_mebs::Pointer mebs = beam->get_mebs(); const Rt_depth_dose *depth_dose = mebs->get_depth_dose()[energy_index]; std::vector& num_part = mebs->get_num_particles(); beam->get_rt_dose_timing()->timer_dose_calc.stop (); // Compute sigma for this energy beam->get_rt_dose_timing()->timer_sigma.resume (); int margins[2] = {0,0}; float sigma_max = 0; compute_sigmas (beam, depth_dose->E0, &sigma_max, "small", margins); beam->get_rt_dose_timing()->timer_sigma.stop (); beam->get_rt_dose_timing()->timer_dose_calc.resume (); Rpl_volume *sigma_rv = beam->sigma_vol; Volume *sigma_vol = sigma_rv->get_vol(); float *sigma_img = sigma_vol->get_raw (); const plm_long *sigma_dim = sigma_vol->get_dim(); // Get the variable magnification at each step std::vector lateral_spacing_0 (sigma_dim[2],0); std::vector lateral_spacing_1 (sigma_dim[2],0); double sid = sigma_rv->get_aperture()->get_distance(); const double *ap_spacing = sigma_rv->get_aperture()->get_spacing(); float clipping_dist = sigma_rv->get_front_clipping_plane(); float step_length = sigma_rv->get_step_length (); for (int k = 0; k < sigma_dim[2]; k++) { float mag = (sid + clipping_dist + k * step_length) / sid; lateral_spacing_0[k] = ap_spacing[0] * mag; lateral_spacing_1[k] = ap_spacing[1] * mag; } // Compute lateral search distance (2.5 max sigma) for each depth // (Only needed if pulling dose, not needed if pushing) // GCS FIX: This need only be computed once per beam, not once per energy std::vector lateral_step_0 (sigma_dim[2],0); std::vector lateral_step_1 (sigma_dim[2],0); for (int k = 0; k < sigma_dim[2]; k++) { float sigma_max = 0.f; for (int i = 0; i < sigma_dim[0]*sigma_dim[1]; i++) { plm_long idx = k*sigma_dim[0]*sigma_dim[1] + i; if (sigma_img[idx] > sigma_max) { sigma_max = sigma_img[idx]; } } lateral_step_0[k] = ceil (2.5 * sigma_max / lateral_spacing_0[k]); lateral_step_1[k] = ceil (2.5 * sigma_max / lateral_spacing_1[k]); } // Create central axis dose volume Rpl_volume *cax_dose_rv = new Rpl_volume; if (!cax_dose_rv) return; cax_dose_rv->clone_geometry (wepl_rv); cax_dose_rv->set_ray_trace_start (RAY_TRACE_START_AT_CLIPPING_PLANE); cax_dose_rv->set_aperture (beam->get_aperture()); cax_dose_rv->set_ct (wepl_rv->get_ct()); cax_dose_rv->set_ct_limit (wepl_rv->get_ct_limit()); cax_dose_rv->compute_ray_data(); cax_dose_rv->set_front_clipping_plane (wepl_rv->get_front_clipping_plane()); cax_dose_rv->set_back_clipping_plane (wepl_rv->get_back_clipping_plane()); cax_dose_rv->compute_rpl_void (); Volume *cax_dose_vol = cax_dose_rv->get_vol (); float *cax_dose_img = cax_dose_vol->get_raw (); // Compute central axis dose Aperture::Pointer& ap = beam->get_aperture (); Volume *ap_vol = 0; const unsigned char *ap_img = 0; if (ap->have_aperture_image()) { ap_vol = ap->get_aperture_vol (); ap_img = ap_vol->get_raw (); } const plm_long *dim = wepl_rv->get_image_dim(); plm_long num_steps = wepl_rv->get_num_steps(); plm_long ij[2] = {0,0}; for (ij[1] = 0; ij[1] < dim[1]; ij[1]++) { for (ij[0] = 0; ij[0] < dim[0]; ij[0]++) { if (ap_img && ap_img[ap_vol->index(ij[0],ij[1],0)] == 0) { continue; } size_t np_index = energy_index * dim[0] * dim[1] + ij[1] * dim[0] + ij[0]; float np = num_part[np_index]; if (np == 0.f) { continue; } for (int s = 0; s < num_steps; s++) { int dose_index = ap_vol->index(ij[0],ij[1],s); float wepl = wepl_img[dose_index]; cax_dose_img[dose_index] += np * depth_dose->lookup_energy(wepl); } } } /* Save sigma volume */ if (beam->get_sigma_out() != "") { std::string fn; fn = string_format ("%s/cax-%02d", beam->get_sigma_out().c_str(), energy_index); cax_dose_rv->save (fn); fn = string_format ("%s/sig-%02d", beam->get_sigma_out().c_str(), energy_index); sigma_rv->save (fn); } // Smear dose by specified sigma for (int s = 0; s < num_steps; s++) { double pixel_spacing[2] = { lateral_spacing_0[s], lateral_spacing_1[s] }; for (ij[1] = 0; ij[1] < dim[1]; ij[1]++) { for (ij[0] = 0; ij[0] < dim[0]; ij[0]++) { plm_long idx = s*sigma_dim[0]*sigma_dim[1] + ij[1]*dim[0] + ij[0]; float cax_dose = cax_dose_img[idx]; if (cax_dose == 0.f) { continue; } double sigma = (double) sigma_img[idx]; double sigma_x3 = sigma * 2.5; // finding the rpl_volume pixels that are contained in the // the 3 sigma range plm_long ij_min[2], ij_max[2]; ij_min[0] = ij[0] - ceil (sigma_x3 / lateral_spacing_0[s]); if (ij_min[0] < 0) ij_min[0] = 0; ij_min[1] = ij[1] - ceil (sigma_x3 / lateral_spacing_1[s]); if (ij_min[1] < 0) ij_min[1] = 0; ij_max[0] = ij[0] + ceil (sigma_x3 / lateral_spacing_0[s]); if (ij_max[0] > dim[0]-1) ij_max[0] = dim[0]-1; ij_max[1] = ij[1] + ceil (sigma_x3 / lateral_spacing_1[s]); if (ij_max[1] > dim[1]-1) ij_max[1] = dim[1]-1; float tot_off_axis = 0.f; plm_long ij1[2]; for (ij1[1] = ij_min[1]; ij1[1] <= ij_max[1]; ij1[1]++) { for (ij1[0] = ij_min[0]; ij1[0] <= ij_max[0]; ij1[0]++) { plm_long idxs = s*sigma_dim[0]*sigma_dim[1] + ij1[1]*dim[0] + ij1[0]; double gaussian_center[2] = { 0., 0. }; double pixel_center[2] = { (double) ij1[0]-ij[0], (double) ij1[1]-ij[1] }; double off_axis_factor; if (sigma == 0) { off_axis_factor = 1; } else { off_axis_factor = double_gaussian_interpolation ( gaussian_center, pixel_center, sigma, pixel_spacing); } dose_rv_img[idxs] += cax_dose * off_axis_factor; #if defined (commentout) // GCS FIX: The below correction would give the // option for dose to tissue / ct_density / STPR; #endif tot_off_axis += off_axis_factor; } } } } } // Free temporary memory delete cax_dose_rv; beam->get_rt_dose_timing()->timer_dose_calc.stop (); } void add_rcomp_length_to_rpl_volume (Rt_beam* beam) { const plm_long *dim = beam->rsp_accum_vol->get_vol()->dim; float* rpl_img = (float*) beam->rsp_accum_vol->get_vol()->img; float* rc_img = (float*) beam->rsp_accum_vol->get_aperture()->get_range_compensator_volume()->img; int idx = 0; for(int i = 0; i < dim[0] * dim[1]; i++) { for (int k = 0; k < dim[2]; k++) { idx = i + k * dim[0] * dim[1]; rpl_img[idx] += rc_img[i] * PMMA_DENSITY*PMMA_STPR; // Lucite material : d * rho * WER } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_dose.h000077500000000000000000000032761321604176500273740ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_dose_h_ #define _rt_dose_h_ #include "aperture.h" #include "rt_depth_dose.h" #include "rt_plan.h" #include "plmdose_config.h" #include "plm_image.h" double energy_direct ( float rgdepth, /* voxel to dose */ Rt_beam* beam, int beam_idx ); void compute_dose_a ( Volume::Pointer dose_vol, Rt_beam* beam, const Volume::Pointer ct_vol ); void compute_dose_b ( Rt_beam* beam, size_t energy_index, const Volume::Pointer ct_vol ); void compute_dose_ray_trace_dij_a ( Rt_beam* beam, size_t energy_index, const Volume::Pointer ct_vol, Volume::Pointer& dose_vol ); void compute_dose_ray_trace_dij_b ( Rt_beam* beam, const Volume::Pointer ct_vol, Volume::Pointer& dose_vol ); void compute_dose_d ( Rt_beam* beam, size_t energy_index, const Volume::Pointer ct_vol ); void compute_dose_ray_desplanques ( Volume* dose_volume, Volume::Pointer ct_vol, Rt_beam* beam, Volume::Pointer final_dose_volume, int beam_index ); void compute_dose_ray_sharp ( const Volume::Pointer ct_vol, Rt_beam* beam, Rpl_volume* rpl_dose_volume, int beam_index, const int* margins ); void compute_dose_ray_shackleford ( Volume::Pointer dose_volume, Rt_plan* plan, Rt_beam *beam, int beam_index, std::vector* area, std::vector* xy_grid, int radius_sample, int theta_sample ); void add_rcomp_length_to_rpl_volume(Rt_beam* beam); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_dose_timing.h000066400000000000000000000022201321604176500307240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_dose_timing_h_ #define _rt_dose_timing_h_ #include "plmdose_config.h" #include "logfile.h" #include "plm_timer.h" #include "smart_pointer.h" class Rt_dose_timing { public: SMART_POINTER_SUPPORT (Rt_dose_timing); public: Plm_timer timer_sigma; Plm_timer timer_dose_calc; Plm_timer timer_reformat; Plm_timer timer_io; Plm_timer timer_misc; public: void reset () { timer_sigma.reset (); timer_dose_calc.reset (); timer_reformat.reset (); timer_io.reset (); timer_misc.reset (); } void report () { lprintf ("Sigma: %f seconds\n", timer_sigma.report()); lprintf ("Calc: %f seconds\n", timer_dose_calc.report()); lprintf ("IO: %f seconds\n", timer_io.report()); lprintf ("Reformat: %f seconds\n", timer_reformat.report()); lprintf ("Misc: %f seconds\n", timer_misc.report()); }; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_lut.cxx000066400000000000000000000226421321604176500276140ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include "rt_lut.h" #include "rpl_volume.h" // for PMMA constants double get_proton_range(double energy) { int i_lo = 0, i_hi = PROTON_TABLE_SIZE; double energy_lo = lookup_proton_range_water[i_lo][0]; double range_lo = lookup_proton_range_water[i_lo][1]; double energy_hi = lookup_proton_range_water[i_hi][0]; double range_hi = lookup_proton_range_water[i_hi][1]; if (energy <= energy_lo) { return range_lo; } if (energy >= energy_hi) { return range_hi; } /* Use binary search to find lookup table entries */ for (int dif = i_hi - i_lo; dif > 1; dif = i_hi - i_lo) { int i_test = i_lo + ((dif + 1) / 2); double energy_test = lookup_proton_range_water[i_test][0]; if (energy > energy_test) { energy_lo = energy_test; i_lo = i_test; } else { energy_hi = energy_test; i_hi = i_test; } } range_lo = lookup_proton_range_water[i_lo][1]; range_hi = lookup_proton_range_water[i_hi][1]; return range_lo + (energy-energy_lo) * (range_hi-range_lo) / (energy_hi-energy_lo); } double get_proton_stop (double energy) { int i_lo = 0, i_hi = PROTON_TABLE_SIZE; double energy_lo = lookup_proton_stop_water[i_lo][0]; double stop_lo = lookup_proton_stop_water[i_lo][1]; double energy_hi = lookup_proton_stop_water[i_hi][0]; double stop_hi = lookup_proton_stop_water[i_hi][1]; if (energy <= energy_lo) { return stop_lo; } if (energy >= energy_hi) { return stop_hi; } /* Use binary search to find lookup table entries */ for (int dif = i_hi - i_lo; dif > 1; dif = i_hi - i_lo) { int i_test = i_lo + ((dif + 1) / 2); double energy_test = lookup_proton_stop_water[i_test][0]; if (energy > energy_test) { energy_lo = energy_test; i_lo = i_test; } else { energy_hi = energy_test; i_hi = i_test; } } stop_lo = lookup_proton_stop_water[i_lo][1]; stop_hi = lookup_proton_stop_water[i_hi][1]; return stop_lo + (energy-energy_lo) * (stop_hi-stop_lo) / (energy_hi-energy_lo); } double get_theta0_Highland(double range) { /* lucite sigma0 (in rads) computing- From the figure A2 of the Hong's paper (be careful, in this paper the fit shows sigma0^2)*/ if (range > 150) { return 0.05464 + 5.8348E-6 * range -5.21006E-9 * range * range; } else { return 0.05394 + 1.80222E-5 * range -5.5430E-8 * range * range; } } double get_theta0_MC(float energy) { return 4.742E-6 * energy * energy -1.918E-3 * energy + 1.158; } double get_theta_rel_Highland(double rc_over_range) { return rc_over_range * ( 1.6047 -2.7295 * rc_over_range + 2.1578 * rc_over_range * rc_over_range); } double get_theta_rel_MC(double rc_over_range) { return 3.833E-2 * pow(rc_over_range, 0.657) + 2.118E-2 * pow(rc_over_range, 6.528); } double get_scat_or_Highland(double rc_over_range) { /* calculation of rc_eff - see Hong's paper graph A3 - linear interpolation of the curve */ if (rc_over_range >= 0 && rc_over_range < 0.5) { return 1 - (0.49 + 0.060 / 0.5 * rc_over_range); } else if (rc_over_range >= 0.5 && rc_over_range <0.8) { return 1 - (0.55 + 0.085 / 0.3 * (rc_over_range-0.5)); } else if (rc_over_range >= 0.8 && rc_over_range <0.9) { return 1 - (0.635 + 0.055 / 0.1 * (rc_over_range-0.8)); } else if (rc_over_range >= 0.9 && rc_over_range <0.95) { return 1 - (0.690 + (rc_over_range-0.9)); } else if (rc_over_range >= 0.95 && rc_over_range <= 1) { return 1 - (0.740 + 0.26/0.05 * (rc_over_range-0.95)); } else if (rc_over_range > 1) { return 0; } else { return 0; } } double get_scat_or_MC (double rc_over_range) { return 0.023 * rc_over_range + 0.332; } double compute_X0_from_HU (double CT_HU) { if (CT_HU <= -1000) { return 30390; } else if (CT_HU > -1000 && CT_HU< 0) { return exp(3.7271E-06 * CT_HU * CT_HU -3.009E-03 * CT_HU + 3.5857); } else if (CT_HU >= 0 && CT_HU < 55) { return -0.0284 * CT_HU + 36.08; } else { return 9.8027E-06 * CT_HU * CT_HU -.028939 * CT_HU + 36.08; } } /* Make GCC compiler less whiny */ #if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 2) #pragma GCC diagnostic ignored "-Wmissing-braces" #endif /* This table has 111 entries */ const double lookup_proton_range_water[][2] ={ 1.000E-03, 6.319E-06, 1.500E-03, 8.969E-06, 2.000E-03, 1.137E-05, 2.500E-03, 1.357E-05, 3.000E-03, 1.560E-05, 4.000E-03, 1.930E-05, 5.000E-03, 2.262E-05, 6.000E-03, 2.567E-05, 7.000E-03, 2.849E-05, 8.000E-03, 3.113E-05, 9.000E-03, 3.363E-05, 1.000E-02, 3.599E-05, 1.250E-02, 4.150E-05, 1.500E-02, 4.657E-05, 1.750E-02, 5.131E-05, 2.000E-02, 5.578E-05, 2.250E-02, 6.005E-05, 2.500E-02, 6.413E-05, 2.750E-02, 6.806E-05, 3.000E-02, 7.187E-05, 3.500E-02, 7.916E-05, 4.000E-02, 8.613E-05, 4.500E-02, 9.284E-05, 5.000E-02, 9.935E-05, 5.500E-02, 1.057E-04, 6.000E-02, 1.120E-04, 6.500E-02, 1.182E-04, 7.000E-02, 1.243E-04, 7.500E-02, 1.303E-04, 8.000E-02, 1.364E-04, 8.500E-02, 1.425E-04, 9.000E-02, 1.485E-04, 9.500E-02, 1.546E-04, 1.000E-01, 1.607E-04, 1.250E-01, 1.920E-04, 1.500E-01, 2.249E-04, 1.750E-01, 2.598E-04, 2.000E-01, 2.966E-04, 2.250E-01, 3.354E-04, 2.500E-01, 3.761E-04, 2.750E-01, 4.186E-04, 3.000E-01, 4.631E-04, 3.500E-01, 5.577E-04, 4.000E-01, 6.599E-04, 4.500E-01, 7.697E-04, 5.000E-01, 8.869E-04, 5.500E-01, 1.012E-03, 6.000E-01, 1.144E-03, 6.500E-01, 1.283E-03, 7.000E-01, 1.430E-03, 7.500E-01, 1.584E-03, 8.000E-01, 1.745E-03, 8.500E-01, 1.913E-03, 9.000E-01, 2.088E-03, 9.500E-01, 2.270E-03, 1.000E+00, 2.458E-03, 1.250E+00, 3.499E-03, 1.500E+00, 4.698E-03, 1.750E+00, 6.052E-03, 2.000E+00, 7.555E-03, 2.250E+00, 9.203E-03, 2.500E+00, 1.099E-02, 2.750E+00, 1.292E-02, 3.000E+00, 1.499E-02, 3.500E+00, 1.952E-02, 4.000E+00, 2.458E-02, 4.500E+00, 3.015E-02, 5.000E+00, 3.623E-02, 5.500E+00, 4.279E-02, 6.000E+00, 4.984E-02, 6.500E+00, 5.737E-02, 7.000E+00, 6.537E-02, 7.500E+00, 7.384E-02, 8.000E+00, 8.277E-02, 8.500E+00, 9.215E-02, 9.000E+00, 1.020E-01, 9.500E+00, 1.123E-01, 1.000E+01, 1.230E-01, 1.250E+01, 1.832E-01, 1.500E+01, 2.539E-01, 1.750E+01, 3.350E-01, 2.000E+01, 4.260E-01, 2.500E+01, 6.370E-01, 2.750E+01, 7.566E-01, 3.000E+01, 8.853E-01, 3.500E+01, 1.170E+00, 4.000E+01, 1.489E+00, 4.500E+01, 1.841E+00, 5.000E+01, 2.227E+00, 5.500E+01, 2.644E+00, 6.000E+01, 3.093E+00, 6.500E+01, 3.572E+00, 7.000E+01, 4.080E+00, 7.500E+01, 4.618E+00, 8.000E+01, 5.184E+00, 8.500E+01, 5.777E+00, 9.000E+01, 6.398E+00, 9.500E+01, 7.045E+00, 1.000E+02, 7.718E+00, 1.250E+02, 1.146E+01, 1.500E+02, 1.577E+01, 1.750E+02, 2.062E+01, 2.000E+02, 2.596E+01, 2.250E+02, 3.174E+01, 2.500E+02, 3.794E+01, 2.750E+02, 4.452E+01, 3.000E+02, 5.145E+01, 3.500E+02, 6.628E+01, 4.000E+02, 8.225E+01, 4.500E+02, 9.921E+01, 5.000E+02, 1.170E+02, }; /* This table has 111 entries */ const double lookup_proton_stop_water[][2] = { 0.0010, 176.9, 0.0015, 198.4, 0.0020, 218.4, 0.0025, 237.0, 0.0030, 254.4, 0.0040, 286.4, 0.0050, 315.3, 0.0060, 342.0, 0.0070, 366.7, 0.0080, 390.0, 0.0090, 412.0, 0.0100, 432.9, 0.0125, 474.5, 0.0150, 511.0, 0.0175, 543.7, 0.0200, 573.3, 0.0225, 600.1, 0.0250, 624.5, 0.0275, 646.7, 0.0300, 667.1, 0.0350, 702.8, 0.0400, 732.4, 0.0450, 756.9, 0.0500, 776.8, 0.0550, 792.7, 0.0600, 805.0, 0.0650, 814.2, 0.0700, 820.5, 0.0750, 824.3, 0.0800, 826.0, 0.0850, 825.8, 0.0900, 823.9, 0.0950, 820.6, 0.1000, 816.1, 0.1250, 781.4, 0.1500, 737.1, 0.1750, 696.9, 0.2000, 661.3, 0.2250, 629.4, 0.2500, 600.6, 0.2750, 574.4, 0.3000, 550.4, 0.3500, 508.0, 0.4000, 471.9, 0.4500, 440.6, 0.5000, 413.2, 0.5500, 389.1, 0.6000, 368.0, 0.6500, 349.2, 0.7000, 332.5, 0.7500, 317.5, 0.8000, 303.9, 0.8500, 291.7, 0.9000, 280.5, 0.9500, 270.2, 1.0000, 260.8, 1.2500, 222.9, 1.5000, 195.7, 1.7500, 174.9, 2.0000, 158.6, 2.2500, 145.4, 2.5000, 134.4, 2.7500, 125.1, 3.0000, 117.2, 3.5000, 104.2, 4.0000, 94.04, 4.5000, 85.86, 5.0000, 79.11, 5.5000, 73.43, 6.0000, 68.58, 6.5000, 64.38, 7.0000, 60.71, 7.5000, 57.47, 8.0000, 54.60, 8.5000, 52.02, 9.0000, 49.69, 9.5000, 47.59, 10.000, 45.67, 12.500, 38.15, 15.000, 32.92, 17.500, 29.05, 20.000, 26.07, 25.000, 21.75, 27.500, 20.13, 30.000, 18.76, 35.000, 16.56, 40.000, 14.88, 45.000, 13.54, 50.000, 12.45, 55.000, 11.54, 60.000, 10.78, 65.000, 10.13, 70.000, 9.559, 75.000, 9.063, 80.000, 8.625, 85.000, 8.236, 90.000, 7.888, 95.000, 7.573, 100.00, 7.289, 125.00, 6.192, 150.00, 5.445, 175.00, 4.903, 200.00, 4.492, 225.00, 4.170, 250.00, 3.911, 275.00, 3.698, 300.00, 3.520, 350.00, 3.241, 400.00, 3.032, 450.00, 2.871, 500.00, 2.743, }; /* matrix that contains the alpha and p parameters from equation: Range = f(E, alpha, p) First line is proton, second line is He... */ extern const double particle_parameters[][2] = { 0.00217, 1.7709,//P /* To be updated to the right values for ions */ 0.0022, 1.77, //HE 0.0022, 1.77, //LI 0.0022, 1.77, //BE 0.0022, 1.77, //B 0.0022, 1.77, //C 0.00, 0.00, //N not used for ion therapy - set to 0 0.0022, 1.77 //O }; plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_lut.h000066400000000000000000000032631321604176500272370ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_lut_h_ #define _rt_lut_h_ #include double get_proton_range(double energy); double get_proton_stop(double energy); /* Range compensator functions, Highland-based definition or Monte Carlo based definition */ double get_theta0_Highland(double range); double get_theta0_MC(float energy); double get_theta_rel_Highland(double rc_over_range); double get_theta_rel_MC(double rc_over_range); double get_scat_or_Highland(double rc_over_range); double get_scat_or_MC(double rc_over_range); double compute_X0_from_HU(double CT_HU); // Radiation length extern const double lookup_proton_range_water[][2]; extern const double lookup_proton_stop_water[][2]; /* declaration of a matrix that contains the alpha and p parameters of the particles (Range = f(E, alpha, p) */ extern const double particle_parameters[][2]; /* Definition of some constants for the Plastimatch dose module */ const int PROTON_TABLE_SIZE = 110; // Look up table size -1 const double PROTON_E_MAX = 255; // Maximum proton energy dealt by Plastimatch is 255 MeV. const double LIGHT_SPEED = 299792458; // m.s-1 const double PROTON_REST_MASS = 939.4; // MeV const double PROTON_WER_AIR = 0.88; const double AIR_DENSITY = 0.001205; // g.cm-3 /* Error Function parameters */ const double ERF_A1 = 0.254829592; const double ERF_A2 = -0.284496736; const double ERF_A3 = 1.421413741; const double ERF_A4 = -1.453152027; const double ERF_A5 = 1.061405429; const double ERF_P = 0.3275911; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_mebs.cxx000077500000000000000000001404211321604176500277350ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include #include #include #include #include #include #include "bragg_curve.h" #include "file_util.h" #include "path_util.h" #include "print_and_exit.h" #include "rt_depth_dose.h" #include "rt_mebs.h" #include "string_util.h" class Rt_mebs_private { public: std::vector depth_dose; float* d_lut; /* depth array (mm) */ float* e_lut; /* energy array (MeV) */ float* f_lut; /* integrated energy array (MeV) */ int num_samples; /* number of depths */ float beam_min_energy; float beam_max_energy; float energy_res; int energy_number; float target_min_depth; /* lower depth of target */ float target_max_depth; /* higher depth of target */ float depth_res; /* depth resolution */ float depth_end; /* end of the depth array */ float prescription_depth_min; float prescription_depth_max; float proximal_margin; float distal_margin; /* spread for optimized SOBP, may be changed to a vector for each energy */ double spread; /* p & alpha are parameters that bind depth and energy according to ICRU */ Particle_type particle_type; double alpha; double p; float photon_energy; // energy for photon mono-energetic beams /* When a new sobp is created from an existing sobp, the peaks are copied (not manual). Modifications of an implicitly defined sobp (by adding a peak) will delete any existing peaks. */ bool have_copied_peaks; bool have_manual_peaks; bool have_prescription; bool have_particle_number_map; /* passive scattering: weights of the mono-energetic beams */ std::vector depth_dose_weight; std::vector energies; /* min and max wed for each ray */ std::vector min_wed_map; std::vector max_wed_map; /* particle number map for both beam line systems */ std::vector num_particles; /* particle number file paths */ std::string particle_number_in; std::string particle_number_out; /* debug */ bool debug; public: Rt_mebs_private () { this->d_lut = new float[0]; this->e_lut = new float[0]; this->f_lut = new float[0]; this->num_samples = 0; this->beam_min_energy = 0.f; this->beam_max_energy = 0.f; this->energy_res = 1.f; this->energy_number = 1; this->target_min_depth = 0.f; /* lower depth of target */ this->target_max_depth = 0.f; /* higher depth of target */ this->depth_res = 0.01f; /* depth resolution */ this->depth_end = 20.f; this->prescription_depth_min = 0.f; this->prescription_depth_max = 0.f; this->proximal_margin = 0.f; this->distal_margin = 0.f; this->spread = 1.0; this->particle_type = PARTICLE_TYPE_P; this->alpha = particle_parameters[0][0]; this->p = particle_parameters[0][1]; this->photon_energy = 6.f; this->have_copied_peaks = false; this->have_manual_peaks = false; this->have_prescription = false; this->have_particle_number_map = false; this->particle_number_in =""; this->particle_number_out =""; this->debug = false; } Rt_mebs_private (Particle_type part) { this->d_lut = new float[0]; this->e_lut = new float[0]; this->f_lut = new float[0]; this->num_samples = 0; this->beam_min_energy = 0.f; this->beam_max_energy = 0.f; this->energy_res = 1.f; this->energy_number = 1; this->target_min_depth = 0.f; this->target_max_depth = 0.f; this->depth_res = 0.01f; this->depth_end = 20.f; this->prescription_depth_min = 0.f; this->prescription_depth_max = 0.f; this->proximal_margin = 0.f; this->distal_margin =0.f; this->spread = 1.0; this->set_particle_type(part); this->photon_energy = 6.f; this->have_copied_peaks = false; this->have_manual_peaks = false; this->have_prescription = false; this->have_particle_number_map = false; this->particle_number_in =""; this->particle_number_out =""; } Rt_mebs_private (const Rt_mebs_private* rsp) { this->d_lut = new float[0]; this->e_lut = new float[0]; this->f_lut = new float[0]; this->num_samples = rsp->num_samples; this->beam_min_energy = rsp->beam_min_energy; this->beam_max_energy = rsp->beam_max_energy; this->energy_res = rsp->energy_res; this->energy_number = rsp->energy_number; this->target_min_depth = rsp->target_min_depth; this->target_max_depth = rsp->target_max_depth; this->depth_res = rsp->depth_res; this->depth_end = rsp->depth_end; this->prescription_depth_min = rsp->prescription_depth_min; this->prescription_depth_max = rsp->prescription_depth_max; this->proximal_margin = rsp->proximal_margin; this->distal_margin = rsp->distal_margin; this->spread =rsp->spread; this->particle_type = rsp->particle_type; this->alpha = rsp->alpha; this->p = rsp->p; this->photon_energy = rsp->photon_energy; this->have_copied_peaks = true; this->have_manual_peaks = rsp->have_manual_peaks; this->have_prescription = rsp->have_prescription; this->have_particle_number_map = rsp->have_particle_number_map; this->particle_number_in = rsp->particle_number_in; this->particle_number_out = rsp->particle_number_out; /* copy the associated depth dose and update the dept dose curve */ for (size_t i = 0; i < rsp->depth_dose.size(); i++) { this->depth_dose.push_back(rsp->depth_dose[i]); } for (size_t i = 0; i < rsp->depth_dose_weight.size(); i++) { this->depth_dose_weight.push_back(rsp->depth_dose_weight[i]); } for (size_t i = 0; i < rsp->energies.size(); i++) { this->energies.push_back(rsp->energies[i]); } for (size_t i = 0; i < rsp->num_particles.size(); i++) { this->num_particles.push_back(rsp->num_particles[i]); } /* update the global depth_dose curve */ this->d_lut = (float*) malloc (this->num_samples*sizeof(float)); this->e_lut = (float*) malloc (this->num_samples*sizeof(float)); this->f_lut = (float*) malloc (this->num_samples*sizeof(float)); memset (this->d_lut, 0, this->num_samples*sizeof(float)); memset (this->e_lut, 0, this->num_samples*sizeof(float)); memset (this->f_lut, 0, this->num_samples*sizeof(float)); for (int i = 0; i < rsp->num_samples; i++) { this->d_lut[i] = rsp->d_lut[i]; this->e_lut[i] = rsp->e_lut[i]; this->f_lut[i] = rsp->f_lut[i]; } this->debug = false; } public: ~Rt_mebs_private () { if (d_lut) delete[] d_lut; if (e_lut) delete[] e_lut; if (f_lut) delete[] f_lut; clear_depth_dose (); } public: void set_particle_type (Particle_type part) { this->particle_type = part; switch (particle_type) { case PARTICLE_TYPE_P: alpha = particle_parameters[0][0]; p = particle_parameters[0][1]; break; case PARTICLE_TYPE_HE: alpha = particle_parameters[1][0]; p = particle_parameters[1][1]; lprintf ("data for helium particle are not available - based on proton beam data"); break; case PARTICLE_TYPE_LI: alpha = particle_parameters[2][0]; p = particle_parameters[2][1]; lprintf ("data for lithium particle type are not available - based on proton beam data"); break; case PARTICLE_TYPE_BE: alpha = particle_parameters[3][0]; p = particle_parameters[3][1]; lprintf ("data for berilium particle type are not available - based on proton beam data"); break; case PARTICLE_TYPE_B: alpha = particle_parameters[4][0]; p = particle_parameters[4][1]; lprintf ("data for bore particle type are not available - based on proton beam data"); break; case PARTICLE_TYPE_C: alpha = particle_parameters[5][0]; p = particle_parameters[5][1]; lprintf ("data for carbon particle type are not available - based on proton beam data"); break; case PARTICLE_TYPE_O: alpha = particle_parameters[7][0]; p = particle_parameters[7][1]; lprintf ("data for oxygen particle type are not available - based on proton beam data"); break; default: alpha = particle_parameters[0][0]; p = particle_parameters[0][1]; particle_type = PARTICLE_TYPE_P; lprintf ("particle not found - proton beam chosen"); break; } } void clear_depth_dose () { if (depth_dose.size() > 0) { printf("Mono energetic beamlet set is erased.\n"); } int stop = depth_dose.size(); /* std::vector::iterator it; for (it = depth_dose.begin(); it != depth_dose.end(); ++it) { delete *it; } */ depth_dose.clear(); /* stop = depth_dose.size(); for (int i = 0; i < stop; i++) { depth_dose.pop_back(); } */ stop = depth_dose_weight.size(); for (int i = 0; i < stop; i++) { depth_dose_weight.pop_back(); } stop = energies.size(); for (int i = 0; i < stop; i++) { energies.pop_back(); } stop = num_particles.size(); for (int i = 0; i < stop; i++) { num_particles.pop_back(); } } }; Rt_mebs::Rt_mebs () { d_ptr = new Rt_mebs_private; } Rt_mebs::Rt_mebs (Particle_type part) { d_ptr = new Rt_mebs_private(part); } Rt_mebs::Rt_mebs (const Rt_mebs::Pointer& rt_mebs) { d_ptr = new Rt_mebs_private (rt_mebs->d_ptr); } Rt_mebs::~Rt_mebs () { delete d_ptr; } void Rt_mebs::clear_depth_dose () { d_ptr->clear_depth_dose (); } void Rt_mebs::add_depth_dose (Rt_depth_dose* depth_dose) { if (d_ptr->have_copied_peaks == true) { d_ptr->clear_depth_dose (); d_ptr->have_copied_peaks = false; } if (depth_dose->dres != d_ptr->depth_res) { printf("*** ERROR: the depth dose added must have the same resolution than the depth_dose set.\n"); printf("depth dose set - resolution: dres = %lf.\n", d_ptr->depth_res); printf("depth dose to be added - resolution: dres = %lf.\n", depth_dose->dres); return; } d_ptr->depth_dose.push_back (depth_dose); d_ptr->energy_number = d_ptr->depth_dose.size(); d_ptr->depth_dose_weight.push_back(1); d_ptr->energies.push_back(depth_dose->E0); /* update the mebs depth dose length if this one is longer */ if (depth_dose->num_samples > d_ptr->num_samples) { d_ptr->num_samples = depth_dose->num_samples; } } void Rt_mebs::add_peak (double E0, double spread, double weight) { if (d_ptr->have_copied_peaks == true) { d_ptr->clear_depth_dose (); d_ptr->have_copied_peaks = false; } switch(d_ptr->particle_type) { case PARTICLE_TYPE_P: // proton { Rt_depth_dose *depth_dose = new Rt_depth_dose ( E0, spread, d_ptr->depth_res, d_ptr->depth_end); if (depth_dose->dend > d_ptr->depth_end) { d_ptr->depth_end = depth_dose->dend; } printf ("Adding peak to sobp (%f, %f, %f) [%f, %f]\n", (float) E0, (float) spread, (float) weight, d_ptr->depth_res, d_ptr->depth_end); d_ptr->depth_dose.push_back (depth_dose); d_ptr->energy_number = d_ptr->depth_dose.size(); d_ptr->depth_dose_weight.push_back((float) weight); d_ptr->energies.push_back(E0); /* update the mebs depth dose length if this one is longer */ if (depth_dose->num_samples > d_ptr->num_samples) { d_ptr->num_samples = depth_dose->num_samples; } } case PARTICLE_TYPE_HE: // helium { //to be implemented } break; case PARTICLE_TYPE_LI: // lithium { //to be implemented } break; case PARTICLE_TYPE_BE: // berilium { //to be implemented } break; case PARTICLE_TYPE_B: // bore { //to be implemented } break; case PARTICLE_TYPE_C: // carbon { //to be implemented } break; case PARTICLE_TYPE_N: // nitrogen { //to be implemented } break; case PARTICLE_TYPE_O: // oxygen { //to be implemented } break; default: { //to be implemented } } } float Rt_mebs::lookup_energy ( float depth) { int i = 0; float energy = 0.0f; /* Sanity check */ if (depth < 0 || depth > d_ptr->depth_end) { return 0.0f; } /* Find index into profile arrays */ for (i = (int) floor(depth / d_ptr->depth_res); i < d_ptr->num_samples-1; i++) { if (d_ptr->d_lut[i] > depth) { i--; break; } } /* Clip input depth to maximum in lookup table */ if (i == d_ptr->num_samples-1) { depth = d_ptr->d_lut[i]; } /* Use index to lookup and interpolate energy */ if (i >= 0 || i < d_ptr->num_samples-1) { // linear interpolation energy = d_ptr->e_lut[i] + (depth - d_ptr->d_lut[i]) * ((d_ptr->e_lut[i+1] - d_ptr->e_lut[i]) / (d_ptr->d_lut[i+1] - d_ptr->d_lut[i])); } else { // we went past the end of the lookup table energy = 0.0f; } return energy; } bool Rt_mebs::generate () { printf("depth_dose number %d\n", (int)d_ptr->depth_dose.size()); /* Construct the data structure first time through */ if (d_ptr->d_lut) delete[] d_ptr->d_lut; if (d_ptr->e_lut) delete[] d_ptr->e_lut; if (d_ptr->f_lut) delete[] d_ptr->f_lut; d_ptr->e_lut = new float [d_ptr->num_samples]; d_ptr->f_lut = new float [d_ptr->num_samples]; d_ptr->d_lut = new float [d_ptr->num_samples]; for (int i = 0; i < d_ptr->num_samples; i++) { d_ptr->d_lut[i] = (float) i * d_ptr->depth_res; d_ptr->e_lut[i] = 0; d_ptr->f_lut[i] = 0; } for (size_t it = 0; it < d_ptr->depth_dose.size(); it++) { const Rt_depth_dose *ppp = d_ptr->depth_dose[it]; /* Check that this peak has the same resolution */ if (ppp->dres != d_ptr->depth_res) { print_and_exit ("Error, mismatch in resolution.\n MEBS: %lg, depth dose # %d: %lg.\n", d_ptr->depth_res, it, ppp->dres); } if (ppp->num_samples > d_ptr->num_samples) { print_and_exit ("Error, num_samples MEBS > num_sample depth dose.\n MEBS: %d, depth dose # %d: %d.\n", d_ptr->num_samples, it, ppp->num_samples); } /* Add weighted pristine peak to mebs */ for (int i = 0; i < ppp->num_samples; i++) { d_ptr->e_lut[i] += d_ptr->depth_dose_weight[it] * ppp->e_lut[i]; } /* Go on to next pristine peak */ it++; } /* build the integrated dose */ if (d_ptr->f_lut[0] && d_ptr->f_lut[0]) {d_ptr->f_lut[0] = d_ptr->e_lut[0];} for (int i = 1; i < d_ptr->num_samples; i++) { d_ptr->f_lut[i] = d_ptr->f_lut[i-1] + d_ptr->e_lut[i]; } return true; } void Rt_mebs::dump (const char* dir) { std::string dirname = dir; /* Dump SOBP */ std::string sobp_fn = string_format ("%s/bragg_curve.txt", dir); FILE* fp = plm_fopen (sobp_fn.c_str(), "w"); for (int i=0; i < d_ptr->num_samples; i++) { fprintf (fp, "%3.2f %3.2f\n", d_ptr->d_lut[i], d_ptr->e_lut[i]); } fclose (fp); /* Dump pristine peaks */ std::vector::const_iterator it = d_ptr->depth_dose.begin(); while (it != d_ptr->depth_dose.end ()) { std::string fn = string_format ("%s/pristine_%4.2f.txt", dir, (float) (*it)->E0); (*it)->dump (fn.c_str()); it++; } } // return on the command line the parameters of the sobp to be build void Rt_mebs::printparameters() { printf ("\nParticle type : %s, alpha: %lg, p: %lg\n", particle_type_string (d_ptr->particle_type), d_ptr->alpha, d_ptr->p); printf("Number of depth_dose : %d\n",d_ptr->energy_number = d_ptr->depth_dose.size()); printf("Energy set (in MeV):\n"); for (size_t i = 0; i < d_ptr->energies.size(); i++) { printf("%lg ", d_ptr->energies[i]); } printf("\nweights set:\n"); for (size_t i = 0; i < d_ptr->depth_dose_weight.size(); i++) { printf("%lg ", d_ptr->depth_dose_weight[i]); } printf("\nEnegy resolution: %g MeV \n",d_ptr->energy_res); printf("E_min : %g MeV; E_max : %g MeV\n",d_ptr->beam_min_energy, d_ptr->beam_max_energy); printf("num_samples: %d\n", d_ptr->num_samples); printf("depth_min_target : %3.2f mm\n",d_ptr->target_min_depth); printf("depth_max_target : %3.2f mm\n",d_ptr->target_max_depth); printf("depth_resolution : %3.2f mm \n",d_ptr->depth_res); printf("depth_end : %3.2f mm\n",d_ptr->depth_end); printf("prescription depths: proximal: %lg mm, distal: %lg mm\n",d_ptr->prescription_depth_min, d_ptr->prescription_depth_max); printf("margins: proximal: %lg mm, distal: %lg mm\n", d_ptr->proximal_margin, d_ptr->distal_margin); } /* reset the mebs depth dose curve */ void Rt_mebs::reset_mebs_depth_dose_curve() { if (d_ptr->d_lut) delete[] d_ptr->d_lut; d_ptr->d_lut = new float[d_ptr->num_samples]; if (d_ptr->e_lut) delete[] d_ptr->e_lut; d_ptr->e_lut = new float[d_ptr->num_samples]; if (d_ptr->f_lut) delete[] d_ptr->f_lut; d_ptr->f_lut = new float[d_ptr->num_samples]; for (int i = 0; i < d_ptr->num_samples; i++) { d_ptr->d_lut[i] = (float) i * d_ptr->depth_res; d_ptr->e_lut[i] = 0; d_ptr->f_lut[i] = 0; } } /* set the mebs parameters by introducing the min and max energies */ void Rt_mebs::set_energies(float new_E_min, float new_E_max) { if (new_E_max <= 0 || new_E_min <= 0) { printf("The energies min and max of the Sobp must be positive!\n"); printf("Emin = %g, Emax = %g \n", new_E_min, new_E_max); return; } if (new_E_max <= new_E_min) { printf("SOBP: The Energy_max must be superior to the Energy_min.Energies unchanged.\n"); printf("Emin = %g, Emax = %g \n", new_E_min, new_E_max); return; } d_ptr->beam_min_energy = new_E_min; d_ptr->beam_max_energy = new_E_max; this->update_prescription_depths_from_energies(); } void Rt_mebs::set_energies(float new_E_min, float new_E_max, float new_step) { d_ptr->energy_res = new_step; this->set_energies(new_E_min, new_E_max); } /* set the mebs parameters by introducing the min and max energies */ void Rt_mebs::set_target_depths(float new_depth_min, float new_depth_max) { if (new_depth_max <= 0 || new_depth_min <= 0) { printf("***ERROR*** The depth min and max of the target must be positive!\n"); printf("depths min = %g, max = %g \n", new_depth_min, new_depth_max); return; } if (new_depth_max <= new_depth_min) { printf("***ERROR*** The Energy_max must be superior to the Energy_min.Energies unchanged.\n"); printf("Emin = %g, Emax = %g \n", new_depth_min, new_depth_max); return; } if (new_depth_min - d_ptr->proximal_margin < 0) { printf("***ERROR*** The proximal margins are too big: depth - margins < 0.\n"); printf("target_depth: %lg mm, proximal margin: %lg mm.\n", new_depth_min, d_ptr->proximal_margin); return; } d_ptr->target_min_depth = new_depth_min; d_ptr->target_max_depth = new_depth_max; d_ptr->prescription_depth_min = new_depth_min - d_ptr->proximal_margin; d_ptr->prescription_depth_max = new_depth_max + d_ptr->distal_margin; d_ptr->depth_end = d_ptr->prescription_depth_max + 20; this->update_energies_from_prescription(); } void Rt_mebs::set_target_depths(float new_z_min, float new_z_max, float new_step) { d_ptr->depth_res = new_step; this->set_target_depths(new_z_min, new_z_max); } void Rt_mebs::set_prescription_depths(float new_prescription_min, float new_prescription_max) { if (new_prescription_min <= d_ptr->proximal_margin || new_prescription_max <= 0) { printf("***ERROR*** The prescription min - proximal margins and prescription max must be positive!\n"); printf("prescription min = %g, max = %g \n", new_prescription_min, new_prescription_max); printf("proximal margin = %g mm.\n", d_ptr->proximal_margin); return; } if (new_prescription_max <= new_prescription_min) { printf("***ERROR*** The prescription max must be superior to the prescription min.\n"); printf("prescription min = %g, prescription max = %g \n", new_prescription_min, new_prescription_max); return; } if (new_prescription_min + d_ptr->proximal_margin > new_prescription_max - d_ptr->distal_margin) { printf("***WARNING*** prox_margin + distal margin > prescription_max - prescription min.\n"); printf("proximal margin: %lg mm, distal margin: %lg mm.\n", d_ptr->proximal_margin, d_ptr->distal_margin); printf("prescription min: %lg mm, prescription max: %lg mm.\n", new_prescription_min, new_prescription_max); return; } d_ptr->prescription_depth_min = new_prescription_min; d_ptr->prescription_depth_max = new_prescription_max; d_ptr->depth_end = d_ptr->prescription_depth_max + 20; this->update_energies_from_prescription(); } void Rt_mebs::set_margins(float proximal_margin, float distal_margin) { if (proximal_margin < 0 || distal_margin < 0) { printf("***ERROR*** The margins must be positive or null!\n"); printf("prescription min = %g, max = %g \n", proximal_margin, distal_margin); return; } d_ptr->proximal_margin = proximal_margin; d_ptr->distal_margin = distal_margin; // the prescription depths are updated later } /* update the mebs depths parameters from energy definition */ void Rt_mebs::update_prescription_depths_from_energies() { d_ptr->prescription_depth_min = ((10*d_ptr->alpha)*pow((double)d_ptr->beam_min_energy, d_ptr->p)); d_ptr->prescription_depth_max = ((10*d_ptr->alpha)*pow((double)d_ptr->beam_max_energy, d_ptr->p)); d_ptr->target_min_depth = d_ptr->prescription_depth_min + d_ptr->proximal_margin; d_ptr->target_max_depth = d_ptr->prescription_depth_max - d_ptr->distal_margin; if (d_ptr->target_min_depth > d_ptr->target_max_depth) { printf("***WARNING*** target volume impossible. The difference between the E_min and E_max is smaller than the sum of the margins.\n"); } d_ptr->depth_end = d_ptr->prescription_depth_max + 20; d_ptr->num_samples = (int)ceil((d_ptr->depth_end/d_ptr->depth_res))+1; d_ptr->energy_number = (int) ceil((d_ptr->beam_max_energy - d_ptr->beam_min_energy) / d_ptr->energy_res) + 1; this->reset_mebs_depth_dose_curve(); } /* update the mebs energy parameters from prescription definition */ void Rt_mebs::update_energies_from_prescription() { int energy_min_index = (int) floor(pow((d_ptr->prescription_depth_min/(10*d_ptr->alpha)),(1/d_ptr->p)) / d_ptr->energy_res); int energy_max_index = (int) ceil(pow((d_ptr->prescription_depth_max/(10*d_ptr->alpha)),(1/d_ptr->p)) / d_ptr->energy_res); d_ptr->beam_min_energy = (float) energy_min_index * d_ptr->energy_res; d_ptr->beam_max_energy = (float) energy_max_index * d_ptr->energy_res; /* check that the E_max is sufficiently high for covering the distal part of the prescription */ d_ptr->beam_max_energy += this->check_and_correct_max_energy(d_ptr->beam_max_energy, d_ptr->prescription_depth_max); energy_max_index = (int) (d_ptr->beam_max_energy / d_ptr->energy_res); /* check that the E_min is sufficiently low for covering the distal part of the prescription */ d_ptr->beam_min_energy += this->check_and_correct_min_energy(d_ptr->beam_min_energy, d_ptr->prescription_depth_min); energy_min_index = (int) (d_ptr->beam_min_energy / d_ptr->energy_res); d_ptr->depth_end = d_ptr->prescription_depth_max + 20; d_ptr->num_samples = (int)ceil((d_ptr->depth_end/d_ptr->depth_res))+1; d_ptr->energy_number = (int) ceil((d_ptr->beam_max_energy - d_ptr->beam_min_energy) / d_ptr->energy_res) + 1; this->reset_mebs_depth_dose_curve(); } float* Rt_mebs::get_d_lut() { return d_ptr->d_lut; } float* Rt_mebs::get_e_lut() { return d_ptr->e_lut; } float* Rt_mebs::get_f_lut() { return d_ptr->f_lut; } void Rt_mebs::set_particle_type(Particle_type particle_type) { d_ptr->set_particle_type (particle_type); if (d_ptr->prescription_depth_min !=0) { this->update_energies_from_prescription(); } } Particle_type Rt_mebs::get_particle_type() { return d_ptr->particle_type; } void Rt_mebs::set_alpha(double alpha) { d_ptr->alpha = alpha; } double Rt_mebs::get_alpha() { return d_ptr->alpha; } void Rt_mebs::set_p(double p) { d_ptr->p = p; } double Rt_mebs::get_p() { return d_ptr->p; } int Rt_mebs::get_energy_number() { return d_ptr->energy_number; } std::vector Rt_mebs::get_energy() { return d_ptr->energies; } std::vector Rt_mebs::get_weight() { return d_ptr->depth_dose_weight; } void Rt_mebs::set_energy_resolution(float eres) { if (eres > 0) { d_ptr->energy_res = eres; d_ptr->energy_number = (int) ceil((d_ptr->beam_max_energy - d_ptr->beam_min_energy) / d_ptr->energy_res) + 1; } else { printf("***WARNING*** Energy resolution must be positive. Energy resolution unchanged"); } } float Rt_mebs::get_energy_resolution() { return d_ptr->energy_res; } void Rt_mebs::set_energy_min(float E_min) { if (E_min > 0) { this->set_energies(E_min, d_ptr->beam_max_energy); } else { printf("***WARNING*** Energy min must be positive. Energy min unchanged"); } } float Rt_mebs::get_energy_min() { return d_ptr->beam_min_energy; } void Rt_mebs::set_energy_max(float E_max) { if (E_max > 0) { this->set_energies(d_ptr->beam_min_energy, E_max); } else { printf("***WARNING*** Energy max must be positive. Energy max unchanged"); } } float Rt_mebs::get_energy_max() { return d_ptr->beam_max_energy; } int Rt_mebs::get_num_samples() { return d_ptr->num_samples; } void Rt_mebs::set_target_min_depth(float dmin) { if (dmin > 0) { this->set_target_depths(dmin, d_ptr->target_max_depth); } else { printf("***WARNING*** Depth min must be positive. Depth min unchanged"); } } float Rt_mebs::get_target_min_depth() { return d_ptr->target_min_depth; } void Rt_mebs::set_target_max_depth(float dmax) { if (dmax > 0) { this->set_target_depths(d_ptr->target_min_depth, dmax); } else { printf("***WARNING*** Depth max must be positive. Depth max unchanged"); } } float Rt_mebs::get_target_max_depth() { return d_ptr->target_max_depth; } void Rt_mebs::set_depth_resolution(float dres) { if (dres > 0) { d_ptr->depth_res = dres; d_ptr->num_samples = (int)ceil((d_ptr->depth_end/d_ptr->depth_res))+1; this->reset_mebs_depth_dose_curve(); } else { printf("***WARNING*** Depth resolution must be positive. Depth resolution unchanged"); } } float Rt_mebs::get_depth_resolution() { return d_ptr->depth_res; } void Rt_mebs::set_depth_end(float dend) { if (dend > 0) { d_ptr->depth_end = dend; d_ptr->num_samples = (int)ceil((d_ptr->depth_end/d_ptr->depth_res))+1; this->reset_mebs_depth_dose_curve(); } else { printf("***WARNING*** Depth end must be positive. Depth end unchanged"); } } float Rt_mebs::get_depth_end() { return d_ptr->depth_end; } float Rt_mebs::get_prescription_min() { return d_ptr->prescription_depth_min; } float Rt_mebs::get_prescription_max() { return d_ptr->prescription_depth_max; } void Rt_mebs::set_distal_margin (float distal_margin) { this->set_margins(d_ptr->proximal_margin, distal_margin); } float Rt_mebs::get_distal_margin() { return d_ptr->distal_margin; } void Rt_mebs::set_proximal_margin (float proximal_margin) { this->set_margins(proximal_margin, d_ptr->distal_margin); } float Rt_mebs::get_proximal_margin() { return d_ptr->proximal_margin; } void Rt_mebs::set_spread (double spread) { d_ptr->spread = spread; } double Rt_mebs::get_spread() { return d_ptr->spread; } void Rt_mebs::set_photon_energy(float energy) { d_ptr->photon_energy = energy; } float Rt_mebs::get_photon_energy() { return d_ptr->photon_energy; } std::vector Rt_mebs::get_depth_dose() { return d_ptr->depth_dose; } std::vector& Rt_mebs::get_num_particles() { return d_ptr->num_particles; } void Rt_mebs::set_prescription (float prescription_min, float prescription_max) { d_ptr->have_prescription = true; this->set_prescription_depths (prescription_min, prescription_max); } void Rt_mebs::set_have_prescription(bool have_prescription) { d_ptr->have_prescription = have_prescription; } bool Rt_mebs::get_have_prescription() { return d_ptr->have_prescription; } void Rt_mebs::set_have_copied_peaks(bool have_copied_peaks) { d_ptr->have_copied_peaks = have_copied_peaks; } bool Rt_mebs::get_have_copied_peaks() { return d_ptr->have_copied_peaks; } void Rt_mebs::set_have_manual_peaks(bool have_manual_peaks) { d_ptr->have_manual_peaks = have_manual_peaks; } bool Rt_mebs::get_have_manual_peaks() { return d_ptr->have_manual_peaks; } void Rt_mebs::set_have_particle_number_map(bool have_particle_number_map) { d_ptr->have_particle_number_map = have_particle_number_map; } bool Rt_mebs::get_have_particle_number_map() { return d_ptr->have_particle_number_map; } std::vector& Rt_mebs::get_min_wed_map() { return d_ptr->min_wed_map; } std::vector& Rt_mebs::get_max_wed_map() { return d_ptr->max_wed_map; } void Rt_mebs::set_particle_number_in (const std::string& str) { d_ptr->particle_number_in = str; } std::string Rt_mebs::get_particle_number_in () { return d_ptr->particle_number_in; } void Rt_mebs::set_particle_number_out (const std::string& str) { d_ptr->particle_number_out = str; } std::string Rt_mebs::get_particle_number_out () { return d_ptr->particle_number_out; } void Rt_mebs::add_depth_dose_weight(float weight) { d_ptr->depth_dose_weight.push_back(weight); } /* This function check (and correct if necessary) that E_max is the closest energy (+/- energy_resolution) to reach the distal prescription */ /* This function is designed to return a float value that represents the increase/decrease of energy to correct it this is used by two parts of the program on different members (explaining this particular structure) */ float Rt_mebs::check_and_correct_max_energy(float E, float depth) { float E_init = E; /* Check that the depth dose is increasing (dose_max not passed) */ float dose = bragg_curve(E, d_ptr->spread, depth); float dose_plus = bragg_curve(E, d_ptr->spread, depth + d_ptr->depth_res); while ( dose_plus < dose ) { E += d_ptr->energy_res; dose = bragg_curve(E, d_ptr->spread, depth); dose_plus = bragg_curve(E, d_ptr->spread, depth+d_ptr->depth_res); } /* Check that this energy is really the smallest one that reach the distal prescription */ /* This case happen if E is already superior at a first estimation, estimated by alpha and p */ if (E < d_ptr->energy_res) { return E - E_init; } E -= d_ptr->energy_res; dose = bragg_curve(E, d_ptr->spread, depth); dose_plus = bragg_curve(E, d_ptr->spread, depth + d_ptr->depth_res); while ( dose_plus > dose) { E -= d_ptr->energy_res; dose = bragg_curve(E, d_ptr->spread, depth); dose_plus = bragg_curve(E, d_ptr->spread, depth + d_ptr->depth_res); } E += d_ptr->energy_res; return E - E_init; } /* This function check (and correct if necessary) that E_min is the closest energy (+/- energy_resolution) to reach the proximal prescription */ /* This function is designed to return a float value that represents the increase/decrease of energy to correct it this is used by two parts of the program on different members (explaining this particular structure) */ float Rt_mebs::check_and_correct_min_energy(float E, float depth) { float E_init = E; /* Check that the depth dose is descreasing (dose_min passed) */ float dose = bragg_curve(E, d_ptr->spread, depth); float dose_minus = bragg_curve(E, d_ptr->spread, depth - d_ptr->depth_res); while ( dose_minus < dose ) { if (E < d_ptr->energy_res) { return E_init - E; } E -= d_ptr->energy_res; dose = bragg_curve(E, d_ptr->spread, depth); dose_minus = bragg_curve(E, d_ptr->spread, depth - d_ptr->depth_res); } /* Check that this energy is really the smallest one that stops before the proximal prescription */ /* This case happens if E is already superior at a first estimation, estimated by alpha and p */ E += d_ptr->energy_res; dose = bragg_curve(E, d_ptr->spread, depth); dose_minus = bragg_curve(E, d_ptr->spread, depth - d_ptr->depth_res); while ( dose_minus > dose) { E += d_ptr->energy_res; dose = bragg_curve(E, d_ptr->spread, depth); dose_minus = bragg_curve(E, d_ptr->spread, depth - d_ptr->depth_res); } E -= d_ptr->energy_res; return E - E_init; } void Rt_mebs::optimize_sobp () { this->update_energies_from_prescription(); std::vector weight_tmp; std::vector energy_tmp; this->optimizer (&weight_tmp, &energy_tmp); for (size_t i = 0; i < energy_tmp.size(); i++) { add_peak(energy_tmp[i], d_ptr->spread, weight_tmp[i]); } } void Rt_mebs::optimizer (std::vector* weight_tmp, std::vector* energy_tmp) { printf("prescription min/max: %lg mm, %lg mm.\n", d_ptr->prescription_depth_min, d_ptr->prescription_depth_max); std::vector depth_dose_tmp; this->initialize_energy_weight_and_depth_dose_vectors(weight_tmp, energy_tmp, &depth_dose_tmp); this->get_optimized_peaks(d_ptr->prescription_depth_min, d_ptr->prescription_depth_max, weight_tmp, &depth_dose_tmp); } void Rt_mebs::initialize_energy_weight_and_depth_dose_vectors ( std::vector* weight_tmp, std::vector* energy_tmp, std::vector* depth_dose_tmp) { /* initialize the energies in the table */ printf("\n %d Mono-energetic BP used:\n", d_ptr->energy_number); for (int i = 0; i < d_ptr->energy_number; i++) { energy_tmp->push_back(d_ptr->beam_max_energy - (float) i * d_ptr->energy_res); weight_tmp->push_back(0); printf("%lg ", (*energy_tmp)[i]); if ((*energy_tmp)[i] < 0) { d_ptr->energy_number--; (*energy_tmp).pop_back(); weight_tmp->pop_back(); printf ("sobp: peak with energy < 0, Energy resolution error. Last peak deleted.\n"); } } printf("\n"); /* initialize the depth dose curve associated to the energy vector */ /* Creates depth dose set */ for (int i = 0; i < d_ptr->energy_number; i++) { Rt_depth_dose* depth_dose = new::Rt_depth_dose((*energy_tmp)[i],d_ptr->spread, d_ptr->depth_res,d_ptr->depth_end); depth_dose_tmp->push_back(depth_dose); if (d_ptr->num_samples < depth_dose->num_samples) { d_ptr->num_samples = depth_dose->num_samples; } } } void Rt_mebs::generate_part_num_from_weight (const plm_long* ap_dim) { //int idx = 0; for (int i = 0; i < d_ptr->energy_number; i++) { for (int j = 0; j < ap_dim[0] * ap_dim[1]; j++) { d_ptr->num_particles.push_back (d_ptr->depth_dose_weight[i]); } } } void Rt_mebs::scale_num_part (double A, const plm_long* ap_dim) { for (int i = 0; i < (int) d_ptr->energy_number * ap_dim[0] * ap_dim[1]; i++) { d_ptr->num_particles[i] = d_ptr->num_particles[i] * A; } } double Rt_mebs::get_particle_number_xyz ( plm_long* idx, double* rest, int dd_idx, const plm_long* ap_dim) { /* The boundaries possible errors like idx = dim are already excluded by the test on the aperture. Practically, idx = dim -1 is not possible */ double A = 0; double B = 0; int beamlet = 0; beamlet = ap_dim[0] * ap_dim[1] * dd_idx + ap_dim[0] * idx[1] + idx[0]; A = d_ptr->num_particles[beamlet] + rest[0] * ( d_ptr->num_particles[beamlet+1] - d_ptr->num_particles[beamlet]); #if defined (commentout) if (d_ptr->debug) { printf (" Mebs::GPNXYZ %f %f", d_ptr->num_particles[beamlet], d_ptr->num_particles[beamlet+1] ); } #endif beamlet = ap_dim[0] * ap_dim[1] * dd_idx + ap_dim[0] * (idx[1]+1) + idx[0]; B = d_ptr->num_particles[beamlet] + rest[0] * ( d_ptr->num_particles[beamlet+1] - d_ptr->num_particles[beamlet]); #if defined (commentout) if (d_ptr->debug) { printf (" %f %f\n", d_ptr->num_particles[beamlet], d_ptr->num_particles[beamlet+1] ); } #endif return A + rest[1] * (B-A); } void Rt_mebs::set_from_spot_map (const Rt_spot_map::Pointer& rsm) { this->clear_depth_dose (); const std::list& spot_list = rsm->get_spot_list(); } void Rt_mebs::load_beamlet_map (Aperture::Pointer& ap) { /* Confirm file can be read */ if (!file_exists (d_ptr->particle_number_in)) { printf ("Error reading config file: %s\n", d_ptr->particle_number_in.c_str()); printf("Particle number map set to 0 for each dose beamlet \n"); return; } /* Read file into string */ std::ifstream t (d_ptr->particle_number_in.c_str()); std::stringstream buffer; std::string strEnergy; std::stringstream ssenergy; buffer << t.rdbuf(); std::string buf; std::stringstream ss (buffer.str()); std::string val; std::string char_part_numb; char sep[] = " "; char* token; int beamlet_number = 0; int line_number = 0; int energy_number = 0; int idx = 0; double part_number = 0; double energy; while (getline (ss, buf)) { buf = string_trim (buf); if (buf == "") continue; if (buf[0] == '#') continue; /* Check the dim for the last beamlet map */ if (buf.find ("[Energy]") != std::string::npos && energy_number != 0 && line_number != ap->get_dim(1)) { printf("***WARNING*** the number of beamlet line doesn't correspond to the aperture size\n"); printf("beamlet line number expected: %d, beamlet line detected: %d.\n", ap->get_dim(1), line_number); } if (buf.find ("[Energy]") != std::string::npos) { val =""; val = buf.c_str(); val = strtok(&val[0], "[Energy]"); energy = strtod(val.c_str(),0); beamlet_number = 0; line_number = 0; if (energy > 0) { printf("Particle number map found for energy %lg.\n", energy); this->add_peak(energy, d_ptr->spread, 1); energy_number++; for (int i = 0; i < ap->get_dim(0) * ap->get_dim(1); i++) { d_ptr->num_particles.push_back(0); } } continue; } if (energy_number == 0) { continue; } /* If we arrive here, it means that we read a beamlet map */ val =""; val = buf.c_str(); val = string_trim (val); token = strtok(&val[0], sep); beamlet_number = 0; while (token != NULL) { part_number = strtod(token,0); if (beamlet_number < ap->get_dim(0)) { idx = (energy_number-1) * ap->get_dim(0) * ap->get_dim(1) + line_number * ap->get_dim(0) + beamlet_number; d_ptr->num_particles[idx] = part_number; beamlet_number++; } token = strtok(NULL, sep); } if (beamlet_number != ap->get_dim(0)) { printf("***WARNING*** the number of beamlets doesn't correspond to the aperture size\n"); printf("line %d: beamlet number expected: %d, beamlet number detected: %d.\n", line_number, ap->get_dim(0), beamlet_number); } line_number++; } /* Check the dim for the last beamlet map */ if (energy_number != 0 && line_number != ap->get_dim(1)) { printf("***WARNING*** the number of beamlet line doesn't correspond to the aperture size\n"); printf("beamlet line number expected: %d, beamlet line detected: %d.\n", ap->get_dim(1), line_number); } } void Rt_mebs::compute_particle_number_matrix_from_target_active ( Rpl_volume* rpl_vol, std::vector & wepl_min, std::vector & wepl_max) { int dim[2] = { static_cast(rpl_vol->get_aperture()->get_dim()[0]), static_cast(rpl_vol->get_aperture()->get_dim()[1]) }; /* vector containing the min and the max of depth of the target */ float min = 0; float max = 0; /* Sanity check */ if (wepl_min.size() != rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1) || wepl_max.size() != rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1)) { printf("ERROR: the aperture size doesn't correspond to the min and max depth maps of the target.\n"); printf("Aperture size: %d, min depth map size: %d, max depth map size: %d.\n", rpl_vol->get_aperture()->get_dim(0) * rpl_vol->get_aperture()->get_dim(1), (int) wepl_min.size(), (int) wepl_max.size()); } for (size_t i = 0; i < wepl_max.size(); i++) { if (wepl_max[i] > max) { max = wepl_max[i]; } } min = max; for (size_t i = 0; i < wepl_min.size(); i++) { if (wepl_min[i] < min && wepl_min[i] != 0) { min = wepl_min[i]; } } this->set_prescription_depths(min, max); printf("Min and max depths in the PTV (target + margins): %lg mm and %lg mm.\n", d_ptr->prescription_depth_min, d_ptr->prescription_depth_max); printf("Min and max energies for treating the PTV: %lg MeV and %lg MeV.\n", d_ptr->beam_min_energy, d_ptr->beam_max_energy); std::vector energy_tmp; std::vector weight_tmp; std::vector depth_dose_tmp; this->initialize_energy_weight_and_depth_dose_vectors (&weight_tmp, &energy_tmp, &depth_dose_tmp); /* initialization of the dose matrix slice for monoenergetic slice */ for (int i = 0; i < dim[0] * dim[1] * d_ptr->energy_number; i++) { d_ptr->num_particles.push_back(0); } printf("Optimization of the particle number map for any mono-energetic slice in progress...\n"); /* Let's optimize the SOBP for each beamlet */ for (size_t i = 0; i < wepl_min.size(); i++) { this->get_optimized_peaks (wepl_min[i], wepl_max[i], &weight_tmp, &depth_dose_tmp); for (int j = 0; j < d_ptr->energy_number; j++) { d_ptr->num_particles[i + j * dim[0] * dim[1] ] = weight_tmp[j]; /* Reset weight_tmp for next turn */ weight_tmp[j] = 0; } } for (size_t i = 0; i < energy_tmp.size(); i++) { add_peak(energy_tmp[i], d_ptr->spread, 1); } } /* This function returns optimized weighted peaks for passive systems (SOBP weights) and active systems (beamlet particle numbers for each energy) */ void Rt_mebs::get_optimized_peaks ( float dmin, float dmax, std::vector* weight_tmp, std::vector* depth_dose_tmp) { if (dmin == 0 || dmax == 0) { return; } int energy_min_index = (int) floor(pow((dmin/(10*d_ptr->alpha)),(1/d_ptr->p)) / d_ptr->energy_res); int energy_max_index = (int) ceil(pow((dmax/(10*d_ptr->alpha)),(1/d_ptr->p)) / d_ptr->energy_res); float E_min_sobp = (float) energy_min_index * d_ptr->energy_res; float E_max_sobp = (float) energy_max_index * d_ptr->energy_res; /* This is useful only for active scanning */ /* check that the E_max is sufficiently high for covering the distal part of the prescription */ E_max_sobp += this->check_and_correct_max_energy(E_max_sobp, dmax); /* check that the E_min is sufficiently low for covering the distal part of the prescription */ E_min_sobp += this->check_and_correct_min_energy(E_min_sobp, dmin); int i0 = (int) ((d_ptr->beam_max_energy - E_max_sobp) / d_ptr->energy_res); int imax = (int) ((d_ptr->beam_max_energy - E_min_sobp) / d_ptr->energy_res); std::vector d_lut_tmp (d_ptr->num_samples, 0); std::vector e_lut_tmp (d_ptr->num_samples, 0); for (int i = 0; i < d_ptr->num_samples; i++) { d_lut_tmp[i] = (float) i * d_ptr->depth_res; } int idx_max = 0; for (int i = i0; i <= imax; i++) { idx_max = (*depth_dose_tmp)[i]->index_of_dose_max; if (idx_max > d_ptr->num_samples) { printf("***WARNING*** depth_dose %d, max_index > samples.\n", i); continue; // the weight remains at 0 } if ( (*depth_dose_tmp)[i]->e_lut[idx_max] <= 0) { printf("***WARNING*** depth dose #%d is null.\n", i); continue; // the weight remains at 0 } (*weight_tmp)[i] = (1-e_lut_tmp[idx_max])/ (*depth_dose_tmp)[i]->e_lut[idx_max]; if ((*weight_tmp)[i] < 0) { (*weight_tmp)[i] = 0; } for (int j = 0; j < (*depth_dose_tmp)[i]->num_samples; j++) { e_lut_tmp[j] += (*weight_tmp)[i] * (*depth_dose_tmp)[i]->e_lut[j]; } } /* Repeat for 40 iterations */ for (int k = 0; k < 40; k++) { for (int i = i0; i <= imax; i++) { if (e_lut_tmp[ (*depth_dose_tmp)[i]->index_of_dose_max] != 0) { (*weight_tmp)[i] /= e_lut_tmp[ (*depth_dose_tmp)[i]->index_of_dose_max]; } } for (int j = 0; j < d_ptr->num_samples; j++) { e_lut_tmp[j] = 0; } for (int i = i0; i <= imax; i++) { for (int j = 0; j < (*depth_dose_tmp)[i]->num_samples; j++) { e_lut_tmp[j] += (*weight_tmp)[i] * (*depth_dose_tmp)[i]->e_lut[j]; } } } double mean_sobp = 0; double mean_count = 0; for (int i = 0; i < d_ptr->num_samples; i++) { if (d_lut_tmp[i] >= dmin && d_lut_tmp[i] <= dmax) { mean_sobp += e_lut_tmp[i]; mean_count++; } } if (mean_count == 0 || mean_sobp == 0) { printf("***WARNING*** The dose is null in the target interval\n"); return; } for (int i = i0; i <= imax; i++) { (*weight_tmp)[i] /= (float) (mean_sobp / mean_count); } } void Rt_mebs::export_as_txt(Aperture::Pointer ap) { make_parent_directories (d_ptr->particle_number_out.c_str()); printf("Trying to write mebs in %s\n", d_ptr->particle_number_out.c_str()); std::ofstream fichier(d_ptr->particle_number_out.c_str()); if ( !fichier ){ std::cerr << "Erreur de creation du fichier beamlet_map" << std::endl; return; } int idx = 0; for (int e = 0; e < d_ptr->energy_number; e++) { fichier << "[ENERGY] "; fichier << d_ptr->energies[e] << std::endl; for (int i = 0; i < ap->get_dim(0); i++) { for (int j = 0; j < ap->get_dim(1); j++) { idx = (e * ap->get_dim(0) + i) * ap->get_dim(1) +j; fichier << d_ptr->num_particles[idx] << " "; } fichier << std::endl; } fichier << std::endl; } fichier.close(); } void Rt_mebs::set_debug (bool debug) { d_ptr->debug = debug; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_mebs.h000077500000000000000000000143251321604176500273650ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- rt_mebs (for mono-energetic beamlet set) is a class that creates beams of different energies, including SOBP (Spread Out Bragg Peak) or any multi-energy beam configuration. ----------------------------------------------------------------------- */ #ifndef _rt_mebs_h_ #define _rt_mebs_h_ #include "plmdose_config.h" #include #include #include #include "logfile.h" #include "particle_type.h" #include "plmdose_config.h" #include "plm_config.h" #include "rpl_volume.h" #include "rt_lut.h" #include "rt_spot_map.h" #include "smart_pointer.h" class Rt_depth_dose; class Rt_mebs_private; class PLMDOSE_API Rt_mebs { public: SMART_POINTER_SUPPORT (Rt_mebs); Rt_mebs_private *d_ptr; public: Rt_mebs (); Rt_mebs (Particle_type part); Rt_mebs (const Rt_mebs::Pointer& rt_mebs); ~Rt_mebs (); /* Remove all depth dose */ void clear_depth_dose (); /* Add a pristine peak to a mebs */ void add_depth_dose (Rt_depth_dose* depth_dose); void add_peak (double E0, double spread, double weight); /* Return simple depth dose result at depth */ float lookup_energy (float depth); /* use manually weighted peaks */ bool generate (); /* Save the depth dose to a file */ void dump (const char* dir); /* Print the parameters of the mebs */ void printparameters(); /* reset the mebs depth dose curve */ void reset_mebs_depth_dose_curve(); /* set the prescription parameters: target and prescription depths, energy */ void set_energies(float new_E_min, float new_E_max); void set_energies(float new_E_min, float new_E_max, float new_step); void set_target_depths(float new_depth_min, float new_depth_max); void set_target_depths(float new_depth_min, float new_depth_max, float new_step); void set_prescription_depths(float new_prescription_min, float new_prescription_max); void set_margins(float proximal_margin, float distal_margin); void update_prescription_depths_from_energies(); void update_energies_from_prescription(); /* Set/Get private members */ float* get_d_lut(); float* get_e_lut(); float* get_f_lut(); void set_particle_type(Particle_type particle_type); Particle_type get_particle_type(); void set_alpha(double alpha); double get_alpha(); void set_p(double p); double get_p(); int get_energy_number(); /* set energy_number is not implemented as it must not be changed externally*/ std::vector get_energy(); std::vector get_weight(); void set_energy_resolution(float eres); float get_energy_resolution(); void set_energy_min(float E_min); float get_energy_min(); void set_energy_max(float E_max); float get_energy_max(); int get_num_samples(); void set_target_min_depth(float dmin); float get_target_min_depth(); void set_target_max_depth(float dmax); float get_target_max_depth(); void set_depth_resolution(float dres); float get_depth_resolution(); void set_depth_end(float dend); float get_depth_end(); float get_prescription_min(); float get_prescription_max(); void set_proximal_margin (float proximal_margin); float get_proximal_margin(); void set_distal_margin (float distal_margin); float get_distal_margin(); void set_spread (double spread); double get_spread(); void set_photon_energy(float energy); float get_photon_energy(); std::vector get_depth_dose(); std::vector& get_num_particles(); void set_prescription(float prescription_min, float prescription_max); void set_have_prescription(bool have_prescription); bool get_have_prescription(); void set_have_copied_peaks(bool have_copied_peaks); bool get_have_copied_peaks(); void set_have_manual_peaks(bool have_manual_peaks); bool get_have_manual_peaks(); void set_have_particle_number_map(bool have_particle_number_map); bool get_have_particle_number_map(); std::vector& get_min_wed_map(); std::vector& get_max_wed_map(); void set_particle_number_in (const std::string& str); std::string get_particle_number_in (); void set_particle_number_out (const std::string& str); std::string get_particle_number_out (); void add_depth_dose_weight(float weight); float check_and_correct_max_energy(float E, float depth); float check_and_correct_min_energy(float E, float depth); /* Optimize, then generate mebs depth curve from prescription range and modulation */ void optimize_sobp (); /* Weight optimizer */ void optimizer (std::vector* weight_tmp, std::vector* energy_tmp); void get_optimized_peaks (float dmin, float dmax, std::vector* weight_tmp, std::vector* depth_dose); void initialize_energy_weight_and_depth_dose_vectors ( std::vector* weight_tmp, std::vector* energy_tmp, std::vector* depth_dose_tmp); void scale_num_part (double A, const plm_long* ap_dim); double get_particle_number_xyz (plm_long* idx, double* rest, int idx_beam, const plm_long* ap_dim); // returns also the wed max and min maps void compute_beam_modifiers_active_scanning ( Volume *seg_vol, float smearing, float proximal_margin, float distal_margin, std::vector& map_wed_min, std::vector& map_wed_max); /* This computes the E_min and E_max map from a target for all pencil beam*/ void generate_part_num_from_weight (const plm_long* ap_dim); void compute_particle_number_matrix_from_target_active ( Rpl_volume* rpl_vol, std::vector & wepl_min, std::vector & wepl_max); void set_from_spot_map (const Rt_spot_map::Pointer& rsm); void load_beamlet_map (Aperture::Pointer& ap); void export_as_txt (Aperture::Pointer ap); /* Debugging */ void set_debug (bool); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_parms.cxx000077500000000000000000000370641321604176500301410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include #include #include "aperture.h" #include "parameter_parser.h" #include "plm_image.h" #include "plm_math.h" #include "print_and_exit.h" #include "rpl_volume.h" #include "rt_beam.h" #include "rt_depth_dose.h" #include "rt_parms.h" #include "rt_plan.h" #include "rt_mebs.h" #include "string_util.h" class Rt_parms_private { public: /* [PEAK] */ double E0; double spread; double weight; double max_depth; double depth_res; std::string bragg_curve; /* Other parameters not directly defined by config the config file but necessary for the beam creation */ Rt_plan* rt_plan; int beam_number; /* contains the number of the beam in the vector beam_storage */ Rt_mebs::Pointer mebs; bool have_prescription; bool ap_have_origin; bool have_manual_peaks; public: Rt_parms_private () { /* [PEAK] */ this->E0 = 100.; this->spread = 1.; this->weight = 1.; this->max_depth = 400.0f; this->depth_res = 0.01f; this->bragg_curve =""; /* Other parameters not directly defined by config the config file but necessary for the beam creation */ this->rt_plan = 0; this->beam_number = -1; this->mebs = Rt_mebs::New(); this->have_prescription = false; this->ap_have_origin = false; this->have_manual_peaks = false; } }; Rt_parms::Rt_parms () { d_ptr = new Rt_parms_private; } Rt_parms::Rt_parms (Rt_plan* rt_plan) { d_ptr = new Rt_parms_private; d_ptr->rt_plan = rt_plan; } Rt_parms::~Rt_parms () { delete d_ptr; } static void print_usage (void) { printf ( "Usage: proton_dose [options] config_file\n" "Options:\n" " --debug Create various debug files\n" ); exit (1); } class Rt_parms_parser : public Parameter_parser { public: Rt_parms *rp; public: Rt_parms_parser (Rt_parms *rp) { this->rp = rp; } public: virtual Plm_return_code begin_section ( const std::string& section) { if (section == "GLOBAL") { return PLM_SUCCESS; } if (section == "COMMENT") { return PLM_SUCCESS; } if (section == "PLAN") { return PLM_SUCCESS; } if (section == "BEAM") { rp->append_beam (); return PLM_SUCCESS; } if (section == "PEAK") { return PLM_SUCCESS; } /* else, unknown section */ return PLM_ERROR; } virtual Plm_return_code end_section ( const std::string& section) { if (section == "PEAK") { rp->append_peak (); return PLM_SUCCESS; } return PLM_SUCCESS; } virtual Plm_return_code set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val) { return this->rp->set_key_value (section, key, index, val); } }; void Rt_parms::set_rt_plan (Rt_plan *rt_plan) { d_ptr->rt_plan = rt_plan; } void Rt_parms::append_beam () { d_ptr->rt_plan->append_beam (); } void Rt_parms::append_peak () { Rt_beam *rt_beam = d_ptr->rt_plan->get_last_rt_beam (); if (!rt_beam) { return; } rt_beam->get_mebs()->set_have_manual_peaks(true); rt_beam->get_mebs()->add_peak (d_ptr->E0, d_ptr->spread, d_ptr->weight); } Plm_return_code Rt_parms::set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val) { if (section == "COMMENT" || section == "GLOBAL") { return PLM_SUCCESS; } /* **** PLAN **** */ if (section == "PLAN") { if (key == "patient") { d_ptr->rt_plan->set_patient (val); } else if (key == "target") { d_ptr->rt_plan->set_target (val); } else if (key == "threading") { Threading threading = THREADING_CPU_OPENMP; if (val == "single") { threading = THREADING_CPU_SINGLE; } else if (val == "openmp") { #if (OPENMP_FOUND) threading = THREADING_CPU_OPENMP; #else threading = THREADING_CPU_SINGLE; #endif } else if (val == "cuda") { #if (CUDA_FOUND) threading = THREADING_CUDA; #elif (OPENMP_FOUND) threading = THREADING_CPU_OPENMP; #else threading = THREADING_CPU_SINGLE; #endif } else { goto error_exit; } d_ptr->rt_plan->set_threading (threading); } else if (key == "dose_out") { d_ptr->rt_plan->set_output_dose_fn (val); } else if (key == "psp_out") { d_ptr->rt_plan->set_output_psp_fn (val); } else if (key == "debug") { d_ptr->rt_plan->set_debug (string_value_true (val)); } else if (key == "dose_prescription") { float norm_dose; if (sscanf (val.c_str(), "%f", &norm_dose) != 1) { goto error_exit; } if (norm_dose <= 0) { goto error_exit; } d_ptr->rt_plan->set_normalization_dose (norm_dose); d_ptr->rt_plan->set_have_dose_norm(true); } else if (key == "ref_dose_point") { float rdp[3]; int rc = sscanf (val.c_str(), "%f %f %f", &rdp[0], &rdp[1], &rdp[2]); if (rc != 3) { goto error_exit; } d_ptr->rt_plan->set_ref_dose_point (rdp); d_ptr->rt_plan->set_have_ref_dose_point(true); } else if (key == "non_normalized_dose") { if (val.length() >= 1) { d_ptr->rt_plan->set_non_norm_dose (val[0]); } else { goto error_exit; } } else { goto error_exit; } return PLM_SUCCESS; } /* **** BEAM **** */ if (section == "BEAM") { Rt_beam *rt_beam = d_ptr->rt_plan->get_last_rt_beam (); if (key == "flavor") { if (val.length() >= 1) { rt_beam->set_flavor (val); } else { goto error_exit; } } else if (key == "beam_line") { rt_beam->set_beam_line_type (val); } else if (key == "homo_approx") { if (val.length() >= 1) { rt_beam->set_homo_approx (val[0]); } else { goto error_exit; } } else if (key == "ray_step") { float step_length; if (sscanf (val.c_str(), "%f", &step_length) != 1) { goto error_exit; } rt_beam->set_step_length (step_length); } else if (key == "aperture_out") { rt_beam->set_aperture_out (val); } else if (key == "proj_dose_out") { rt_beam->set_proj_dose_out (val); } else if (key == "proj_img_out") { rt_beam->set_proj_img_out (val); } else if (key == "proj_target_out") { rt_beam->set_proj_target_out (val); } else if (key == "rc_out") { rt_beam->set_range_compensator_out (val); } else if (key == "particle_number_out") { rt_beam->get_mebs()->set_particle_number_out (val); } else if (key == "sigma_out") { rt_beam->set_sigma_out (val); } else if (key == "wed_out") { rt_beam->set_wed_out (val); } else if (key == "beam_dump_out") { rt_beam->set_beam_dump_out (val); } else if (key == "dij_out") { rt_beam->set_dij_out (val); } else if (key == "beam_type") { Particle_type part = particle_type_parse (val); if (part == PARTICLE_TYPE_UNKNOWN) { goto error_exit; } rt_beam->get_mebs()->set_particle_type (part); } else if (key == "beam_weight") { float beam_weight; if (sscanf (val.c_str(), "%f", &beam_weight) != 1) { goto error_exit; } rt_beam->set_beam_weight (beam_weight); } else if (key == "depth_dose_z_max") { if (sscanf (val.c_str(), "%lf", &(d_ptr->max_depth)) != 1) { goto error_exit; } rt_beam->get_mebs()->set_depth_end(d_ptr->max_depth); } else if (key == "depth_dose_z_res") { if (sscanf (val.c_str(), "%lf", &(d_ptr->depth_res)) != 1) { goto error_exit; } rt_beam->get_mebs()->set_depth_resolution(d_ptr->max_depth); } else if (key == "source") { float src[3]; int rc = sscanf (val.c_str(), "%f %f %f", &src[0], &src[1], &src[2]); if (rc != 3) { goto error_exit; } rt_beam->set_source_position (src); } else if (key == "isocenter") { float isocenter[3]; int rc = sscanf (val.c_str(), "%f %f %f", &isocenter[0], &isocenter[1], &isocenter[2]); if (rc != 3) { goto error_exit; } rt_beam->set_isocenter_position (isocenter); } else if (key == "prescription_min_max") { float prescription_min; float prescription_max; int rc = sscanf (val.c_str(), "%f %f", &prescription_min, &prescription_max); if (rc != 2) { goto error_exit; } rt_beam->get_mebs()->set_prescription (prescription_min, prescription_max); } else if (key == "aperture_up") { float vup[3]; int rc = sscanf (val.c_str(), "%f %f %f", &vup[0], &vup[1], &vup[2]); if (rc != 3) { goto error_exit; } rt_beam->set_aperture_vup (vup); } else if (key == "aperture_offset") { float ap_distance; if (sscanf (val.c_str(), "%f", &ap_distance) != 1) { goto error_exit; } rt_beam->set_aperture_distance (ap_distance); } else if (key == "aperture_origin") { float ap_origin[2]; int rc = sscanf (val.c_str(), "%f %f", &ap_origin[0], &ap_origin[1]); if (rc != 2) { goto error_exit; } rt_beam->set_aperture_origin (ap_origin); } else if (key == "aperture_resolution") { int a, b; int rc = sscanf (val.c_str(), "%i %i", &a, &b); if (rc != 2) { goto error_exit; } plm_long ap_dim[2] = { a, b }; rt_beam->set_aperture_resolution (ap_dim); } else if (key == "aperture_spacing") { float ap_spacing[2]; int rc = sscanf (val.c_str(), "%f %f", &ap_spacing[0], &ap_spacing[1]); if (rc != 2) { goto error_exit; } rt_beam->set_aperture_spacing (ap_spacing); } else if (key == "range_comp_mc_model") { if (val.length() >= 1) { rt_beam->set_rc_MC_model (val[0]); } else { goto error_exit; } } else if (key == "source_size") { float source_size; if (sscanf (val.c_str(), "%f", &source_size) != 1) { goto error_exit; } rt_beam->set_source_size (source_size); } else if (key == "aperture_file_in") { rt_beam->set_aperture_in (val); } else if (key == "range_compensator_file_in") { rt_beam->set_range_compensator_in (val); } else if (key == "particle_number_in") { rt_beam->get_mebs()->set_particle_number_in (val); rt_beam->get_mebs()->set_have_particle_number_map(true); } else if (key == "aperture_smearing") { float smearing; if (sscanf (val.c_str(), "%f", &smearing) != 1) { goto error_exit; } rt_beam->set_smearing (smearing); } else if (key == "proximal_margin") { float proximal_margin; if (sscanf (val.c_str(), "%f", &proximal_margin) != 1) { goto error_exit; } rt_beam->get_mebs()->set_proximal_margin (proximal_margin); } else if (key == "distal_margin") { float distal_margin; if (sscanf (val.c_str(), "%f", &distal_margin) != 1) { goto error_exit; } rt_beam->get_mebs()->set_distal_margin (distal_margin); } else if (key == "energy_resolution") { float eres; if (sscanf (val.c_str(), "%f", &eres) != 1) { goto error_exit; } rt_beam->get_mebs()->set_energy_resolution(eres); } else if (key == "energy_x") { float photon_energy; if (sscanf (val.c_str(), "%f", &photon_energy) != 1) { goto error_exit; } rt_beam->get_mebs()->set_photon_energy (photon_energy); } else if (key == "spot") { float xpos, ypos, energy, sigma, weight; if (sscanf (val.c_str(), "%f,%f,%f,%f,%f", &xpos, &ypos, &energy, &sigma, &weight) != 1) { goto error_exit; } rt_beam->add_spot (xpos, ypos, energy, sigma, weight); } else { goto error_exit; } return PLM_SUCCESS; } if (section == "PEAK") { if (key == "energy") { if (sscanf (val.c_str(), "%lf", &(d_ptr->E0)) != 1) { goto error_exit; } } else if (key == "spread") { if (sscanf (val.c_str(), "%lf", &(d_ptr->spread)) != 1) { goto error_exit; } } else if (key == "weight") { if (sscanf (val.c_str(), "%lf", &(d_ptr->weight)) != 1) { goto error_exit; } } else if (key == "bragg_curve") { #if defined (commentout_TODO) d_ptr->rt_plan->beam->load (val); #endif } else { goto error_exit; } return PLM_SUCCESS; } print_and_exit ("Unknown section value: %s\n", section.c_str()); return PLM_ERROR; error_exit: print_and_exit ("Unknown (key,val) combination: (%s,%s)\n", key.c_str(), val.c_str()); return PLM_ERROR; } Plm_return_code Rt_parms::set_command_file (const char *command_file) { Rt_parms_parser rpp (this); return rpp.parse_config_file (command_file); } Plm_return_code Rt_parms::parse_args (int argc, char** argv) { int i; for (i=1; irt_plan->set_debug (true); } else { print_usage (); break; } } if (!argv[i]) { print_usage (); } return this->set_command_file (argv[i]); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_parms.h000066400000000000000000000021411321604176500275470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_parms_h_ #define _rt_parms_h_ #include "plmdose_config.h" #include #include "plm_return_code.h" #include "rt_plan.h" #include "smart_pointer.h" #include "threading.h" class Plm_image; class Rt_parms_private; class Rt_plan; class PLMDOSE_API Rt_parms { public: SMART_POINTER_SUPPORT (Rt_parms); Rt_parms_private *d_ptr; public: Rt_parms (); Rt_parms (Rt_plan* rt_plan); ~Rt_parms (); public: void set_rt_plan (Rt_plan *rt_plan); Plm_return_code set_command_file (const char *command_file); Plm_return_code parse_args (int argc, char** argv); Plm_return_code set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val); void append_beam (); void append_peak (); protected: void parse_config (const char* config_fn); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_plan.cxx000077500000000000000000000564511321604176500277520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include #include #include #include "aperture.h" #include "dose_volume_functions.h" #include "float_pair_list.h" #include "plm_image.h" #include "plm_exception.h" #include "plm_timer.h" #include "print_and_exit.h" #include "proj_matrix.h" #include "proj_volume.h" #include "ray_data.h" #include "rpl_volume.h" #include "rt_beam.h" #include "rt_beam_model.h" #include "rt_depth_dose.h" #include "rt_dose.h" #include "rt_dose_timing.h" #include "rt_lut.h" #include "rt_parms.h" #include "rt_plan.h" #include "rt_sigma.h" #include "rt_mebs.h" #include "rt_study.h" #include "volume.h" #include "volume_adjust.h" #include "volume_header.h" #include "volume_macros.h" #include "volume_resample.h" class Rt_plan_private { public: bool debug; float rdp[3]; bool have_rdp; bool have_dose_norm; float normalization_dose; // dose prescription char non_norm_dose; float depth_dose_max; /* Filenames for input and output images */ std::string patient_fn; std::string target_fn; std::string output_dose_fn; std::string output_psp_fn; /* Patient (hu), patient (ed or sp) , target, output dose volume */ Plm_image::Pointer patient_hu; Plm_image::Pointer patient_psp; Plm_image::Pointer target; Plm_image::Pointer dose; Rt_parms::Pointer rt_parms; Rt_study* rt_study; Rt_dose_timing::Pointer rt_dose_timing; Rt_beam_model::Pointer beam_model; /* Storage of beams */ std::vector beam_storage; public: Rt_plan_private () { debug = false; this->rdp[0] = 0.f; this->rdp[1] = 0.f; this->rdp[2] = 0.f; this->have_rdp = false; this->have_dose_norm = false; this->normalization_dose = 100.f; this->non_norm_dose = 'n'; this->depth_dose_max = 1.f; patient_hu = Plm_image::New(); patient_psp = Plm_image::Pointer(); target = Plm_image::Pointer(); dose = Plm_image::New(); rt_parms = Rt_parms::New (); rt_dose_timing = Rt_dose_timing::New (); } ~Rt_plan_private () { } }; Rt_plan::Rt_plan () { this->d_ptr = new Rt_plan_private; d_ptr->rt_parms->set_rt_plan (this); } Rt_plan::~Rt_plan () { delete d_ptr; } Plm_return_code Rt_plan::parse_args (int argc, char* argv[]) { return d_ptr->rt_parms->parse_args (argc, argv); } Plm_return_code Rt_plan::set_command_file (const char *command_file) { return d_ptr->rt_parms->set_command_file (command_file); } void Rt_plan::set_patient (const std::string& patient_fn) { d_ptr->patient_fn = patient_fn; } void Rt_plan::set_patient (Plm_image::Pointer& ct_vol) { d_ptr->patient_hu = ct_vol; d_ptr->patient_hu->convert (PLM_IMG_TYPE_GPUIT_FLOAT); d_ptr->patient_psp = Plm_image::Pointer (); } void Rt_plan::set_patient (ShortImageType::Pointer& ct_vol) { /* compute_segdepth_volume assumes float, so convert here */ d_ptr->patient_hu->set_itk (ct_vol); d_ptr->patient_hu->convert (PLM_IMG_TYPE_GPUIT_FLOAT); d_ptr->patient_psp = Plm_image::Pointer (); } void Rt_plan::set_patient (FloatImageType::Pointer& ct_vol) { d_ptr->patient_hu->set_itk (ct_vol); d_ptr->patient_hu->convert (PLM_IMG_TYPE_GPUIT_FLOAT); d_ptr->patient_psp = Plm_image::Pointer (); } void Rt_plan::set_patient (Volume* ct_vol) { d_ptr->patient_hu->set_volume (ct_vol); } Volume::Pointer Rt_plan::get_patient_volume () { return d_ptr->patient_hu->get_volume_float (); } Plm_image * Rt_plan::get_patient () { return d_ptr->patient_hu.get(); } void Rt_plan::set_target (const std::string& target_fn) { d_ptr->target_fn = target_fn; } void Rt_plan::set_target (UCharImageType::Pointer& target_vol) { d_ptr->target = Plm_image::New (target_vol); /* compute_segdepth_volume assumes float */ d_ptr->target->convert (PLM_IMG_TYPE_GPUIT_FLOAT); this->propagate_target_to_beams (); } void Rt_plan::set_target (FloatImageType::Pointer& target_vol) { d_ptr->target = Plm_image::New (target_vol); /* compute_segdepth_volume assumes float */ d_ptr->target->convert (PLM_IMG_TYPE_GPUIT_FLOAT); this->propagate_target_to_beams (); } void Rt_plan::load_target () { if (d_ptr->target_fn == "") { return; } d_ptr->target = Plm_image::New (new Plm_image (d_ptr->target_fn)); /* Need float, because compute_segdepth_volume assumes float */ d_ptr->target->convert (PLM_IMG_TYPE_GPUIT_FLOAT); this->propagate_target_to_beams (); } Plm_image::Pointer& Rt_plan::get_target () { return d_ptr->target; } void Rt_plan::set_rt_study(Rt_study* rt_study) { d_ptr->rt_study = rt_study; } Rt_study* Rt_plan::get_rt_study() { return d_ptr->rt_study; } Rt_beam* Rt_plan::append_beam () { Rt_beam* last_beam = get_last_rt_beam (); Rt_beam* new_beam; if (last_beam) { new_beam = new Rt_beam (last_beam); } else { new_beam = new Rt_beam; } d_ptr->beam_storage.push_back (new_beam); new_beam->set_rt_dose_timing (d_ptr->rt_dose_timing); new_beam->set_target (d_ptr->target); return new_beam; } Rt_beam* Rt_plan::get_last_rt_beam () { if (d_ptr->beam_storage.empty()) { return 0; } return d_ptr->beam_storage.back(); } bool Rt_plan::get_debug (void) const { return d_ptr->debug; } void Rt_plan::set_debug (bool debug) { d_ptr->debug = debug; } void Rt_plan::set_threading (Threading threading) { /* Not used yet */ } void Rt_plan::set_normalization_dose (float normalization_dose) { d_ptr->normalization_dose = normalization_dose; } float Rt_plan::get_normalization_dose() { return d_ptr->normalization_dose; } const float* Rt_plan::get_ref_dose_point () const { return d_ptr->rdp; } float Rt_plan::get_ref_dose_point (int dim) const { return d_ptr->rdp[dim]; } void Rt_plan::set_ref_dose_point (const float* rdp) { for (int d = 0; d < 3; d++) { d_ptr->rdp[d] = rdp[d]; } } void Rt_plan::set_ref_dose_point (const double* rdp) { for (int d = 0; d < 3; d++) { d_ptr->rdp[d] = rdp[d]; } } void Rt_plan::set_have_ref_dose_point(bool have_rdp) { d_ptr->have_rdp = have_rdp; } bool Rt_plan::get_have_ref_dose_point() { return d_ptr->have_rdp; } void Rt_plan::set_have_dose_norm (bool have_dose_norm) { d_ptr->have_dose_norm = have_dose_norm; } bool Rt_plan::get_have_dose_norm() { return d_ptr->have_dose_norm; } char Rt_plan::get_non_norm_dose () const { return d_ptr->non_norm_dose; } void Rt_plan::set_non_norm_dose (char non_norm_dose) { d_ptr->non_norm_dose = non_norm_dose; } void Rt_plan::propagate_target_to_beams () { /* Loop through beams, and reset target on them */ for (size_t i = 0; i < d_ptr->beam_storage.size(); i++) { d_ptr->beam_storage[i]->set_target(d_ptr->target); } } void Rt_plan::create_patient_psp () { Float_pair_list lookup; lookup.push_back (std::pair (NLMIN(float), 0)); lookup.push_back (std::pair (-1000, 0.00106)); lookup.push_back (std::pair (0, 1.0)); lookup.push_back (std::pair (41.46, 1.048674)); lookup.push_back (std::pair (NLMAX(float), 0.005011)); Volume::Pointer psp = volume_adjust ( d_ptr->patient_hu->get_volume(), lookup); d_ptr->patient_psp = Plm_image::New (psp); } void Rt_plan::normalize_beam_dose (Rt_beam *beam) { Plm_image::Pointer dose = beam->get_dose (); Volume::Pointer dose_vol = dose->get_volume (); float* dose_img = (float*) dose_vol->img; /* Dose normalization process*/ if (this->get_non_norm_dose() != 'y') { if (this->get_have_ref_dose_point()) // case 1: ref dose point defined { float rdp_ijk[3] = {0,0,0}; float rdp[3] = {this->get_ref_dose_point(0), this->get_ref_dose_point(1), this->get_ref_dose_point(2)}; rdp_ijk[0] = (rdp[0] - dose_vol->origin[0]) / dose_vol->spacing[0]; rdp_ijk[1] = (rdp[1] - dose_vol->origin[1]) / dose_vol->spacing[1]; rdp_ijk[2] = (rdp[2] - dose_vol->origin[2]) / dose_vol->spacing[2]; if (rdp_ijk[0] >=0 && rdp_ijk[1] >=0 && rdp_ijk[2] >=0 && rdp_ijk[0] < dose_vol->dim[0] && rdp_ijk[1] < dose_vol->dim[1] && rdp_ijk[2] < dose_vol->dim[2]) { printf("Dose normalized to the dose reference point.\n"); dose_normalization_to_dose_and_point(dose_vol, beam->get_beam_weight() * this->get_normalization_dose(), rdp_ijk, rdp, beam); // if no normalization dose, norm_dose = 1 by default if (this->get_have_dose_norm()) { printf("%lg x %lg Gy.\n", beam->get_beam_weight(), this->get_normalization_dose()); } else { printf("%lg x 100%%.\n", beam->get_beam_weight()); } printf("Primary PB num. x, y: %d, %d, primary PB res. x, y: %lg PB/mm, %lg PB/mm\n", beam->get_aperture()->get_dim(0), beam->get_aperture()->get_dim(1), 1.0 / (double) beam->get_aperture()->get_spacing(0), 1.0 / (double) beam->get_aperture()->get_spacing(1)); } else { printf("***WARNING***\nThe reference dose point is not in the image volume.\n"); dose_normalization_to_dose(dose_vol, beam->get_beam_weight() * this->get_normalization_dose(), beam); if (this->get_have_dose_norm()) { printf("%lg x %lg Gy.\n", beam->get_beam_weight(), this->get_normalization_dose()); } else { printf("%lg x 100%%.\n", beam->get_beam_weight()); } printf("Primary PB num. x, y: %d, %d, primary PB res. x, y: %lg PB/mm, %lg PB/mm\n", beam->get_aperture()->get_dim(0), beam->get_aperture()->get_dim(1), 1.0 / (double) beam->get_aperture()->get_spacing(0), 1.0 / (double) beam->get_aperture()->get_spacing(1)); } } else // case 2: no red dose point defined { dose_normalization_to_dose(dose_vol, beam->get_beam_weight() * this->get_normalization_dose(), beam); // normalization_dose = 1 if no dose_prescription is set if (this->get_have_dose_norm()) { printf("%lg x %lg Gy.\n", beam->get_beam_weight(), this->get_normalization_dose()); } else { printf("%lg x 100%%.\n", beam->get_beam_weight()); } printf("Primary PB num. x, y: %d, %d, primary PB res. x, y: %lg PB/mm, %lg PB/mm\n", beam->get_aperture()->get_dim(0), beam->get_aperture()->get_dim(1), 1.0 / (double) beam->get_aperture()->get_spacing(0), 1.0 / (double) beam->get_aperture()->get_spacing(1)); } } else // raw dose, dose not normalized { for (int i = 0; i < dose_vol->dim[0] * dose_vol->dim[1] * dose_vol->dim[2]; i++) { dose_img[i] *= beam->get_beam_weight(); } } } void Rt_plan::compute_dose (Rt_beam *beam) { printf ("-- compute_dose entry --\n"); d_ptr->rt_dose_timing->timer_misc.resume (); Volume::Pointer ct_vol = this->get_patient_volume (); Volume::Pointer dose_vol = ct_vol->clone_empty (); Volume* dose_volume_tmp = new Volume; float margin = 0; int margins[2] = {0,0}; double range = 0; int new_dim[2]={0,0}; double new_center[2]={0,0}; double biggest_sigma_ever = 0; /* Convert from HU to stopping power, if not already done */ if (!d_ptr->patient_psp) { this->create_patient_psp (); } /* Resample target to match CT resolution, if not already done */ if (d_ptr->target) { Volume_header vh (d_ptr->patient_hu); d_ptr->target->set_volume ( volume_resample (d_ptr->target->get_volume(), &vh)); this->propagate_target_to_beams (); } d_ptr->rt_dose_timing->timer_misc.stop (); /* Create rpl images, compute beam modifiers, SOBP etc. according to the teatment strategy */ d_ptr->rt_dose_timing->timer_dose_calc.resume (); if (!beam->prepare_for_calc (d_ptr->patient_hu, d_ptr->patient_psp, d_ptr->target)) { print_and_exit ("ERROR: Unable to initiliaze plan.\n"); } d_ptr->rt_dose_timing->timer_dose_calc.stop (); #if defined (commentout) printf ("Computing rpl_ct\n"); beam->hu_samp_vol->compute_rpl_HU (); #endif if (beam->get_flavor() == "a") { compute_dose_a (dose_vol, beam, ct_vol); } else if (beam->get_flavor() == "b") { d_ptr->rt_dose_timing->timer_dose_calc.resume (); // Add range compensator to rpl volume if (beam->rsp_accum_vol->get_aperture()->have_range_compensator_image()) { add_rcomp_length_to_rpl_volume(beam); } // Loop through energies Rt_mebs::Pointer mebs = beam->get_mebs(); std::vector depth_dose = mebs->get_depth_dose(); for (size_t i = 0; i < depth_dose.size(); i++) { compute_dose_b (beam, i, ct_vol); } d_ptr->rt_dose_timing->timer_dose_calc.stop (); d_ptr->rt_dose_timing->timer_reformat.resume (); dose_volume_reconstruction (beam->dose_rv, dose_vol); d_ptr->rt_dose_timing->timer_reformat.stop (); } else if (beam->get_flavor() == "ray_trace_dij_a") { /* This is the same as alg 'a', except that it computes and exports Dij matrices */ d_ptr->rt_dose_timing->timer_dose_calc.resume (); // Loop through energies Rt_mebs::Pointer mebs = beam->get_mebs(); std::vector depth_dose = mebs->get_depth_dose(); for (size_t i = 0; i < depth_dose.size(); i++) { compute_dose_ray_trace_dij_a (beam, i, ct_vol, dose_vol); } d_ptr->rt_dose_timing->timer_dose_calc.resume (); } else if (beam->get_flavor() == "ray_trace_dij_b") { /* This is the same as alg 'b', except that it computes and exports Dij matrices */ d_ptr->rt_dose_timing->timer_dose_calc.resume (); // Add range compensator to rpl volume if (beam->rsp_accum_vol->get_aperture()->have_range_compensator_image()) { add_rcomp_length_to_rpl_volume(beam); } // Loop through energies compute_dose_ray_trace_dij_b (beam, ct_vol, dose_vol); d_ptr->rt_dose_timing->timer_dose_calc.stop (); d_ptr->rt_dose_timing->timer_reformat.resume (); dose_volume_reconstruction (beam->dose_rv, dose_vol); d_ptr->rt_dose_timing->timer_reformat.stop (); } else if (beam->get_flavor() == "d") { // Loop through energies Rt_mebs::Pointer mebs = beam->get_mebs(); std::vector depth_dose = mebs->get_depth_dose(); for (size_t i = 0; i < depth_dose.size(); i++) { compute_dose_d (beam, i, ct_vol); } d_ptr->rt_dose_timing->timer_reformat.resume (); dose_volume_reconstruction (beam->dose_rv, dose_vol); d_ptr->rt_dose_timing->timer_reformat.stop (); } d_ptr->rt_dose_timing->timer_misc.resume (); Plm_image::Pointer dose = Plm_image::New(); dose->set_volume (dose_vol); beam->set_dose (dose); this->normalize_beam_dose (beam); d_ptr->rt_dose_timing->timer_misc.stop (); } Plm_return_code Rt_plan::compute_plan () { d_ptr->rt_dose_timing->reset (); if (!d_ptr->rt_parms) { print_and_exit ("Error: cannot compute_plan without an Rt_parms\n"); } if (d_ptr->output_dose_fn == "") { print_and_exit ("Error: Output dose filename " "not specified in configuration file!\n"); } if (d_ptr->patient_fn == "") { print_and_exit ("Error: Patient image " "not specified in configuration file!\n"); } /* Load the patient CT image */ d_ptr->rt_dose_timing->timer_io.resume (); Plm_image::Pointer ct = Plm_image::New (d_ptr->patient_fn, PLM_IMG_TYPE_ITK_FLOAT); if (!ct) { print_and_exit ("Error: Unable to load patient volume.\n"); } this->set_patient (ct); /* Load the patient target structure */ this->load_target (); d_ptr->rt_dose_timing->timer_io.stop (); /* Display debugging information */ d_ptr->rt_dose_timing->timer_misc.resume (); this->print_verif (); Volume::Pointer ct_vol = this->get_patient_volume (); Volume::Pointer dose_vol = ct_vol->clone_empty (); plm_long dim[3] = {dose_vol->dim[0], dose_vol->dim[1], dose_vol->dim[2]}; float* total_dose_img = (float*) dose_vol->img; d_ptr->rt_dose_timing->timer_misc.stop (); for (size_t i = 0; i < d_ptr->beam_storage.size(); i++) { printf ("\nStart dose calculation Beam %d\n", (int) i + 1); Rt_beam *beam = d_ptr->beam_storage[i]; /* Generate dose */ this->set_debug (true); this->compute_dose (beam); /* Save beam data */ d_ptr->rt_dose_timing->timer_io.resume (); beam->save_beam_output (); d_ptr->rt_dose_timing->timer_io.stop (); /* Dose cumulation to the plan dose volume */ d_ptr->rt_dose_timing->timer_misc.resume (); float* beam_dose_img = (float*) d_ptr->beam_storage[i]->get_dose()->get_volume()->img; for (int j = 0; j < dim[0] * dim[1] * dim[2]; j++) { total_dose_img[j] += beam_dose_img[j]; } d_ptr->rt_dose_timing->timer_misc.stop (); } /* Save stopping power image */ d_ptr->rt_dose_timing->timer_io.resume (); if (d_ptr->output_psp_fn != "") { d_ptr->patient_psp->save_image (d_ptr->output_psp_fn); } /* Save dose output */ Plm_image::Pointer dose = Plm_image::New(); dose->set_volume (dose_vol); this->set_dose(dose); this->get_dose()->save_image (d_ptr->output_dose_fn.c_str()); d_ptr->rt_dose_timing->timer_io.stop (); d_ptr->rt_dose_timing->report (); printf ("done. \n\n"); return PLM_SUCCESS; } Plm_image::Pointer Rt_plan::get_dose () { return d_ptr->dose; } FloatImageType::Pointer Rt_plan::get_dose_itk () { return d_ptr->dose->itk_float(); } void Rt_plan::set_output_dose_fn (const std::string& output_dose_fn) { d_ptr->output_dose_fn = output_dose_fn; } void Rt_plan::set_output_psp_fn (const std::string& output_psp_fn) { d_ptr->output_psp_fn = output_psp_fn; } void Rt_plan::set_dose (Plm_image::Pointer& dose) { d_ptr->dose = dose; } void Rt_plan::print_verif () { printf("\n [PLAN]"); printf("\n patient : %s", d_ptr->patient_fn.c_str()); printf("\n target : %s", d_ptr->target_fn.c_str()); printf("\n dose_out : %s", d_ptr->output_dose_fn.c_str()); printf("\n debug : %d", this->get_debug()); printf("\n dose norm : %lg", this->get_normalization_dose()); printf("\n \n [SETTINGS]"); int num_beams = d_ptr->beam_storage.size(); printf("\n flavor: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_flavor().c_str());} printf("\n homo_approx: "); for (int i = 0; i < num_beams; i++) {printf("%c ** ", d_ptr->beam_storage[i]->get_homo_approx());} printf("\n ray_step: "); for (int i = 0; i < num_beams; i++) {printf("%lg ** ", d_ptr->beam_storage[i]->get_step_length());} printf("\n aperture_out: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_aperture_out().c_str());} printf("\n proj_dose_out: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_proj_dose_out().c_str());} printf("\n proj_img_out: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_proj_img_out().c_str());} printf("\n range_comp_out: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_range_compensator_out().c_str());} printf("\n sigma_out: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_sigma_out().c_str());} printf("\n wed_out: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_wed_out().c_str());} printf("\n beam_weight: "); for (int i = 0; i < num_beams; i++) {printf("%g ** ", d_ptr->beam_storage[i]->get_beam_weight());} printf("\n \n [GEOMETRY & APERTURE]"); printf("\n source: "); for (int i = 0; i < num_beams; i++) {printf("%lg %lg %lg ** ", d_ptr->beam_storage[i]->get_source_position()[0], d_ptr->beam_storage[i]->get_source_position()[1], d_ptr->beam_storage[i]->get_source_position()[2]);} printf("\n isocenter: "); for (int i = 0; i < num_beams; i++) {printf("%lg %lg %lg ** ", d_ptr->beam_storage[i]->get_isocenter_position()[0], d_ptr->beam_storage[i]->get_isocenter_position()[1], d_ptr->beam_storage[i]->get_isocenter_position()[2]);} printf("\n vup: "); for (int i = 0; i < num_beams; i++) {printf("%lg %lg %lg ** ", d_ptr->beam_storage[i]->get_aperture()->vup[0], d_ptr->beam_storage[i]->get_aperture()->vup[1], d_ptr->beam_storage[i]->get_aperture()->vup[2]);} printf("\n offset: "); for (int i = 0; i < num_beams; i++) {printf("%lg ** ", d_ptr->beam_storage[i]->get_aperture()->get_distance());} printf("\n ap_center in pixels: "); for (int i = 0; i < num_beams; i++) {printf("%lg %lg ** ", d_ptr->beam_storage[i]->get_aperture()->get_center()[0], d_ptr->beam_storage[i]->get_aperture()->get_center()[1]);} printf("\n i_res: "); for (int i = 0; i < num_beams; i++) {printf("%d %d ** ", d_ptr->beam_storage[i]->get_aperture()->get_dim()[0], d_ptr->beam_storage[i]->get_aperture()->get_dim()[1]);} printf("\n spacing: "); for (int i = 0; i < num_beams; i++) {printf("%lg %lg ** ", d_ptr->beam_storage[i]->get_aperture()->get_spacing()[0], d_ptr->beam_storage[i]->get_aperture()->get_spacing()[1]);} printf("\n source_size: "); for (int i = 0; i < num_beams; i++) {printf("%lg ** ", d_ptr->beam_storage[i]->get_source_size());} printf("\n ap_file_in: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_aperture_in().c_str());} printf("\n rc_file_in: "); for (int i = 0; i < num_beams; i++) {printf("%s ** ", d_ptr->beam_storage[i]->get_range_compensator_in().c_str());} printf("\n smearing: "); for (int i = 0; i < num_beams; i++) {printf("%lg ** ", d_ptr->beam_storage[i]->get_smearing());} printf("\n \n [PEAK]"); printf("\n E0: "); for (int i = 0; i < num_beams; i++) { printf("P%d ",i); for (size_t j = 0; j < d_ptr->beam_storage[i]->get_mebs()->get_depth_dose().size(); j++) { printf("%lg ** ", d_ptr->beam_storage[i]->get_mebs()->get_depth_dose()[j]->E0); } } printf("\n spread: "); for (int i = 0; i < num_beams; i++) { printf("P%d ",i); for (size_t j = 0; j < d_ptr->beam_storage[i]->get_mebs()->get_depth_dose().size(); j++) { printf("%lg ** ", d_ptr->beam_storage[i]->get_mebs()->get_depth_dose()[j]->spread); } } printf("\n weight: "); for (int i = 0; i < num_beams; i++) { printf("P%d ",i); for (size_t j = 0; j < d_ptr->beam_storage[i]->get_mebs()->get_depth_dose().size(); j++) { printf("%lg ** ", d_ptr->beam_storage[i]->get_mebs()->get_weight()[j]); } } printf ("\n"); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_plan.h000066400000000000000000000071011321604176500273600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_plan_h_ #define _rt_plan_h_ #include "plmdose_config.h" #include "plm_image.h" #include "plm_return_code.h" #include "rt_beam.h" #include "smart_pointer.h" #include "threading.h" class Plm_image; class Proj_matrix; class Rpl_volume; class Rt_plan_private; class Rt_study; class Volume; class PLMDOSE_API Rt_plan { public: SMART_POINTER_SUPPORT (Rt_plan); Rt_plan_private *d_ptr; public: Rt_plan (); ~Rt_plan (); public: Plm_return_code parse_args (int argc, char* argv[]); Plm_return_code set_command_file (const char *command_file); /* Set the CT volume for dose calculation. The Rt_plan takes ownership of this CT/Patient. */ void set_patient (const std::string& patient_fn); void set_patient (Plm_image::Pointer&); void set_patient (ShortImageType::Pointer&); void set_patient (FloatImageType::Pointer&); void set_patient (Volume*); /* Get the patient volume */ Volume::Pointer get_patient_volume (); Plm_image *get_patient (); /* Set/Get the target volume */ void set_target (const std::string& target_fn); void set_target (UCharImageType::Pointer&); void set_target (FloatImageType::Pointer&); Plm_image::Pointer& get_target (); void load_target (); /* Set/Get Rt_study */ void set_rt_study(Rt_study* rt_study); Rt_study* get_rt_study(); /* Get/Set Rt_beam(s) */ Rt_beam* append_beam (); Rt_beam* get_last_rt_beam (); /* Return the state of the debug flag, which generates debug information on the console */ bool get_debug () const; /* Set the state of the debug flag, which generates debug information on the console */ void set_debug (bool debug); /* Set/Get threading */ void set_threading (Threading threading); /* Set/Set normalization dose */ void set_normalization_dose (float normalization_dose); float get_normalization_dose (); /* Get the position of the beam isocenter in world coordinates. */ const float* get_ref_dose_point () const; /* Get the x, y, or z coordinate of the beam source in world coordinates. */ float get_ref_dose_point (int dim) const; /* Set the position of the beam isocenter in world coordinates. */ void set_ref_dose_point (const float rdp[3]); /* Set the position of the beam isocenter in world coordinates. */ void set_ref_dose_point (const double rdp[3]); /* Set / Get the declaration of the normalization conditions*/ void set_have_ref_dose_point(bool have_rdp); bool get_have_ref_dose_point(); void set_have_dose_norm(bool have_dose_norm); bool get_have_dose_norm(); /*! \brief Get the "non normalized" dose option */ char get_non_norm_dose () const; /*! \brief Set "non normalized" dose option */ void set_non_norm_dose (char non_norm_dose); /* Compute dose */ void create_patient_psp (); void propagate_target_to_beams (); void compute_dose (Rt_beam *beam); Plm_return_code compute_plan (); void normalize_beam_dose (Rt_beam *beam); /* Getting outputs and creating output files */ Plm_image::Pointer get_dose (); FloatImageType::Pointer get_dose_itk (); void set_output_dose_fn (const std::string& output_dose_fn); void set_output_psp_fn (const std::string& output_psp_fn); void set_dose(Plm_image::Pointer& dose); void print_verif (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_sigma.cxx000077500000000000000000000574141321604176500301200ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include "ray_data.h" #include "rpl_volume.h" #include "rt_beam.h" #include "rt_lut.h" #include "rt_sigma.h" void compute_sigmas ( const Rt_beam* beam, float energy, float* sigma_max, std::string size, int* margins) { // We compute the sigmas for source, range compensator and patient // as described in the Hong's paper. // First we set the volume in which the sigmas have to be calculated: // the normal rpl_sigma_volume, or the extended rpl_sigma_volume // for margins. Rpl_volume* sigma_vol; Rpl_volume* ct_vol; Rpl_volume* rgl_vol; if (size == "small") { sigma_vol = beam->sigma_vol; ct_vol = beam->hu_samp_vol; rgl_vol = beam->rsp_accum_vol; } else { sigma_vol = beam->sigma_vol_lg; ct_vol = beam->rpl_vol_samp_lg; rgl_vol = beam->rpl_vol_lg; } /* Now that the volumes were defined, we can compute the sigmas in them and do the quadratic sigmas sum */ /* sigma^2 patient */ compute_sigma_pt (sigma_vol, rgl_vol, ct_vol, beam, energy); /* + sigma^2 source */ if (beam->get_source_size() > 0) { compute_sigma_source (sigma_vol, rgl_vol, beam, energy); } else { printf("Sigma source computed - sigma_src_max = 0 mm. (Source size <= 0)\n"); } /* + sigma^2 range compensator */ if (beam->get_aperture()->have_range_compensator_image() && energy > 1) { compute_sigma_range_compensator(sigma_vol, rgl_vol, beam, energy, margins); } else { printf("Sigma range compensator computed - sigma_rc_max = 0 mm. (No range compensator or the energy is too small)\n"); } /* Last step: sigma = sqrt(sigma_pt^2 + sigma_src^2 + sigma_rc^2), at this point sigma_vol contains the sum of the sigmas' square */ /* We update also the value of sigma_max */ float* sigma_img = (float*) sigma_vol->get_vol()->img; plm_long dim[3] = { sigma_vol->get_vol()->dim[0], sigma_vol->get_vol()->dim[1], sigma_vol->get_vol()->dim[2] }; *sigma_max = 0; for (int i = 0; i < dim[0] * dim[1] * dim[2]; i++) { sigma_img[i] = sqrt(sigma_img[i]); if (sigma_img[i] > *sigma_max) { *sigma_max = sigma_img[i]; } } printf("Global sigma computed - Global sigma_max = %lg mm.\n", *sigma_max); return; } void compute_sigma_pt ( Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rpl_volume* ct_vol, const Rt_beam* beam, float energy) { float sigma_max = 0; if (beam->get_homo_approx() == 'y') { sigma_max = compute_sigma_pt_homo (sigma_vol, rpl_volume, energy); } else { sigma_max = compute_sigma_pt_hetero (sigma_vol, rpl_volume, ct_vol, energy); } printf("Sigma patient computed - sigma_pt_max = %lg mm.\n", sigma_max); return; } float compute_sigma_pt_homo ( Rpl_volume* sigma_vol, Rpl_volume* rpl_vol, float energy) { float sigma_max = 0; const plm_long *dim = sigma_vol->get_vol()->dim; const plm_long *dim_rpl = rpl_vol->get_vol()->dim; int idx = 0; if (dim[0] != dim_rpl[0] || dim[1] != dim_rpl[1] || dim[2] != dim_rpl[2]) { printf("Error: rpl_vol & sigma_vol have different dimensions. Sigma volume not built\n"); return 0; } // At this time, sigma_vol contains the range length, // WITHOUT range compensator float* sigma_volume = (float*) sigma_vol->get_vol()->img; float* rpl_img = (float*) rpl_vol->get_vol()->img; double x_over_range = 0; unsigned char* ap_img = 0; if (rpl_vol->get_aperture()->have_aperture_image()) { ap_img = (unsigned char*) rpl_vol->get_aperture()->get_aperture_volume()->img; } /* Hong method to calculate the sigma value for homogeneous medium */ /* Range value in water extracted from a fit based on 1-250MeV from the NIST data - ranges in mm */ double range = 10 * get_proton_range(energy); // Sigma0 value from the Hong fit - See paper Hong "A pencil beam // algorithm for proton dose calculation" - sigma in mm: x10 double sigma0 = 0.02275 * range + 1.2085E-6 * range * range; /* Calculation of the sigma values from the medium equivalent depth */ for (int i = 0; i < dim[0] * dim [1]; i++) { for (int k = 0; k < dim[2]; k++) { idx = k * dim[0] * dim[1] + i; if (ap_img && ap_img[i] == 0) { continue; } if (rpl_img[idx] <= 0) { sigma_volume[idx] = 0; } else if (rpl_img[idx] >= range) { // sigma will contains the square of the sigmas to do // the quadratic sum sigma_volume[idx] = sigma0 * sigma0; /* sigma_max update */ if (sigma0 > sigma_max) { sigma_max = sigma0; } } else { x_over_range = rpl_img[idx] / range; /* sigma = y0 * Hong (x/range) */ sigma_volume[idx] = sigma0 * x_over_range * ( 0.26232 + 0.64298 * x_over_range + 0.0952393 * x_over_range * x_over_range); if (sigma_volume[idx] > sigma_max) { sigma_max = sigma_volume[idx]; } // We return sigma^2 to sigma_vol sigma_volume[idx] *= sigma_volume[idx]; } } } return sigma_max; } float compute_sigma_pt_hetero ( Rpl_volume* sigma_vol, Rpl_volume* rpl_vol, Rpl_volume* ct_vol, float energy) { float sigma_max = 0; float* sigma_img = (float*) sigma_vol->get_vol()->img; float* rpl_img = (float*) rpl_vol->get_vol()->img; float* ct_img = (float*) ct_vol->get_vol()->img; unsigned char* ap_img = 0; if (rpl_vol->get_aperture()->have_aperture_image()) { ap_img = (unsigned char*) rpl_vol->get_aperture()->get_aperture_volume()->img; } plm_long dim[3] = { sigma_vol->get_vol()->dim[0], sigma_vol->get_vol()->dim[1], sigma_vol->get_vol()->dim[2]}; std::vector sigma_ray (dim[2],0); std::vector HU_ray (dim[2],0); std::vector range_length_ray (dim[2], 0); /* some variables useful for the sigma integration */ int idx = 0; float spacing = sigma_vol->get_vol()->spacing[2]/10; // in cm to correspond to the Highland formula float E = energy; float mc2 = (float) PROTON_REST_MASS; /* proton mass at rest (MeV) */ float c = (float) LIGHT_SPEED; /* speed of light (m/s) */ float p = 0.0; /* Proton momentum (passed in) */ float v = 0.0; /* Proton velocity (passed in) */ float function_to_be_integrated; /* right term to be integrated in the Highland equation */ float inverse_rad_length_integrated = 0; /* and left part */ float sum = 0.0; /* integration expressions, right part of equation */ float POI_depth = 0.0; /* depth of the point of interest (where is calculated the sigma value)in cm - centered at the pixel center */ float pixel_depth = 0.0; /* depth of the contributing pixel to total sigma (in cm) - center between 2 pixels, the difference in rglength comes from the center of the previous pixel to the center of this pixel */ float step = 0.0; /* step of integration, will depends on the radiologic length */ /* initializiation of all the rays on which the integration will be done */ printf ("sigma_img: %d %d %d\n", (int) sigma_vol->get_vol()->dim[0], (int) sigma_vol->get_vol()->dim[1], (int) sigma_vol->get_vol()->dim[2]); printf("dim: %d %d %d\n", (int) dim[0], (int) dim[1], (int) dim[2]); for (int apert_idx = 0; apert_idx < dim[0] * dim[1]; apert_idx++) { if (!rpl_vol->get_aperture()->have_aperture_image() || (rpl_vol->get_aperture()->have_aperture_image() && ap_img[apert_idx] > 0)) { int first_non_null_loc = 0; for (int s = 0; s < dim[2]; s++) { idx = dim[0]*dim[1]*s + apert_idx; range_length_ray[s] = rpl_img[idx]; // at this point sigma is still a range_length volume without range compensator sigma_ray[s] = 0; HU_ray[s] = ct_img[idx]; // the density ray is initialized with density } //Now we can compute the sigma rays!!!! /* Step 1: the sigma is filled with zeros, so we let them = 0 as long as rg_length is 0, meaning the ray is out of the physical volume */ /* we mark the first pixel in the volume, and the calculations will start with this one */ for (int s = 0; s < dim[2]; s++) { if (range_length_ray[s] > 0) { first_non_null_loc = s; break; } if (s == dim[2]-1) { first_non_null_loc = dim[2]-1; } } // Step 2: Each pixel in the volume will receive its sigma // (in reality y0) value, according to the differential // Highland formula */ std::vector pv_cache (dim[2], 0); std::vector inv_rad_len (dim[2], 0); std::vector stop_cache (dim[2], 0); // we set the energy of the particles to the nominal energy // for this ray E = energy; for (int s = first_non_null_loc; s < dim[2]; s++) { p = sqrt(2*E*mc2+E*E)/c; // in MeV.s.m-1 v = c*sqrt(1-pow((mc2/(E+mc2)),2)); //in m.s-1 pv_cache[s] = p * v; /* GCS FIX: The X0 depends on radiation length, not proton stopping power. Yuck. */ // dE/dx_mat = dE /dx_watter * STPR (lut in g/cm2) inv_rad_len[s] = 1.0f / compute_X0_from_HU(HU_ray[s]); stop_cache[s] = compute_PrSTPR_from_HU(HU_ray[s]) * get_proton_stop(E); sum = 0; inverse_rad_length_integrated = 0; POI_depth = (float) (s+0.5)*spacing; E = energy; /*integration */ for (int t = first_non_null_loc; t <= s && E > 0.1;t++) // 0.1 cut off energy, if set to 0, the very small energies create a singularity and a giant/wrong sigma { if (t == s) { pixel_depth = (t+.25f)*spacing; // we integrate only up to the voxel center, not the whole pixel step = spacing/2; } else { pixel_depth = (t+0.5f)*spacing; step = spacing; } function_to_be_integrated = pow(((POI_depth - pixel_depth)/pv_cache[t]),2) * inv_rad_len[t]; //i in cm sum += function_to_be_integrated*step; inverse_rad_length_integrated += step * inv_rad_len[t]; /* energy is updated after passing through dz */ E = E - step * stop_cache[t]; } // We have reached the POI pixel and we can store the y0 value sigma_ray[s] = 141.0f *(1.0f+1.0f/9.0f*log10(inverse_rad_length_integrated))* (float) sqrt(sum); // in mm if (E < 0.25) // sigma formula is not defined anymore { break; } } /* We fill the rest of the sigma_ray with the max_sigma value to avoid to gather the dose on the axis with a sigma = 0 after the range */ /* And we copy the temporary sigma_ray in the sigma volume for each ray */ for (int s = 0; s < dim[2]; s++) { if (s != 0) { if (sigma_ray[s] < sigma_ray[s-1]) { sigma_ray[s] = sigma_ray[s-1]; } } /* We update the sigma_max value */ if (sigma_ray[s] > sigma_max) { sigma_max = sigma_ray[s]; } sigma_img[dim[0]*dim[1]*s + apert_idx] = sigma_ray[s] * sigma_ray[s]; // We want to have sigma^2 to make a quadratic sum of the sigmas } } } return sigma_max; } void compute_sigma_source ( Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, const Rt_beam *beam, float energy) { /* Method of the Hong's algorithm - See Hong's paper */ float* sigma_img = (float*) sigma_vol->get_vol()->img; float* rgl_img = (float*) rpl_volume->get_vol()->img; unsigned char* ap_img = (unsigned char*) beam->get_aperture()->get_aperture_volume()->img; int idx = 0; double proj = 0; // projection factor of the ray on the z axis double dist_cp = 0; // distance cp - source for the ray float sigma_max = 0; float sigma = 0; /* MD Fix: Why plan->ap->nrm is incorrect at this point??? */ double nrm[3] = {0,0,0}; vec3_sub3 (nrm, beam->get_source_position(), beam->get_isocenter_position()); vec3_normalize1 (nrm); plm_long dim[3] = { sigma_vol->get_vol()->dim[0], sigma_vol->get_vol()->dim[1], sigma_vol->get_vol()->dim[2]}; float range = get_proton_range(energy); for (int i = 0; i < dim[0] * dim[1]; i++) { if (ap_img[i] > 0) { Ray_data* ray_data = &sigma_vol->get_ray_data()[i]; proj = -vec3_dot(ray_data->ray, nrm); dist_cp = vec3_dist(ray_data->cp,beam->get_source_position()); for (int j = 0; j < dim[2]; j++) { if ( rgl_img[idx] < range +10) // +10 because we calculate sigma_src a little bit farther after the range to be sure (+1 cm) { idx = dim[0]*dim[1]*j + i; sigma = beam->get_source_size() * ((dist_cp + proj * (float) j * sigma_vol->get_vol()->spacing[2])/ beam->get_aperture()->get_distance() - 1); sigma_img[idx] += sigma * sigma; // we return the square of sigma_source for the quadratic sum, added to the sigma patient already contained in the sigma volume /* We update sigma_max */ if (sigma_max < sigma) { sigma_max = sigma; } } else { break; } } } } printf ("Sigma source computed - sigma_source_max = %lg mm.\n", sigma_max); } void compute_sigma_range_compensator ( Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, const Rt_beam *beam, float energy, int* margins) { /* There are two methods for computing the beam spread due to a range compensator */ /* Method1 rc_MC_model: Hong's algorithm (Highland)- See Hong's paper */ /* Method2: model built on Monte Carlo simulations - Paper still unpublished */ /* The range compensator is supposed to be made of lucite and placed right after the aperture*/ if (energy < 1) { printf("Sigma range compensator = 0 mm, the energy is too small (<1 MeV).\n"); return; } /* Range value in lucite extracted from a fit based on 1-250MeV from the NIST data - ranges in mm */ double range = 10 * get_proton_range((double) energy); /* Theta0 computation */ double theta0 = 0; if (beam->get_rc_MC_model() != 'y') { theta0 = get_theta0_Highland(range); } else { theta0 = get_theta0_MC(energy); } /* sigma calculation and length computations */ float* sigma_img = (float*) sigma_vol->get_vol()->img; float* rgl_img = (float*) rpl_volume->get_vol()->img; float* rc_img = (float*) beam->get_aperture()->get_range_compensator_volume ()->img; unsigned char* ap_img = 0; if (rpl_volume->get_aperture()->have_aperture_image()) { ap_img = (unsigned char*) beam->get_aperture()->get_aperture_volume()->img; } plm_long dim[3] = { sigma_vol->get_vol()->dim[0], sigma_vol->get_vol()->dim[1], sigma_vol->get_vol()->dim[2] }; int idx = 0; int idx2d_sm = 0; int idx2d_lg = 0; int ijk[3] = {0,0,0}; double proj = 0; // projection factor of the ray on the z axis double dist_cp = 0; // distance cp - source for the ray double rc_over_range; double rc_eff; double theta_srm; double sigma_max = 0; float POI; float l_eff; double sigma; double nrm[3] = {0,0,0}; /* MD Fix: Why plan->ap->nrm is incorrect at this point??? */ vec3_sub3 (nrm, beam->get_source_position(), beam->get_isocenter_position()); vec3_normalize1(nrm); if (margins[0] == 0 && margins[1] == 0) { for (int i = 0; i < dim[0] * dim[1]; i++) { /* calculation of sigma_srm, see graph A3 from the Hong's paper */ if (!rpl_volume->get_aperture()->have_aperture_image() || (ap_img && ap_img[i] > 0)) { Ray_data* ray_data = &sigma_vol->get_ray_data()[i]; proj = -vec3_dot(ray_data->ray, nrm); if (proj == 0) { printf("error: some rays are perpendicular to the beam axis \n"); return; } dist_cp = vec3_dist(ray_data->cp, beam->get_source_position()); rc_over_range = rc_img[i] / proj * PMMA_DENSITY * PMMA_STPR / range; // energy is >1, so range > 0 (range is in water: rho * WER) if (rc_over_range < 1) { if (beam->get_rc_MC_model() != 'y') { theta_srm = theta0 * get_theta_rel_Highland(rc_over_range); rc_eff = get_scat_or_Highland(rc_over_range) * rc_img[i]; } else { theta_srm = theta0 * get_theta_rel_MC(rc_over_range); rc_eff = get_scat_or_MC(rc_over_range) * rc_img[i]; } for (int j = 0; j < dim[2]; j++) { idx = dim[0]*dim[1]*j + i; if ( rgl_img[idx] < range +10) // +10 because we calculate sigma_rg_compensator a little bit farther after the range to be sure (+1 cm) { POI = dist_cp + (float) j * sigma_vol->get_vol()->spacing[2] - beam->get_aperture()->get_distance() / proj; l_eff = rc_eff * proj; /* sigma = sigma_srm * (z_POI + z_eff) */ if (POI + l_eff >= 0) { sigma = theta_srm * (POI + l_eff); } else { sigma = 0; printf("Warning: the image volume intersect the range compensator - in this area the sigma_range compensator will be null.\n"); } sigma_img[idx] += sigma * sigma; // we return the square of sigma_source for the quadratic sum, added to the sigma patient already contained in the sigma volume /* We update sigma_max */ if (sigma_max < sigma) { sigma_max = sigma; } } else { break; } } } } } } else // if margins != 0 we deal with a large volume containing margins { for(int j = margins[1]; j < dim[1] - margins[1]; j++) { ijk[1] = j - margins[1]; for (int i = margins[0]; i < dim[0] - margins[0]; i++) { ijk[0] = i - margins[0]; idx2d_sm = ijk[1] * (dim[0] - 2 * margins[0]) + ijk[0]; idx2d_lg = j * dim[0] + i; /* calculation of sigma_srm, see graph A3 from the Hong's paper */ if (!rpl_volume->get_aperture()->have_aperture_image() || (rpl_volume->get_aperture()->have_aperture_image() && ap_img[idx2d_sm] > 0)) { Ray_data* ray_data = &sigma_vol->get_ray_data()[idx2d_lg]; proj = -vec3_dot(ray_data->ray, nrm); if (proj == 0) { printf("error: some rays are perpendicular to the beam axis \n"); return; } dist_cp = vec3_dist(ray_data->cp, beam->get_source_position()); rc_over_range = rc_img[idx2d_sm] / proj * PMMA_DENSITY * PMMA_STPR / range; // energy is >1, so range > 0 if (rc_over_range < 1) { if (beam->get_rc_MC_model() != 'y') { theta_srm = theta0 * get_theta_rel_Highland(rc_over_range); rc_eff = get_scat_or_Highland(rc_over_range) * rc_img[idx2d_sm]; } else { theta_srm = theta0 * get_theta_rel_MC(rc_over_range); rc_eff = get_scat_or_MC(rc_over_range) * rc_img[idx2d_sm]; } for (int k = 0; k < dim[2]; k++) { idx = dim[0]*dim[1]*k + idx2d_lg; if ( (rgl_img[idx] + rc_img[idx2d_sm]) < range +10) // +10 because we calculate sigma_rg_compensator a little bit farther after the range to be sure (+1 cm) { POI = dist_cp + (float) k * sigma_vol->get_vol()->spacing[2] - beam->get_aperture()->get_distance() / proj; l_eff = rc_eff * proj; /* sigma = sigma_srm * (z_POI- z_eff) */ if (POI + l_eff >= 0) { sigma = theta_srm * (POI - l_eff); } else { sigma = 0; printf("Warning: the image volume intersect the range compensator - in this area the sigma_range compensator will be null.\n"); } sigma_img[idx] += sigma * sigma; // we return the square of sigma_source for the quadratic sum, added to the sigma patient already contained in the sigma volume /* We update sigma_max */ if (sigma_max < sigma) { sigma_max = sigma; } } else { break; } } } } } } } printf("Sigma range compensator computed - sigma_rc_max = %lg mm.\n", sigma_max); return; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_sigma.h000066400000000000000000000017511321604176500275330ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_sigma_h_ #define _rt_sigma_h_ #include "rt_plan.h" #include "rpl_volume.h" void compute_sigmas (const Rt_beam* beam, float energy, float* sigma_max, std::string size, int* margins); void compute_sigma_pt (Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, Rpl_volume* ct_vol, const Rt_beam* beam, float energy); float compute_sigma_pt_homo (Rpl_volume* sigma_vol, Rpl_volume* rpl_vol, float energy); float compute_sigma_pt_hetero (Rpl_volume* sigma_vol, Rpl_volume* rgl_vol, Rpl_volume* ct_vol, float energy); void compute_sigma_source (Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, const Rt_beam* beam, float energy); void compute_sigma_range_compensator (Rpl_volume* sigma_vol, Rpl_volume* rpl_volume, const Rt_beam* beam, float energy, int* margins); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_spot_map.cxx000077500000000000000000000020441321604176500306270ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmdose_config.h" #include #include "rt_spot_map.h" class Rt_spot_map_private { public: std::list spot_list; }; Rt_spot_map::Rt_spot_map () { d_ptr = new Rt_spot_map_private; } Rt_spot_map::~Rt_spot_map () { delete d_ptr; } void Rt_spot_map::add_spot ( float xpos, float ypos, float energy, float sigma, float weight) { d_ptr->spot_list.push_back ( Rt_spot (xpos, ypos, energy, sigma, weight)); } size_t Rt_spot_map::num_spots () const { return d_ptr->spot_list.size (); } const std::list& Rt_spot_map::get_spot_list () const { return d_ptr->spot_list; } void Rt_spot_map::load_spot_map (const std::string& fn) { } void Rt_spot_map::save_spot_map (const std::string& fn) const { } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/rt_spot_map.h000077500000000000000000000022251321604176500302550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_spot_map_h_ #define _rt_spot_map_h_ #include "plmdose_config.h" #include "smart_pointer.h" class Rt_spot_map_private; class PLMDOSE_API Rt_spot { public: Rt_spot ( float xpos, float ypos, float energy, float sigma, float weight) : xpos(xpos), ypos(ypos), energy(energy), sigma(sigma), weight(weight) {} public: float xpos; float ypos; float energy; float sigma; float weight; }; class PLMDOSE_API Rt_spot_map { public: SMART_POINTER_SUPPORT (Rt_spot_map); Rt_spot_map_private *d_ptr; public: Rt_spot_map (); ~Rt_spot_map (); public: void add_spot ( float xpos, float ypos, float energy, float sigma, float weight); size_t num_spots () const; const std::list& get_spot_list () const; void load_spot_map (const std::string& fn); void save_spot_map (const std::string& fn) const; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/wed_parms.cxx000066400000000000000000000325271321604176500302670ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include #include #include #include "plm_math.h" #include "print_and_exit.h" #include "string_util.h" #include "wed_parms.h" #ifndef NULL #define NULL ((void*)0) #endif Wed_Parms::Wed_Parms () { this->debug = 0; this->group = 0; this->mode = 0; this->ray_step = 1.0f; this->src[0] = -1000.f; this->src[1] = 0.f; this->src[2] = 0.f; this->isocenter[0] = 0.f; this->isocenter[1] = 0.f; this->isocenter[2] = 0.f; this->beam_res = 1.f; this->vup[0] = 0.f; this->vup[1] = 0.f; this->vup[2] = 1.f; this->have_ires = false; this->ires[0] = 200; this->ires[1] = 200; this->have_ic = false; this->ic[0] = 99.5f; this->ic[1] = 99.5f; this->ap_spacing[0] = 1.; this->ap_spacing[1] = 1.; this->ap_offset = 100; this->dew_dim[0] = -999.; this->dew_dim[1] = -999.; this->dew_dim[2] = -999.; this->dew_origin[0] = -999.; this->dew_origin[1] = -999.; this->dew_origin[2] = -999.; this->dew_spacing[0] = -999.; this->dew_spacing[1] = -999.; this->dew_spacing[2] = -999.; this->sinogram = 0; this->sinogram_res = 360; } Wed_Parms::~Wed_Parms () { } static void print_usage (void) { printf ("Usage: wed config_file\n"); printf ("Options:\n"); printf ("\t--dew (reverse wed calculation)\n"); printf ("\t--segdepth \n"); printf ("\t--projwed \n"); exit (1); } int Wed_Parms::get_group_lines(char* groupfile) { std::string line; std::ifstream text(groupfile); int numlines = 0; if (text.is_open()) { while (text.good()) { getline(text,line); if ( (!line.empty()) && (line.compare(0,1,"#")) ) { numlines++; } } } return numlines; } #if defined (commentout) void Wed_Parms::parse_group(int argc, char** argv, int linenumber) { int linecounter = 0; for (int i=1; i> pvol_file >> dose_file >> dose_wed_file; if (pvol_file.size()>=4) { if (pvol_file.compare(pvol_file.size()-4,4,".mha")) { print_and_exit ("%s is not in .mha format.\n", pvol_file.c_str()); return; } } else {print_and_exit ("%s is not in .mha format.\n", pvol_file.c_str());} if (dose_file.size()>=4) { if (dose_file.compare(dose_file.size()-4,4,".mha")) { print_and_exit ("%s is not an .mha file.\n", dose_file.c_str()); return; } } else {print_and_exit ("%s is not in .mha format.\n", dose_file.c_str());} this->input_ct_fn = pvol_file; this->input_dose_fn = dose_file.c_str(); //add "_wed" to pvol_file names pvol_file.insert (pvol_file.size()-4,"_wed"); this->output_ct_fn = pvol_file; this->output_dose_fn = dose_wed_file.c_str(); } linecounter++; } } } } } } #endif int Wed_Parms::set_key_val ( const char* key, const char* val, int section ) { switch (section) { /* [INPUT SETTINGS] */ case 0: //Whether wed or reverse, input patient and rpl vol /* patient is legacy term */ if (!strcmp (key, "ct") || !strcmp (key, "patient")) { this->input_ct_fn = val; } else if (!strcmp (key, "proj_wed")) { this->input_proj_wed_fn = val; } //Any mode will use the skin dose if specified else if (!strcmp (key, "skin")) { this->input_skin_fn = val; } //If normal wed procedure, input dose else if (!strcmp (key, "dose")) { this->input_dose_fn = val; } //If reverse wed procedure, input dose_wed else if (!strcmp (key, "wed_dose") || !strcmp (key, "dose_wed")) { this->input_wed_dose_fn = val; } //If in depth/segmentation mode, input segment else if (!strcmp (key, "target")) { this->input_target_fn = val; } break; /* [OUTPUT SETTINGS] */ case 1: if (!strcmp (key, "proj_ct")) { this->output_proj_ct_fn = val; } else if (!strcmp (key, "proj_wed")) { this->output_proj_wed_fn = val; } else if (!strcmp (key, "proj_dose")) { this->output_proj_dose_fn = val; } /* patient_wed is legacy term */ else if (!strcmp (key, "wed_ct") || !strcmp (key, "patient_wed")) { this->output_wed_ct_fn = val; } /* dose_wed is legacy term */ else if (!strcmp (key, "wed_dose") || !strcmp (key, "dose_wed")) { this->output_wed_dose_fn = val; } else if (!strcmp (key, "ct")) { this->output_ct_fn = val; } else if (!strcmp (key, "dew_ct")) { this->output_dew_ct_fn = val; } /* dose is legacy term */ else if (!strcmp (key, "dew_dose") || !strcmp (key, "dose")) { this->output_dew_dose_fn = val; } #if defined (commentout) else if (!strcmp (key, "aperture")) { this->output_ap_fn = val; } #endif break; /* [BEAM] */ case 2: if (!strcmp (key, "ray_step")) { if (sscanf (val, "%f", &this->ray_step) != 1) { goto error_exit; } } else if (!strcmp (key, "pos")) { if (sscanf (val, "%f %f %f", &(this->src[0]), &(this->src[1]), &(this->src[2])) != 3) { goto error_exit; } } else if (!strcmp (key, "isocenter")) { if (sscanf (val, "%f %f %f", &(this->isocenter[0]), &(this->isocenter[1]), &(this->isocenter[2])) != 3) { goto error_exit; } } else if (!strcmp (key, "res")) { if (sscanf (val, "%f", &(this->beam_res)) != 1) { goto error_exit; } } break; /* [APERTURE] */ case 3: if (!strcmp (key, "up")) { if (sscanf (val, "%f %f %f", &(this->vup[0]), &(this->vup[1]), &(this->vup[2])) != 3) { goto error_exit; } } else if (!strcmp (key, "center")) { if (sscanf (val, "%f %f", &(this->ic[0]), &(this->ic[1])) != 2) { goto error_exit; } this->have_ic = true; } else if (!strcmp (key, "offset")) { if (sscanf (val, "%f", &(this->ap_offset)) != 1) { goto error_exit; } } else if (!strcmp (key, "spacing")) { if (sscanf (val, "%f %f", &(this->ap_spacing[0]), &(this->ap_spacing[1])) != 2) { goto error_exit; } } else if (!strcmp (key, "resolution")) { if (sscanf (val, "%i %i", &(this->ires[0]), &(this->ires[1])) != 2) { goto error_exit; } this->have_ires = true; } break; /* [DEW VOLUME] */ case 4: if (!strcmp (key, "dew_dim")) { if (sscanf (val, "%f %f %f", &(this->dew_dim[0]), &(this->dew_dim[1]), &(this->dew_dim[2])) != 3) { goto error_exit; } } else if (!strcmp (key, "dew_origin")) { if (sscanf (val, "%f %f %f", &(this->dew_origin[0]), &(this->dew_origin[1]), &(this->dew_origin[2])) != 3) { goto error_exit; } } if (!strcmp (key, "dew_spacing")) { if (sscanf (val, "%f %f %f", &(this->dew_spacing[0]), &(this->dew_spacing[1]), &(this->dew_spacing[2])) != 3) { goto error_exit; } } break; /* [PROJECTION VOLUME] */ case 5: if (!strcmp (key, "sinogram")) { if (sscanf (val, "%f", &(this->sinogram)) != 1) { goto error_exit; } } else if (!strcmp (key, "resolution")) { if (sscanf (val, "%i", &(this->sinogram_res)) != 1) { goto error_exit; } } break; } return 0; error_exit: print_and_exit ("Unknown (key,val) combination: (%s,%s)\n", key, val); return -1; } void Wed_Parms::parse_config ( const char* config_fn ) { /* Read file into string */ std::ifstream t (config_fn); std::stringstream buffer; buffer << t.rdbuf(); std::string buf; std::string buf_ori; /* An extra copy for diagnostics */ int section = -1; std::stringstream ss (buffer.str()); while (getline (ss, buf)) { buf_ori = buf; buf = string_trim (buf); buf_ori = string_trim (buf_ori, "\r\n"); if (buf == "") continue; if (buf[0] == '#') continue; if (buf[0] == '[') { if (buf.find ("[INPUT SETTINGS]") != std::string::npos || buf.find ("[input settings]") != std::string::npos) { section = 0; continue; } if (buf.find ("[OUTPUT SETTINGS]") != std::string::npos || buf.find ("[output settings]") != std::string::npos) { section = 1; continue; } else if (buf.find ("[BEAM]") != std::string::npos || buf.find ("[beam]") != std::string::npos) { section = 2; continue; } else if (buf.find ("[APERTURE]") != std::string::npos || buf.find ("[aperture]") != std::string::npos) { section = 3; continue; } else if (buf.find ("[DEW VOLUME]") != std::string::npos || buf.find ("[dew volume]") != std::string::npos) { section = 4; continue; } else if (buf.find ("[PROJECTION VOLUME]") != std::string::npos || buf.find ("[projective volume]") != std::string::npos) { section = 5; continue; } else { printf ("Parse error: %s\n", buf_ori.c_str()); } } size_t key_loc = buf.find ("="); if (key_loc == std::string::npos) { continue; } std::string key = buf.substr (0, key_loc); std::string val = buf.substr (key_loc+1); key = string_trim (key); val = string_trim (val); if (key != "" && val != "") { if (this->set_key_val (key.c_str(), val.c_str(), section) < 0) { printf ("Parse error: %s\n", buf_ori.c_str()); } } } } bool Wed_Parms::parse_args (int argc, char** argv) { int i; for (i=1; idebug = 1; } if (!strcmp (argv[i], "--group")) { if (!argv[i+1]) { //group needs an argument print_usage (); return false; } else { this->group = get_group_lines(argv[i+1]); return true; } } if (!strcmp (argv[i], "--dew")) { this->mode = 1; } else if (!strcmp (argv[i], "--segdepth")) { this->mode = 2; } else if (!strcmp (argv[i], "--projwed")) { this->mode = 3; } else { print_usage (); break; } } if (!argv[i]) { print_usage (); } else { this->parse_config (argv[i]); } //Input CT always required if (this->input_ct_fn == "") { print_and_exit ("** ERROR: Input patient image not specified in configuration file!\n"); } return true; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/dose/wed_parms.h000077500000000000000000000044701321604176500277130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _wed_parms_h_ #define _wed_parms_h_ #include "plmdose_config.h" #include #include "plm_int.h" class PLMDOSE_API Wed_Parms { public: Wed_Parms (); ~Wed_Parms (); bool parse_args (int argc, char** argv); private: void parse_config (const char* config_fn); int set_key_val (const char* key, const char* val, int section); int get_group_lines (char* groupfile); public: /* [SETTINGS] */ int debug; int group; short mode; /*Running in wed, dew, or segdepth?*/ std::string input_ct_fn; /* input: patient volume */ std::string input_dose_fn; /* input: dose volume */ std::string input_proj_ct_fn; /* input: ct in proj coordinates */ std::string input_proj_wed_fn; /* input: wed in proj coordinates */ std::string input_wed_dose_fn; /* input: dose in wed coordinates */ std::string input_target_fn; /* input: segment volume */ std::string input_skin_fn; /* input: skin volume */ std::string output_proj_ct_fn; /* output: ct in proj coordinates */ std::string output_proj_wed_fn; /* output: wed in proj coordinates */ std::string output_proj_dose_fn; /* output: dose in proj coordinates */ std::string output_wed_ct_fn; /* output: ct in wed coordinates */ std::string output_wed_dose_fn; /* output: dose in wed coordinates */ std::string output_ct_fn; /* output: ct in world coordinates */ std::string output_dew_ct_fn; /* output: ct in world coordinates */ std::string output_dew_dose_fn; /* output: dose in world coordinates */ /* [BEAM] */ bool have_ray_step; float ray_step; /* Uniform ray step size (mm) */ float src[3]; float isocenter[3]; float beam_res; /* [APERTURE] */ float vup[3]; plm_long ires[2]; bool have_ic; bool have_ires; float ic[2]; float ap_spacing[2]; float ap_offset; /* [DEW VOLUME] */ float dew_dim[3]; float dew_origin[3]; float dew_spacing[3]; /* [PROJ VOLUME] */ float sinogram; int sinogram_res; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/matlab/000077500000000000000000000000001321604176500260575ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/matlab/mex_drr.c000077500000000000000000000055121321604176500276710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "mex.h" #include "plm_config.h" #include #include #include #include "fdk_opts.h" #include "fdk_util.h" #include "file_util.h" #include #include "plm_math.h" #include "proj_image.h" #include "proj_matrix.h" #include "ramp_filter.h" #include "volume.h" #include "drr.h" #include "drr_opts.h" void mexFunction ( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { /* declare input variables */ /* mxArray *proj_in = prhs[0]; double *proj = mxGetPr(proj_in); mxArray *cam_in = prhs[1]; double *cam = mxGetPr(cam_in); mxArray *tgt_in = prhs[2]; double *tgt = mxGetPr(tgt_in); mxArray *vup_in = prhs[3]; double *vup = mxGetPr(vup_in); mxArray *sid_in = prhs[4]; double *sid = mxGetPr(sid_in); mxArray *ic_in = prhs[5]; double *ic = mxGetPr(ic_in); mxArray *ps_in = prhs[6]; double *ps = mxGetPr(ps_in); mxArray *ires_in = prhs[7]; double *ires = mxGetPr(ires_in); */ /* DRR API example */ Volume *vol; Proj_image *proj; /* hardcoded values */ double cam[3] = { 1500,1500,1500 }; double tgt[3] = { 20,20,20 }; //iso from RT plan double vup[3] = { 0,0,1 }; double sid[3] = { 100,100,100 }; double ic[3] = { 0,0,0 }; double ps[3] = { 1,1,1 }; int ires[2] = { 512,512 }; char options[3] = "cpu"; /* Create the CT volume */ int dim[3] = { 512, 512, 152 }; float offset[3] = { -255.5, -255.5, -123.75 }; float spacing[3] = { 1.0, 1.0, 2.5 }; enum Volume_pixel_type pix_type = PT_FLOAT; float direction_cosines[9] = { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 }; vol = new Volume (dim, offset, spacing, direction_cosines, pix_type, 1, 0); /* Fill in the CT volume with values */ float *img = (float*) vol->img; img[100] = 32.6; /* Create empty projection image */ proj = proj_image_create (); /* Add storage for image bytes */ proj_image_create_img (proj, ires); /* Add empty projection matrix */ proj_image_create_pmat (proj); /* Set up the projection matrix */ proj_matrix_set (proj->pmat, cam, tgt, vup, *sid, ic, ps, ires); /* Render the drr */ drr_render_volume_perspective (proj, vol, ps, 0, options); /* Do something with the image */ /* declare output variables */ /* double *drr = mxGetPr(drr_out); */ printf("pixel (32,10) is: %g\n", proj->img[32*ires[0]+10]); /* output */ /* plhs[0] = drr_out; */ /* Clean up memory */ delete vol; proj_image_destroy (proj); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/opencl/000077500000000000000000000000001321604176500260775ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/opencl/CMakeLists.txt000066400000000000000000000015241321604176500306410ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_opencl) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) set (PLMOPENCL_LIBRARY_SRC opencl_util.cxx ) ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- if (OPENCL_FOUND) set (PLMOPENCL_LIBRARY_DEPENDENCIES plmsys ${OPENCL_LIBRARIES} ) plm_add_library ( plmopencl "${PLMOPENCL_LIBRARY_SRC}" "${PLMOPENCL_LIBRARY_DEPENDENCIES}" "${PLMOPENCL_LIBRARY_LDFLAGS}" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "") endif () autotune_opencl.cxx000066400000000000000000000034641321604176500317570ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/opencl/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include "autotune_opencl.h" void divideWork ( cl_device_id *devices, cl_uint device_count, int dimensions, size_t work_per_device[MAX_GPU_COUNT][3], size_t *work_total ) { float compute_ratio; size_t allotted_work, total_allotted_work; cl_device_id device; cl_uint compute_units, clock_frequency, total_compute_ability, compute_ability[MAX_GPU_COUNT], max_compute_ability, max_device; int dim = dimensions - 1; total_compute_ability = 0; max_compute_ability = 0; max_device = 0; for (cl_uint i = 0; i < device_count; i++) { device = devices[i]; clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, NULL); compute_ability[i] = compute_units * clock_frequency; total_compute_ability += compute_ability[i]; if (compute_ability[i] > max_compute_ability) { max_compute_ability = compute_ability[i]; max_device = i; } } total_allotted_work = 0; for (cl_uint i = 0; i < device_count; i++) { for (int j = 0; j < dim; j++) { work_per_device[i][j] = work_total[j]; } compute_ratio = (float)compute_ability[i] / (float)total_compute_ability; compute_ratio = floor(compute_ratio * 100) / 100; allotted_work = (size_t)(floor((float)work_total[dim] * compute_ratio)); work_per_device[i][dim] = allotted_work; total_allotted_work += allotted_work; } work_per_device[max_device][dim] += work_total[dim] - total_allotted_work; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/opencl/autotune_opencl.h000066400000000000000000000011701321604176500314530ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _AUTOTUNE_OPENCL_H_ #define _AUTOTUNE_OPENCL_H_ #include "plm_config.h" #include "opencl_util.h" #define MAX_GPU_COUNT 8 #if defined __cplusplus extern "C" { #endif plmopencl_EXPORT (void divideWork, cl_device_id *devices, cl_uint device_count, int dimensions, size_t work_per_device[MAX_GPU_COUNT][3], size_t *work_total ); #if defined __cplusplus } #endif #endif delayload_opencl.h000066400000000000000000000604351321604176500314770ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/opencl/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ // JAS 2010.12.10 // This stuff is pretty much copy and pasted from and then // morphed into something useful to dlsym() by replacing externs with // typedefs and then renaming stuff with leading underscores to make // everything play nice without name conflicts. If new OpenCL // functions are rolled out later and you want to dynamically load them, // then you are going to have to update this file, buddy. // // For this, // :'<,'>s/^cl/__cl/g is your (vim) friend #ifndef _delayload_opencl_h_ #define _delayload_opencl_h_ #if defined (__APPLE__) #include #else #include #endif // Needed for delay loading windows DLLs #if _WIN32 #pragma comment(lib, "delayimp") #pragma comment(lib, "user32") #endif #if defined __cplusplus extern "C" { #endif /* Platform API */ typedef CL_API_ENTRY cl_int CL_API_CALL __clGetPlatformIDs(cl_uint /* num_entries */, cl_platform_id * /* platforms */, cl_uint * /* num_platforms */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetPlatformInfo(cl_platform_id /* platform */, cl_platform_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; /* Device APIs */ typedef CL_API_ENTRY cl_int CL_API_CALL __clGetDeviceIDs(cl_platform_id /* platform */, cl_device_type /* device_type */, cl_uint /* num_entries */, cl_device_id * /* devices */, cl_uint * /* num_devices */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetDeviceInfo(cl_device_id /* device */, cl_device_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; /* Context APIs */ typedef CL_API_ENTRY cl_context CL_API_CALL __clCreateContext(const cl_context_properties * /* properties */, cl_uint /* num_devices */, const cl_device_id * /* devices */, void (*pfn_notify)(const char *, const void *, size_t, void *) /* pfn_notify */, void * /* user_data */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_context CL_API_CALL __clCreateContextFromType(const cl_context_properties * /* properties */, cl_device_type /* device_type */, void (*pfn_notify)(const char *, const void *, size_t, void *) /* pfn_notify */, void * /* user_data */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clRetainContext(cl_context /* context */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clReleaseContext(cl_context /* context */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetContextInfo(cl_context /* context */, cl_context_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; /* Command Queue APIs */ typedef CL_API_ENTRY cl_command_queue CL_API_CALL __clCreateCommandQueue(cl_context /* context */, cl_device_id /* device */, cl_command_queue_properties /* properties */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clRetainCommandQueue(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clReleaseCommandQueue(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetCommandQueueInfo(cl_command_queue /* command_queue */, cl_command_queue_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clSetCommandQueueProperty(cl_command_queue /* command_queue */, cl_command_queue_properties /* properties */, cl_bool /* enable */, cl_command_queue_properties * /* old_properties */) CL_API_SUFFIX__VERSION_1_0; /* Memory Object APIs */ typedef CL_API_ENTRY cl_mem CL_API_CALL __clCreateBuffer(cl_context /* context */, cl_mem_flags /* flags */, size_t /* size */, void * /* host_ptr */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_mem CL_API_CALL __clCreateImage2D(cl_context /* context */, cl_mem_flags /* flags */, const cl_image_format * /* image_format */, size_t /* image_width */, size_t /* image_height */, size_t /* image_row_pitch */, void * /* host_ptr */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_mem CL_API_CALL __clCreateImage3D(cl_context /* context */, cl_mem_flags /* flags */, const cl_image_format * /* image_format */, size_t /* image_width */, size_t /* image_height */, size_t /* image_depth */, size_t /* image_row_pitch */, size_t /* image_slice_pitch */, void * /* host_ptr */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clRetainMemObject(cl_mem /* memobj */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clReleaseMemObject(cl_mem /* memobj */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetSupportedImageFormats(cl_context /* context */, cl_mem_flags /* flags */, cl_mem_object_type /* image_type */, cl_uint /* num_entries */, cl_image_format * /* image_formats */, cl_uint * /* num_image_formats */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetMemObjectInfo(cl_mem /* memobj */, cl_mem_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetImageInfo(cl_mem /* image */, cl_image_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; /* Sampler APIs */ typedef CL_API_ENTRY cl_sampler CL_API_CALL __clCreateSampler(cl_context /* context */, cl_bool /* normalized_coords */, cl_addressing_mode /* addressing_mode */, cl_filter_mode /* filter_mode */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clRetainSampler(cl_sampler /* sampler */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clReleaseSampler(cl_sampler /* sampler */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetSamplerInfo(cl_sampler /* sampler */, cl_sampler_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; /* Program Object APIs */ typedef CL_API_ENTRY cl_program CL_API_CALL __clCreateProgramWithSource(cl_context /* context */, cl_uint /* count */, const char ** /* strings */, const size_t * /* lengths */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_program CL_API_CALL __clCreateProgramWithBinary(cl_context /* context */, cl_uint /* num_devices */, const cl_device_id * /* device_list */, const size_t * /* lengths */, const unsigned char ** /* binaries */, cl_int * /* binary_status */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clRetainProgram(cl_program /* program */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clReleaseProgram(cl_program /* program */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clBuildProgram(cl_program /* program */, cl_uint /* num_devices */, const cl_device_id * /* device_list */, const char * /* options */, void (*pfn_notify)(cl_program /* program */, void * /* user_data */), void * /* user_data */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clUnloadCompiler(void) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetProgramInfo(cl_program /* program */, cl_program_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetProgramBuildInfo(cl_program /* program */, cl_device_id /* device */, cl_program_build_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; /* Kernel Object APIs */ typedef CL_API_ENTRY cl_kernel CL_API_CALL __clCreateKernel(cl_program /* program */, const char * /* kernel_name */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clCreateKernelsInProgram(cl_program /* program */, cl_uint /* num_kernels */, cl_kernel * /* kernels */, cl_uint * /* num_kernels_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clRetainKernel(cl_kernel /* kernel */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clReleaseKernel(cl_kernel /* kernel */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clSetKernelArg(cl_kernel /* kernel */, cl_uint /* arg_index */, size_t /* arg_size */, const void * /* arg_value */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetKernelInfo(cl_kernel /* kernel */, cl_kernel_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetKernelWorkGroupInfo(cl_kernel /* kernel */, cl_device_id /* device */, cl_kernel_work_group_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; /* Event Object APIs */ typedef CL_API_ENTRY cl_int CL_API_CALL __clWaitForEvents(cl_uint /* num_events */, const cl_event * /* event_list */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clGetEventInfo(cl_event /* event */, cl_event_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clRetainEvent(cl_event /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clReleaseEvent(cl_event /* event */) CL_API_SUFFIX__VERSION_1_0; /* Profiling APIs */ typedef CL_API_ENTRY cl_int CL_API_CALL __clGetEventProfilingInfo(cl_event /* event */, cl_profiling_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; /* Flush and Finish APIs */ typedef CL_API_ENTRY cl_int CL_API_CALL __clFlush(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clFinish(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; /* Enqueued Commands APIs */ typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueReadBuffer(cl_command_queue /* command_queue */, cl_mem /* buffer */, cl_bool /* blocking_read */, size_t /* offset */, size_t /* cb */, void * /* ptr */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueWriteBuffer(cl_command_queue /* command_queue */, cl_mem /* buffer */, cl_bool /* blocking_write */, size_t /* offset */, size_t /* cb */, const void * /* ptr */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueCopyBuffer(cl_command_queue /* command_queue */, cl_mem /* src_buffer */, cl_mem /* dst_buffer */, size_t /* src_offset */, size_t /* dst_offset */, size_t /* cb */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueReadImage(cl_command_queue /* command_queue */, cl_mem /* image */, cl_bool /* blocking_read */, const size_t * /* origin[3] */, const size_t * /* region[3] */, size_t /* row_pitch */, size_t /* slice_pitch */, void * /* ptr */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueWriteImage(cl_command_queue /* command_queue */, cl_mem /* image */, cl_bool /* blocking_write */, const size_t * /* origin[3] */, const size_t * /* region[3] */, size_t /* input_row_pitch */, size_t /* input_slice_pitch */, const void * /* ptr */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueCopyImage(cl_command_queue /* command_queue */, cl_mem /* src_image */, cl_mem /* dst_image */, const size_t * /* src_origin[3] */, const size_t * /* dst_origin[3] */, const size_t * /* region[3] */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueCopyImageToBuffer(cl_command_queue /* command_queue */, cl_mem /* src_image */, cl_mem /* dst_buffer */, const size_t * /* src_origin[3] */, const size_t * /* region[3] */, size_t /* dst_offset */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueCopyBufferToImage(cl_command_queue /* command_queue */, cl_mem /* src_buffer */, cl_mem /* dst_image */, size_t /* src_offset */, const size_t * /* dst_origin[3] */, const size_t * /* region[3] */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY void * CL_API_CALL __clEnqueueMapBuffer(cl_command_queue /* command_queue */, cl_mem /* buffer */, cl_bool /* blocking_map */, cl_map_flags /* map_flags */, size_t /* offset */, size_t /* cb */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY void * CL_API_CALL __clEnqueueMapImage(cl_command_queue /* command_queue */, cl_mem /* image */, cl_bool /* blocking_map */, cl_map_flags /* map_flags */, const size_t * /* origin[3] */, const size_t * /* region[3] */, size_t * /* image_row_pitch */, size_t * /* image_slice_pitch */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueUnmapMemObject(cl_command_queue /* command_queue */, cl_mem /* memobj */, void * /* mapped_ptr */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueNDRangeKernel(cl_command_queue /* command_queue */, cl_kernel /* kernel */, cl_uint /* work_dim */, const size_t * /* global_work_offset */, const size_t * /* global_work_size */, const size_t * /* local_work_size */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueTask(cl_command_queue /* command_queue */, cl_kernel /* kernel */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueNativeKernel(cl_command_queue /* command_queue */, void (*user_func)(void *), void * /* args */, size_t /* cb_args */, cl_uint /* num_mem_objects */, const cl_mem * /* mem_list */, const void ** /* args_mem_loc */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueMarker(cl_command_queue /* command_queue */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueWaitForEvents(cl_command_queue /* command_queue */, cl_uint /* num_events */, const cl_event * /* event_list */) CL_API_SUFFIX__VERSION_1_0; typedef CL_API_ENTRY cl_int CL_API_CALL __clEnqueueBarrier(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; #if defined __cplusplus } #endif // JAS 2010.12.10 // OpenCL is special since the OpenCL dev stuff // doesn't include return typedefs... so we make them // oursevles (see delayload_opencl.h) and we have a // special casting dlsym() macro for it. #if !defined(_WIN32) && defined(PLM_USE_GPU_PLUGINS) #define LOAD_SYMBOL_OPENCL(sym, lib, type) \ sym = (__##sym *)dlsym (lib, #sym); #else #define LOAD_SYMBOL_OPENCL(sym, lib, type) \ ; #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/opencl/opencl_util.cxx000066400000000000000000000436001321604176500311430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include #include "delayload.h" #include "delayload_opencl.h" #include "opencl_util.h" #include "print_and_exit.h" #include "string_util.h" void opencl_device_info ( cl_device_id device, cl_device_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret ) { cl_int status; status = clGetDeviceInfo ( device, param_name, param_value_size, param_value, param_value_size_ret ); opencl_check_error (status, "clGetDeviceInfo"); } void opencl_dump_device_info (cl_device_id device) { char param_string[1024]; cl_bool param_bool; opencl_device_info ( device, CL_DEVICE_VENDOR, sizeof(param_string), param_string, NULL ); printf (" CL_DEVICE_VENDOR = %s\n", param_string); opencl_device_info ( device, CL_DEVICE_NAME, sizeof(param_string), param_string, NULL ); printf (" CL_DEVICE_NAME = %s\n", param_string); opencl_device_info ( device, CL_DEVICE_AVAILABLE, sizeof (cl_bool), ¶m_bool, NULL ); printf (" CL_DEVICE_AVAILABLE = %d\n", param_bool); opencl_device_info ( device, CL_DEVICE_VERSION, sizeof(param_string), param_string, NULL ); printf (" CL_DEVICE_VERSION = %s\n", param_string); opencl_device_info ( device, CL_DRIVER_VERSION, sizeof(param_string), param_string, NULL ); printf (" CL_DRIVER_VERSION = %s\n", param_string); opencl_device_info ( device, CL_DEVICE_IMAGE_SUPPORT, sizeof (cl_bool), ¶m_bool, NULL ); printf (" CL_DEVICE_IMAGE_SUPPORT = %d\n", param_bool); } cl_int opencl_dump_platform_info (cl_platform_id platform) { cl_int status; char buf[100]; status = clGetPlatformInfo ( platform, CL_PLATFORM_NAME, sizeof (buf), buf, NULL ); if (status != CL_SUCCESS) { return status; } printf (" Name = %s\n", buf); status = clGetPlatformInfo ( platform, CL_PLATFORM_VENDOR, sizeof (buf), buf, NULL ); if (status != CL_SUCCESS) { return status; } printf (" Vendor = %s\n", buf); return CL_SUCCESS; } cl_platform_id opencl_select_platform (void) { cl_int status = 0; cl_uint num_platforms; cl_platform_id platform = NULL; status = clGetPlatformIDs (0, NULL, &num_platforms); if (status != CL_SUCCESS) { print_and_exit ("Error in clGetPlatformIDs\n"); } if (num_platforms > 0) { unsigned int i; cl_platform_id* platform_list = (cl_platform_id*) malloc ( sizeof (cl_platform_id) * num_platforms ); printf ("Found %d platforms\n", num_platforms); status = clGetPlatformIDs (num_platforms, platform_list, NULL); if (status != CL_SUCCESS) { print_and_exit ("Error in clGetPlatformIDs\n"); } for (i = 0; i < num_platforms; i++) { printf ("OpenCL platform [%d]\n", i); status = opencl_dump_platform_info (platform_list[i]); if (status != CL_SUCCESS) { continue; } /* Choose first platform (?) */ if (!platform) { platform = platform_list[i]; } } free (platform_list); } return platform; } void opencl_dump_devices (Opencl_device *ocl_dev) { printf ("Num_devices = %d\n", ocl_dev->device_count); for (cl_uint i = 0; i < ocl_dev->device_count; i++) { printf ("OpenCL device [%d]\n", i); opencl_dump_device_info (ocl_dev->devices[i]); } } /* Create one command queue for each device */ cl_int opencl_create_command_queues (Opencl_device *ocl_dev) { cl_int status; ocl_dev->command_queues = (cl_command_queue *) malloc ( ocl_dev->device_count * sizeof(cl_command_queue) ); for (cl_uint i = 0; i < ocl_dev->device_count; i++) { cl_uint cxt_no; /* Find the right context depending if method a or b was used */ if (ocl_dev->context_count == 1) { cxt_no = 0; } else { cxt_no = i; } ocl_dev->command_queues[i] = clCreateCommandQueue ( ocl_dev->contexts[cxt_no], ocl_dev->devices[i], CL_QUEUE_PROFILING_ENABLE, &status ); if (status != CL_SUCCESS) { return status; } } return CL_SUCCESS; } /* Flavor a creates one context with multiple devices in it */ cl_int opencl_create_context_a (Opencl_device *ocl_dev) { cl_int status = 0; cl_context_properties cps[3]; cl_context_properties* cprops; size_t device_list_size; if (ocl_dev->platform) { cps[0] = CL_CONTEXT_PLATFORM; cps[1] = (cl_context_properties) ocl_dev->platform; cps[2] = 0; cprops = cps; } else { cprops = NULL; } /* Create context from platform */ ocl_dev->context_count = 1; ocl_dev->contexts = (cl_context*) malloc (sizeof(cl_context)); ocl_dev->contexts[0] = clCreateContextFromType ( cprops, CL_DEVICE_TYPE_GPU, NULL, NULL, &status ); if (status != CL_SUCCESS) { print_and_exit ("Error in clCreateContextFromType\n"); } /* Get size of device list */ status = clGetContextInfo ( ocl_dev->contexts[0], CL_CONTEXT_DEVICES, 0, NULL, &device_list_size ); if (status != CL_SUCCESS) { print_and_exit ("Error in clGetContextInfo\n"); } if (device_list_size == 0) { print_and_exit ("No devices found (clGetContextInfo)\n"); } /* Get the device list data */ ocl_dev->device_count = device_list_size / sizeof(cl_device_id); ocl_dev->devices = (cl_device_id *) malloc (device_list_size); status = clGetContextInfo ( ocl_dev->contexts[0], CL_CONTEXT_DEVICES, device_list_size, ocl_dev->devices, NULL ); if (status != CL_SUCCESS) { print_and_exit ("Error in clGetContextInfo\n"); } /* Print out a little status about the devices */ opencl_dump_devices (ocl_dev); return CL_SUCCESS; } /* Flavor b creates multiple contexts, each with one device */ cl_int opencl_create_context_b (Opencl_device *ocl_dev) { cl_int status; cl_context_properties cps[3]; cl_context_properties* cprops; if (ocl_dev->platform) { cps[0] = CL_CONTEXT_PLATFORM; cps[1] = (cl_context_properties) ocl_dev->platform; cps[2] = 0; cprops = cps; } else { cprops = NULL; } /* Get number of devices of type GPU on this platform */ status = clGetDeviceIDs ( ocl_dev->platform, CL_DEVICE_TYPE_GPU, 0, NULL, &ocl_dev->device_count ); if (status != CL_SUCCESS) { return status; } /* Get list of device ids */ ocl_dev->devices = (cl_device_id *) malloc ( ocl_dev->device_count * sizeof(cl_device_id) ); status = clGetDeviceIDs ( ocl_dev->platform, CL_DEVICE_TYPE_GPU, ocl_dev->device_count, ocl_dev->devices, NULL ); if (status != CL_SUCCESS) { return status; } /* Print out a little status about the devices */ opencl_dump_devices (ocl_dev); /* Create context and command queue for each device */ ocl_dev->context_count = ocl_dev->device_count; ocl_dev->contexts = (cl_context *) malloc ( ocl_dev->context_count * sizeof(cl_context)); for (cl_uint i = 0; i < ocl_dev->device_count; i++) { ocl_dev->contexts[i] = clCreateContext ( cprops, 1, &ocl_dev->devices[i], NULL, NULL, &status ); opencl_check_error (status, "clCreateContext"); } return CL_SUCCESS; } cl_int opencl_open_device (Opencl_device *ocl_dev) { cl_int status = 0; memset (ocl_dev, 0, sizeof(Opencl_device)); /* Select platform */ ocl_dev->platform = opencl_select_platform (); /* ATI examples suggest you can try to create a context and command queue even if platform is NULL. So we don't fail (yet) if platform is NULL here. */ /* Create contexts (there are two versions of this function: a, b) */ //status = opencl_create_context_a (ocl_dev); status = opencl_create_context_b (ocl_dev); if (status != CL_SUCCESS) { return status; } /* Create command queues */ status = opencl_create_command_queues (ocl_dev); return status; } void opencl_close_device (Opencl_device *ocl_dev) { cl_int status = 0; for (cl_uint i = 0; i < ocl_dev->context_count; i++) { status = clReleaseCommandQueue (ocl_dev->command_queues[i]); if (status != CL_SUCCESS) { print_and_exit ("Error in clReleaseCommandQueue\n"); } status = clReleaseContext (ocl_dev->contexts[i]); if (status != CL_SUCCESS) { print_and_exit ("Error in clReleaseContext\n"); } } free (ocl_dev->devices); free (ocl_dev->contexts); free (ocl_dev->command_queues); } Opencl_buf* opencl_buf_create ( Opencl_device *ocl_dev, cl_mem_flags flags, size_t buffer_size, void *buffer ) { /* Create one buffer per context? one buffer per device? For now we create one per context. Each device buffer is a copy of the input buffer. */ Opencl_buf* ocl_buf = (Opencl_buf*) malloc ( ocl_dev->context_count * sizeof(Opencl_buf)); for (cl_uint i = 0; i < ocl_dev->context_count; i++) { cl_int status; ocl_buf[i] = clCreateBuffer ( ocl_dev->contexts[i], flags, buffer_size, buffer, &status ); opencl_check_error (status, "clCreateBuffer"); } return ocl_buf; } void opencl_buf_read ( Opencl_device *ocl_dev, Opencl_buf* ocl_buf, size_t buffer_size, void *buffer ) { /* For buffer read/write, only the top-level logic knows how to assign data to different devices. */ /* The below logic assumes only one device (for now). */ cl_int status; status = clEnqueueReadBuffer ( ocl_dev->command_queues[0], ocl_buf[0], CL_TRUE, 0, buffer_size, buffer, 0, NULL, NULL ); opencl_check_error (status, "clEnqueueReadBuffer"); } void opencl_buf_write ( Opencl_device *ocl_dev, Opencl_buf* ocl_buf, size_t buffer_size, void *buffer ) { /* For buffer read/write, only the top-level logic knows how to assign data to different devices. */ /* The below logic assumes only one device (for now). */ cl_int status; status = clEnqueueWriteBuffer ( ocl_dev->command_queues[0], ocl_buf[0], CL_TRUE, 0, buffer_size, buffer, 0, NULL, NULL ); opencl_check_error (status, "clEnqueueWriteBuffer"); } void opencl_kernel_create ( Opencl_device *ocl_dev, const char *kernel_name ) { ocl_dev->kernels = (cl_kernel*) malloc ( ocl_dev->device_count * sizeof(cl_kernel)); for (cl_uint i = 0; i < ocl_dev->device_count; i++) { cl_int status; ocl_dev->kernels[i] = clCreateKernel ( ocl_dev->programs[i], kernel_name, &status ); opencl_check_error (status, "clCreateKernel"); } } void opencl_load_programs ( Opencl_device *ocl_dev, const char* filename ) { cl_int status; std::string buf; const char *buf_cstr; size_t len; /* Load the file contents into a string */ buf = slurp_file (filename); /* Load and compile the programs */ buf_cstr = buf.c_str(); len = (size_t) buf.length (); ocl_dev->programs = (cl_program*) malloc ( ocl_dev->device_count * sizeof(cl_program)); for (cl_uint i = 0; i < ocl_dev->device_count; i++) { ocl_dev->programs[i] = clCreateProgramWithSource ( ocl_dev->contexts[i], 1, &buf_cstr, &len, &status ); opencl_check_error (status, "Error calling clCreateProgramWithSource."); /* Here we need to find the devices associated with this context, which depends on if method a or b was used. */ if (ocl_dev->context_count == 1) { status = clBuildProgram ( ocl_dev->programs[i], ocl_dev->device_count, ocl_dev->devices, NULL, NULL, NULL ); } else { status = clBuildProgram ( ocl_dev->programs[i], 1, &ocl_dev->devices[i], NULL, NULL, NULL ); } if (status != CL_SUCCESS) { opencl_dump_build_log (ocl_dev, ocl_dev->programs[i]); opencl_check_error (status, "Error calling clBuildProgram."); } } } void opencl_set_kernel_args ( Opencl_device *ocl_dev, ... ) { va_list va; cl_int status; cl_uint arg_index; size_t arg_size; void* arg; /* Set the arguments */ va_start (va, ocl_dev); arg_index = 0; while ((arg_size = va_arg (va, size_t)) != 0) { arg = va_arg (va, void*); /* Here I would add the loop for each device... */ /* But instead just send to kernel 0 */ //printf ("OKE: %d %d %p\n", arg_index, arg_size, arg); status = clSetKernelArg ( ocl_dev->kernels[0], arg_index++, arg_size, arg ); opencl_check_error (status, "clSetKernelArg"); } va_end (va); } void opencl_kernel_enqueue ( Opencl_device *ocl_dev, size_t global_work_size, size_t local_work_size ) { cl_event events[2]; cl_int status; /* Add kernel to the queue */ status = clEnqueueNDRangeKernel ( ocl_dev->command_queues[0], ocl_dev->kernels[0], 1, NULL, &global_work_size, &local_work_size, 0, NULL, &events[0] ); opencl_check_error (status, "clEnqueueNDRangeKernel"); status = clWaitForEvents(1, &events[0]); opencl_check_error (status, "clWaitForEvents"); clReleaseEvent(events[0]); } cl_ulong opencl_timer (cl_event &event) { cl_ulong start, end; clGetEventProfilingInfo ( event, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, NULL ); clGetEventProfilingInfo ( event, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL ); return (end - start); } void opencl_dump_build_log (Opencl_device *ocl_dev, cl_program program) { cl_int rc; char buf[10240]; rc = clGetProgramBuildInfo ( program, ocl_dev->devices[0], CL_PROGRAM_BUILD_LOG, sizeof(buf), buf, NULL ); opencl_check_error (rc, "clGetProgramBuildInfo"); printf ("Build log:\n%s\n", buf); } const char* opencl_error_string (cl_int status) { static const char* error_strings[] = { "CL_SUCCESS", "CL_DEVICE_NOT_FOUND", "CL_DEVICE_NOT_AVAILABLE", "CL_COMPILER_NOT_AVAILABLE", "CL_MEM_OBJECT_ALLOCATION_FAILURE", "CL_OUT_OF_RESOURCES", "CL_OUT_OF_HOST_MEMORY", "CL_PROFILING_INFO_NOT_AVAILABLE", "CL_MEM_COPY_OVERLAP", "CL_IMAGE_FORMAT_MISMATCH", "CL_IMAGE_FORMAT_NOT_SUPPORTED", "CL_BUILD_PROGRAM_FAILURE", "CL_MAP_FAILURE", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "CL_INVALID_VALUE", "CL_INVALID_DEVICE_TYPE", "CL_INVALID_PLATFORM", "CL_INVALID_DEVICE", "CL_INVALID_CONTEXT", "CL_INVALID_QUEUE_PROPERTIES", "CL_INVALID_COMMAND_QUEUE", "CL_INVALID_HOST_PTR", "CL_INVALID_MEM_OBJECT", "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR", "CL_INVALID_IMAGE_SIZE", "CL_INVALID_SAMPLER", "CL_INVALID_BINARY", "CL_INVALID_BUILD_OPTIONS", "CL_INVALID_PROGRAM", "CL_INVALID_PROGRAM_EXECUTABLE", "CL_INVALID_KERNEL_NAME", "CL_INVALID_KERNEL_DEFINITION", "CL_INVALID_KERNEL", "CL_INVALID_ARG_INDEX", "CL_INVALID_ARG_VALUE", "CL_INVALID_ARG_SIZE", "CL_INVALID_KERNEL_ARGS", "CL_INVALID_WORK_DIMENSION", "CL_INVALID_WORK_GROUP_SIZE", "CL_INVALID_WORK_ITEM_SIZE", "CL_INVALID_GLOBAL_OFFSET", "CL_INVALID_EVENT_WAIT_LIST", "CL_INVALID_EVENT", "CL_INVALID_OPERATION", "CL_INVALID_GL_OBJECT", "CL_INVALID_BUFFER_SIZE", "CL_INVALID_MIP_LEVEL", "CL_INVALID_GLOBAL_WORK_SIZE", }; status = -status; if (status < 0 || status >= (cl_int) sizeof(error_strings)) { return ""; } return error_strings[status]; } void opencl_check_error (cl_int status, const char *msg) { if (status != CL_SUCCESS) { print_and_exit ("OPENCL ERROR: %s (%d,%s).\n", msg, status, opencl_error_string (status)); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/opencl/opencl_util.h000066400000000000000000000052261321604176500305720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _opencl_utils_h_ #define _opencl_utils_h_ #include "plm_config.h" #if (OPENCL_FOUND) #ifdef __APPLE__ #include #else #include #endif typedef cl_mem Opencl_buf; typedef struct opencl_device Opencl_device; struct opencl_device { cl_platform_id platform; cl_uint context_count; cl_context *contexts; /* Each of these have device_count entries */ cl_uint device_count; cl_device_id *devices; cl_command_queue *command_queues; cl_program *programs; cl_kernel *kernels; }; // JAS 2012.05.15 // This seems to cause build errors on OS X -- commented out // /* This should probably be done with CMake ... */ //#ifdef __APPLE__ //# define opencl_idx(vec,idx) vec[idx] //#else # define opencl_idx(vec,idx) vec.s[idx] //#endif #if defined __cplusplus extern "C" { #endif plmopencl_EXPORT ( cl_platform_id opencl_select_platform, void ); plmopencl_EXPORT ( void opencl_print_devices, void ); plmopencl_EXPORT ( cl_int opencl_open_device, Opencl_device *ocl_dev ); plmopencl_EXPORT ( void opencl_close_device, Opencl_device *ocl_dev ); plmopencl_EXPORT ( cl_ulong opencl_timer, cl_event &event ); plmopencl_EXPORT ( void opencl_check_error, cl_int return_code, const char *msg ); plmopencl_EXPORT ( void opencl_load_programs, Opencl_device *ocl_dev, const char* filename ); plmopencl_EXPORT ( void opencl_dump_build_log, Opencl_device *ocl_dev, cl_program program ); plmopencl_EXPORT ( Opencl_buf* opencl_buf_create, Opencl_device *ocl_dev, cl_mem_flags flags, size_t buffer_size, void *buffer ); plmopencl_EXPORT ( void opencl_buf_read, Opencl_device *ocl_dev, Opencl_buf* ocl_buf, size_t buffer_size, void *buffer ); plmopencl_EXPORT ( void opencl_buf_write, Opencl_device *ocl_dev, Opencl_buf* ocl_buf, size_t buffer_size, void *buffer ); plmopencl_EXPORT ( void opencl_kernel_create, Opencl_device *ocl_dev, const char *kernel_name ); plmopencl_EXPORT ( void opencl_set_kernel_args, Opencl_device *ocl_dev, ... ); plmopencl_EXPORT ( void opencl_kernel_enqueue, Opencl_device *ocl_dev, size_t global_work_size, size_t local_work_size ); #if defined __cplusplus } #endif #endif /* HAVE_OPENCL */ #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/000077500000000000000000000000001321604176500252435ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/CMakeLists.txt000066400000000000000000000100671321604176500300070ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_qt) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/plmqt_config.h.in ${CMAKE_BINARY_DIR}/plmqt_config.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (BEFORE ${CMAKE_CURRENT_BINARY_DIR}) if (QT4_FOUND) set (QT4_INCLUDE_DIRS ${QT_QTGUI_INCLUDE_DIR} ${QT_INCLUDE_DIR} ${QT_QTCORE_INCLUDE_DIR}) set (QT4_LIBRARIES ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY}) endif () ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (PLASTIMATCH_QT_SRC # pqt_application.cxx pqt_application.h pqt_data_source_dialog.cxx pqt_data_source_dialog.h pqt_data_source_list_model.cxx pqt_data_source_list_model.h pqt_database.cxx pqt_database.h pqt_findscu.cxx pqt_findscu.h pqt_main.cxx pqt_main_window.cxx pqt_main_window.h pqt_patient_list_model.cxx pqt_patient_list_model.h ) set (CRYSTALVIEW_SRC cview_portal.cxx cview_portal.h cview_main.cxx cview_main.h ) if (PLM_CONFIG_BUILD_QT_PLUGINS) set (QT_DESIGNER_PLUGINS_SRC cview_portal.cxx cview_portal.h cview_portal_plugin.cxx cview_portal_plugin.h ) endif() ##----------------------------------------------------------------------------- ## SPECIAL BUILD RULES: Qt ##----------------------------------------------------------------------------- if (QT4_FOUND) qt4_wrap_cpp (PORTAL_MOC_SRC cview_portal.h ) qt4_wrap_cpp (CRYSTALVIEW_MOC_SRC cview_main.h ) if (PLM_CONFIG_BUILD_QT_PLUGINS) qt4_wrap_cpp (QT_DESIGNER_PLUGINS_MOC_SRC cview_portal.h cview_portal_plugin.h ) endif() set (CRYSTALVIEW_SRC ${CRYSTALVIEW_SRC} ${CRYSTALVIEW_MOC_SRC} ${PORTAL_MOC_SRC} ) if (QT_QTSQL_FOUND) qt4_wrap_cpp (PLASTIMATCH_QT_SRC # pqt_application.h pqt_data_source_dialog.h pqt_data_source_list_model.h pqt_main_window.h pqt_patient_list_model.h ) qt4_wrap_ui (PLASTIMATCH_QT_SRC pqt_data_source_dialog.ui pqt_main_window.ui ) endif () endif () ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- if (ITK_FOUND AND QT4_FOUND) set (CRYSTALVIEW_LIBRARIES ${PLASTIMATCH_LIBS} ${QT_QTSQL_LIBRARIES} ${QT4_LIBRARIES}) plm_add_executable_v2 (cview "${CRYSTALVIEW_SRC}" "${QT4_INCLUDE_DIRS}" "${CRYSTALVIEW_LIBRARIES}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_IF_NOT_DEBIAN}) endif () if (ITK_FOUND AND QT4_FOUND AND QT_QTSQL_FOUND) if (PLM_CONFIG_ENABLE_PLASTIMATCH_QT) set (PLASTIMATCH_QT_LIBRARIES ${PLASTIMATCH_LIBS} ${QT_QTSQL_LIBRARIES} ${QT4_LIBRARIES}) plm_add_executable_v2 (plastimatch_qt "${PLASTIMATCH_QT_SRC}" "${QT4_INCLUDE_DIRS}" "${PLASTIMATCH_QT_LIBRARIES}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_IF_NOT_DEBIAN}) endif () endif () ##----------------------------------------------------------------------------- ## BUILD QT DESIGNER PLUGINS ##----------------------------------------------------------------------------- if (PLM_CONFIG_BUILD_QT_PLUGINS) add_definitions(-DQT_PLUGIN) add_definitions(-DQT_NO_DEBUG) add_definitions(-DQT_SHARED) add_definitions(-DQDESIGNER_EXPORT_WIDGETS) add_library(cview_portal_plugin SHARED ${QT_DESIGNER_PLUGINS_SRC} ${QT_DESIGNER_PLUGINS_MOC_SRC} ) set (QT_DESIGNER_PLUGINS_LIBRARIES ${PLASTIMATCH_LIBS} ${QT_LIBRARIES}) target_link_libraries(cview_portal_plugin ${QT_DESIGNER_PLUGINS_LIBRARIES}) set_target_properties (cview_portal_plugin PROPERTIES LIBRARY_OUTPUT_DIRECTORY designer) install (TARGETS cview_portal_plugin # DESTINATION ${QT_PLUGINS_DIR}/designer DESTINATION ${PLM_INSTALL_LIB_DIR}/designer) endif() plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/cview_main.cxx000066400000000000000000000126401321604176500301130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* JAS - 2011.08.14 * This is CrystalView... which is currently more or less just a * testbed for my PortalWidget Qt4 class. All of this is in * very early stages of development. */ #include "plmqt_config.h" #include #include #include "cview_portal.h" #include "cview_main.h" #include "plm_image.h" #define VERSION "0.09a" ///////////////////////////////////////////////////////// // PortalGrid : public // PortalGrid::PortalGrid (QWidget *parent) :QWidget (parent) { /* Create a grid layout with splitters */ QGridLayout *grid = new QGridLayout (this); QSplitter *splitterT = new QSplitter (Qt::Horizontal); QSplitter *splitterB = new QSplitter (Qt::Horizontal); QSplitter *splitterV = new QSplitter (Qt::Vertical); /* Create some portals */ for (int i=0; i<4; i++) { portal[i] = new PortalWidget; } /* place portals inside splitters */ splitterT->addWidget (portal[0]); splitterT->addWidget (portal[1]); splitterB->addWidget (portal[2]); splitterB->addWidget (portal[3]); splitterV->addWidget (splitterT); splitterV->addWidget (splitterB); /* Let's make a slider and connect it to portal[1] */ QSlider *slider1 = new QSlider (Qt::Vertical); slider1->setRange (0, 512); connect (slider1, SIGNAL(valueChanged(int)), portal[1], SLOT(renderSlice(int))); connect (portal[1], SIGNAL(sliceChanged(int)), slider1, SLOT(setValue(int))); /* Set the layout */ grid->addWidget (splitterV, 0, 0); grid->addWidget (slider1, 0, 1); setLayout (grid); } ///////////////////////////////////////////////////////// // CrystalWindow : private // bool CrystalWindow::openVol (const char* fn) { if (pli) { for (int i=0; i<4; i++) { portalGrid->portal[i]->detachVolume(); } } pli = plm_image_load (fn, PLM_IMG_TYPE_ITK_FLOAT); if (!pli) { return false; } input_vol = pli->get_volume_float (); if (!input_vol) { return false; } for (int i=0; i<4; i++) { portalGrid->portal[i]->resetPortal(); portalGrid->portal[i]->setVolume (input_vol.get()); } portalGrid->portal[0]->setView (PortalWidget::Axial); portalGrid->portal[1]->setView (PortalWidget::Coronal); portalGrid->portal[2]->setView (PortalWidget::Sagittal); portalGrid->portal[3]->setView (PortalWidget::Axial); return true; } void CrystalWindow::createActions () { actionOpen = new QAction (tr("&Open Volume"), this); actionExit = new QAction (tr("E&xit"), this); actionAboutQt = new QAction (tr("About &Qt"), this); connect (actionExit, SIGNAL(triggered()), qApp, SLOT(quit())); connect (actionOpen, SIGNAL(triggered()), this, SLOT(open())); connect (actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt())); } void CrystalWindow::createMenu () { menuFile = menuBar()->addMenu (tr("&File")); menuFile->addAction (actionOpen); menuFile->addAction (actionExit); menuBar()->addSeparator(); /* fancy in some environments */ menuHelp = menuBar()->addMenu (tr("&Help")); menuHelp->addAction (actionAboutQt); } ///////////////////////////////////////////////////////// // CrystalWindow : slots // void CrystalWindow::open () { QString fileName = QFileDialog::getOpenFileName ( this, tr("Open Volume"), "", tr("Image Volumes (*.mha *.mhd *.nrrd)") ); QByteArray ba = fileName.toLocal8Bit(); const char *fn = ba.data(); /* Only attempt load if user selects a file */ if (strcmp (fn, "")) { openVol (fn); } } ///////////////////////////////////////////////////////// // CrystalWindow : public // CrystalWindow::CrystalWindow (int argc, char** argv, QWidget *parent) :QMainWindow (parent) { pli.reset(); createActions (); createMenu (); portalGrid = new PortalGrid; setCentralWidget (portalGrid); /* open mha from command line */ if (argc > 1) { if (!openVol (argv[1])) { std::cout << "Failed to load: " << argv[1] << "\n"; } } } ///////////////////////////////////////////////////////// // main () // int main (int argc, char** argv) { std::cout << "CrystalView " << VERSION << "\n" << "Usage: cview [mha_file]\n\n" << " Application Hotkeys:\n" << " 1 - axial view\n" << " 2 - coronal view\n" << " 3 - sagittal view\n" << " -/+ - change active slice\n" << " ] - zoom in\n" << " [ - zoom out\n" << " r - reset portal\n\n" << " Mouse Functions:\n" << " Lclick - update HUD values\n" << " Rclick - pan/scroll\n" << " wheel - change active slice\n" << " Ctrl+wheel - zoom in/out\n" << " Rclick+wheel - zoom in/out\n\n"; QApplication app (argc, argv); CrystalWindow cview_window (argc, argv); cview_window.setWindowTitle ("CrystalView " VERSION); cview_window.setMinimumSize (640, 480); cview_window.show (); return app.exec (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/cview_main.h000066400000000000000000000017731321604176500275450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _cview_main_h_ #define _cview_main_h_ #include #include "cview_portal.h" #include "plm_image.h" #include "volume.h" class PortalGrid : public QWidget { public: PortalGrid (QWidget* parent = 0); public: PortalWidget* portal[4]; }; class CrystalWindow : public QMainWindow { Q_OBJECT; public: CrystalWindow (int argc, char** argv, QWidget *parent = 0); public slots: void open (); private: /* methods */ bool openVol (const char* fn); void createActions (); void createMenu (); private: /* variables */ PortalGrid *portalGrid; Plm_image::Pointer pli; Volume::Pointer input_vol; QMenu *menuFile; QMenu *menuHelp; QAction *actionOpen; QAction *actionExit; QAction *actionAboutQt; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/cview_portal.cxx000066400000000000000000000367431321604176500305020ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include "cview_portal.h" #include "plm_math.h" #include "volume.h" // TODO: * Clean up this file! // * Add: Multi-Volume / Layered Rendering System /* This just determines the amount of black space * a portal has within it */ #define FIELD_RES 4096 ///////////////////////////////////////////////////////// // PortalWidget: public // PortalWidget::PortalWidget (QWidget *parent) : QGraphicsView (parent) { scene = NULL; fb = NULL; slice = NULL; pmi = NULL; vol = NULL; view = Axial; min_intensity = FLT_MAX; max_intensity = FLT_MIN; current_slice = -1; pan_mode = false; view_center[0] = FIELD_RES/2; view_center[1] = FIELD_RES/2; hud_mode = false; memset (hud_xyz, 0, 3*sizeof (float)); memset (hud_ijk, 0, 3*sizeof (int)); setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy (Qt::ScrollBarAlwaysOff); setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); setTransformationAnchor(QGraphicsView::AnchorUnderMouse); scene = new QGraphicsScene (this); scene->setItemIndexMethod (QGraphicsScene::NoIndex); scene->setSceneRect (0, 0, FIELD_RES, FIELD_RES); scene->setBackgroundBrush (QBrush (Qt::black, Qt::SolidPattern)); setScene (scene); textPhy = new QGraphicsTextItem; textVox = new QGraphicsTextItem; textPhy->setZValue (99); textVox->setZValue (99); textPhy->setDefaultTextColor (Qt::red); textVox->setDefaultTextColor (Qt::green); scene->addItem (textPhy); scene->addItem (textVox); } ///////////////////////////////////////////////////////// // PortalWidget: private // int PortalWidget::getPixelValue (float* ij) { int ij_f[2]; int ij_r[2]; float li_1[2], li_2[2]; /* linear interpolation fractions */ float hfu; int idx; float* img = (float*) vol->img; li_clamp_2d (ij_f, ij_r, li_1, li_2, ij); idx = stride[2]*current_slice + stride[1]*(ij_f[1]+0) + stride[0]*(ij_f[0]+0); hfu = li_1[0] * li_1[1] * img[idx]; idx = stride[2]*current_slice + stride[1]*(ij_f[1]+0) + stride[0]*(ij_f[0]+1); hfu += li_2[0] * li_1[1] * img[idx]; idx = stride[2]*current_slice + stride[1]*(ij_f[1]+1) + stride[0]*(ij_f[0]+0); hfu += li_1[0] * li_2[1] * img[idx]; idx = stride[2]*current_slice + stride[1]*(ij_f[1]+1) + stride[0]*(ij_f[0]+1); hfu += li_2[0] * li_2[1] * img[idx]; /* remap to 8-bit grayscale */ int scaled = floor ((hfu - min_intensity) / (max_intensity - min_intensity) * 255 ); if (scaled > 255) { return 255; } else if (scaled < 0) { return 0; } return scaled; } void PortalWidget::updateCursor (const QPoint& view_ij) { QPointF scene_ij; /* portal: scene coords */ QPoint slice_ij; /* slice: pixel coods */ QPointF slice_xy; /* slice: realspace coords */ QPointF slice_offset; /* scene coords of slice left edge */ float slice_z; /* QGraphicsPixmapItem is derived from QGraphicsItem */ if ((void*)pmi != (void*)itemAt (view_ij)) { return; } else if (!vol) { return; } scene_ij = mapToScene (view_ij); slice_offset.rx() = ((FIELD_RES - pmap.width())/2.0)*res[0]; slice_offset.ry() = ((FIELD_RES - pmap.height())/2.0)*res[1]; slice_xy.rx() = (scene_ij.x()*res[0]-slice_offset.x())/scale.factor() + origin[0]; slice_xy.ry() = (scene_ij.y()*res[1]-slice_offset.y())/scale.factor() + origin[1]; slice_z = (current_slice*spacing[2] + origin[2]); slice_ij.rx() = (slice_xy.x()-origin[0])/res[0]; slice_ij.ry() = (slice_xy.y()-origin[1])/res[1]; switch (view) { case Axial: hud_xyz[0] = slice_xy.x(); hud_xyz[1] = slice_xy.y(); hud_xyz[2] = slice_z; hud_ijk[0] = slice_ij.x()*res[0]/spacing[0]; hud_ijk[1] = slice_ij.y()*res[1]/spacing[1]; hud_ijk[2] = current_slice; break; case Coronal: hud_xyz[0] = slice_xy.x(); hud_xyz[1] = slice_z; hud_xyz[2] = (-1.0)*slice_xy.y(); hud_ijk[0] = slice_ij.x()*res[0]/spacing[0]; hud_ijk[1] = current_slice; hud_ijk[2] = slice_ij.y()*res[1]/spacing[1]; break; case Sagittal: hud_xyz[0] = slice_z; hud_xyz[1] = slice_xy.x(); hud_xyz[2] = (-1.0)*slice_xy.y(); hud_ijk[0] = current_slice; hud_ijk[1] = slice_ij.x()*res[0]/spacing[0]; hud_ijk[2] = slice_ij.y()*res[1]/spacing[1]; break; } // emit targetChanged (xyz[0], xyz[1], xyz[2]); updateHUD (); #if 0 std::cout << "--------------------------------------------\n" << " View: " << view_ij.x() << " "<< view_ij.y() << "\n" << " Scene: " << scene_ij.x() << " " << scene_ij.y() << "\n" << " Slice: " << slice_ij.x() << " " << slice_ij.y() << "\n" << "RealSpace: " << slice_xy.x() << " " << slice_xy.y() << "\n"; #endif } void PortalWidget::updateHUD () { textPhy->setPlainText (QString ("Phy: %1 %2 %3") .arg (hud_xyz[0], 0, 'f', 2) .arg (hud_xyz[1], 0, 'f', 2) .arg (hud_xyz[2], 0, 'f', 2)); textVox->setPlainText (QString ("Vox: %1 %2 %3") .arg (hud_ijk[0]) .arg (hud_ijk[1]) .arg (hud_ijk[2])); textPhy->setPos (mapToScene(0,0)); textVox->setPos (mapToScene(0,this->height()-24)); } void PortalWidget::setWindowScale () { float tmp[2]; tmp[0] = (float)size().height() / (float)dim[0]; tmp[1] = (float)size().width() / (float)dim[1]; if (tmp[0] < tmp[1]) { scale.window = tmp[0]; } else { scale.window = tmp[1]; } } void PortalWidget::doZoom (int step) { if ( (current_slice + step < ijk_max[2]) && (current_slice + step >= 0) ) { current_slice += step; renderSlice (current_slice); } } void PortalWidget::doScale (float step) { scale.user += step; renderSlice (current_slice); } void PortalWidget::li_clamp_2d ( int *ij_f, /* Output: "floor" pixel in moving img in vox*/ int *ij_r, /* Ouptut: "round" pixel in moving img in vox*/ float *li_1, /* Output: Fraction for upper index voxel */ float *li_2, /* Output: Fraction for lower index voxel */ float *ij /* Input: Unrounded pixel coordinates in vox */ ) { for (int n=0; n<2; n++) { float maff = floor (ij[n]); ij_f[n] = (int) maff; ij_r[n] = ROUND_INT (ij[n]); li_2[n] = ij[n] - maff; if (ij_f[n] < 0) { ij_f[n] = 0; ij_r[n] = 0; li_2[n] = 0.0f; } else if (ij_f[n] >= ijk_max[n]-1) { ij_f[n] = ijk_max[n] - 2; ij_r[n] = ijk_max[n] - 1; li_2[n] = 1.0f; } li_1[n] = 1.0f - li_2[n]; } } ///////////////////////////////////////////////////////// // PortalWidget: protected // void PortalWidget::wheelEvent (QWheelEvent *event) { /* Note: delta is in "# of 8ths of a degree" * Each wheel click is usually 15 degrees on most mice */ int step = event->delta() / (8*15); if ( scale.wheelMode ) { doScale (0.1*(float)step); } else { doZoom (step); } } void PortalWidget::keyPressEvent (QKeyEvent *event) { switch (event->key()) { case Qt::Key_1: setView (Axial); break; case Qt::Key_2: setView (Coronal); break; case Qt::Key_3: setView (Sagittal); break; case Qt::Key_J: case Qt::Key_Minus: doZoom (-1); break; case Qt::Key_K: case Qt::Key_Plus: case Qt::Key_Equal: doZoom (1); break; case Qt::Key_BracketRight: case Qt::Key_L: doScale (+0.1f); break; case Qt::Key_BracketLeft: case Qt::Key_H: doScale (-0.1f); break; case Qt::Key_R: resetPortal (); updateHUD (); break; case Qt::Key_Control: scale.wheelMode = true; break; default: /* Forward to default callback */ QGraphicsView::keyPressEvent (event); } } void PortalWidget::keyReleaseEvent (QKeyEvent *event) { switch (event->key()) { case Qt::Key_Control: scale.wheelMode = false; break; default: /* Forward to default callback */ QGraphicsView::keyPressEvent (event); } } void PortalWidget::mousePressEvent (QMouseEvent *event) { QPoint view_ij; /* portal: viewport coords */ view_ij = event->pos(); switch (event->button()) { case Qt::LeftButton: updateCursor (view_ij); updateHUD (); hud_mode = true; event->accept(); break; case Qt::RightButton: scale.wheelMode = true; pan_mode = true; pan_xy[0] = view_ij.x(); pan_xy[1] = view_ij.y(); setCursor (Qt::ClosedHandCursor); event->accept(); break; default: event->ignore(); break; } } void PortalWidget::mouseReleaseEvent (QMouseEvent *event) { switch (event->button()) { case Qt::LeftButton: hud_mode = false; event->ignore(); break; case Qt::RightButton: scale.wheelMode = false; pan_mode = false; setCursor (Qt::ArrowCursor); event->accept(); break; default: event->ignore(); break; } } void PortalWidget::mouseMoveEvent (QMouseEvent *event) { int dx = event->pos().x() - pan_xy[0]; int dy = event->pos().y() - pan_xy[1]; if (pan_mode) { translate ( (double)dx, (double)dy); updateHUD (); view_center[0] -= dx; view_center[1] -= dy; pan_xy[0] = event->pos().x(); pan_xy[1] = event->pos().y(); } if (hud_mode) { updateCursor (event->pos()); updateHUD (); } event->ignore(); } void PortalWidget::resizeEvent (QResizeEvent *event) { centerOn (view_center[0], view_center[1]); setWindowScale (); renderSlice (current_slice); updateHUD (); } ///////////////////////////////////////////////////////// // PortalWidget: slots // void PortalWidget::setVolume (Volume* vol) { this->vol = vol; float* img = (float*) vol->img; /* Obtain value range */ min_intensity = FLT_MAX; max_intensity = FLT_MIN; for (plm_long i=0; inpix; i++) { if ( img[i] < min_intensity ) { min_intensity = img[i]; } if ( img[i] > max_intensity ) { max_intensity = img[i]; } } /* Reset HUD */ memset (hud_xyz, 0, 3*sizeof (float)); memset (hud_ijk, 0, 3*sizeof (int)); updateHUD (); /* Display the loaded volume */ PortalWidget::setView (Axial); } void PortalWidget::setView (enum PortalViewType view) { /* Cannot setView with no volume attached to portal */ if (!vol) { return; } /* Delete the old rendering surface */ if (slice) { scene->removeItem (pmi); delete slice; free (fb); } this->view = view; /* Change coordinate systems */ switch (view) { case Axial: ijk_max[0] = vol->dim[0]; ijk_max[1] = vol->dim[1]; ijk_max[2] = vol->dim[2]; stride[0] = 1; stride[1] = vol->dim[0]; stride[2] = vol->dim[1] * vol->dim[0]; spacing[0] = fabs (vol->spacing[0]); spacing[1] = fabs (vol->spacing[1]); spacing[2] = fabs (vol->spacing[2]); origin[0] = vol->origin[0]; origin[1] = vol->origin[1]; origin[2] = vol->origin[2]; break; case Coronal: ijk_max[0] = vol->dim[0]; ijk_max[1] = vol->dim[2]; ijk_max[2] = vol->dim[1]; stride[0] = 1; stride[1] = vol->dim[1] * vol->dim[0]; stride[2] = vol->dim[0]; spacing[0] = fabs (vol->spacing[0]); spacing[1] = fabs (vol->spacing[2]); spacing[2] = fabs (vol->spacing[1]); origin[0] = vol->origin[0]; origin[1] = vol->origin[2]; origin[2] = vol->origin[1]; break; case Sagittal: ijk_max[0] = vol->dim[1]; ijk_max[1] = vol->dim[2]; ijk_max[2] = vol->dim[0]; stride[0] = vol->dim[0]; stride[1] = vol->dim[1] * vol->dim[0]; stride[2] = 1; spacing[0] = fabs (vol->spacing[1]); spacing[1] = fabs (vol->spacing[2]); spacing[2] = fabs (vol->spacing[0]); origin[0] = vol->origin[1]; origin[1] = vol->origin[2]; origin[2] = vol->origin[0]; break; default: exit (-1); break; } /* Rendering surface dimensions (pix) */ dim[0] = floor (ijk_max[0]*spacing[0]); dim[1] = floor (ijk_max[1]*spacing[1]); setWindowScale (); /* Portal resolution (mm per pix) */ res[0] = (spacing[0] * (float)ijk_max[0]) / (float)dim[0]; res[1] = (spacing[1] * (float)ijk_max[1]) / (float)dim[1]; /* Make a new rendering surface */ fb = (uchar*) malloc (4*dim[0]*dim[1]*sizeof (uchar)); slice = new QImage (fb, dim[0], dim[1], QImage::Format_ARGB32); pmi = scene->addPixmap (pmap); /* We always set the portal to the center slice after changing the view */ renderSlice (ijk_max[2] / 2); } void PortalWidget::setTarget (float* xyz) { // set realspace coords } void PortalWidget::resetPortal () { scale.user = 1.0; scale.wheelMode = false; pan_mode = false; view_center[0] = FIELD_RES/2; view_center[1] = FIELD_RES/2; centerOn (view_center[0], view_center[1]); renderSlice (current_slice); } void PortalWidget::renderSlice (int slice_num) { int i, j; /* slice coords */ int p[2]; /* frame buffer coords */ float xy[2]; /* real space coords */ float ij[2]; /* volume slice indices */ int shade; uchar* pixel; if (!vol) { return; } else if ((slice_num < 0) || (slice_num >= ijk_max[2])) { return; } current_slice = slice_num; /* Set slice pixels */ for (j=0; jsetPixmap (pmap); pmi->setOffset (((FIELD_RES - pmap.width())/2), ((FIELD_RES- pmap.height())/2)); emit sliceChanged (current_slice); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/cview_portal.h000066400000000000000000000103161321604176500301130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _cview_portal_h_ #define _cview_portal_h_ #include class Volume; class PortalWidget : public QGraphicsView { private: class ScaleHandler { public: bool wheelMode; /* mouse wheel scaling toggle */ float window; /* determined by portal size */ float user; /* determined by user */ float factor () { return window*user; } ScaleHandler () { wheelMode = false; window = 1.0; user = 1.0; }; }; /****************************************************************/ Q_OBJECT /* Needed for QT signals/slots */ public: enum PortalViewType { Axial, Coronal, Sagittal }; private: /* Qt4 rendering */ QGraphicsScene* scene; /* Portal's QGraphicsScene */ uchar* fb; /* Framebuffer for drawing */ QImage* slice; /* QImage tied to Framebuffer */ QPixmap pmap; /* QPixmap for rendering */ QGraphicsPixmapItem* pmi; /* Needed to update QPixmap */ /* Image Attributes */ Volume* vol; /* Plastimatch volume */ float min_intensity; /* Min floating point value from volume */ float max_intensity; /* Max floating point value from volume */ int stride[3]; /* volume strides for current view type */ /* Portal Geometry */ int ijk_max[3]; /* index limits for current view type */ int current_slice; /* Current slice index within volume */ int dim[2]; /* rendering surface dims (in pixels) */ float res[2]; /* portal resolution (in mm per pixel) */ float spacing[3]; /* voxel spacing in slice (in mm) */ float origin[3]; /* volume slice origin (in mm) */ PortalViewType view; /* Axial or Coronal or Sagittal */ ScaleHandler scale; /* Scroll/Panning */ bool pan_mode; /* is panning mode enabled? */ int pan_xy[2]; /* tracking variables for panning */ int view_center[2]; /* point in scene that is in view center */ /* HUD */ bool hud_mode; float hud_xyz[3]; int hud_ijk[3]; QGraphicsTextItem* textPhy; QGraphicsTextItem* textVox; public: PortalWidget (QWidget *parent = 0); int getNumSlices () { return ijk_max[2]; } private: int getPixelValue (float* ij); void updateCursor (const QPoint& view_ij); void updateHUD (); void setWindowScale (); void doZoom (int step); void doScale (float step); void li_clamp_2d (int *ij_f, int *ij_r, float *li_1, float *li_2, float *ij); signals: void targetChanged (float* xyz); /* on cursor change */ void sliceChanged (int n); /* on slice change */ public slots: void setVolume (Volume* vol); /* Attach volume to portal */ void detachVolume () { vol = NULL; } /* Detach volume from portal */ void setView (enum PortalViewType view); /* Set portal view type */ void setTarget (float* xyz); /* Set the cursor RS coords */ void resetPortal (); /* Removes user transforms */ void renderSlice (int slice_num); /* Render slice_num */ protected: void wheelEvent (QWheelEvent *event); void keyPressEvent (QKeyEvent *event); void keyReleaseEvent (QKeyEvent *event); void mousePressEvent (QMouseEvent *event); void mouseReleaseEvent (QMouseEvent *event); void mouseMoveEvent (QMouseEvent *event); void resizeEvent (QResizeEvent *event); }; #endif cview_portal_plugin.cxx000066400000000000000000000021001321604176500317550ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt#include #include #include "cview_portal_plugin.h" #include "cview_portal.h" PortalWidgetPlugin::PortalWidgetPlugin (QObject* parent) : QObject (parent) { } QString PortalWidgetPlugin::name () const { return "PortalWidget"; } QString PortalWidgetPlugin::includeFile () const { return "portal_widget.h"; } QString PortalWidgetPlugin::group () const { return tr ("CrystalView Widgets"); } QIcon PortalWidgetPlugin::icon () const { // TODO: Add an icon to a resourece file for this return QIcon (); // return QIcon (":/images/portal_widget.png"); } QString PortalWidgetPlugin::toolTip () const { return tr ("Volume slice viewing widget"); } QString PortalWidgetPlugin::whatsThis () const { return tr ("This widget allows for slice by slice viewing of Plm_image objects"); } bool PortalWidgetPlugin::isContainer () const { return false; } QWidget* PortalWidgetPlugin::createWidget (QWidget* parent) { return new PortalWidget (parent); } Q_EXPORT_PLUGIN2(portalwidgetplugin, PortalWidgetPlugin); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/cview_portal_plugin.h000066400000000000000000000010071321604176500314660ustar00rootroot00000000000000#include class PortalWidgetPlugin : public QObject, public QDesignerCustomWidgetInterface { Q_OBJECT; Q_INTERFACES(QDesignerCustomWidgetInterface); public: PortalWidgetPlugin(QObject *parent = 0); QString name() const; QString includeFile() const; QString group() const; QIcon icon() const; QString toolTip() const; QString whatsThis() const; bool isContainer() const; QWidget *createWidget(QWidget* parent); }; plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/plmqt_config.h.in000066400000000000000000000013201321604176500304770ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plmqt_config_h__ #define __plmqt_config_h__ #include "plm_config.h" #ifdef API # undef API #endif #ifdef C_API # undef C_API #endif #if ((defined(_WIN32) || defined(WIN32)) && (defined (PLM_BUILD_SHARED_LIBS))) # ifdef plmqt_EXPORTS # define C_API EXTERNC __declspec(dllexport) # define API __declspec(dllexport) # else # define C_API EXTERNC __declspec(dllimport) # define API __declspec(dllimport) # endif #else # define C_API EXTERNC # define API #endif #endif pqt_data_source_dialog.cxx000066400000000000000000000073201321604176500324060ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmqt_config.h" #include #include "pqt_data_source_dialog.h" #include "pqt_database.h" Pqt_data_source_dialog::Pqt_data_source_dialog () { setupUi (this); // this sets up the GUI /* Hide status */ this->label_status->hide(); /* Attach model to QT listView */ this->m_data_source_list_model = new Pqt_data_source_list_model; this->listView_data_source_list->setModel (this->m_data_source_list_model); /* Which data source is active in dialog box */ this->m_active_index = -1; } Pqt_data_source_dialog::~Pqt_data_source_dialog () { } void Pqt_data_source_dialog::pushbutton_new_released (void) { /* Update dialog box */ /* GCS FIX: This works correctly, but emits a Qt warning on the console */ this->m_active_index = -1; this->m_data_source_list_model->set_active_row (-1); update_fields (); } void Pqt_data_source_dialog::pushbutton_save_released (void) { /* Validate input */ if (this->lineEdit_data_source_name->text().isEmpty()) { QMessageBox::information (0, QString ("Info"), QString ("Please fill in the data source name.")); return; } if (this->lineEdit_host->text().isEmpty()) { QMessageBox::information (0, QString ("Info"), QString ("Please fill in the hostname.")); return; } if (this->lineEdit_port->text().isEmpty()) { QMessageBox::information (0, QString ("Info"), QString ("Please fill in the port.")); return; } if (this->lineEdit_aet->text().isEmpty()) { QMessageBox::information (0, QString ("Info"), QString ("Please fill in AET.")); return; } /* Insert into database */ pqt_database_insert_data_source ( this->lineEdit_data_source_name->text(), this->lineEdit_host->text(), this->lineEdit_port->text(), this->lineEdit_aet->text()); /* Refresh list model and dialog box fields */ this->refresh_from_database (); } void Pqt_data_source_dialog::pushbutton_delete_released (void) { /* Do nothing if no data source is highlighted */ if (this->m_active_index == -1) { return; } /* Delete the row from the database */ this->m_data_source_list_model->set_active_row (this->m_active_index); pqt_database_delete_data_source ( this->m_data_source_list_model->get_label (), this->m_data_source_list_model->get_host (), this->m_data_source_list_model->get_port (), this->m_data_source_list_model->get_aet ()); /* Refresh list model and dialog box fields */ this->refresh_from_database (); } void Pqt_data_source_dialog::listview_data_source_activated ( QModelIndex model_index ) { if (model_index.row() == this->m_active_index) { return; } this->m_active_index = model_index.row(); update_fields (); } void Pqt_data_source_dialog::update_fields (void) { QString label = this->m_data_source_list_model->get_label (); this->lineEdit_data_source_name->setText (label); QString host = this->m_data_source_list_model->get_host (); this->lineEdit_host->setText (host); QString port = this->m_data_source_list_model->get_port (); this->lineEdit_port->setText (port); QString aet = this->m_data_source_list_model->get_aet (); this->lineEdit_aet->setText (aet); } void Pqt_data_source_dialog::refresh_from_database (void) { /* Refresh model - this also sets query index to -1 */ this->m_data_source_list_model->load_query (); /* Update dialog box */ /* GCS FIX: This works correctly, but emits a Qt warning on the console */ this->m_active_index = -1; update_fields (); } pqt_data_source_dialog.h000066400000000000000000000022321321604176500320300ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pqt_data_source_dialog_h_ #define _pqt_data_source_dialog_h_ #include "plmqt_config.h" #include "ui_pqt_data_source_dialog.h" #include "pqt_data_source_list_model.h" //QT_BEGIN_NAMESPACE // class QAction; // class QDialogButtonBox; // class QGroupBox; // class QLabel; // class QLineEdit; // class QMenu; // class QMenuBar; // class QPushButton; // class QTextEdit; //QT_END_NAMESPACE class Pqt_data_source_dialog : public QDialog, private Ui::pqtDataSourceDialog { Q_OBJECT ; public: Pqt_data_source_dialog (); ~Pqt_data_source_dialog (); Pqt_data_source_list_model *m_data_source_list_model; public slots: void pushbutton_new_released (void); void pushbutton_save_released (void); void pushbutton_delete_released (void); void listview_data_source_activated (QModelIndex model_index); public: int m_active_index; void refresh_from_database (void); void update_fields (void); }; #endif pqt_data_source_dialog.ui000066400000000000000000000150201321604176500322150ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt pqtDataSourceDialog 0 0 600 446 Data Sources 10 20 211 371 245 20 331 231 QFormLayout::AllNonFixedFieldsGrow Data source name Data source type false Host Port AET Status true TextLabel 10 400 571 29 New Delete Qt::Horizontal 40 20 Save Close pushButton_close released() pqtDataSourceDialog accept() 537 421 314 296 pushButton_save released() pqtDataSourceDialog pushbutton_save_released() 456 419 439 332 pushButton_new released() pqtDataSourceDialog pushbutton_new_released() 70 418 258 368 pushButton_delete released() pqtDataSourceDialog pushbutton_delete_released() 150 419 257 402 listView_data_source_list activated(QModelIndex) pqtDataSourceDialog listview_data_source_activated(QModelIndex) 154 225 261 240 listView_data_source_list clicked(QModelIndex) pqtDataSourceDialog listview_data_source_activated(QModelIndex) 95 187 270 248 pushbutton_save_released() pushbutton_new_released() pushbutton_delete_released() listview_data_source_activated(QModelIndex) pqt_data_source_list_model.cxx000066400000000000000000000035751321604176500333120ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmqt_config.h" #include #include #include "pqt_database.h" #include "pqt_data_source_list_model.h" int Pqt_data_source_list_model::rowCount ( const QModelIndex& parent ) const { return this->m_num_rows; } QVariant Pqt_data_source_list_model::data (const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.row() >= this->m_num_rows) { return QVariant(); } if (role != Qt::DisplayRole) { return QVariant(); } this->m_query.seek (index.row()); return this->m_query.value(0).toString(); } void Pqt_data_source_list_model::set_active_row (int index) { this->m_query.seek (index); } QString Pqt_data_source_list_model::get_label (void) { return this->m_query.value(0).toString(); } QString Pqt_data_source_list_model::get_host (void) { return this->m_query.value(1).toString(); } QString Pqt_data_source_list_model::get_port (void) { return this->m_query.value(2).toString(); } QString Pqt_data_source_list_model::get_aet (void) { return this->m_query.value(3).toString(); } void Pqt_data_source_list_model::load_query (void) { /* Load data sources from database */ this->m_query = pqt_database_query_data_source_label (); this->m_num_rows = 0; /* QSqlQuery::size returns -1 if not supported (sqlite). So we manually count the rows. */ while (this->m_query.next()) { this->m_num_rows ++; } /* Reset query back to first row */ this->m_query.seek (-1); /* Refresh widget by resetting model (I think this is how it is supposed to be done, can't find in documentation) */ this->reset (); } pqt_data_source_list_model.h000066400000000000000000000020471321604176500327300ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pqt_data_source_list_model_h_ #define _pqt_data_source_list_model_h_ #include "plmqt_config.h" #include #include "ui_pqt_main_window.h" class Pqt_data_source_list_model : public QAbstractListModel { Q_OBJECT ; public: Pqt_data_source_list_model (QObject *parent = 0) : QAbstractListModel (parent) { load_query (); } ~Pqt_data_source_list_model () {} /* Overrides from base class */ int rowCount (const QModelIndex& parent = QModelIndex()) const; QVariant data (const QModelIndex& index, int role) const; /* Other methods */ void load_query (void); void set_active_row (int index); QString get_label (void); QString get_host (void); QString get_port (void); QString get_aet (void); public: mutable QSqlQuery m_query; int m_num_rows; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/pqt_database.cxx000066400000000000000000000102231321604176500304150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmqt_config.h" #include #include #include #include #include #include #include #include #include #include #include /* Use global variable for database handle */ static QSqlDatabase global_db; static void print_database_error (QSqlError sql_error) { QMessageBox::information (0, QString ("Database error"), QString ("Database error: %1, %2, %3") .arg(sql_error.type()) .arg(sql_error.number()) .arg(sql_error.text())); } void pqt_database_start (QString db_path) { /* Make parent directory for database file if it doesn't exist */ QDir().mkpath(QFileInfo(db_path).absolutePath()); /* Open the sqlite database file. */ global_db = QSqlDatabase::addDatabase ("QSQLITE"); global_db.setDatabaseName (db_path); bool ok = global_db.open (); if (!ok) { print_database_error (global_db.lastError()); return; } QSqlQuery query; QString sql; /* Check database for version upgrade */ sql = "CREATE TABLE IF NOT EXISTS " "pqt_application_version ( " " version TEXT " ");"; if (!query.exec (sql)) { print_database_error (query.lastError()); return; } sql = "SELECT version FROM pqt_application_version;"; if (!query.exec (sql)) { print_database_error (query.lastError()); return; } if (query.next ()) { QString version_string = query.value(0).toString(); #if defined (commentout) QMessageBox::information (0, QString ("Version string"), QString ("PQT database version = %1").arg(version_string)); #endif } else { /* New database. Add version string. */ sql = "INSERT INTO pqt_application_version values ('Experimental');"; if (!query.exec (sql)) { print_database_error (query.lastError()); return; } } /* Create tables if they don't exist */ sql = "CREATE TABLE IF NOT EXISTS " "data_source ( " " oi INTEGER PRIMARY KEY, " " label TEXT, " " type TEXT, " " host TEXT, " " port TEXT, " " aet TEXT " ");"; if (!query.exec (sql)) { print_database_error (query.lastError()); return; } sql = "CREATE TABLE IF NOT EXISTS " "data_source_dicom ( " " oi INTEGER PRIMARY KEY, " " host TEXT, " " port TEXT, " " aet TEXT " ");"; if (!query.exec (sql)) { print_database_error (query.lastError()); return; } sql = "CREATE TABLE IF NOT EXISTS " "data_source_directory ( " " oi INTEGER PRIMARY KEY, " " directory TEXT " ");"; if (!query.exec (sql)) { print_database_error (query.lastError()); return; } } void pqt_database_stop (void) { printf ("Closing databse\n"); global_db.close (); printf ("Done closing databse\n"); } QSqlQuery pqt_database_query_data_source_label (void) { QString sql = "SELECT label,host,port,aet FROM data_source ORDER BY label;"; QSqlQuery query = QSqlQuery (sql); #if defined (commentout) while (query.next ()) { QString label_string = query.value(0).toString(); QTextStream(stdout) << QString ("label = %1\n").arg(label_string); } query.seek (-1); #endif return query; } void pqt_database_insert_data_source (QString label, QString host, QString port, QString aet) { QString sql = QString ( "INSERT INTO data_source " "(label, type, host, port, aet) " "values ('%1', '', '%2', '%3', '%4');") .arg (label) .arg (host) .arg (port) .arg (aet); QSqlQuery query; if (!query.exec (sql)) { print_database_error (query.lastError()); return; } } void pqt_database_delete_data_source (QString label, QString host, QString port, QString aet) { QString sql = QString ( "DELETE FROM data_source WHERE " "label = \"%1\" AND host = \"%2\" AND port = \"%3\" AND aet = \"%4\";") .arg (label) .arg (host) .arg (port) .arg (aet); QTextStream(stdout) << sql << "\n"; QSqlQuery query; if (!query.exec (sql)) { print_database_error (query.lastError()); return; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/pqt_database.h000066400000000000000000000012541321604176500300460ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pqt_database_h_ #define _pqt_database_h_ #include "plmqt_config.h" #include #include void pqt_database_start (QString db_path); void pqt_database_stop (void); QSqlQuery pqt_database_query_data_source_label (void); void pqt_database_insert_data_source (QString label, QString host, QString port, QString aet); void pqt_database_delete_data_source (QString label, QString host, QString port, QString aet); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/pqt_findscu.cxx000066400000000000000000000043631321604176500303140ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmqt_config.h" #include #include #include #include #include "pqt_findscu.h" Pqt_findscu::~Pqt_findscu (void) { while (!this->m_patient_list.isEmpty()) delete this->m_patient_list.takeFirst(); } void Pqt_findscu::query (QString host, QString port, QString aet) { QTextStream(stdout) << QString("Performing query: %1 %2 %3\n") .arg (host) .arg (port) .arg (aet); /* Execute findscu as a synchronous external process */ QString program = "findscu"; QStringList arguments; arguments << "-P" << "-k" << "0010,0010" << "-k" << "0010,0020" << "-k" << "0008,0052=PATIENT" << "-aec" << "READWRITE" << "localhost" << "5678"; QProcess *process = new QProcess; process->start (program, arguments); if (!process->waitForStarted()) return; if (!process->waitForFinished()) return; /* Parse stdout from findscu, look for patient id, patient name, and add to the list of patients */ QByteArray result; char buf[4096]; qint64 rc; QRegExp rx("\\(([^)]*)[^[]*\\[([^]]*)"); Pqt_findscu_entry *fe = 0; while ((rc = process->readLine (buf, sizeof(buf))) != -1) { int match = rx.indexIn (buf); if (match == -1) { continue; } /* Got dicom tag, value pair */ QString tag = rx.cap(1); QString value = rx.cap(2); /* Check for patient name */ if (!QString::compare (tag, "0010,0010")) { fe = new Pqt_findscu_entry; fe->m_patient_name = value; continue; } if (!fe) continue; /* Check for patient id */ if (!QString::compare (tag, "0010,0020")) { fe->m_patient_id = value; /* Last tag/value. Add to list. */ this->m_patient_list << fe; fe = 0; } } if (fe) delete fe; } void Pqt_findscu::debug (void) { for (int i = 0; i < this->m_patient_list.size(); ++i) { Pqt_findscu_entry *fe = this->m_patient_list.at(i); QTextStream(stdout) << QString("[%1] [%2] [%3]\n") .arg (i) .arg (fe->m_patient_id) .arg (fe->m_patient_name); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/pqt_findscu.h000066400000000000000000000012011321604176500277250ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pqt_findscu_h_ #define _pqt_findscu_h_ #include "plmqt_config.h" #include #include class Pqt_findscu_entry { public: QString m_patient_id; QString m_patient_name; }; class Pqt_findscu { public: ~Pqt_findscu (void); public: QList m_patient_list; public: void query (QString host, QString port, QString aet); void debug (void); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/pqt_main.cxx000066400000000000000000000042251321604176500276020ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmqt_config.h" #include #include #include #include "pqt_database.h" #include "pqt_findscu.h" #include "pqt_main_window.h" static void initialize_application (void) { /* Set path to persistent application settings */ QCoreApplication::setOrganizationName ("Plastimatch"); QCoreApplication::setOrganizationDomain ("plastimatch.org"); QCoreApplication::setApplicationName ("plastimatch_qt"); /* QT doesn't seem to have an API for getting the user's application data directory. So we construct a hypothetical ini file name, then grab the directory. */ QSettings tmp ( QSettings::IniFormat, /* Make sure we get path, not registry */ QSettings::UserScope, /* Get user directory, not system direcory */ "Plastimatch", /* Orginazation name (subfolder within path) */ "plastimatch_qt" /* Application name (file name with subfolder) */ ); QString config_dir = QFileInfo(tmp.fileName()).absolutePath(); #if defined (commentout) QMessageBox::information (0, QString ("Info"), QString ("Config dir is %1").arg (config_dir)); #endif /* Construct filename of sqlite database that holds settings. On unix, this is $HOME/.config/Plastimatch/pqt.sqlite */ QSettings settings; QString db_path = settings.value ("db/sqlite3_path", QFileInfo (QDir (config_dir), QString ("pqt.sqlite")) .absoluteFilePath()).toString(); /* Load database */ printf ("Starting database\n"); pqt_database_start (db_path); } int main (int argc, char **argv) { int rc; QApplication app (argc, argv); initialize_application (); Pqt_main_window pqt_main_window; pqt_main_window.show (); rc = app.exec(); pqt_database_stop (); /* Application emits database warning on program exit. Apparently this is a bug in Qt. Ref: http://lists.trolltech.com/qt-interest/2008-05/msg00553.html */ return rc; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/pqt_main_window.cxx000066400000000000000000000023511321604176500311670ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmqt_config.h" #include #include #include "pqt_data_source_dialog.h" #include "pqt_database.h" #include "pqt_main_window.h" Pqt_main_window::Pqt_main_window () { /* Sets up the GUI */ setupUi (this); /* Create data source dialog */ m_data_source_dialog = new Pqt_data_source_dialog; /* Query remote sources */ QSqlQuery query = pqt_database_query_data_source_label (); while (query.next()) { this->m_findscu.query ( query.value(1).toString(), query.value(2).toString(), query.value(3).toString()); } this->m_findscu.debug (); /* Attach model to QT table in main window */ m_patient_list_model = new Pqt_patient_list_model; tableView->setModel (m_patient_list_model); } Pqt_main_window::~Pqt_main_window () { delete m_data_source_dialog; delete m_patient_list_model; QSettings settings; settings.sync (); } void Pqt_main_window::new_data_source (void) { /* Open dialog */ m_data_source_dialog->show (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/pqt_main_window.h000066400000000000000000000017461321604176500306230ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pqt_main_window_h_ #define _pqt_main_window_h_ #include "plmqt_config.h" #include "pqt_data_source_dialog.h" #include "pqt_findscu.h" #include "pqt_patient_list_model.h" #include "ui_pqt_main_window.h" //QT_BEGIN_NAMESPACE // class QAction; // class QDialogButtonBox; // class QGroupBox; // class QLabel; // class QLineEdit; // class QMenu; // class QMenuBar; // class QPushButton; // class QTextEdit; //QT_END_NAMESPACE class Pqt_main_window : public QMainWindow, private Ui::pqtMainWindow { Q_OBJECT ; public: Pqt_main_window (); ~Pqt_main_window (); Pqt_data_source_dialog *m_data_source_dialog; Pqt_patient_list_model *m_patient_list_model; Pqt_findscu m_findscu; public slots: void new_data_source (void); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/pqt_main_window.ui000066400000000000000000000141011321604176500307760ustar00rootroot00000000000000 pqtMainWindow 0 0 754 653 MainWindow Patient Name Patient ID Qt::Horizontal 40 20 x y z PushButton Qt::Vertical 20 40 Qt::Horizontal QAbstractItemView::SelectRows true true true true false true true Qt::Horizontal 40 20 0 0 754 27 &File Ed&it &Data sources &Quit actionNew_data_source triggered() pqtMainWindow new_data_source() -1 -1 487 304 actionQuit triggered() pqtMainWindow close() -1 -1 487 304 new_data_source() pqt_patient_list_model.cxx000066400000000000000000000022061321604176500324530ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmqt_config.h" #include #include "pqt_patient_list_model.h" int Pqt_patient_list_model::rowCount ( const QModelIndex& parent ) const { return 2; } int Pqt_patient_list_model::columnCount ( const QModelIndex& parent ) const { return 3; } QVariant Pqt_patient_list_model::data (const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.row() >= 2) { return QVariant(); } if (role == Qt::DisplayRole) { return QString ("String %1").arg(index.row()); } else { return QVariant(); } } QVariant Pqt_patient_list_model::headerData ( int section, Qt::Orientation orientation, int role ) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) return QString("Column %1").arg(section); else return QString("Row %1").arg(section); } pqt_patient_list_model.h000066400000000000000000000015561321604176500321070ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/qt/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _pqt_patient_list_model_h_ #define _pqt_patient_list_model_h_ #include "plmqt_config.h" #include "ui_pqt_main_window.h" class Pqt_patient_list_model : public QAbstractTableModel { Q_OBJECT ; public: Pqt_patient_list_model (QObject *parent = 0) : QAbstractTableModel (parent) {} ~Pqt_patient_list_model () {} int rowCount (const QModelIndex& parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data (const QModelIndex& index, int role) const; QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/000077500000000000000000000000001321604176500271725ustar00rootroot00000000000000CMakeLists.txt000066400000000000000000000053251321604176500316600ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_reconstruct) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/plmreconstruct_config.h.in ${CMAKE_BINARY_DIR}/plmreconstruct_config.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) if (CUDA_FOUND) add_subdirectory (cuda) include_directories (BEFORE "${CMAKE_CURRENT_SOURCE_DIR}/cuda") endif () ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (PLMRECONSTRUCT_LIBRARY_SRC bowtie_correction.cxx drr.cxx drr_trilin.cxx fdk.cxx fdk_util.cxx ) if (OPENCL_FOUND) set (PLMRECONSTRUCT_LIBRARY_SRC ${PLMRECONSTRUCT_LIBRARY_SRC} drr_opencl.cxx fdk_opencl.cxx ) endif () ##----------------------------------------------------------------------------- ## LIBRARY DEPENDENCIES ##----------------------------------------------------------------------------- set (PLMRECONSTRUCT_LIBRARY_DEPENDENCIES plmutil plmbase plmsys ) if (CUDA_FOUND) set (PLMRECONSTRUCT_LIBRARY_DEPENDENCIES ${PLMRECONSTRUCT_LIBRARY_DEPENDENCIES} plmcuda ) set (PLMRECONSTRUCT_LIBRARY_DEPENDENCIES ${PLMRECONSTRUCT_LIBRARY_DEPENDENCIES} plmreconstructcuda ) endif () if (OPENCL_FOUND) set (PLMRECONSTRUCT_LIBRARY_DEPENDENCIES ${PLMRECONSTRUCT_LIBRARY_DEPENDENCIES} plmopencl ) endif () ##----------------------------------------------------------------------------- ## SPECIAL BUILD RULES: OpenMP ##----------------------------------------------------------------------------- if (OPENMP_FOUND) set (PLMRECONSTRUCT_LIBRARY_LDFLAGS "${OPENMP_LDFLAGS}") set_source_files_properties (drr.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) set_source_files_properties (fdk.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) endif () ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- plm_add_library ( plmreconstruct "${PLMRECONSTRUCT_LIBRARY_SRC}" "${PLMRECONSTRUCT_LIBRARY_DEPENDENCIES}" "${PLMRECONSTRUCT_LIBRARY_LDFLAGS}" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "") if (CUDA_FOUND) # if (PLM_USE_GPU_PLUGINS) # because plmreconstructcuda is dynamically loaded (not linked) # CMake needs to be told explicitly that plmreconstruct # depends on it, so we tell it explicitly here add_dependencies (plmreconstruct plmreconstructcuda) # endif () endif () bowtie_correction.cxx000066400000000000000000000136541321604176500333700ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmreconstruct_config.h" #include #include #include #if FFTW_FOUND #include "fftw3.h" #endif #include "bowtie_correction.h" #include "fdk.h" #include "mha_io.h" #include "plm_int.h" #include "plm_math.h" #include "volume.h" #ifndef DEGTORAD static const double DEGTORAD = 3.14159265 / 180.0; #endif #if FFTW_FOUND static void LowPass (int n, double * v) { int i; fftw_complex* in, * fft, * ifft; fftw_plan fftp, ifftp; in = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * n); fft = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * n); ifft = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * n); for (i = 0; i < n; i++) { in[i][0] = v[i]; in[i][1] = 0.0; } fftp = fftw_plan_dft_1d (n, in, fft, FFTW_FORWARD, FFTW_ESTIMATE); ifftp = fftw_plan_dft_1d (n, fft, ifft, FFTW_BACKWARD, FFTW_ESTIMATE); fftw_execute (fftp); for (i = 0; i < n; i++) { double tmp = pow ((cos (i * DEGTORAD * 360 / n) + 1) / 2, 20); fft[i][0] *= tmp; fft[i][1] *= tmp; } fftw_execute (ifftp); for (i = 0; i < n; i++) v[i] = ifft[i][0] / (float) n; } static void process_norm_CBCT (Volume * norm_CBCT, Fdk_parms* parms) { plm_long ni, nj, nk; double norm_radius; double radius; int radius_r; double average; double *average_r; int *pixels_r; int pixels; float *norm; average_r = (double *) malloc (norm_CBCT->dim[0] * sizeof(double)); if (average_r == NULL) { printf ("Malloc error for *average"); exit (1); } for (ni = 0; ni < norm_CBCT->dim[0]; ni++) average_r[ni] = 0.0f; pixels_r = (int *) malloc (norm_CBCT->dim[0] * sizeof(int)); if (pixels_r == NULL) { printf ("Malloc error for *pixels_r"); exit (1); } for (ni = 0; ni < norm_CBCT->dim[0]; ni++) pixels_r[ni] = 0.0f; pixels = 0; average = 0; norm = (float *) norm_CBCT->img; if (parms->full_fan) { printf ("Processing %s\n", parms->Full_normCBCT_name); norm_radius = parms->Full_radius; } else { printf ("Processing %s\n", parms->Half_normCBCT_name); norm_radius = parms->Half_radius; } for (nj = 0; nj < norm_CBCT->dim[1]; nj++) { for (ni = 0; ni < norm_CBCT->dim[0]; ni++) { float x = (float) ni * norm_CBCT->spacing[0] + norm_CBCT->origin[0] - norm_CBCT->spacing[0]; float y = (float) nj * norm_CBCT->spacing[1] + norm_CBCT->origin[1] - norm_CBCT->spacing[1]; radius = sqrt (x * x + y * y); radius_r = (int)(radius / norm_CBCT->spacing[0] + 0.5); for (nk = 0; nk < norm_CBCT->dim[2]; nk++) { if (radius > norm_radius - 20 && radius < norm_radius) { plm_long pi = volume_index (norm_CBCT->dim, ni, nj, nk); average += norm[pi]; pixels++; } average_r[radius_r] += norm[volume_index (norm_CBCT->dim, ni, nj, nk)]; pixels_r[radius_r]++; } } } average /= (float) pixels; printf ("average(radius %d-%d mm)=%f\n", (int) norm_radius - 20, (int) norm_radius, average); for (ni = 0; ni < norm_CBCT->dim[0]; ni++) average_r[ni] /= pixels_r[ni]; for (ni = 0; ni <= 2; ni++) average_r[ni] = average_r[3]; LowPass (140, average_r); for (nj = 0; nj < norm_CBCT->dim[1]; nj++) { for (ni = 0; ni < norm_CBCT->dim[0]; ni++) { float x = (float) ni * norm_CBCT->spacing[0] + norm_CBCT->origin[0] - norm_CBCT->spacing[0]; float y = (float) nj * norm_CBCT->spacing[1] + norm_CBCT->origin[1] - norm_CBCT->spacing[1]; radius = sqrt (x * x + y * y); radius_r = (int)(radius / norm_CBCT->spacing[0] + 0.5); for (nk = 0; nk < norm_CBCT->dim[2]; nk++) { if (radius > norm_radius) norm[volume_index (norm_CBCT->dim, ni, nj, nk)] = 0.0f; else{ norm[volume_index (norm_CBCT->dim, ni, nj, nk)] = average - average_r[radius_r]; } } } } printf ("The norm mha is processed\n"); free (average_r); free (pixels_r); } #endif /* FFTW_FOUND */ void bowtie_correction (Volume *vol, Fdk_parms *parms) { Volume *norm_CBCT; float *img, *norm; plm_long ni, nj, nk; plm_long i, j, k; if (parms->full_fan) { norm_CBCT = read_mha (parms->Full_normCBCT_name); } else { norm_CBCT = read_mha (parms->Half_normCBCT_name); } #if FFTW_FOUND process_norm_CBCT (norm_CBCT, parms); #endif img = (float *) vol->img; norm = (float *) norm_CBCT->img; for (k = 0; k < vol->dim[2]; k++) { nk = (int) floor ((k * vol->spacing[2] + vol->origin[2] - vol->spacing[2] - (norm_CBCT->origin[2] - norm_CBCT->spacing[2])) / norm_CBCT->spacing[2]); if ((nk < 0) || (nk >= norm_CBCT->dim[2])) continue; for (j = 0; j < vol->dim[1]; j++) { nj = (int) floor ((j * vol->spacing[1] + vol->origin[1] - vol->spacing[1] - (norm_CBCT->origin[1] - norm_CBCT->spacing[1])) / norm_CBCT->spacing[1]); if ((nj < 0) || (nj >= norm_CBCT->dim[1])) continue; for (i = 0; i < vol->dim[0]; i++) { ni = (int) floor ((i * vol->spacing[0] + vol->origin[0] - vol->spacing[0] - (norm_CBCT->origin[0] - norm_CBCT->spacing[0])) / norm_CBCT->spacing[0]); if ((ni < 0) || (ni >= norm_CBCT->dim[0])) continue; img[volume_index (vol->dim, i, j, k)] += norm[volume_index (norm_CBCT->dim, ni, nj, nk)]; } } } free (norm_CBCT->img); free (norm_CBCT); } bowtie_correction.h000066400000000000000000000006731321604176500330120ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bowtie_correction_h_ #define _bowtie_correction_h_ #include "plmreconstruct_config.h" class Fdk_parms; class Volume; PLMRECONSTRUCT_C_API void bowtie_correction (Volume *vol, Fdk_parms *parms); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/cuda/000077500000000000000000000000001321604176500301065ustar00rootroot00000000000000CMakeLists.txt000066400000000000000000000055061321604176500325750ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/cuda##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_reconstruct_cuda) set_directory_properties (PROPERTIES INCLUDE_DIRECTORIES "") set_directory_properties (PROPERTIES COMPILE_DEFINITIONS "") include_directories (BEFORE ${CMAKE_BINARY_DIR}) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/base) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/cuda) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/reconstruct) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/sys) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/util) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (AFTER ${DLIB_INCLUDE_DIR}) include_directories (AFTER ${MSINTTYPES_INCLUDE_DIR}) set (PLMRECONSTRUCT_CUDA_SRC drr_cuda.cu fdk_cuda.cu ) set (PLMRECONSTRUCT_CUDA_IFACE_SRC drr_cuda.cpp fdk_cuda.cpp ) set (PLMRECONSTRUCTCUDA_LIBRARY_SRC ${PLMRECONSTRUCT_CUDA_IFACE_SRC} ${PLMRECONSTRUCT_CUDA_SRC} ) ##----------------------------------------------------------------------------- ## SPECIAL BUILD RULES: CUDA ##----------------------------------------------------------------------------- if (CUDA_FOUND) if (PLM_USE_GPU_PLUGINS) # build CUDA as separate plmreconstructcuda shared library plm_add_gpu_plugin_library (plmreconstructcuda "${PLMRECONSTRUCTCUDA_LIBRARY_SRC}") target_link_libraries (plmreconstructcuda plmcuda ${CUDA_LIBRARIES}) # set dependencies that plmreconstruct library needs if (WIN32 AND NOT CYGWIN AND NOT MINGW) # windows needs to delayload it set (PLMRECONSTRUCT_LIBRARY_DEPENDENCIES ${PLMRECONSTRUCT_LIBRARY_DEPENDENCIES} plmreconstructcuda) set (PLMRECONSTRUCT_LIBRARY_LDFLAGS "${PLMRECONSTRUCT_LIBRARY_LDFLAGS} /DELAYLOAD:plmreconstructcuda.dll") endif () if (NOT WIN32 AND LIBDL_FOUND) # and unix needs dlopen() set (PLMRECONSTRUCT_LIBRARY_DEPENDENCIES ${PLMRECONSTRUCT_LIBRARY_DEPENDENCIES} -ldl) endif () else () # building CUDA into plmreconstruct cuda_compile (CUDA_WRAPPERS ${PLMRECONSTRUCT_CUDA_SRC}) # set (PLMRECONSTRUCT_LIBRARY_SRC # ${PLMRECONSTRUCT_LIBRARY_SRC} # ${PLMRECONSTRUCT_CUDA_IFACE_SRC} # ${CUDA_WRAPPERS} # ) # set (PLMRECONSTRUCT_LIBRARY_DEPENDENCIES # ${PLMRECONSTRUCT_LIBRARY_DEPENDENCIES} # ${CUDA_LIBRARIES} # ) set (PLMRECONSTRUCTCUDA_LIBRARY_SRC ${CUDA_WRAPPERS} ${PLMRECONSTRUCT_CUDA_IFACE_SRC} ) plm_add_library (plmreconstructcuda "${PLMRECONSTRUCTCUDA_LIBRARY_SRC}" "" "" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "") endif () endif () drr_cuda.cpp000066400000000000000000000013151321604176500323160ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #define PLM_CUDA_COMPILE 1 #include "plmreconstruct_config.h" #include #include #include #include #if defined (_WIN32) #include #endif #include "drr.h" #include "drr_cuda.h" void* drr_cuda_state_create ( Proj_image *proj, Volume *vol, Drr_options *options ) { return drr_cuda_state_create_cu (proj, vol, options); } void drr_cuda_state_destroy ( void *void_state ) { drr_cuda_state_destroy_cu (void_state); } drr_cuda.cu000066400000000000000000000330221321604176500321430ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmreconstruct_config.h" #include #include #include #include #include #include "cuda_util.h" #include "drr.h" #include "drr_cuda.h" #include "drr_cuda_p.h" #include "plm_cuda_math.h" #include "plm_math.h" #include "proj_image.h" #include "proj_matrix.h" #include "volume.h" #include "volume_limit.h" /****************************************************\ * Uncomment the line below to enable verbose output. * * Enabling this should not nerf performance. * \****************************************************/ #define VERBOSE 1 /**********************************************************\ * Uncomment the line below to enable detailed performance * * reporting. This measurement alters the system, however, * * resulting in significantly slower kernel execution. * \**********************************************************/ #define TIME_KERNEL #ifdef __DEVICE_EMULATION__ #define EMUSYNC __syncthreads() #else #define EMUSYNC #endif /* Textures */ //texture tex_img; //texture tex_matrix; //texture tex_vol; texture tex_vol; #define DRR_LEN_TOLERANCE 1e-6 /* From volume_limit.c */ __device__ int volume_limit_clip_segment ( float3 lower_limit, /* INPUT: The bounding box to clip to */ float3 upper_limit, /* INPUT: The bounding box to clip to */ float3 *ip1, /* OUTPUT: Intersection point 1 */ float3 *ip2, /* OUTPUT: Intersection point 2 */ float3 p1, /* INPUT: Line segment point 1 */ float3 p2 /* INPUT: Line segment point 2 */ ) { float3 ray, inv_ray; float alpha_in, alpha_out; float3 alpha_low, alpha_high; int3 ploc; int3 is_parallel; ray = p2 - p1; inv_ray = 1.0f / ray; /* Find intersection configuration of ray base */ /* -1 is POINTLOC_LEFT, 0 is POINTLOC_INSIDE, 1 is POINTLOC_RIGHT */ ploc = make_int3 (-1, -1, -1); if (p1.x > upper_limit.x) { ploc.x = 1; } else if (p1.x > lower_limit.x) { ploc.x = 0; } if (p1.y > upper_limit.y) { ploc.y = 1; } else if (p1.y > lower_limit.y) { ploc.y = 0; } if (p1.z > upper_limit.z) { ploc.z = 1; } else if (p1.z > lower_limit.z) { ploc.z = 0; } /* Check if ray parallel to grid */ is_parallel = fabsf3(ray) < DRR_LEN_TOLERANCE; /* Compute alphas for general configuration */ alpha_low = (lower_limit - p1) * inv_ray; alpha_high = (upper_limit - p1) * inv_ray; /* Check case where ray is parallel to grid. If any dimension is parallel to grid, then p1 must be inside slap, otherwise there is no intersection of segment and cube. */ if (is_parallel.x) { if (!ploc.x) return 0; alpha_low.x = - FLT_MAX; alpha_high.x = + FLT_MAX; } if (is_parallel.y) { if (!ploc.y) return 0; alpha_low.y = - FLT_MAX; alpha_high.y = + FLT_MAX; } if (is_parallel.z) { if (!ploc.z) return 0; alpha_low.z = - FLT_MAX; alpha_high.z = + FLT_MAX; } /* Sort alpha */ sortf3 (&alpha_low, &alpha_high); /* Check if alpha values overlap in all three dimensions. alpha_in is the minimum alpha, where the ray enters the volume. alpha_out is where it exits the volume. */ alpha_in = fmaxf(alpha_low.x, fmaxf (alpha_low.y, alpha_low.z)); alpha_out = fminf(alpha_high.x, fminf (alpha_high.y, alpha_high.z)); /* If exit is before entrance, the segment does not intersect the volume */ if (alpha_out - alpha_in < DRR_LEN_TOLERANCE) { return 0; } /* Compute the volume intersection points */ *ip1 = p1 + alpha_in * ray; *ip2 = p1 + alpha_out * ray; return 1; } /* From volume_limit.c */ __device__ float ray_trace_uniform ( float *dev_vol, /* Output: the rendered drr */ float3 vol_offset, /* Input: volume geometry */ int3 vol_dim, /* Input: volume resolution */ float3 vol_spacing, /* Input: volume voxel spacing */ float3 ip1, /* Input: intersection point 1 */ float3 ip2 /* Input: intersection point 2 */ ) { float3 ray = normalize (ip2 - ip1); float step_length = 0.1f; float3 inv_spacing = 1.0f / vol_spacing; float acc = 0.0f; int step; #define MAX_STEPS 10000 for (step = 0; step < MAX_STEPS; step++) { float3 ipx; int3 ai; int idx; /* Find 3-D location for this sample */ ipx = ip1 + step * step_length * ray; /* Find 3D index of sample within 3D volume */ ai = make_int3 (floorf3 (((ipx - vol_offset) + 0.5 * vol_spacing) * inv_spacing)); /* Find linear index within 3D volume */ idx = ((ai.z * vol_dim.y + ai.y) * vol_dim.x) + ai.x; if (ai.x >= 0 && ai.y >= 0 && ai.z >= 0 && ai.x < vol_dim.x && ai.y < vol_dim.y && ai.z < vol_dim.z) { acc += step_length * tex1Dfetch (tex_vol, idx); } } return acc; } /* Main DRR function */ __global__ void kernel_drr ( float *dev_img, /* Output: the rendered drr */ int2 img_dim, /* Input: size of output image */ float *dev_vol, /* Input: the input volume */ float2 ic, /* Input: image center */ float3 nrm, /* Input: normal vector */ float sad, /* Input: source-axis distance */ float scale, /* Input: user defined scale */ float3 p1, /* Input: 3-D loc, source */ float3 ul_room, /* Input: 3-D loc, upper-left pixel of panel */ float3 incr_r, /* Input: 3-D distance between pixels in row */ float3 incr_c, /* Input: 3-D distance between pixels in col */ int4 image_window, /* Input: sub-window of image to render */ float3 lower_limit, /* Input: lower bounding box of volume */ float3 upper_limit, /* Input: upper bounding box of volume */ float3 vol_offset, /* Input: volume geometry */ int3 vol_dim, /* Input: volume resolution */ float3 vol_spacing /* Input: volume voxel spacing */ ) { extern __shared__ float sdata[]; float3 p2; float3 ip1, ip2; int r, c; float outval; float3 r_tgt, tmp; /* Get coordinates of this image pixel */ c = blockIdx.x * blockDim.x + threadIdx.x; r = blockIdx.y * blockDim.y + threadIdx.y; /* Compute ray */ r_tgt = ul_room; tmp = r * incr_r; r_tgt = r_tgt + tmp; tmp = c * incr_c; p2 = r_tgt + tmp; /* Compute output location */ //cols = image_window.w - image_window.z + 1; //idx = (c - image_window.z) + (r - image_window.x) * cols; /* Clip ray to volume */ if (volume_limit_clip_segment (lower_limit, upper_limit, &ip1, &ip2, p1, p2) == 0) { outval = 0.0f; } else { outval = ray_trace_uniform (dev_vol, vol_offset, vol_dim, vol_spacing, ip1, ip2); } /* Write output pixel value */ if (r < img_dim.y && c < img_dim.x) { /* Translate from mm voxels to cm*gm */ outval = 0.1 * outval; /* Add to image */ dev_img[r*img_dim.x + c] = scale * outval; } } void* drr_cuda_state_create_cu ( Proj_image *proj, Volume *vol, Drr_options *options ) { Drr_cuda_state *state; Drr_kernel_args *kargs; state = (Drr_cuda_state *) malloc (sizeof(Drr_cuda_state)); memset (state, 0, sizeof(Drr_cuda_state)); state->kargs = kargs = (Drr_kernel_args*) malloc (sizeof(Drr_kernel_args)); //cudaMalloc ((void**) &state->dev_matrix, 12 * sizeof(float)); cudaMalloc ((void**) &state->dev_kargs, sizeof(Drr_kernel_args)); kargs->vol_origin = make_float3 (vol->origin); kargs->vol_dim = make_int3 (vol->dim); kargs->vol_spacing = make_float3 (vol->spacing); #if defined (commentout) /* The below code is Junan's. Presumably this way can be better for using hardware linear interpolation, but for now I'm going to follow Tony's method. */ // prepare texture cudaChannelFormatDesc ca_descriptor; cudaExtent ca_extent; cudaArray *dev_3Dvol=0; ca_descriptor = cudaCreateChannelDesc(); ca_extent.width = vol->dim[0]; ca_extent.height = vol->dim[1]; ca_extent.depth = vol->dim[2]; cudaMalloc3DArray (&dev_3Dvol, &ca_descriptor, ca_extent); cudaBindTextureToArray (tex_3Dvol, dev_3Dvol, ca_descriptor); cudaMemcpy3DParms cpy_params = {0}; cpy_params.extent = ca_extent; cpy_params.kind = cudaMemcpyHostToDevice; cpy_params.dstArray = dev_3Dvol; //http://sites.google.com/site/cudaiap2009/cookbook-1#TOC-CUDA-3D-Texture-Example-Gerald-Dall // The pitched pointer is really tricky to get right. We give the // pitch of a row, then the number of elements in a row, then the // height, and we omit the 3rd dimension. cpy_params.srcPtr = make_cudaPitchedPtr ((void*)vol->img, ca_extent.width * sizeof(float), ca_extent.width , ca_extent.height); cudaMemcpy3D (&cpy_params); #endif cudaMalloc ((void**) &state->dev_vol, vol->npix * sizeof (float)); CUDA_check_error ("Failed to allocate dev_vol."); cudaMemcpy (state->dev_vol, vol->img, vol->npix * sizeof (float), cudaMemcpyHostToDevice); CUDA_check_error ("Failed to memcpy dev_vol host to device."); cudaBindTexture (0, tex_vol, state->dev_vol, vol->npix * sizeof (float)); CUDA_check_error ("Failed to bind state->dev_vol to texture."); cudaMalloc ((void**) &state->dev_img, options->image_resolution[0] * options->image_resolution[1] * sizeof(float)); CUDA_check_error ("Failed to allocate dev_img.\n"); return (void*) state; } void drr_cuda_state_destroy_cu ( void *void_state ) { Drr_cuda_state *state = (Drr_cuda_state*) void_state; cudaUnbindTexture (tex_vol); cudaFree (state->dev_vol); cudaFree (state->dev_img); cudaFree (state->dev_kargs); //cudaFree (state->dev_matrix); free (state->kargs); } void drr_cuda_ray_trace_image ( Proj_image *proj, Volume *vol, Volume_limit *vol_limit, double p1[3], double ul_room[3], double incr_r[3], double incr_c[3], void *dev_state, Drr_options *options ) { // CUDA device pointers Drr_cuda_state *state = (Drr_cuda_state*) dev_state; Drr_kernel_args *kargs = state->kargs; // Start the timer //plm_timer_start (&timer); // Load dynamic kernel arguments (different for each projection) kargs->img_dim.x = proj->dim[0]; kargs->img_dim.y = proj->dim[1]; kargs->ic.x = proj->pmat->ic[0]; kargs->ic.y = proj->pmat->ic[1]; kargs->nrm.x = proj->pmat->nrm[0]; kargs->nrm.y = proj->pmat->nrm[1]; kargs->nrm.z = proj->pmat->nrm[2]; kargs->sad = proj->pmat->sad; kargs->sid = proj->pmat->sid; //for (i = 0; i < 12; i++) { //kargs->matrix[i] = (float) proj->pmat->matrix[i]; //} kargs->p1.x = p1[0]; kargs->p1.y = p1[1]; kargs->p1.z = p1[2]; kargs->ul_room.x = ul_room[0]; kargs->ul_room.y = ul_room[1]; kargs->ul_room.z = ul_room[2]; kargs->incr_r = make_float3 (incr_r); kargs->incr_c = make_float3 (incr_c); kargs->image_window = make_int4 (options->image_window); kargs->lower_limit = make_float3 (vol_limit->lower_limit); kargs->upper_limit = make_float3 (vol_limit->upper_limit); kargs->scale = options->scale; //cudaMemcpy (state->dev_matrix, kargs->matrix, sizeof(kargs->matrix), //cudaMemcpyHostToDevice); //cudaBindTexture (0, tex_matrix, state->dev_matrix, sizeof(kargs->matrix)); // Thread Block Dimensions int tBlock_x = 16; int tBlock_y = 16; // Each element in the image gets 1 thread int blocksInX = (proj->dim[0]+tBlock_x-1)/tBlock_x; int blocksInY = (proj->dim[1]+tBlock_y-1)/tBlock_y; dim3 dimGrid = dim3(blocksInX, blocksInY); dim3 dimBlock = dim3(tBlock_x, tBlock_y); //int smemSize = vol->dim[0] * sizeof(float); //printf ("Preprocessing time: %f secs\n", plm_timer_report (&timer)); //plm_timer_start (&timer); // Invoke ze kernel \(^_^)/ kernel_drr<<< dimGrid, dimBlock >>> ( state->dev_img, kargs->img_dim, state->dev_vol, kargs->ic, kargs->nrm, kargs->sad, kargs->scale, kargs->p1, kargs->ul_room, kargs->incr_r, kargs->incr_c, kargs->image_window, kargs->lower_limit, kargs->upper_limit, kargs->vol_origin, kargs->vol_dim, kargs->vol_spacing); CUDA_check_error ("Kernel Panic!"); #if defined (TIME_KERNEL) // CUDA kernel calls are asynchronous... // In order to accurately time the kernel // execution time we need to set a thread // barrier here after its execution. cudaThreadSynchronize(); #endif //cudaThreadSynchronize(); //printf ("Kernel time: %f secs\n", plm_timer_report (&timer)); // Copy reconstructed volume from device to host cudaMemcpy (proj->img, state->dev_img, proj->dim[0] * proj->dim[1] * sizeof(float), cudaMemcpyDeviceToHost); CUDA_check_error("Error: Unable to retrieve data volume."); } drr_cuda.h000066400000000000000000000022071321604176500317640ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _drr_cuda_h_ #define _drr_cuda_h_ #include "plmreconstruct_config.h" #include "delayload.h" class Drr_options; class Proj_image; class Volume; class Volume_limit; #if defined __cplusplus extern "C" { #endif PLMRECONSTRUCTCUDA_API DELAYLOAD_WRAP ( void* drr_cuda_state_create, Proj_image *proj, Volume *vol, Drr_options *options ); PLMRECONSTRUCTCUDA_API DELAYLOAD_WRAP ( void drr_cuda_state_destroy, void *void_state ); void* drr_cuda_state_create_cu ( Proj_image *proj, Volume *vol, Drr_options *options ); void drr_cuda_state_destroy_cu ( void *void_state ); PLMRECONSTRUCTCUDA_API DELAYLOAD_WRAP ( void drr_cuda_ray_trace_image, Proj_image *proj, Volume *vol, Volume_limit *vol_limit, double p1[3], double ul_room[3], double incr_r[3], double incr_c[3], void *dev_state, Drr_options *options ); #if defined __cplusplus } #endif #endif drr_cuda_p.h000066400000000000000000000022551321604176500323060ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _drr_cuda_p_h_ #define _drr_cuda_p_h_ #include "drr_cuda.h" typedef struct drr_kernel_args Drr_kernel_args; struct drr_kernel_args { int2 img_dim; float2 ic; float3 nrm; float sad; float sid; float scale; float3 p1; float3 ul_room; float3 incr_r; float3 incr_c; int4 image_window; float3 lower_limit; float3 upper_limit; float3 vol_origin; int3 vol_dim; float3 vol_spacing; float matrix[12]; //char padding[4]; //for data alignment << ? //padding to 128Bytes }; typedef struct drr_cuda_state Drr_cuda_state; struct drr_cuda_state { Drr_kernel_args *kargs; // Holds kernel parameters on host Drr_kernel_args *dev_kargs; // Holds kernel parameters on device float *dev_vol; // Holds volume on device float *dev_img; // Holds image pixels on device float *dev_matrix; // Holds projection matrix on device }; #endif fdk_cuda.cpp000066400000000000000000000031211321604176500322700ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #define PLM_CUDA_COMPILE 1 #include "plmreconstruct_config.h" #include #include #include #include #if defined (_WIN32) #include #endif #include "fdk.h" #include "fdk_cuda.h" // JAS 2011.01.20 // I have changed the type of parameter "scale" from float to double. // When typed as float, parameter passing between gpuit and the plmcuda // plugin would fail and produce garbage within the function. This is // a temporary kludge/fix. We *should* be able to use parameters of type float // when communicating to the plugin. void* fdk_cuda_state_create ( Volume *vol, unsigned int image_npix, double scale, Fdk_parms *parms ) { return fdk_cuda_state_create_cu (vol, image_npix, scale, parms); } void fdk_cuda_state_destroy ( void *void_state ) { fdk_cuda_state_destroy_cu (void_state); } void fdk_cuda_queue_image ( void *dev_state, int *dim, double *ic, double *nrm, double sad, double sid, double *matrix, float *img ) { fdk_cuda_queue_image_cu (dev_state, dim, ic, nrm, sad, sid, matrix, img); } void fdk_cuda_backproject (void *dev_state) { fdk_cuda_backproject_cu (dev_state); } void fdk_cuda_fetch_volume ( void *dev_state, void *host_buf, unsigned int copy_size ) { fdk_cuda_fetch_volume_cu (dev_state, host_buf, copy_size); } fdk_cuda.cu000066400000000000000000000511731321604176500321270ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmreconstruct_config.h" #include #include #include #include #include #include "cuda_util.h" #include "fdk_cuda_p.h" #include "plm_math.h" #include "proj_image_dir.h" #include "volume.h" /****************************************************\ * Uncomment the line below to enable verbose output. * * Enabling this should not nerf performance. * \****************************************************/ //#define VERBOSE /**********************************************************\ * Uncomment the line below to enable detailed performance * * reporting. This measurement alters the system, however, * * resulting in significantly slower kernel execution. * \**********************************************************/ //#define TIME_KERNEL // P R O T O T Y P E S //////////////////////////////////////////////////// __global__ void kernel_fdk (float *dev_vol, int2 img_dim, float2 ic, float3 nrm, float sad, float scale, float3 vol_origin, int3 vol_dim, float3 vol_spacing, unsigned int Blocks_Y, float invBlocks_Y); /////////////////////////////////////////////////////////////////////////// // T E X T U R E S //////////////////////////////////////////////////////// texture tex_img; texture tex_matrix; /////////////////////////////////////////////////////////////////////////// //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ // K E R N E L S -_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_( S T A R T )_ //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ __global__ void kernel_fdk_gmem ( float *dev_vol, float *pimg, float *pmat, int2 img_dim, float2 ic, float3 nrm, float sad, float scale, float3 vol_origin, int3 vol_dim, float3 vol_spacing, unsigned int Blocks_Y, float invBlocks_Y) { // CUDA 2.0 does not allow for a 3D grid, which severely // limits the manipulation of large 3D arrays of data. The // following code is a hack to bypass this implementation // limitation. unsigned int blockIdx_z = __float2uint_rd(blockIdx.y * invBlocks_Y); unsigned int blockIdx_y = blockIdx.y - __umul24(blockIdx_z, Blocks_Y); unsigned int i = __umul24(blockIdx.x, blockDim.x) + threadIdx.x; unsigned int j = __umul24(blockIdx_y, blockDim.y) + threadIdx.y; unsigned int k = __umul24(blockIdx_z, blockDim.z) + threadIdx.z; if (i >= vol_dim.x || j >= vol_dim.y || k >= vol_dim.z) { return; } // Index row major into the volume long int vol_idx = i + ( j*(vol_dim.x) ) + ( k*(vol_dim.x)*(vol_dim.y) ); float3 vp; float3 ip; int2 ip_r; float s; float voxel_data; // origin volume coords vp.x = vol_origin.x + i * vol_spacing.x; vp.y = vol_origin.y + j * vol_spacing.y; vp.z = vol_origin.z + k * vol_spacing.z; // matrix multiply ip.x = pmat[0]*vp.x + pmat[1]*vp.y + pmat[2]*vp.z + pmat[3]; ip.y = pmat[4]*vp.x + pmat[5]*vp.y + pmat[6]*vp.z + pmat[7]; ip.z = pmat[8]*vp.x + pmat[9]*vp.y + pmat[10]*vp.z + pmat[11]; // Change coordinate systems ip.x = ic.x + ip.x / ip.z; ip.y = ic.y + ip.y / ip.z; // Get pixel from 2D image ip_r.x = __float2int_rd(ip.x); ip_r.y = __float2int_rd(ip.y); // Clip against image dimensions if (ip_r.x < 0 || ip_r.x >= img_dim.x || ip_r.y < 0 || ip_r.y >= img_dim.y) { return; } voxel_data = pimg[ip_r.x*img_dim.x + ip_r.y]; // Dot product s = nrm.x*vp.x + nrm.y*vp.y + nrm.z*vp.z; // Conebeam weighting factor s = sad - s; s = (sad * sad) / (s * s); // Place it into the volume dev_vol[vol_idx] += scale * s * voxel_data; } __global__ void kernel_fdk ( float *dev_vol, int2 img_dim, float2 ic, float3 nrm, float sad, float scale, float3 vol_origin, int3 vol_dim, float3 vol_spacing, unsigned int Blocks_Y, float invBlocks_Y ) { // CUDA 2.0 does not allow for a 3D grid, which severely // limits the manipulation of large 3D arrays of data. The // following code is a hack to bypass this implementation // limitation. unsigned int blockIdx_z = __float2uint_rd(blockIdx.y * invBlocks_Y); unsigned int blockIdx_y = blockIdx.y - __umul24(blockIdx_z, Blocks_Y); unsigned int i = __umul24(blockIdx.x, blockDim.x) + threadIdx.x; unsigned int j = __umul24(blockIdx_y, blockDim.y) + threadIdx.y; unsigned int k = __umul24(blockIdx_z, blockDim.z) + threadIdx.z; if (i >= vol_dim.x || j >= vol_dim.y || k >= vol_dim.z) { return; } // Index row major into the volume long int vol_idx = i + ( j*(vol_dim.x) ) + ( k*(vol_dim.x)*(vol_dim.y) ); float3 vp; float3 ip; float s; float voxel_data; // origin volume coords vp.x = vol_origin.x + i * vol_spacing.x; vp.y = vol_origin.y + j * vol_spacing.y; vp.z = vol_origin.z + k * vol_spacing.z; // matrix multiply ip.x = tex1Dfetch(tex_matrix, 0)*vp.x + tex1Dfetch(tex_matrix, 1)*vp.y + tex1Dfetch(tex_matrix, 2)*vp.z + tex1Dfetch(tex_matrix, 3); ip.y = tex1Dfetch(tex_matrix, 4)*vp.x + tex1Dfetch(tex_matrix, 5)*vp.y + tex1Dfetch(tex_matrix, 6)*vp.z + tex1Dfetch(tex_matrix, 7); ip.z = tex1Dfetch(tex_matrix, 8)*vp.x + tex1Dfetch(tex_matrix, 9)*vp.y + tex1Dfetch(tex_matrix, 10)*vp.z + tex1Dfetch(tex_matrix, 11); // Change coordinate systems ip.x = ic.x + ip.x / ip.z; ip.y = ic.y + ip.y / ip.z; // Get pixel from 2D image ip.x = __float2int_rd(ip.x); ip.y = __float2int_rd(ip.y); // Clip against image dimensions if (ip.x < 0 || ip.x >= img_dim.x || ip.y < 0 || ip.y >= img_dim.y) { return; } voxel_data = tex1Dfetch(tex_img, ip.y*img_dim.x + ip.x); // Dot product s = nrm.x*vp.x + nrm.y*vp.y + nrm.z*vp.z; // Conebeam weighting factor s = sad - s; s = (sad * sad) / (s * s); // Place it into the volume dev_vol[vol_idx] += scale * s * voxel_data; } //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ // K E R N E L S -_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-( E N D )-_-_ //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ /////////////////////////////////////////////////////////////////////////// // FUNCTION: CUDA_reconstruct_conebeam() ////////////////////////////////// #if defined (commentout) extern "C" int CUDA_reconstruct_conebeam ( Volume *vol, Proj_image_dir *proj_dir, Fdk_parms *parms ) { Proj_matrix *pmat; // Thread Block Dimensions int tBlock_x = 16; int tBlock_y = 4; int tBlock_z = 4; // Each element in the volume (each voxel) gets 1 thread int blocksInX = (vol->dim[0]+tBlock_x-1)/tBlock_x; int blocksInY = (vol->dim[1]+tBlock_y-1)/tBlock_y; int blocksInZ = (vol->dim[2]+tBlock_z-1)/tBlock_z; dim3 dimGrid = dim3(blocksInX, blocksInY*blocksInZ); dim3 dimBlock = dim3(tBlock_x, tBlock_y, tBlock_z); // Size of volume Malloc int vol_size_malloc = (vol->dim[0]*vol->dim[1]*vol->dim[2])*sizeof(float); // Structure for passing arugments to kernel: (See fdk_cuda.h) kernel_args_fdk *kargs; kargs = (kernel_args_fdk *) malloc(sizeof(kernel_args_fdk)); Proj_image* cbi; int num_imgs = proj_dir->num_proj_images; int i; // CUDA device pointers float *dev_vol; // Holds voxels on device float *dev_img; // Holds image pixels on device float *dev_matrix; kernel_args_fdk *dev_kargs; // Holds kernel parameters cudaMalloc( (void**)&dev_matrix, 12*sizeof(float) ); cudaMalloc( (void**)&dev_kargs, sizeof(kernel_args_fdk) ); float scale = (float) (sqrt(3.0) / (double) num_imgs); scale = scale * parms->scale; // Load static kernel arguments kargs->scale = scale; kargs->vol_origin.x = vol->origin[0]; kargs->vol_origin.y = vol->origin[1]; kargs->vol_origin.z = vol->origin[2]; kargs->vol_dim.x = vol->dim[0]; kargs->vol_dim.y = vol->dim[1]; kargs->vol_dim.z = vol->dim[2]; kargs->vol_spacing.x = vol->spacing[0]; kargs->vol_spacing.y = vol->spacing[1]; kargs->vol_spacing.z = vol->spacing[2]; ////// TIMING CODE ////////////////////// Plm_timer* timer_total = new Plm_timer; double time_total = 0; #if defined (TIME_KERNEL) Plm_timer* timer = new Plm_timer; double backproject_time = 0.0; double filter_time = 0.0; double io_time = 0.0; #endif // Start timing total execution timer_total->start (); #if defined (VERBOSE) // First, we need to allocate memory on the host device // for the 3D volume of voxels that will hold our reconstruction. printf("========================================\n"); printf("Allocating %dMB of video memory...", vol_size_malloc/1048576); #endif cudaMalloc( (void**)&dev_vol, vol_size_malloc); cudaMemset( (void *) dev_vol, 0, vol_size_malloc); CUDA_check_error("Unable to allocate data volume"); #if defined (VERBOSE) printf(" done.\n\n"); // State the kernel execution parameters printf("kernel parameters:\n dimGrid: %u, %u " "(Logical: %u, %u, %u)\n dimBlock: %u, %u, %u\n", dimGrid.x, dimGrid.y, dimGrid.x, blocksInY, blocksInZ, dimBlock.x, dimBlock.y, dimBlock.z); printf("%u voxels in volume\n", vol->npix); printf("%u projections to process\n", 1+(parms->last_img - parms->first_img) / parms->skip_img); printf("%u Total Operations\n", vol->npix * (1+(parms->last_img - parms->first_img) / parms->skip_img)); printf("========================================\n\n"); // Start working printf("Processing...\n"); #endif // This is just to retrieve the 2D image dimensions cbi = proj_image_dir_load_image (proj_dir, 0); cudaMalloc ((void**)&dev_img, cbi->dim[0]*cbi->dim[1]*sizeof(float)); proj_image_destroy (cbi); // Project each image into the volume one at a time for (i = 0; i < proj_dir->num_proj_images; i++) { // Load the current image #if defined (TIME_KERNEL) timer->start (); #endif // load the next 2D projection cbi = proj_image_dir_load_image (proj_dir, i); pmat = cbi->pmat; #if defined (TIME_KERNEL) io_time += timer->report (); #endif if (parms->filter == FDK_FILTER_TYPE_RAMP) { #if defined (TIME_KERNEL) timer->start (); #endif proj_image_filter (cbi); #if defined (TIME_KERNEL) filter_time += timer->report (); #endif } // Load dynamic kernel arguments kargs->img_dim.x = cbi->dim[0]; kargs->img_dim.y = cbi->dim[1]; kargs->ic.x = pmat->ic[0]; kargs->ic.y = pmat->ic[1]; kargs->nrm.x = pmat->nrm[0]; kargs->nrm.y = pmat->nrm[1]; kargs->nrm.z = pmat->nrm[2]; kargs->sad = pmat->sad; kargs->sid = pmat->sid; for (int j = 0; j < 12; j++) { kargs->matrix[j] = (float)pmat->matrix[j]; } // Copy image pixel data & projection matrix to device Global Memory // and then bind them to the texture hardware. cudaMemcpy (dev_img, cbi->img, cbi->dim[0]*cbi->dim[1]*sizeof(float), cudaMemcpyHostToDevice); cudaBindTexture (0, tex_img, dev_img, cbi->dim[0]*cbi->dim[1]*sizeof(float)); cudaMemcpy (dev_matrix, kargs->matrix, sizeof(kargs->matrix), cudaMemcpyHostToDevice); cudaBindTexture (0, tex_matrix, dev_matrix, sizeof(kargs->matrix)); // Free the current image proj_image_destroy ( cbi ); #if defined (VERBOSE) printf ("Executing kernel... "); #endif #if defined (TIME_KERNEL) timer->start (); #endif // Note: cbi->img AND cbi->matrix are passed via texture memory //------------------------------------- kernel_fdk <<< dimGrid, dimBlock >>> ( dev_vol, kargs->img_dim, kargs->ic, kargs->nrm, kargs->sad, kargs->scale, kargs->vol_origin, kargs->vol_dim, kargs->vol_spacing, blocksInY, 1.0f/(float)blocksInY ); CUDA_check_error("Kernel Panic!"); #if defined (TIME_KERNEL) // CUDA kernel calls are asynchronous... // In order to accurately time the kernel // execution time we need to set a thread // barrier here after its execution. cudaThreadSynchronize(); #endif #if defined (VERBOSE) printf ("done.\n"); #endif // Unbind the image and projection matrix textures cudaUnbindTexture (tex_img); cudaUnbindTexture (tex_matrix); #if defined (TIME_KERNEL) backproject_time += timer->report (); #endif } // next projection #if defined (VERBOSE) printf(" done.\n\n"); #endif // Copy reconstructed volume from device to host cudaMemcpy (vol->img, dev_vol, vol->npix * vol->pix_size, cudaMemcpyDeviceToHost); CUDA_check_error ("Error: Unable to retrieve data volume."); // Report total time time_total = timer_total->report (); printf ("========================================\n"); printf ("[Total Execution Time: %.9fs ]\n", time_total); #if defined (TIME_KERNEL) printf ("I/O time = %g\n", io_time); printf ("Filter time = %g\n", filter_time); printf ("Backprojection time = %g\n", backproject_time); #endif int num_images = 1 + (parms->last_img - parms->first_img) / parms->skip_img; printf ("[Average Projection Time: %.9fs ]\n", time_total / num_images); #if defined (TIME_KERNEL) printf ("I/O time = %g\n", io_time / num_images); printf ("Filter time = %g\n", filter_time / num_images); printf ("Backprojection time = %g\n", backproject_time / num_images); #endif printf ("========================================\n"); delete timer; delete timer_total; // Cleanup cudaFree (dev_img); cudaFree (dev_kargs); cudaFree (dev_matrix); cudaFree (dev_vol); return 0; } #endif void* fdk_cuda_state_create_cu ( Volume *vol, unsigned int image_npix, float scale, Fdk_parms *parms ) { Fdk_cuda_state *state; Fdk_cuda_kernel_args *kargs; // Thread Block Dimensions int tBlock_x = 16; int tBlock_y = 4; int tBlock_z = 4; // Each element in the volume (each voxel) gets 1 thread int blocksInX = (vol->dim[0]+tBlock_x-1)/tBlock_x; int blocksInY = (vol->dim[1]+tBlock_y-1)/tBlock_y; int blocksInZ = (vol->dim[2]+tBlock_z-1)/tBlock_z; //dim3 dimGrid = dim3(blocksInX, blocksInY*blocksInZ); //dim3 dimBlock = dim3(tBlock_x, tBlock_y, tBlock_z); int vol_size_malloc = vol->npix * sizeof(float); #if defined (VERBOSE) // First, we need to allocate memory on the host device // for the 3D volume of voxels that will hold our reconstruction. printf("========================================\n"); printf("Allocating %dMB of video memory...", vol_size_malloc/1048576); #endif /* Allocate memory */ state = (Fdk_cuda_state*) malloc (sizeof (Fdk_cuda_state)); cudaMalloc ((void**) &state->dev_matrix, 12*sizeof(float)); cudaMalloc ((void**) &state->dev_kargs, sizeof(Fdk_cuda_kernel_args)); cudaMalloc ((void**) &state->dev_vol, vol_size_malloc); cudaMemset ((void*) state->dev_vol, 0, vol_size_malloc); CUDA_check_error ("Unable to allocate memory for volume"); cudaMalloc ((void**) &state->dev_img, image_npix * sizeof(float)); CUDA_check_error ("Unable to allocate memory for projection image"); #if defined (VERBOSE) printf(" done.\n\n"); #endif /* Set grid and block size */ state->dimGrid = dim3 (blocksInX, blocksInY * blocksInZ); state->dimBlock = dim3 (tBlock_x, tBlock_y, tBlock_z); state->blocksInY = blocksInY; /* Set static kernel arguments */ kargs = &state->kargs; kargs->scale = scale; kargs->vol_origin.x = vol->origin[0]; kargs->vol_origin.y = vol->origin[1]; kargs->vol_origin.z = vol->origin[2]; kargs->vol_dim.x = vol->dim[0]; kargs->vol_dim.y = vol->dim[1]; kargs->vol_dim.z = vol->dim[2]; kargs->vol_spacing.x = vol->spacing[0]; kargs->vol_spacing.y = vol->spacing[1]; kargs->vol_spacing.z = vol->spacing[2]; #if defined (VERBOSE) // State the kernel execution parameters printf("kernel parameters:\n dimGrid: %u, %u\n dimBlock: %u, %u, %u\n", state->dimGrid.x, state->dimGrid.y, state->dimBlock.x, state->dimBlock.y, state->dimBlock.z); printf("%u voxels in volume\n", vol->npix); printf ("parms->last_img: %i\n", parms->last_img); printf("%u projections to process\n", 1+(parms->last_img - parms->first_img) / parms->skip_img); printf("%u Total Operations\n", vol->npix * (1+(parms->last_img - parms->first_img) / parms->skip_img)); printf("========================================\n\n"); #endif return (void*) state; } void fdk_cuda_state_destroy_cu ( void *dev_state ) { Fdk_cuda_state *state = (Fdk_cuda_state*) dev_state; cudaFree (state->dev_img); cudaFree (state->dev_kargs); cudaFree (state->dev_matrix); cudaFree (state->dev_vol); free (dev_state); } void fdk_cuda_queue_image_cu ( void *dev_state, int *dim, double *ic, double *nrm, double sad, double sid, double *matrix, float *img ) { Fdk_cuda_state *state = (Fdk_cuda_state*) dev_state; Fdk_cuda_kernel_args *kargs = &state->kargs; /* Set dynamic kernel arguments */ kargs->img_dim.x = dim[0]; kargs->img_dim.y = dim[1]; kargs->ic.x = ic[0]; kargs->ic.y = ic[1]; kargs->nrm.x = nrm[0]; kargs->nrm.y = nrm[1]; kargs->nrm.z = nrm[2]; kargs->sad = sad; kargs->sid = sid; for (int j = 0; j < 12; j++) { kargs->matrix[j] = (float) matrix[j]; } // Copy image pixel data & projection matrix to device Global Memory // and then bind them to the texture hardware. cudaMemcpy ( state->dev_img, img, dim[0] * dim[1] * sizeof(float), cudaMemcpyHostToDevice ); cudaBindTexture (0, tex_img, state->dev_img, dim[0] * dim[1] * sizeof(float) ); cudaMemcpy ( state->dev_matrix, kargs->matrix, sizeof(kargs->matrix), cudaMemcpyHostToDevice ); cudaBindTexture (0, tex_matrix, state->dev_matrix, sizeof(kargs->matrix) ); } void fdk_cuda_backproject_cu (void *dev_state) { Fdk_cuda_state *state = (Fdk_cuda_state*) dev_state; Fdk_cuda_kernel_args *kargs = &state->kargs; // Note: cbi->img AND cbi->matrix are passed via texture memory kernel_fdk <<< state->dimGrid, state->dimBlock >>> ( state->dev_vol, kargs->img_dim, kargs->ic, kargs->nrm, kargs->sad, kargs->scale, kargs->vol_origin, kargs->vol_dim, kargs->vol_spacing, state->blocksInY, 1.0f / (float) state->blocksInY ); CUDA_check_error ("Kernel Panic!"); #if FDK_CUDA_TIME_KERNEL // CUDA kernel calls are asynchronous... // In order to accurately time the kernel // execution time we need to set a thread // barrier here after its execution. cudaThreadSynchronize(); #endif #if defined (VERBOSE) printf ("done.\n"); #endif // Unbind the image and projection matrix textures cudaUnbindTexture (tex_img); cudaUnbindTexture (tex_matrix); } void fdk_cuda_fetch_volume_cu ( void *dev_state, void *host_buf, unsigned int copy_size ) { Fdk_cuda_state *state = (Fdk_cuda_state*) dev_state; // Copy reconstructed volume from device to host //cudaMemcpy (vol->img, dev_vol, vol->npix * vol->pix_size, cudaMemcpyDeviceToHost); cudaMemcpy (host_buf, state->dev_vol, copy_size, cudaMemcpyDeviceToHost); CUDA_check_error ("Error: Unable to retrieve data volume."); } fdk_cuda.h000066400000000000000000000034061321604176500317430ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _fdk_cuda_h_ #define _fdk_cuda_h_ #include "plmreconstruct_config.h" #include "delayload.h" class Fdk_parms; class Volume; #define FDK_CUDA_TIME_KERNEL 0 #if defined __cplusplus extern "C" { #endif // CUDA Plugin (plmcuda) interfaces //////////// PLMRECONSTRUCTCUDA_API DELAYLOAD_WRAP ( void* fdk_cuda_state_create, Volume *vol, unsigned int image_npix, double scale, Fdk_parms *parms ); PLMRECONSTRUCTCUDA_API DELAYLOAD_WRAP ( void fdk_cuda_state_destroy, void *void_state ); PLMRECONSTRUCTCUDA_API DELAYLOAD_WRAP ( void fdk_cuda_queue_image, void *dev_state, int *dim, double *ic, double *nrm, double sad, double sid, double *matrix, float *img ); PLMRECONSTRUCTCUDA_API DELAYLOAD_WRAP ( void fdk_cuda_backproject, void *dev_state ); PLMRECONSTRUCTCUDA_API DELAYLOAD_WRAP ( void fdk_cuda_fetch_volume, void *dev_state, void *host_buf, unsigned int copy_size ); //////////////////////////////////////////////// void* fdk_cuda_state_create_cu ( Volume *vol, unsigned int image_npix, float scale, Fdk_parms *parms ); void fdk_cuda_state_destroy_cu ( void *void_state ); void fdk_cuda_queue_image_cu ( void *dev_state, int *dim, double *ic, double *nrm, double sad, double sid, double *matrix, float *img ); void fdk_cuda_backproject_cu (void *dev_state); void fdk_cuda_fetch_volume_cu ( void *dev_state, void *host_buf, unsigned int copy_size ); #if defined __cplusplus } #endif #endif fdk_cuda_p.h000066400000000000000000000023101321604176500322530ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _fdk_cuda_p_h_ #define _fdk_cuda_p_h_ #include #include "fdk_cuda.h" typedef struct kernel_args_fdk Fdk_cuda_kernel_args; struct kernel_args_fdk { int2 img_dim; float2 ic; float3 nrm; float sad; float sid; float scale; float3 vol_origin; int3 vol_dim; float3 vol_spacing; float matrix[12]; char padding[4]; //for data alignment //padding to 128Bytes }; typedef struct fdk_cuda_state Fdk_cuda_state; struct fdk_cuda_state { Fdk_cuda_kernel_args kargs; // Host kernel args Fdk_cuda_kernel_args *dev_kargs; // Device kernel args float *dev_vol; // Device volume voxels float *dev_img; // Device image pixels float *dev_matrix; // Device projection matrix dim3 dimGrid; // CUDA grid size dim3 dimBlock; // CUDA block size int blocksInY; // CUDA grid size }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/drr.cxx000066400000000000000000000232431321604176500305110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmreconstruct_config.h" #include #include #include #if (OPENMP_FOUND) #include #endif #include "delayload.h" #include "drr.h" #include "drr_cuda.h" #include "drr_opencl.h" #include "drr_trilin.h" #include "file_util.h" #include "plm_int.h" #include "plm_math.h" #include "proj_image.h" #include "proj_matrix.h" #include "print_and_exit.h" #include "ray_trace.h" #include "threading.h" #include "volume.h" #include "volume_limit.h" class Callback_data { public: Volume *vol; /* Volume being traced */ int r; /* Row of ray */ int c; /* Column of ray */ FILE *details_fp; /* Write ray trace details to this file */ double accum; /* Accumulated intensity */ int num_pix; /* Number of pixels traversed */ Hu_conversion hu_conversion; /* Should input voxels be mapped from HU to attenuation? How? */ public: Callback_data () { vol = 0; r = 0; c = 0; details_fp = 0; accum = 0.; num_pix = 0; hu_conversion = PREPROCESS_CONVERSION; } }; //#define DRR_DEBUG_CALLBACK 1 //#define DEBUG_INTENSITIES 1 /* According to NIST, the mass attenuation coefficient of H2O at 50 keV is 0.22 cm^2 per gram. Thus, we scale by 0.022 per mm http://physics.nist.gov/PhysRefData/XrayMassCoef/ComTab/water.html */ static float attenuation_lookup_hu (float pix_density) { const double min_hu = -800.0; const double mu_h2o = 0.022; if (pix_density <= min_hu) { return 0.0; } else { return (pix_density/1000.0) * mu_h2o + mu_h2o; } } static float attenuation_lookup (float pix_density) { return attenuation_lookup_hu (pix_density); } void drr_preprocess_attenuation (Volume* vol) { plm_long i; float* new_img; float* old_img; old_img = (float*) vol->img; new_img = (float*) malloc (vol->npix*sizeof(float)); for (i = 0; i < vol->npix; i++) { new_img[i] = attenuation_lookup (old_img[i]); } vol->pix_type = PT_FLOAT; free (vol->img); vol->img = new_img; } void drr_ray_trace_callback ( void *callback_data, size_t vox_index, double vox_len, float vox_value ) { Callback_data *cd = (Callback_data *) callback_data; if (cd->hu_conversion == INLINE_CONVERSION) { cd->accum += vox_len * attenuation_lookup (vox_value); } else { cd->accum += vox_len * vox_value; } #if defined (DRR_DEBUG_CALLBACK) printf ("idx: %d len: %10g dens: %10g acc: %10g\n", (int) vox_index, vox_len, vox_value, cd->accum); #endif if (cd->details_fp) { plm_long ijk[3]; COORDS_FROM_INDEX (ijk, vox_index, cd->vol->dim); fprintf (cd->details_fp, "%d,%d,%d,%d,%d,%g,%g,%g\n", cd->r, cd->c, (int) ijk[0], (int) ijk[1], (int) ijk[2], vox_len, vox_value, cd->accum); } cd->num_pix++; } double /* Return value: intensity of ray */ drr_ray_trace_exact ( Callback_data *cd, /* Input: callback data */ Volume *vol, /* Input: volume */ Volume_limit *vol_limit, /* Input: min/max coordinates of volume */ double *p1in, /* Input: start point for ray */ double *p2in /* Input: end point for ray */ ) { ray_trace_exact (vol, vol_limit, &drr_ray_trace_callback, cd, p1in, p2in); return cd->accum; } double /* Return value: intensity of ray */ drr_ray_trace_uniform ( Callback_data *cd, /* Input: callback data */ Volume *vol, /* Input: volume */ Volume_limit *vol_limit, /* Input: min/max coordinates of volume */ double *p1in, /* Input: start point for ray */ double *p2in /* Input: end point for ray */ ) { float ray_step; /* Set ray_step proportional to voxel size */ ray_step = vol->spacing[0]; if (vol->dim[1] < ray_step) ray_step = vol->spacing[1]; if (vol->dim[2] < ray_step) ray_step = vol->spacing[2]; ray_step *= 0.75; #if defined (commentout) printf ("p1 = %f %f %f\n", p1in[0], p1in[1], p1in[2]); printf ("p2 = %f %f %f\n", p2in[0], p2in[1], p2in[2]); #endif ray_trace_uniform (vol, vol_limit, &drr_ray_trace_callback, cd, p1in, p2in, ray_step); return cd->accum; } void drr_ray_trace_image ( Proj_image *proj, Volume *vol, Volume_limit *vol_limit, double p1[3], double ul_room[3], double incr_r[3], double incr_c[3], Drr_options *options ) { int r; #if defined (DRR_VERBOSE) int rows = options->image_window[1] - options->image_window[0] + 1; #endif int cols = options->image_window[3] - options->image_window[2] + 1; FILE *details_fp = 0; if (options->output_details_fn != "") { details_fp = plm_fopen (options->output_details_fn.c_str(), "w"); if (!details_fp) { print_and_exit ("Failed to open %s for write\n", options->output_details_fn.c_str()); } } /* Compute the drr pixels */ #pragma omp parallel for for (r=options->image_window[0]; r<=options->image_window[1]; r++) { int c; double r_tgt[3]; double tmp[3]; double p2[3]; //if (r % 50 == 0) printf ("Row: %4d/%d\n", r, rows); vec3_copy (r_tgt, ul_room); vec3_scale3 (tmp, incr_r, (double) r); vec3_add2 (r_tgt, tmp); for (c=options->image_window[2]; c<=options->image_window[3]; c++) { double value = 0.0; int idx = c - options->image_window[2] + (r - options->image_window[0]) * cols; #if defined (DRR_VERBOSE) printf ("Row: %4d/%d Col:%4d/%d\n", r, rows, c, cols); #endif vec3_scale3 (tmp, incr_c, (double) c); vec3_add3 (p2, r_tgt, tmp); Callback_data cd; cd.vol = vol; cd.r = r; cd.c = c; cd.details_fp = details_fp; cd.hu_conversion = options->hu_conversion; switch (options->algorithm) { case DRR_ALGORITHM_EXACT: value = drr_ray_trace_exact (&cd, vol, vol_limit, p1, p2); break; case DRR_ALGORITHM_TRILINEAR_EXACT: value = drr_trace_ray_trilin_exact (vol, p1, p2); break; case DRR_ALGORITHM_TRILINEAR_APPROX: value = drr_trace_ray_trilin_approx (vol, p1, p2); break; case DRR_ALGORITHM_UNIFORM: value = drr_ray_trace_uniform (&cd, vol, vol_limit, p1, p2); break; default: print_and_exit ("Error, unknown drr algorithm\n"); break; } value = value / 10; /* Translate from mm pixels to cm*gm */ if (options->exponential_mapping) { value = exp(-value); } value = value * options->scale; /* User requested scaling */ proj->img[idx] = (float) value; } } if (options->output_details_fn != "") { fclose (details_fp); } } void drr_render_volume_perspective ( Proj_image *proj, Volume *vol, double ps[2], void *dev_state, Drr_options *options ) { double p1[3]; double ic_room[3]; double ul_room[3]; double incr_r[3]; double incr_c[3]; double tmp[3]; Volume_limit vol_limit; double nrm[3], pdn[3], prt[3]; Proj_matrix *pmat = proj->pmat; pmat->get_nrm (nrm); pmat->get_pdn (pdn); pmat->get_prt (prt); /* Compute position of image center in room coordinates */ vec3_scale3 (tmp, nrm, - pmat->sid); vec3_add3 (ic_room, pmat->cam, tmp); /* Compute incremental change in 3d position for each change in panel row/column. */ vec3_scale3 (incr_c, prt, ps[1]); vec3_scale3 (incr_r, pdn, ps[0]); /* Get position of upper left pixel on panel */ vec3_copy (ul_room, ic_room); vec3_scale3 (tmp, incr_r, - pmat->ic[1]); vec3_add2 (ul_room, tmp); vec3_scale3 (tmp, incr_c, - pmat->ic[0]); vec3_add2 (ul_room, tmp); /* drr_ray_trace uses p1 & p2, p1 is the camera, p2 is in the direction of the ray */ vec3_copy (p1, pmat->cam); #if defined (DRR_VERBOSE) printf ("NRM: %g %g %g\n", nrm[0], nrm[1], nrm[2]); printf ("PDN: %g %g %g\n", pdn[0], pdn[1], pdn[2]); printf ("PRT: %g %g %g\n", prt[0], prt[1], prt[2]); printf ("CAM: %g %g %g\n", pmat->cam[0], pmat->cam[1], pmat->cam[2]); printf ("ICR: %g %g %g\n", ic_room[0], ic_room[1], ic_room[2]); printf ("INCR_C: %g %g %g\n", incr_c[0], incr_c[1], incr_c[2]); printf ("INCR_R: %g %g %g\n", incr_r[0], incr_r[1], incr_r[2]); printf ("UL_ROOM: %g %g %g\n", ul_room[0], ul_room[1], ul_room[2]); printf ("IMG WDW: %d %d %d %d\n", options->image_window[0], options->image_window[1], options->image_window[2], options->image_window[3]); #endif /* Compute volume boundary box */ volume_limit_set (&vol_limit, vol); /* Trace the set of rays */ switch (options->threading) { case THREADING_CUDA: { #if CUDA_FOUND LOAD_LIBRARY_SAFE (libplmreconstructcuda); LOAD_SYMBOL (drr_cuda_ray_trace_image, libplmreconstructcuda); drr_cuda_ray_trace_image (proj, vol, &vol_limit, p1, ul_room, incr_r, incr_c, dev_state, options); UNLOAD_LIBRARY (libplmreconstructcuda); break; #else /* Fall through */ #endif } #if OPENCL_FOUND case THREADING_OPENCL: drr_opencl_ray_trace_image (proj, vol, &vol_limit, p1, ul_room, incr_r, incr_c, dev_state, options); break; #else /* Fall through */ #endif case THREADING_CPU_SINGLE: case THREADING_CPU_OPENMP: drr_ray_trace_image (proj, vol, &vol_limit, p1, ul_room, incr_r, incr_c, options); break; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/drr.h000066400000000000000000000052471321604176500301420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _drr_h_ #define _drr_h_ #include "plmreconstruct_config.h" #include #include "plm_math.h" #include "threading.h" class Drr_options; class Proj_image; class Volume; #define OUTPUT_FORMAT_PFM 0 #define OUTPUT_FORMAT_PGM 1 #define OUTPUT_FORMAT_RAW 2 //#define DRR_VERBOSE 1 //#define DRR_DEBUG_CALLBACK 1 //#define DRR_ULTRA_VERBOSE 1 enum drr_algorithm { DRR_ALGORITHM_EXACT, DRR_ALGORITHM_TRILINEAR_EXACT, DRR_ALGORITHM_TRILINEAR_APPROX, DRR_ALGORITHM_UNIFORM }; typedef enum drr_algorithm Drr_algorithm; enum hu_conversion_type { PREPROCESS_CONVERSION, INLINE_CONVERSION, NO_CONVERSION }; typedef enum hu_conversion_type Hu_conversion; class Drr_options { public: Threading threading; int image_resolution[2]; /* In pixels */ float image_size[2]; /* In mm */ int have_image_center; /* Was image_center spec'd in options? */ float image_center[2]; /* In pixels */ int have_image_window; /* Was image_window spec'd in options? */ int image_window[4]; /* In pixels */ float isocenter[3]; /* In mm */ float start_angle; /* Source gantry angle */ int num_angles; int have_angle_diff; /* Was angle_diff spec'd in options? */ float angle_diff; /* In degrees */ int have_nrm; /* Was nrm specified? */ float nrm[3]; /* Normal vector (unitless) */ float vup[3]; /* Direction vector (unitless) */ float sad; /* In mm */ float sid; /* In mm */ float scale; int exponential_mapping; int output_format; Hu_conversion hu_conversion; Drr_algorithm algorithm; char* input_file; int geometry_only; char* output_prefix; /* The option specified by the user goes in output_details_prefix, and the individual filename for a specific angle goes in output_details_fn */ std::string output_details_prefix; std::string output_details_fn; }; PLMRECONSTRUCT_C_API void drr_render_volume_perspective ( Proj_image *proj, Volume *vol, double ps[2], void *dev_state, Drr_options *options ); PLMRECONSTRUCT_C_API void drr_preprocess_attenuation (Volume* vol); PLMRECONSTRUCT_C_API void preprocess_attenuation_and_drr_render_volume_cl ( Volume* vol, Drr_options* options ); #endif drr_opencl.cl000066400000000000000000000145611321604176500315710ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #define DRR_HUGE_DOUBLE 1e10 #define DRR_LEN_TOLERANCE 1e-6 #define DRR_STRIDE_TOLERANCE 1e-10 /* From volume_limit.c */ int volume_limit_clip_segment ( float4 lower_limit, /* INPUT: The bounding box to clip to */ float4 upper_limit, /* INPUT: The bounding box to clip to */ float4 *ip1, /* OUTPUT: Intersection point 1 */ float4 *ip2, /* OUTPUT: Intersection point 2 */ float4 p1, /* INPUT: Line segment point 1 */ float4 p2 /* INPUT: Line segment point 2 */ ) { float4 ray, inv_ray; float alpha_in, alpha_out; float4 alpha_low, alpha_high; int4 ploc = {-1, -1, -1, 0}; int4 is_parallel; ray = p2 - p1; inv_ray = 1.0f / ray; /* Find intersection configuration of ray base */ /* -1 is POINTLOC_LEFT, 0 is POINTLOC_INSIDE, 1 is POINTLOC_RIGHT */ if (p1.x > upper_limit.x) { ploc.x = 1; } else if (p1.x > lower_limit.x) { ploc.x = 0; } if (p1.y > upper_limit.y) { ploc.y = 1; } else if (p1.y > lower_limit.y) { ploc.y = 0; } if (p1.z > upper_limit.z) { ploc.z = 1; } else if (p1.z > lower_limit.z) { ploc.z = 0; } /* Check if ray parallel to grid */ is_parallel = fabs (ray) < DRR_LEN_TOLERANCE; /* Compute alphas for general configuration */ alpha_low = (lower_limit - p1) * inv_ray; alpha_high = (upper_limit - p1) * inv_ray; /* Check case where ray is parallel to grid. If any dimension is parallel to grid, then p1 must be inside slap, otherwise there is no intersection of segment and cube. */ if (is_parallel.x) { if (!ploc.x) return 0; alpha_low.x = - FLT_MAX; alpha_high.x = + FLT_MAX; } if (is_parallel.y) { if (!ploc.y) return 0; alpha_low.y = - FLT_MAX; alpha_high.y = + FLT_MAX; } if (is_parallel.z) { if (!ploc.z) return 0; alpha_low.z = - FLT_MAX; alpha_high.z = + FLT_MAX; } /* Sort alpha */ int4 mask = alpha_high > alpha_low; float4 tmp = alpha_high; alpha_high = select (alpha_low, alpha_high, mask); alpha_low = select (tmp, alpha_low, mask); /* Check if alpha values overlap in all three dimensions. alpha_in is the minimum alpha, where the ray enters the volume. alpha_out is where it exits the volume. */ alpha_in = fmax (alpha_low.x, fmax (alpha_low.y, alpha_low.z)); alpha_out = fmin (alpha_high.x, fmin (alpha_high.y, alpha_high.z)); /* If exit is before entrance, the segment does not intersect the volume */ if (alpha_out - alpha_in < DRR_LEN_TOLERANCE) { return 0; } /* Compute the volume intersection points */ *ip1 = p1 + alpha_in * ray; *ip2 = p1 + alpha_out * ray; return 1; } float ray_trace_uniform ( __global const float *dev_vol, /* Input: the input volume */ float4 vol_offset, /* Input: volume geometry */ int4 vol_dim, /* Input: volume resolution */ float4 vol_spacing, /* Input: volume voxel spacing */ float4 ip1, /* Input: intersection point 1 */ float4 ip2 /* Input: intersection point 2 */ ) { float4 ray; float step_length = 0.1f; float4 inv_spacing = 1.0f / vol_spacing; float acc = 0.0f; int step; ray = normalize (ip2 - ip1); #define MAX_STEPS 10000 for (step = 0; step < MAX_STEPS; step++) { float4 ipx; int4 ai; int idx; /* Find 3-D location for this sample */ ipx = ip1 + step * step_length * ray; /* Find 3D index of sample within 3D volume */ ai = convert_int4_sat_rtn (((ipx - vol_offset) + 0.5 * vol_spacing) * inv_spacing); /* Find linear index within 3D volume */ idx = ((ai.z * vol_dim.y + ai.y) * vol_dim.x) + ai.x; if (ai.x >= 0 && ai.y >= 0 && ai.z >= 0 && ai.x < vol_dim.x && ai.y < vol_dim.y && ai.z < vol_dim.z) { acc += step_length * dev_vol[idx]; } } return acc; } /* GCS Dec 12, 2010. A couple of points to consider when creating OpenCL kernels. OpenCL 1.0 does not support int3, float3. Maximum guaranteed support for 8 arguments in constant memory. */ __kernel void kernel_drr ( __global float *dev_img, /* Output: the rendered drr */ __global const float *dev_vol, /* Input: the input volume */ int4 vol_dim, /* Input: volume resolution */ float4 vol_offset, /* Input: volume geometry */ float4 vol_spacing, /* Input: volume voxel spacing */ int2 img_dim, /* Input: size of output image */ float2 ic, /* Input: image center */ int4 img_window, /* Input: sub-window of image to render */ float4 p1, /* Input: 3-D loc, source */ float4 ul_room, /* Input: 3-D loc, upper-left pix panel */ float4 incr_r, /* Input: 3-D dist between pixels in row */ float4 incr_c, /* Input: 3-D dist between pixels in col */ float4 nrm, /* Input: normal vector */ float4 lower_limit, /* Input: lower bounding box of volume */ float4 upper_limit, /* Input: upper bounding box of volume */ const float sad, /* Input: source-axis distance */ const float scale /* Input: user defined scale */ ) { uint id = get_global_id(0); int r = id / img_dim.x; int c = id - (r * img_dim.x); float4 p2; float4 ip1, ip2; float outval; float4 r_tgt, tmp; int rc; if (r >= img_dim.x) { return; } /* Compute ray */ r_tgt = ul_room; tmp = r * incr_r; r_tgt = r_tgt + tmp; tmp = c * incr_c; p2 = r_tgt + tmp; /* Clip ray to volume */ rc = volume_limit_clip_segment (lower_limit, upper_limit, &ip1, &ip2, p1, p2); if (rc == 0) { outval = 0.0f; } else { ip1.w = 0; ip2.w = 0; outval = ray_trace_uniform (dev_vol, vol_offset, vol_dim, vol_spacing, ip1, ip2); } /* Assign output value */ if (r < img_dim.x && c < img_dim.y) { /* Translate from mm voxels to cm*gm */ outval = 0.1 * outval; /* Add to image */ //dev_img[r*img_dim.x+c] = scale * outval; dev_img[id] = scale * outval; } } drr_opencl.cxx000066400000000000000000000134241321604176500317720ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmreconstruct_config.h" #include #include #include #include #include "drr.h" #include "drr_opencl.h" #include "drr_opencl_p.h" #include "opencl_util.h" #include "plm_math.h" #include "proj_image.h" #include "proj_matrix.h" #include "volume.h" #include "volume_limit.h" void* drr_opencl_state_create ( Proj_image *proj, Volume *vol, Drr_options *options ) { printf ("drr_opencl_state_create: 1\n"); LOAD_LIBRARY_SAFE (libplmopencl); printf ("drr_opencl_state_create: 2\n"); LOAD_SYMBOL (opencl_open_device, libplmopencl); LOAD_SYMBOL (opencl_load_programs, libplmopencl); LOAD_SYMBOL (opencl_kernel_create, libplmopencl); LOAD_SYMBOL (opencl_buf_create, libplmopencl); printf ("drr_opencl_state_create: 3\n"); Drr_opencl_state *dev_state; dev_state = (Drr_opencl_state*) malloc (sizeof (Drr_opencl_state)); printf ("drr_opencl_state_create: 4\n"); /* Set up devices and kernels */ opencl_open_device (&dev_state->ocl_dev); opencl_load_programs (&dev_state->ocl_dev, "drr_opencl.cl"); opencl_kernel_create (&dev_state->ocl_dev, "kernel_drr"); printf ("drr_opencl_state_create: 5\n"); /* Set up device memory */ dev_state->ocl_buf_img = opencl_buf_create ( &dev_state->ocl_dev, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, proj->dim[1] * proj->dim[0] * sizeof(float), 0 ); dev_state->ocl_buf_vol = opencl_buf_create ( &dev_state->ocl_dev, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, vol->pix_size * vol->npix, vol->img ); printf ("drr_opencl_state_create: 6\n"); UNLOAD_LIBRARY (libplmopencl); printf ("drr_opencl_state_create: 7\n"); return (void*) dev_state; } void drr_opencl_state_destroy (void *dev_state) { if (!dev_state) return; free (dev_state); } void drr_opencl_ray_trace_image ( Proj_image *proj, Volume *vol, Volume_limit *vol_limit, double p1[3], double ul_room[3], double incr_r[3], double incr_c[3], void *dev_state_v, Drr_options *options ) { LOAD_LIBRARY_SAFE (libplmopencl); LOAD_SYMBOL (opencl_set_kernel_args, libplmopencl); LOAD_SYMBOL (opencl_kernel_enqueue, libplmopencl); LOAD_SYMBOL (opencl_buf_read, libplmopencl); Drr_opencl_state *dev_state = (Drr_opencl_state*) dev_state_v; Proj_matrix *pmat = proj->pmat; cl_float2 ocl_ic; cl_float4 ocl_p1, ocl_ul_room, ocl_incr_r, ocl_incr_c; cl_float4 ocl_nrm, ocl_lower_limit, ocl_upper_limit; cl_float ocl_sad; cl_int4 ocl_vol_dim; /* Copy ic to device (convert from double to float) */ opencl_idx(ocl_ic,0) = proj->pmat->ic[0]; opencl_idx(ocl_ic,1) = proj->pmat->ic[1]; /* Copy p1 to device (convert from double to float) */ opencl_idx(ocl_p1,0) = p1[0]; opencl_idx(ocl_p1,1) = p1[1]; opencl_idx(ocl_p1,2) = p1[2]; /* Copy ul_room to device (convert from double to float) */ opencl_idx(ocl_ul_room,0) = ul_room[0]; opencl_idx(ocl_ul_room,1) = ul_room[1]; opencl_idx(ocl_ul_room,2) = ul_room[2]; /* Copy incr_r to device (convert from double to float) */ opencl_idx(ocl_incr_r,0) = incr_r[0]; opencl_idx(ocl_incr_r,1) = incr_r[1]; opencl_idx(ocl_incr_r,2) = incr_r[2]; /* Copy incr_c to device (convert from double to float) */ opencl_idx(ocl_incr_c,0) = incr_c[0]; opencl_idx(ocl_incr_c,1) = incr_c[1]; opencl_idx(ocl_incr_c,2) = incr_c[2]; /* Copy nrm to device (convert from double to float) */ opencl_idx(ocl_nrm,0) = pmat->nrm[0]; opencl_idx(ocl_nrm,1) = pmat->nrm[1]; opencl_idx(ocl_nrm,2) = pmat->nrm[2]; /* Copy lower_limit to device (convert from double to float) */ opencl_idx(ocl_lower_limit,0) = vol_limit->lower_limit[0]; opencl_idx(ocl_lower_limit,1) = vol_limit->lower_limit[1]; opencl_idx(ocl_lower_limit,2) = vol_limit->lower_limit[2]; /* Copy upper_limit to device (convert from double to float) */ opencl_idx(ocl_upper_limit,0) = vol_limit->upper_limit[0]; opencl_idx(ocl_upper_limit,1) = vol_limit->upper_limit[1]; opencl_idx(ocl_upper_limit,2) = vol_limit->upper_limit[2]; /* Convert sad from double to float */ ocl_sad = proj->pmat->sad; /* Copy volume dim (convert from size_t to int) */ opencl_idx(ocl_vol_dim,0) = vol->dim[0]; opencl_idx(ocl_vol_dim,1) = vol->dim[1]; opencl_idx(ocl_vol_dim,2) = vol->dim[2]; /* Set drr kernel arguments */ opencl_set_kernel_args ( &dev_state->ocl_dev, sizeof (cl_mem), &dev_state->ocl_buf_img[0], sizeof (cl_mem), &dev_state->ocl_buf_vol[0], sizeof (cl_int4), &ocl_vol_dim, sizeof (cl_float4), vol->origin, sizeof (cl_float4), vol->spacing, sizeof (cl_int2), proj->dim, sizeof (cl_float2), &ocl_ic, sizeof (cl_int4), options->image_window, sizeof (cl_float4), &ocl_p1, sizeof (cl_float4), &ocl_ul_room, sizeof (cl_float4), &ocl_incr_r, sizeof (cl_float4), &ocl_incr_c, sizeof (cl_float4), &ocl_nrm, sizeof (cl_float4), &ocl_lower_limit, sizeof (cl_float4), &ocl_upper_limit, sizeof (cl_float), &ocl_sad, sizeof (cl_float), &options->scale, (size_t) 0 ); /* Compute workgroup size */ /* (Max local_work_size for my ATI RV710 is 128) */ size_t local_work_size = 128; size_t global_work_size = (float) proj->dim[0] * proj->dim[1]; /* Invoke kernel */ opencl_kernel_enqueue (&dev_state->ocl_dev, global_work_size, local_work_size); /* Read back results */ opencl_buf_read (&dev_state->ocl_dev, dev_state->ocl_buf_img, sizeof (float) * proj->dim[0] * proj->dim[1], proj->img); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/drr_opencl.h000066400000000000000000000015451321604176500314770ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _DRR_OPENCL_H_ #define _DRR_OPENCL_H_ #include "plmreconstruct_config.h" #include "delayload.h" class Drr_options; class Proj_image; class Volume; class Volume_limit; PLMRECONSTRUCT_C_API void* drr_opencl_state_create ( Proj_image *proj, Volume *vol, Drr_options *options ); PLMRECONSTRUCT_C_API void drr_opencl_state_destroy (void *dev_state); PLMRECONSTRUCT_C_API void drr_opencl_ray_trace_image ( Proj_image *proj, Volume *vol, Volume_limit *vol_limit, double p1[3], double ul_room[3], double incr_r[3], double incr_c[3], void *dev_state, Drr_options *options ); #endif drr_opencl_p.h000066400000000000000000000014151321604176500317330ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _drr_opencl_p_h_ #define _drr_opencl_p_h_ #include "plmreconstruct_config.h" #include "opencl_util.h" typedef struct drr_opencl_state Drr_opencl_state; struct drr_opencl_state { Opencl_device ocl_dev; Opencl_buf *ocl_buf_img; Opencl_buf *ocl_buf_vol; }; struct volume_limit_f { /* upper and lower limits of volume, including tolerances */ float lower_limit[3]; float upper_limit[3]; /* dir == 0 if lower_limit corresponds to lower index */ int dir[3]; }; typedef struct volume_limit_f Volume_limit_f; #endif drr_trilin.cxx000066400000000000000000000643311321604176500320160ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmreconstruct_config.h" #include #include #include #include "drr_trilin.h" #include "plm_math.h" #define ULTRA_VERBOSE 1 //#define VERBOSE 1 #if defined (commentout) /* Output is stored in ips (ips = intersection points) */ /* This version computes 1/2 a voxel within the volume, as used for the interpolation methods */ int drr_compute_boundary_intersections_2 (double ips[2][4], Volume* vol, double* p1, double* p2) { /* Intersect ray with volume boundaries -- may not intersect in degenerate cases Boundaries are described by implicit eqn for plane: tau = [a b c d], where plane is (tau dot point) = 0 */ double ctx0[4] = {1,0,0,-(vol->xmin+vol->pix_spacing[0]/2.0)}; double ctx1[4] = {1,0,0,-(vol->xmax-vol->pix_spacing[0]/2.0)}; double cty0[4] = {0,1,0,-(vol->ymin+vol->pix_spacing[1]/2.0)}; double cty1[4] = {0,1,0,-(vol->ymax-vol->pix_spacing[1]/2.0)}; double ctz0[4] = {0,0,1,-(vol->zmin+vol->pix_spacing[2]/2.0)}; double ctz1[4] = {0,0,1,-(vol->zmax-vol->pix_spacing[2]/2.0)}; int ctx_bi[2] = {1,2}; int cty_bi[2] = {0,2}; int ctz_bi[2] = {0,1}; double ctx_bd[4] = {vol->ymin,vol->ymax,vol->zmin,vol->zmax}; double cty_bd[4] = {vol->xmin,vol->xmax,vol->zmin,vol->zmax}; double ctz_bd[4] = {vol->xmin,vol->xmax,vol->ymin,vol->ymax}; double rayh[4], p1h[4], p2h[4]; int ipidx = 0; vec3_copy (p1h, p1); p1h[3] = 1.0; vec3_copy (p2h, p2); p2h[3] = 1.0; /* rayh = p2 - p1 */ vec3_copy (rayh, p2); vec3_sub2 (rayh, p1); vec3_normalize1 (rayh); rayh[3] = 0.0; #if defined (commentout) tr = drr_boundary_intersection_test (ip, ctx0, ctx_bi, ctx_bd, rayh, p1h, p2h); if (tr>0 && ipidx < 2) vec4_copy(ips[ipidx++],ip); tr = drr_boundary_intersection_test (ip, ctx1, ctx_bi, ctx_bd, rayh, p1h, p2h); if (tr>0 && ipidx < 2) vec4_copy(ips[ipidx++],ip); tr = drr_boundary_intersection_test (ip, cty0, cty_bi, cty_bd, rayh, p1h, p2h); if (tr>0 && ipidx < 2) vec4_copy(ips[ipidx++],ip); tr = drr_boundary_intersection_test (ip, cty1, cty_bi, cty_bd, rayh, p1h, p2h); if (tr>0 && ipidx < 2) vec4_copy(ips[ipidx++],ip); tr = drr_boundary_intersection_test (ip, ctz0, ctz_bi, ctz_bd, rayh, p1h, p2h); if (tr>0 && ipidx < 2) vec4_copy(ips[ipidx++],ip); tr = drr_boundary_intersection_test (ip, ctz1, ctz_bi, ctz_bd, rayh, p1h, p2h); if (tr>0 && ipidx < 2) vec4_copy(ips[ipidx++],ip); #endif printf ("This function is unfinished"); exit (-1); /* No intersection */ if (ipidx < 2) return 0; else return 1; } void drr_trace_init_loopvars_interp (int* ai, int* aidir, double* ao, double* al, double pt, double ry, double samp) { if (ry > 0) { *aidir = 1; *ai = (int) floor((pt+DRR_TOPLANE_TOLERANCE) / samp * 2.0); *ai = (*ai + 1) / 2; *ao = samp - (pt - (2*(*ai)-1) * samp / 2.0); } else { *aidir = -1; *ai = (int) floor((pt-DRR_TOPLANE_TOLERANCE) / samp * 2.0); *ai = (*ai + 1) / 2; *ao = samp - (((2*(*ai+1))-1) * samp / 2.0 - pt); } *al = samp; if (fabs(ry) > DRR_STRIDE_TOLERANCE) { *ao = *ao / fabs(ry); *al = *al / fabs(ry); } else { *ao = DRR_HUGE_DOUBLE; *al = DRR_HUGE_DOUBLE; } } void drr_trace_init_loopvars_interp_2 (int* ai, int* aidir, double* ao, double* al, double pt, double ry, double samp) { if (ry > 0) { *aidir = 1; *ai = (int) floor((pt-(samp/2.0)+DRR_TOPLANE_TOLERANCE) / samp); *ao = samp - ((pt+(samp/2.0)) - (*ai) * samp); } else { *aidir = -1; *ai = (int) floor((pt+(samp/2.0)-DRR_TOPLANE_TOLERANCE) / samp); *ao = samp - ((*ai+1) * samp - (pt-(samp/2.0))); } *al = samp; if (fabs(ry) > DRR_STRIDE_TOLERANCE) { *ao = *ao / fabs(ry); *al = *al / fabs(ry); } else { *ao = DRR_HUGE_DOUBLE; *al = DRR_HUGE_DOUBLE; } } double interp_coefficient (double u0, double UU, double v0, double VV, double w0, double WW, int x, int y, int z) { if (x == 1) { u0 = 1.0 - u0; UU = - UU; } if (y == 1) { v0 = 1.0 - v0; VV = - VV; } if (z == 1) { w0 = 1.0 - w0; WW = - WW; } return u0*v0*w0 + (u0*v0*WW + u0*VV*w0 + UU*v0*w0) / 2.0 + (u0*VV*WW + UU*v0*WW + UU*VV*w0) / 3.0 + UU*VV*WW / 4.0; } /* GCS FIX: The last slice of voxels is wrong */ double drr_trace_ray_trilin_exact (Volume* vol, double* p1in, double* p2in) { double ips[2][4]; double *p1 = &ips[0][0], *p2 = &ips[1][0]; int ai_x, ai_y, ai_z; int aixdir, aiydir, aizdir; double ao_x, ao_y, ao_z; double ao_x0, ao_x1, ao_y0, ao_y1, ao_z0, ao_z1; double al_x, al_y, al_z; double rayh[4]; double len; double aggr_len = 0.0; double accum = 0.0; int num_pix = 0; float* img = (float*) vol->img; if (!drr_compute_boundary_intersections (ips, vol, p1in, p2in)) { return 0.0; } len = vec3_dist(p1,p2); #if defined (VERBOSE) printf ("p1i: "); vec3_print_eol (stdout,p1); printf ("p2i: "); vec3_print_eol (stdout,p2); #endif vec3_sub3 (rayh, p2, p1); vec3_normalize1 (rayh); rayh[3] = 0.0; /* We'll go from p1 to p2 */ /* Variable notation: ai_x // index of x aixdir // x indices moving up or down? ao_x // absolute length to next voxel crossing al_x // length between voxel crossings */ drr_trace_init_loopvars_interp (&ai_x, &aixdir, &ao_x, &al_x, p1[0] - vol->xmin, rayh[0], vol->pix_spacing[0]); drr_trace_init_loopvars_interp (&ai_y, &aiydir, &ao_y, &al_y, p1[1] - vol->ymin, rayh[1], vol->pix_spacing[1]); drr_trace_init_loopvars_interp (&ai_z, &aizdir, &ao_z, &al_z, p1[2] - vol->zmin, rayh[2], vol->pix_spacing[2]); do { int x1, x2, y1, y2, z1, z2; float pix111, pix112, pix121, pix122, pix211, pix212, pix221, pix222; double pix_len; if (ai_x==0) { x1 = ai_x; x2 = ai_x; } else if (ai_x == vol->dim[2]) { x1 = ai_x-1; x2 = ai_x-1; } else { x1 = ai_x-1; x2 = ai_x; } if (ai_y==0) { y1 = ai_y; y2 = ai_y; } else if (ai_y == vol->dim[2]) { y1 = ai_y-1; y2 = ai_y-1; } else { y1 = ai_y-1; y2 = ai_y; } if (ai_z==0) { z1 = ai_z; z2 = ai_z; } else if (ai_z == vol->dim[2]) { z1 = ai_z-1; z2 = ai_z-1; } else { z1 = ai_z-1; z2 = ai_z; } pix111 = img[(z1*vol->dim[1]+y1)*vol->dim[0]+x1]; pix112 = img[(z2*vol->dim[1]+y1)*vol->dim[0]+x1]; pix121 = img[(z1*vol->dim[1]+y2)*vol->dim[0]+x1]; pix122 = img[(z2*vol->dim[1]+y2)*vol->dim[0]+x1]; pix211 = img[(z1*vol->dim[1]+y1)*vol->dim[0]+x2]; pix212 = img[(z2*vol->dim[1]+y1)*vol->dim[0]+x2]; pix221 = img[(z1*vol->dim[1]+y2)*vol->dim[0]+x2]; pix222 = img[(z2*vol->dim[1]+y2)*vol->dim[0]+x2]; #if defined (ULTRA_VERBOSE) printf ("(%d %d %d) (%d %d %d) (%g,%g,%g) (%g,%g,%g)\n", ai_x,ai_y,ai_z, aixdir,aiydir,aizdir, ao_x,ao_y,ao_z, al_x,al_y,al_z); #endif if (aixdir == +1) { ao_x0 = al_x - ao_x; } else { ao_x0 = ao_x; } if (aiydir == +1) { ao_y0 = al_y - ao_y; } else { ao_y0 = ao_y; } if (aizdir == +1) { ao_z0 = al_z - ao_z; } else { ao_z0 = ao_z; } if ((ao_x < ao_y) && (ao_x < ao_z)) { pix_len = ao_x; aggr_len += ao_x; ao_y -= ao_x; ao_z -= ao_x; ao_x = al_x; ai_x += aixdir; } else if ((ao_y < ao_z)) { pix_len = ao_y; aggr_len += ao_y; ao_z -= ao_y; ao_x -= ao_y; ao_y = al_y; ai_y += aiydir; } else { pix_len = ao_z; aggr_len += ao_z; ao_x -= ao_z; ao_y -= ao_z; ao_z = al_z; ai_z += aizdir; } #if defined (commentout) if (aixdir == +1) { ao_x1 = ao_x0 + pix_len; } else { ao_x1 = ao_x0 - pix_len; } if (aiydir == +1) { ao_y1 = ao_y0 + pix_len; } else { ao_y1 = ao_y0 - pix_len; } if (aizdir == +1) { ao_z1 = ao_z0 + pix_len; } else { ao_z1 = ao_z0 - pix_len; } #endif ao_x1 = ao_x0 + aixdir * pix_len; ao_y1 = ao_y0 + aiydir * pix_len; ao_z1 = ao_z0 + aizdir * pix_len; #if defined (ULTRA_VERBOSE) printf ("AOXYZ = %g %g, %g %g, %g %g\n", ao_x0, ao_x1, ao_y0, ao_y1, ao_z0, ao_z1); #endif { double u0 = ao_x0 / al_x; double u1 = ao_x1 / al_x; double UU = (u1 - u0); double v0 = ao_y0 / al_y; double v1 = ao_y1 / al_y; double VV = (v1 - v0); double w0 = ao_z0 / al_z; double w1 = ao_z1 / al_z; double WW = (w1 - w0); #if defined (ULTRA_VERBOSE) double tmp_accum; #endif #if defined (PREPROCESS_ATTENUATION) accum += pix_len * (interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,1) * pix111 + interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,2) * pix112 + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,1) * pix121 + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,2) * pix122 + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,1) * pix211 + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,2) * pix212 + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,1) * pix221 + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,2) * pix222); #else accum += pix_len * (interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,1) * attenuation_lookup (pix111) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,2) * attenuation_lookup (pix112) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,1) * attenuation_lookup (pix121) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,2) * attenuation_lookup (pix122) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,1) * attenuation_lookup (pix211) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,2) * attenuation_lookup (pix212) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,1) * attenuation_lookup (pix221) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,2) * attenuation_lookup (pix222)); #endif #if defined (ULTRA_VERBOSE) printf ("UVW = (%g,%g,%g, * %g,%g,%g, * %g,%g,%g)\n", u0,u1,UU,v0,v1,VV,w0,w1,WW); tmp_accum = interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,1) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,2) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,1) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,2) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,1) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,2) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,1) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,2); printf ("ACCUM = %g (%g,%g,%g,%g,%g,%g,%g,%g)\n", tmp_accum, interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,1), interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,2), interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,1), interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,2), interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,1), interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,2), interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,1), interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,2)); #endif if (interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,1) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,2) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,1) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,2) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,1) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,2) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,1) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,2) < 0) { printf ("Error with interp_coefficient()\n"); } } num_pix++; } while (aggr_len+DRR_LEN_TOLERANCE < len); return accum; } double drr_trace_ray_trilin_exact_under_development (Volume* vol, double* p1in, double* p2in) { double ips[2][4]; double *p1 = &ips[0][0], *p2 = &ips[1][0]; int ai_x, ai_y, ai_z; int aixdir, aiydir, aizdir; double ao_x, ao_y, ao_z; // double ao_x0, ao_x1, ao_y0, ao_y1, ao_z0, ao_z1; double al_x, al_y, al_z; double rayh[4]; double len; double aggr_len = 0.0; double accum = 0.0; double ap_x0, ap_x1, ap_x, ap_y0, ap_y1, ap_y, ap_z0, ap_z1, ap_z; int num_pix = 0; float* img = (float*) vol->img; if (!drr_compute_boundary_intersections (ips, vol, p1in, p2in)) { return 0.0; } len = vec3_dist(p1,p2); #if defined (VERBOSE) vec_set_fmt ("%12.10g "); printf ("p1i: "); vec3_print_eol (stdout,p1); printf ("p2i: "); vec3_print_eol (stdout,p2); #endif if (!drr_compute_boundary_intersections_2 (ips, vol, p1in, p2in)) { return 0.0; } len = vec3_dist(p1,p2); #if defined (VERBOSE) printf ("p1i: "); vec3_print_eol (stdout,p1); printf ("p2i: "); vec3_print_eol (stdout,p2); #endif vec3_sub3 (rayh, p2, p1); vec3_normalize1 (rayh); rayh[3] = 0.0; /* We'll go from p1 to p2 */ /* Variable notation: ai_x // index of x aixdir // x indices moving up or down? ao_x // absolute length to next voxel crossing al_x // length between voxel crossings */ drr_trace_init_loopvars_interp_2 (&ai_x, &aixdir, &ao_x, &al_x, p1[0] - vol->xmin, rayh[0], vol->pix_spacing[0]); drr_trace_init_loopvars_interp_2 (&ai_y, &aiydir, &ao_y, &al_y, p1[1] - vol->ymin, rayh[1], vol->pix_spacing[1]); drr_trace_init_loopvars_interp_2 (&ai_z, &aizdir, &ao_z, &al_z, p1[2] - vol->zmin, rayh[2], vol->pix_spacing[2]); /* ap_x // intra-voxel position of x ap_x0 // intra-voxel position of x after a crossing */ if (aixdir == +1) { ap_x0 = 0.0; ap_x1 = 1.0; ap_x = ao_x; } else { ap_x0 = 1.0; ap_x1 = 0.0; ap_x = al_x - ao_x; } if (aiydir == +1) { ap_y0 = 0.0; ap_y1 = 1.0; ap_y = ao_y; } else { ap_y0 = 1.0; ap_y1 = 0.0; ap_y = al_y - ao_y; } if (aizdir == +1) { ap_z0 = 0.0; ap_z1 = 1.0; ap_z = ao_z; } else { ap_z0 = 1.0; ap_z1 = 0.0; ap_z = al_z - ao_z; } do { int x1, x2, y1, y2, z1, z2; float pix111, pix112, pix121, pix122, pix211, pix212, pix221, pix222; double pix_len; double ap_x_init = ap_x; double ap_y_init = ap_y; double ap_z_init = ap_z; double ap_x_end; double ap_y_end; double ap_z_end; #if defined (ULTRA_VERBOSE) printf ("(%d %d %d) (%d %d %d) (%g,%g,%g) (%g,%g,%g)\n", ai_x,ai_y,ai_z, aixdir,aiydir,aizdir, ao_x,ao_y,ao_z, al_x,al_y,al_z); #endif x1 = ai_x; x2 = ai_x + 1; y1 = ai_y; y2 = ai_y + 1; z1 = ai_z; z2 = ai_z + 1; pix111 = img[(z1*vol->dim[1]+y1)*vol->dim[0]+x1]; pix112 = img[(z2*vol->dim[1]+y1)*vol->dim[0]+x1]; pix121 = img[(z1*vol->dim[1]+y2)*vol->dim[0]+x1]; pix122 = img[(z2*vol->dim[1]+y2)*vol->dim[0]+x1]; pix211 = img[(z1*vol->dim[1]+y1)*vol->dim[0]+x2]; pix212 = img[(z2*vol->dim[1]+y1)*vol->dim[0]+x2]; pix221 = img[(z1*vol->dim[1]+y2)*vol->dim[0]+x2]; pix222 = img[(z2*vol->dim[1]+y2)*vol->dim[0]+x2]; if ((ao_x < ao_y) && (ao_x < ao_z)) { pix_len = ao_x; aggr_len += ao_x; ao_y -= ao_x; ao_z -= ao_x; ao_x = al_x; ai_x += aixdir; ap_x = ap_x0; ap_y += aiydir * ao_x / al_y; ap_z += aizdir * ao_x / al_z; ap_x_end = ap_x1; ap_y_end = ap_y; ap_z_end = ap_z; } else if ((ao_y < ao_z)) { pix_len = ao_y; aggr_len += ao_y; ao_z -= ao_y; ao_x -= ao_y; ao_y = al_y; ap_y = ap_y0; ai_y += aiydir; ap_x += aixdir * ao_y / al_x; ap_y = ap_y0; ap_z += aizdir * ao_y / al_z; ap_x_end = ap_x; ap_y_end = ap_y1; ap_z_end = ap_z; } else { pix_len = ao_z; aggr_len += ao_z; ao_x -= ao_z; ao_y -= ao_z; ao_z = al_z; ap_z = ap_z0; ai_z += aizdir; ap_x += aixdir * ao_z / al_x; ap_y += aiydir * ao_z / al_y; ap_z = ap_z0; ap_x_end = ap_x; ap_y_end = ap_y; ap_z_end = ap_z1; } #if defined (ULTRA_VERBOSE) printf ("LEN = %g AGG = %g\n", len, aggr_len); printf ("AOXYZ = %g %g, %g %g, %g %g\n", ap_x_init, ap_x_end, ap_y_init, ap_y_end, ap_z_init, ap_z_end); #endif { double u0 = ap_x_init; double UU = ap_x_end - ap_x_init; double v0 = ap_y_init; double VV = ap_y_end - ap_y_init; double w0 = ap_z_init; double WW = ap_y_end - ap_y_init; #if defined (ULTRA_VERBOSE) double tmp_accum; #endif #if defined (PREPROCESS_ATTENUATION) accum += pix_len * (interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,1) * pix111 + interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,2) * pix112 + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,1) * pix121 + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,2) * pix122 + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,1) * pix211 + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,2) * pix212 + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,1) * pix221 + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,2) * pix222); #else accum += pix_len * (interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,1) * attenuation_lookup (pix111) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,2) * attenuation_lookup (pix112) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,1) * attenuation_lookup (pix121) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,2) * attenuation_lookup (pix122) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,1) * attenuation_lookup (pix211) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,2) * attenuation_lookup (pix212) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,1) * attenuation_lookup (pix221) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,2) * attenuation_lookup (pix222)); #endif #if defined (ULTRA_VERBOSE) printf ("UVW = (%g,%g, * %g,%g * %g,%g)\n", u0,UU,v0,VV,w0,WW); tmp_accum = interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,1) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,2) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,1) + interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,2) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,1) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,2) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,1) + interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,2); printf ("ACCUM = %g (%g,%g,%g,%g,%g,%g,%g,%g)\n", tmp_accum, interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,1), interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,2), interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,1), interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,2), interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,1), interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,2), interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,1), interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,2)); if (interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,1) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,1,1,2) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,1) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,1,2,2) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,1) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,2,1,2) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,1) < 0 || interp_coefficient (u0,UU,v0,VV,w0,WW,2,2,2) < 0) { printf ("Error with interp_coefficient()\n"); } #endif } num_pix++; } while (aggr_len+DRR_LEN_TOLERANCE < len); return accum; } double approx_coefficient (double UU, double VV, double WW, int x, int y, int z) { if (x == 1) { UU = 1.0 - UU; } if (y == 1) { VV = 1.0 - VV; } if (z == 1) { WW = 1.0 - WW; } return UU * VV * WW; } double drr_trace_ray_trilin_approx (Volume* vol, double* p1in, double* p2in) { double ips[2][4]; double *p1 = &ips[0][0], *p2 = &ips[1][0]; int ai_x, ai_y, ai_z; int aixdir, aiydir, aizdir; double ao_x, ao_y, ao_z; double ao_x0, ao_x1, ao_y0, ao_y1, ao_z0, ao_z1; double al_x, al_y, al_z; double rayh[4]; double len; double aggr_len = 0.0; double accum = 0.0; int num_pix = 0; float* img = (float*) vol->img; if (!drr_compute_boundary_intersections (ips, vol, p1in, p2in)) { return 0.0; } len = vec3_dist(p1,p2); #if defined (VERBOSE) printf ("p1i: "); vec3_print_eol (stdout,p1); printf ("p2i: "); vec3_print_eol (stdout,p2); #endif vec3_sub3 (rayh, p2, p1); vec3_normalize1 (rayh); rayh[3] = 0.0; /* We'll go from p1 to p2 */ /* Variable notation: ai_x // index of x aixdir // x indices moving up or down? ao_x // absolute length to next voxel crossing al_x // length between voxel crossings */ drr_trace_init_loopvars_interp (&ai_x, &aixdir, &ao_x, &al_x, p1[0] - vol->xmin, rayh[0], vol->pix_spacing[0]); drr_trace_init_loopvars_interp (&ai_y, &aiydir, &ao_y, &al_y, p1[1] - vol->ymin, rayh[1], vol->pix_spacing[1]); drr_trace_init_loopvars_interp (&ai_z, &aizdir, &ao_z, &al_z, p1[2] - vol->zmin, rayh[2], vol->pix_spacing[2]); do { int x1, x2, y1, y2, z1, z2; float pix111, pix112, pix121, pix122, pix211, pix212, pix221, pix222; double pix_len; if (ai_x==0) { x1 = ai_x; x2 = ai_x; } else if (ai_x == vol->dim[2]) { x1 = ai_x-1; x2 = ai_x-1; } else { x1 = ai_x-1; x2 = ai_x; } if (ai_y==0) { y1 = ai_y; y2 = ai_y; } else if (ai_y == vol->dim[2]) { y1 = ai_y-1; y2 = ai_y-1; } else { y1 = ai_y-1; y2 = ai_y; } if (ai_z==0) { z1 = ai_z; z2 = ai_z; } else if (ai_z == vol->dim[2]) { z1 = ai_z-1; z2 = ai_z-1; } else { z1 = ai_z-1; z2 = ai_z; } pix111 = img[(z1*vol->dim[1]+y1)*vol->dim[0]+x1]; pix112 = img[(z2*vol->dim[1]+y1)*vol->dim[0]+x1]; pix121 = img[(z1*vol->dim[1]+y2)*vol->dim[0]+x1]; pix122 = img[(z2*vol->dim[1]+y2)*vol->dim[0]+x1]; pix211 = img[(z1*vol->dim[1]+y1)*vol->dim[0]+x2]; pix212 = img[(z2*vol->dim[1]+y1)*vol->dim[0]+x2]; pix221 = img[(z1*vol->dim[1]+y2)*vol->dim[0]+x2]; pix222 = img[(z2*vol->dim[1]+y2)*vol->dim[0]+x2]; #if defined (ULTRA_VERBOSE) printf ("(%d %d %d) (%d %d %d) (%g,%g,%g) (%g,%g,%g)\n", ai_x,ai_y,ai_z, aixdir,aiydir,aizdir, ao_x,ao_y,ao_z, al_x,al_y,al_z); #endif if (aixdir == +1) { ao_x0 = al_x - ao_x; } else { ao_x0 = ao_x; } if (aiydir == +1) { ao_y0 = al_y - ao_y; } else { ao_y0 = ao_y; } if (aizdir == +1) { ao_z0 = al_z - ao_z; } else { ao_z0 = ao_z; } if ((ao_x < ao_y) && (ao_x < ao_z)) { pix_len = ao_x; aggr_len += ao_x; ao_y -= ao_x; ao_z -= ao_x; ao_x = al_x; ai_x += aixdir; } else if ((ao_y < ao_z)) { pix_len = ao_y; aggr_len += ao_y; ao_z -= ao_y; ao_x -= ao_y; ao_y = al_y; ai_y += aiydir; } else { pix_len = ao_z; aggr_len += ao_z; ao_x -= ao_z; ao_y -= ao_z; ao_z = al_z; ai_z += aizdir; } if (aixdir == +1) { ao_x1 = ao_x0 + pix_len; } else { ao_x1 = ao_x0 - pix_len; } if (aiydir == +1) { ao_y1 = ao_y0 + pix_len; } else { ao_y1 = ao_y0 - pix_len; } if (aizdir == +1) { ao_z1 = ao_z0 + pix_len; } else { ao_z1 = ao_z0 - pix_len; } #if defined (ULTRA_VERBOSE) printf ("AOXYZ = %g %g, %g %g, %g %g\n", ao_x0, ao_x1, ao_y0, ao_y1, ao_z0, ao_z1); #endif { double u0 = ao_x0 / al_x; double u1 = ao_x1 / al_x; double UU = (u1 + u0) / 2.0; double v0 = ao_y0 / al_y; double v1 = ao_y1 / al_y; double VV = (v1 + v0) / 2.0; double w0 = ao_z0 / al_z; double w1 = ao_z1 / al_z; double WW = (w1 + w0) / 2.0; #if defined (ULTRA_VERBOSE) double tmp_accum; #endif #if defined (PREPROCESS_ATTENUATION) accum += pix_len * (approx_coefficient (UU,VV,WW,1,1,1) * pix111 + approx_coefficient (UU,VV,WW,1,1,2) * pix112 + approx_coefficient (UU,VV,WW,1,2,1) * pix121 + approx_coefficient (UU,VV,WW,1,2,2) * pix122 + approx_coefficient (UU,VV,WW,2,1,1) * pix211 + approx_coefficient (UU,VV,WW,2,1,2) * pix212 + approx_coefficient (UU,VV,WW,2,2,1) * pix221 + approx_coefficient (UU,VV,WW,2,2,2) * pix222); #else accum += pix_len * (approx_coefficient (UU,VV,WW,1,1,1) * attenuation_lookup (pix111) + approx_coefficient (UU,VV,WW,1,1,2) * attenuation_lookup (pix112) + approx_coefficient (UU,VV,WW,1,2,1) * attenuation_lookup (pix121) + approx_coefficient (UU,VV,WW,1,2,2) * attenuation_lookup (pix122) + approx_coefficient (UU,VV,WW,2,1,1) * attenuation_lookup (pix211) + approx_coefficient (UU,VV,WW,2,1,2) * attenuation_lookup (pix212) + approx_coefficient (UU,VV,WW,2,2,1) * attenuation_lookup (pix221) + approx_coefficient (UU,VV,WW,2,2,2) * attenuation_lookup (pix222)); #endif #if defined (ULTRA_VERBOSE) printf ("UVW = (%g,%g,%g, * %g,%g,%g, * %g,%g,%g)\n", u0,u1,UU,v0,v1,VV,w0,w1,WW); tmp_accum = approx_coefficient (UU,VV,WW,1,1,1) + approx_coefficient (UU,VV,WW,1,1,2) + approx_coefficient (UU,VV,WW,1,2,1) + approx_coefficient (UU,VV,WW,1,2,2) + approx_coefficient (UU,VV,WW,2,1,1) + approx_coefficient (UU,VV,WW,2,1,2) + approx_coefficient (UU,VV,WW,2,2,1) + approx_coefficient (UU,VV,WW,2,2,2); printf ("ACCUM = %g (%g,%g,%g,%g,%g,%g,%g,%g)\n", tmp_accum, approx_coefficient (UU,VV,WW,1,1,1), approx_coefficient (UU,VV,WW,1,1,2), approx_coefficient (UU,VV,WW,1,2,1), approx_coefficient (UU,VV,WW,1,2,2), approx_coefficient (UU,VV,WW,2,1,1), approx_coefficient (UU,VV,WW,2,1,2), approx_coefficient (UU,VV,WW,2,2,1), approx_coefficient (UU,VV,WW,2,2,2)); if (approx_coefficient (UU,VV,WW,1,1,1) < 0 || approx_coefficient (UU,VV,WW,1,1,2) < 0 || approx_coefficient (UU,VV,WW,1,2,1) < 0 || approx_coefficient (UU,VV,WW,1,2,2) < 0 || approx_coefficient (UU,VV,WW,2,1,1) < 0 || approx_coefficient (UU,VV,WW,2,1,2) < 0 || approx_coefficient (UU,VV,WW,2,2,1) < 0 || approx_coefficient (UU,VV,WW,2,2,2) < 0) { printf ("Error with approx_coefficient()\n"); } #endif } num_pix++; } while (aggr_len+DRR_LEN_TOLERANCE < len); return accum; } #endif double drr_trace_ray_trilin_approx (Volume* vol, double* p1in, double* p2in) { return 0.0; } double drr_trace_ray_trilin_exact (Volume* vol, double* p1in, double* p2in) { return 0.0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/drr_trilin.h000066400000000000000000000010171321604176500315120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _drr_trilin_h_ #define _drr_trilin_h_ #include "plmreconstruct_config.h" class Volume; PLMRECONSTRUCT_API double drr_trace_ray_trilin_approx (Volume* vol, double* p1in, double* p2in); PLMRECONSTRUCT_API double drr_trace_ray_trilin_exact (Volume* vol, double* p1in, double* p2in); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/fdk.cxx000077500000000000000000000456341321604176500305010ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmreconstruct_config.h" #include #include #include #include #include #if (OPENMP_FOUND) #include #endif #include "bowtie_correction.h" #include "delayload.h" #include "fdk.h" #include "fdk_cuda.h" #include "fdk_opencl.h" #include "file_util.h" #include "plm_math.h" #include "plm_timer.h" #include "proj_image.h" #include "proj_image_dir.h" #include "proj_image_filter.h" #include "proj_matrix.h" #include "volume.h" #if CUDA_FOUND void CUDA_reconstruct_conebeam ( Volume *vol, Proj_image_dir *proj_dir, Fdk_parms *parms ) { void *dev_state; Proj_matrix *pmat; Proj_image* cbi; int num_imgs; int i; float scale; Plm_timer* timer_total = new Plm_timer; double time_total = 0; #if FDK_CUDA_TIME_KERNEL Plm_timer* timer = new Plm_timer; double backproject_time = 0.0; double filter_time = 0.0; double io_time = 0.0; #endif LOAD_LIBRARY_SAFE (libplmreconstructcuda); LOAD_SYMBOL (fdk_cuda_state_create, libplmreconstructcuda); LOAD_SYMBOL (fdk_cuda_queue_image, libplmreconstructcuda); LOAD_SYMBOL (fdk_cuda_fetch_volume, libplmreconstructcuda); LOAD_SYMBOL (fdk_cuda_backproject, libplmreconstructcuda); LOAD_SYMBOL (fdk_cuda_state_destroy, libplmreconstructcuda); // Start timing total execution timer_total->start (); /* Attempt to set image scale */ num_imgs = proj_dir->num_proj_images; scale = (float) (sqrt(3.0) / (double) num_imgs); scale = scale * parms->scale; // This is just to retrieve the 2D image dimensions cbi = proj_dir->load_image (0); dev_state = fdk_cuda_state_create ( vol, cbi->dim[0]*cbi->dim[1], scale, parms ); // Free image (we will re-load it in the main loop) delete cbi; // Project each image into the volume one at a time for (i = 0; i < proj_dir->num_proj_images; i++) { #if FDK_CUDA_TIME_KERNEL timer->start (); #endif // load the next 2D projection cbi = proj_dir->load_image (i); pmat = cbi->pmat; #if FDK_CUDA_TIME_KERNEL io_time += timer->report (); #endif if (parms->filter == FDK_FILTER_TYPE_RAMP) { #if FDK_CUDA_TIME_KERNEL timer->start (); #endif proj_image_filter (cbi); #if FDK_CUDA_TIME_KERNEL filter_time += timer->report (); #endif } /* Send projection image to device */ fdk_cuda_queue_image ( dev_state, cbi->dim, pmat->ic, pmat->nrm, pmat->sad, pmat->sid, pmat->matrix, cbi->img ); /* Free the current image */ delete cbi; #if defined (VERBOSE) printf ("Executing kernel... "); #endif #if FDK_CUDA_TIME_KERNEL timer->start (); #endif /* Execute backprojection kernel */ fdk_cuda_backproject (dev_state); #if FDK_CUDA_TIME_KERNEL backproject_time += timer->report (); #endif } // next projection #if defined (VERBOSE) printf(" done.\n\n"); #endif /* Retrieve reconstructed volume from device */ fdk_cuda_fetch_volume (dev_state, vol->img, vol->npix * vol->pix_size); /* Free memory on device */ fdk_cuda_state_destroy (dev_state); UNLOAD_LIBRARY (libplmreconstructcuda); /* Report total time */ time_total = timer_total->report (); printf ("========================================\n"); printf ("[Total Execution Time: %.9fs ]\n", time_total); #if FDK_CUDA_TIME_KERNEL printf ("I/O time = %g\n", io_time); printf ("Filter time = %g\n", filter_time); printf ("Backprojection time = %g\n", backproject_time); #endif num_imgs = 1 + (parms->last_img - parms->first_img) / parms->skip_img; printf ("[Average Projection Time: %.9fs ]\n", time_total / num_imgs); #if FDK_CUDA_TIME_KERNEL printf ("I/O time = %g\n", io_time / num_images); printf ("Filter time = %g\n", filter_time / num_images); printf ("Backprojection time = %g\n", backproject_time / num_images); #endif printf ("========================================\n"); #if FDK_CUDA_TIME_KERNEL delete timer; #endif delete timer_total; } #endif /* get_pixel_value_c seems to be no faster than get_pixel_value_b, despite having two fewer compares. */ inline float get_pixel_value_c (Proj_image* cbi, double r, double c) { int rr, cc; #if defined (commentout) r += 0.5; if (r < 0) return 0.0; rr = (int) r; if (rr >= cbi->dim[1]) return 0.0; c += 0.5; if (c < 0) return 0.0; cc = (int) c; if (cc >= cbi->dim[0]) return 0.0; #endif r += 0.5; if (r < 0) return 0.0; if (r >= (double) cbi->dim[1]) return 0.0; rr = (int) r; c += 0.5; if (c < 0) return 0.0; if (c >= (double) cbi->dim[0]) return 0.0; cc = (int) c; return cbi->img[rr*cbi->dim[0] + cc]; } /* Nearest neighbor interpolation of intensity value on image */ inline float get_pixel_value_b (Proj_image* cbi, double r, double c) { int rr, cc; rr = ROUND_INT(r); if (rr < 0 || rr >= cbi->dim[1]) return 0.0; cc = ROUND_INT(c); if (cc < 0 || cc >= cbi->dim[0]) return 0.0; return cbi->img[rr*cbi->dim[0] + cc]; } /* First try at OpenMP FDK... modeled after version c */ void project_volume_onto_image_d (Volume* vol, Proj_image* cbi, float scale) { long i, j, k, p; float* img = (float*) vol->img; double *xip, *yip, *zip; double acc2[3],acc3[3]; double dw; double sad_sid_2; Proj_matrix *pmat = cbi->pmat; /* Rescale image (destructive rescaling) */ sad_sid_2 = (pmat->sad * pmat->sad) / (pmat->sid * pmat->sid); for (i = 0; i < cbi->dim[0]*cbi->dim[1]; i++) { cbi->img[i] *= sad_sid_2; // Speedup trick re: Kachelsreiss cbi->img[i] *= scale; // User scaling } xip = (double*) malloc (3*vol->dim[0]*sizeof(double)); yip = (double*) malloc (3*vol->dim[1]*sizeof(double)); zip = (double*) malloc (3*vol->dim[2]*sizeof(double)); /* Precompute partial projections here */ #pragma omp parallel for for (i = 0; i < vol->dim[0]; i++) { double x = (double) (vol->origin[0] + i * vol->spacing[0]); xip[i*3+0] = x * (pmat->matrix[0] + pmat->ic[0] * pmat->matrix[8]); xip[i*3+1] = x * (pmat->matrix[4] + pmat->ic[1] * pmat->matrix[8]); xip[i*3+2] = x * pmat->matrix[8]; } #pragma omp parallel for for (j = 0; j < vol->dim[1]; j++) { double y = (double) (vol->origin[1] + j * vol->spacing[1]); yip[j*3+0] = y * (pmat->matrix[1] + pmat->ic[0] * pmat->matrix[9]); yip[j*3+1] = y * (pmat->matrix[5] + pmat->ic[1] * pmat->matrix[9]); yip[j*3+2] = y * pmat->matrix[9]; } #pragma omp parallel for for (k = 0; k < vol->dim[2]; k++) { double z = (double) (vol->origin[2] + k * vol->spacing[2]); zip[k*3+0] = z * (pmat->matrix[2] + pmat->ic[0] * pmat->matrix[10]) + pmat->ic[0] * pmat->matrix[11] + pmat->matrix[3]; zip[k*3+1] = z * (pmat->matrix[6] + pmat->ic[1] * pmat->matrix[10]) + pmat->ic[1] * pmat->matrix[11] + pmat->matrix[7]; zip[k*3+2] = z * pmat->matrix[10] + pmat->matrix[11]; } /* Main loop */ // OpenMP attempt #1 (slower than single core version c) #pragma omp parallel for for (p = 0; p < (vol->dim[2] * vol->dim[1] * vol->dim[0]); p++) { i = p % vol->dim[0]; j = ((p - i) / vol->dim[0]) % vol->dim[1]; k = (((p - i) / vol->dim[0]) / vol->dim[1]) % vol->dim[2]; vec3_add3 (acc2, &zip[3*k], &yip[3*j]); vec3_add3 (acc3, acc2, &xip[3*i]); dw = 1 / acc3[2]; acc3[0] = acc3[0] * dw; acc3[1] = acc3[1] * dw; img[p] += dw * dw * get_pixel_value_c (cbi, acc3[0], acc3[1]); } /* // OpenMP attempt #2 (still slower than single core version c) #pragma omp parallel for private(i,j) { for (k = 0; k < vol->dim[2]; k++) { for (j = 0; j < vol->dim[1]; j++) { vec3_add3 (acc2, &zip[3*k], &yip[3*j]); for (i = 0; i < vol->dim[0]; i++) { vec3_add3 (acc3, acc2, &xip[3*i]); dw = 1 / acc3[2]; acc3[0] = acc3[0] * dw; acc3[1] = acc3[1] * dw; p = i + j*vol->dim[0] + k*vol->dim[0]*vol->dim[1]; img[p] += dw * dw * get_pixel_value_c (cbi, acc3[0], acc3[1]); } } } } */ free (xip); free (yip); free (zip); } /* This version folds ic & wip into zip, as well as using faster nearest neighbor macro. */ void project_volume_onto_image_c (Volume* vol, Proj_image* cbi, float scale) { plm_long i, j, k; float* img = (float*) vol->img; double *xip, *yip, *zip; double sad_sid_2; Proj_matrix *pmat = cbi->pmat; /* Rescale image (destructive rescaling) */ sad_sid_2 = (pmat->sad * pmat->sad) / (pmat->sid * pmat->sid); for (i = 0; i < cbi->dim[0]*cbi->dim[1]; i++) { cbi->img[i] *= sad_sid_2; // Speedup trick re: Kachelsreiss cbi->img[i] *= scale; // User scaling } xip = (double*) malloc (3*vol->dim[0]*sizeof(double)); yip = (double*) malloc (3*vol->dim[1]*sizeof(double)); zip = (double*) malloc (3*vol->dim[2]*sizeof(double)); /* Precompute partial projections here */ for (i = 0; i < vol->dim[0]; i++) { double x = (double) (vol->origin[0] + i * vol->spacing[0]); xip[i*3+0] = x * (pmat->matrix[0] + pmat->ic[0] * pmat->matrix[8]); xip[i*3+1] = x * (pmat->matrix[4] + pmat->ic[1] * pmat->matrix[8]); xip[i*3+2] = x * pmat->matrix[8]; } for (j = 0; j < vol->dim[1]; j++) { double y = (double) (vol->origin[1] + j * vol->spacing[1]); yip[j*3+0] = y * (pmat->matrix[1] + pmat->ic[0] * pmat->matrix[9]); yip[j*3+1] = y * (pmat->matrix[5] + pmat->ic[1] * pmat->matrix[9]); yip[j*3+2] = y * pmat->matrix[9]; } for (k = 0; k < vol->dim[2]; k++) { double z = (double) (vol->origin[2] + k * vol->spacing[2]); zip[k*3+0] = z * (pmat->matrix[2] + pmat->ic[0] * pmat->matrix[10]) + pmat->ic[0] * pmat->matrix[11] + pmat->matrix[3]; zip[k*3+1] = z * (pmat->matrix[6] + pmat->ic[1] * pmat->matrix[10]) + pmat->ic[1] * pmat->matrix[11] + pmat->matrix[7]; zip[k*3+2] = z * pmat->matrix[10] + pmat->matrix[11]; } /* Main loop */ #pragma omp parallel for for (k = 0; k < vol->dim[2]; k++) { plm_long p = k * vol->dim[1] * vol->dim[0]; plm_long j; for (j = 0; j < vol->dim[1]; j++) { plm_long i; double acc2[3]; vec3_add3 (acc2, &zip[3*k], &yip[3*j]); for (i = 0; i < vol->dim[0]; i++) { double dw; double acc3[3]; vec3_add3 (acc3, acc2, &xip[3*i]); dw = 1 / acc3[2]; acc3[0] = acc3[0] * dw; acc3[1] = acc3[1] * dw; img[p++] += dw * dw * get_pixel_value_c (cbi, acc3[1], acc3[0]); } } } free (xip); free (yip); free (zip); } void project_volume_onto_image_b (Volume* vol, Proj_image* cbi, float scale) { plm_long i, j, k, p; float* img = (float*) vol->img; double wip[3]; double *xip, *yip, *zip; double acc1[3],acc2[3],acc3[3]; double *x, *y, *z; double dw; double sad_sid_2; Proj_matrix *pmat = cbi->pmat; /* Rescale image (destructive rescaling) */ sad_sid_2 = (pmat->sad * pmat->sad) / (pmat->sid * pmat->sid); for (i = 0; i < cbi->dim[0]*cbi->dim[1]; i++) { cbi->img[i] *= sad_sid_2; // Speedup trick re: Kachelsreiss cbi->img[i] *= scale; // User scaling } x = (double*) malloc (vol->dim[0]*sizeof(double)); y = (double*) malloc (vol->dim[1]*sizeof(double)); z = (double*) malloc (vol->dim[2]*sizeof(double)); xip = (double*) malloc (3*vol->dim[0]*sizeof(double)); yip = (double*) malloc (3*vol->dim[1]*sizeof(double)); zip = (double*) malloc (3*vol->dim[2]*sizeof(double)); /* Precompute partial projections here */ for (i = 0; i < vol->dim[0]; i++) { x[i] = (double) (vol->origin[0] + i * vol->spacing[0]); xip[i*3+0] = x[i] * pmat->matrix[0]; xip[i*3+1] = x[i] * pmat->matrix[4]; xip[i*3+2] = x[i] * pmat->matrix[8]; x[i] *= pmat->nrm[0]; } for (j = 0; j < vol->dim[1]; j++) { y[j] = (double) (vol->origin[1] + j * vol->spacing[1]); yip[j*3+0] = y[j] * pmat->matrix[1]; yip[j*3+1] = y[j] * pmat->matrix[5]; yip[j*3+2] = y[j] * pmat->matrix[9]; y[j] *= pmat->nrm[1]; } for (k = 0; k < vol->dim[2]; k++) { z[k] = (double) (vol->origin[2] + k * vol->spacing[2]); zip[k*3+0] = z[k] * pmat->matrix[2]; zip[k*3+1] = z[k] * pmat->matrix[6]; zip[k*3+2] = z[k] * pmat->matrix[10]; z[k] *= pmat->nrm[2]; z[k] = pmat->sad - z[k]; } wip[0] = pmat->matrix[3]; wip[1] = pmat->matrix[7]; wip[2] = pmat->matrix[11]; /* Main loop */ p = 0; for (k = 0; k < vol->dim[2]; k++) { vec3_add3 (acc1, wip, &zip[3*k]); for (j = 0; j < vol->dim[1]; j++) { vec3_add3 (acc2, acc1, &yip[3*j]); for (i = 0; i < vol->dim[0]; i++) { vec3_add3 (acc3, acc2, &xip[3*i]); dw = 1 / acc3[2]; acc3[0] = pmat->ic[0] + acc3[0] * dw; acc3[1] = pmat->ic[1] + acc3[1] * dw; img[p++] += dw * dw * get_pixel_value_c (cbi, acc3[1], acc3[0]); } } } free (x); free (y); free (z); free (xip); free (yip); free (zip); } void project_volume_onto_image_a (Volume* vol, Proj_image* cbi, float scale) { plm_long i, j, k, p; float* img = (float*) vol->img; double wip[3]; double *xip, *yip, *zip; double acc1[3],acc2[3],acc3[3]; double *x, *y, *z; double s1, s, sad2; Proj_matrix *pmat = cbi->pmat; /* Rescale image (destructive rescaling) */ for (i = 0; i < cbi->dim[0]*cbi->dim[1]; i++) { cbi->img[i] *= scale; } x = (double*) malloc (vol->dim[0]*sizeof(double)); y = (double*) malloc (vol->dim[1]*sizeof(double)); z = (double*) malloc (vol->dim[2]*sizeof(double)); xip = (double*) malloc (3*vol->dim[0]*sizeof(double)); yip = (double*) malloc (3*vol->dim[1]*sizeof(double)); zip = (double*) malloc (3*vol->dim[2]*sizeof(double)); /* Precompute partial projections here */ for (i = 0; i < vol->dim[0]; i++) { x[i] = (double) (vol->origin[0] + i * vol->spacing[0]); xip[i*3+0] = x[i] * pmat->matrix[0]; xip[i*3+1] = x[i] * pmat->matrix[4]; xip[i*3+2] = x[i] * pmat->matrix[8]; x[i] *= pmat->nrm[0]; } for (j = 0; j < vol->dim[1]; j++) { y[j] = (double) (vol->origin[1] + j * vol->spacing[1]); yip[j*3+0] = y[j] * pmat->matrix[1]; yip[j*3+1] = y[j] * pmat->matrix[5]; yip[j*3+2] = y[j] * pmat->matrix[9]; y[j] *= pmat->nrm[1]; } for (k = 0; k < vol->dim[2]; k++) { z[k] = (double) (vol->origin[2] + k * vol->spacing[2]); zip[k*3+0] = z[k] * pmat->matrix[2]; zip[k*3+1] = z[k] * pmat->matrix[6]; zip[k*3+2] = z[k] * pmat->matrix[10]; z[k] *= pmat->nrm[2]; z[k] = pmat->sad - z[k]; } wip[0] = pmat->matrix[3]; wip[1] = pmat->matrix[7]; wip[2] = pmat->matrix[11]; sad2 = pmat->sad * pmat->sad; /* Main loop */ p = 0; for (k = 0; k < vol->dim[2]; k++) { vec3_add3 (acc1, wip, &zip[3*k]); s = z[k]; for (j = 0; j < vol->dim[1]; j++) { vec3_add3 (acc2, acc1, &yip[3*j]); s1 = z[k] - y[j]; for (i = 0; i < vol->dim[0]; i++) { s = s1 - x[i]; //printf ("%10.10g ", s); s = sad2 / (s * s); vec3_add3 (acc3, acc2, &xip[3*i]); //printf ("%10.10g\n", acc3[2]); acc3[0] = pmat->ic[0] + acc3[0] / acc3[2]; acc3[1] = pmat->ic[1] + acc3[1] / acc3[2]; img[p++] += s * get_pixel_value_b (cbi, acc3[1], acc3[0]); } } } free (x); free (y); free (z); free (xip); free (yip); free (zip); } /* Reference implementation is the most straightforward implementation, also it is the slowest */ void project_volume_onto_image_reference ( Volume* vol, Proj_image* cbi, float scale ) { plm_long i, j, k, p; double vp[4]; /* vp = voxel position */ float* img = (float*) vol->img; Proj_matrix *pmat = cbi->pmat; /* projection matrix 3D -> 2D in homogenous coordinates */ p = 0; vp[3] = 1.0; /* Loop k (slices), j (rows), i (cols) */ for (k = 0; k < vol->dim[2]; k++) { vp[2] = (double) (vol->origin[2] + k * vol->spacing[2]); for (j = 0; j < vol->dim[1]; j++) { vp[1] = (double) (vol->origin[1] + j * vol->spacing[1]); for (i = 0; i < vol->dim[0]; i++) { double ip[3]; /* ip = image position */ double s; /* s = projection of vp onto s axis */ vp[0] = (double) (vol->origin[0] + i * vol->spacing[0]); mat43_mult_vec4 (ip, pmat->matrix, vp); /* ip = matrix * vp */ ip[0] = pmat->ic[0] + ip[0] / ip[2]; ip[1] = pmat->ic[1] + ip[1] / ip[2]; /* Distance on cenral axis from voxel center to source */ /* pmat->nrm is normal of panel */ s = vec3_dot (pmat->nrm, vp); /* Conebeam weighting factor */ s = pmat->sad - s; s = pmat->sad * pmat->sad / (s * s); img[p++] += scale * s * get_pixel_value_b (cbi, ip[1], ip[0]); } } } } /* Main reconstruction loop - Loop over images, and backproject each image into the volume. */ void reconstruct_conebeam ( Volume* vol, Proj_image_dir *proj_dir, Fdk_parms* parms ) { int i; int num_imgs = proj_dir->num_proj_images; float scale; double filter_time = 0.0; double backproject_time = 0.0; double io_time = 0.0; Proj_image* cbi; /* cbi == cone beam image */ Plm_timer* timer = new Plm_timer; /* Arbitrary scale applied to each image */ scale = (float) (sqrt(3.f) / (double) num_imgs); scale = scale * parms->scale; for (i = 0; i < num_imgs; i++) { printf ("Processing image %d\n", i); timer->start (); cbi = proj_dir->load_image (i); io_time += timer->report (); /* Apply ramp filter */ if (parms->filter == FDK_FILTER_TYPE_RAMP) { timer->start (); proj_image_filter (cbi); filter_time += timer->report (); } // printf ("Projecting Image %d\n", i); timer->start (); switch (parms->flavor) { case '0': project_volume_onto_image_reference (vol, cbi, scale); break; case 'a': project_volume_onto_image_a (vol, cbi, scale); break; case 'b': project_volume_onto_image_b (vol, cbi, scale); break; default: case 'c': project_volume_onto_image_c (vol, cbi, scale); break; case 'd': project_volume_onto_image_d (vol, cbi, scale); break; } backproject_time += timer->report (); delete cbi; } printf ("I/O time (total) = %g\n", io_time); printf ("I/O time (per image) = %g\n", io_time / num_imgs); printf ("Filter time = %g\n", filter_time); printf ("Filter time (per image) = %g\n", filter_time / num_imgs); printf ("Backprojection time = %g\n", backproject_time); printf ("Backprojection time (per image) = %g\n", backproject_time / num_imgs); delete timer; } void fdk_do_bowtie (Volume* vol, Fdk_parms* parms) { int norm_exists; if (parms->full_fan) norm_exists = file_exists (parms->Full_normCBCT_name); else norm_exists = file_exists (parms->Half_normCBCT_name); if (norm_exists) { bowtie_correction (vol, parms); } else { printf("%s\n%s\n", parms->Full_normCBCT_name, parms->Half_normCBCT_name); printf("Skip bowtie correction because norm files do not exits\n"); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/fdk.h000066400000000000000000000023651321604176500301150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _fdk_h_ #define _fdk_h_ #include "plmreconstruct_config.h" #include "plm_int.h" #include "threading.h" class Proj_image_dir; class Volume; enum Fdk_filter_type { FDK_FILTER_TYPE_NONE, FDK_FILTER_TYPE_RAMP }; class Fdk_parms { public: Threading threading; int image_range_requested; int first_img; int skip_img; int last_img; plm_long dim[3]; float vol_size[3]; float xy_offset[2]; float scale; enum Fdk_filter_type filter; char flavor; char* input_dir; char* output_file; int full_fan; //Full_fan=1, Half_fan=0; char* Full_normCBCT_name; int Full_radius; char* Half_normCBCT_name; int Half_radius; }; PLMRECONSTRUCT_C_API void reconstruct_conebeam ( Volume* vol, Proj_image_dir *proj_dir, Fdk_parms* parms ); PLMRECONSTRUCT_C_API void CUDA_reconstruct_conebeam ( Volume *vol, Proj_image_dir *proj_dir, Fdk_parms *parms ); PLMRECONSTRUCT_C_API void fdk_do_bowtie (Volume* vol, Fdk_parms* parms); #endif fdk_cuda_wrap.cpp000066400000000000000000000000331321604176500324040ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct#include "fdk_cuda.cu.cpp" fdk_opencl.cl000066400000000000000000000376401321604176500315510ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ // Sweep through all voxel values and renormalize them to the Hounsfield (hu) scale. #if defined (commentout) __kernel void convert_to_hu_cl( __global float *img, int nvoxels ) { int p = get_global_id(0); if (p < nvoxels) img[p] = (149.70059880239520958083832335329 * img[p]) - 1000; } // Define image/texture sampling parameters const sampler_t dev_img_sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; #endif #if defined (commentout) // FDK kernel - no interpolation __kernel void kernel_fdk( __global float *dev_vol, __read_only image2d_t dev_img, __constant float *dev_matrix, __constant float4 *nrm, __constant float4 *vol_offset, __constant float4 *vol_pix_spacing, __constant int4 *vol_dim, __constant float2 *ic, __constant int2 *proj_dim, __constant float *sad, __constant float *scale, __constant int4 *ndevice, int offset ) { uint i = get_global_id(0); uint j = get_global_id(1); uint k = get_global_id(2); if (i >= (*ndevice).x || j >= (*ndevice).y || k >= (*ndevice).z) return; // Index row major into the volume long vol_idx = i + (j * (*vol_dim).x) + (k * (*vol_dim).x * (*vol_dim).y); k += offset; // Get volume value from global memory float dev_vol_value = dev_vol[vol_idx]; // Offset volume coordinates float4 vp; vp.x = (*vol_offset).x + (i * (*vol_pix_spacing).x); // Compiler should combine into 1 FMAD. vp.y = (*vol_offset).y + (j * (*vol_pix_spacing).y); // Compiler should combine into 1 FMAD. vp.z = (*vol_offset).z + (k * (*vol_pix_spacing).z); // Compiler should combine into 1 FMAD. // Matrix multiplication float4 ip; ip.x = (dev_matrix[0] * vp.x) + (dev_matrix[1] * vp.y) + (dev_matrix[2] * vp.z) + dev_matrix[3]; ip.y = (dev_matrix[4] * vp.x) + (dev_matrix[5] * vp.y) + (dev_matrix[6] * vp.z) + dev_matrix[7]; ip.z = (dev_matrix[8] * vp.x) + (dev_matrix[9] * vp.y) + (dev_matrix[10] * vp.z) + dev_matrix[11]; // Change coordinate systems ip.x = (*ic).x + ip.x / ip.z; ip.y = (*ic).y + ip.y / ip.z; // Retrieve pixel location from 2D image int2 pos; pos.y = convert_int_rtn(ip.x); pos.x = convert_int_rtn(ip.y); // Clip against image dimensions if (pos.x < 0 || pos.x >= (*proj_dim).x || pos.y < 0 || pos.y >= (*proj_dim).y) return; // Get pixel from texture memory float4 voxel_data = read_imagef(dev_img, dev_img_sampler, pos); // Dot product float s = ((*nrm).x * vp.x) + ((*nrm).y * vp.y) + ((*nrm).z * vp.z); // Conebeam weighting factor s = (*sad) - s; s = ((*sad) * (*sad)) / (s * s); // Place weighing factor into the volume dev_vol[vol_idx] = dev_vol_value + ((*scale) * s * voxel_data.x); } // FDK kernel - bilinear interopolation __kernel void kernel_fdk_bilinear( __global float *dev_vol, __read_only image2d_t dev_img, __constant float *dev_matrix, __constant float4 *nrm, __constant float4 *vol_offset, __constant float4 *vol_pix_spacing, int4 vol_dim, __constant float2 *ic, int2 proj_dim, __constant float *sad, __constant float *scale, __constant int4 *ndevice, int offset ){ uint i = get_global_id(0); uint j = get_global_id(1); uint k = get_global_id(2); if (i >= (*ndevice).x || j >= (*ndevice).y || k >= (*ndevice).z) return; // Index row major into the volume long vol_idx = i + (j * (*vol_dim).x) + (k * (*vol_dim).x * (*vol_dim).y); k += offset; // Get volume value from global memory float dev_vol_value = dev_vol[vol_idx]; // offset volume coords float4 vp; vp.x = (*vol_offset).x + (i * (*vol_pix_spacing).x); // Compiler should combine into 1 FMAD. vp.y = (*vol_offset).y + (j * (*vol_pix_spacing).y); // Compiler should combine into 1 FMAD. vp.z = (*vol_offset).z + (k * (*vol_pix_spacing).z); // Compiler should combine into 1 FMAD. // matrix multiply float4 ip; ip.x = (dev_matrix[0] * vp.x) + (dev_matrix[1] * vp.y) + (dev_matrix[2] * vp.z) + dev_matrix[3]; ip.y = (dev_matrix[4] * vp.x) + (dev_matrix[5] * vp.y) + (dev_matrix[6] * vp.z) + dev_matrix[7]; ip.z = (dev_matrix[8] * vp.x) + (dev_matrix[9] * vp.y) + (dev_matrix[10] * vp.z) + dev_matrix[11]; // Change coordinate systems ip.x = (*ic).x + ip.x / ip.z; ip.y = (*ic).y + ip.y / ip.z; // Get pixel location from 2D image float2 pos; pos.y = ip.x; pos.x = ip.y; // Clip against image dimensions if (pos.x < 0 || pos.x >= (*proj_dim).x || pos.y < 0 || pos.y >= (*proj_dim).y) return; // Dot product float s = ((*nrm).x * vp.x) + ((*nrm).y * vp.y) + ((*nrm).z * vp.z); // Conebeam weighting factor s = (*sad) - s; s = ((*sad) * (*sad)) / (s * s); // Distance from interpolated pixel to [0][0] point float2 dist; dist.x = pos.x - floor(pos.x); dist.y = pos.y - floor(pos.y); // Variable used to store 4 pixel intensities float4 p[2][2]; // Position in image of [0][0] in bilinear matrix int2 bilinear_pos; bilinear_pos.x = floor(pos.x); bilinear_pos.y = floor(pos.y); // Variable storing position to read image int2 interp_pos; for (int i=0; i < 2; i++) { for (int j = 0; j < 2; j++) { interp_pos.x = bilinear_pos.x + i; interp_pos.y = bilinear_pos.y + j; // Checks if pixel is outside image if (interp_pos.x < 0) interp_pos.x = 0; else if(interp_pos.x >= (*proj_dim).x) interp_pos.x = (*proj_dim).x - 1; if (interp_pos.y < 0) interp_pos.y = 0; else if(interp_pos.y >= (*proj_dim).y) interp_pos.y = (*proj_dim).y - 1; p[i][j] = read_imagef(dev_img, dev_img_sampler, interp_pos); } } float intensity = p[0][0].x * (1 - dist.x) * (1 - dist.y) + p[0][1].x * (1 - dist.x) * dist.y + p[1][0].x * dist.x * (1 - dist.y) + p[1][1].x * dist.x * dist.y; // Place it into the volume dev_vol[vol_idx] = dev_vol_value + ((*scale) * s * intensity); } // FDK kernel - bicubic interpolation __kernel void kernel_fdk_bicubic( __global float *dev_vol, __read_only image2d_t dev_img, __constant float *dev_matrix, __constant float4 *nrm, __constant float4 *vol_offset, __constant float4 *vol_pix_spacing, __constant int4 *vol_dim, __constant float2 *ic, __constant int2 *proj_dim, __constant float *sad, __constant float *scale, __constant int4 *ndevice, int offset ){ uint i = get_global_id(0); uint j = get_global_id(1); uint k = get_global_id(2); if (i >= (*ndevice).x || j >= (*ndevice).y || k >= (*ndevice).z) return; // Index row major into the volume long vol_idx = i + (j * (*vol_dim).x) + (k * (*vol_dim).x * (*vol_dim).y); k += offset; // Get volume value from global memory float dev_vol_value = dev_vol[vol_idx]; // offset volume coords float4 vp; vp.x = (*vol_offset).x + (i * (*vol_pix_spacing).x); // Compiler should combine into 1 FMAD. vp.y = (*vol_offset).y + (j * (*vol_pix_spacing).y); // Compiler should combine into 1 FMAD. vp.z = (*vol_offset).z + (k * (*vol_pix_spacing).z); // Compiler should combine into 1 FMAD. // matrix multiply float4 ip; ip.x = (dev_matrix[0] * vp.x) + (dev_matrix[1] * vp.y) + (dev_matrix[2] * vp.z) + dev_matrix[3]; ip.y = (dev_matrix[4] * vp.x) + (dev_matrix[5] * vp.y) + (dev_matrix[6] * vp.z) + dev_matrix[7]; ip.z = (dev_matrix[8] * vp.x) + (dev_matrix[9] * vp.y) + (dev_matrix[10] * vp.z) + dev_matrix[11]; // Change coordinate systems ip.x = (*ic).x + ip.x / ip.z; ip.y = (*ic).y + ip.y / ip.z; // Get pixel from 2D image float2 pos; pos.y = ip.x; pos.x = ip.y; // Clip against image dimensions if (pos.x < 0 || pos.x >= (*proj_dim).x || pos.y < 0 || pos.y >= (*proj_dim).y) return; // Dot product float s = ((*nrm).x * vp.x) + ((*nrm).y * vp.y) + ((*nrm).z * vp.z); // Conebeam weighting factor s = (*sad) - s; s = ((*sad) * (*sad)) / (s * s); // Distance from interpolated pixel to [0][0] point float2 dist; dist.x = pos.x - floor(pos.x); dist.y = pos.y - floor(pos.y); // Variable used to store 16 pixel intensities float4 p[4][4]; // Position in image of [0][0] in bicubic matrix int2 bicubic_pos; bicubic_pos.x = floor(pos.x); bicubic_pos.y = floor(pos.y); // Variable storing position to read image int2 interp_pos; for (int i = -1; i < 3; i++) { for (int j = -1; j < 3; j++) { interp_pos.x = bicubic_pos.x + i; interp_pos.y = bicubic_pos.y + j; // Checks if pixel is outside image if (interp_pos.x < 0) interp_pos.x = 0; else if(interp_pos.x >= (*proj_dim).x) interp_pos.x = (*proj_dim).x - 1; if (interp_pos.y < 0) interp_pos.y = 0; else if(interp_pos.y >= (*proj_dim).y) interp_pos.y = (*proj_dim).y - 1; p[i + 1][j + 1] = read_imagef(dev_img, dev_img_sampler, interp_pos); } } float16 a; a.s0 = p[1][1].x; a.s1 = - (0.5 * p[1][0].x) + (0.5 * p[1][2].x); a.s2 = p[1][0].x - (2.5 * p[1][1].x) + (2 * p[1][2].x) - (0.5 * p[1][3].x); a.s3 = - (0.5 * p[1][0].x) + (1.5 * p[1][1].x) - (1.5 * p[1][2].x) + (0.5 * p[1][3].x); a.s4 = (0.5 * p[2][1].x) - (0.5 * p[0][1].x); a.s5 = - (0.25 * p[2][0].x) + (0.25 * p[2][2].x) + (0.25 * p[0][0].x) - (0.25 * p[0][2].x); a.s6 = (0.5 * p[2][0].x) - (1.25 * p[2][1].x) + p[2][2].x - (0.25 * p[2][3].x) - (0.5 * p[0][0].x) + (1.25 * p[0][1].x) - p[0][2].x + (0.25 * p[0][3].x); a.s7 = - (0.25 * p[2][0].x) + (0.75 * p[2][1].x) - (0.75 * p[2][2].x) + (0.25 * p[2][3].x) + (0.25 * p[0][0].x) - (0.75 * p[0][1].x) + (0.75 * p[0][2].x) - (0.25 * p[0][3].x); a.s8 = - (0.5 * p[3][1].x) + (2 * p[2][1].x) - (2.5 * p[1][1].x) + p[0][1].x; a.s9 = (0.25 * p[3][0].x) - (0.25 * p[3][2].x) - p[2][0].x + p[2][2].x + (1.25 * p[1][0].x) - (1.25 * p[1][2].x) - (0.5 * p[0][0].x) + (0.5 * p[0][2].x); a.sa = - (0.5 * p[3][0].x) + (1.25 * p[3][1].x) - p[3][2].x + (0.25 * p[3][3].x) + (2 * p[2][0].x) - (5 * p[2][1].x) + (4 * p[2][2].x) - p[2][3].x - (2.5 * p[1][0].x) + (6.25 * p[1][1].x) - (5 * p[1][2].x) + (1.25 * p[1][3].x) + p[0][0].x - (2.5 * p[0][1].x) + (2 * p[0][2].x) - (0.5 * p[0][3].x); a.sb = (0.25 * p[3][0].x) - (0.75 * p[3][1].x) + (0.75 * p[3][2].x) - (0.25 * p[3][3].x) - p[2][0].x + (3 * p[2][1].x) - (3 * p[2][2].x) + p[2][3].x + (1.25 * p[1][0].x) - (3.75 * p[1][1].x) + (3.75 * p[1][2].x) - (1.25 * p[1][3].x) - (0.5 * p[0][0].x) + (1.5 * p[0][1].x) - (1.5 * p[0][2].x) + (0.5 * p[0][3].x); a.sc = (0.5 * p[3][1].x) - (1.5 * p[2][1].x) + (1.5 * p[1][1].x) - (0.5 * p[0][1].x); a.sd = - (0.25 * p[3][0].x) + (0.25 * p[3][2].x) + (0.75 * p[2][0].x) - (0.75 * p[2][2].x) - (0.75 * p[1][0].x) + (0.75 * p[1][2].x) + (0.25 * p[0][0].x) - (0.25 * p[0][2].x); a.se = (0.5 * p[3][0].x) - (1.25 * p[3][1].x) + p[3][2].x - (0.25 * p[3][3].x) - (1.5 * p[2][0].x) + (3.75 * p[2][1].x) - (3 * p[2][2].x) + (0.75 * p[2][3].x) + (1.5 * p[1][0].x) - (3.75 * p[1][1].x) + (3 * p[1][2].x) - (0.75 * p[1][3].x) - (0.5 * p[0][0].x) + (1.25 * p[0][1].x) - p[0][2].x + (0.25 * p[0][3].x); a.sf = - (0.25 * p[3][0].x) + (0.75 * p[3][1].x) - (0.75 * p[3][2].x) + (0.25 * p[3][3].x) + (0.75 * p[2][0].x) - (2.25 * p[2][1].x) + (2.25 * p[2][2].x) - (0.75 * p[2][3].x) - (0.75 * p[1][0].x) + (2.25 * p[1][1].x) - (2.25 * p[1][2].x) + (0.75 * p[1][3].x) + (0.25 * p[0][0].x) - (0.75 * p[0][1].x) + (0.75 * p[0][2].x) - (0.25 * p[0][3].x); float intensity = a.s0 + (a.s1 * dist.y) + (a.s2 * dist.y * dist.y) + (a.s3 * dist.y * dist.y * dist.y) + (a.s4 * dist.x) + (a.s5 * dist.x * dist.y) + (a.s6 * dist.x * dist.y * dist.y) + (a.s7 * dist.x * dist.y * dist.y * dist.y) + (a.s8 * dist.x * dist.x) + (a.s9 * dist.x * dist.x * dist.y) + (a.sa * dist.x * dist.x * dist.y * dist.y) + (a.sb * dist.x * dist.x * dist.y * dist.y * dist.y) + (a.sc * dist.x * dist.x * dist.x) + (a.sd * dist.x * dist.x * dist.x * dist.y) + (a.se * dist.x * dist.x * dist.x * dist.y * dist.y) + (a.sf * dist.x * dist.x * dist.x * dist.y * dist.y * dist.y); // Place it into the volume dev_vol[vol_idx] = dev_vol_value + ((*scale) * s * intensity); } __kernel void kernel_fdk ( __global float *dev_vol, __read_only image2d_t dev_img, __constant float *dev_matrix, __constant float4 *nrm, __constant float4 *vol_offset, __constant float4 *vol_pix_spacing, __constant int4 *vol_dim, __constant float2 *ic, __constant int2 *proj_dim, __constant float *sad, __constant float *scale, __constant int4 *ndevice, int offset ) { } #endif __kernel void fdk_kernel_nn ( __global float *dev_vol, __global float *dev_img, __constant float *dev_matrix, int4 vol_dim, __constant float *vol_offset, __constant float *vol_spacing, int2 proj_dim, __constant float *nrm, __constant float *ic, const float sad, const float scale ) { uint id = get_global_id(0); uint id_l = get_local_id(0); int k = id / vol_dim.x / vol_dim.y; int j = (id - (k * vol_dim.x * vol_dim.y)) / vol_dim.x; int i = id - k * vol_dim.x * vol_dim.y - j * vol_dim.x; if (k >= vol_dim.z) { return; } // Get volume value from global memory float dev_vol_value = dev_vol[id]; // Get (x,y,z) coordinates float4 vp; vp.x = vol_offset[0] + (i * vol_spacing[0]); vp.y = vol_offset[1] + (j * vol_spacing[1]); vp.z = vol_offset[2] + (k * vol_spacing[2]); // Matrix multiplication float4 ip; ip.x = (dev_matrix[0] * vp.x) + (dev_matrix[1] * vp.y) + (dev_matrix[2] * vp.z) + dev_matrix[3]; ip.y = (dev_matrix[4] * vp.x) + (dev_matrix[5] * vp.y) + (dev_matrix[6] * vp.z) + dev_matrix[7]; ip.z = (dev_matrix[8] * vp.x) + (dev_matrix[9] * vp.y) + (dev_matrix[10] * vp.z) + dev_matrix[11]; // Change coordinate systems ip.x = ic[0] + ip.x / ip.z; ip.y = ic[1] + ip.y / ip.z; // Retrieve pixel location from 2D image int2 pos; pos.y = convert_int_rtn (ip.x); pos.x = convert_int_rtn (ip.y); // Clip against image dimensions if (pos.x < 0 || pos.x >= proj_dim.x || pos.y < 0 || pos.y >= proj_dim.y) { return; } // Get pixel from image //float4 voxel_data = read_imagef(dev_img, dev_img_sampler, pos); float pix_val = dev_img[pos.y * proj_dim.x + pos.x]; // Get distance to voxel projected to panel normal float s = (nrm[0] * vp.x) + (nrm[1] * vp.y) + (nrm[2] * vp.z); // Conebeam weighting factor s = sad - s; s = (sad * sad) / (s * s); // Weight pixel and backproject into volume dev_vol[id] = dev_vol_value + (scale * s * pix_val); } fdk_opencl.cxx000066400000000000000000000145361321604176500317540ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmreconstruct_config.h" #include #include #include #include #include "autotune_opencl.h" #include "fdk.h" #include "fdk_opencl_p.h" #include "opencl_util.h" #include "plm_math.h" #include "proj_image.h" #include "proj_image_dir.h" #include "proj_image_filter.h" #include "proj_matrix.h" #include "volume.h" void opencl_reconstruct_conebeam ( Volume *vol, Proj_image_dir *proj_dir, Fdk_parms *parms ) { Opencl_device ocl_dev; Opencl_buf *ocl_buf_vol; Opencl_buf *ocl_buf_img; Opencl_buf *ocl_buf_matrix; cl_int4 ocl_vol_dim; Opencl_buf *ocl_buf_vol_origin; Opencl_buf *ocl_buf_vol_spacing; cl_int2 ocl_proj_dim; Opencl_buf *ocl_buf_nrm; Opencl_buf *ocl_buf_ic; Proj_image *proj; int image_num; float scale; LOAD_LIBRARY_SAFE (libplmopencl); LOAD_SYMBOL (opencl_open_device, libplmopencl); LOAD_SYMBOL (opencl_load_programs, libplmopencl); LOAD_SYMBOL (opencl_kernel_create, libplmopencl); LOAD_SYMBOL (opencl_buf_create, libplmopencl); LOAD_SYMBOL (opencl_buf_write, libplmopencl); LOAD_SYMBOL (opencl_set_kernel_args, libplmopencl); LOAD_SYMBOL (opencl_kernel_enqueue, libplmopencl); LOAD_SYMBOL (opencl_buf_read, libplmopencl); /* Set up devices and kernels */ opencl_open_device (&ocl_dev); opencl_load_programs (&ocl_dev, "fdk_opencl.cl"); opencl_kernel_create (&ocl_dev, "fdk_kernel_nn"); /* Retrieve 2D image to get dimensions */ proj = proj_dir->load_image (0); /* Set up device memory */ ocl_buf_vol = opencl_buf_create ( &ocl_dev, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, vol->pix_size * vol->npix, vol->img ); ocl_buf_img = opencl_buf_create ( &ocl_dev, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, proj->dim[1] * proj->dim[0] * sizeof(float), 0 ); ocl_buf_matrix = opencl_buf_create ( &ocl_dev, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, 12 * sizeof(float), 0 ); /* Copy volume dim (convert from size_t to int) */ opencl_idx(ocl_vol_dim,0) = vol->dim[0]; opencl_idx(ocl_vol_dim,1) = vol->dim[1]; opencl_idx(ocl_vol_dim,2) = vol->dim[2]; ocl_buf_vol_origin = opencl_buf_create ( &ocl_dev, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, 3 * sizeof(float), vol->origin ); ocl_buf_vol_spacing = opencl_buf_create ( &ocl_dev, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, 3 * sizeof(float), vol->spacing ); /* Copy projection image dim (convert from size_t to int) */ opencl_idx(ocl_proj_dim,0) = proj->dim[0]; opencl_idx(ocl_proj_dim,1) = proj->dim[1]; ocl_buf_nrm = opencl_buf_create ( &ocl_dev, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, 3 * sizeof(float), 0 ); ocl_buf_ic = opencl_buf_create ( &ocl_dev, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, 2 * sizeof(float), 0 ); /* Calculate the scale */ image_num = 1 + (parms->last_img - parms->first_img) / parms->skip_img; scale = (float)(sqrt(3.0)/(double)image_num); scale = scale * parms->scale; /* Free proj image */ delete proj; /* Project each image into the volume one at a time */ for (image_num = parms->first_img; image_num < proj_dir->num_proj_images; image_num++) { int i; float matrix[12], nrm[3], ic[2], sad; /* Load the current image and properties */ proj = proj_dir->load_image (image_num); /* Apply ramp filter */ if (parms->filter == FDK_FILTER_TYPE_RAMP) { proj_image_filter (proj); } /* Copy image bytes to device */ opencl_buf_write (&ocl_dev, ocl_buf_img, proj->dim[1] * proj->dim[0] * sizeof(float), proj->img); /* Copy matrix to device (convert from double to float) */ for (i = 0; i < 12; i++) { matrix[i] = proj->pmat->matrix[i]; } opencl_buf_write (&ocl_dev, ocl_buf_matrix, 12 * sizeof(float), matrix); /* Copy ic to device (convert from double to float) */ ic[0] = proj->pmat->ic[0]; ic[1] = proj->pmat->ic[1]; opencl_buf_write (&ocl_dev, ocl_buf_ic, 2 * sizeof(float), ic); /* Copy nrm to device (convert from double to float) */ nrm[0] = proj->pmat->nrm[0]; nrm[1] = proj->pmat->nrm[1]; nrm[2] = proj->pmat->nrm[2]; opencl_buf_write (&ocl_dev, ocl_buf_nrm, 3 * sizeof(float), nrm); /* Convert sad from double to float */ sad = proj->pmat->sad; /* Set fdk kernel arguments */ opencl_set_kernel_args ( &ocl_dev, sizeof (cl_mem), &ocl_buf_vol[0], sizeof (cl_mem), &ocl_buf_img[0], sizeof (cl_mem), &ocl_buf_matrix[0], sizeof (cl_int4), &ocl_vol_dim, sizeof (cl_mem), &ocl_buf_vol_origin[0], sizeof (cl_mem), &ocl_buf_vol_spacing[0], sizeof (cl_int2), &ocl_proj_dim, sizeof (cl_mem), &ocl_buf_nrm[0], sizeof (cl_mem), &ocl_buf_ic[0], sizeof (cl_float), &sad, sizeof (cl_float), &scale, (size_t) 0 ); /* Compute workgroup size */ /* (Max local_work_size for my ATI RV710 is 128) */ size_t local_work_size = 128; size_t global_work_size = (float) vol->npix; #if defined (commentout) /* For debugging */ local_work_size = 4; global_work_size = 8; #endif /* Invoke kernel */ opencl_kernel_enqueue (&ocl_dev, global_work_size, local_work_size); } /* Read back results */ opencl_buf_read (&ocl_dev, ocl_buf_vol, vol->pix_size * vol->npix, vol->img); #if defined (commentout) /* For debugging */ int num_nonzero = 0; for (cl_uint i = 0; i < vol->npix; i++) { if (img[i] != 0.0f) { printf ("[%d] %f\n", i, img[i]); if (++num_nonzero == 10) { break; } } } #endif UNLOAD_LIBRARY (libplmopencl); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/fdk_opencl.h000066400000000000000000000010151321604176500314440ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _FDK_OPENCL_H_ #define _FDK_OPENCL_H_ #include "plmreconstruct_config.h" #include "delayload.h" class Fdk_parms; class Proj_image_dir; class Volume; PLMRECONSTRUCT_C_API void opencl_reconstruct_conebeam ( Volume *vol, Proj_image_dir *proj_dir, Fdk_parms *parms ); #endif fdk_opencl_p.h000066400000000000000000000007711321604176500317140ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct#ifndef _FDK_OPENCL_P_H_ #define _FDK_OPENCL_P_H_ #include "fdk_opencl.h" #define MAX_GPU_COUNT 8 struct int2 { int x; int y; }; struct int4 { int x; int y; int z; int w; }; struct float2 { float x; float y; }; struct float4 { float x; float y; float z; float w; }; struct kernel_args_fdk { int2 img_dim; float2 ic; float4 nrm; float sad; float sid; float scale; float4 vol_offset; int4 vol_dim; float4 vol_spacing; float matrix[12]; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/fdk_util.cxx000066400000000000000000000026321321604176500315220ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmreconstruct_config.h" #include #include #include #include "fdk.h" #include "fdk_util.h" #include "ramp_filter.h" #include "volume.h" Volume* my_create_volume (Fdk_parms* parms) { float offset[3]; float spacing[3]; float* vol_size = parms->vol_size; plm_long* dim = parms->dim; spacing[0] = vol_size[0] / dim[0]; spacing[1] = vol_size[1] / dim[1]; spacing[2] = vol_size[2] / dim[2]; offset[0] = -vol_size[0] / 2.0f + spacing[0] / 2.0f; offset[1] = -vol_size[1] / 2.0f + spacing[1] / 2.0f; offset[2] = -vol_size[2] / 2.0f + spacing[2] / 2.0f; return new Volume (dim, offset, spacing, 0, PT_FLOAT, 1); } float convert_to_hu_pixel (float in_value) { float hu; float diameter = 40.0; /* reconstruction diameter in cm */ hu = 1000 * ((in_value / diameter) - .167) / .167; return hu; } void convert_to_hu (Volume* vol, Fdk_parms* parms) { plm_long i, j, k, p; float* img = (float*) vol->img; p = 0; for (k = 0; k < vol->dim[2]; k++) { for (j = 0; j < vol->dim[1]; j++) { for (i = 0; i < vol->dim[0]; i++) { img[p] = convert_to_hu_pixel (img[p]); p++; } } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/fdk_util.h000066400000000000000000000012611321604176500311440ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _fdk_utils_h_ #define _fdk_utils_h_ #include "plmreconstruct_config.h" class Fdk_parms; class Proj_image; class Volume; PLMRECONSTRUCT_C_API void convert_to_hu (Volume* vol, Fdk_parms* parms); PLMRECONSTRUCT_C_API Volume* my_create_volume (Fdk_parms* parms); Proj_image* get_image_pfm (Fdk_parms* parms, int image_num); Proj_image* get_image_raw (Fdk_parms* parms, int image_num); void write_coronal_sagittal (Fdk_parms* parms, Volume* vol); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/historical/000077500000000000000000000000001321604176500313335ustar00rootroot00000000000000drr_cuda_old.cu000066400000000000000000000311141321604176500342260ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/historical/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" /****************************************************\ * Uncomment the line below to enable verbose output. * * Enabling this should not nerf performance. * \****************************************************/ #define VERBOSE 1 /**********************************************************\ * Uncomment the line below to enable detailed performance * * reporting. This measurement alters the system, however, * * resulting in significantly slower kernel execution. * \**********************************************************/ #define TIME_KERNEL #ifdef __DEVICE_EMULATION__ #define EMUSYNC __syncthreads() #else #define EMUSYNC #endif /***************** * C #includes * *****************/ #include #include #include #include #include #include "drr_cuda.h" #include "drr_cuda_p.h" #include "drr_opts.h" #include "file_util.h" #include "plm_math.h" #include "proj_image.h" #include "volume.h" #include "timer.h" // P R O T O T Y P E S //////////////////////////////////////////////////// void checkCUDAError(const char *msg); __global__ void kernel_drr_i3 (float * dev_vol, int2 img_dim, float2 ic, float3 nrm, float sad, float scale, float3 vol_offset, int3 vol_dim, float3 vol_pix_spacing); // T E X T U R E S //////////////////////////////////////////////////////// texture tex_img; texture tex_matrix; texture tex_coef; texture tex_3Dvol; // uses 3D textures and pre-calculated coefs to accelerate DRR generation. void kernel_drr_i3 (float * dev_img, int2 img_dim, float2 ic, float3 nrm, float sad, float scale, float3 vol_offset, int3 vol_dim, float3 vol_pix_spacing) { // CUDA 2.0 does not allow for a 3D grid, which severely // limits the manipulation of large 3D arrays of data. The // following code is a hack to bypass this implementation // limitation. extern __shared__ float sdata[]; float3 vp; int i,j,k; int x,y,xy7; float vol; unsigned int tid = threadIdx.x; x = blockIdx.x; y = blockIdx.y; xy7=7*(y*img_dim.x+x); if (abs(tex1Dfetch(tex_matrix, 5))>abs(tex1Dfetch(tex_matrix, 4))) { vp.x=vol_offset.x+threadIdx.x*vol_pix_spacing.x; vp.y=tex1Dfetch(tex_coef, xy7)*vp.x+tex1Dfetch(tex_coef, xy7+1); vp.z=tex1Dfetch(tex_coef, xy7+4)*vp.x +tex1Dfetch(tex_coef, xy7+5)*vp.y+tex1Dfetch(tex_coef, xy7+6); i= threadIdx.x; j= __float2int_rd((vp.y-vol_offset.y)/vol_pix_spacing.y); k= __float2int_rd((vp.z-vol_offset.z)/vol_pix_spacing.z); //if (j<0||j>=vol_dim.y||k<0||k>=vol_dim.z) if ((i-vol_dim.x/2)*(i-vol_dim.x/2)+(j-vol_dim.y/2)*(j-vol_dim.y/2) > vol_dim.y*vol_dim.y/4||k<0||k>=vol_dim.z) { sdata[tid]=0.0f; } else { vol=tex3D(tex_3Dvol,i,j,k); sdata[tid]=(vol+1000.0f); } } else { vp.y=vol_offset.y+threadIdx.x*vol_pix_spacing.y; vp.x=tex1Dfetch(tex_coef, xy7+2)*vp.y+tex1Dfetch(tex_coef, xy7+3); vp.z=tex1Dfetch(tex_coef, xy7+4)*vp.x +tex1Dfetch(tex_coef, xy7+5)*vp.y+tex1Dfetch(tex_coef, xy7+6); j= threadIdx.x; i= __float2int_rd((vp.x-vol_offset.x)/vol_pix_spacing.x); k= __float2int_rd((vp.z-vol_offset.z)/vol_pix_spacing.z); if ((i-vol_dim.x/2)*(i-vol_dim.x/2)+(j-vol_dim.y/2)*(j-vol_dim.y/2) > vol_dim.y*vol_dim.y/4||k<0||k>=vol_dim.z) { sdata[tid]=0.0f; } else { vol=tex3D(tex_3Dvol,i,j,k); sdata[tid]=(vol+1000.0f); } } __syncthreads(); // do reduction in shared mem for(unsigned int s=blockDim.x/2; s>32; s>>=1) { if (tid < s) sdata[tid] += sdata[tid + s]; __syncthreads(); } #ifndef __DEVICE_EMULATION__ if (tid < 32) #endif { sdata[tid] += sdata[tid + 32]; EMUSYNC; sdata[tid] += sdata[tid + 16]; EMUSYNC; sdata[tid] += sdata[tid + 8]; EMUSYNC; sdata[tid] += sdata[tid + 4]; EMUSYNC; sdata[tid] += sdata[tid + 2]; EMUSYNC; sdata[tid] += sdata[tid + 1]; EMUSYNC; } // write result for this block to global mem if (tid == 0) dev_img[blockIdx.x*img_dim.y + blockIdx.y] = sdata[0]; } void* drr_cuda_state_create ( Proj_image *proj, Volume *vol, Drr_options *options ) { Drr_cuda_state *state; Drr_kernel_args *kargs; state = (Drr_cuda_state *) malloc (sizeof(Drr_cuda_state)); memset (state, 0, sizeof(Drr_cuda_state)); state->kargs = kargs = (Drr_kernel_args*) malloc (sizeof(Drr_kernel_args)); cudaMalloc ((void**) &state->dev_matrix, 12 * sizeof(float)); cudaMalloc ((void**) &state->dev_kargs, sizeof(Drr_kernel_args)); printf ("printf state = %p\n", state); printf ("printf state->kargs = %p\n", state->kargs); kargs->vol_offset.x = vol->offset[0]; kargs->vol_offset.y = vol->offset[1]; kargs->vol_offset.z = vol->offset[2]; kargs->vol_dim.x = vol->dim[0]; kargs->vol_dim.y = vol->dim[1]; kargs->vol_dim.z = vol->dim[2]; kargs->vol_pix_spacing.x = vol->pix_spacing[0]; kargs->vol_pix_spacing.y = vol->pix_spacing[1]; kargs->vol_pix_spacing.z = vol->pix_spacing[2]; // prepare texture cudaChannelFormatDesc ca_descriptor; cudaExtent ca_extent; cudaArray *dev_3Dvol=0; ca_descriptor = cudaCreateChannelDesc(); ca_extent.width = vol->dim[0]; ca_extent.height = vol->dim[1]; ca_extent.depth = vol->dim[2]; cudaMalloc3DArray (&dev_3Dvol, &ca_descriptor, ca_extent); cudaBindTextureToArray (tex_3Dvol, dev_3Dvol, ca_descriptor); cudaMemcpy3DParms cpy_params = {0}; cpy_params.extent = ca_extent; cpy_params.kind = cudaMemcpyHostToDevice; cpy_params.dstArray = dev_3Dvol; //http://sites.google.com/site/cudaiap2009/cookbook-1#TOC-CUDA-3D-Texture-Example-Gerald-Dall // The pitched pointer is really tricky to get right. We give the // pitch of a row, then the number of elements in a row, then the // height, and we omit the 3rd dimension. cpy_params.srcPtr = make_cudaPitchedPtr ((void*)vol->img, ca_extent.width * sizeof(float), ca_extent.width , ca_extent.height); cudaMemcpy3D (&cpy_params); cudaMalloc ((void**) &state->dev_img, options->image_resolution[0] * options->image_resolution[1] * sizeof(float)); cudaMalloc ((void**) &state->dev_coef, 7 * options->image_resolution[0] * options->image_resolution[1] * sizeof(float)); checkCUDAError ("Unable to allocate coef devmem"); state->host_coef = (float*) malloc ( 7 * options->image_resolution[0] * options->image_resolution[1] * sizeof(float)); return (void*) state; } void drr_cuda_state_destroy ( void *void_state ) { Drr_cuda_state *state = (Drr_cuda_state*) void_state; cudaFree (state->dev_img); cudaFree (state->dev_kargs); cudaFree (state->dev_matrix); cudaFree (state->dev_coef); free (state->host_coef); free (state->kargs); } void drr_cuda_render_volume_perspective ( Proj_image *proj, void *void_state, Volume *vol, double ps[2], char *multispectral_fn, Drr_options *options ) { Timer timer, total_timer; double time_kernel = 0; double time_io = 0; int i; // CUDA device pointers Drr_cuda_state *state = (Drr_cuda_state*) void_state; Drr_kernel_args *kargs = state->kargs; float *host_coef = state->host_coef; // Start the timer plm_timer_start (&total_timer); plm_timer_start (&timer); // Load dynamic kernel arguments kargs->img_dim.x = proj->dim[0]; kargs->img_dim.y = proj->dim[1]; kargs->ic.x = proj->pmat->ic[0]; kargs->ic.y = proj->pmat->ic[1]; kargs->nrm.x = proj->pmat->nrm[0]; kargs->nrm.y = proj->pmat->nrm[1]; kargs->nrm.z = proj->pmat->nrm[2]; kargs->sad = proj->pmat->sad; kargs->sid = proj->pmat->sid; for (i = 0; i < 12; i++) { kargs->matrix[i] = (float) proj->pmat->matrix[i]; } // Precalculate coeff int xy7; double *matrix = proj->pmat->matrix; for (int x = 0; x < proj->dim[0] ; x++) { for (int y = 0; y < proj->dim[1] ; y++) { xy7 = 7 * (y * proj->dim[0] + x); #if defined (commentout) host_coef[xy7] =((y-ic[1])*proj->pmat->matrix[8]-proj->pmat->matrix[4])/(proj->pmat->matrix[5]-(y-ic[1])*proj->pmat->matrix[9]); host_coef[xy7+2]=((y-ic[1])*proj->pmat->matrix[9]-proj->pmat->matrix[5])/(proj->pmat->matrix[4]-(y-ic[1])*proj->pmat->matrix[8]); host_coef[xy7+1]=(y-ic[1])*proj->pmat->matrix[11]/(proj->pmat->matrix[5]-(y-ic[1])*proj->pmat->matrix[9]); host_coef[xy7+3]=(y-ic[1])*proj->pmat->matrix[11]/(proj->pmat->matrix[4]-(y-ic[1])*proj->pmat->matrix[8]); host_coef[xy7+4]=(x-ic[0])*proj->pmat->matrix[8]/proj->pmat->matrix[2]; host_coef[xy7+5]=(x-ic[0])*proj->pmat->matrix[9]/proj->pmat->matrix[2]; host_coef[xy7+6]=(x-ic[0])*proj->pmat->matrix[11]/proj->pmat->matrix[2]; #endif host_coef[xy7] = (y * matrix[8] - matrix[4]) / (matrix[5] - y * matrix[9]); host_coef[xy7+2] = (y * matrix[9] - matrix[5]) / (matrix[4] - y * matrix[8]); host_coef[xy7+1] = y * matrix[11] / (matrix[5] - y * matrix[9]); host_coef[xy7+3] = y * matrix[11] / (matrix[4] - y * matrix[8]); host_coef[xy7+4] = x * matrix[8] / matrix[2]; host_coef[xy7+5] = x * matrix[9] / matrix[2]; host_coef[xy7+6] = x * matrix[11] / matrix[2]; } } time_io += plm_timer_report (&timer); plm_timer_start (&timer); cudaMemcpy (state->dev_matrix, kargs->matrix, sizeof(kargs->matrix), cudaMemcpyHostToDevice); cudaBindTexture (0, tex_matrix, state->dev_matrix, sizeof(kargs->matrix)); cudaMemcpy (state->dev_coef, host_coef, 7 * proj->dim[0] * proj->dim[1] * sizeof(float), cudaMemcpyHostToDevice); cudaBindTexture (0, tex_coef, state->dev_coef, 7 * proj->dim[0] * proj->dim[1] * sizeof(float)); // Thead Block Dimensions int tBlock_x = vol->dim[0]; int tBlock_y = 1; int tBlock_z = 1; // Each element in the volume (each voxel) gets 1 thread int blocksInX = proj->dim[0]; int blocksInY = proj->dim[1]; dim3 dimGrid = dim3(blocksInX, blocksInY); dim3 dimBlock = dim3(tBlock_x, tBlock_y, tBlock_z); // Invoke ze kernel \(^_^)/ // Note: proj->img AND proj->matrix are passed via texture memory int smemSize = vol->dim[0] * sizeof(float); plm_timer_start (&timer); //------------------------------------- kernel_drr_i3<<< dimGrid, dimBlock, smemSize>>> ( state->dev_img, kargs->img_dim, kargs->ic, kargs->nrm, kargs->sad, kargs->scale, kargs->vol_offset, kargs->vol_dim, kargs->vol_pix_spacing); checkCUDAError("Kernel Panic!"); #if defined (TIME_KERNEL) // CUDA kernel calls are asynchronous... // In order to accurately time the kernel // execution time we need to set a thread // barrier here after its execution. cudaThreadSynchronize(); #endif time_kernel += plm_timer_report (&timer); // Unbind the image and projection matrix textures //cudaUnbindTexture( tex_img ); cudaUnbindTexture (tex_matrix); cudaUnbindTexture (tex_coef); // Copy reconstructed volume from device to host //cudaMemcpy( vol->img, dev_vol, vol->npix * vol->pix_size, cudaMemcpyDeviceToHost ); cudaMemcpy (proj->img, state->dev_img, proj->dim[0] * proj->dim[1] * sizeof(float), cudaMemcpyDeviceToHost); checkCUDAError("Error: Unable to retrieve data volume."); } /////////////////////////////////////////////////////////////////////////// // FUNCTION: checkCUDAError() ///////////////////////////////////////////// void checkCUDAError(const char *msg) { cudaError_t err = cudaGetLastError(); if ( cudaSuccess != err) { fprintf(stderr, "CUDA ERROR: %s (%s).\n", msg, cudaGetErrorString( err) ); exit(EXIT_FAILURE); } } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Vim Editor Settings //////////////////////////////////////////////////// // vim:ts=8:sw=8:cindent:nowrap /////////////////////////////////////////////////////////////////////////// drr_opencl_old.cxx000077500000000000000000000570301321604176500347750ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/historical/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "plmsys.h" #include "autotune_opencl.h" #include "drr_opencl.h" #include "drr_opencl_p.h" #include "drr.h" #include "drr_opts.h" #include "plm_math.h" #include "opencl_util.h" #include "opencl_util_nvidia.h" #include "proj_image.h" #include "proj_matrix.h" #include "volume.h" #include "volume_limit.h" #if defined (commentout) /* Globals */ cl_int error; /* Use for error checking */ cl_context context[MAX_GPU_COUNT]; /* Context from device */ cl_command_queue command_queue[MAX_GPU_COUNT]; /* Command Queue from Context */ cl_program program[MAX_GPU_COUNT]; /* Program from .cl file */ cl_uint device_count; /* number of devices available */ cl_device_id *devices; /* pointer to devices */ cl_device_id device; /* object for individual device in for loop */ char device_name[MAX_GPU_COUNT][256]; /* device names */ void drr_render_volume_perspective_cl ( Proj_image *proj, Volume *vol, double ps[2], Drr_options *options, int img_size, int float3_size, cl_mem *g_dev_vol, cl_mem *g_dev_img, cl_mem *c_vol_dim, cl_mem *c_img_dim, cl_mem *c_offset, cl_mem *c_pix_spacing, cl_mem *c_vol_limits, cl_mem *c_p1, cl_mem *c_ul_room, cl_mem *c_incr_r, cl_mem *c_incr_c, cl_mem *c_pixel_device, cl_kernel *drr_kernel, cl_ulong *drr_total, cl_ulong *img_total, size_t drr_global_work_size[MAX_GPU_COUNT][2], size_t drr_local_work_size[MAX_GPU_COUNT][2], int4 *pixels_per_device, int2 *pixel_offset, int *img_size_device) { double p1[3]; double ic_room[3]; double ul_room[3]; double incr_r[3]; double incr_c[3]; double tmp[3]; Volume_limit vol_limit; double nrm[3], pdn[3], prt[3]; Proj_matrix *pmat = proj->pmat; int res_r = options->image_window[1] - options->image_window[0] + 1; int res_c = options->image_window[3] - options->image_window[2] + 1; float p1_f[3]; float ul_room_f[3]; float incr_r_f[3]; float incr_c_f[3]; Volume_limit_f vol_limit_f; /* Set defaults */ int2 img_dim = {res_r, res_c}; int preprocess_attenuation = DRR_PREPROCESS_ATTENUATION; /* Create variables for kernel and memory timing */ cl_event drr_event[MAX_GPU_COUNT], img_event[MAX_GPU_COUNT]; proj_matrix_get_nrm(pmat, nrm); proj_matrix_get_pdn(pmat, pdn); proj_matrix_get_prt(pmat, prt); /* Compute position of image center in room coordinates */ vec3_scale3(tmp, nrm, - pmat->sid); vec3_add3(ic_room, pmat->cam, tmp); /* Compute incremental change in 3d position for each change in panel row/column. */ vec3_scale3(incr_c, prt, ps[1]); vec3_scale3(incr_r, pdn, ps[0]); /* Get position of upper left pixel on panel */ vec3_copy(ul_room, ic_room); vec3_scale3(tmp, incr_r, - pmat->ic[0]); vec3_add2(ul_room, tmp); vec3_scale3(tmp, incr_c, - pmat->ic[1]); vec3_add2(ul_room, tmp); /* drr_ray_trace uses p1 & p2, p1 is the camera, p2 is in the direction of the ray */ vec3_copy(p1, pmat->cam); /* Compute volume boundary box */ volume_limit_set (&vol_limit, vol); /* Convert all doubles to floats */ for (int i = 0; i < 3; i++) { p1_f[i] = (float)p1[i]; ul_room_f[i] = (float)ul_room[i]; incr_r_f[i] = (float)incr_r[i]; incr_c_f[i] = (float)incr_c[i]; vol_limit_f.dir[i] = vol_limit.dir[i]; vol_limit_f.lower_limit[i] = vol_limit.lower_limit[i]; vol_limit_f.upper_limit[i] = vol_limit.upper_limit[i]; } for (cl_uint i = 0; i < device_count; i++) { /* Copy global memory from host to device */ error = clEnqueueWriteBuffer(command_queue[i], g_dev_img[i], CL_FALSE, 0, img_size_device[i], (float*)proj->img + pixel_offset[i].y, 0, NULL, &img_event[i]); oclCheckError(error, CL_SUCCESS); /* Copy constant memory from host to device */ error |= clEnqueueWriteBuffer(command_queue[i], c_vol_dim[i], CL_FALSE, 0, 3 * sizeof(int), &vol->dim, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_img_dim[i], CL_FALSE, 0, sizeof(int2), &img_dim, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_offset[i], CL_FALSE, 0, float3_size, &vol->offset, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_pix_spacing[i], CL_FALSE, 0, float3_size, &vol->pix_spacing, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_vol_limits[i], CL_FALSE, 0, sizeof(Volume_limit_f), &vol_limit_f, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_p1[i], CL_FALSE, 0, float3_size, p1_f, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_ul_room[i], CL_FALSE, 0, float3_size, &ul_room_f, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_incr_r[i], CL_FALSE, 0, float3_size, incr_r_f, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_incr_c[i], CL_FALSE, 0, float3_size, incr_c_f, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_pixel_device[i], CL_FALSE, 0, sizeof(int4), &pixels_per_device[i], 0, NULL, NULL); oclCheckError(error, CL_SUCCESS); } /* Wait for all queues to finish */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Count device time */ for (cl_uint i = 0; i < device_count; i++) { img_total[i] += opencl_timer (img_event[i]); } /* Sets drr kernel arguments */ for (cl_uint i = 0; i < device_count; i++) { error |= clSetKernelArg(drr_kernel[i], 0, sizeof(cl_mem), (void *) &g_dev_vol[i]); error |= clSetKernelArg(drr_kernel[i], 1, sizeof(cl_mem), (void *) &g_dev_img[i]); error |= clSetKernelArg(drr_kernel[i], 2, sizeof(cl_mem), (void *) &c_vol_dim[i]); error |= clSetKernelArg(drr_kernel[i], 3, sizeof(cl_mem), (void *) &c_img_dim[i]); error |= clSetKernelArg(drr_kernel[i], 4, sizeof(cl_mem), (void *) &c_offset[i]); error |= clSetKernelArg(drr_kernel[i], 5, sizeof(cl_mem), (void *) &c_pix_spacing[i]); error |= clSetKernelArg(drr_kernel[i], 6, sizeof(cl_mem), (void *) &c_vol_limits[i]); error |= clSetKernelArg(drr_kernel[i], 7, sizeof(cl_mem), (void *) &c_p1[i]); error |= clSetKernelArg(drr_kernel[i], 8, sizeof(cl_mem), (void *) &c_ul_room[i]); error |= clSetKernelArg(drr_kernel[i], 9, sizeof(cl_mem), (void *) &c_incr_r[i]); error |= clSetKernelArg(drr_kernel[i], 10, sizeof(cl_mem), (void *) &c_incr_c[i]); error |= clSetKernelArg(drr_kernel[i], 11, sizeof(cl_mem), (void *) &c_pixel_device[i]); error |= clSetKernelArg(drr_kernel[i], 12, sizeof(float), &options->scale); error |= clSetKernelArg(drr_kernel[i], 13, sizeof(int), &options->output_format); error |= clSetKernelArg(drr_kernel[i], 14, sizeof(int), &preprocess_attenuation); error |= clSetKernelArg(drr_kernel[i], 15, sizeof(int), &options->exponential_mapping); error |= clSetKernelArg(drr_kernel[i], 16, sizeof(int), &pixel_offset[i].x); oclCheckError(error, CL_SUCCESS); } /* Wait for all queues to finish */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Invoke all drr kernels */ for (cl_uint i = 0; i < device_count; i++) { error = clEnqueueNDRangeKernel(command_queue[i], drr_kernel[i], 2, NULL, drr_global_work_size[i], drr_local_work_size[i], 0, NULL, &drr_event[i]); oclCheckError(error, CL_SUCCESS); } /* Wait for all kernels to finish */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Count kernel time */ for (cl_uint i = 0; i < device_count; i++) drr_total[i] += opencl_timer (drr_event[i]); /* Copy img/multispectral from device to host */ for (cl_uint i = 0; i < device_count; i++) { error = clEnqueueReadBuffer(command_queue[i], g_dev_img[i], CL_FALSE, 0, img_size_device[i], (float*)proj->img + pixel_offset[i].y, 0, NULL, &img_event[i]); oclCheckError(error, CL_SUCCESS); } /* Count device to host time */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Count device time */ for (cl_uint i = 0; i < device_count; i++) { img_total[i] += opencl_timer (img_event[i]); } } void create_matrix_and_drr_cl ( Volume* vol, Proj_image *proj, double cam[3], double tgt[3], double nrm[3], int a, Drr_options* options, int img_size, int float3_size, cl_mem *g_dev_vol, cl_mem *g_dev_img, cl_mem *c_vol_dim, cl_mem *c_img_dim, cl_mem *c_offset, cl_mem *c_pix_spacing, cl_mem *c_vol_limits, cl_mem *c_p1, cl_mem *c_ul_room, cl_mem *c_incr_r, cl_mem *c_incr_c, cl_mem *c_pixel_device, cl_kernel *drr_kernel, cl_ulong *drr_total, cl_ulong *img_total, size_t drr_global_work_size[MAX_GPU_COUNT][2], size_t drr_local_work_size[MAX_GPU_COUNT][2], int4 *pixels_per_device, int2 *pixel_offset, int *img_size_device) { char mat_fn[256]; char img_fn[256]; Proj_matrix *pmat = proj->pmat; double vup[3] = { options->vup[0], options->vup[1], options->vup[2] }; double sid = options->sid; Plm_timer* timer = plm_timer_create (); /* Set ic = image center (in pixels), and ps = pixel size (in mm) Note: pixels are numbered from 0 to ires-1 */ double ic[2] = { options->image_center[0], options->image_center[1] }; /* Set image resolution */ int ires[2] = { options->image_resolution[0], options->image_resolution[1] }; /* Set physical size of imager in mm */ int isize[2] = { options->image_size[0], options->image_size[1] }; /* Set pixel size in mm */ double ps[2] = { (double)isize[0]/(double)ires[0], (double)isize[1]/(double)ires[1] }; /* Create projection matrix */ sprintf(mat_fn, "%s%04d.txt", options->output_prefix, a); proj_matrix_set(pmat, cam, tgt, vup, sid, ic, ps, ires); if (options->output_format == OUTPUT_FORMAT_PFM) { sprintf(img_fn, "%s%04d.pfm", options->output_prefix, a); } else if (options->output_format == OUTPUT_FORMAT_PGM) { sprintf(img_fn, "%s%04d.pgm", options->output_prefix, a); } else { sprintf(img_fn, "%s%04d.raw", options->output_prefix, a); } drr_render_volume_perspective_cl(proj, vol, ps, options, img_size, float3_size, g_dev_vol, g_dev_img, c_vol_dim, c_img_dim, c_offset, c_pix_spacing, c_vol_limits, c_p1, c_ul_room, c_incr_r, c_incr_c, c_pixel_device, drr_kernel, drr_total, img_total, drr_global_work_size, drr_local_work_size, pixels_per_device, pixel_offset, img_size_device); plm_timer_start(timer); proj_image_save(proj, img_fn, mat_fn); printf("I/O time: %f sec\n", plm_timer_report(timer)); plm_timer_destroy (timer); } #endif /* commentout */ void drr_opencl_render_volume ( Volume* vol, Drr_options* options ) { /* Declare all global memory buffers */ cl_mem g_dev_vol[MAX_GPU_COUNT]; cl_mem g_dev_img[MAX_GPU_COUNT]; /* Delcare all constant memory buffers */ cl_mem c_vol_dim[MAX_GPU_COUNT]; cl_mem c_img_dim[MAX_GPU_COUNT]; cl_mem c_offset[MAX_GPU_COUNT]; cl_mem c_pix_spacing[MAX_GPU_COUNT]; cl_mem c_vol_limits[MAX_GPU_COUNT]; cl_mem c_p1[MAX_GPU_COUNT]; cl_mem c_ul_room[MAX_GPU_COUNT]; cl_mem c_incr_r[MAX_GPU_COUNT]; cl_mem c_incr_c[MAX_GPU_COUNT]; cl_mem c_pixel_device[MAX_GPU_COUNT]; /* Declare all kernels */ cl_kernel drr_kernel[MAX_GPU_COUNT]; /* Declare other OpenCL variables */ cl_event vol_event[MAX_GPU_COUNT]; cl_ulong drr_total[MAX_GPU_COUNT]; cl_ulong img_total[MAX_GPU_COUNT]; cl_ulong vol_total[MAX_GPU_COUNT]; cl_ulong preprocess_total[MAX_GPU_COUNT]; int4 pixels_per_device[MAX_GPU_COUNT]; int2 pixel_offset[MAX_GPU_COUNT]; int img_size_device[MAX_GPU_COUNT]; size_t program_length; size_t drr_local_work_size[MAX_GPU_COUNT][2]; size_t drr_global_work_size[MAX_GPU_COUNT][2]; size_t work_per_device[MAX_GPU_COUNT][3]; /* Calculate dynamic size of memory buffers */ int image_height = options->image_window[1] - options->image_window[0] + 1; int image_width = options->image_window[3] - options->image_window[2] + 1; int float3_size = 3 * sizeof(float); int vol_size = (vol->dim[0] * vol->dim[1] * vol->dim[2]) * sizeof(float); int img_size = image_height * image_width * sizeof(float); size_t work_total[3] = {image_width, image_height, 0}; Opencl_device ocl_dev; opencl_open_device (&ocl_dev); opencl_load_programs (&ocl_dev, "drr_opencl.cl"); #if defined (commentout) /* Calculate number of voxels per device */ divideWork (devices, device_count, 2, work_per_device, work_total); #endif Proj_image *proj; Proj_matrix *pmat; Plm_timer timer = plm_timer_create (); #if defined (commentout) /* Initialize timers */ for (cl_uint i = 0; i < device_count; i++) { drr_total[i] = 0; img_total[i] = 0; vol_total[i] = 0; } /* Allocate pixels to each device */ for (cl_uint i = 0; i < device_count; i++) { pixels_per_device[i].x = (int)work_per_device[i][0]; pixels_per_device[i].y = (int)work_per_device[i][1]; pixels_per_device[i].z = pixels_per_device[i].x * pixels_per_device[i].y; } /* Determine pixel offset on each device and memory buffer size */ for (cl_uint i = 0; i < device_count; i++) { pixel_offset[i].x = 0; pixel_offset[i].y = 0; for (cl_uint j = 0; j < i; j++) { pixel_offset[i].x += pixels_per_device[j].y; pixel_offset[i].y += pixels_per_device[j].z; } img_size_device[i] = pixels_per_device[i].z * sizeof(float); } for (cl_uint i = 0; i < device_count; i++) { /* Allocate global memory on all devices */ g_dev_vol[i] = clCreateBuffer(context[i], CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, vol_size, NULL, &error); oclCheckError(error, CL_SUCCESS); g_dev_img[i] = clCreateBuffer(context[i], CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, img_size_device[i], NULL, &error); oclCheckError(error, CL_SUCCESS); /* Allocate constant memory on all devices */ c_vol_dim[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, 3 * sizeof(int), NULL, &error); oclCheckError(error, CL_SUCCESS); c_img_dim[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int2), NULL, &error); oclCheckError(error, CL_SUCCESS); c_offset[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, float3_size, NULL, &error); oclCheckError(error, CL_SUCCESS); c_pix_spacing[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, float3_size, NULL, &error); oclCheckError(error, CL_SUCCESS); c_vol_limits[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, 3 * sizeof(Volume_limit), NULL, &error); oclCheckError(error, CL_SUCCESS); c_p1[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, float3_size, NULL, &error); oclCheckError(error, CL_SUCCESS); c_ul_room[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, float3_size, NULL, &error); oclCheckError(error, CL_SUCCESS); c_incr_r[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, float3_size, NULL, &error); oclCheckError(error, CL_SUCCESS); c_incr_c[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, float3_size, NULL, &error); oclCheckError(error, CL_SUCCESS); c_pixel_device[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int4), NULL, &error); oclCheckError(error, CL_SUCCESS); /* Create the drr kernel on all devices */ //drr_kernel[i] = clCreateKernel(program[i], "kernel_drr", &error); drr_kernel[0] = clCreateKernel(program, "kernel_drr", &error); oclCheckError(error, CL_SUCCESS); } /* Wait for all queues to finish */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Calculate the drr runtime environment */ for (cl_uint i = 0; i < device_count; i++) { drr_local_work_size[i][0] = 128; drr_local_work_size[i][1] = 1; drr_global_work_size[i][0] = shrRoundUp((int)drr_local_work_size[i][0], pixels_per_device[i].x); drr_global_work_size[i][1] = shrRoundUp((int)drr_local_work_size[i][1], pixels_per_device[i].y); } /* Copy memory from host to device */ for (cl_uint i = 0; i < device_count; i++) { error = clEnqueueWriteBuffer(command_queue[i], g_dev_vol[i], CL_FALSE, 0, vol_size, vol->img, 0, NULL, &vol_event[i]); oclCheckError(error, CL_SUCCESS); } /* Waits for volume to finish copying */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Count host to device time */ for (cl_uint i = 0; i < device_count; i++) vol_total[i] += opencl_timer (vol_event[i]); #if defined (DRR_PREPROCESS_ATTENUATION) /* Create variables for preprocess kernel and memory timing */ size_t preprocess_local_work_size[MAX_GPU_COUNT]; size_t preprocess_global_work_size[MAX_GPU_COUNT]; cl_event preprocess_event[MAX_GPU_COUNT]; /* Initialize preprocess timers */ for (cl_uint i = 0; i < device_count; i++) preprocess_total[i] = 0; if (vol->pix_type != PT_FLOAT) { float *old_img = (float*)vol->img; float *new_img = (float*)malloc(vol->npix * sizeof(float)); for (int i = 0; i < vol->npix; i++) { new_img[i] = old_img[i]; } vol->pix_type = PT_FLOAT; free(vol->img); vol->img = new_img; /* Update global memory from host to device */ for (cl_uint i = 0; i < device_count; i++) { error = clEnqueueWriteBuffer(command_queue[i], g_dev_vol[i], CL_FALSE, 0, vol_size, vol->img, 0, NULL, &vol_event[i]); oclCheckError(error, CL_SUCCESS); } /* Waits for volume to finish copying */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Count host to device time */ for (cl_uint i = 0; i < device_count; i++) vol_total[i] += opencl_timer (vol_event[i]); } /* Creates the kernel object */ cl_kernel preprocess_kernel[MAX_GPU_COUNT]; for (cl_uint i = 0; i < device_count; i++) { //preprocess_kernel[i] = clCreateKernel(program[i], "preprocess_attenuation_cl", &error); preprocess_kernel[i] = clCreateKernel (program, "preprocess_attenuation_cl", &error); oclCheckError(error, CL_SUCCESS); } /* Sets preprocess kernel arguments */ for (cl_uint i = 0; i < device_count; i++) { error = clSetKernelArg(preprocess_kernel[i], 0, sizeof(cl_mem), (void *) &g_dev_vol[i]); error |= clSetKernelArg(preprocess_kernel[i], 1, sizeof(int), &vol->npix); oclCheckError(error, CL_SUCCESS); } /* Wait for all queues to finish */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Enqueue kernel and execute */ for (cl_uint i=0; i < device_count; i++) { preprocess_local_work_size[i] = 512; preprocess_global_work_size[i] = shrRoundUp((int)preprocess_local_work_size[i], vol->npix); } for (cl_uint i = 0; i < device_count; i++) { error = clEnqueueNDRangeKernel(command_queue[i], preprocess_kernel[i], 1, NULL, &preprocess_global_work_size[i], &preprocess_local_work_size[i], 0, NULL, &preprocess_event[i]); oclCheckError(error, CL_SUCCESS); } /* Waits for queue to finish */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Count kernel time */ for (cl_uint i = 0; i < device_count; i++) preprocess_total[i] += opencl_timer (preprocess_event[i]); /* Release kernels and memory */ for (cl_uint i = 0; i < device_count; i++) { clReleaseKernel(preprocess_kernel[i]); } #endif /* DRR_PREPROCESS_ATTENUATION */ /* tgt is isocenter */ double tgt[3] = { options->isocenter[0], options->isocenter[1], options->isocenter[2] }; plm_timer_start (timer); /* Allocate data for image and matrix */ proj = proj_image_create(); proj_image_create_pmat(proj); proj_image_create_img(proj, options->image_resolution); pmat = proj->pmat; /* If nrm was specified, only create a single image */ if (options->have_nrm) { double cam[3]; double nrm[3] = { options->nrm[0], options->nrm[1], options->nrm[2] }; /* Make sure nrm is normal */ vec3_normalize1(nrm); /* Place camera at distance "sad" from the volume isocenter */ cam[0] = tgt[0] + options->sad * nrm[0]; cam[1] = tgt[1] + options->sad * nrm[1]; cam[2] = tgt[2] + options->sad * nrm[2]; create_matrix_and_drr_cl(vol, proj, cam, tgt, nrm, 0, options, img_size, float3_size, g_dev_vol, g_dev_img, c_vol_dim, c_img_dim, c_offset, c_pix_spacing, c_vol_limits, c_p1, c_ul_room, c_incr_r, c_incr_c, c_pixel_device, drr_kernel, drr_total, img_total, drr_global_work_size, drr_local_work_size, pixels_per_device, pixel_offset, img_size_device); } else { /* Otherwise, loop through camera angles */ for (int a = 0; a < options->num_angles; a++) { double angle = a * options->angle_diff; double cam[3]; double nrm[3]; shrLog("Rendering DRR %d\n", a); /* Place camera at distance "sad" from the volume isocenter */ cam[0] = tgt[0] + options->sad * cos(angle); cam[1] = tgt[1] - options->sad * sin(angle); cam[2] = tgt[2]; /* Compute normal vector */ vec3_sub3(nrm, tgt, cam); vec3_normalize1(nrm); create_matrix_and_drr_cl(vol, proj, cam, tgt, nrm, a, options, img_size, float3_size, g_dev_vol, g_dev_img, c_vol_dim, c_img_dim, c_offset, c_pix_spacing, c_vol_limits, c_p1, c_ul_room, c_incr_r, c_incr_c, c_pixel_device, drr_kernel, drr_total, img_total, drr_global_work_size, drr_local_work_size, pixels_per_device, pixel_offset, img_size_device); } } proj_image_destroy(proj); for (cl_uint i = 0; i < device_count; i++) { /* Release kernels */ clReleaseKernel(drr_kernel[i]); /* Release constant memory buffers */ clReleaseMemObject(c_pixel_device[i]); clReleaseMemObject(c_incr_c[i]); clReleaseMemObject(c_incr_r[i]); clReleaseMemObject(c_ul_room[i]); clReleaseMemObject(c_p1[i]); clReleaseMemObject(c_vol_limits[i]); clReleaseMemObject(c_pix_spacing[i]); clReleaseMemObject(c_offset[i]); clReleaseMemObject(c_img_dim[i]); clReleaseMemObject(c_vol_dim[i]); /* Release global memory buffers */ clReleaseMemObject(g_dev_img[i]); clReleaseMemObject(g_dev_vol[i]); } /***************************************************************/ /**************************************************************** * STEP 4: Perform timing * ****************************************************************/ float overall_runtime = 0; for (cl_uint i = 0; i < device_count; i++) { float drr_kernel_runtime = drr_total[i] * 1.0e-6f; float preprocess_kernel_runtime = preprocess_total[i] * 1.0e-6f; float img_copy_runtime = img_total[i] * 1.0e-6f; float vol_copy_runtime = vol_total[i] * 1.0e-6f; float total_runtime = (drr_kernel_runtime + preprocess_kernel_runtime + img_copy_runtime + vol_copy_runtime) * 1.0e-3f; overall_runtime += total_runtime; shrLog("Device %d: %s\n", i, device_name[i]); shrLog("\tDRR Kernel run time: %f ms\n", drr_kernel_runtime); shrLog("\tHu Kernel run time: %f ms\n", preprocess_kernel_runtime); shrLog("\tImage host/device & device/host copy run time: %f ms\n", img_copy_runtime); shrLog("\tVolume host to device copy run time: %f ms\n", vol_copy_runtime); shrLog("\tTotal run time: %f s\n\n", total_runtime); } /***************************************************************/ /**************************************************************** * STEP 4: Cleanup OpenCL and finish * ****************************************************************/ for (cl_uint i = 0; i < device_count; i++) { //clReleaseProgram(program[i]); clReleaseProgram(program); clReleaseCommandQueue(command_queue[i]); clReleaseContext(context[i]); } shrLog("Done DRR_OPENCL...\n\n"); shrLog("Total OpenCL run time: %f s\n", overall_runtime); printf("Total run time: %g s\n", plm_timer_report(timer)); plm_timer_destroy (timer); #endif /* commentout */ } fdk_opencl_old.cxx000077500000000000000000000521761321604176500347600ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/historical/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Title : OpenCL implementation of FDK Algorithm Authors : Atapattu, Chatura Houck, Dustin O'Brien, Ronald Partel, Michael Description : This is an OpenCL implementation of the FDK algorithm used to convert 2D cone-beam images into a 3D volumetric image Created : 11/01/2009 Modified : ongoing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /******************* * C #includes * *******************/ #include #include #include #include #include "plmbase.h" /******************* * OPENCL #includes * *****************/ #include "opencl_util.h" /******************* * FDK #includes * *******************/ #include "autotune_opencl.h" #include "fdk_opencl_p.h" #include "fdk_opts.h" #include "fdk_util.h" #include "plm_math.h" #include "opencl_util_nvidia.h" #include "proj_image.h" #include "proj_image_dir.h" #include "volume.h" #undef MAX_GPU_COUNT #define MAX_GPU_COUNT 1 /* * Summary: This OpenCL stub function performs most of the IO and flow control. The actual back projection is performed by the OpenCL kernel "fdk_kernel()" * Parameters: Pointer to volume and runtime options * Return: Float of runtime */ void OPENCL_reconstruct_conebeam_and_convert_to_hu (Volume *vol, Proj_image_dir *proj_dir, Fdk_options *options) { int image_num, num_images, matrix_size, vol_size; float scale, overall_runtime, fdk_kernel_runtime, hu_kernel_runtime, img_copy_runtime, vol_copy_runtime, total_runtime; char device_name[MAX_GPU_COUNT][256]; /* Device names */ Proj_image *cbi; kernel_args_fdk *kargs; /* Declare global memory */ cl_mem g_dev_vol[MAX_GPU_COUNT]; /* Declare image/texture memory */ cl_mem t_dev_img[MAX_GPU_COUNT]; /* Declare constant memory */ cl_mem c_dev_matrix[MAX_GPU_COUNT]; cl_mem c_nrm[MAX_GPU_COUNT]; cl_mem c_vol_offset[MAX_GPU_COUNT]; cl_mem c_vol_pix_spacing[MAX_GPU_COUNT]; cl_mem c_vol_dim[MAX_GPU_COUNT]; cl_mem c_ic[MAX_GPU_COUNT]; cl_mem c_img_dim[MAX_GPU_COUNT]; cl_mem c_sad[MAX_GPU_COUNT]; cl_mem c_scale[MAX_GPU_COUNT]; cl_mem c_voxel_device[MAX_GPU_COUNT]; /* Declare OpenCL kernels */ cl_kernel fdk_kernel[MAX_GPU_COUNT]; cl_kernel hu_kernel[MAX_GPU_COUNT]; /* Declare other OpenCL variables */ cl_event fdk_event[MAX_GPU_COUNT], hu_event[MAX_GPU_COUNT], img_event[MAX_GPU_COUNT], vol_event[MAX_GPU_COUNT]; cl_ulong fdk_total[MAX_GPU_COUNT], hu_total[MAX_GPU_COUNT], img_total[MAX_GPU_COUNT], vol_total[MAX_GPU_COUNT]; size_t fdk_local_work_size[MAX_GPU_COUNT][3]; size_t fdk_global_work_size[MAX_GPU_COUNT][3]; size_t hu_local_work_size[MAX_GPU_COUNT]; size_t hu_global_work_size[MAX_GPU_COUNT]; cl_context context[MAX_GPU_COUNT]; /* Context from device */ cl_command_queue command_queue[MAX_GPU_COUNT]; /* Command Queue from Context */ cl_program program[MAX_GPU_COUNT]; /* Program from .cl file */ cl_int error; cl_uint device_count; /* Number of devices available */ cl_device_id device; /* Object for individual device in 'for loop' */ cl_device_id *devices; /* Pointer to devices */ cl_platform_id platform; cl_image_format img_format; size_t program_length, img_row_pitch; size_t work_per_device[MAX_GPU_COUNT][3]; size_t work_total[3] = {vol->dim[0], vol->dim[1], vol->dim[2]}; int4 voxels_per_device[MAX_GPU_COUNT]; int2 voxel_offset[MAX_GPU_COUNT]; /**************************************************************** * STEP 1: Set global variables and algorithm parameters * ****************************************************************/ /* Set logfile name and start logs */ shrSetLogFileName ("fdk_opencl.txt"); shrLog("Starting FDK_OPENCL...\n\n"); /* Structure for passing arugments to kernel: (See fdk_cuda.h) */ kargs = (kernel_args_fdk *) malloc(sizeof(kernel_args_fdk)); /* Calculate the scale */ num_images = proj_dir->num_proj_images; image_num = 1 + (options->last_img - options->first_img) / options->skip_img; scale = (float)(sqrt(3.0)/(double)image_num); scale = scale * options->scale; /* Load static kernel arguments */ kargs->scale = scale; kargs->vol_offset.x = vol->offset[0]; kargs->vol_offset.y = vol->offset[1]; kargs->vol_offset.z = vol->offset[2]; kargs->vol_dim.x = vol->dim[0]; kargs->vol_dim.y = vol->dim[1]; kargs->vol_dim.z = vol->dim[2]; kargs->vol_pix_spacing.x = vol->pix_spacing[0]; kargs->vol_pix_spacing.y = vol->pix_spacing[1]; kargs->vol_pix_spacing.z = vol->pix_spacing[2]; /* Retrieve 2D image to get dimensions */ cbi = proj_image_dir_load_image(proj_dir, 0); /* Verify that dimensions are within limits */ if (cbi->dim[0] > CL_DEVICE_IMAGE2D_MAX_WIDTH || cbi->dim[1] > CL_DEVICE_IMAGE2D_MAX_HEIGHT) { shrLog("Image dimensions too large for %s\n", CL_DEVICE_NAME); shrLog("Maximum height and width: %d x %d\n", CL_DEVICE_IMAGE2D_MAX_HEIGHT, CL_DEVICE_IMAGE2D_MAX_WIDTH); shrLog("Image height and width: %d x %d\n", cbi->dim[1], cbi->dim[0]); shrLog("Exiting...\n\n"); exit(-1); } /* Calculate dynamic size of memory buffers */ vol_size = vol->npix * sizeof(float); matrix_size = 12 * sizeof(float); int img_dim[2] = {cbi->dim[0], cbi->dim[1]}; /* Free cbi image */ proj_image_destroy(cbi); /* Set parameters for texture/image memory */ size_t img_origin[3] = {0, 0, 0}; size_t img_region[3] = {img_dim[0], img_dim[1], 1}; img_row_pitch = img_dim[0] * sizeof(float); img_format.image_channel_order = CL_R; img_format.image_channel_data_type = CL_FLOAT; /***************************************************************/ /**************************************************************** * STEP 2: Setup OpenCL * ****************************************************************/ /* Get the OpenCL platform */ error = oclGetPlatformID(&platform); oclCheckError(error, CL_SUCCESS); /* Get devices of type GPU */ error = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, NULL, &device_count); oclCheckError(error, CL_SUCCESS); /* Make sure using no more than the maximum number of GPUs */ if (device_count > MAX_GPU_COUNT) device_count = MAX_GPU_COUNT; devices = (cl_device_id *)malloc(device_count * sizeof(cl_device_id)); error = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, device_count, devices, NULL); oclCheckError(error, CL_SUCCESS); /* Create context properties */ cl_context_properties properties[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0}; /* Calculate number of voxels per device */ divideWork(devices, device_count, 3, work_per_device, work_total); shrLog("Using %d device(s):\n", device_count); /* Create context and command queue for each device */ for (cl_uint i = 0; i < device_count; i++) { /* Context */ context[i] = clCreateContext(properties, 1, &devices[i], NULL, NULL, &error); oclCheckError(error, CL_SUCCESS); /* Device info */ device = oclGetDev(context[i], 0); clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_name[i]), device_name[i], NULL); oclCheckError(error, CL_SUCCESS); shrLog("\tDevice %d: %s handling %d x %d x %d voxels\n", i, device_name[i], work_per_device[i][0], work_per_device[i][1], work_per_device[i][2]); /* Command queue */ command_queue[i] = clCreateCommandQueue(context[i], device, CL_QUEUE_PROFILING_ENABLE, &error); oclCheckError(error, CL_SUCCESS); } shrLog("\n%u voxels in volume\n", vol->npix); shrLog("%u projections to process\n", 1+(options->last_img - options->first_img) / options->skip_img); shrLog("%u total operations\n", vol->npix * (1+(options->last_img - options->first_img) / options->skip_img)); shrLog("========================================\n\n"); /* Program Setup */ char* source_path = shrFindFilePath("fdk_opencl.cl", ""); oclCheckError(source_path != NULL, shrTRUE); char *source = oclLoadProgSource(source_path, "", &program_length); oclCheckError(source != NULL, shrTRUE); /* Create the program */ for (cl_uint i = 0; i < device_count; i++) { program[i] = clCreateProgramWithSource(context[i], 1, (const char **)&source, &program_length, &error); oclCheckError(error, CL_SUCCESS); /* Build the program */ error = clBuildProgram(program[i], 0, NULL, NULL, NULL, NULL); if (error != CL_SUCCESS) { /* Write out standard error, Build Log and PTX, then return error */ shrLogEx(LOGBOTH | ERRORMSG, error, STDERROR); oclLogBuildInfo(program[i], oclGetFirstDev(context[i])); oclLogPtx(program[i], oclGetFirstDev(context[i]), "fdk_opencl.ptx"); } } /***************************************************************/ /**************************************************************** * STEP 2: Perform FDK algorithm on each device * ****************************************************************/ /* Allocate voxels to each device */ for (cl_uint i = 0; i < device_count; i++) { voxels_per_device[i].x = (int)work_per_device[i][0]; voxels_per_device[i].y = (int)work_per_device[i][1]; voxels_per_device[i].z = (int)work_per_device[i][2]; voxels_per_device[i].w = voxels_per_device[i].x * voxels_per_device[i].y * voxels_per_device[i].z; } /* Determine voxel offset on each device */ for (cl_uint i = 0; i < device_count; i++) { voxel_offset[i].x = 0; voxel_offset[i].y = 0; for (cl_uint j = 0; j < i; j++) { voxel_offset[i].x += voxels_per_device[j].z; voxel_offset[i].y += voxels_per_device[j].w; } } /* Calculate local and global work sizes on each device */ for (cl_uint i = 0; i < device_count; i++) { fdk_local_work_size[i][0] = 512; fdk_local_work_size[i][1] = 1; fdk_local_work_size[i][2] = 1; fdk_global_work_size[i][0] = shrRoundUp((int)fdk_local_work_size[i][0], voxels_per_device[i].x); fdk_global_work_size[i][1] = shrRoundUp((int)fdk_local_work_size[i][1], voxels_per_device[i].y); fdk_global_work_size[i][2] = shrRoundUp((int)fdk_local_work_size[i][2], voxels_per_device[i].z); hu_local_work_size[i] = 512; hu_global_work_size[i] = shrRoundUp((int)hu_local_work_size[i], voxels_per_device[i].w); } for (cl_uint i = 0; i < device_count; i++) { /* Create volume buffer */ g_dev_vol[i] = clCreateBuffer(context[i], CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, voxels_per_device[i].w * sizeof(float), NULL, &error); oclCheckError(error, CL_SUCCESS); /* Create texture/image memory buffers on device */ t_dev_img[i] = clCreateImage2D(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &img_format, img_dim[0], img_dim[1], 0, NULL, &error); oclCheckError(error, CL_SUCCESS); /* Create constant memory buffers on device */ c_dev_matrix[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, matrix_size, NULL, &error); oclCheckError(error, CL_SUCCESS); c_nrm[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(float4), NULL, &error); oclCheckError(error, CL_SUCCESS); c_vol_offset[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(float4), NULL, &error); oclCheckError(error, CL_SUCCESS); c_vol_pix_spacing[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(float4), NULL, &error); oclCheckError(error, CL_SUCCESS); c_vol_dim[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int4), NULL, &error); oclCheckError(error, CL_SUCCESS); c_ic[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(float2), NULL, &error); oclCheckError(error, CL_SUCCESS); c_img_dim[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int2), NULL, &error); oclCheckError(error, CL_SUCCESS); c_sad[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(float), NULL, &error); oclCheckError(error, CL_SUCCESS); c_scale[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(float), NULL, &error); oclCheckError(error, CL_SUCCESS); c_voxel_device[i] = clCreateBuffer(context[i], CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int4), NULL, &error); oclCheckError(error, CL_SUCCESS); } /* Wait for all queues to finish */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Creates the kernel objects */ for (cl_uint i = 0; i < device_count; i++) { fdk_kernel[i] = clCreateKernel(program[i], "kernel_fdk", &error); //fdk_kernel[i] = clCreateKernel(program[i], "kernel_fdk_bilinear", &error); //fdk_kernel[i] = clCreateKernel(program[i], "kernel_fdk_bicubic", &error); oclCheckError(error, CL_SUCCESS); hu_kernel[i] = clCreateKernel(program[i], "convert_to_hu_cl", &error); oclCheckError(error, CL_SUCCESS); } /* Initialize all timers */ for (cl_uint i = 0; i < device_count; i++) { fdk_total[i] = 0; hu_total[i] = 0; img_total[i] = 0; vol_total[i] = 0; } /* Project each image into the volume one at a time */ for (image_num = options->first_img; image_num < proj_dir->num_proj_images; image_num++) { /* Load the current image and properties */ cbi = proj_image_dir_load_image(proj_dir, image_num); if (options->filter == FDK_FILTER_TYPE_RAMP) proj_image_filter (cbi); /* Load dynamic kernel arguments */ kargs->img_dim.x = cbi->dim[0]; kargs->img_dim.y = cbi->dim[1]; kargs->ic.x = cbi->pmat->ic[0]; kargs->ic.y = cbi->pmat->ic[1]; kargs->nrm.x = cbi->pmat->nrm[0]; kargs->nrm.y = cbi->pmat->nrm[1]; kargs->nrm.z = cbi->pmat->nrm[2]; kargs->sad = cbi->pmat->sad; kargs->sid = cbi->pmat->sid; for (int j = 0; j < 12; j++) kargs->matrix[j] = (float)cbi->pmat->matrix[j]; /* Loop to copy data from host to each device */ for (cl_uint i = 0; i < device_count; i++) { /* Copy texture/image memory from host to device */ error = clEnqueueWriteImage(command_queue[i], t_dev_img[i], CL_FALSE, img_origin, img_region, img_row_pitch, 0, cbi->img, 0, NULL, &img_event[i]); oclCheckError(error, CL_SUCCESS); /* Copy constant memory from host to device */ error = clEnqueueWriteBuffer(command_queue[i], c_dev_matrix[i], CL_FALSE, 0, matrix_size, &kargs->matrix, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_nrm[i], CL_FALSE, 0, sizeof(float4), &kargs->nrm, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_vol_offset[i], CL_FALSE, 0, sizeof(float4), &kargs->vol_offset, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_vol_pix_spacing[i], CL_FALSE, 0, sizeof(float4), &kargs->vol_pix_spacing, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_vol_dim[i], CL_FALSE, 0, sizeof(int4), &kargs->vol_dim, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_ic[i], CL_FALSE, 0, sizeof(float2), &kargs->ic, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_img_dim[i], CL_FALSE, 0, sizeof(int2), &kargs->img_dim, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_sad[i], CL_FALSE, 0, sizeof(float), &kargs->sad, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_scale[i], CL_FALSE, 0, sizeof(float), &kargs->scale, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue[i], c_voxel_device[i], CL_FALSE, 0, sizeof(int4), &voxels_per_device[i], 0, NULL, NULL); oclCheckError(error, CL_SUCCESS); } /* Wait for all queues to finish */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Count host to device time */ for (cl_uint i = 0; i < device_count; i++) img_total[i] += opencl_timer (img_event[i]); /* Set fdk kernel arguments */ for (cl_uint i = 0; i < device_count; i++) { error |= clSetKernelArg(fdk_kernel[i], 0, sizeof(cl_mem), (void *) &g_dev_vol[i]); error |= clSetKernelArg(fdk_kernel[i], 1, sizeof(cl_mem), (void *) &t_dev_img[i]); error |= clSetKernelArg(fdk_kernel[i], 2, sizeof(cl_mem), (void *) &c_dev_matrix[i]); error |= clSetKernelArg(fdk_kernel[i], 3, sizeof(cl_mem), (void *) &c_nrm[i]); error |= clSetKernelArg(fdk_kernel[i], 4, sizeof(cl_mem), (void *) &c_vol_offset[i]); error |= clSetKernelArg(fdk_kernel[i], 5, sizeof(cl_mem), (void *) &c_vol_pix_spacing[i]); error |= clSetKernelArg(fdk_kernel[i], 6, sizeof(cl_mem), (void *) &c_vol_dim[i]); error |= clSetKernelArg(fdk_kernel[i], 7, sizeof(cl_mem), (void *) &c_ic[i]); error |= clSetKernelArg(fdk_kernel[i], 8, sizeof(cl_mem), (void *) &c_img_dim[i]); error |= clSetKernelArg(fdk_kernel[i], 9, sizeof(cl_mem), (void *) &c_sad[i]); error |= clSetKernelArg(fdk_kernel[i], 10, sizeof(cl_mem), (void *) &c_scale[i]); error |= clSetKernelArg(fdk_kernel[i], 11, sizeof(cl_mem), (void *) &c_voxel_device[i]); error |= clSetKernelArg(fdk_kernel[i], 12, sizeof(int), &voxel_offset[i].x); oclCheckError(error, CL_SUCCESS); } /* Wait for all queues to finish */ for (cl_uint i = 0; i < device_count; i++) { clFinish(command_queue[i]); } /* Invoke all fdk kernels */ for (cl_uint i = 0; i < device_count; i++) { error = clEnqueueNDRangeKernel(command_queue[i], fdk_kernel[i], 3, NULL, fdk_global_work_size[i], fdk_local_work_size[i], 0, NULL, &fdk_event[i]); oclCheckError(error, CL_SUCCESS); } /* Wait for fdk kernel to finish */ for (cl_uint i = 0; i < device_count; i++) { clFinish(command_queue[i]); } /* Count fdk kernel time */ for (cl_uint i = 0; i < device_count; i++) { fdk_total[i] += opencl_timer (fdk_event[i]); } /* Free the current image */ proj_image_destroy(cbi); } /* Sets hu kernel arguments */ for (cl_uint i = 0; i < device_count; i++) { error = clSetKernelArg(hu_kernel[i], 0, sizeof(cl_mem), (void *) &g_dev_vol[i]); error |= clSetKernelArg(hu_kernel[i], 1, sizeof(int), &voxels_per_device[i].w); oclCheckError(error, CL_SUCCESS); } /* Wait for all queues to finish */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Invoke all hu kernels */ for (cl_uint i = 0; i < device_count; i++) { error = clEnqueueNDRangeKernel(command_queue[i], hu_kernel[i], 1, NULL, &hu_global_work_size[i], &hu_local_work_size[i], 0, NULL, &hu_event[i]); oclCheckError(error, CL_SUCCESS); } /* Waits for hu kernel to finish */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Count hu kernel time */ for (cl_uint i = 0; i < device_count; i++) hu_total[i] += opencl_timer (hu_event[i]); /* Copy reconstructed volume from device to host */ for (cl_uint i = 0; i < device_count; i++) { error = clEnqueueReadBuffer(command_queue[i], g_dev_vol[i], CL_FALSE, 0, voxels_per_device[i].w * sizeof(float), (float*)vol->img + voxel_offset[i].y, 0, NULL, &vol_event[i]); oclCheckError(error, CL_SUCCESS); } /* Waits for volume to finish copying */ for (cl_uint i = 0; i < device_count; i++) clFinish(command_queue[i]); /* Count device to host time */ for (cl_uint i = 0; i < device_count; i++) vol_total[i] += opencl_timer (vol_event[i]); for (cl_uint i = 0; i < device_count; i++) { /* Release kernels */ clReleaseKernel(fdk_kernel[i]); clReleaseKernel(hu_kernel[i]); /* Release constant memory buffers */ clReleaseMemObject(c_voxel_device[i]); clReleaseMemObject(c_scale[i]); clReleaseMemObject(c_sad[i]); clReleaseMemObject(c_img_dim[i]); clReleaseMemObject(c_ic[i]); clReleaseMemObject(c_vol_dim[i]); clReleaseMemObject(c_vol_pix_spacing[i]); clReleaseMemObject(c_vol_offset[i]); clReleaseMemObject(c_nrm[i]); clReleaseMemObject(c_dev_matrix[i]); /* Release texture/image memory buffers */ clReleaseMemObject(t_dev_img[i]); /* Release global memory buffers */ clReleaseMemObject(g_dev_vol[i]); } /***************************************************************/ /**************************************************************** * STEP 3: Perform timing * ****************************************************************/ overall_runtime = 0; for (cl_uint i = 0; i < device_count; i++) { fdk_kernel_runtime = fdk_total[i] * 1.0e-6f; hu_kernel_runtime = hu_total[i] * 1.0e-6f; img_copy_runtime = img_total[i] * 1.0e-6f; vol_copy_runtime = vol_total[i] * 1.0e-6f; total_runtime = (fdk_kernel_runtime + hu_kernel_runtime + img_copy_runtime + vol_copy_runtime) * 1.0e-3f; overall_runtime += total_runtime; shrLog("Device %d: %s\n", i, device_name[i]); shrLog("\tFDK Kernel run time: %f ms\n", fdk_kernel_runtime); shrLog("\tHu Kernel run time: %f ms\n", hu_kernel_runtime); shrLog("\tCBI host to device copy run time: %f ms\n", img_copy_runtime); shrLog("\tVolume device to host copy run time: %f ms\n", vol_copy_runtime); shrLog("\tTotal run time: %f s\n\n", total_runtime); } /***************************************************************/ /**************************************************************** * STEP 4: Cleanup OpenCL and finish * ****************************************************************/ for (cl_uint i = 0; i < device_count; i++) { clReleaseProgram(program[i]); clReleaseCommandQueue(command_queue[i]); clReleaseContext(context[i]); } shrLog("Done FDK_OPENCL...\n\n"); shrLog("Total OpenCL run time: %f s\n\n", overall_runtime); } plmreconstruct.h000066400000000000000000000012561321604176500323540ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifdef __PLM_MASTER_HEADER__ #error "plmreconstruct.h cannot be #included by another plastimatch header!" #else #define __PLM_MASTER_HEADER__ #ifndef _plmreconstruct_h_ #define _plmreconstruct_h_ #include "plmreconstruct_config.h" #include "bowtie_correction.h" #include "drr.h" #include "drr_trilin.h" #include "fdk.h" #include "fdk_util.h" #endif /* #ifndef _plmreconstruct_h_ */ #undef __PLM_MASTER_HEADER__ #endif /* #ifdef __PLM_MASTER_HEADER__ */ plmreconstruct_config.h.in000066400000000000000000000021621321604176500343030ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/reconstruct/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plmreconstruct_config_h__ #define __plmreconstruct_config_h__ #include "plm_config.h" #if ((defined(_WIN32) || defined(WIN32)) && (defined (PLM_BUILD_SHARED_LIBS))) # ifdef plmreconstruct_EXPORTS # define PLMRECONSTRUCT_C_API EXTERNC __declspec(dllexport) # define PLMRECONSTRUCT_API __declspec(dllexport) # else # define PLMRECONSTRUCT_C_API EXTERNC __declspec(dllimport) # define PLMRECONSTRUCT_API __declspec(dllimport) # endif # ifdef plmreconstructcuda_EXPORTS # define PLMRECONSTRUCTCUDA_C_API EXTERNC __declspec(dllexport) # define PLMRECONSTRUCTCUDA_API __declspec(dllexport) # else # define PLMRECONSTRUCTCUDA_C_API EXTERNC __declspec(dllimport) # define PLMRECONSTRUCTCUDA_API __declspec(dllimport) # endif #else # define PLMRECONSTRUCTCUDA_C_API EXTERNC # define PLMRECONSTRUCTCUDA_API # define PLMRECONSTRUCT_C_API EXTERNC # define PLMRECONSTRUCT_API #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/000077500000000000000000000000001321604176500264435ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/CMakeLists.txt000066400000000000000000000132541321604176500312100ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_register) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/plmregister_config.h.in ${CMAKE_BINARY_DIR}/plmregister_config.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (BEFORE ${CMAKE_CURRENT_BINARY_DIR}) if (CUDA_FOUND) add_subdirectory (cuda) include_directories (BEFORE "${CMAKE_CURRENT_SOURCE_DIR}/cuda") endif () ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (PLMREGISTER_LIBRARY_SRC bspline.cxx bspline.h bspline_loop.txx bspline_landmarks.cxx bspline_landmarks.h bspline_gm.cxx bspline_gm.h bspline_gm.txx bspline_mi.cxx bspline_mi.h bspline_mi.txx bspline_mse.cxx bspline_mse.h bspline_mse.txx bspline_optimize.cxx bspline_optimize.h bspline_optimize_lbfgsb.cxx bspline_optimize_lbfgsb.h bspline_optimize_liblbfgs.cxx bspline_optimize_liblbfgs.h bspline_optimize_nlopt.cxx bspline_optimize_nlopt.h bspline_optimize_steepest.cxx bspline_optimize_steepest.h bspline_parms.cxx bspline_parms.h bspline_score.cxx bspline_score.h bspline_stage.cxx bspline_stage.h bspline_state.cxx bspline_state.h bspline_regularize.cxx bspline_regularize.h bspline_regularize_analytic.cxx bspline_regularize_analytic.h bspline_regularize_numeric.cxx bspline_regularize_numeric.h bspline_regularize_semi_analytic.cxx demons.cxx demons.h demons_cpu.cxx demons_opencl_p.h demons_state.cxx demons_state.h gpuit_demons.cxx gpuit_demons.h groupwise_parms.cxx groupwise_parms.h histogram.cxx histogram.h itk_align_center.cxx itk_align_center.h itk_demons.cxx itk_demons.h itk_demons_registration_filter.h itk_demons_util.cxx itk_demons_util.h itk_diff_demons.cxx itk_diff_demons.h itk_fsf_demons.cxx itk_fsf_demons.h itk_log_demons.cxx itk_log_demons.h itk_sym_log_demons.cxx itk_sym_log_demons.h itk_optimizer.cxx itk_optimizer.h itk_registration.cxx itk_registration.h itk_registration_observer.cxx itk_registration_private.h itk_sym_log_demons.h itk_tps.cxx itk_tps.h joint_histogram.cxx joint_histogram.h landmark_warp.cxx landmark_warp.h metric_parms.cxx metric_parms.h metric_state.cxx metric_state.h process_parms.cxx process_parms.h rbf_cluster.cxx rbf_cluster.h rbf_gauss.cxx rbf_gauss.h rbf_wendland.cxx rbf_wendland.h registration.cxx registration.h registration_data.cxx registration_data.h registration_parms.cxx registration_parms.h registration_resample.cxx registration_resample.h registration_similarity_data.h registration_util.cxx registration_util.h shared_parms.cxx shared_parms.h similarity_metric_type.cxx similarity_metric_type.h stage_parms.cxx stage_parms.h translation_grid_search.cxx translation_grid_search.h translation_mi.cxx translation_mi.h translation_mse.cxx translation_mse.h ) if (OPENCL_FOUND) set (PLMREGISTER_LIBRARY_SRC ${PLMREGISTER_LIBRARY_SRC} demons_opencl.cxx ) endif () if (PLM_BUILD_VISCOUS) set (PLMREGISTER_LIBRARY_SRC ${PLMREGISTER_LIBRARY_SRC} viscous.cxx ) endif () ##----------------------------------------------------------------------------- ## LIBRARY DEPENDENCIES ##----------------------------------------------------------------------------- set (PLMREGISTER_LIBRARY_DEPENDENCIES) set (PLMREGISTER_LIBRARY_DEPENDENCIES ${PLMREGISTER_LIBRARY_DEPENDENCIES} ${LIBLBFGS_LIBRARIES} plmbase plmsys plmutil ) if (CUDA_FOUND) set (PLMREGISTER_LIBRARY_DEPENDENCIES ${PLMREGISTER_LIBRARY_DEPENDENCIES} plmcuda ) set (PLMREGISTER_LIBRARY_DEPENDENCIES ${PLMREGISTER_LIBRARY_DEPENDENCIES} plmregistercuda ) endif () if (OPENCL_FOUND) set (PLMREGISTER_LIBRARY_DEPENDENCIES ${PLMREGISTER_LIBRARY_DEPENDENCIES} plmopencl ) endif () if (NLOPT_FOUND) set (PLMREGISTER_LIBRARY_DEPENDENCIES ${PLMREGISTER_LIBRARY_DEPENDENCIES} ${NLOPT_LIBRARIES} ) endif () ##----------------------------------------------------------------------------- ## SPECIAL BUILD RULES: OpenMP & SSE2 ##----------------------------------------------------------------------------- if (OPENMP_FOUND) set (PLMREGISTER_LIBRARY_LDFLAGS "${OPENMP_LDFLAGS}") set_source_files_properties (bspline.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) set_source_files_properties (bspline_gm.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) set_source_files_properties (bspline_mi.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) set_source_files_properties (bspline_mse.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) set_source_files_properties (bspline_regularize_analytic.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) endif () # bspline registration benefits from SSE2 if (SSE2_FOUND AND NOT BUILD_AGAINST_SLICER3) plm_set_sse2_flags (bspline.cxx bspline_gm.cxx bspline_mi.cxx bspline_mse.cxx) endif () ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- plm_add_library ( plmregister "${PLMREGISTER_LIBRARY_SRC}" "${PLMREGISTER_LIBRARY_DEPENDENCIES}" "${PLMREGISTER_LIBRARY_LDFLAGS}" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "") # because plmregistercuda is dynamically loaded (not linked) # CMake needs to be told explicitly that plmregister # depends on it, so we tell it explicitly here if (CUDA_FOUND) add_dependencies (plmregister plmregistercuda) endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline.cxx000066400000000000000000000347371321604176500306410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- Proposed variable naming guide: Fixed image voxel (f[3]), fidx Moving image voxel (m[3]), midx < ditto > - what about ROI's ? - what about physical coords ? Tile (fixed) (t[3]), tidx Offset within tile (fixed) (o[3]), oidx Control point (c[3]), cidx Coefficient array ? Multiplier LUT qidx Index LUT pidx qlut = Multiplier LUT clut = Index LUT ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #ifndef _WIN32 #include #endif #if (OPENMP_FOUND) #include #endif #if (SSE2_FOUND) #include #endif #include "bspline.h" #include "bspline_gm.h" #include "bspline_interpolate.h" #include "bspline_landmarks.h" #include "bspline_mi.h" #include "bspline_mse.h" #include "bspline_optimize.h" #include "bspline_parms.h" #include "bspline_regularize.h" #include "bspline_state.h" #include "bspline_xform.h" #include "delayload.h" #include "file_util.h" #include "interpolate_macros.h" #include "joint_histogram.h" #include "logfile.h" #include "plm_math.h" #include "plm_timer.h" #include "print_and_exit.h" #include "string_util.h" #include "volume.h" #include "volume_macros.h" //////////////////////////////////////////////////////////////////////////////// // FUNCTION: calc_offsets() // // This function accepts the number or voxels per control region // and the dimensions of the control grid to generate where the linear // memory offsets lie for the beginning of each tile in a 32-byte // aligned tile-major data organization scheme (such as that which // is produced by kernel_row_to_tile_major(). // // Author: James Shackleford // Data: July 30th, 2009 //////////////////////////////////////////////////////////////////////////////// int* calc_offsets (int* tile_dims, int* cdims) { int vox_per_tile = (tile_dims[0] * tile_dims[1] * tile_dims[2]); int pad = 32 - (vox_per_tile % 32); int num_tiles = (cdims[0]-3)*(cdims[1]-3)*(cdims[2]-3); int* output = (int*)malloc(num_tiles*sizeof(int)); int i; for(i = 0; i < num_tiles; i++) output[i] = (vox_per_tile + pad) * i; return output; } //////////////////////////////////////////////////////////////////////////////// // FUNCTION: find_knots() // // This function takes a tile index as an input and generates // the indicies of the 64 control knots that it affects. // // Returns: // knots[idx] - idx is [0,63] and knots[idx] = the linear knot index // of affected control knot # idx within the entire control // knot grid. // // tile_pos[ // // Author: James Shackleford // Data: July 13th, 2009 //////////////////////////////////////////////////////////////////////////////// void find_knots ( plm_long* knots, plm_long tile_num, plm_long* rdims, plm_long* cdims ) { int tile_loc[3]; int i, j, k; int idx = 0; int num_tiles_x = cdims[0] - 3; int num_tiles_y = cdims[1] - 3; int num_tiles_z = cdims[2] - 3; // First get the [x,y,z] coordinate of // the tile in the control grid. tile_loc[0] = tile_num % num_tiles_x; tile_loc[1] = ((tile_num - tile_loc[0]) / num_tiles_x) % num_tiles_y; tile_loc[2] = ((((tile_num - tile_loc[0]) / num_tiles_x) / num_tiles_y) % num_tiles_z); // Tiles do not start on the edges of the grid, so we // push them to the center of the control grid. tile_loc[0]++; tile_loc[1]++; tile_loc[2]++; // Find 64 knots' [x,y,z] coordinates // and convert into a linear knot index for (k = -1; k < 3; k++) { for (j = -1; j < 3; j++) { for (i = -1; i < 3; i++) { knots[idx++] = (cdims[0]*cdims[1]*(tile_loc[2]+k)) + (cdims[0]*(tile_loc[1]+j)) + (tile_loc[0]+i); } } } } /* ----------------------------------------------------------------------- Debugging routines ----------------------------------------------------------------------- */ void dump_total_gradient (Bspline_xform* bxf, Bspline_score* ssd, const char* fn) { int i; FILE* fp; make_parent_directories (fn); fp = fopen (fn, "wb"); for (i = 0; i < bxf->num_coeff; i++) { fprintf (fp, "%20.20f\n", ssd->total_grad[i]); } fclose (fp); } void bspline_display_coeff_stats (Bspline_xform* bxf) { float cf_min, cf_avg, cf_max; int i; cf_avg = 0.0; cf_min = cf_max = bxf->coeff[0]; for (i = 0; i < bxf->num_coeff; i++) { cf_avg += bxf->coeff[i]; if (cf_min > bxf->coeff[i]) cf_min = bxf->coeff[i]; if (cf_max < bxf->coeff[i]) cf_max = bxf->coeff[i]; } logfile_printf (" " "CMIN %6.2f CAVG %6.2f CMAX %6.2f\n", cf_min, cf_avg / bxf->num_coeff, cf_max); } void bspline_save_debug_state ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform *bxf ) { if (parms->debug) { std::string fn; char buf[1024]; sprintf (buf, "%02d_grad_%03d_%03d.txt", parms->debug_stage, bst->it, bst->feval); fn = parms->debug_dir + "/" + buf; dump_total_gradient (bxf, &bst->ssd, fn.c_str()); sprintf (buf, "%02d_coeff_%03d_%03d.txt", parms->debug_stage, bst->it, bst->feval); fn = parms->debug_dir + "/" + buf; bxf->save (fn.c_str()); if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) { sprintf (buf, "%02d_", parms->debug_stage); fn = parms->debug_dir + "/" + buf; bst->get_mi_hist()->dump_hist (bst->feval, fn); } } } Volume* bspline_compute_vf (const Bspline_xform* bxf) { Volume* vf = new Volume ( bxf->img_dim, bxf->img_origin, bxf->img_spacing, 0, PT_VF_FLOAT_INTERLEAVED, 3 ); bspline_interpolate_vf (vf, bxf); return vf; } void bspline_update_sets (float* sets_x, float* sets_y, float* sets_z, int qidx, float* dc_dv, Bspline_xform* bxf) { int sidx; // set index /* Initialize q_lut */ float* q_lut = &bxf->q_lut[64*qidx]; /* Condense dc_dv & commit to sets for tile */ for (sidx=0; sidx<64; sidx++) { sets_x[sidx] += dc_dv[0] * q_lut[sidx]; sets_y[sidx] += dc_dv[1] * q_lut[sidx]; sets_z[sidx] += dc_dv[2] * q_lut[sidx]; } } void bspline_update_sets_b (float* sets_x, float* sets_y, float* sets_z, plm_long *q, float* dc_dv, Bspline_xform* bxf) { int i,j,k,m; float A,B,C; /* Initialize b_luts */ float* bx_lut = &bxf->bx_lut[q[0]*4]; float* by_lut = &bxf->by_lut[q[1]*4]; float* bz_lut = &bxf->bz_lut[q[2]*4]; /* Condense dc_dv & commit to sets for tile */ m=0; for (k=0; k<4; k++) { C = bz_lut[k]; for (j=0; j<4; j++) { B = by_lut[j] * C; for (i=0; i<4; i++) { A = bx_lut[i] * B; sets_x[m] += dc_dv[0] * A; sets_y[m] += dc_dv[1] * A; sets_z[m] += dc_dv[2] * A; m++; } } } } void bspline_sort_sets (float* cond_x, float* cond_y, float* cond_z, float* sets_x, float* sets_y, float* sets_z, plm_long pidx, Bspline_xform* bxf) { int sidx, kidx; plm_long* k_lut = (plm_long*) malloc (64*sizeof(plm_long)); /* Generate the knot index lut */ find_knots (k_lut, pidx, bxf->rdims, bxf->cdims); /* Rackem' Up */ for (sidx=0; sidx<64; sidx++) { kidx = k_lut[sidx]; cond_x[ (64*kidx) + sidx ] = sets_x[sidx]; cond_y[ (64*kidx) + sidx ] = sets_y[sidx]; cond_z[ (64*kidx) + sidx ] = sets_z[sidx]; } free (k_lut); } void bspline_condense_smetric_grad (float* cond_x, float* cond_y, float* cond_z, Bspline_xform* bxf, Bspline_score* ssd) { plm_long kidx, sidx; for (kidx=0; kidx < bxf->num_knots; kidx++) { for (sidx=0; sidx<64; sidx++) { ssd->curr_smetric_grad[3*kidx + 0] += cond_x[64*kidx + sidx]; ssd->curr_smetric_grad[3*kidx + 1] += cond_y[64*kidx + sidx]; ssd->curr_smetric_grad[3*kidx + 2] += cond_z[64*kidx + sidx]; } } } static void logfile_print_score (float score) { if (score < 10. && score > -10.) { logfile_printf (" %1.7f ", score); } else { logfile_printf (" %9.3f ", score); } } void report_score ( Bspline_parms *parms, Bspline_xform *bxf, Bspline_state *bst ) { Bspline_score* ssd = &bst->ssd; Regularization_parms* reg_parms = parms->reg_parms; Bspline_landmarks* blm = parms->blm; int i; double ssd_grad_norm, ssd_grad_mean; /* Compute gradient statistics */ ssd_grad_norm = 0; ssd_grad_mean = 0; for (i = 0; i < bxf->num_coeff; i++) { ssd_grad_mean += bst->ssd.total_grad[i]; ssd_grad_norm += (double) bst->ssd.total_grad[i] * (double) bst->ssd.total_grad[i]; } /* Compute total time */ double total_smetric_time = 0; double total_time = 0; plm_long hack_num_vox = 0; std::vector::const_iterator it_mr = ssd->metric_record.begin(); while (it_mr != ssd->metric_record.end()) { total_time += it_mr->time; if (hack_num_vox == 0) { hack_num_vox = it_mr->num_vox; } ++it_mr; } total_smetric_time = total_time; total_time += ssd->time_rmetric; /* First line, iterations, score, misc stats */ logfile_printf ("[%2d,%3d] ", bst->it, bst->feval); if (reg_parms->lambda > 0 || blm->num_landmarks > 0 || bst->similarity_data.size() > 1) { logfile_printf ("SCORE "); } else { logfile_printf ("%-6s", bst->similarity_data.front()->metric_string()); } logfile_print_score (ssd->total_score); logfile_printf ( "NV %6d GM %9.3f GN %9.3g [ %9.3f s ]\n", hack_num_vox, ssd_grad_mean, sqrt (ssd_grad_norm), total_time); /* Second line */ if (reg_parms->lambda > 0 || blm->num_landmarks > 0 || bst->similarity_data.size() > 1) { logfile_printf (" "); /* Part 1 - smetric(s) */ /* GCS FIX: It should not be that one of these is a list and the other is a vector. */ std::vector::const_iterator it_mr = ssd->metric_record.begin(); std::list::const_iterator it_st = bst->similarity_data.begin(); while (it_mr != ssd->metric_record.end()) { logfile_printf ("%-6s", (*it_st)->metric_string()); logfile_print_score (it_mr->score); ++it_mr, ++it_st; } if (ssd->metric_record.size() > 1 && (reg_parms->lambda > 0 || blm->num_landmarks > 0)) { logfile_printf ("\n"); logfile_printf (" "); } if (reg_parms->lambda > 0 || blm->num_landmarks > 0) { /* Part 2 - regularization metric */ if (reg_parms->lambda > 0) { logfile_printf ("RM %9.3f ", reg_parms->lambda * bst->ssd.rmetric); } /* Part 3 - landmark metric */ if (blm->num_landmarks > 0) { logfile_printf ("LM %9.3f ", blm->landmark_stiffness * bst->ssd.lmetric); } /* Part 4 - timing */ if (reg_parms->lambda > 0) { logfile_printf ("[ %9.3f | %9.3f ]", total_smetric_time, ssd->time_rmetric); } } logfile_printf ("\n"); } } void bspline_score (Bspline_optimize *bod) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Regularization_parms* reg_parms = parms->reg_parms; Bspline_landmarks* blm = parms->blm; /* Zero out the score for this iteration */ bst->ssd.reset_score (); /* Compute similarity metric. This is done for each metric and each similarity metric within each image plane. */ std::list::const_iterator it_sd; bst->sm = 0; for (it_sd = bst->similarity_data.begin(); it_sd != bst->similarity_data.end(); ++it_sd) { bst->set_metric_state (*it_sd); bst->initialize_similarity_images (); Plm_timer timer; timer.start (); switch ((*it_sd)->metric_type) { case SIMILARITY_METRIC_DMAP: case SIMILARITY_METRIC_MSE: bspline_score_mse (bod); break; case SIMILARITY_METRIC_MI_MATTES: bspline_score_mi (bod); break; case SIMILARITY_METRIC_GM: bspline_score_gm (bod); break; default: print_and_exit ( "Unknown similarity metric in bspline_score()\n"); break; } bst->ssd.metric_record.push_back ( Metric_score (bst->ssd.curr_smetric, timer.report (), bst->ssd.curr_num_vox)); #if defined (commentout) printf (">> %f + %f * %f ->", bst->ssd.total_score, (*it_sd)->metric_lambda, bst->ssd.curr_smetric); #endif bst->ssd.accumulate ((*it_sd)->metric_lambda); #if defined (commentout) printf (" %f\n", bst->ssd.total_score); #endif bst->sm ++; } /* Compute regularization */ if (reg_parms->lambda > 0.0f) { bst->rst.compute_score (&bst->ssd, reg_parms, bxf); } /* Compute landmark score/gradient to image score/gradient */ if (blm->num_landmarks > 0) { bspline_landmarks_score (parms, bst, bxf); } /* Update total score with regularization and landmarks */ bst->ssd.total_score += reg_parms->lambda * bst->ssd.rmetric; if (blm->num_landmarks > 0) { bst->ssd.total_score += blm->landmark_stiffness * bst->ssd.lmetric; } /* Report results of this iteration */ report_score (parms, bxf, bst); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline.h000066400000000000000000000031531321604176500302520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_h_ #define _bspline_h_ #include "plmregister_config.h" #include "plm_int.h" #include class Joint_histogram; class Bspline_optimize; class Bspline_parms; class Bspline_score; class Bspline_state; class Bspline_xform; class Volume; PLMREGISTER_API Volume* bspline_compute_vf (const Bspline_xform* bxf); void bspline_display_coeff_stats (Bspline_xform* bxf); PLMREGISTER_API void bspline_score (Bspline_optimize *bod); int* calc_offsets (int* tile_dims, int* cdims); void find_knots (plm_long* knots, plm_long tile_num, plm_long* rdims, plm_long* cdims); void report_score ( Bspline_parms *parms, Bspline_xform *bxf, Bspline_state *bst ); /* Debugging routines */ PLMREGISTER_API void bspline_save_debug_state ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform* bxf ); void bspline_condense_smetric_grad ( float* cond_x, float* cond_y, float* cond_z, Bspline_xform* bxf, Bspline_score* ssd ); void bspline_update_sets ( float* sets_x, float* sets_y, float* sets_z, int qidx, float* dc_dv, Bspline_xform* bxf ); void bspline_update_sets_b ( float* sets_x, float* sets_y, float* sets_z, plm_long *q, float* dc_dv, Bspline_xform* bxf ); void bspline_sort_sets ( float* cond_x, float* cond_y, float* cond_z, float* sets_x, float* sets_y, float* sets_z, plm_long pidx, Bspline_xform* bxf ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_gm.cxx000066400000000000000000000033321321604176500313070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include #if (OPENMP_FOUND) #include #endif #if (SSE2_FOUND) #include #endif #include "bspline.h" #include "bspline_correspond.h" #include "bspline_interpolate.h" #include "bspline_loop.txx" #include "bspline_macros.h" #include "bspline_gm.h" #include "bspline_gm.txx" #include "bspline_optimize.h" #include "bspline_parms.h" #include "bspline_state.h" #include "file_util.h" #include "interpolate.h" #include "interpolate_macros.h" #include "logfile.h" #include "mha_io.h" #include "plm_math.h" #include "plm_timer.h" #include "string_util.h" #include "volume.h" #include "volume_macros.h" /* ----------------------------------------------------------------------- FUNCTION: bspline_score_k_mse(), bspline_score_l_mse() This is the same as 'c', except using templates. This is the older "fast" single-threaded MSE implementation, modified to respect direction cosines (and ROI support removed). ----------------------------------------------------------------------- */ void bspline_score_k_gm ( Bspline_optimize *bod ) { /* Create/initialize bspline_loop_user */ Bspline_gm_k blu (bod); /* Run the loop */ bspline_loop_voxel_serial (blu, bod); /* Normalize score for MSE */ bspline_score_normalize (bod, blu.score_acc); } void bspline_score_gm ( Bspline_optimize *bod ) { return bspline_score_k_gm (bod); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_gm.h000066400000000000000000000006241321604176500307350ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_gm_h_ #define _bspline_gm_h_ #include "plmregister_config.h" class Bspline_optimize; PLMREGISTER_API void bspline_score_gm (Bspline_optimize *bod); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_gm.txx000077500000000000000000000056171321604176500313430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_gm_txx_ #define _bspline_gm_txx_ class Bspline_gm_k { public: float *m_grad; /* GCS: Oct 5, 2009. We have determined that sequential accumulation of the score requires double precision. However, reduction accumulation does not. */ double score_acc; public: Bspline_gm_k (Bspline_optimize *bod) { Bspline_state *bst = bod->get_bspline_state (); Volume *moving_grad = bst->moving_grad; m_grad = (float*) moving_grad->img; score_acc = 0.; } public: void loop_function ( Bspline_optimize *bod, /* In/out: generic optimization data */ Bspline_xform *bxf, /* Input: coefficient values */ Bspline_state *bst, /* Input: state of bspline */ Bspline_score *ssd, /* In/out: score and gradient */ const Volume *fixed, /* Input: fixed image */ const Volume *moving, /* Input: moving image */ const float *f_img, /* Input: raw intensity array for fixed */ const float *m_img, /* Input: raw intensity array for moving */ plm_long fidx, /* Input: index of voxel in fixed image */ plm_long midx_f, /* Input: index (floor) in moving image*/ plm_long mijk_r[3], /* Input: coords (rounded) in moving image*/ plm_long pidx, /* Input: region index of fixed voxel */ plm_long qidx, /* Input: offset index of fixed voxel */ float li_1[3], /* Input: linear interpolation fraction */ float li_2[3] /* Input: linear interpolation fraction */ ) { float m_val; float dc_dv[3]; /* Get value in fixed image */ float f_val = f_img[fidx]; /* Compute moving image intensity using linear interpolation */ /* Macro is slightly faster than function */ LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], midx_f, m_img, moving); /* This replaces the commented out code */ plm_long mvr = volume_index (moving->dim, mijk_r); /* Compute intensity difference */ float diff = m_val - f_val; /* Update score */ this->score_acc += diff * diff; /* Compute spatial gradient using nearest neighbors */ dc_dv[0] = diff * m_grad[3*mvr+0]; /* x component */ dc_dv[1] = diff * m_grad[3*mvr+1]; /* y component */ dc_dv[2] = diff * m_grad[3*mvr+2]; /* z component */ /* Update cost function gradient */ ssd->update_smetric_grad_b (bxf, pidx, qidx, dc_dv); ssd->curr_num_vox++; } }; #endif bspline_landmarks.cxx000066400000000000000000000152051321604176500326030ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include "bspline.h" #include "bspline_interpolate.h" #include "bspline_landmarks.h" #include "bspline_parms.h" #include "bspline_state.h" #include "bspline_xform.h" #include "direction_matrices.h" #include "file_util.h" #include "logfile.h" #include "plm_math.h" #include "pointset.h" #include "print_and_exit.h" #include "volume_macros.h" void bspline_landmarks_score_a ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform* bxf ) { Bspline_score* ssd = &bst->ssd; Bspline_landmarks *blm = parms->blm; size_t lidx; #if defined (commentout) FILE *fp, *fp2; #endif float land_score, land_grad_coeff; FILE* landmark_fp = 0; static int it = 0; if (parms->debug) { char buf[1024]; //sprintf (buf, "lm_%02d.txt", it); sprintf (buf, "%02d_lm_%02d.txt", parms->debug_stage, bst->feval); std::string fn = parms->debug_dir + "/" + buf; landmark_fp = plm_fopen (fn.c_str(), "wb"); it ++; } land_score = 0; land_grad_coeff = blm->landmark_stiffness / blm->num_landmarks; #if defined (commentout) fp = fopen ("warplist_a.fcsv","w"); fp2 = fopen ("distlist_a.dat","w"); fprintf (fp, "# name = warped\n"); #endif for (lidx=0; lidx < blm->num_landmarks; lidx++) { plm_long p[3], q[3]; plm_long qidx; float mxyz[3]; /* Location of fixed landmark in moving image */ float diff[3]; /* mxyz - moving_landmark */ float dc_dv[3]; float dxyz[3]; float l_dist=0; for (int d = 0; d < 3; d++) { p[d] = blm->fixed_landmarks_p[lidx*3+d]; q[d] = blm->fixed_landmarks_q[lidx*3+d]; } qidx = volume_index (bxf->vox_per_rgn, q); bspline_interp_pix (dxyz, bxf, p, qidx); for (int d = 0; d < 3; d++) { mxyz[d] = blm->fixed_landmarks->point_list[lidx].p[d] + dxyz[d]; diff[d] = blm->moving_landmarks->point_list[lidx].p[d] - mxyz[d]; } l_dist = diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]; land_score += l_dist; if (parms->debug) { fprintf (landmark_fp, " flm = %5.2f %5.2f %5.2f\n", blm->fixed_landmarks->point_list[lidx].p[0], blm->fixed_landmarks->point_list[lidx].p[1], blm->fixed_landmarks->point_list[lidx].p[2]); fprintf (landmark_fp, " dxyz = %5.2f %5.2f %5.2f\n", dxyz[0], dxyz[1], dxyz[2]); fprintf (landmark_fp, " diff = %5.2f %5.2f %5.2f (%5.2f)\n", diff[0], diff[1], diff[2], sqrt(l_dist)); fprintf (landmark_fp, " mxyz = %5.2f %5.2f %5.2f\n", mxyz[0], mxyz[1], mxyz[2]); fprintf (landmark_fp, " mlm = %5.2f %5.2f %5.2f\n", blm->moving_landmarks->point_list[lidx].p[0], blm->moving_landmarks->point_list[lidx].p[1], blm->moving_landmarks->point_list[lidx].p[2]); fprintf (landmark_fp, "--\n"); } // calculating gradients dc_dv[0] = - land_grad_coeff * diff[0]; dc_dv[1] = - land_grad_coeff * diff[1]; dc_dv[2] = - land_grad_coeff * diff[2]; ssd->update_total_grad (bxf, p, qidx, dc_dv); #if defined (commentout) /* Note: Slicer landmarks are in RAS coordinates. Change LPS to RAS */ fprintf (fp, "W%d,%f,%f,%f,1,1\n", lidx, -mxyz[0], -mxyz[1], mxyz[2]); fprintf (fp2,"W%d %.3f\n", lidx, sqrt(l_dist)); #endif } #if defined (commentout) fclose(fp); fclose(fp2); #endif if (parms->debug) { fclose (landmark_fp); } ssd->lmetric = land_score / blm->num_landmarks; } void bspline_landmarks_score ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform* bxf ) { /* Only 'a' is supported at this time */ bspline_landmarks_score_a (parms, bst, bxf); } void Bspline_landmarks::initialize (const Bspline_xform* bxf) { if (!this->fixed_landmarks || !this->moving_landmarks || this->num_landmarks == 0) { return; } float step[9]; float proj[9]; lprintf ("Computing landmark grid coordinates\n" "image dc=%s\n" "image or=%g %g %g\n" "image dm=%d %d %d\n", bxf->dc.get_string().c_str(), bxf->img_origin[0], bxf->img_origin[1], bxf->img_origin[2], (int) bxf->img_dim[0], (int) bxf->img_dim[1], (int) bxf->img_dim[2] ); compute_direction_matrices (step, proj, bxf->dc, bxf->img_spacing); this->fixed_landmarks_p = new int[3*this->num_landmarks]; this->fixed_landmarks_q = new int[3*this->num_landmarks]; for (size_t i = 0; i < num_landmarks; i++) { const Labeled_point& fp = this->fixed_landmarks->point_list[i]; float landmark_ijk[3]; float landmark_xyz[3]; landmark_xyz[0] = fp.p[0] - bxf->img_origin[0]; landmark_xyz[1] = fp.p[1] - bxf->img_origin[1]; landmark_xyz[2] = fp.p[2] - bxf->img_origin[2]; landmark_ijk[0] = PROJECT_X (landmark_xyz, proj); landmark_ijk[1] = PROJECT_Y (landmark_xyz, proj); landmark_ijk[2] = PROJECT_Z (landmark_xyz, proj); printf ("[%d], (%g %g %g) -> (%f %f %f)\n", (int) i, fp.p[0], fp.p[1], fp.p[2], landmark_ijk[0], landmark_ijk[1], landmark_ijk[2]); for (int d = 0; d < 3; d++) { plm_long v; v = landmark_ijk[d]; if (v < 0 || v >= bxf->img_dim[d]) { print_and_exit ( "Error: fixed landmark %d outside of fixed image.\n", i); } this->fixed_landmarks_p[i*3+d] = v / bxf->vox_per_rgn[d]; this->fixed_landmarks_q[i*3+d] = v % bxf->vox_per_rgn[d]; } } } void Bspline_landmarks::set_landmarks ( const Labeled_pointset *fixed_landmarks, const Labeled_pointset *moving_landmarks) { this->fixed_landmarks = fixed_landmarks; this->moving_landmarks = moving_landmarks; /* Find list with fewer landmarks */ if (moving_landmarks->get_count() > fixed_landmarks->get_count()) { this->num_landmarks = fixed_landmarks->get_count(); } else { this->num_landmarks = moving_landmarks->get_count(); } } bspline_landmarks.h000066400000000000000000000044571321604176500322370ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_landmarks_h_ #define _bspline_landmarks_h_ #include "plmregister_config.h" template class PLMREGISTER_API Pointset; class Bspline_mi_hist; class Bspline_parms; class Bspline_state; class Bspline_xform; class Labeled_point; class Volume; typedef Pointset Labeled_pointset; class PLMREGISTER_API Bspline_landmarks { public: size_t num_landmarks; const Labeled_pointset *fixed_landmarks; const Labeled_pointset *moving_landmarks; float landmark_stiffness; char landmark_implementation; int *fixed_landmarks_p; int *fixed_landmarks_q; public: Bspline_landmarks () { num_landmarks = 0; fixed_landmarks = 0; moving_landmarks = 0; landmark_stiffness = 1.0; landmark_implementation = 'a'; fixed_landmarks_p = 0; fixed_landmarks_q = 0; } ~Bspline_landmarks () { /* Do not delete fixed_landmarks and moving_landmarks, they are owned by the caller. */ if (fixed_landmarks_p) { delete[] fixed_landmarks_p; } if (fixed_landmarks_q) { delete[] fixed_landmarks_q; } } void set_landmarks ( const Labeled_pointset *fixed_landmarks, const Labeled_pointset *moving_landmarks ); void initialize (const Bspline_xform* bxf); }; PLMREGISTER_C_API Bspline_landmarks* bspline_landmarks_load ( char *fixed_fn, char *moving_fn ); PLMREGISTER_C_API void bspline_landmarks_adjust ( Bspline_landmarks *blm, Volume *fixed, Volume *moving ); void bspline_landmarks_score ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform *bxf ); /* // NSh 2012-02-17 - definitions of these fxns are missing PLMREGISTER_C_API void bspline_landmarks_warp ( Volume *vector_field, Bspline_parms *parms, Bspline_xform* bxf, Volume *fixed, Volume *moving ); PLMREGISTER_C_API void bspline_landmarks_write_file ( const char *fn, char *title, float *coords, int n ); */ #endif bspline_loop.txx000077500000000000000000000452751321604176500316360ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_loop_txx_ #define _bspline_loop_txx_ #include "plmregister_config.h" #include #if OPENMP_FOUND #include #endif #include "bspline_macros.h" #include "bspline_mse.h" #include "bspline_optimize.h" #include "bspline_parms.h" #include "file_util.h" #include "interpolate.h" #include "interpolate_macros.h" #include "plm_timer.h" #include "string_util.h" /* ----------------------------------------------------------------------- B-Spline registration. Reference implementation, meant to be easy to understand. Equivalent to "MSE C" method. Respects direction cosines and ROI images. ----------------------------------------------------------------------- */ template< class Bspline_loop_user > void bspline_loop_voxel_serial ( Bspline_loop_user& bspline_loop_user, Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Bspline_score* ssd = &bst->ssd; Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *fixed_roi = bst->fixed_roi; Volume *moving_roi = bst->moving_roi; plm_long fijk[3], fidx; /* Indices within fixed image (vox) */ float mijk[3]; /* Indices within moving image (vox) */ float fxyz[3]; /* Position within fixed image (mm) */ float mxyz[3]; /* Position within moving image (mm) */ plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3], pidx; /* Region index of fixed voxel */ plm_long q[3], qidx; /* Offset index of fixed voxel */ float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; float dxyz[3]; FILE* val_fp = 0; FILE* dc_dv_fp = 0; FILE* corr_fp = 0; if (parms->debug) { std::string fn; fn = string_format ("%s/%02d_%03d_%03d_dc_dv.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); dc_dv_fp = plm_fopen (fn.c_str(), "wb"); fn = string_format ("%s/%02d_%03d_%03d_val.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); val_fp = plm_fopen (fn.c_str(), "wb"); fn = string_format ("%s/%02d_%03d_%03d_corr.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); corr_fp = plm_fopen (fn.c_str(), "wb"); } LOOP_Z (fijk, fxyz, fixed) { p[2] = REGION_INDEX_Z (fijk, bxf); q[2] = REGION_OFFSET_Z (fijk, bxf); LOOP_Y (fijk, fxyz, fixed) { p[1] = REGION_INDEX_Y (fijk, bxf); q[1] = REGION_OFFSET_Y (fijk, bxf); LOOP_X (fijk, fxyz, fixed) { p[0] = REGION_INDEX_X (fijk, bxf); q[0] = REGION_OFFSET_X (fijk, bxf); /* Discard fixed image voxels outside of roi */ if (fixed_roi) { if (!inside_roi (fxyz, fixed_roi)) continue; } /* Get B-spline deformation vector */ pidx = volume_index (bxf->rdims, p); qidx = volume_index (bxf->vox_per_rgn, q); bspline_interp_pix_b (dxyz, bxf, pidx, qidx); /* Find correspondence in moving image */ int rc; rc = bspline_find_correspondence_dcos_roi ( mxyz, mijk, fxyz, dxyz, moving, moving_roi); /* If voxel is not inside moving image */ if (!rc) continue; if (parms->debug) { fprintf (corr_fp, "%d %d %d, %f %f %f -> %f %f %f, %f %f %f\n", (unsigned int) fijk[0], (unsigned int) fijk[1], (unsigned int) fijk[2], fxyz[0], fxyz[1], fxyz[2], mijk[0], mijk[1], mijk[2], fxyz[0] + dxyz[0], fxyz[1] + dxyz[1], fxyz[2] + dxyz[2] ); } /* Compute interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Compute linear index of fixed image voxel */ fidx = volume_index (fixed->dim, fijk); /* Find linear index of "corner voxel" in moving image */ midx_f = volume_index (moving->dim, mijk_f); /* Run the target function */ bspline_loop_user.loop_function ( bod, bxf, bst, ssd, fixed, moving, f_img, m_img, fidx, midx_f, mijk_r, pidx, qidx, li_1, li_2); } /* LOOP_THRU_ROI_X */ } /* LOOP_THRU_ROI_Y */ } /* LOOP_THRU_ROI_Z */ if (parms->debug) { fclose (val_fp); fclose (dc_dv_fp); fclose (corr_fp); } } /* ----------------------------------------------------------------------- B-Spline registration. Fasted known method for single core CPU. Equivalent to "MSE H" method. Respects direction cosines and ROI images. ----------------------------------------------------------------------- */ template< class Bspline_loop_user > void bspline_loop_tile_serial ( Bspline_loop_user& bspline_loop_user, Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Bspline_score* ssd = &bst->ssd; Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *fixed_roi = bst->fixed_roi; Volume *moving_roi = bst->moving_roi; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); // Zero out accumulators memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); FILE* val_fp = 0; FILE* dc_dv_fp = 0; FILE* corr_fp = 0; if (parms->debug) { std::string fn; fn = string_format ("%s/%02d_%03d_%03d_dc_dv.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); dc_dv_fp = plm_fopen (fn.c_str(), "wb"); fn = string_format ("%s/%02d_%03d_%03d_val.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); val_fp = plm_fopen (fn.c_str(), "wb"); fn = string_format ("%s/%02d_%03d_%03d_corr.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); corr_fp = plm_fopen (fn.c_str(), "wb"); } // Serial across tiles plm_long pidx; LOOP_THRU_VOL_TILES (pidx, bxf) { int ijk_tile[3]; plm_long q[3]; plm_long fijk[3], fidx; /* Indices within fixed image (vox) */ float fxyz[3]; /* Position within fixed image (mm) */ float mijk[3]; /* Indices within moving image (vox) */ float mxyz[3]; /* Position within moving image (mm) */ plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ float dxyz[3]; float li_1[3], li_2[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); // Get tile coordinates from index COORDS_FROM_INDEX (ijk_tile, pidx, bxf->rdims); // Serial through voxels in tile LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { // Construct coordinates into fixed image volume GET_VOL_COORDS (fijk, ijk_tile, q, bxf); /* Discard fixed image voxels outside of roi */ if (fixed_roi) { if (!inside_roi (fxyz, fixed_roi)) continue; } // Compute physical coordinates of fixed image voxel /* To remove DCOS support, switch to GET_REAL_SPACE_COORDS (fxyz, fijk, bxf); */ POSITION_FROM_COORDS (fxyz, fijk, bxf->img_origin, fixed->step); // Construct the image volume index fidx = volume_index (fixed->dim, fijk); // Calc. deformation vector (dxyz) for voxel bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ int rc; rc = bspline_find_correspondence_dcos_roi ( mxyz, mijk, fxyz, dxyz, moving, moving_roi); /* If voxel is not inside moving image */ if (!rc) continue; if (parms->debug) { fprintf (corr_fp, "%d %d %d, %f %f %f -> %f %f %f, %f %f %f\n", (unsigned int) fijk[0], (unsigned int) fijk[1], (unsigned int) fijk[2], fxyz[0], fxyz[1], fxyz[2], mijk[0], mijk[1], mijk[2], fxyz[0] + dxyz[0], fxyz[1] + dxyz[1], fxyz[2] + dxyz[2]); } // Compute linear interpolation fractions li_clamp_3d ( mijk, mijk_f, mijk_r, li_1, li_2, moving ); // Find linear indices for moving image midx_f = volume_index (moving->dim, mijk_f); /* Run the target function */ bspline_loop_user.loop_function ( bod, bxf, bst, ssd, fixed, moving, f_img, m_img, fidx, midx_f, mijk_r, li_1, li_2, q, sets_x, sets_y, sets_z); } /* LOOP_THRU_TILE_X */ } /* LOOP_THRU_TILE_Y */ } /* LOOP_THRU_TILE_Z */ // The tile is now condensed. Now we will put it in the // proper slot within the control point bin that it belong to. bspline_sort_sets ( cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, pidx, bxf ); } /* LOOP_THRU_VOL_TILES */ /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. A single bin summation is * dc_dp for the single control point associated with the bin. * The number of total bins is equal to the number of control * points in the control grid. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); if (parms->debug) { fclose (val_fp); fclose (dc_dv_fp); fclose (corr_fp); } } /* ----------------------------------------------------------------------- B-Spline registration. Fasted known method for single core CPU. Equivalent to "MSE I" method. Respects direction cosines and ROI images. ----------------------------------------------------------------------- */ #if OPENMP_FOUND template< class Bspline_loop_user > void bspline_loop_tile_parallel ( Bspline_loop_user& bspline_loop_user, Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Bspline_score* ssd = &bst->ssd; Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *fixed_roi = bst->fixed_roi; Volume *moving_roi = bst->moving_roi; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); // Zero out accumulators memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); FILE* val_fp = 0; FILE* dc_dv_fp = 0; FILE* corr_fp = 0; if (parms->debug) { std::string fn; fn = string_format ("%s/%02d_%03d_%03d_dc_dv.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); dc_dv_fp = plm_fopen (fn.c_str(), "wb"); fn = string_format ("%s/%02d_%03d_%03d_val.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); val_fp = plm_fopen (fn.c_str(), "wb"); fn = string_format ("%s/%02d_%03d_%03d_corr.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); corr_fp = plm_fopen (fn.c_str(), "wb"); } /* Allocate and initialize private thread data */ int num_threads = 1; #pragma omp parallel #pragma omp master { num_threads = omp_get_num_threads (); } typename Bspline_loop_user::Thread_data thread_data_array = new typename Bspline_loop_user::Thread_data[num_threads]; // Parallel across tiles plm_long pidx; #pragma omp parallel for LOOP_THRU_VOL_TILES (pidx, bxf) { /* Get pointer to private data for this thread */ int thread_num = omp_get_thread_num (); typename Bspline_loop_user::Thread_data *thread_data = thread_data_array[thread_num]; int rc; int ijk_tile[3]; plm_long q[3]; plm_long fijk[3], fidx; /* Indices within fixed image (vox) */ float fxyz[3]; /* Position within fixed image (mm) */ float mijk[3]; /* Indices within moving image (vox) */ float mxyz[3]; /* Position within moving image (mm) */ plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3], midx_r; /* Round */ float dxyz[3]; float li_1[3], li_2[3]; float m_val, diff; float dc_dv[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); // Get tile coordinates from index COORDS_FROM_INDEX (ijk_tile, pidx, bxf->rdims); // Serial through voxels in tile LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { // Construct coordinates into fixed image volume GET_VOL_COORDS (fijk, ijk_tile, q, bxf); /* Discard fixed image voxels outside of roi */ if (fixed_roi) { if (!inside_roi (fxyz, fixed_roi)) continue; } // Compute physical coordinates of fixed image voxel /* To remove DCOS support, switch to GET_REAL_SPACE_COORDS (fxyz, fijk, bxf); */ POSITION_FROM_COORDS (fxyz, fijk, bxf->img_origin, fixed->step); // Construct the image volume index fidx = volume_index (fixed->dim, fijk); // Calc. deformation vector (dxyz) for voxel bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ int rc; rc = bspline_find_correspondence_dcos_roi ( mxyz, mijk, fxyz, dxyz, moving, moving_roi); /* If voxel is not inside moving image */ if (!rc) continue; if (parms->debug) { fprintf (corr_fp, "%d %d %d, %f %f %f -> %f %f %f, %f %f %f\n", (unsigned int) fijk[0], (unsigned int) fijk[1], (unsigned int) fijk[2], fxyz[0], fxyz[1], fxyz[2], mijk[0], mijk[1], mijk[2], fxyz[0] + dxyz[0], fxyz[1] + dxyz[1], fxyz[2] + dxyz[2]); } // Compute linear interpolation fractions li_clamp_3d ( mijk, mijk_f, mijk_r, li_1, li_2, moving ); // Find linear indices for moving image midx_f = volume_index (moving->dim, mijk_f); midx_r = volume_index (moving->dim, mijk_r); /* Run the target function */ bspline_loop_user.loop_function ( bod, bxf, bst, ssd, fixed, moving, f_img, m_img, fidx, midx_f, mijk_r, li_1, li_2, q, sets_x, sets_y, sets_z); } /* LOOP_THRU_TILE_X */ } /* LOOP_THRU_TILE_Y */ } /* LOOP_THRU_TILE_Z */ // The tile is now condensed. Now we will put it in the // proper slot within the control point bin that it belong to. bspline_sort_sets ( cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, pidx, bxf ); } /* LOOP_THRU_VOL_TILES */ /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. A single bin summation is * dc_dp for the single control point associated with the bin. * The number of total bins is equal to the number of control * points in the control grid. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); if (parms->debug) { fclose (val_fp); fclose (dc_dv_fp); fclose (corr_fp); } } #endif /* OPENMP_FOUND */ #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_mi.cxx000066400000000000000000003205411321604176500313150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #if (OPENMP_FOUND) #include #endif #if (SSE2_FOUND) #include #endif #include "bspline.h" #include "bspline_correspond.h" #include "bspline_cuda.h" #include "bspline_interpolate.h" #include "bspline_loop.txx" #include "bspline_macros.h" #include "bspline_mi.h" #include "bspline_mi.txx" #include "bspline_optimize.h" #include "bspline_parms.h" #include "bspline_state.h" #include "file_util.h" #include "interpolate.h" #include "interpolate_macros.h" #include "joint_histogram.h" #include "logfile.h" #include "mha_io.h" #include "plm_math.h" #include "volume_macros.h" #include "volume.h" /* Some neat debug facilities * Will probably move these somewhere more appropriate soon */ Volume* volume_clip_intensity (Volume* vin, float bot, float top) { plm_long i, j, N; int* marks; float* imgin; float* imgout; float min; Volume* vout; vout = volume_clone (vin); imgin = (float*) vin->img; imgout = (float*) vout->img; N=0; min = FLT_MAX; for (i=0; inpix; i++) { if ( (imgin[i] >= bot) && (imgin[i] <= top) ) { N++; } if (imgin[i] < min) { min = imgin[i]; } } if (N == 0) { return NULL; } marks = (int*) malloc (N * sizeof (int)); j=0; for (i=0; inpix; i++) { if ( (imgin[i] >= bot) && (imgin[i] <= top) ) { marks[j++] = i; } imgout[i] = min; } for (i=0; i= dmax) { maqs[2] = dmax - 1; if (maqs[1] >= dmax) { maqs[1] = dmax - 1; if (maqs[0] >= dmax) { maqs[0] = dmax - 1; } } } } inline void clamp_quadratic_interpolate_grad_inline ( float ma, /* Input: (Unrounded) pixel coordinate (in vox units) */ long dmax, /* Input: Maximum coordinate in this dimension */ long maqs[3], /* Output: x, y, or z coord of 3 pixels in moving img */ float faqs[3] /* Output: Gradient interpolant for 3 voxels */ ) { float marf = floorf (ma + 0.5); /* marf = ma, rounded, floating */ long mari = (long) marf; /* mari = ma, rounded, integer */ float t = ma - marf + 0.5; faqs[0] = -1.0f + t; faqs[1] = -2.0f * t + 1.0f; faqs[2] = t; maqs[0] = mari - 1; maqs[1] = mari; maqs[2] = mari + 1; if (maqs[0] < 0) { faqs[0] = faqs[1] = faqs[2] = 0.0f; /* No gradient at image boundary */ maqs[0] = 0; if (maqs[1] < 0) { maqs[1] = 0; if (maqs[2] < 0) { maqs[2] = 0; } } } else if (maqs[2] >= dmax) { faqs[0] = faqs[1] = faqs[2] = 0.0f; /* No gradient at image boundary */ maqs[2] = dmax - 1; if (maqs[1] >= dmax) { maqs[1] = dmax - 1; if (maqs[0] >= dmax) { maqs[0] = dmax - 1; } } } } /* This function will split the amout to add between two bins (linear interp) based on m_val, but one bin based on f_val. */ inline void bspline_mi_hist_lookup ( long j_idxs[2], /* Output: Joint histogram indices */ long m_idxs[2], /* Output: Moving marginal indices */ long f_idxs[1], /* Output: Fixed marginal indices */ float fxs[2], /* Output: Fraction contribution at indices */ Joint_histogram* mi_hist, /* Input: The histogram */ float f_val, /* Input: Intensity of fixed image */ float m_val /* Input: Intensity of moving image */ ) { plm_long fl; float midx, midx_trunc; plm_long ml_1, ml_2; /* 1-d index of bin 1, bin 2 */ float mf_1, mf_2; /* fraction to bin 1, bin 2 */ long f_idx; /* Index into 2-d histogram */ /* Fixed image is binned */ fl = (long) floor ((f_val - mi_hist->fixed.offset) / mi_hist->fixed.delta); f_idx = fl * mi_hist->moving.bins; /* This had better not happen! */ if (fl < 0 || fl >= mi_hist->fixed.bins) { fprintf (stderr, "Error: fixed image binning problem.\n" "Bin %ld from val %g parms [off=%g, delt=%g, (%ld bins)]\n", fl, f_val, mi_hist->fixed.offset, mi_hist->fixed.delta, mi_hist->fixed.bins); exit (-1); } /* Moving image binning is interpolated (linear, not b-spline) */ midx = ((m_val - mi_hist->moving.offset) / mi_hist->moving.delta); midx_trunc = floorf (midx); ml_1 = (long) midx_trunc; mf_1 = midx - midx_trunc; // Always between 0 and 1 ml_2 = ml_1 + 1; mf_2 = 1.0 - mf_1; if (ml_1 < 0) { /* This had better not happen! */ fprintf (stderr, "Error: moving image binning problem\n"); exit (-1); } else if (ml_2 >= mi_hist->moving.bins) { /* This could happen due to rounding */ ml_1 = mi_hist->moving.bins - 2; ml_2 = mi_hist->moving.bins - 1; mf_1 = 0.0; mf_2 = 1.0; } if (mf_1 < 0.0 || mf_1 > 1.0 || mf_2 < 0.0 || mf_2 > 1.0) { fprintf (stderr, "Error: MI interpolation problem\n"); exit (-1); } j_idxs[0] = f_idx + ml_1; j_idxs[1] = f_idx + ml_2; fxs[0] = mf_1; fxs[1] = mf_2; f_idxs[0] = fl; m_idxs[0] = ml_1; m_idxs[1] = ml_2; } /* This function will split the amout to add between two bins (linear interp) based on m_val, but one bin based on f_val. */ inline void bspline_mi_hist_add ( Joint_histogram* mi_hist, /* The histogram */ float f_val, /* Intensity of fixed image */ float m_val, /* Intensity of moving image */ float amt /* How much to add to histogram */ ) { double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; long j_idxs[2]; long m_idxs[2]; long f_idxs[1]; float fxs[2]; bspline_mi_hist_lookup (j_idxs, m_idxs, f_idxs, fxs, mi_hist, f_val, m_val); fxs[0] *= amt; fxs[1] *= amt; f_hist[f_idxs[0]] += amt; /* This is inefficient */ m_hist[m_idxs[0]] += fxs[0]; m_hist[m_idxs[1]] += fxs[1]; j_hist[j_idxs[0]] += fxs[0]; j_hist[j_idxs[1]] += fxs[1]; } /* This algorithm uses a un-normalized score. */ static float mi_hist_score_omp (Joint_histogram* mi_hist, int num_vox) { double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; int f_bin, m_bin, j_bin; double fnv = (double) num_vox; double score = 0; double hist_thresh = 0.001 / (mi_hist->moving.bins * mi_hist->fixed.bins); /* Compute cost */ #pragma omp parallel for reduction(-:score) for (j_bin=0; j_bin < (mi_hist->fixed.bins * mi_hist->moving.bins); j_bin++) { m_bin = j_bin % mi_hist->moving.bins; f_bin = j_bin / mi_hist->moving.bins; if (j_hist[j_bin] > hist_thresh) { score -= j_hist[j_bin] * logf(fnv * j_hist[j_bin] / (m_hist[m_bin] * f_hist[f_bin])); } } score = score / fnv; return (float) score; } inline float compute_dS_dP ( double* j_hist, double* f_hist, double* m_hist, long* j_idxs, long* f_idxs, long* m_idxs, float num_vox_f, float* fxs, float score, int debug ) { float dS_dP_0, dS_dP_1, dS_dP; const float j_hist_thresh = 0.0001f; if (debug) { fprintf (stderr, "j=[%ld %ld] (%g %g), " "f=[%ld] (%g), " "m=[%ld %ld] (%g %g), " "fxs = (%g %g)\n", j_idxs[0], j_idxs[1], j_hist[j_idxs[0]], j_hist[j_idxs[1]], f_idxs[0], f_hist[f_idxs[0]], m_idxs[0], m_idxs[1], m_hist[m_idxs[0]], m_hist[m_idxs[1]], fxs[0], fxs[1]); } if (j_hist[j_idxs[0]] < j_hist_thresh) { dS_dP_0 = 0.0f; } else { dS_dP_0 = fxs[0] * (logf((num_vox_f * j_hist[j_idxs[0]]) / (f_hist[f_idxs[0]] * m_hist[m_idxs[0]])) - score); } if (j_hist[j_idxs[1]] < j_hist_thresh) { dS_dP_1 = 0.0f; } else { dS_dP_1 = fxs[1] * (logf((num_vox_f * j_hist[j_idxs[1]]) / (f_hist[f_idxs[0]] * m_hist[m_idxs[1]])) - score); } dS_dP = dS_dP_0 + dS_dP_1; if (debug) { fprintf (stderr, "dS_dP %g = %g %g\n", dS_dP, dS_dP_0, dS_dP_1); } return dS_dP; } /* Use 1 histogram per thread so we are * thread safe when employing multi-core */ #if (OPENMP_FOUND) static inline void bspline_mi_hist_add_pvi_8_omp_v2 ( Joint_histogram* mi_hist, double* f_hist_omp, double* m_hist_omp, double* j_hist_omp, Volume *fixed, Volume *moving, int fidx, int midx_f, float li_1[3], /* Fraction of interpolant in lower index */ float li_2[3], /* Fraction of interpolant in upper index */ int thread_num) { float w[8]; int n[8]; plm_long idx_fbin, idx_mbin, idx_jbin, idx_pv; int offset_fbin; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; /* Compute partial volumes from trilinear interpolation weights */ w[0] = li_1[0] * li_1[1] * li_1[2]; // Partial Volume w0 w[1] = li_2[0] * li_1[1] * li_1[2]; // Partial Volume w1 w[2] = li_1[0] * li_2[1] * li_1[2]; // Partial Volume w2 w[3] = li_2[0] * li_2[1] * li_1[2]; // Partial Volume w3 w[4] = li_1[0] * li_1[1] * li_2[2]; // Partial Volume w4 w[5] = li_2[0] * li_1[1] * li_2[2]; // Partial Volume w5 w[6] = li_1[0] * li_2[1] * li_2[2]; // Partial Volume w6 w[7] = li_2[0] * li_2[1] * li_2[2]; // Partial Volume w7 /* Note that Sum(wN) for N within [0,7] should = 1 */ // Calculate Point Indices for 8 neighborhood n[0] = midx_f; n[1] = n[0] + 1; n[2] = n[0] + moving->dim[0]; n[3] = n[2] + 1; n[4] = n[0] + moving->dim[0]*moving->dim[1]; n[5] = n[4] + 1; n[6] = n[4] + moving->dim[0]; n[7] = n[6] + 1; // Calculate fixed histogram bin and increment it idx_fbin = floor ((f_img[fidx] - mi_hist->fixed.offset) / mi_hist->fixed.delta); f_hist_omp[mi_hist->fixed.bins*thread_num + idx_fbin]++; offset_fbin = idx_fbin * mi_hist->moving.bins; // Add PV weights to moving & joint histograms for (idx_pv=0; idx_pv<8; idx_pv++) { idx_mbin = floor ((m_img[n[idx_pv]] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; if (idx_mbin != mi_hist->moving.big_bin) { m_hist_omp[mi_hist->moving.bins*thread_num + idx_mbin] += w[idx_pv]; } if (idx_jbin != mi_hist->joint.big_bin) { j_hist_omp[mi_hist->moving.bins*mi_hist->fixed.bins*thread_num + idx_jbin] += w[idx_pv]; } } } #endif /* JAS 2010.11.30 * This is an intentionally bad idea and will be removed as soon the paper I'm * writing sees some ink. * * Uses CRITICAL SECTIONS instead of locks to make histogram writes thread * safe when employing multi-core */ #if (OPENMP_FOUND) static inline void bspline_mi_hist_add_pvi_8_omp_crits ( Joint_histogram* mi_hist, Volume *fixed, Volume *moving, int fidx, int midx_f, float li_1[3], /* Fraction of interpolant in lower index */ float li_2[3]) /* Fraction of interpolant in upper index */ { float w[8]; int n[8]; plm_long idx_fbin, idx_mbin, idx_jbin, idx_pv; int offset_fbin; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; double *f_hist = mi_hist->f_hist; double *m_hist = mi_hist->m_hist; double *j_hist = mi_hist->j_hist; /* Compute partial volumes from trilinear interpolation weights */ w[0] = li_1[0] * li_1[1] * li_1[2]; // Partial Volume w0 w[1] = li_2[0] * li_1[1] * li_1[2]; // Partial Volume w1 w[2] = li_1[0] * li_2[1] * li_1[2]; // Partial Volume w2 w[3] = li_2[0] * li_2[1] * li_1[2]; // Partial Volume w3 w[4] = li_1[0] * li_1[1] * li_2[2]; // Partial Volume w4 w[5] = li_2[0] * li_1[1] * li_2[2]; // Partial Volume w5 w[6] = li_1[0] * li_2[1] * li_2[2]; // Partial Volume w6 w[7] = li_2[0] * li_2[1] * li_2[2]; // Partial Volume w7 /* Note that Sum(wN) for N within [0,7] should = 1 */ // Calculate Point Indices for 8 neighborhood n[0] = midx_f; n[1] = n[0] + 1; n[2] = n[0] + moving->dim[0]; n[3] = n[2] + 1; n[4] = n[0] + moving->dim[0]*moving->dim[1]; n[5] = n[4] + 1; n[6] = n[4] + moving->dim[0]; n[7] = n[6] + 1; // Calculate fixed histogram bin and increment it idx_fbin = floor ((f_img[fidx] - mi_hist->fixed.offset) / mi_hist->fixed.delta); #pragma omp critical (fixed_histogram) { f_hist[idx_fbin]++; } offset_fbin = idx_fbin * mi_hist->moving.bins; // Add PV weights to moving & joint histograms for (idx_pv=0; idx_pv<8; idx_pv++) { idx_mbin = floor ((m_img[n[idx_pv]] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; if (idx_mbin != mi_hist->moving.big_bin) { #pragma omp critical (moving_histogram) { m_hist[idx_mbin] += w[idx_pv]; } } if (idx_jbin != mi_hist->joint.big_bin) { #pragma omp critical (joint_histogram) { j_hist[idx_jbin] += w[idx_pv]; } } } } #endif /* Used locks to make histogram writes * thread safe when employing multi-core */ #if (OPENMP_FOUND) static inline void bspline_mi_hist_add_pvi_8_omp ( Joint_histogram* mi_hist, Volume *fixed, Volume *moving, int fidx, int midx_f, float li_1[3], /* Fraction of interpolant in lower index */ float li_2[3], /* Fraction of interpolant in upper index */ omp_lock_t* f_locks, omp_lock_t* m_locks, omp_lock_t* j_locks) { float w[8]; int n[8]; plm_long idx_fbin, idx_mbin, idx_jbin, idx_pv; int offset_fbin; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; double *f_hist = mi_hist->f_hist; double *m_hist = mi_hist->m_hist; double *j_hist = mi_hist->j_hist; /* Compute partial volumes from trilinear interpolation weights */ w[0] = li_1[0] * li_1[1] * li_1[2]; // Partial Volume w0 w[1] = li_2[0] * li_1[1] * li_1[2]; // Partial Volume w1 w[2] = li_1[0] * li_2[1] * li_1[2]; // Partial Volume w2 w[3] = li_2[0] * li_2[1] * li_1[2]; // Partial Volume w3 w[4] = li_1[0] * li_1[1] * li_2[2]; // Partial Volume w4 w[5] = li_2[0] * li_1[1] * li_2[2]; // Partial Volume w5 w[6] = li_1[0] * li_2[1] * li_2[2]; // Partial Volume w6 w[7] = li_2[0] * li_2[1] * li_2[2]; // Partial Volume w7 /* Note that Sum(wN) for N within [0,7] should = 1 */ // Calculate Point Indices for 8 neighborhood n[0] = midx_f; n[1] = n[0] + 1; n[2] = n[0] + moving->dim[0]; n[3] = n[2] + 1; n[4] = n[0] + moving->dim[0]*moving->dim[1]; n[5] = n[4] + 1; n[6] = n[4] + moving->dim[0]; n[7] = n[6] + 1; // Calculate fixed histogram bin and increment it idx_fbin = floor ((f_img[fidx] - mi_hist->fixed.offset) / mi_hist->fixed.delta); if (mi_hist->fixed.type == HIST_VOPT) { idx_fbin = mi_hist->fixed.key_lut[idx_fbin]; } omp_set_lock(&f_locks[idx_fbin]); f_hist[idx_fbin]++; omp_unset_lock(&f_locks[idx_fbin]); offset_fbin = idx_fbin * mi_hist->moving.bins; // Add PV weights to moving & joint histograms for (idx_pv=0; idx_pv<8; idx_pv++) { idx_mbin = floor ((m_img[n[idx_pv]] - mi_hist->moving.offset) / mi_hist->moving.delta); if (mi_hist->moving.type == HIST_VOPT) { idx_mbin = mi_hist->moving.key_lut[idx_mbin]; } idx_jbin = offset_fbin + idx_mbin; if (idx_mbin != mi_hist->moving.big_bin) { omp_set_lock(&m_locks[idx_mbin]); m_hist[idx_mbin] += w[idx_pv]; omp_unset_lock(&m_locks[idx_mbin]); } if (idx_jbin != mi_hist->joint.big_bin) { omp_set_lock(&j_locks[idx_jbin]); j_hist[idx_jbin] += w[idx_pv]; omp_unset_lock(&j_locks[idx_jbin]); } } } #endif #if defined (commentout) static inline void bspline_mi_hist_add_pvi_6 ( Joint_histogram* mi_hist, Volume *fixed, Volume *moving, int fidx, int midx_f, float mijk[3] ) { long miqs[3], mjqs[3], mkqs[3]; /* Rounded indices */ float fxqs[3], fyqs[3], fzqs[3]; /* Fractional values */ float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; const float ONE_THIRD = 1.0f / 3.0f; /* Compute quadratic interpolation fractions */ clamp_quadratic_interpolate_inline (mijk[0], moving->dim[0], miqs, fxqs); clamp_quadratic_interpolate_inline (mijk[1], moving->dim[1], mjqs, fyqs); clamp_quadratic_interpolate_inline (mijk[2], moving->dim[2], mkqs, fzqs); #if 0 printf ("[%d %d %d], [%d %d %d], [%d %d %d]\n", miqs[0], miqs[1], miqs[2], mjqs[0], mjqs[1], mjqs[2], mkqs[0], mkqs[1], mkqs[2] ); printf ("[%f %f %f], [%f %f %f], [%f %f %f]\n", fxqs[0], fxqs[1], fxqs[2], fyqs[0], fyqs[1], fyqs[2], fzqs[0], fzqs[1], fzqs[2] ); #endif /* PARTIAL VALUE INTERPOLATION - 6 neighborhood */ midx_f = (mkqs[1] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[1]; bspline_mi_hist_add (mi_hist, f_img[fidx], m_img[midx_f], ONE_THIRD * (fxqs[1] + fyqs[1] + fzqs[1])); midx_f = (mkqs[1] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[0]; bspline_mi_hist_add (mi_hist, f_img[fidx], m_img[midx_f], ONE_THIRD * fxqs[0]); midx_f = (mkqs[1] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[2]; bspline_mi_hist_add (mi_hist, f_img[fidx], m_img[midx_f], ONE_THIRD * fxqs[2]); midx_f = (mkqs[1] * moving->dim[1] + mjqs[0]) * moving->dim[0] + miqs[1]; bspline_mi_hist_add (mi_hist, f_img[fidx], m_img[midx_f], ONE_THIRD * fyqs[0]); midx_f = (mkqs[1] * moving->dim[1] + mjqs[2]) * moving->dim[0] + miqs[1]; bspline_mi_hist_add (mi_hist, f_img[fidx], m_img[midx_f], ONE_THIRD * fyqs[2]); midx_f = (mkqs[0] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[1]; bspline_mi_hist_add (mi_hist, f_img[fidx], m_img[midx_f], ONE_THIRD * fzqs[0]); midx_f = (mkqs[2] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[1]; bspline_mi_hist_add (mi_hist, f_img[fidx], m_img[midx_f], ONE_THIRD * fzqs[2]); } #endif /* ----------------------------------------------------------------------- bspline_mi_pvi_8_dc_dv bspline_mi_pvi_6_dc_dv Compute pixel contribution to gradient based on histogram change There are 6 or 8 correspondences between fixed and moving. Each of these correspondences will update 2 or 3 histogram bins (other options are possible, but this is my current strategy). First, figure out which histogram bins this correspondence influences by calling bspline_mi_hist_lookup(). Next, compute dS/dP * dP/dx. dP/dx is zero outside of the 8 neighborhood. Otherwise it is +/- 1/pixel size. dS/dP is 1/N (ln (N P / Pf Pm) - I) dS/dP is weighted by the relative contribution of the 2 histogram bins. dS_dx and dc_dv are really the same thing. Just different notation. For dc_dv: We do -= instead of += because our optimizer wants to minimize instead of maximize. The right hand side is - for "left" voxels, and + for "right" voxels. Use a hard threshold on j_hist[j_idxs] to prevent overflow. This test should be reconsidered, because it is theoretically unsound. Some trivial speedups for the future: The pixel size component is constant, so we can post-multiply. 1/N is constant, so post-multiply. ----------------------------------------------------------------------- */ static inline void bspline_mi_pvi_8_dc_dv ( float dc_dv[3], /* Output */ Joint_histogram* mi_hist, /* Input */ Bspline_state *bst, /* Input */ Volume *fixed, /* Input */ Volume *moving, /* Input */ int fidx, /* Input */ int midx_f, /* Input */ float mijk[3], /* Input */ float num_vox_f, /* Input */ float li_1[3], /* Input */ float li_2[3] /* Input */ ) { float dS_dP; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; Bspline_score* ssd = &bst->ssd; int idx_fbin, idx_mbin, idx_jbin, idx_pv; int offset_fbin; int n[8]; float dw[24]; dc_dv[0] = dc_dv[1] = dc_dv[2] = 0.0f; /* Calculate Point Indices for 8 neighborhood */ n[0] = midx_f; n[1] = n[0] + 1; n[2] = n[0] + moving->dim[0]; n[3] = n[2] + 1; n[4] = n[0] + moving->dim[0]*moving->dim[1]; n[5] = n[4] + 1; n[6] = n[4] + moving->dim[0]; n[7] = n[6] + 1; /* Pre-compute differential PV slices */ dw[3*0+0] = ( -1 ) * li_1[1] * li_1[2]; // dw0 dw[3*0+1] = li_1[0] * ( -1 ) * li_1[2]; dw[3*0+2] = li_1[0] * li_1[1] * ( -1 ); dw[3*1+0] = ( +1 ) * li_1[1] * li_1[2]; // dw1 dw[3*1+1] = li_2[0] * ( -1 ) * li_1[2]; dw[3*1+2] = li_2[0] * li_1[1] * ( -1 ); dw[3*2+0] = ( -1 ) * li_2[1] * li_1[2]; // dw2 dw[3*2+1] = li_1[0] * ( +1 ) * li_1[2]; dw[3*2+2] = li_1[0] * li_2[1] * ( -1 ); dw[3*3+0] = ( +1 ) * li_2[1] * li_1[2]; // dw3 dw[3*3+1] = li_2[0] * ( +1 ) * li_1[2]; dw[3*3+2] = li_2[0] * li_2[1] * ( -1 ); dw[3*4+0] = ( -1 ) * li_1[1] * li_2[2]; // dw4 dw[3*4+1] = li_1[0] * ( -1 ) * li_2[2]; dw[3*4+2] = li_1[0] * li_1[1] * ( +1 ); dw[3*5+0] = ( +1 ) * li_1[1] * li_2[2]; // dw5 dw[3*5+1] = li_2[0] * ( -1 ) * li_2[2]; dw[3*5+2] = li_2[0] * li_1[1] * ( +1 ); dw[3*6+0] = ( -1 ) * li_2[1] * li_2[2]; // dw6 dw[3*6+1] = li_1[0] * ( +1 ) * li_2[2]; dw[3*6+2] = li_1[0] * li_2[1] * ( +1 ); dw[3*7+0] = ( +1 ) * li_2[1] * li_2[2]; // dw7 dw[3*7+1] = li_2[0] * ( +1 ) * li_2[2]; dw[3*7+2] = li_2[0] * li_2[1] * ( +1 ); /* Fixed image voxel's histogram index */ idx_fbin = floor ((f_img[fidx] - mi_hist->fixed.offset) / mi_hist->fixed.delta); if (mi_hist->fixed.type == HIST_VOPT) { idx_fbin = mi_hist->fixed.key_lut[idx_fbin]; } offset_fbin = idx_fbin * mi_hist->moving.bins; /* Partial Volume Contributions */ for (idx_pv=0; idx_pv<8; idx_pv++) { idx_mbin = floor ((m_img[n[idx_pv]] - mi_hist->moving.offset) / mi_hist->moving.delta); if (mi_hist->moving.type == HIST_VOPT) { idx_mbin = mi_hist->moving.key_lut[idx_mbin]; } idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > 0.0001) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric; dc_dv[0] -= dw[3*idx_pv+0] * dS_dP; dc_dv[1] -= dw[3*idx_pv+1] * dS_dP; dc_dv[2] -= dw[3*idx_pv+2] * dS_dP; } } dc_dv[0] = dc_dv[0] / num_vox_f / moving->spacing[0]; dc_dv[1] = dc_dv[1] / num_vox_f / moving->spacing[1]; dc_dv[2] = dc_dv[2] / num_vox_f / moving->spacing[2]; #if defined (commentout) for (idx_pv=0; idx_pv<8; idx_pv++) { printf ("dw%i [ %2.5f %2.5f %2.5f ]\n", idx_pv, dw[3*idx_pv+0], dw[3*idx_pv+1], dw[3*idx_pv+2]); } printf ("S [ %2.5f %2.5f %2.5f ]\n\n\n", dc_dv[0], dc_dv[1], dc_dv[2]); exit(0); #endif } static inline void bspline_mi_pvi_6_dc_dv ( float dc_dv[3], /* Output */ Joint_histogram* mi_hist, /* Input */ Bspline_state *bst, /* Input */ Volume *fixed, /* Input */ Volume *moving, /* Input */ int fidx, /* Input: Index into fixed image */ int midx_f, /* Input: Index into moving image (unnecessary) */ float mijk[3], /* Input: ijk indices in moving image (vox) */ float num_vox_f /* Input: Number of voxels falling into the moving image */ ) { long miqs[3], mjqs[3], mkqs[3]; /* Rounded indices */ float fxqs[3], fyqs[3], fzqs[3]; /* Fractional values */ long j_idxs[2]; long m_idxs[2]; long f_idxs[1]; float fxs[2]; float dS_dP; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; Bspline_score* ssd = &bst->ssd; int debug = 0; dc_dv[0] = dc_dv[1] = dc_dv[2] = 0.0f; /* Compute quadratic interpolation fractions */ clamp_quadratic_interpolate_grad_inline (mijk[0], moving->dim[0], miqs, fxqs); clamp_quadratic_interpolate_grad_inline (mijk[1], moving->dim[1], mjqs, fyqs); clamp_quadratic_interpolate_grad_inline (mijk[2], moving->dim[2], mkqs, fzqs); /* PARTIAL VALUE INTERPOLATION - 6 neighborhood */ float smetric = ssd->curr_smetric; midx_f = (mkqs[1] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[1]; bspline_mi_hist_lookup (j_idxs, m_idxs, f_idxs, fxs, mi_hist, f_img[fidx], m_img[midx_f]); dS_dP = compute_dS_dP (j_hist, f_hist, m_hist, j_idxs, f_idxs, m_idxs, num_vox_f, fxs, smetric, debug); dc_dv[0] += - fxqs[1] * dS_dP; dc_dv[1] += - fyqs[1] * dS_dP; dc_dv[2] += - fzqs[1] * dS_dP; midx_f = (mkqs[1] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[0]; bspline_mi_hist_lookup (j_idxs, m_idxs, f_idxs, fxs, mi_hist, f_img[fidx], m_img[midx_f]); dS_dP = compute_dS_dP (j_hist, f_hist, m_hist, j_idxs, f_idxs, m_idxs, num_vox_f, fxs, smetric, debug); dc_dv[0] += - fxqs[0] * dS_dP; midx_f = (mkqs[1] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[2]; bspline_mi_hist_lookup (j_idxs, m_idxs, f_idxs, fxs, mi_hist, f_img[fidx], m_img[midx_f]); dS_dP = compute_dS_dP (j_hist, f_hist, m_hist, j_idxs, f_idxs, m_idxs, num_vox_f, fxs, smetric, debug); dc_dv[0] += - fxqs[2] * dS_dP; midx_f = (mkqs[1] * moving->dim[1] + mjqs[0]) * moving->dim[0] + miqs[1]; bspline_mi_hist_lookup (j_idxs, m_idxs, f_idxs, fxs, mi_hist, f_img[fidx], m_img[midx_f]); dS_dP = compute_dS_dP (j_hist, f_hist, m_hist, j_idxs, f_idxs, m_idxs, num_vox_f, fxs, smetric, debug); dc_dv[1] += - fyqs[0] * dS_dP; midx_f = (mkqs[1] * moving->dim[1] + mjqs[2]) * moving->dim[0] + miqs[1]; bspline_mi_hist_lookup (j_idxs, m_idxs, f_idxs, fxs, mi_hist, f_img[fidx], m_img[midx_f]); dS_dP = compute_dS_dP (j_hist, f_hist, m_hist, j_idxs, f_idxs, m_idxs, num_vox_f, fxs, smetric, debug); dc_dv[1] += - fyqs[2] * dS_dP; midx_f = (mkqs[0] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[1]; bspline_mi_hist_lookup (j_idxs, m_idxs, f_idxs, fxs, mi_hist, f_img[fidx], m_img[midx_f]); dS_dP = compute_dS_dP (j_hist, f_hist, m_hist, j_idxs, f_idxs, m_idxs, num_vox_f, fxs, smetric, debug); dc_dv[2] += - fzqs[0] * dS_dP; midx_f = (mkqs[2] * moving->dim[1] + mjqs[1]) * moving->dim[0] + miqs[1]; bspline_mi_hist_lookup (j_idxs, m_idxs, f_idxs, fxs, mi_hist, f_img[fidx], m_img[midx_f]); dS_dP = compute_dS_dP (j_hist, f_hist, m_hist, j_idxs, f_idxs, m_idxs, num_vox_f, fxs, smetric, debug); dc_dv[2] += - fzqs[2] * dS_dP; dc_dv[0] = dc_dv[0] / moving->spacing[0] / num_vox_f; dc_dv[1] = dc_dv[1] / moving->spacing[1] / num_vox_f; dc_dv[2] = dc_dv[2] / moving->spacing[2] / num_vox_f; } /* ----------------------------------------------------------------------- Scoring functions ----------------------------------------------------------------------- */ /* B-Spline Registration using Mutual Information * Implementation I * -- Histograms are OpenMP accelerated * -- Uses OpenMP for Cost & dc_dv computation * -- Uses methods introduced in bspline_score_g_mse * to compute dc_dp more rapidly. */ #if (OPENMP_FOUND) void bspline_score_i_mi ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Bspline_score* ssd = &bst->ssd; Joint_histogram* mi_hist = bst->get_mi_hist(); long pidx; float num_vox_f; float mse_score = 0.0f; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; double mhis = 0.0f; /* Moving histogram incomplete sum */ double jhis = 0.0f; /* Joint histogram incomplete sum */ int num_threads; double* f_hist_omp = NULL; double* m_hist_omp = NULL; double* j_hist_omp = NULL; plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); memset (f_hist, 0, mi_hist->fixed.bins * sizeof(double)); memset (m_hist, 0, mi_hist->moving.bins * sizeof(double)); memset (j_hist, 0, mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(double)); memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); #pragma omp parallel #pragma omp master { num_threads = omp_get_num_threads (); f_hist_omp = (double*) malloc (num_threads * sizeof (double) * mi_hist->fixed.bins); m_hist_omp = (double*) malloc (num_threads * sizeof (double) * mi_hist->moving.bins); j_hist_omp = (double*) malloc (num_threads * sizeof (double) * mi_hist->fixed.bins * mi_hist->moving.bins); memset (f_hist_omp, 0, num_threads * sizeof (double) * mi_hist->fixed.bins); memset (m_hist_omp, 0, num_threads * sizeof (double) * mi_hist->moving.bins); memset (j_hist_omp, 0, num_threads * sizeof (double) * mi_hist->fixed.bins * mi_hist->moving.bins); } /* PASS 1 - Accumulate histogram */ #pragma omp parallel for LOOP_THRU_VOL_TILES (pidx, bxf) { int rc; plm_long fijk[3], fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ int thread_num = omp_get_thread_num (); /* Get tile indices from linear index */ COORDS_FROM_INDEX (p, pidx, bxf->rdims); /* Serial through the voxels in a tile */ LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { /* Construct coordinates into fixed image volume */ GET_VOL_COORDS (fijk, p, q, bxf); /* Check to make sure the indices are valid (inside volume) */ if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) { continue; } if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) { continue; } if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) { continue; } /* Compute space coordinates of fixed image voxel */ GET_REAL_SPACE_COORDS (fxyz, fijk, bxf); /* Compute deformation vector (dxyz) for voxel */ bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ rc = bspline_find_correspondence_dcos (mxyz, mijk, fxyz, dxyz, moving); /* If voxel is not inside moving image */ if (!rc) continue; /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Constrcut the fixed image linear index within volume space */ fidx = volume_index (fixed->dim, fijk); /* Find linear index the corner voxel used to identifiy the * neighborhood of the moving image voxels corresponding * to the current fixed image voxel */ midx_f = volume_index (moving->dim, mijk_f); /* Add to histogram */ bspline_mi_hist_add_pvi_8_omp_v2 ( mi_hist, f_hist_omp, m_hist_omp, j_hist_omp, fixed, moving, fidx, midx_f, li_1, li_2, thread_num); } } } // tile } // openmp /* Merge the OpenMP histogram copies */ for (plm_long b=0; bfixed.bins; b++) { for (int c=0; cfixed.bins + b]; } } for (plm_long b=0; bmoving.bins; b++) { for (int c=0; cmoving.bins + b]; } } for (plm_long j=0; jfixed.bins; j++) { for (plm_long i=0; imoving.bins; i++) { for (int c=0; cmoving.bins+i] += j_hist_omp[c*mi_hist->moving.bins*mi_hist->fixed.bins + j*mi_hist->moving.bins + i]; } } } /* Compute num_vox and find fullest fixed hist bin */ for (plm_long i=0; ifixed.bins; i++) { if (f_hist[i] > f_hist[mi_hist->fixed.big_bin]) { mi_hist->fixed.big_bin = i; } ssd->curr_num_vox += f_hist[i]; } /* Fill in the missing histogram bin */ for (plm_long i=0; imoving.bins; i++) { mhis += m_hist[i]; } m_hist[mi_hist->moving.big_bin] = (double) ssd->curr_num_vox - mhis; /* Look for the biggest moving histogram bin */ // printf ("moving.big_bin [%i -> ", mi_hist->moving.big_bin); for (plm_long i=0; imoving.bins; i++) { if (m_hist[i] > m_hist[mi_hist->moving.big_bin]) { mi_hist->moving.big_bin = i; } } // printf ("%i]\n", mi_hist->moving.big_bin); /* Fill in the missing jnt hist bin */ for (plm_long j=0; jfixed.bins; j++) { for (plm_long i=0; imoving.bins; i++) { jhis += j_hist[j*mi_hist->moving.bins + i]; } } j_hist[mi_hist->joint.big_bin] = (double) ssd->curr_num_vox - jhis; /* Look for the biggest joint histogram bin */ // printf ("joint.big_bin [%i -> ", mi_hist->joint.big_bin); for (plm_long j=0; jfixed.bins; j++) { for (plm_long i=0; imoving.bins; i++) { if (j_hist[j*mi_hist->moving.bins + i] > j_hist[mi_hist->joint.big_bin]) { mi_hist->joint.big_bin = j*mi_hist->moving.bins + i; } } } // printf ("%i]\n", mi_hist->joint.big_bin); /* Draw histogram images if user wants them */ if (parms->xpm_hist_dump) { dump_xpm_hist (mi_hist, parms->xpm_hist_dump, bst->it); } /* Display histrogram stats in debug mode */ if (parms->debug) { double tmp; long zz; for (zz=0,tmp=0; zz < mi_hist->fixed.bins; zz++) { tmp += f_hist[zz]; } printf ("f_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins; zz++) { tmp += m_hist[zz]; } printf ("m_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins * mi_hist->fixed.bins; zz++) { tmp += j_hist[zz]; } printf ("j_hist total: %f\n", tmp); } /* Compute score */ ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox); num_vox_f = (float) ssd->curr_num_vox; /* PASS 2 - Compute Gradient (Parallel across tiles) */ #pragma omp parallel for LOOP_THRU_VOL_TILES (pidx, bxf) { int rc; plm_long fijk[3], fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float dc_dv[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); /* Get tile indices from linear index */ COORDS_FROM_INDEX (p, pidx, bxf->rdims); /* Serial through the voxels in a tile */ LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { /* Construct coordinates into fixed image volume */ GET_VOL_COORDS (fijk, p, q, bxf); /* Check to make sure the indices are valid (inside volume) */ if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) { continue; } if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) { continue; } if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) { continue; } /* Compute space coordinates of fixed image voxel */ GET_REAL_SPACE_COORDS (fxyz, fijk, bxf); /* Compute deformation vector (dxyz) for voxel */ bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ rc = bspline_find_correspondence_dcos (mxyz, mijk, fxyz, dxyz, moving); /* If voxel is not inside moving image */ if (!rc) continue; /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Constrcut the fixed image linear index within volume space */ fidx = volume_index (fixed->dim, fijk); /* Find linear index the corner voxel used to identifiy the * neighborhood of the moving image voxels corresponding * to the current fixed image voxel */ midx_f = volume_index (moving->dim, mijk_f); /* Compute dc_dv */ bspline_mi_pvi_8_dc_dv (dc_dv, mi_hist, bst, fixed, moving, fidx, midx_f, mijk, num_vox_f, li_1, li_2); /* Update condensed tile sets */ bspline_update_sets_b (sets_x, sets_y, sets_z, q, dc_dv, bxf); } } } // tile /* We now have a tile of condensed dc_dv values (64 values). * Let's put each one in the proper slot within the control * point bin its belogs to */ bspline_sort_sets (cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, pidx, bxf); } // openmp /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. The result with be dc_dp. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); #if 0 if (parms->debug) { fclose (fp); } #endif mse_score = mse_score / ssd->curr_num_vox; } #endif /* B-Spline Registration using Mutual Information * Implementation H (D w/ direction cosines & true roi support) * -- Uses OpenMP for Cost & dc_dv computation * -- Uses methods introduced in bspline_score_g_mse * to compute dc_dp more rapidly. */ void bspline_score_h_mi ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Bspline_score* ssd = &bst->ssd; Joint_histogram* mi_hist = bst->get_mi_hist(); float diff; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; float num_vox_f; long pidx; float m_val; plm_long fijk[3] = {0}; plm_long fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float mse_score = 0.0f; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); Volume* fixed_roi = bst->fixed_roi; Volume* moving_roi = bst->moving_roi; #if 0 Volume* dbg_vol = volume_clone_empty (moving); float* dbg_img = (float*) dbg_vol->img; #endif FILE* fp = 0; static int it = 0; if (parms->debug) { char buf[1024]; sprintf (buf, "dump_mi_%02d.txt", it); std::string fn = parms->debug_dir + "/" + buf; fp = plm_fopen (fn.c_str(), "wb"); it ++; } memset (f_hist, 0, mi_hist->fixed.bins * sizeof(double)); memset (m_hist, 0, mi_hist->moving.bins * sizeof(double)); memset (j_hist, 0, mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(double)); memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); /* PASS 1 - Accumulate histogram */ LOOP_Z (fijk, fxyz, fixed) { p[2] = REGION_INDEX_Z (fijk, bxf); q[2] = REGION_OFFSET_Z (fijk, bxf); LOOP_Y (fijk, fxyz, fixed) { p[1] = REGION_INDEX_Y (fijk, bxf); q[1] = REGION_OFFSET_Y (fijk, bxf); LOOP_X (fijk, fxyz, fixed) { int rc; p[0] = REGION_INDEX_X (fijk, bxf); q[0] = REGION_OFFSET_X (fijk, bxf); /* JAS 2012.03.26: Tends to break the optimizer (PGTOL) */ /* Check to make sure the indices are valid (inside roi) */ if (fixed_roi) { if (!inside_roi (fxyz, fixed_roi)) continue; } /* Get B-spline deformation vector */ pidx = volume_index (bxf->rdims, p); bspline_interp_pix_c (dxyz, bxf, pidx, q); rc = bspline_find_correspondence_dcos_roi ( mxyz, mijk, fxyz, dxyz, moving, moving_roi); /* If voxel is not inside moving image */ if (!rc) continue; if (parms->debug) { fprintf (fp, "[%i %i %i]\t->[%f %f %f]\n", (int) fijk[0], (int) fijk[1], (int) fijk[2], mijk[0], mijk[1], mijk[2]); } li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Find linear index of fixed image voxel */ fidx = volume_index (fixed->dim, fijk); /* Find linear index of "corner voxel" in moving image */ midx_f = volume_index (moving->dim, mijk_f); /* Compute moving image intensity using linear interpolation */ // NOTE: Not used by MI PVI8 LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], midx_f, m_img, moving ); /* PARTIAL VALUE INTERPOLATION - 8 neighborhood */ mi_hist->add_pvi_8 ( fixed, moving, fidx, midx_f, li_1, li_2); /* Compute intensity difference */ diff = m_val - f_img[fidx]; mse_score += diff * diff; ssd->curr_num_vox ++; } /* LOOP_THRU_ROI_X */ } /* LOOP_THRU_ROI_Y */ } /* LOOP_TRHU_ROI_Z */ #if 0 write_mha ("dbg_vol.mha", dbg_vol); exit (0); #endif /* Draw histogram images if user wants them */ if (parms->xpm_hist_dump) { dump_xpm_hist (mi_hist, parms->xpm_hist_dump, bst->it); } /* Compute score */ ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox); num_vox_f = (float) ssd->curr_num_vox; /* PASS 2 - Compute Gradient (Parallel across tiles) */ #pragma omp parallel for LOOP_THRU_VOL_TILES (pidx, bxf) { int rc; plm_long fijk[3], fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float dc_dv[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); /* Get tile indices from linear index */ COORDS_FROM_INDEX (p, pidx, bxf->rdims); /* Serial through the voxels in a tile */ LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { /* Construct ijk indices into fixed image volume */ GET_VOL_COORDS (fijk, p, q, bxf); /* Check to make sure the indices are valid (inside volume) */ if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) { continue; } if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) { continue; } if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) { continue; } /* Compute space coordinates of fixed image voxel */ POSITION_FROM_COORDS (fxyz, fijk, bxf->img_origin, fixed->step); /* JAS 2012.03.26: Tends to break the optimizer (PGTOL) */ /* Check to make sure the indices are valid (inside roi) */ if (fixed_roi) { if (!inside_roi (fxyz, fixed_roi)) continue; } /* Compute deformation vector (dxyz) for voxel */ bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ rc = bspline_find_correspondence_dcos_roi ( mxyz, mijk, fxyz, dxyz, moving, moving_roi); /* If voxel is not inside moving image */ if (!rc) continue; /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Construct the fixed image linear index within volume space */ fidx = volume_index (fixed->dim, fijk); /* Find linear index the corner voxel used to identifiy the * neighborhood of the moving image voxels corresponding * to the current fixed image voxel */ midx_f = volume_index (moving->dim, mijk_f); /* Compute dc_dv */ bspline_mi_pvi_8_dc_dv_dcos ( dc_dv, mi_hist, bst, fixed, moving, fidx, midx_f, num_vox_f, li_1, li_2 ); /* Update condensed tile sets */ bspline_update_sets_b ( sets_x, sets_y, sets_z, q, dc_dv, bxf ); } /* LOOP_THRU_TILE_X */ } /* LOOP_THRU_TILE_Y */ } /* LOOP_THRU_TILE_Z */ /* We now have a tile of condensed dc_dv values (64 values). * Let's put each one in the proper slot within the control * point bin its belogs to */ bspline_sort_sets (cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, pidx, bxf); } /* LOOP_THRU_VOL_TILES */ /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. The result will be dc_dp. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); if (parms->debug) { fclose (fp); } mse_score = mse_score / ssd->curr_num_vox; if (parms->debug) { printf ("<< MSE %3.3f >>\n", mse_score); } } /* B-Spline Registration using Mutual Information * Implementation G (D w/ direction cosines) * -- Uses OpenMP for Cost & dc_dv computation * -- Uses methods introduced in bspline_score_g_mse * to compute dc_dp more rapidly. */ void bspline_score_g_mi ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Bspline_score* ssd = &bst->ssd; Joint_histogram* mi_hist = bst->get_mi_hist(); float diff; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; float num_vox_f; long pidx; float m_val; plm_long fijk[3] = {0}; plm_long fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float mse_score = 0.0f; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); #if 0 FILE* fp = 0; char debug_fn[1024]; static int it = 0; if (parms->debug) { sprintf (debug_fn, "dump_mi_%02d.txt", it++); fp = fopen (debug_fn, "w"); } #endif memset (f_hist, 0, mi_hist->fixed.bins * sizeof(double)); memset (m_hist, 0, mi_hist->moving.bins * sizeof(double)); memset (j_hist, 0, mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(double)); memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); /* PASS 1 - Accumulate histogram */ LOOP_Z (fijk, fxyz, fixed) { p[2] = REGION_INDEX_Z (fijk, bxf); q[2] = REGION_OFFSET_Z (fijk, bxf); LOOP_Y (fijk, fxyz, fixed) { p[1] = REGION_INDEX_Y (fijk, bxf); q[1] = REGION_OFFSET_Y (fijk, bxf); LOOP_X (fijk, fxyz, fixed) { int rc; p[0] = REGION_INDEX_X (fijk, bxf); q[0] = REGION_OFFSET_X (fijk, bxf); /* Get B-spline deformation vector */ pidx = volume_index (bxf->rdims, p); bspline_interp_pix_c (dxyz, bxf, pidx, q); rc = bspline_find_correspondence_dcos (mxyz, mijk, fxyz, dxyz, moving); /* If voxel is not inside moving image */ if (!rc) continue; li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Find linear index of fixed image voxel */ fidx = volume_index (fixed->dim, fijk); /* Find linear index of "corner voxel" in moving image */ midx_f = volume_index (moving->dim, mijk_f); /* Compute moving image intensity using linear interpolation */ // NOTE: Not used by MI PVI8 LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], midx_f, m_img, moving ); /* PARTIAL VALUE INTERPOLATION - 8 neighborhood */ mi_hist->add_pvi_8 ( fixed, moving, fidx, midx_f, li_1, li_2); /* Compute intensity difference */ diff = m_val - f_img[fidx]; mse_score += diff * diff; ssd->curr_num_vox ++; } /* LOOP_THRU_ROI_X */ } /* LOOP_THRU_ROI_Y */ } /* LOOP_TRHU_ROI_Z */ /* Draw histogram images if user wants them */ if (parms->xpm_hist_dump) { dump_xpm_hist (mi_hist, parms->xpm_hist_dump, bst->it); } /* Compute score */ ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox); num_vox_f = (float) ssd->curr_num_vox; /* PASS 2 - Compute Gradient (Parallel across tiles) */ #pragma omp parallel for LOOP_THRU_VOL_TILES (pidx, bxf) { int rc; plm_long fijk[3], fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float dc_dv[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); /* Get tile indices from linear index */ COORDS_FROM_INDEX (p, pidx, bxf->rdims); /* Serial through the voxels in a tile */ LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { /* Construct ijk indices into fixed image volume */ GET_VOL_COORDS (fijk, p, q, bxf); /* Check to make sure the indices are valid (inside volume) */ if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) { continue; } if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) { continue; } if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) { continue; } /* Compute space coordinates of fixed image voxel */ POSITION_FROM_COORDS (fxyz, fijk, bxf->img_origin, fixed->step); /* Compute deformation vector (dxyz) for voxel */ bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ rc = bspline_find_correspondence_dcos (mxyz, mijk, fxyz, dxyz, moving); /* If voxel is not inside moving image */ if (!rc) continue; /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Constrcut the fixed image linear index within volume space */ fidx = volume_index (fixed->dim, fijk); /* Find linear index the corner voxel used to identifiy the * neighborhood of the moving image voxels corresponding * to the current fixed image voxel */ midx_f = volume_index (moving->dim, mijk_f); /* Compute dc_dv */ bspline_mi_pvi_8_dc_dv_dcos ( dc_dv, mi_hist, bst, fixed, moving, fidx, midx_f, num_vox_f, li_1, li_2 ); /* Update condensed tile sets */ bspline_update_sets_b ( sets_x, sets_y, sets_z, q, dc_dv, bxf ); } /* LOOP_THRU_TILE_X */ } /* LOOP_THRU_TILE_Y */ } /* LOOP_THRU_TILE_Z */ /* We now have a tile of condensed dc_dv values (64 values). * Let's put each one in the proper slot within the control * point bin its belogs to */ bspline_sort_sets (cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, pidx, bxf); } /* LOOP_THRU_VOL_TILES */ /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. The result will be dc_dp. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); #if 0 if (parms->debug) { fclose (fp); } #endif mse_score = mse_score / ssd->curr_num_vox; if (parms->debug) { printf ("<< MSE %3.3f >>\n", mse_score); } } /* JAS 2010.11.30 * This is an intentionally bad idea -- proof of concept code * * B-Spline Registration using Mutual Information * Implementation F (not good... only for comparison to E) * -- Histograms are OpenMP accelerated * (using CRITICAL SECTIONS... just to show better performance with locks) * -- Uses OpenMP for Cost & dc_dv computation * -- Uses methods introduced in bspline_score_g_mse * to compute dc_dp more rapidly. */ #if (OPENMP_FOUND) void bspline_score_f_mi ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Bspline_score* ssd = &bst->ssd; Joint_histogram* mi_hist = bst->get_mi_hist(); int pidx; float num_vox_f; float mse_score = 0.0f; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; double mhis = 0.0f; /* Moving histogram incomplete sum */ double jhis = 0.0f; /* Joint histogram incomplete sum */ plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); #if 0 FILE* fp = 0; static int it = 0; char debug_fn[1024]; if (parms->debug) { sprintf (debug_fn, "dump_mi_%02d.txt", it++); fp = fopen (debug_fn, "w"); } #endif memset (f_hist, 0, mi_hist->fixed.bins * sizeof(double)); memset (m_hist, 0, mi_hist->moving.bins * sizeof(double)); memset (j_hist, 0, mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(double)); memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); /* PASS 1 - Accumulate histogram */ #pragma omp parallel for LOOP_THRU_VOL_TILES (pidx, bxf) { int rc; plm_long fijk[3], fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ /* Get tile indices from linear index */ COORDS_FROM_INDEX (p, pidx, bxf->rdims); /* Serial through the voxels in a tile */ LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { /* Construct coordinates into fixed image volume */ GET_VOL_COORDS (fijk, p, q, bxf); /* Check to make sure the indices are valid (inside volume) */ if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) { continue; } if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) { continue; } if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) { continue; } /* Compute space coordinates of fixed image voxel */ GET_REAL_SPACE_COORDS (fxyz, fijk, bxf); /* Compute deformation vector (dxyz) for voxel */ bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ rc = bspline_find_correspondence_dcos (mxyz, mijk, fxyz, dxyz, moving); /* If voxel is not inside moving image */ if (!rc) continue; /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Constrcut the fixed image linear index within volume space */ fidx = volume_index (fixed->dim, fijk); /* Find linear index the corner voxel used to identifiy the * neighborhood of the moving image voxels corresponding * to the current fixed image voxel */ midx_f = volume_index (moving->dim, mijk_f); /* Add to histogram */ bspline_mi_hist_add_pvi_8_omp_crits (mi_hist, fixed, moving, fidx, midx_f, li_1, li_2); } } } // tile } // openmp /* Compute num_vox and find fullest fixed hist bin */ for (plm_long i=0; ifixed.bins; i++) { if (f_hist[i] > f_hist[mi_hist->fixed.big_bin]) { mi_hist->fixed.big_bin = i; } ssd->curr_num_vox += f_hist[i]; } /* Fill in the missing histogram bin */ for(plm_long i=0; imoving.bins; i++) { mhis += m_hist[i]; } m_hist[mi_hist->moving.big_bin] = (double) ssd->curr_num_vox - mhis; /* Look for the biggest moving histogram bin */ for(plm_long i=0; imoving.bins; i++) { if (m_hist[i] > m_hist[mi_hist->moving.big_bin]) { mi_hist->moving.big_bin = i; } } /* Fill in the missing jnt hist bin */ for(plm_long j=0; jfixed.bins; j++) { for(plm_long i=0; imoving.bins; i++) { jhis += j_hist[j*mi_hist->moving.bins + i]; } } j_hist[mi_hist->joint.big_bin] = (double) ssd->curr_num_vox - jhis; /* Look for the biggest joint histogram bin */ for(plm_long j=0; jfixed.bins; j++) { for(plm_long i=0; imoving.bins; i++) { if (j_hist[j*mi_hist->moving.bins + i] > j_hist[mi_hist->joint.big_bin]) { mi_hist->joint.big_bin = j*mi_hist->moving.bins + i; } } } /* Draw histogram images if user wants them */ if (parms->xpm_hist_dump) { dump_xpm_hist (mi_hist, parms->xpm_hist_dump, bst->it); } /* Display histrogram stats in debug mode */ if (parms->debug) { plm_long zz; double tmp; for (zz=0,tmp=0; zz < mi_hist->fixed.bins; zz++) { tmp += f_hist[zz]; } printf ("f_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins; zz++) { tmp += m_hist[zz]; } printf ("m_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins * mi_hist->fixed.bins; zz++) { tmp += j_hist[zz]; } printf ("j_hist total: %f\n", tmp); } /* Compute score */ ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox); num_vox_f = (float) ssd->curr_num_vox; /* PASS 2 - Compute Gradient (Parallel across tiles) */ #pragma omp parallel for LOOP_THRU_VOL_TILES (pidx, bxf) { int rc; plm_long fijk[3], fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float dc_dv[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); /* Get tile indices from linear index */ COORDS_FROM_INDEX (p, pidx, bxf->rdims); /* Serial through the voxels in a tile */ LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { /* Construct coordinates into fixed image volume */ GET_VOL_COORDS (fijk, p, q, bxf); /* Check to make sure the indices are valid (inside volume) */ if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) { continue; } if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) { continue; } if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) { continue; } /* Compute space coordinates of fixed image voxel */ GET_REAL_SPACE_COORDS (fxyz, fijk, bxf); /* Compute deformation vector (dxyz) for voxel */ bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ rc = bspline_find_correspondence_dcos (mxyz, mijk, fxyz, dxyz, moving); /* If voxel is not inside moving image */ if (!rc) continue; /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Constrcut the fixed image linear index within volume space */ fidx = volume_index (fixed->dim, fijk); /* Find linear index the corner voxel used to identifiy the * neighborhood of the moving image voxels corresponding * to the current fixed image voxel */ midx_f = volume_index (moving->dim, mijk_f); /* Compute dc_dv */ bspline_mi_pvi_8_dc_dv (dc_dv, mi_hist, bst, fixed, moving, fidx, midx_f, mijk, num_vox_f, li_1, li_2); /* Update condensed tile sets */ bspline_update_sets_b (sets_x, sets_y, sets_z, q, dc_dv, bxf); } } } // tile /* We now have a tile of condensed dc_dv values (64 values). * Let's put each one in the proper slot within the control * point bin its belogs to */ bspline_sort_sets (cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, pidx, bxf); } // openmp /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. The result with be dc_dp. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); #if 0 if (parms->debug) { fclose (fp); } #endif mse_score = mse_score / ssd->curr_num_vox; } #endif /* B-Spline Registration using Mutual Information * Implementation E (D is still faster) * -- Histograms are OpenMP accelerated * (only good on i7 core? really bad otherwise it seems...) * -- Uses OpenMP for Cost & dc_dv computation * -- Uses methods introduced in bspline_score_g_mse * to compute dc_dp more rapidly. */ #if (OPENMP_FOUND) void bspline_score_e_mi ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Bspline_score* ssd = &bst->ssd; Joint_histogram* mi_hist = bst->get_mi_hist(); long pidx; float num_vox_f; float mse_score = 0.0f; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; double mhis = 0.0f; /* Moving histogram incomplete sum */ double jhis = 0.0f; /* Joint histogram incomplete sum */ omp_lock_t *f_locks, *m_locks, *j_locks; plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); #if 0 FILE* fp = 0; char debug_fn[1024]; static int it = 0; if (parms->debug) { sprintf (debug_fn, "dump_mi_%02d.txt", it++); fp = fopen (debug_fn, "w"); } #endif memset (f_hist, 0, mi_hist->fixed.bins * sizeof(double)); memset (m_hist, 0, mi_hist->moving.bins * sizeof(double)); memset (j_hist, 0, mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(double)); memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); /* -- OpenMP locks for histograms --------------------- */ f_locks = (omp_lock_t*) malloc (mi_hist->fixed.bins * sizeof(omp_lock_t)); m_locks = (omp_lock_t*) malloc (mi_hist->moving.bins * sizeof(omp_lock_t)); j_locks = (omp_lock_t*) malloc (mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(omp_lock_t)); #pragma omp parallel for for (plm_long i=0; i < mi_hist->fixed.bins; i++) { omp_init_lock(&f_locks[i]); } #pragma omp parallel for for (plm_long i=0; i < mi_hist->moving.bins; i++) { omp_init_lock(&m_locks[i]); } #pragma omp parallel for for (plm_long i=0; i < mi_hist->fixed.bins * mi_hist->moving.bins; i++) { omp_init_lock(&j_locks[i]); } /* ---------------------------------------------------- */ /* PASS 1 - Accumulate histogram */ #pragma omp parallel for LOOP_THRU_VOL_TILES (pidx, bxf) { int rc; plm_long fijk[3], fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ /* Get tile indices from linear index */ COORDS_FROM_INDEX (p, pidx, bxf->rdims); /* Serial through the voxels in a tile */ LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { /* Construct coordinates into fixed image volume */ GET_VOL_COORDS (fijk, p, q, bxf); /* Check to make sure the indices are valid (inside volume) */ if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) { continue; } if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) { continue; } if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) { continue; } /* Compute space coordinates of fixed image voxel */ GET_REAL_SPACE_COORDS (fxyz, fijk, bxf); /* Compute deformation vector (dxyz) for voxel */ bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ rc = bspline_find_correspondence_dcos (mxyz, mijk, fxyz, dxyz, moving); /* If voxel is not inside moving image */ if (!rc) continue; /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Constrcut the fixed image linear index within volume space */ fidx = volume_index (fixed->dim, fijk); /* Find linear index the corner voxel used to identifiy the * neighborhood of the moving image voxels corresponding * to the current fixed image voxel */ midx_f = volume_index (moving->dim, mijk_f); /* Add to histogram */ bspline_mi_hist_add_pvi_8_omp (mi_hist, fixed, moving, fidx, midx_f, li_1, li_2, f_locks, m_locks, j_locks); #if defined (commentout) #endif } } } // tile } // openmp /* Compute num_vox and find fullest fixed hist bin */ for (plm_long i=0; ifixed.bins; i++) { if (f_hist[i] > f_hist[mi_hist->fixed.big_bin]) { mi_hist->fixed.big_bin = i; } ssd->curr_num_vox += f_hist[i]; } /* Fill in the missing histogram bin */ for (plm_long i=0; imoving.bins; i++) { mhis += m_hist[i]; } m_hist[mi_hist->moving.big_bin] = (double) ssd->curr_num_vox - mhis; /* Look for the biggest moving histogram bin */ // printf ("moving.big_bin [%i -> ", mi_hist->moving.big_bin); for (plm_long i=0; imoving.bins; i++) { if (m_hist[i] > m_hist[mi_hist->moving.big_bin]) { mi_hist->moving.big_bin = i; } } // printf ("%i]\n", mi_hist->moving.big_bin); /* Fill in the missing jnt hist bin */ for (plm_long j=0; jfixed.bins; j++) { for (plm_long i=0; imoving.bins; i++) { jhis += j_hist[j*mi_hist->moving.bins + i]; } } j_hist[mi_hist->joint.big_bin] = (double) ssd->curr_num_vox - jhis; /* Look for the biggest joint histogram bin */ // printf ("joint.big_bin [%i -> ", mi_hist->joint.big_bin); for (plm_long j=0; jfixed.bins; j++) { for (plm_long i=0; imoving.bins; i++) { if (j_hist[j*mi_hist->moving.bins + i] > j_hist[mi_hist->joint.big_bin]) { mi_hist->joint.big_bin = j*mi_hist->moving.bins + i; } } } // printf ("%i]\n", mi_hist->joint.big_bin); /* Draw histogram images if user wants them */ if (parms->xpm_hist_dump) { dump_xpm_hist (mi_hist, parms->xpm_hist_dump, bst->it); } /* Display histrogram stats in debug mode */ if (parms->debug) { double tmp; long zz; for (zz=0,tmp=0; zz < mi_hist->fixed.bins; zz++) { tmp += f_hist[zz]; } printf ("f_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins; zz++) { tmp += m_hist[zz]; } printf ("m_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins * mi_hist->fixed.bins; zz++) { tmp += j_hist[zz]; } printf ("j_hist total: %f\n", tmp); } /* Compute score */ ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox); num_vox_f = (float) ssd->curr_num_vox; /* PASS 2 - Compute Gradient (Parallel across tiles) */ #pragma omp parallel for LOOP_THRU_VOL_TILES (pidx, bxf) { int rc; plm_long fijk[3], fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float dc_dv[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); /* Get tile indices from linear index */ COORDS_FROM_INDEX (p, pidx, bxf->rdims); /* Serial through the voxels in a tile */ LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { /* Construct coordinates into fixed image volume */ GET_VOL_COORDS (fijk, p, q, bxf); /* Check to make sure the indices are valid (inside volume) */ if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) { continue; } if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) { continue; } if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) { continue; } /* Compute space coordinates of fixed image voxel */ GET_REAL_SPACE_COORDS (fxyz, fijk, bxf); /* Compute deformation vector (dxyz) for voxel */ bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ rc = bspline_find_correspondence_dcos (mxyz, mijk, fxyz, dxyz, moving); /* If voxel is not inside moving image */ if (!rc) continue; /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Constrcut the fixed image linear index within volume space */ fidx = volume_index (fixed->dim, fijk); /* Find linear index the corner voxel used to identifiy the * neighborhood of the moving image voxels corresponding * to the current fixed image voxel */ midx_f = volume_index (moving->dim, mijk_f); /* Compute dc_dv */ bspline_mi_pvi_8_dc_dv (dc_dv, mi_hist, bst, fixed, moving, fidx, midx_f, mijk, num_vox_f, li_1, li_2); /* Update condensed tile sets */ bspline_update_sets_b (sets_x, sets_y, sets_z, q, dc_dv, bxf); } } } // tile /* We now have a tile of condensed dc_dv values (64 values). * Let's put each one in the proper slot within the control * point bin its belogs to */ bspline_sort_sets (cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, pidx, bxf); } // openmp /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. The result with be dc_dp. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); #pragma omp parallel for for (long i=0; i < mi_hist->fixed.bins; i++) { omp_destroy_lock(&f_locks[i]); } #pragma omp parallel for for (long i=0; i < mi_hist->moving.bins; i++) { omp_destroy_lock(&m_locks[i]); } #pragma omp parallel for for (long i=0; i < mi_hist->fixed.bins * mi_hist->moving.bins; i++) { omp_destroy_lock(&j_locks[i]); } #if 0 if (parms->debug) { fclose (fp); } #endif mse_score = mse_score / ssd->curr_num_vox; } #endif /* B-Spline Registration using Mutual Information * Implementation D * -- Uses OpenMP for Cost & dc_dv computation * -- Uses methods introduced in bspline_score_g_mse * to compute dc_dp more rapidly. */ void bspline_score_d_mi ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Bspline_score* ssd = &bst->ssd; Joint_histogram* mi_hist = bst->get_mi_hist(); plm_long rijk[3]; float diff; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; float num_vox_f; long pidx; float m_val; plm_long fijk[3]; plm_long fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float mse_score = 0.0f; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); #if 0 FILE* fp = 0; char debug_fn[1024]; static int it = 0; if (parms->debug) { sprintf (debug_fn, "dump_mi_%02d.txt", it++); fp = fopen (debug_fn, "w"); } #endif memset (f_hist, 0, mi_hist->fixed.bins * sizeof(double)); memset (m_hist, 0, mi_hist->moving.bins * sizeof(double)); memset (j_hist, 0, mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(double)); memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); /* PASS 1 - Accumulate histogram */ LOOP_THRU_ROI_Z (rijk, fijk, bxf) { p[2] = REGION_INDEX_Z (rijk, bxf); q[2] = REGION_OFFSET_Z (rijk, bxf); fxyz[2] = GET_WORLD_COORD_Z_NO_DCOS (fijk, bxf); LOOP_THRU_ROI_Y (rijk, fijk, bxf) { p[1] = REGION_INDEX_Y (rijk, bxf); q[1] = REGION_OFFSET_Y (rijk, bxf); fxyz[1] = GET_WORLD_COORD_Y_NO_DCOS (fijk, bxf); LOOP_THRU_ROI_X (rijk, fijk, bxf) { int rc; p[0] = REGION_INDEX_X (rijk, bxf); q[0] = REGION_OFFSET_X (rijk, bxf); fxyz[0] = GET_WORLD_COORD_X_NO_DCOS (fijk, bxf); /* Get B-spline deformation vector */ pidx = volume_index (bxf->rdims, p); bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ rc = bspline_find_correspondence_dcos ( mxyz, mijk, fxyz, dxyz, moving ); /* If voxel is not inside moving image */ if (!rc) continue; li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Find linear index of fixed image voxel */ fidx = volume_index (fixed->dim, fijk); /* Find linear index of "corner voxel" in moving image */ midx_f = volume_index (moving->dim, mijk_f); /* Compute moving image intensity using linear interpolation */ // NOTE: Not used by MI PVI8 LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], midx_f, m_img, moving ); #if defined (commentout) /* LINEAR INTERPOLATION */ bspline_mi_hist_add (mi_hist, f_img[fidx], m_val, 1.0); #endif /* PARTIAL VALUE INTERPOLATION - 8 neighborhood */ mi_hist->add_pvi_8 ( fixed, moving, fidx, midx_f, li_1, li_2); #if defined (commentout) /* PARTIAL VALUE INTERPOLATION - 6 neighborhood */ bspline_mi_hist_add_pvi_6 ( mi_hist, fixed, moving, fidx, midx_f, mijk ); #endif /* Compute intensity difference */ diff = m_val - f_img[fidx]; mse_score += diff * diff; ssd->curr_num_vox ++; } /* LOOP_THRU_ROI_X */ } /* LOOP_THRU_ROI_Y */ } /* LOOP_TRHU_ROI_Z */ /* Draw histogram images if user wants them */ if (parms->xpm_hist_dump) { dump_xpm_hist (mi_hist, parms->xpm_hist_dump, bst->it); } /* Display histrogram stats in debug mode */ if (parms->debug) { plm_long zz; double tmp; for (zz=0,tmp=0; zz < mi_hist->fixed.bins; zz++) { tmp += f_hist[zz]; } printf ("f_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins; zz++) { tmp += m_hist[zz]; } printf ("m_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins * mi_hist->fixed.bins; zz++) { tmp += j_hist[zz]; } printf ("j_hist total: %f\n", tmp); } /* Compute score */ ssd->curr_smetric = mi_hist_score_omp (mi_hist, ssd->curr_num_vox); num_vox_f = (float) ssd->curr_num_vox; /* PASS 2 - Compute Gradient (Parallel across tiles) */ #pragma omp parallel for LOOP_THRU_VOL_TILES (pidx, bxf) { int rc; plm_long fijk[3], fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float dxyz[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float dc_dv[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); /* Get tile indices from linear index */ COORDS_FROM_INDEX (p, pidx, bxf->rdims); /* Serial through the voxels in a tile */ LOOP_THRU_TILE_Z (q, bxf) { LOOP_THRU_TILE_Y (q, bxf) { LOOP_THRU_TILE_X (q, bxf) { /* Construct coordinates into fixed image volume */ GET_VOL_COORDS (fijk, p, q, bxf); /* Check to make sure the indices are valid (inside volume) */ if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) { continue; } if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) { continue; } if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) { continue; } /* Compute space coordinates of fixed image voxel */ GET_REAL_SPACE_COORDS (fxyz, fijk, bxf); /* Compute deformation vector (dxyz) for voxel */ bspline_interp_pix_c (dxyz, bxf, pidx, q); /* Find correspondence in moving image */ rc = bspline_find_correspondence_dcos (mxyz, mijk, fxyz, dxyz, moving); /* If voxel is not inside moving image */ if (!rc) continue; /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Constrcut the fixed image linear index within volume space */ fidx = volume_index (fixed->dim, fijk); /* Find linear index the corner voxel used to identifiy the * neighborhood of the moving image voxels corresponding * to the current fixed image voxel */ midx_f = volume_index (moving->dim, mijk_f); /* Compute dc_dv */ bspline_mi_pvi_8_dc_dv ( dc_dv, mi_hist, bst, fixed, moving, fidx, midx_f, mijk, num_vox_f, li_1, li_2 ); /* Update condensed tile sets */ bspline_update_sets_b ( sets_x, sets_y, sets_z, q, dc_dv, bxf ); } /* LOOP_THRU_TILE_X */ } /* LOOP_THRU_TILE_Y */ } /* LOOP_THRU_TILE_Z */ /* We now have a tile of condensed dc_dv values (64 values). * Let's put each one in the proper slot within the control * point bin its belogs to */ bspline_sort_sets (cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, pidx, bxf); } /* LOOP_THRU_VOL_TILES */ /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. The result will be dc_dp. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); #if 0 if (parms->debug) { fclose (fp); } #endif mse_score = mse_score / ssd->curr_num_vox; if (parms->debug) { printf ("<< MSE %3.3f >>\n", mse_score); } } /* Mutual information version of implementation "C" */ void bspline_score_c_mi ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *fixed_roi = bst->fixed_roi; Volume *moving_roi = bst->moving_roi; Bspline_score* ssd = &bst->ssd; Joint_histogram* mi_hist = bst->get_mi_hist(); //plm_long rijk[3]; plm_long fijk[3], fidx; float mijk[3]; float fxyz[3]; float mxyz[3]; plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ plm_long p[3]; plm_long q[3]; float diff; float dc_dv[3]; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; float dxyz[3]; float num_vox_f; plm_long pidx, qidx; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float m_val; float mse_score = 0.0f; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; #if 0 FILE* fp = 0; char debug_fn[1024]; static int it = 0; if (parms->debug) { sprintf (debug_fn, "dump_mi_%02d.txt", it++); fp = fopen (debug_fn, "w"); } #endif memset (f_hist, 0, mi_hist->fixed.bins * sizeof(double)); memset (m_hist, 0, mi_hist->moving.bins * sizeof(double)); memset (j_hist, 0, mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(double)); /* PASS 1 - Accumulate histogram */ LOOP_Z (fijk, fxyz, fixed) { p[2] = REGION_INDEX_Z (fijk, bxf); q[2] = REGION_OFFSET_Z (fijk, bxf); LOOP_Y (fijk, fxyz, fixed) { p[1] = REGION_INDEX_Y (fijk, bxf); q[1] = REGION_OFFSET_Y (fijk, bxf); LOOP_X (fijk, fxyz, fixed) { p[0] = REGION_INDEX_X (fijk, bxf); q[0] = REGION_OFFSET_X (fijk, bxf); if (fixed_roi) { if (!inside_roi (fxyz, fixed_roi)) continue; } /* Get B-spline deformation vector */ pidx = volume_index (bxf->rdims, p); qidx = volume_index (bxf->vox_per_rgn, q); bspline_interp_pix_b (dxyz, bxf, pidx, qidx); /* Find correspondence in moving image */ int rc; rc = bspline_find_correspondence_dcos_roi ( mxyz, mijk, fxyz, dxyz, moving, moving_roi); /* If voxel is not inside moving image */ if (!rc) continue; li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Find linear index of fixed image voxel */ fidx = volume_index (fixed->dim, fijk); /* Find linear index of "corner voxel" in moving image */ midx_f = volume_index (moving->dim, mijk_f); /* Compute moving image intensity using linear interpolation */ /* Macro is slightly faster than function */ // NOTE: Not used by MI PVI8 LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], midx_f, m_img, moving ); #if defined (commentout) /* LINEAR INTERPOLATION */ bspline_mi_hist_add (mi_hist, f_img[fidx], m_val, 1.0); #endif /* PARTIAL VALUE INTERPOLATION - 8 neighborhood */ mi_hist->add_pvi_8 ( fixed, moving, fidx, midx_f, li_1, li_2); #if defined (commentout) /* PARTIAL VALUE INTERPOLATION - 6 neighborhood */ bspline_mi_hist_add_pvi_6 ( mi_hist, fixed, moving, fidx, midx_f, mijk ); #endif /* Compute intensity difference */ diff = m_val - f_img[fidx]; mse_score += diff * diff; ssd->curr_num_vox++; } /* LOOP_THRU_ROI_X */ } /* LOOP_THRU_ROI_Y */ } /* LOOP_THRU_ROI_Z */ /* Draw histogram images if user wants them */ if (parms->xpm_hist_dump) { dump_xpm_hist (mi_hist, parms->xpm_hist_dump, bst->it); } /* Display histrogram stats in debug mode */ if (parms->debug) { plm_long zz; double tmp; for (zz=0,tmp=0; zz < mi_hist->fixed.bins; zz++) { tmp += f_hist[zz]; } printf ("f_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins; zz++) { tmp += m_hist[zz]; } printf ("m_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins * mi_hist->fixed.bins; zz++) { tmp += j_hist[zz]; } printf ("j_hist total: %f\n", tmp); } /* Compute score */ ssd->curr_smetric = mi_hist->compute_score (ssd->curr_num_vox); num_vox_f = (float) ssd->curr_num_vox; /* PASS 2 - Compute gradient */ LOOP_Z (fijk, fxyz, fixed) { p[2] = REGION_INDEX_Z (fijk, bxf); q[2] = REGION_OFFSET_Z (fijk, bxf); LOOP_Y (fijk, fxyz, fixed) { p[1] = REGION_INDEX_Y (fijk, bxf); q[1] = REGION_OFFSET_Y (fijk, bxf); LOOP_X (fijk, fxyz, fixed) { p[0] = REGION_INDEX_X (fijk, bxf); q[0] = REGION_OFFSET_X (fijk, bxf); if (fixed_roi) { if (!inside_roi (fxyz, fixed_roi)) continue; } /* Get B-spline deformation vector */ pidx = volume_index (bxf->rdims, p); qidx = volume_index (bxf->vox_per_rgn, q); bspline_interp_pix_b (dxyz, bxf, pidx, qidx); /* Find linear index of fixed image voxel */ fidx = volume_index (fixed->dim, fijk); /* Find correspondence in moving image */ int rc; rc = bspline_find_correspondence_dcos_roi ( mxyz, mijk, fxyz, dxyz, moving, moving_roi); /* If voxel is not inside moving image */ if (!rc) continue; /* LINEAR INTERPOLATION - (not implemented) */ /* *** PARTIAL VALUE INTERPOLATION - 8 neighborhood *** */ /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Find linear index of fixed image voxel */ fidx = volume_index (fixed->dim, fijk); /* Find linear index of "corner voxel" in moving image */ midx_f = volume_index (moving->dim, mijk_f); /* Compute dc_dv */ bspline_mi_pvi_8_dc_dv_dcos ( dc_dv, mi_hist, bst, fixed, moving, fidx, midx_f, num_vox_f, li_1, li_2 ); #if defined (commentout) /* PARTIAL VALUE INTERPOLATION - 6 neighborhood */ bspline_mi_pvi_6_dc_dv ( dc_dv, mi_hist, bst, fixed, moving, fidx, midx_f, mijk, num_vox_f ); #endif bst->ssd.update_smetric_grad_b (bxf, pidx, qidx, dc_dv); } /* LOOP_THRU_ROI_X */ } /* LOOP_THRU_ROI_Y */ } /* LOOP_THRU_ROI_Z */ #if 0 if (parms->debug) { fclose (fp); } #endif mse_score = mse_score / ssd->curr_num_vox; } /* Mutual information version of implementation "k" */ void bspline_score_k_mi ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_score* ssd = &bst->ssd; Joint_histogram* mi_hist = bst->get_mi_hist(); double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; memset (f_hist, 0, mi_hist->fixed.bins * sizeof(double)); memset (m_hist, 0, mi_hist->moving.bins * sizeof(double)); memset (j_hist, 0, mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(double)); /* Create/initialize bspline_loop_user (PASS 1) */ Bspline_mi_k_pass_1 blu1 (bod); blu1.set_mi_hist (mi_hist); /* Run the loop */ bspline_loop_voxel_serial (blu1, bod); /* Draw histogram images if user wants them */ if (parms->xpm_hist_dump) { dump_xpm_hist (mi_hist, parms->xpm_hist_dump, bst->it); } /* Display histrogram stats in debug mode */ if (parms->debug) { plm_long zz; double tmp; for (zz=0,tmp=0; zz < mi_hist->fixed.bins; zz++) { tmp += f_hist[zz]; } printf ("f_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins; zz++) { tmp += m_hist[zz]; } printf ("m_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins * mi_hist->fixed.bins; zz++) { tmp += j_hist[zz]; } printf ("j_hist total: %f\n", tmp); } /* Compute score */ ssd->curr_smetric = mi_hist->compute_score (ssd->curr_num_vox); /* Create/initialize bspline_loop_user (PASS 2) */ Bspline_mi_k_pass_2 blu2 (bod); blu2.set_mi_hist (mi_hist); /* Run the loop */ bspline_loop_voxel_serial (blu2, bod); } /* Mutual information version of implementation "l" */ void bspline_score_l_mi ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_score* ssd = &bst->ssd; Joint_histogram* mi_hist = bst->get_mi_hist(); double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; memset (f_hist, 0, mi_hist->fixed.bins * sizeof(double)); memset (m_hist, 0, mi_hist->moving.bins * sizeof(double)); memset (j_hist, 0, mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(double)); /* Create/initialize bspline_loop_user (PASS 1) */ Bspline_mi_k_pass_1 blu1 (bod); blu1.set_mi_hist (mi_hist); /* Run the loop */ bspline_loop_voxel_serial (blu1, bod); /* Draw histogram images if user wants them */ if (parms->xpm_hist_dump) { dump_xpm_hist (mi_hist, parms->xpm_hist_dump, bst->it); } /* Display histrogram stats in debug mode */ if (parms->debug) { plm_long zz; double tmp; for (zz=0,tmp=0; zz < mi_hist->fixed.bins; zz++) { tmp += f_hist[zz]; } printf ("f_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins; zz++) { tmp += m_hist[zz]; } printf ("m_hist total: %f\n", tmp); for (zz=0,tmp=0; zz < mi_hist->moving.bins * mi_hist->fixed.bins; zz++) { tmp += j_hist[zz]; } printf ("j_hist total: %f\n", tmp); } /* Compute score */ ssd->curr_smetric = mi_hist->compute_score (ssd->curr_num_vox); /* Create/initialize bspline_loop_user (PASS 2) */ Bspline_mi_k_pass_2 blu2 (bod); blu2.set_mi_hist (mi_hist); /* Run the loop */ bspline_loop_voxel_serial (blu2, bod); } void bspline_score_mi ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Volume* fixed_roi = bst->fixed_roi; Volume* moving_roi = bst->moving_roi; bool have_roi = fixed_roi || moving_roi; bool have_histogram_minmax_val = (parms->mi_fixed_image_minVal!=0) || (parms->mi_fixed_image_maxVal!=0) || (parms->mi_moving_image_minVal!=0) || (parms->mi_moving_image_maxVal!=0); /* CPU Implementations */ if (parms->threading == BTHR_CPU) { /* Metric: Mutual Information with roi or intensity min/max values*/ if (have_roi || have_histogram_minmax_val) { switch (parms->implementation) { case 'c': bspline_score_c_mi (bod); break; #if (OPENMP_FOUND) case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': bspline_score_h_mi (bod); break; #endif case 'k': bspline_score_k_mi (bod); break; case 'l': bspline_score_l_mi (bod); break; default: #if (OPENMP_FOUND) bspline_score_h_mi (bod); #else bspline_score_c_mi (bod); #endif break; } } /* Metric: Mutual Information without roi */ else { switch (parms->implementation) { case 'c': bspline_score_c_mi (bod); break; #if (OPENMP_FOUND) case 'd': bspline_score_d_mi (bod); break; case 'e': bspline_score_e_mi (bod); break; case 'f': bspline_score_f_mi (bod); break; case 'g': bspline_score_g_mi (bod); break; case 'h': bspline_score_h_mi (bod); break; case 'i': bspline_score_i_mi (bod); break; #endif case 'k': bspline_score_k_mi (bod); break; case 'l': bspline_score_l_mi (bod); break; default: #if (OPENMP_FOUND) bspline_score_g_mi (bod); #else bspline_score_c_mi (bod); #endif break; } } /* end MI */ } /* end CPU Implementations */ /* CUDA Implementations */ #if (CUDA_FOUND) else if (parms->threading == BTHR_CUDA) { /* Be sure we loaded the CUDA plugin */ LOAD_LIBRARY_SAFE (libplmregistercuda); LOAD_SYMBOL (CUDA_bspline_mi_a, libplmregistercuda); switch (parms->implementation) { case 'a': CUDA_bspline_mi_a ( bod->get_bspline_parms(), bod->get_bspline_state(), bod->get_bspline_xform()); break; default: CUDA_bspline_mi_a ( bod->get_bspline_parms(), bod->get_bspline_state(), bod->get_bspline_xform()); break; } UNLOAD_LIBRARY (libplmregistercuda); } /* CUDA Implementations */ #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_mi.h000066400000000000000000000016351321604176500307420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_mi_h_ #define _bspline_mi_h_ #include "plmregister_config.h" class Bspline_optimize; PLMREGISTER_API void bspline_score_c_mi (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_d_mi (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_e_mi (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_f_mi (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_g_mi (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_h_mi (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_i_mi (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_k_mi (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_mi (Bspline_optimize *bod); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_mi.txx000077500000000000000000000175401321604176500313430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_mi_txx_ #define _bspline_mi_txx_ #include "compiler_warnings.h" static inline void bspline_mi_pvi_8_dc_dv_dcos ( float dc_dv[3], /* Output */ Joint_histogram* mi_hist, /* Input */ Bspline_state *bst, /* Input */ const Volume *fixed, /* Input */ const Volume *moving, /* Input */ int fidx, /* Input */ int mvf, /* Input */ float num_vox_f, /* Input */ float li_1[3], /* Input */ float li_2[3] /* Input */ ) { float dS_dP; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; Bspline_score* ssd = &bst->ssd; int idx_fbin, idx_mbin, idx_jbin, idx_pv; int offset_fbin; int n[8]; float dw[24]; dc_dv[0] = dc_dv[1] = dc_dv[2] = 0.0f; /* Calculate Point Indices for 8 neighborhood */ n[0] = mvf; n[1] = n[0] + 1; n[2] = n[0] + moving->dim[0]; n[3] = n[2] + 1; n[4] = n[0] + moving->dim[0]*moving->dim[1]; n[5] = n[4] + 1; n[6] = n[4] + moving->dim[0]; n[7] = n[6] + 1; /* Pre-compute differential PV slices */ dw[3*0+0] = ( -1 ) * li_1[1] * li_1[2]; // dw0 dw[3*0+1] = li_1[0] * ( -1 ) * li_1[2]; dw[3*0+2] = li_1[0] * li_1[1] * ( -1 ); dw[3*1+0] = ( +1 ) * li_1[1] * li_1[2]; // dw1 dw[3*1+1] = li_2[0] * ( -1 ) * li_1[2]; dw[3*1+2] = li_2[0] * li_1[1] * ( -1 ); dw[3*2+0] = ( -1 ) * li_2[1] * li_1[2]; // dw2 dw[3*2+1] = li_1[0] * ( +1 ) * li_1[2]; dw[3*2+2] = li_1[0] * li_2[1] * ( -1 ); dw[3*3+0] = ( +1 ) * li_2[1] * li_1[2]; // dw3 dw[3*3+1] = li_2[0] * ( +1 ) * li_1[2]; dw[3*3+2] = li_2[0] * li_2[1] * ( -1 ); dw[3*4+0] = ( -1 ) * li_1[1] * li_2[2]; // dw4 dw[3*4+1] = li_1[0] * ( -1 ) * li_2[2]; dw[3*4+2] = li_1[0] * li_1[1] * ( +1 ); dw[3*5+0] = ( +1 ) * li_1[1] * li_2[2]; // dw5 dw[3*5+1] = li_2[0] * ( -1 ) * li_2[2]; dw[3*5+2] = li_2[0] * li_1[1] * ( +1 ); dw[3*6+0] = ( -1 ) * li_2[1] * li_2[2]; // dw6 dw[3*6+1] = li_1[0] * ( +1 ) * li_2[2]; dw[3*6+2] = li_1[0] * li_2[1] * ( +1 ); dw[3*7+0] = ( +1 ) * li_2[1] * li_2[2]; // dw7 dw[3*7+1] = li_2[0] * ( +1 ) * li_2[2]; dw[3*7+2] = li_2[0] * li_2[1] * ( +1 ); /* Fixed image voxel's histogram index */ idx_fbin = floor ((f_img[fidx] - mi_hist->fixed.offset) / mi_hist->fixed.delta); if (mi_hist->fixed.type == HIST_VOPT) { idx_fbin = mi_hist->fixed.key_lut[idx_fbin]; } offset_fbin = idx_fbin * mi_hist->moving.bins; /* Partial Volume Contributions */ for (idx_pv=0; idx_pv<8; idx_pv++) { idx_mbin = floor ((m_img[n[idx_pv]] - mi_hist->moving.offset) / mi_hist->moving.delta); if (mi_hist->moving.type == HIST_VOPT) { idx_mbin = mi_hist->moving.key_lut[idx_mbin]; } idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > 0.0001) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric; dc_dv[0] -= dw[3*idx_pv+0] * dS_dP; dc_dv[1] -= dw[3*idx_pv+1] * dS_dP; dc_dv[2] -= dw[3*idx_pv+2] * dS_dP; } } dc_dv[0] = dc_dv[0] / num_vox_f; dc_dv[1] = dc_dv[1] / num_vox_f; dc_dv[2] = dc_dv[2] / num_vox_f; dc_dv[0] = PROJECT_X (dc_dv, moving->proj); dc_dv[1] = PROJECT_Y (dc_dv, moving->proj); dc_dv[2] = PROJECT_Z (dc_dv, moving->proj); #if defined (commentout) for (idx_pv=0; idx_pv<8; idx_pv++) { printf ("dw%i [ %2.5f %2.5f %2.5f ]\n", idx_pv, dw[3*idx_pv+0], dw[3*idx_pv+1], dw[3*idx_pv+2]); } printf ("S [ %2.5f %2.5f %2.5f ]\n\n\n", dc_dv[0], dc_dv[1], dc_dv[2]); exit(0); #endif } class Bspline_mi_k_pass_1 { public: double score_acc; Joint_histogram *mi_hist; public: Bspline_mi_k_pass_1 (Bspline_optimize *bod) { score_acc = 0.f; } void set_mi_hist (Joint_histogram *mi_hist) { this->mi_hist = mi_hist; } public: void loop_function ( Bspline_optimize *bod, /* In/out: generic optimization data */ Bspline_xform *bxf, /* Input: coefficient values */ Bspline_state *bst, /* Input: state of bspline */ Bspline_score *ssd, /* In/out: score and gradient */ const Volume *fixed, /* Input: fixed image */ const Volume *moving, /* Input: moving image */ const float *f_img, /* Input: raw intensity array for fixed */ const float *m_img, /* Input: raw intensity array for moving */ plm_long fidx, /* Input: index of voxel in fixed image */ plm_long midx_f, /* Input: index (floor) in moving image*/ plm_long mijk_r[3], /* Input: coords (rounded) in moving image*/ plm_long pidx, /* Input: region index of fixed voxel */ plm_long qidx, /* Input: offset index of fixed voxel */ float li_1[3], /* Input: linear interpolation fraction */ float li_2[3] /* Input: linear interpolation fraction */ ) { /* Compute moving image intensity using linear interpolation */ /* Macro is slightly faster than function */ float m_val; LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], midx_f, m_img, moving); UNUSED_VARIABLE (m_val); /* PARTIAL VALUE INTERPOLATION - 8 neighborhood */ mi_hist->add_pvi_8 ( fixed, moving, fidx, midx_f, li_1, li_2 ); /* Keep track of voxels used */ ssd->curr_num_vox++; } }; class Bspline_mi_k_pass_2 { public: float num_vox_f; Joint_histogram *mi_hist; public: Bspline_mi_k_pass_2 (Bspline_optimize *bod) { Bspline_score* ssd = bod->get_bspline_state()->get_bspline_score(); num_vox_f = (float) ssd->curr_num_vox; } void set_mi_hist (Joint_histogram *mi_hist) { this->mi_hist = mi_hist; } public: void loop_function ( Bspline_optimize *bod, /* In/out: generic optimization data */ Bspline_xform *bxf, /* Input: coefficient values */ Bspline_state *bst, /* Input: state of bspline */ Bspline_score *ssd, /* In/out: score and gradient */ const Volume *fixed, /* Input: fixed image */ const Volume *moving, /* Input: moving image */ const float *f_img, /* Input: raw intensity array for fixed */ const float *m_img, /* Input: raw intensity array for moving */ plm_long fidx, /* Input: index of voxel in fixed image */ plm_long midx_f, /* Input: index (floor) in moving image*/ plm_long mijk_r[3], /* Input: coords (rounded) in moving image*/ plm_long pidx, /* Input: region index of fixed voxel */ plm_long qidx, /* Input: offset index of fixed voxel */ float li_1[3], /* Input: linear interpolation fraction */ float li_2[3] /* Input: linear interpolation fraction */ ) { /* Compute dc_dv */ float dc_dv[3]; bspline_mi_pvi_8_dc_dv_dcos ( dc_dv, mi_hist, bst, fixed, moving, fidx, midx_f, num_vox_f, li_1, li_2 ); /* Update cost function gradient */ ssd->update_smetric_grad_b (bxf, pidx, qidx, dc_dv); } }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_mse.cxx000066400000000000000000001020131321604176500314640ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include #if (OPENMP_FOUND) #include #endif #if (SSE2_FOUND) #include #endif #include "bspline.h" #include "bspline_correspond.h" #include "bspline_cuda.h" #include "bspline_interpolate.h" #include "bspline_loop.txx" #include "bspline_macros.h" #include "bspline_mse.h" #include "bspline_mse.txx" #include "bspline_optimize.h" #include "bspline_parms.h" #include "bspline_state.h" #include "file_util.h" #include "interpolate.h" #include "interpolate_macros.h" #include "logfile.h" #include "mha_io.h" #include "plm_math.h" #include "plm_timer.h" #include "string_util.h" #include "volume.h" #include "volume_macros.h" void bspline_score_normalize ( Bspline_optimize *bod, double raw_score ) { Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Bspline_score *ssd = &bst->ssd; const int MIN_VOX = 1; /* GCS FIX: This is partly correct. It would be better if I could set the smetric to slightly more than the previous best score. By setting to FLT_MAX, it causes the optimizer to exit prematurely. However, the best score is not currently stored in the state. */ if (ssd->curr_num_vox < MIN_VOX) { ssd->curr_smetric = FLT_MAX; for (int i = 0; i < bxf->num_coeff; i++) { ssd->curr_smetric_grad[i] = 0; } } else { ssd->curr_smetric = raw_score / ssd->curr_num_vox; for (int i = 0; i < bxf->num_coeff; i++) { ssd->curr_smetric_grad[i] = 2 * ssd->curr_smetric_grad[i] / ssd->curr_num_vox; } } } /////////////////////////////////////////////////////////////////////////////// // FUNCTION: bspline_score_i_mse() // // This is a multi-CPU implementation using OpenMP, using the tile // "condense" method. It is similar to flavor "g", but respects // image rois. /////////////////////////////////////////////////////////////////////////////// void bspline_score_i_mse ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *moving_grad = bst->moving_grad; Bspline_score* ssd = &bst->ssd; double score_tile; float* f_img = (float*)fixed->img; float* m_img = (float*)moving->img; float* m_grad = (float*)moving_grad->img; int idx_tile; plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); Volume* fixed_roi = bst->fixed_roi; Volume* moving_roi = bst->moving_roi; static int it = 0; FILE* corr_fp = 0; if (parms->debug) { std::string fn = string_format ("%s/%02d_corr_mse_%03d_%03d.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); corr_fp = plm_fopen (fn.c_str(), "wb"); it ++; } // Zero out accumulators int num_vox = 0; score_tile = 0; memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); // Parallel across tiles #pragma omp parallel for reduction (+:num_vox,score_tile) LOOP_THRU_VOL_TILES (idx_tile, bxf) { int rc; plm_long ijk_tile[3]; plm_long ijk_local[3]; float fxyz[3]; plm_long fijk[3]; plm_long idx_fixed; float dxyz[3]; float xyz_moving[3]; float ijk_moving[3]; plm_long ijk_moving_floor[3]; plm_long ijk_moving_round[3]; plm_long idx_moving_floor; plm_long idx_moving_round; float li_1[3], li_2[3]; float m_val, diff; float dc_dv[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); // Get tile coordinates from index COORDS_FROM_INDEX (ijk_tile, idx_tile, bxf->rdims); // Serial through voxels in tile LOOP_THRU_TILE_Z (ijk_local, bxf) { LOOP_THRU_TILE_Y (ijk_local, bxf) { LOOP_THRU_TILE_X (ijk_local, bxf) { // Construct coordinates into fixed image volume GET_VOL_COORDS (fijk, ijk_tile, ijk_local, bxf); // Make sure we are inside the image volume if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) continue; if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) continue; if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) continue; // Compute physical coordinates of fixed image voxel POSITION_FROM_COORDS (fxyz, fijk, bxf->img_origin, fixed->step); /* JAS 2012.03.26: Tends to break the optimizer (PGTOL) */ /* Check to make sure the indices are valid (inside roi) */ if (fixed_roi) { if (!inside_roi (fxyz, fixed_roi)) continue; } // Construct the image volume index idx_fixed = volume_index (fixed->dim, fijk); // Calc. deformation vector (dxyz) for voxel bspline_interp_pix_c (dxyz, bxf, idx_tile, ijk_local); // Calc. moving image coordinate from the deformation // vector rc = bspline_find_correspondence_dcos_roi ( xyz_moving, ijk_moving, fxyz, dxyz, moving, moving_roi); if (parms->debug) { fprintf (corr_fp, "%d %d %d %f %f %f\n", (unsigned int) fijk[0], (unsigned int) fijk[1], (unsigned int) fijk[2], ijk_moving[0], ijk_moving[1], ijk_moving[2]); } /* If voxel is not inside moving image */ if (!rc) continue; // Compute linear interpolation fractions li_clamp_3d ( ijk_moving, ijk_moving_floor, ijk_moving_round, li_1, li_2, moving ); // Find linear indices for moving image idx_moving_floor = volume_index ( moving->dim, ijk_moving_floor); idx_moving_round = volume_index ( moving->dim, ijk_moving_round); // Calc. moving voxel intensity via linear interpolation LI_VALUE ( m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], idx_moving_floor, m_img, moving ); // Compute intensity difference diff = m_val - f_img[idx_fixed]; // Store the score! score_tile += diff * diff; num_vox++; // Compute dc_dv dc_dv[0] = diff * m_grad[3 * idx_moving_round + 0]; dc_dv[1] = diff * m_grad[3 * idx_moving_round + 1]; dc_dv[2] = diff * m_grad[3 * idx_moving_round + 2]; /* Generate condensed tile */ bspline_update_sets_b ( sets_x, sets_y, sets_z, ijk_local, dc_dv, bxf ); } /* LOOP_THRU_TILE_X */ } /* LOOP_THRU_TILE_Y */ } /* LOOP_THRU_TILE_Z */ // The tile is now condensed. Now we will put it in the // proper slot within the control point bin that it belong to. bspline_sort_sets ( cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, idx_tile, bxf ); } /* LOOP_THRU_VOL_TILES */ ssd->curr_num_vox = num_vox; /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. The result with be dc_dp. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); /* Normalize score for MSE */ bspline_score_normalize (bod, score_tile); if (parms->debug) { fclose (corr_fp); } } /////////////////////////////////////////////////////////////////////////////// // FUNCTION: bspline_score_h_mse() // // This is a single core CPU implementation of CUDA implementation J. // The tile "condense" method is demonstrated. // // ** This is the fastest know CPU implmentation for single core ** // // See also: // OpenMP implementation of CUDA J: bspline_score_g_mse() // // AUTHOR: James A. Shackleford // DATE: 11.22.2009 /////////////////////////////////////////////////////////////////////////////// void bspline_score_h_mse ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *moving_grad = bst->moving_grad; Bspline_score* ssd = &bst->ssd; double score_tile; float* f_img = (float*)fixed->img; float* m_img = (float*)moving->img; float* m_grad = (float*)moving_grad->img; plm_long idx_tile; plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); static int it = 0; // Zero out accumulators score_tile = 0; memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); FILE* corr_fp = 0; if (parms->debug) { std::string fn = string_format ("%s/%02d_corr_mse_%03d_%03d.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); corr_fp = plm_fopen (fn.c_str(), "wb"); it ++; } // Serial across tiles LOOP_THRU_VOL_TILES (idx_tile, bxf) { int rc; int ijk_tile[3]; plm_long ijk_local[3]; float fxyz[3]; plm_long fijk[3]; plm_long idx_fixed; float dxyz[3]; float xyz_moving[3]; float ijk_moving[3]; plm_long ijk_moving_floor[3]; plm_long ijk_moving_round[3]; plm_long idx_moving_floor; plm_long idx_moving_round; float li_1[3], li_2[3]; float m_val, diff; float dc_dv[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); // Get tile coordinates from index COORDS_FROM_INDEX (ijk_tile, idx_tile, bxf->rdims); // Serial through voxels in tile LOOP_THRU_TILE_Z (ijk_local, bxf) { LOOP_THRU_TILE_Y (ijk_local, bxf) { LOOP_THRU_TILE_X (ijk_local, bxf) { // Construct coordinates into fixed image volume GET_VOL_COORDS (fijk, ijk_tile, ijk_local, bxf); // Make sure we are inside the region of interest if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) continue; if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) continue; if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) continue; // Compute physical coordinates of fixed image voxel POSITION_FROM_COORDS (fxyz, fijk, bxf->img_origin, fixed->step); // Construct the image volume index idx_fixed = volume_index (fixed->dim, fijk); // Calc. deformation vector (dxyz) for voxel bspline_interp_pix_c (dxyz, bxf, idx_tile, ijk_local); // Calc. moving image coordinate from the deformation vector /* To remove DCOS support, change function call to bspline_find_correspondence() */ rc = bspline_find_correspondence_dcos ( xyz_moving, ijk_moving, fxyz, dxyz, moving); // Return code is 0 if voxel is pushed outside of moving image if (!rc) continue; if (parms->debug) { fprintf (corr_fp, "%d %d %d %f %f %f\n", (unsigned int) fijk[0], (unsigned int) fijk[1], (unsigned int) fijk[2], ijk_moving[0], ijk_moving[1], ijk_moving[2]); } // Compute linear interpolation fractions li_clamp_3d ( ijk_moving, ijk_moving_floor, ijk_moving_round, li_1, li_2, moving ); // Find linear indices for moving image idx_moving_floor = volume_index (moving->dim, ijk_moving_floor); idx_moving_round = volume_index (moving->dim, ijk_moving_round); // Calc. moving voxel intensity via linear interpolation LI_VALUE ( m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], idx_moving_floor, m_img, moving ); // Compute intensity difference diff = m_val - f_img[idx_fixed]; // Store the score! score_tile += diff * diff; ssd->curr_num_vox++; // Compute dc_dv dc_dv[0] = diff * m_grad[3 * idx_moving_round + 0]; dc_dv[1] = diff * m_grad[3 * idx_moving_round + 1]; dc_dv[2] = diff * m_grad[3 * idx_moving_round + 2]; /* Generate condensed tile */ bspline_update_sets_b (sets_x, sets_y, sets_z, ijk_local, dc_dv, bxf); } /* LOOP_THRU_TILE_X */ } /* LOOP_THRU_TILE_Y */ } /* LOOP_THRU_TILE_Z */ // The tile is now condensed. Now we will put it in the // proper slot within the control point bin that it belong to. bspline_sort_sets ( cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, idx_tile, bxf ); } /* LOOP_THRU_VOL_TILES */ /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. A single bin summation is * dc_dp for the single control point associated with the bin. * The number of total bins is equal to the number of control * points in the control grid. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); /* Normalize score for MSE */ bspline_score_normalize (bod, score_tile); if (parms->debug) { fclose (corr_fp); } } /////////////////////////////////////////////////////////////////////////////// // FUNCTION: bspline_score_g_mse() // // This is a multi-CPU implementation of CUDA implementation J. OpenMP is // used. The tile "condense" method is demonstrated. // // ** This is the fastest know CPU implmentation for multi core ** // (That does not require SSE) // // AUTHOR: James A. Shackleford // DATE: 11.22.2009 // // 2012-06-10 (GCS): Updated to DCOS, only 0.15% increase in runtime, // judged not worth maintaining separate code. /////////////////////////////////////////////////////////////////////////////// void bspline_score_g_mse ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *moving_grad = bst->moving_grad; Bspline_score* ssd = &bst->ssd; double score_tile; float* f_img = (float*)fixed->img; float* m_img = (float*)moving->img; float* m_grad = (float*)moving_grad->img; int idx_tile; plm_long cond_size = 64*bxf->num_knots*sizeof(float); float* cond_x = (float*)malloc(cond_size); float* cond_y = (float*)malloc(cond_size); float* cond_z = (float*)malloc(cond_size); static int it = 0; FILE* corr_fp = 0; if (parms->debug) { std::string fn = string_format ("%s/%02d_corr_mse_%03d_%03d.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); corr_fp = plm_fopen (fn.c_str(), "wb"); it ++; } // Zero out accumulators int num_vox = 0; score_tile = 0; memset(cond_x, 0, cond_size); memset(cond_y, 0, cond_size); memset(cond_z, 0, cond_size); // Parallel across tiles #pragma omp parallel for reduction (+:num_vox,score_tile) LOOP_THRU_VOL_TILES (idx_tile, bxf) { int rc; plm_long ijk_tile[3]; plm_long ijk_local[3]; float fxyz[3]; plm_long fijk[3]; plm_long idx_fixed; float dxyz[3]; float xyz_moving[3]; float ijk_moving[3]; plm_long ijk_moving_floor[3]; plm_long ijk_moving_round[3]; plm_long idx_moving_floor; plm_long idx_moving_round; float li_1[3], li_2[3]; float m_val, diff; float dc_dv[3]; float sets_x[64]; float sets_y[64]; float sets_z[64]; memset(sets_x, 0, 64*sizeof(float)); memset(sets_y, 0, 64*sizeof(float)); memset(sets_z, 0, 64*sizeof(float)); // Get tile coordinates from index COORDS_FROM_INDEX (ijk_tile, idx_tile, bxf->rdims); // Serial through voxels in tile LOOP_THRU_TILE_Z (ijk_local, bxf) { LOOP_THRU_TILE_Y (ijk_local, bxf) { LOOP_THRU_TILE_X (ijk_local, bxf) { // Construct coordinates into fixed image volume GET_VOL_COORDS (fijk, ijk_tile, ijk_local, bxf); // Make sure we are inside the image volume if (fijk[0] >= bxf->roi_offset[0] + bxf->roi_dim[0]) continue; if (fijk[1] >= bxf->roi_offset[1] + bxf->roi_dim[1]) continue; if (fijk[2] >= bxf->roi_offset[2] + bxf->roi_dim[2]) continue; // Compute physical coordinates of fixed image voxel POSITION_FROM_COORDS (fxyz, fijk, bxf->img_origin, fixed->step); // Construct the image volume index idx_fixed = volume_index (fixed->dim, fijk); // Calc. deformation vector (dxyz) for voxel bspline_interp_pix_c (dxyz, bxf, idx_tile, ijk_local); // Calc. moving image coordinate from the deformation // vector /* To remove DCOS support, change function call to bspline_find_correspondence() */ rc = bspline_find_correspondence_dcos ( xyz_moving, ijk_moving, fxyz, dxyz, moving); if (parms->debug) { fprintf (corr_fp, "%d %d %d %f %f %f\n", (unsigned int) fijk[0], (unsigned int) fijk[1], (unsigned int) fijk[2], ijk_moving[0], ijk_moving[1], ijk_moving[2]); } // Return code is 0 if voxel is pushed outside of // moving image if (!rc) continue; // Compute linear interpolation fractions li_clamp_3d ( ijk_moving, ijk_moving_floor, ijk_moving_round, li_1, li_2, moving ); // Find linear indices for moving image idx_moving_floor = volume_index ( moving->dim, ijk_moving_floor); idx_moving_round = volume_index ( moving->dim, ijk_moving_round); // Calc. moving voxel intensity via linear interpolation LI_VALUE ( m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], idx_moving_floor, m_img, moving ); // Compute intensity difference diff = m_val - f_img[idx_fixed]; // Store the score! score_tile += diff * diff; num_vox++; // Compute dc_dv dc_dv[0] = diff * m_grad[3 * idx_moving_round + 0]; dc_dv[1] = diff * m_grad[3 * idx_moving_round + 1]; dc_dv[2] = diff * m_grad[3 * idx_moving_round + 2]; /* Generate condensed tile */ bspline_update_sets_b ( sets_x, sets_y, sets_z, ijk_local, dc_dv, bxf ); } /* LOOP_THRU_TILE_X */ } /* LOOP_THRU_TILE_Y */ } /* LOOP_THRU_TILE_Z */ // The tile is now condensed. Now we will put it in the // proper slot within the control point bin that it belong to. bspline_sort_sets ( cond_x, cond_y, cond_z, sets_x, sets_y, sets_z, idx_tile, bxf ); } /* LOOP_THRU_VOL_TILES */ ssd->curr_num_vox = num_vox; /* Now we have a ton of bins and each bin's 64 slots are full. * Let's sum each bin's 64 slots. The result with be dc_dp. */ bspline_condense_smetric_grad (cond_x, cond_y, cond_z, bxf, ssd); free (cond_x); free (cond_y); free (cond_z); /* Normalize score for MSE */ bspline_score_normalize (bod, score_tile); if (parms->debug) { fclose (corr_fp); } } /* ----------------------------------------------------------------------- FUNCTION: bspline_score_c_mse() This is the older "fast" single-threaded MSE implementation, modified to respect direction cosines (and ROI support removed). ----------------------------------------------------------------------- */ void bspline_score_c_mse ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *moving_grad = bst->moving_grad; Bspline_score* ssd = &bst->ssd; plm_long fijk[3], fv; /* Indices within fixed image (vox) */ float mijk[3]; /* Indices within moving image (vox) */ float fxyz[3]; /* Position within fixed image (mm) */ float mxyz[3]; /* Position within moving image (mm) */ plm_long mijk_f[3], mvf; /* Floor */ plm_long mijk_r[3], mvr; /* Round */ plm_long p[3], pidx; /* Region index of fixed voxel */ plm_long q[3], qidx; /* Offset index of fixed voxel */ float dc_dv[3]; float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; float* m_grad = (float*) moving_grad->img; float dxyz[3]; float m_val; /* GCS: Oct 5, 2009. We have determined that sequential accumulation of the score requires double precision. However, reduction accumulation does not. */ double score_acc = 0.; static int it = 0; FILE* val_fp = 0; FILE* dc_dv_fp = 0; FILE* corr_fp = 0; if (parms->debug) { std::string fn; fn = string_format ("%s/%02d_dc_dv_mse_%03d_%03d.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); dc_dv_fp = plm_fopen (fn.c_str(), "wb"); fn = string_format ("%s/%02d_val_mse_%03d_%03d.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); val_fp = plm_fopen (fn.c_str(), "wb"); fn = string_format ("%s/%02d_corr_mse_%03d_%03d.csv", parms->debug_dir.c_str(), parms->debug_stage, bst->it, bst->feval); corr_fp = plm_fopen (fn.c_str(), "wb"); it ++; } /* GCS FIX: region of interest is not used */ LOOP_Z (fijk, fxyz, fixed) { p[2] = REGION_INDEX_Z (fijk, bxf); q[2] = REGION_OFFSET_Z (fijk, bxf); LOOP_Y (fijk, fxyz, fixed) { p[1] = REGION_INDEX_Y (fijk, bxf); q[1] = REGION_OFFSET_Y (fijk, bxf); LOOP_X (fijk, fxyz, fixed) { p[0] = REGION_INDEX_X (fijk, bxf); q[0] = REGION_OFFSET_X (fijk, bxf); /* Get B-spline deformation vector */ pidx = volume_index (bxf->rdims, p); qidx = volume_index (bxf->vox_per_rgn, q); bspline_interp_pix_b (dxyz, bxf, pidx, qidx); /* Compute moving image coordinate of fixed image voxel */ mxyz[2] = fxyz[2] + dxyz[2] - moving->origin[2]; mxyz[1] = fxyz[1] + dxyz[1] - moving->origin[1]; mxyz[0] = fxyz[0] + dxyz[0] - moving->origin[0]; mijk[2] = PROJECT_Z (mxyz, moving->proj); mijk[1] = PROJECT_Y (mxyz, moving->proj); mijk[0] = PROJECT_X (mxyz, moving->proj); if (parms->debug) { fprintf (corr_fp, "%d %d %d, %f %f %f -> %f %f %f, %f %f %f\n", (unsigned int) fijk[0], (unsigned int) fijk[1], (unsigned int) fijk[2], fxyz[0], fxyz[1], fxyz[2], mijk[0], mijk[1], mijk[2], fxyz[0] + dxyz[0], fxyz[1] + dxyz[1], fxyz[2] + dxyz[2] ); } if (!moving->is_inside (mijk)) continue; /* Compute interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Find linear index of "corner voxel" in moving image */ mvf = volume_index (moving->dim, mijk_f); /* Compute moving image intensity using linear interpolation */ /* Macro is slightly faster than function */ LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], mvf, m_img, moving); /* Compute linear index of fixed image voxel */ fv = volume_index (fixed->dim, fijk); /* Compute intensity difference */ float diff = m_val - f_img[fv]; /* Compute spatial gradient using nearest neighbors */ mvr = volume_index (moving->dim, mijk_r); dc_dv[0] = diff * m_grad[3*mvr+0]; /* x component */ dc_dv[1] = diff * m_grad[3*mvr+1]; /* y component */ dc_dv[2] = diff * m_grad[3*mvr+2]; /* z component */ bst->ssd.update_smetric_grad_b (bxf, pidx, qidx, dc_dv); if (parms->debug) { fprintf (val_fp, "%u %u %u %g %g %g\n", (unsigned int) fijk[0], (unsigned int) fijk[1], (unsigned int) fijk[2], f_img[fv], m_val, diff); fprintf (dc_dv_fp, "%u %u %u %g %g %g %g\n", (unsigned int) fijk[0], (unsigned int) fijk[1], (unsigned int) fijk[2], diff, dc_dv[0], dc_dv[1], dc_dv[2]); } score_acc += diff * diff; ssd->curr_num_vox++; } /* LOOP_THRU_ROI_X */ } /* LOOP_THRU_ROI_Y */ } /* LOOP_THRU_ROI_Z */ if (parms->debug) { fclose (val_fp); fclose (dc_dv_fp); fclose (corr_fp); } /* Normalize score for MSE */ bspline_score_normalize (bod, score_acc); } /* ----------------------------------------------------------------------- FUNCTION: bspline_score_k_mse(), bspline_score_l_mse() This is the same as 'c', except using templates. This is the older "fast" single-threaded MSE implementation, modified to respect direction cosines (and ROI support removed). ----------------------------------------------------------------------- */ void bspline_score_k_mse ( Bspline_optimize *bod ) { /* Create/initialize bspline_loop_user */ Bspline_mse_k blu (bod); /* Run the loop */ bspline_loop_voxel_serial (blu, bod); /* Normalize score for MSE */ bspline_score_normalize (bod, blu.score_acc); } void bspline_score_l_mse ( Bspline_optimize *bod ) { /* Create/initialize bspline_loop_user */ Bspline_mse_l blu (bod); /* Run the loop */ bspline_loop_tile_serial (blu, bod); /* Normalize score for MSE */ bspline_score_normalize (bod, blu.score_acc); } void bspline_score_m_mse ( Bspline_optimize *bod ) { } void bspline_score_n_mse ( Bspline_optimize *bod ) { } void bspline_score_mse ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Volume* fixed_roi = bst->fixed_roi; Volume* moving_roi = bst->moving_roi; bool have_roi = fixed_roi || moving_roi; /* CPU Implementations */ if (parms->threading == BTHR_CPU) { if (have_roi) { switch (parms->implementation) { case 'c': case 'k': bspline_score_k_mse (bod); break; default: bspline_score_i_mse (bod); break; } } else { switch (parms->implementation) { case 'c': bspline_score_c_mse (bod); break; case 'g': bspline_score_g_mse (bod); break; case 'h': bspline_score_h_mse (bod); break; case 'i': bspline_score_i_mse (bod); break; case 'k': bspline_score_k_mse (bod); break; case 'l': bspline_score_l_mse (bod); break; case 'm': bspline_score_m_mse (bod); break; case 'n': bspline_score_n_mse (bod); break; default: #if (OPENMP_FOUND) bspline_score_g_mse (bod); #else bspline_score_h_mse (bod); #endif break; } } } #if (CUDA_FOUND) /* CUDA Implementations */ else if (parms->threading == BTHR_CUDA) { /* Be sure we loaded the CUDA plugin */ LOAD_LIBRARY_SAFE (libplmregistercuda); LOAD_SYMBOL (CUDA_bspline_mse_j, libplmregistercuda); switch (parms->implementation) { case 'j': CUDA_bspline_mse_j ( bod->get_bspline_parms(), bod->get_bspline_state(), bod->get_bspline_xform()); break; default: CUDA_bspline_mse_j ( bod->get_bspline_parms(), bod->get_bspline_state(), bod->get_bspline_xform()); break; } /* Unload plugin when done */ UNLOAD_LIBRARY (libplmregistercuda); } #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_mse.h000066400000000000000000000020131321604176500311100ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_mse_h_ #define _bspline_mse_h_ #include "plmregister_config.h" class Bspline_optimize; PLMREGISTER_API void bspline_score_c_mse (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_g_mse (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_h_mse (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_i_mse (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_k_mse (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_l_mse (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_m_mse (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_n_mse (Bspline_optimize *bod); PLMREGISTER_API void bspline_score_normalize ( Bspline_optimize *bod, double raw_score ); PLMREGISTER_API void bspline_score_mse (Bspline_optimize *bod); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_mse.txx000077500000000000000000000135721321604176500315230ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_mse_txx_ #define _bspline_mse_txx_ class Bspline_mse_k { public: float *m_grad; /* GCS: Oct 5, 2009. We have determined that sequential accumulation of the score requires double precision. However, reduction accumulation does not. */ double score_acc; public: Bspline_mse_k (Bspline_optimize *bod) { Bspline_state *bst = bod->get_bspline_state (); Volume *moving_grad = bst->moving_grad; m_grad = (float*) moving_grad->img; score_acc = 0.; } public: void loop_function ( Bspline_optimize *bod, /* In/out: generic optimization data */ Bspline_xform *bxf, /* Input: coefficient values */ Bspline_state *bst, /* Input: state of bspline */ Bspline_score *ssd, /* In/out: score and gradient */ const Volume *fixed, /* Input: fixed image */ const Volume *moving, /* Input: moving image */ const float *f_img, /* Input: raw intensity array for fixed */ const float *m_img, /* Input: raw intensity array for moving */ plm_long fidx, /* Input: index of voxel in fixed image */ plm_long midx_f, /* Input: index (floor) in moving image*/ plm_long mijk_r[3], /* Input: coords (rounded) in moving image*/ plm_long pidx, /* Input: region index of fixed voxel */ plm_long qidx, /* Input: offset index of fixed voxel */ float li_1[3], /* Input: linear interpolation fraction */ float li_2[3] /* Input: linear interpolation fraction */ ) { float m_val; float dc_dv[3]; /* Get value in fixed image */ float f_val = f_img[fidx]; /* Compute moving image intensity using linear interpolation */ /* Macro is slightly faster than function */ LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], midx_f, m_img, moving); /* This replaces the commented out code */ plm_long mvr = volume_index (moving->dim, mijk_r); /* Compute intensity difference */ float diff = m_val - f_val; /* Update score */ this->score_acc += diff * diff; /* Update voxel count */ ssd->curr_num_vox++; /* Compute spatial gradient using nearest neighbors */ dc_dv[0] = diff * m_grad[3*mvr+0]; /* x component */ dc_dv[1] = diff * m_grad[3*mvr+1]; /* y component */ dc_dv[2] = diff * m_grad[3*mvr+2]; /* z component */ /* Update cost function gradient */ ssd->update_smetric_grad_b (bxf, pidx, qidx, dc_dv); } }; class Bspline_mse_l { public: float *m_grad; /* GCS: Oct 5, 2009. We have determined that sequential accumulation of the score requires double precision. However, reduction accumulation does not. */ double score_acc; public: class Thread_data { public: double tile_score; public: Thread_data () { tile_score = 0.; } }; public: Bspline_mse_l (Bspline_optimize *bod) { Bspline_state *bst = bod->get_bspline_state (); Volume *moving_grad = bst->moving_grad; m_grad = (float*) moving_grad->img; score_acc = 0.; } public: void loop_function ( Bspline_optimize *bod, /* In/out: generic optimization data */ Bspline_xform *bxf, /* Input: coefficient values */ Bspline_state *bst, /* Input: state of bspline */ Bspline_score *ssd, /* In/out: score and gradient */ const Volume *fixed, /* Input: fixed image */ const Volume *moving, /* Input: moving image */ const float *f_img, /* Input: raw intensity array for fixed */ const float *m_img, /* Input: raw intensity array for moving */ plm_long fidx, /* Input: index of voxel in fixed image */ plm_long midx_f, /* Input: index (floor) in moving image*/ plm_long mijk_r[3], /* Input: coords (rounded) in moving image*/ float li_1[3], /* Input: linear interpolation fraction */ float li_2[3], /* Input: linear interpolation fraction */ plm_long q[3], /* Input: coords of voxel within tile */ float *sets_x, /* Input: gradient accumulation set */ float *sets_y, /* Input: gradient accumulation set */ float *sets_z /* Input: gradient accumulation set */ ) { float m_val; float dc_dv[3]; /* Get value in fixed image */ float f_val = f_img[fidx]; /* Compute moving image intensity using linear interpolation */ /* Macro is slightly faster than function */ LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], midx_f, m_img, moving); /* This replaces the commented out code */ plm_long mvr = volume_index (moving->dim, mijk_r); /* Compute intensity difference */ float diff = m_val - f_val; /* Update score */ this->score_acc += diff * diff; /* Update voxel count */ ssd->curr_num_vox++; /* Compute spatial gradient using nearest neighbors */ dc_dv[0] = diff * m_grad[3*mvr+0]; /* x component */ dc_dv[1] = diff * m_grad[3*mvr+1]; /* y component */ dc_dv[2] = diff * m_grad[3*mvr+2]; /* z component */ /* Generate condensed tile */ bspline_update_sets_b (sets_x, sets_y, sets_z, q, dc_dv, bxf); } }; #endif bspline_optimize.cxx000066400000000000000000000071201321604176500324640ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include "bspline.h" #include "bspline_mi.h" #include "bspline_optimize.h" #include "bspline_optimize_lbfgsb.h" #include "bspline_optimize_liblbfgs.h" #include "bspline_optimize_nlopt.h" #include "bspline_optimize_steepest.h" #include "bspline_parms.h" #include "bspline_state.h" #include "bspline_xform.h" #include "logfile.h" #include "plm_math.h" class Bspline_optimize_private { public: Bspline_state::Pointer bst; Bspline_xform *bxf; Bspline_parms *parms; }; Bspline_optimize::Bspline_optimize () { d_ptr = new Bspline_optimize_private; d_ptr->bst = Bspline_state::New (); } Bspline_optimize::~Bspline_optimize () { delete d_ptr; } static void bspline_optimize_select ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); switch (parms->optimization) { case BOPT_LBFGSB: bspline_optimize_lbfgsb (bod); break; case BOPT_STEEPEST: bspline_optimize_steepest (bod); break; case BOPT_LIBLBFGS: bspline_optimize_liblbfgs (bod); break; #if (NLOPT_FOUND) case BOPT_NLOPT_LBFGS: bspline_optimize_nlopt (bod, NLOPT_LD_LBFGS); break; case BOPT_NLOPT_LD_MMA: bspline_optimize_nlopt (bod, NLOPT_LD_MMA); break; case BOPT_NLOPT_PTN_1: //bspline_optimize_nlopt (&bod, NLOPT_LD_TNEWTON_PRECOND_RESTART); bspline_optimize_nlopt (bod, NLOPT_LD_VAR2); break; #else case BOPT_NLOPT_LBFGS: case BOPT_NLOPT_LD_MMA: case BOPT_NLOPT_PTN_1: logfile_printf ( "Plastimatch was not compiled against NLopt.\n" "Reverting to liblbfgs.\n" ); bspline_optimize_liblbfgs (bod); #endif default: bspline_optimize_liblbfgs (bod); break; } } void Bspline_optimize::optimize ( ) { Bspline_parms *parms = this->get_bspline_parms (); Bspline_state *bst = this->get_bspline_state (); Bspline_xform *bxf = this->get_bspline_xform (); d_ptr->bst->initialize (bxf, parms); /* GCS FIX: The below does not belong in bspline_state. And it should be done if any similarity metric is MI. */ /* JAS Fix 2011.09.14 * The MI algorithm will get stuck for a set of coefficients all equaling * zero due to the method we use to compute the cost function gradient. * However, it is possible we could be inheriting coefficients from a * prior stage, so we must check for inherited coefficients before * applying an initial offset to the coefficient array. */ if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) { bxf->jitter_if_zero (); } parms->log (); bxf->log_header (); bst->log_metric (); /* Initialize histograms */ bst->initialize_mi_histograms (); /* Do the optimization */ bspline_optimize_select (this); } Bspline_parms* Bspline_optimize::get_bspline_parms () { return d_ptr->parms; } Bspline_state* Bspline_optimize::get_bspline_state () { return d_ptr->bst.get(); } Bspline_xform* Bspline_optimize::get_bspline_xform () { return d_ptr->bxf; } void Bspline_optimize::set_bspline_parms (Bspline_parms *parms) { d_ptr->parms = parms; } void Bspline_optimize::set_bspline_xform (Bspline_xform *bxf) { d_ptr->bxf = bxf; } bspline_optimize.h000066400000000000000000000017471321604176500321220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_optimize_h_ #define _bspline_optimize_h_ #include "plmregister_config.h" #include "bspline_state.h" #include "smart_pointer.h" class Bspline_optimize_private; class Bspline_parms; class Bspline_xform; class PLMREGISTER_API Bspline_optimize { public: SMART_POINTER_SUPPORT (Bspline_optimize); Bspline_optimize_private *d_ptr; public: Bspline_optimize (); ~Bspline_optimize (); public: Bspline_parms* get_bspline_parms (); Bspline_state* get_bspline_state (); Bspline_xform* get_bspline_xform (); void set_bspline_parms (Bspline_parms *parms); void set_bspline_xform (Bspline_xform *bxf); void optimize (); }; PLMREGISTER_C_API void bspline_optimize ( Bspline_xform *bxf, Bspline_parms *parms); #endif bspline_optimize_lbfgsb.cxx000066400000000000000000000212501321604176500340030ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include #include "bspline.h" #include "bspline_optimize.h" #include "bspline_optimize_lbfgsb.h" #include "bspline_parms.h" #include "bspline_state.h" #include "bspline_xform.h" #include "logfile.h" #include "plm_math.h" #include "print_and_exit.h" #include "v3p_netlib.h" #include "v3p_f2c_mangle.h" class Nocedal_optimizer { public: char task[60], csave[60]; logical lsave[4]; integer n, m, iprint, *nbd, *iwa, isave[44]; doublereal f, factr, pgtol, *x, *l, *u, *g, *wa, dsave[29]; public: Nocedal_optimizer (Bspline_optimize *bod); ~Nocedal_optimizer () { free (nbd); free (iwa); free (x); free (l); free (u); free (g); free (wa); } void setulb () { v3p_netlib_setulb_(&n,&m,x,l,u,nbd,&f,g,&factr,&pgtol,wa,iwa, task,&iprint,csave,lsave,isave,dsave); } }; Nocedal_optimizer::Nocedal_optimizer (Bspline_optimize *bod) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_xform *bxf = bod->get_bspline_xform (); int nmax = bxf->num_coeff; int mmax = parms->lbfgsb_mmax; /* Automatic memory sizing for hessian approximation based on heuristic */ if (parms->lbfgsb_mmax < 1) { mmax = 2 + (int) floor (sqrt ((float) (bxf->num_coeff))); if (mmax > std::numeric_limits::max() / nmax / 10) { mmax = std::numeric_limits::max() / nmax / 10; } if (mmax > 500) { mmax = 500; } } /* Matrix is never bigger than square */ if (mmax > nmax) { mmax = nmax; } /* Check that we have enough memory for the requested mmax */ do { nbd = (integer*) malloc (sizeof(integer)*nmax); iwa = (integer*) malloc (sizeof(integer)*3*nmax); x = (doublereal*) malloc (sizeof(doublereal)*nmax); l = (doublereal*) malloc (sizeof(doublereal)*nmax); u = (doublereal*) malloc (sizeof(doublereal)*nmax); g = (doublereal*) malloc (sizeof(doublereal)*nmax); /* GCS 2014-11-13. Depending on the version of ITK, you get different versions of the Nocedal code. The different versions have different requirements on the size of wa[]. Instead of detecting the version, we simply ask for enough memory to handle either case. */ size_t wa_size_2006 = 2 * mmax*nmax + 4 * nmax + 12 * mmax*mmax + 12 * mmax; size_t wa_size_2010 = 2 * mmax*nmax + 5 * nmax + 11 * mmax*mmax + 8 * mmax; size_t wa_size = wa_size_2006; if (wa_size < wa_size_2010) { wa_size = wa_size_2010; } wa = (doublereal*)malloc(sizeof(doublereal) * wa_size); if ((nbd == NULL) || (iwa == NULL) || ( x == NULL) || ( l == NULL) || ( u == NULL) || ( g == NULL) || ( wa == NULL)) { /* We didn't get enough memory. Free what we got. */ free (nbd); free (iwa); free (x); free (l); free (u); free (g); free (wa); /* Give a little feedback to the user */ logfile_printf ( "Tried nmax, mmax = %d %d, but ran out of memory!\n", nmax, mmax); /* Try again with reduced request */ if (mmax > 20) { mmax = mmax / 2; } else if (mmax > 10) { mmax = 10; } else if (mmax > 2) { mmax --; } else { print_and_exit ("System ran out of memory when " "initializing Nocedal optimizer.\n"); } } else { /* Everything went great. We got the memory. */ break; } } while (1); m = mmax; n = nmax; /* Give a little feedback to the user */ logfile_printf ("Setting nmax, mmax = %d %d\n", nmax, mmax); /* If iprint is 1, the file iterate.dat will be created */ iprint = 0; factr = parms->lbfgsb_factr; pgtol = parms->lbfgsb_pgtol; /* Bounds for deformation problem */ for (int i = 0; i < n; i++) { nbd[i] = 0; l[i]=-1.0e1; u[i]=+1.0e1; } /* Initial guess */ for (int i = 0; i < n; i++) { x[i] = bxf->coeff[i]; } /* Remember: Fortran expects strings to be padded with blanks */ memset (task, ' ', sizeof(task)); memcpy (task, "START", 5); logfile_printf (">>> %c%c%c%c%c%c%c%c%c%c\n", task[0], task[1], task[2], task[3], task[4], task[5], task[6], task[7], task[8], task[9]); } void bspline_optimize_lbfgsb ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Bspline_score* ssd = &bst->ssd; FILE *fp = 0; double old_best_score = DBL_MAX; double best_score = DBL_MAX; float *best_coeff = (float*) malloc (sizeof(float) * bxf->num_coeff); float *lss_coeff = (float*) malloc (sizeof(float) * bxf->num_coeff); Nocedal_optimizer optimizer (bod); /* Initialize # iterations, # function evaluations */ bst->it = 0; bst->feval = 0; if (parms->debug) { fp = fopen ("scores.txt", "w"); } /* The lss_coeff array keeps track of the coefficient values at the start of a line search. */ for (int i = 0; i < bxf->num_coeff; i++) { lss_coeff[i] = bxf->coeff[i]; } while (1) { /* Get next search location */ optimizer.setulb (); if (optimizer.task[0] == 'F' && optimizer.task[1] == 'G') { /* Got a new probe location within a line search */ /* Copy from fortran to C (double -> float) */ for (int i = 0; i < bxf->num_coeff; i++) { bxf->coeff[i] = (float) optimizer.x[i]; } /* Compute line search distance */ float ls_dist = 0.f; for (int i = 0; i < bxf->num_coeff; i++) { float d = lss_coeff[i] - bxf->coeff[i]; ls_dist += d*d; } ls_dist = sqrt (ls_dist); /* Compute cost and gradient */ bspline_score (bod); /* Save coeff if best score */ if (ssd->total_score < best_score) { best_score = ssd->total_score; for (int i = 0; i < bxf->num_coeff; i++) { best_coeff[i] = bxf->coeff[i]; } } /* Give a little feedback to the user */ bspline_display_coeff_stats (bxf); logfile_printf (" " "LSD %6.2f\n", ls_dist); /* Save some debugging information */ bspline_save_debug_state (parms, bst, bxf); if (parms->debug) { fprintf (fp, "%f\n", ssd->total_score); } /* Copy from C to fortran (float -> double) */ optimizer.f = ssd->total_score; for (int i = 0; i < bxf->num_coeff; i++) { optimizer.g[i] = ssd->total_grad[i]; } /* Check # feval */ if (bst->feval >= parms->max_feval) break; bst->feval ++; } else if (memcmp (optimizer.task, "NEW_X", strlen ("NEW_X")) == 0) { /* Optimizer has completed a line search. */ /* Check convergence tolerance */ if (old_best_score != DBL_MAX) { double score_diff = old_best_score - ssd->total_score; if (score_diff < parms->convergence_tol && bst->it >= parms->min_its) { break; } } old_best_score = ssd->total_score; /* Update line search start location */ printf ("Update lss_coeff\n"); for (int i = 0; i < bxf->num_coeff; i++) { lss_coeff[i] = (float) optimizer.x[i]; } /* Check iterations */ if (bst->it >= parms->max_its) { break; } bst->it ++; } else { break; } } if (parms->debug) { fclose (fp); } /* Copy out the best results */ for (int i = 0; i < bxf->num_coeff; i++) { bxf->coeff[i] = best_coeff[i]; } free (best_coeff); free (lss_coeff); } bspline_optimize_lbfgsb.h000066400000000000000000000006521321604176500334330ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_optimize_lbfgsb_h_ #define _bspline_optimize_lbfgsb_h_ #include class Bspline_optimize; PLMREGISTER_C_API void bspline_optimize_lbfgsb (Bspline_optimize *bod); #endif bspline_optimize_liblbfgs.cxx000066400000000000000000000053311321604176500343320ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include "bspline.h" #include "bspline_optimize.h" #include "bspline_optimize_liblbfgs.h" #include "bspline_parms.h" #include "bspline_state.h" #include "bspline_xform.h" #include "logfile.h" #include "plm_math.h" static lbfgsfloatval_t evaluate ( void *instance, const lbfgsfloatval_t *x, lbfgsfloatval_t *g, const int n, const lbfgsfloatval_t step) { Bspline_optimize *bod = (Bspline_optimize*) instance; Bspline_xform *bxf = bod->get_bspline_xform (); Bspline_state *bst = bod->get_bspline_state (); int i; /* Copy x in */ for (i = 0; i < bxf->num_coeff; i++) { bxf->coeff[i] = (float) x[i]; } /* Compute cost and gradient */ bspline_score (bod); /* Copy gradient out */ for (i = 0; i < bxf->num_coeff; i++) { g[i] = (lbfgsfloatval_t) bst->ssd.total_grad[i]; } /* Increment num function evals */ bst->feval ++; /* Return cost */ return (lbfgsfloatval_t) bst->ssd.total_score; } static int progress( void *instance, const lbfgsfloatval_t *x, const lbfgsfloatval_t *g, const lbfgsfloatval_t fx, const lbfgsfloatval_t xnorm, const lbfgsfloatval_t gnorm, const lbfgsfloatval_t step, int n, /* Size of input vector */ int k, /* Iteration number */ int ls /* feval within this iteration */ ) { Bspline_optimize *bod = (Bspline_optimize*) instance; Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); logfile_printf ( " XN %9.3f GN %9.3f ST %9.3f\n", xnorm, gnorm, step); bst->it = k; if (bst->it > parms->max_its || bst->feval > parms->max_feval) { return 1; } return 0; } void bspline_optimize_liblbfgs (Bspline_optimize *bod) { int i, rc; lbfgsfloatval_t fx; lbfgs_parameter_t param; lbfgsfloatval_t *x; Bspline_xform *bxf = bod->get_bspline_xform (); x = lbfgs_malloc (bxf->num_coeff); /* Convert x0 from float to lbfgsfloatval_t */ for (i = 0; i < bxf->num_coeff; i++) { x[i] = (lbfgsfloatval_t) bxf->coeff[i]; } /* Set default parameters */ lbfgs_parameter_init (¶m); /* Run the optimizer */ rc = lbfgs (bxf->num_coeff, x, &fx, evaluate, progress, (void*) bod, ¶m); (void) rc; /* Suppress compiler warning */ lbfgs_free (x); } bspline_optimize_liblbfgs.h000066400000000000000000000007201321604176500337540ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_optimize_liblbfgs_h_ #define _bspline_optimize_liblbfgs_h_ #include "plmregister_config.h" #include "lbfgs.h" class Bspline_optimize; PLMREGISTER_C_API void bspline_optimize_liblbfgs (Bspline_optimize *bod); #endif bspline_optimize_nlopt.cxx000066400000000000000000000042651321604176500337070ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #if (NLOPT_FOUND) #include "nlopt.h" #endif #include "bspline.h" #include "bspline_optimize.h" #include "bspline_optimize_nlopt.h" #include "bspline_parms.h" #include "bspline_xform.h" #include "plm_math.h" #if (NLOPT_FOUND) /* NLopt score function */ static double bspline_optimize_nlopt_score ( int n, const double *x, double *grad, void *data) { int i; Bspline_optimize *bod = (Bspline_optimize*) data; Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); /* Copy x in */ for (i = 0; i < bxf->num_coeff; i++) { bxf->coeff[i] = (float) x[i]; } /* Compute cost and gradient */ bspline_score (bod); /* Copy gradient out */ for (i = 0; i < bxf->num_coeff; i++) { grad[i] = (double) bst->ssd.total_grad[i]; } /* Return cost */ return (double) bst->ssd.total_score; } void bspline_optimize_nlopt (Bspline_optimize *bod, nlopt_algorithm algorithm) { int i; double *lb, *ub, *x; double minf; Bspline_parms *parms = bod->get_bspline_parms (); Bspline_xform *bxf = bod->get_bspline_xform (); x = (double*) malloc (sizeof(double) * bxf->num_coeff); lb = (double*) malloc (sizeof(double) * bxf->num_coeff); ub = (double*) malloc (sizeof(double) * bxf->num_coeff); for (i = 0; i < bxf->num_coeff; i++) { lb[i] = -HUGE_VAL; ub[i] = +HUGE_VAL; x[i] = (double) bxf->coeff[i]; } nlopt_result nr = nlopt_minimize ( algorithm, bxf->num_coeff, bspline_optimize_nlopt_score, bod, lb, ub, x, &minf, -HUGE_VAL, 0, 1., 0, 0, parms->max_its, 0); printf ("nlopt returned: %d\n", nr); for (i = 0; i < bxf->num_coeff; i++) { bxf->coeff[i] = (float) x[i]; } free (x); free (ub); free (lb); } #endif bspline_optimize_nlopt.h000066400000000000000000000010471321604176500333270ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_optimize_nlopt_h_ #define _bspline_optimize_nlopt_h_ #include "plmregister_config.h" #if (NLOPT_FOUND) #include "nlopt.h" #endif class Bspline_optimize; #if (NLOPT_FOUND) PLMREGISTER_C_API void bspline_optimize_nlopt ( Bspline_optimize *bod, nlopt_algorithm algorithm ); #endif #endif bspline_optimize_steepest.cxx000066400000000000000000000316041321604176500344040ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #if (OPENMP_FOUND) #include #endif #include "bspline.h" #include "bspline_optimize.h" #include "bspline_optimize_steepest.h" #include "bspline_parms.h" #include "bspline_state.h" #include "bspline_xform.h" #include "logfile.h" /* * This is a simple gradient plotter based on * steepest_trust() */ void bspline_optimize_steepest_trace ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Bspline_score* ssd = &bst->ssd; int i; float alpha = 1.0f; float ssd_grad_norm; float old_score; FILE *fp = 0; double htg; int success; float *grad_backup; int j; FILE *trace; char filename[20]; float score_backup; float *x; /* Start of line search */ float *h; /* Search direction */ if (parms->debug) { fp = fopen("scores.txt", "w"); } // GCS FIX: I'm pretty sure the below makes no sense. // JAS 04.19.2010 // For Testing... if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) { alpha = 1.0f; printf ("Using alpha_0 (%f)\n", alpha); } /* Allocate memory for search direction */ x = (float*) malloc (bxf->num_coeff * sizeof(float)); h = (float*) malloc (bxf->num_coeff * sizeof(float)); grad_backup = (float*) malloc (bxf->num_coeff * sizeof(float)); /* Set iteration */ bst->it = 0; bst->feval = 0; success = 0; memcpy (x, bxf->coeff, bxf->num_coeff * sizeof(float)); /* Get score and gradient */ bspline_score (bod); old_score = bst->ssd.total_score; /* Get search direction */ ssd_grad_norm = 0; for (i = 0; i < bxf->num_coeff; i++) { ssd_grad_norm += ssd->total_grad[i] * ssd->total_grad[i]; } ssd_grad_norm = sqrt (ssd_grad_norm); htg = 0.0; for (i = 0; i < bxf->num_coeff; i++) { h[i] = - ssd->total_grad[i] / ssd_grad_norm; htg -= h[i] * ssd->total_grad[i]; } /* Give a little feedback to the user */ bspline_display_coeff_stats (bxf); /* Save some debugging information */ bspline_save_debug_state (parms, bst, bxf); if (parms->debug) { fprintf (fp, "%f\n", ssd->total_score); } while (bst->it < parms->max_its && bst->feval < parms->max_feval) { double gr; int accept_step = 0; /* Update num function evaluations */ bst->feval ++; /* Compute new search location */ for (i = 0; i < bxf->num_coeff; i++) { bxf->coeff[i] = x[i] + alpha * h[i]; } /* Get score and gradient */ bspline_score (bod); /* Compute gain ratio with linear model */ gr = (old_score - bst->ssd.total_score) / htg; if (gr < 0) { /* Cost increased. Keep search direction and reduce trust rgn. */ alpha = 0.5 * alpha; } else if (gr < 0.25) { alpha = 0.5 * alpha; accept_step = 1; } else if (gr > 0.75) { alpha = 3.0 * alpha; accept_step = 1; } else { accept_step = 1; } /* Give a little feedback to the user */ bspline_display_coeff_stats (bxf); logfile_printf (" " "GR %6.2f NEW_A %6.4f ACCEPT? %d\n", gr, alpha, accept_step); /* Save some debugging information */ bspline_save_debug_state (parms, bst, bxf); if (parms->debug) { fprintf (fp, "%f\n", ssd->total_score); } /* If score was reduced, we accept the line search (fall through). Otherwise, we reduce trust region (continue). */ if (!accept_step) continue; /* Update iteration number */ bst->it ++; // At this point we have a good set of coefficients that // minimize the cost function. // // So, let's plot the gradient before starting a new // line search. success ++; memcpy (x, bxf->coeff, bxf->num_coeff * sizeof(float)); memcpy (grad_backup, ssd->total_grad, bxf->num_coeff * sizeof(float)); score_backup = ssd->total_score; sprintf (filename, "grad_%04i.csv", success); trace = fopen(filename, "w"); printf ("Capturing Gradient (grad_%04i.csv)\n", success); // For each step along the gradient for (i = -35; i < 35; i++) { for (j = 0; j < bxf->num_coeff; j++) { bxf->coeff[j] = x[j] + i * 1 * h[j]; } /* Get score */ printf ("\t"); bspline_score (bod); fprintf (trace, "%d, %10.10f\n", i, bst->ssd.total_score); fflush(trace); } fclose (trace); printf ("Finished Capturing Gradient.\n\n"); memcpy (ssd->total_grad, grad_backup, bxf->num_coeff * sizeof(float)); ssd->total_score = score_backup; /* Start new line search */ ssd_grad_norm = 0; for (i = 0; i < bxf->num_coeff; i++) { ssd_grad_norm += ssd->total_grad[i] * ssd->total_grad[i]; } ssd_grad_norm = sqrt (ssd_grad_norm); htg = 0.0; for (i = 0; i < bxf->num_coeff; i++) { h[i] = - ssd->total_grad[i] / ssd_grad_norm; htg -= h[i] * ssd->total_grad[i]; } old_score = bst->ssd.total_score; } /* Save best result */ memcpy (bxf->coeff, x, bxf->num_coeff * sizeof(float)); bst->ssd.total_score = old_score; if (parms->debug) { fclose (fp); } free (grad_backup); free (x); free (h); } /* This combines a steepest descent direction with trust interval line search. See Eqn 2.8 + Eqn 2.20 in Madsen, Nielsen, and Tingleff's booklet: "Methods for non-linear least squares probelms" http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf See also: http://www2.imm.dtu.dk/~hbn/immoptibox/ It works ok, but seems to get caught in Stiefel's cage. */ void bspline_optimize_steepest_trust ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Bspline_score* ssd = &bst->ssd; int i; float alpha = 1.0f; float ssd_grad_norm; float old_score; FILE *fp = 0; float *x; /* Start of line search */ float *h; /* Search direction */ double htg; if (parms->debug) { fp = fopen("scores.txt", "w"); } // GCS FIX: I'm pretty sure the below makes no sense. // JAS 04.19.2010 // For testing... if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) { alpha = 1.0f; printf ("Using alpha_0 (%f)\n", alpha); } /* Allocate memory for search direction */ x = (float*) malloc (bxf->num_coeff * sizeof(float)); h = (float*) malloc (bxf->num_coeff * sizeof(float)); /* Set iteration */ bst->it = 0; bst->feval = 0; memcpy (x, bxf->coeff, bxf->num_coeff * sizeof(float)); /* Get score and gradient */ bspline_score (bod); old_score = bst->ssd.total_score; /* Get search direction */ ssd_grad_norm = 0; for (i = 0; i < bxf->num_coeff; i++) { ssd_grad_norm += ssd->total_grad[i] * ssd->total_grad[i]; } ssd_grad_norm = sqrt (ssd_grad_norm); htg = 0.0; for (i = 0; i < bxf->num_coeff; i++) { h[i] = - ssd->total_grad[i] / ssd_grad_norm; htg -= h[i] * ssd->total_grad[i]; } /* Give a little feedback to the user */ bspline_display_coeff_stats (bxf); /* Save some debugging information */ bspline_save_debug_state (parms, bst, bxf); if (parms->debug) { fprintf (fp, "%f\n", ssd->total_score); } while (bst->it < parms->max_its && bst->feval < parms->max_feval) { double gr; int accept_step = 0; /* Update num function evaluations */ bst->feval ++; /* Compute new search location */ for (i = 0; i < bxf->num_coeff; i++) { bxf->coeff[i] = x[i] + alpha * h[i]; } /* Get score and gradient */ bspline_score (bod); /* Compute gain ratio with linear model */ gr = (old_score - bst->ssd.total_score) / htg; if (gr < 0) { /* Cost increased. Keep search direction and reduce trust rgn. */ alpha = 0.5 * alpha; } else if (gr < 0.25) { alpha = 0.5 * alpha; accept_step = 1; } else if (gr > 0.75) { alpha = 3.0 * alpha; accept_step = 1; } else { accept_step = 1; } /* Give a little feedback to the user */ bspline_display_coeff_stats (bxf); logfile_printf (" " "GR %6.2f NEW_A %6.2f ACCEPT? %d\n", gr, alpha, accept_step); /* Save some debugging information */ bspline_save_debug_state (parms, bst, bxf); if (parms->debug) { fprintf (fp, "%f\n", ssd->total_score); } /* If score was reduced, we accept the line search */ if (!accept_step) continue; /* Update iteration number */ bst->it ++; /* Start new line search */ memcpy (x, bxf->coeff, bxf->num_coeff * sizeof(float)); ssd_grad_norm = 0; for (i = 0; i < bxf->num_coeff; i++) { ssd_grad_norm += ssd->total_grad[i] * ssd->total_grad[i]; } ssd_grad_norm = sqrt (ssd_grad_norm); htg = 0.0; for (i = 0; i < bxf->num_coeff; i++) { h[i] = - ssd->total_grad[i] / ssd_grad_norm; htg -= h[i] * ssd->total_grad[i]; } old_score = bst->ssd.total_score; } /* Save best result */ memcpy (bxf->coeff, x, bxf->num_coeff * sizeof(float)); bst->ssd.total_score = old_score; if (parms->debug) { fclose (fp); } free (x); free (h); } /* This is a really terrible algorithm. It takes steps without doing any sort of line search. */ void bspline_optimize_steepest_naive ( Bspline_optimize *bod ) { Bspline_parms *parms = bod->get_bspline_parms (); Bspline_state *bst = bod->get_bspline_state (); Bspline_xform *bxf = bod->get_bspline_xform (); Bspline_score* ssd = &bst->ssd; int i; // float a = 0.003f; // float alpha = 0.5f, A = 10.0f; float a, gamma; float gain = 1.5; float ssd_grad_norm; float old_score; FILE* fp = 0; if (parms->debug) { fp = fopen("scores.txt", "w"); } /* Set iteration */ bst->it = 0; bst->feval = 0; /* Get score and gradient */ bspline_score (bod); old_score = bst->ssd.total_score; /* Set alpha based on norm gradient */ ssd_grad_norm = 0; for (i = 0; i < bxf->num_coeff; i++) { ssd_grad_norm += fabs (ssd->total_grad[i]); } a = 1.0f / ssd_grad_norm; gamma = a; logfile_printf ("Initial gamma is %g\n", gamma); /* Give a little feedback to the user */ bspline_display_coeff_stats (bxf); /* Save some debugging information */ bspline_save_debug_state (parms, bst, bxf); if (parms->debug) { fprintf (fp, "%f\n", ssd->total_score); } while (bst->it < parms->max_its && bst->feval < parms->max_feval) { /* Update num iterations & num function evaluations */ bst->it ++; bst->feval ++; logfile_printf ("Beginning iteration %d, gamma = %g\n", bst->it, gamma); /* Update b-spline coefficients from gradient */ //gamma = a / pow(it + A, alpha); for (i = 0; i < bxf->num_coeff; i++) { bxf->coeff[i] = bxf->coeff[i] + gamma * ssd->total_grad[i]; } /* Get score and gradient */ bspline_score (bod); /* Update gamma */ if (bst->ssd.total_score < old_score) { gamma *= gain; } else { gamma /= gain; } old_score = bst->ssd.total_score; /* Give a little feedback to the user */ bspline_display_coeff_stats (bxf); /* Save some debugging information */ bspline_save_debug_state (parms, bst, bxf); if (parms->debug) { fprintf (fp, "%f\n", ssd->total_score); } } if (parms->debug) { fclose (fp); } } void bspline_optimize_steepest ( Bspline_optimize *bod ) { const int USE_NAIVE = 0; if (USE_NAIVE) { bspline_optimize_steepest_naive (bod); } else { bspline_optimize_steepest_trust (bod); // DEBUG // bspline_optimize_steepest_trace ( // bxf, bst, parms, fixed, moving, moving_grad); } } bspline_optimize_steepest.h000066400000000000000000000006751321604176500340350ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_optimize_steepest_h_ #define _bspline_optimize_steepest_h_ #include "plmregister_config.h" class Bspline_optimize; PLMREGISTER_C_API void bspline_optimize_steepest (Bspline_optimize *bod); #endif bspline_parms.cxx000066400000000000000000000027451321604176500317560ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "bspline_parms.h" #include "bspline_landmarks.h" #include "bspline_regularize.h" #include "logfile.h" Bspline_parms::Bspline_parms () { this->threading = BTHR_CPU; this->optimization = BOPT_LBFGSB; this->min_its = 0; this->max_its = 10; this->max_feval = 10; this->debug = 0; this->debug_dir = "."; this->debug_stage = 0; this->gpuid = 0; this->convergence_tol = 1e-6; this->mi_hist_type = HIST_EQSP; this->mi_hist_fixed_bins = 32; this->mi_hist_moving_bins = 32; this->mi_fixed_image_minVal=0; this->mi_fixed_image_maxVal=0; this->mi_moving_image_minVal=0; this->mi_moving_image_maxVal=0; this->lbfgsb_factr = 1.0e+7; this->lbfgsb_pgtol = 1.0e-5; this->lbfgsb_mmax = -1; this->fixed_stiffness = 0; this->reg_parms = new Regularization_parms; this->blm = new Bspline_landmarks; this->rbf_radius = 0; this->rbf_young_modulus = 0; this->xpm_hist_dump = 0; } Bspline_parms::~Bspline_parms () { delete this->blm; delete this->reg_parms; } void Bspline_parms::log () { logfile_printf ("BSPLINE PARMS\n"); logfile_printf ("max_its = %d\n", this->max_its); logfile_printf ("max_feval = %d\n", this->max_feval); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_parms.h000066400000000000000000000054031321604176500314540ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_parms_h_ #define _bspline_parms_h_ #include "plmregister_config.h" #include #include #include #include "double_align8.h" #include "joint_histogram.h" #include "metric_state.h" #include "similarity_metric_type.h" #include "smart_pointer.h" enum BsplineOptimization { BOPT_LBFGSB, BOPT_STEEPEST, BOPT_LIBLBFGS, BOPT_NLOPT_LBFGS, BOPT_NLOPT_LD_MMA, BOPT_NLOPT_PTN_1, }; enum BsplineThreading { BTHR_CPU, BTHR_CUDA }; class Bspline_landmarks; class Regularization_parms; class PLMREGISTER_API Bspline_parms { public: SMART_POINTER_SUPPORT (Bspline_parms); public: Bspline_parms (); ~Bspline_parms (); public: /* General optimizer parms */ enum BsplineOptimization optimization; int min_its; /* Miniumum iterations (line searches) */ int max_its; /* Max iterations (line searches) */ int max_feval; /* Max function evaluations */ double_align8 convergence_tol; /* When to stop iterations based on score */ /* LBFGSB optimizer parms */ double_align8 lbfgsb_factr; /* Function value tolerance for L-BFGS-B */ double_align8 lbfgsb_pgtol; /* Projected grad tolerance for L-BFGS-B */ int lbfgsb_mmax; /* Number of rows in M matrix */ /* Debugging */ int debug; /* Create grad & histogram files */ std::string debug_dir; /* Directory where to create debug files */ int debug_stage; /* Used to tag debug files by stage */ char* xpm_hist_dump; /* Pointer to base string of hist dumps */ /* Threading */ enum BsplineThreading threading; int gpuid; /* Sets GPU to use for multi-gpu machines */ /*! \brief Implementation ('a', 'b', etc.) -- to be moved into Stage_similarity_data */ char implementation; /* MI similarity metric */ enum Mi_hist_type mi_hist_type; plm_long mi_hist_fixed_bins; plm_long mi_hist_moving_bins; /* Image ROI selection */ float mi_fixed_image_minVal; float mi_fixed_image_maxVal; float mi_moving_image_minVal; float mi_moving_image_maxVal; /* Regularization */ Regularization_parms* reg_parms; Volume* fixed_stiffness; /* Landmarks */ Bspline_landmarks* blm; /* Landmarks parameters */ /*! \brief Radius of RBF; if rbf_radius>0, RBF are used */ float rbf_radius; /*! \brief Penalty for the large 2nd derivative of RBF vector field */ float rbf_young_modulus; public: void log (); }; #endif bspline_regularize.cxx000066400000000000000000000057271321604176500330100ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include "bspline_regularize.h" #include "print_and_exit.h" Bspline_regularize::Bspline_regularize () { /* all methods */ this->reg_parms = 0; this->bxf = 0; this->fixed_stiffness = 0; /* semi-analytic method */ this->q_dxdyz_lut = 0; this->q_xdydz_lut = 0; this->q_dxydz_lut = 0; this->q_d2xyz_lut = 0; this->q_xd2yz_lut = 0; this->q_xyd2z_lut = 0; /* analytic method */ this->QX_mats = 0; this->QY_mats = 0; this->QZ_mats = 0; this->QX = 0; this->QY = 0; this->QZ = 0; this->V_mats = 0; this->V = 0; this->cond = 0; } Bspline_regularize::~Bspline_regularize () { if (!reg_parms) { return; } /* Don't free reg_parms, fixed, moving, bxf; you don't own them */ /* Semi-analytic method has LUTs to free */ free (this->q_dxdyz_lut); free (this->q_xdydz_lut); free (this->q_dxydz_lut); free (this->q_d2xyz_lut); free (this->q_xd2yz_lut); free (this->q_xyd2z_lut); /* Numeric method has Q matrices to free */ free (this->QX_mats); free (this->QY_mats); free (this->QZ_mats); free (this->QX); free (this->QY); free (this->QZ); free (this->V_mats); free (this->V); free (this->cond); } void Bspline_regularize::initialize ( Regularization_parms *reg_parms, Bspline_xform* bxf ) { this->reg_parms = reg_parms; this->bxf = bxf; switch (reg_parms->implementation) { case 'a': this->numeric_init (bxf); break; case 'b': case 'c': this->analytic_init (bxf); break; case 'd': this->semi_analytic_init (bxf); break; default: print_and_exit ( "Error: unknown reg_parms->implementation (%c)\n", reg_parms->implementation ); break; } } void Bspline_regularize::compute_score ( Bspline_score *bspline_score, /* Gets updated */ const Regularization_parms* reg_parms, const Bspline_xform* bxf ) { switch (reg_parms->implementation) { case 'a': this->compute_score_numeric (bspline_score, reg_parms, this, bxf); break; case 'b': this->compute_score_analytic (bspline_score, reg_parms, this, bxf); break; case 'c': #if (OPENMP_FOUND) this->compute_score_analytic_omp (bspline_score, reg_parms, this, bxf); #else this->compute_score_analytic (bspline_score, reg_parms, this, bxf); #endif break; case 'd': this->compute_score_semi_analytic (bspline_score, reg_parms, this, bxf); break; default: print_and_exit ( "Error: unknown reg_parms->implementation (%c)\n", reg_parms->implementation ); break; } } bspline_regularize.h000066400000000000000000000067101321604176500324260ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_regularize_h_ #define _bspline_regularize_h_ #include "plmregister_config.h" #include "volume.h" class Bspline_score; class Bspline_xform; class Regularization_parms { public: char implementation; /* Implementation: a, b, c, etc */ float lambda; /* Smoothness weighting factor */ public: Regularization_parms () { this->implementation = '\0'; this->lambda = 0.0f; } }; class PLMREGISTER_API Bspline_regularize { public: SMART_POINTER_SUPPORT (Bspline_regularize); public: Bspline_regularize (); ~Bspline_regularize (); public: /* all methods */ Regularization_parms *reg_parms; Bspline_xform *bxf; Volume* fixed_stiffness; /* numeric methods */ float* q_dxdyz_lut; /* LUT for influence of dN1/dx*dN2/dy*N3 */ float* q_xdydz_lut; /* LUT for influence of N1*dN2/dy*dN3/dz */ float* q_dxydz_lut; /* LUT for influence of dN1/dx*N2*dN3/dz */ float* q_d2xyz_lut; /* LUT for influence of (d2N1/dx2)*N2*N3 */ float* q_xd2yz_lut; /* LUT for influence of N1*(d2N2/dy2)*N3 */ float* q_xyd2z_lut; /* LUT for influence of N1*N2*(d2N3/dz2) */ /* analytic methods */ double* QX_mats; /* Three 4x4 matrices */ double* QY_mats; /* Three 4x4 matrices */ double* QZ_mats; /* Three 4x4 matrices */ double** QX; double** QY; double** QZ; double* V_mats; /* The 6 64x64 V matricies */ double** V; double* cond; public: void initialize ( Regularization_parms* reg_parms, Bspline_xform* bxf ); void compute_score ( Bspline_score* bsp_score, /* Gets updated */ const Regularization_parms* reg_parms, const Bspline_xform* bxf ); protected: void numeric_init ( const Bspline_xform* bxf); void compute_score_numeric ( Bspline_score *bscore, const Regularization_parms *parms, const Bspline_regularize *rst, const Bspline_xform* bxf); void analytic_init ( const Bspline_xform* bxf); void compute_score_analytic ( Bspline_score *bspline_score, const Regularization_parms* reg_parms, const Bspline_regularize* rst, const Bspline_xform* bxf); void compute_score_analytic_omp ( Bspline_score *bspline_score, const Regularization_parms* reg_parms, const Bspline_regularize* rst, const Bspline_xform* bxf); void semi_analytic_init ( const Bspline_xform* bxf); void create_qlut_grad ( const Bspline_xform* bxf, const float img_spacing[3], const plm_long vox_per_rgn[3]); void hessian_component ( float out[3], const Bspline_xform* bxf, plm_long p[3], plm_long qidx, int derive1, int derive2); void hessian_update_grad ( Bspline_score *bscore, const Bspline_xform* bxf, plm_long p[3], plm_long qidx, float dc_dv[3], int derive1, int derive2); void compute_score_semi_analytic ( Bspline_score *bscore, const Regularization_parms *parms, const Bspline_regularize *rst, const Bspline_xform* bxf); }; #endif bspline_regularize_analytic.cxx000066400000000000000000000426441321604176500346730ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #if (OPENMP_FOUND) #include #endif #include "bspline.h" #include "bspline_regularize.h" #include "bspline_regularize_analytic.h" #include "bspline_score.h" #include "bspline_xform.h" #include "plm_math.h" #include "plm_timer.h" #include "volume.h" void print_matrix (double* mat, int m, int n) { int i,j; for (j=0; jimg; plm_long p[3]; float q[3]; float* q_lut; plm_long* c_lut; for (k = 0; k < vol->dim[2]; k++) { p[2] = k / bxf->vox_per_rgn[2]; q[2] = k % bxf->vox_per_rgn[2]; for (j = 0; j < vol->dim[1]; j++) { p[1] = j / bxf->vox_per_rgn[1]; q[1] = j % bxf->vox_per_rgn[1]; for (i = 0; i < vol->dim[0]; i++) { p[0] = i / bxf->vox_per_rgn[0]; q[0] = i % bxf->vox_per_rgn[0]; pidx = volume_index (bxf->rdims, p[0], p[1], p[2]); qidx = volume_index (bxf->vox_per_rgn, q[0], q[1], q[2]); idx_poi = volume_index (vol->dim, i, j, k); vec_poi = &img[3*idx_poi]; q_lut = &bxf->q_lut[qidx*64]; c_lut = &bxf->c_lut[pidx*64]; z = 0; for (c = 0; c < 4; c++) { for (b = 0; b < 4; b++) { for (a = 0; a < 4; a++) { cidx = 3 * c_lut[z]; bxf->coeff[cidx+0] += vec_poi[0] * q_lut[z]; bxf->coeff[cidx+1] += vec_poi[1] * q_lut[z]; bxf->coeff[cidx+2] += vec_poi[2] * q_lut[z]; z++; } } } } /* i < vol-dim[0] */ } /* j < vol->dim[1] */ } /* k < vol->dim[2] */ } #if (OPENMP_FOUND) void reg_sort_sets ( double* cond, double* sets, plm_long* k_lut, const Bspline_xform* bxf ) { int sidx, kidx; /* Rackem' Up */ for (sidx=0; sidx<64; sidx++) { kidx = k_lut[sidx]; cond[3*(64*kidx+sidx)+0] = sets[3*sidx+0]; cond[3*(64*kidx+sidx)+1] = sets[3*sidx+1]; cond[3*(64*kidx+sidx)+2] = sets[3*sidx+2]; } } #endif #if (OPENMP_FOUND) void reg_update_grad ( Bspline_score* ssd, double* cond, const Bspline_xform* bxf ) { int kidx, sidx; for (kidx=0; kidx < bxf->num_knots; kidx++) { for (sidx=0; sidx<64; sidx++) { ssd->total_grad[3*kidx+0] += cond[3*(64*kidx+sidx)+0]; ssd->total_grad[3*kidx+1] += cond[3*(64*kidx+sidx)+1]; ssd->total_grad[3*kidx+2] += cond[3*(64*kidx+sidx)+2]; } } } #endif void find_knots_3 (plm_long* knots, plm_long tile_num, const plm_long* cdims) { int tile_loc[3]; int i, j, k; int idx = 0; int num_tiles_x = cdims[0] - 3; int num_tiles_y = cdims[1] - 3; int num_tiles_z = cdims[2] - 3; // First get the [x,y,z] coordinate of // the tile in the control grid. tile_loc[0] = tile_num % num_tiles_x; tile_loc[1] = ((tile_num - tile_loc[0]) / num_tiles_x) % num_tiles_y; tile_loc[2] = ((((tile_num - tile_loc[0]) / num_tiles_x) / num_tiles_y) % num_tiles_z); /* GCS 2011-07-14: Why not remove the below three lines, and let i,j,k run from 0 to 3? */ // Tiles do not start on the edges of the grid, so we // push them to the center of the control grid. tile_loc[0]++; tile_loc[1]++; tile_loc[2]++; // Find 64 knots' [x,y,z] coordinates // and convert into a linear knot index for (k = -1; k < 3; k++) for (j = -1; j < 3; j++) for (i = -1; i < 3; i++) { knots[idx++] = (cdims[0]*cdims[1]*(tile_loc[2]+k)) + (cdims[0]*(tile_loc[1]+j)) + (tile_loc[0]+i); } } void eval_integral (double* V, double* Qn, double gs) { int i,j; double S[16]; double I[7] = { gs, (1.0/2.0) * (gs * gs), (1.0/3.0) * (gs * gs * gs), (1.0/4.0) * (gs * gs * gs * gs), (1.0/5.0) * (gs * gs * gs * gs * gs), (1.0/6.0) * (gs * gs * gs * gs * gs * gs), (1.0/7.0) * (gs * gs * gs * gs * gs * gs * gs) }; // Generate 16 4x4 matrix by taking the outer // product of the each row in the Q matrix with // every other row in the Q matrix. We use these // to generate each element in V. for (j=0; j<4; j++) { for (i=0; i<4; i++) { vec_outer (S, Qn+(4*j), Qn+(4*i), 4); V[4*j + i] = (I[0] * S[ 0]) + (I[1] * (S[ 1] + S[ 4])) + (I[2] * (S[ 2] + S[ 5] + S[ 8])) + (I[3] * (S[ 3] + S[ 6] + S[ 9] + S[12])) + (I[4] * (S[ 7] + S[10] + S[13])) + (I[5] * (S[11] + S[14])) + (I[6] * (S[15])); } } } void init_analytic (double **QX, double **QY, double **QZ, const Bspline_xform* bxf) { double rx, ry, rz; double B[16] = { 1.0/6.0, -1.0/2.0, 1.0/2.0, -1.0/6.0, 2.0/3.0, 0.0 , -1.0 , 1.0/2.0, 1.0/6.0, 1.0/2.0, 1.0/2.0, -1.0/2.0, 0.0 , 0.0 , 0.0 , 1.0/6.0 }; /* grid spacing */ rx = 1.0/bxf->grid_spac[0]; ry = 1.0/bxf->grid_spac[1]; rz = 1.0/bxf->grid_spac[2]; double RX[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, rx, 0.0, 0.0, 0.0, 0.0, rx*rx, 0.0, 0.0, 0.0, 0.0, rx*rx*rx }; double RY[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, ry, 0.0, 0.0, 0.0, 0.0, ry*ry, 0.0, 0.0, 0.0, 0.0, ry*ry*ry }; double RZ[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, rz, 0.0, 0.0, 0.0, 0.0, rz*rz, 0.0, 0.0, 0.0, 0.0, rz*rz*rz }; double delta1[16] = { 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0 }; double delta2[16] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 6.0, 0.0, 0.0 }; // Let's call Q the product of the recripocal grid spacing // matrix (R) and the B-spline coefficient matrix (B). mat_mult_mat (QX[0], B, 4, 4, RX, 4, 4); mat_mult_mat (QY[0], B, 4, 4, RY, 4, 4); mat_mult_mat (QZ[0], B, 4, 4, RZ, 4, 4); // Get the product of QX, QY, QZ and delta. // QX1 is the first-order derivative of X // QX2 is the second-order derivative of X // QY1 is the first-order derivative of Y // ... etc mat_mult_mat (QX[1], QX[0], 4, 4, delta1, 4, 4); mat_mult_mat (QX[2], QX[0], 4, 4, delta2, 4, 4); mat_mult_mat (QY[1], QY[0], 4, 4, delta1, 4, 4); mat_mult_mat (QY[2], QY[0], 4, 4, delta2, 4, 4); mat_mult_mat (QZ[1], QZ[0], 4, 4, delta1, 4, 4); mat_mult_mat (QZ[2], QZ[0], 4, 4, delta2, 4, 4); } void get_Vmatrix (double* V, double* X, double* Y, double* Z) { int i,j; double tmp[256]; /* 16 x 16 matrix */ /* Calculate the temporary 16*16 matrix */ for (j=0; j<4; j++) { for (i=0; i<4; i++) { tmp[16*(j+ 0) + (i+ 0)] = Y[4*0 + 0] * Z[4*j + i]; tmp[16*(j+ 0) + (i+ 4)] = Y[4*0 + 1] * Z[4*j + i]; tmp[16*(j+ 0) + (i+ 8)] = Y[4*0 + 2] * Z[4*j + i]; tmp[16*(j+ 0) + (i+12)] = Y[4*0 + 3] * Z[4*j + i]; tmp[16*(j+ 4) + (i+ 0)] = Y[4*1 + 0] * Z[4*j + i]; tmp[16*(j+ 4) + (i+ 4)] = Y[4*1 + 1] * Z[4*j + i]; tmp[16*(j+ 4) + (i+ 8)] = Y[4*1 + 2] * Z[4*j + i]; tmp[16*(j+ 4) + (i+12)] = Y[4*1 + 3] * Z[4*j + i]; tmp[16*(j+ 8) + (i+ 0)] = Y[4*2 + 0] * Z[4*j + i]; tmp[16*(j+ 8) + (i+ 4)] = Y[4*2 + 1] * Z[4*j + i]; tmp[16*(j+ 8) + (i+ 8)] = Y[4*2 + 2] * Z[4*j + i]; tmp[16*(j+ 8) + (i+12)] = Y[4*2 + 3] * Z[4*j + i]; tmp[16*(j+12) + (i+ 0)] = Y[4*3 + 0] * Z[4*j + i]; tmp[16*(j+12) + (i+ 4)] = Y[4*3 + 1] * Z[4*j + i]; tmp[16*(j+12) + (i+ 8)] = Y[4*3 + 2] * Z[4*j + i]; tmp[16*(j+12) + (i+12)] = Y[4*3 + 3] * Z[4*j + i]; } } /* Calculate the 64*64 V matrix */ for (j=0; j<16; j++) { for (i=0; i<16; i++) { V[64*(j+ 0) + (i+ 0)] = X[4*0 + 0] * tmp[16*j + i]; V[64*(j+ 0) + (i+16)] = X[4*0 + 1] * tmp[16*j + i]; V[64*(j+ 0) + (i+32)] = X[4*0 + 2] * tmp[16*j + i]; V[64*(j+ 0) + (i+48)] = X[4*0 + 3] * tmp[16*j + i]; V[64*(j+16) + (i+ 0)] = X[4*1 + 0] * tmp[16*j + i]; V[64*(j+16) + (i+16)] = X[4*1 + 1] * tmp[16*j + i]; V[64*(j+16) + (i+32)] = X[4*1 + 2] * tmp[16*j + i]; V[64*(j+16) + (i+48)] = X[4*1 + 3] * tmp[16*j + i]; V[64*(j+32) + (i+ 0)] = X[4*2 + 0] * tmp[16*j + i]; V[64*(j+32) + (i+16)] = X[4*2 + 1] * tmp[16*j + i]; V[64*(j+32) + (i+32)] = X[4*2 + 2] * tmp[16*j + i]; V[64*(j+32) + (i+48)] = X[4*2 + 3] * tmp[16*j + i]; V[64*(j+48) + (i+ 0)] = X[4*3 + 0] * tmp[16*j + i]; V[64*(j+48) + (i+16)] = X[4*3 + 1] * tmp[16*j + i]; V[64*(j+48) + (i+32)] = X[4*3 + 2] * tmp[16*j + i]; V[64*(j+48) + (i+48)] = X[4*3 + 3] * tmp[16*j + i]; } } } /* Employs my "world famous" thread safe "condense" control-point * update method for mulit-core acceleration. Also, score is * returned so as to take advantage of OpenMP's built in * sum-reduction capabilities */ #if (OPENMP_FOUND) double region_smoothness_omp ( double* sets, const Regularization_parms* reg_parms, const Bspline_xform* bxf, double* V, plm_long* knots ) { double S = 0.0; /* Region smoothness */ double X[64] = {0}; double Y[64] = {0}; double Z[64] = {0}; int i, j; for (j=0; j<64; j++) { /* S = pVp operation ----------------------------- */ for (i=0; i<64; i++) { X[j] += bxf->coeff[3*knots[i]+0] * V[64*j + i]; Y[j] += bxf->coeff[3*knots[i]+1] * V[64*j + i]; Z[j] += bxf->coeff[3*knots[i]+2] * V[64*j + i]; } S += X[j] * bxf->coeff[3*knots[j]+0]; S += Y[j] * bxf->coeff[3*knots[j]+1]; S += Z[j] * bxf->coeff[3*knots[j]+2]; /* ------------------------------------------------ */ /* dS/dp = 2Vp operation */ sets[3*j+0] += 2 * reg_parms->lambda * X[j]; sets[3*j+1] += 2 * reg_parms->lambda * Y[j]; sets[3*j+2] += 2 * reg_parms->lambda * Z[j]; } return S; } #endif void region_smoothness ( Bspline_score *bspline_score, const Regularization_parms* reg_parms, const Bspline_xform* bxf, double* V, plm_long* knots) { double S = 0.0; /* Region smoothness */ double X[64] = {0}; double Y[64] = {0}; double Z[64] = {0}; int i,j; for (j=0; j<64; j++) { /* S = pVp operation ----------------------------- */ for (i=0; i<64; i++) { X[j] += bxf->coeff[3*knots[i]+0] * V[64*j + i]; Y[j] += bxf->coeff[3*knots[i]+1] * V[64*j + i]; Z[j] += bxf->coeff[3*knots[i]+2] * V[64*j + i]; } S += X[j] * bxf->coeff[3*knots[j]+0]; S += Y[j] * bxf->coeff[3*knots[j]+1]; S += Z[j] * bxf->coeff[3*knots[j]+2]; /* ------------------------------------------------ */ /* dS/dp = 2Vp operation */ bspline_score->total_grad[3*knots[j]+0] += 2 * reg_parms->lambda * X[j]; bspline_score->total_grad[3*knots[j]+1] += 2 * reg_parms->lambda * Y[j]; bspline_score->total_grad[3*knots[j]+2] += 2 * reg_parms->lambda * Z[j]; } bspline_score->rmetric += S; } void Bspline_regularize::analytic_init ( const Bspline_xform* bxf) { double X[256]; /* 16 x 16 matrix */ double Y[256]; /* 16 x 16 matrix */ double Z[256]; /* 16 x 16 matrix */ double gs[3]; this->cond = (double*)malloc(3*64*bxf->num_knots*sizeof(double)); gs[0] = (double)bxf->grid_spac[0]; gs[1] = (double)bxf->grid_spac[1]; gs[2] = (double)bxf->grid_spac[2]; this->QX_mats = (double*)malloc (3 * 16 * sizeof (double)); this->QY_mats = (double*)malloc (3 * 16 * sizeof (double)); this->QZ_mats = (double*)malloc (3 * 16 * sizeof (double)); memset (this->QX_mats, 0, 3*16*sizeof(double)); memset (this->QY_mats, 0, 3*16*sizeof(double)); memset (this->QZ_mats, 0, 3*16*sizeof(double)); this->QX = (double**)malloc (3 * sizeof (double*)); this->QY = (double**)malloc (3 * sizeof (double*)); this->QZ = (double**)malloc (3 * sizeof (double*)); /* 4x4 matrices */ this->QX[0] = this->QX_mats; this->QX[1] = this->QX[0] + 16; this->QX[2] = this->QX[1] + 16; this->QY[0] = this->QY_mats; this->QY[1] = this->QY[0] + 16; this->QY[2] = this->QY[1] + 16; this->QZ[0] = this->QZ_mats; this->QZ[1] = this->QZ[0] + 16; this->QZ[2] = this->QZ[1] + 16; init_analytic (this->QX, this->QY, this->QZ, bxf); /* The below should probably be wrapped into init_analytic() */ this->V_mats = (double*)malloc (6*4096 * sizeof (double)); this->V = (double**)malloc (6 * sizeof (double*)); /* The six 64 x 64 V matrices */ this->V[0] = this->V_mats; this->V[1] = this->V[0] + 4096; this->V[2] = this->V[1] + 4096; this->V[3] = this->V[2] + 4096; this->V[4] = this->V[3] + 4096; this->V[5] = this->V[4] + 4096; eval_integral (X, this->QX[2], gs[0]); eval_integral (Y, this->QY[0], gs[1]); eval_integral (Z, this->QZ[0], gs[2]); get_Vmatrix (this->V[0], X, Y, Z); eval_integral (X, this->QX[0], gs[0]); eval_integral (Y, this->QY[2], gs[1]); eval_integral (Z, this->QZ[0], gs[2]); get_Vmatrix (this->V[1], X, Y, Z); eval_integral (X, this->QX[0], gs[0]); eval_integral (Y, this->QY[0], gs[1]); eval_integral (Z, this->QZ[2], gs[2]); get_Vmatrix (this->V[2], X, Y, Z); eval_integral (X, this->QX[1], gs[0]); eval_integral (Y, this->QY[1], gs[1]); eval_integral (Z, this->QZ[0], gs[2]); get_Vmatrix (this->V[3], X, Y, Z); eval_integral (X, this->QX[1], gs[0]); eval_integral (Y, this->QY[0], gs[1]); eval_integral (Z, this->QZ[1], gs[2]); get_Vmatrix (this->V[4], X, Y, Z); eval_integral (X, this->QX[0], gs[0]); eval_integral (Y, this->QY[1], gs[1]); eval_integral (Z, this->QZ[1], gs[2]); get_Vmatrix (this->V[5], X, Y, Z); printf ("Regularizer initialized\n"); } /* flavor 'c' */ #if (OPENMP_FOUND) void Bspline_regularize::compute_score_analytic_omp ( Bspline_score *bspline_score, const Regularization_parms* reg_parms, const Bspline_regularize* rst, const Bspline_xform* bxf) { plm_long i, n; double S = 0.0; Plm_timer* timer = new Plm_timer; timer->start (); memset (rst->cond, 0, 3*64*bxf->num_knots * sizeof (double)); // Total number of regions in grid n = bxf->rdims[0] * bxf->rdims[1] * bxf->rdims[2]; bspline_score->rmetric = 0.0; #pragma omp parallel for reduction(+:S) for (i=0; icdims); S += region_smoothness_omp (sets, reg_parms, bxf, rst->V[0], knots); S += region_smoothness_omp (sets, reg_parms, bxf, rst->V[1], knots); S += region_smoothness_omp (sets, reg_parms, bxf, rst->V[2], knots); S += region_smoothness_omp (sets, reg_parms, bxf, rst->V[3], knots); S += region_smoothness_omp (sets, reg_parms, bxf, rst->V[4], knots); S += region_smoothness_omp (sets, reg_parms, bxf, rst->V[5], knots); reg_sort_sets (rst->cond, sets, knots, bxf); } reg_update_grad (bspline_score, rst->cond, bxf); bspline_score->rmetric = S; bspline_score->time_rmetric = timer->report (); delete timer; } #endif /* flavor 'b' */ void Bspline_regularize::compute_score_analytic ( Bspline_score *bspline_score, const Regularization_parms* reg_parms, const Bspline_regularize* rst, const Bspline_xform* bxf) { plm_long i, n; plm_long knots[64]; Plm_timer* timer = new Plm_timer; timer->start (); // Total number of regions in grid n = bxf->rdims[0] * bxf->rdims[1] * bxf->rdims[2]; bspline_score->rmetric = 0.0; for (i=0; icdims); region_smoothness (bspline_score, reg_parms, bxf, rst->V[0], knots); region_smoothness (bspline_score, reg_parms, bxf, rst->V[1], knots); region_smoothness (bspline_score, reg_parms, bxf, rst->V[2], knots); region_smoothness (bspline_score, reg_parms, bxf, rst->V[3], knots); region_smoothness (bspline_score, reg_parms, bxf, rst->V[4], knots); region_smoothness (bspline_score, reg_parms, bxf, rst->V[5], knots); } bspline_score->time_rmetric = timer->report (); delete timer; } bspline_regularize_analytic.h000066400000000000000000000004741321604176500343130ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_regularize_analytic_h_ #define _bspline_regularize_analytic_h_ #endif bspline_regularize_numeric.cxx000066400000000000000000000317621321604176500345300ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include "bspline.h" #include "bspline_macros.h" #include "bspline_regularize.h" #include "bspline_regularize_numeric.h" #include "bspline_score.h" #include "bspline_xform.h" #include "logfile.h" #include "mha_io.h" #include "plm_math.h" #include "plm_timer.h" #include "print_and_exit.h" #include "volume_macros.h" #include "volume.h" /* Flavor 'a' */ static void compute_score_numeric_internal ( Bspline_score *bscore, const Regularization_parms *parms, const Bspline_regularize *rst, const Bspline_xform* bxf, const Volume* vol ) { plm_long i, j, k; int c; float *img = (float*) vol->img; float dx = vol->spacing[0]; float dy = vol->spacing[1]; float dz = vol->spacing[2]; float dxdydz = dx * dy * dz; float inv_dxdx = 1.0f / (dx * dx); float inv_dydy = 1.0f / (dy * dy); float inv_dzdz = 1.0f / (dz * dz); float inv_dxdy = 0.25f / (dx*dy); float inv_dxdz = 0.25f / (dx*dz); float inv_dydz = 0.25f / (dy*dz); /* Index of current point-of-interest (POI) */ int idx_poi; /* Indices of POI's SxS neighbors */ int idx_in, idx_ip; int idx_jn, idx_jp; int idx_kn, idx_kp; /* Indicies of POI's diagonal neighbors */ int idx_injn, idx_injp, idx_ipjn, idx_ipjp; int idx_inkn, idx_inkp, idx_ipkn, idx_ipkp; int idx_jnkn, idx_jnkp, idx_jpkn, idx_jpkp; /* Deformation vector @ POI */ float *vec_poi; /* Vectors of POI's SxS neighbors */ float *vec_in, *vec_ip; float *vec_jn, *vec_jp; float *vec_kn, *vec_kp; /* Vectors of POI's diagonal neighbors */ float *vec_injn, *vec_injp; float *vec_ipjn, *vec_ipjp; float *vec_inkn, *vec_inkp; float *vec_ipkn, *vec_ipkp; float *vec_jnkn, *vec_jnkp; float *vec_jpkn, *vec_jpkp; /* Vector's partial spatial derivatives */ float d2_dx2[3], d2_dxdy[3]; float d2_dy2[3], d2_dxdz[3]; float d2_dz2[3], d2_dydz[3]; /* Voxel-specific stiffness */ const float *fsimg = 0; if (rst->fixed_stiffness) { fsimg = rst->fixed_stiffness->get_raw(); } /* Square of 2nd derivative */ float d2_sq; /* Smoothness */ float S; #if defined (DEBUG) FILE* fp[3]; printf ("Warning: compiled with DEBUG : writing to to files:\n"); printf (" d2ux_dxy_sq.txt\n"); fp[0] = fopen ("d2ux_dxdy_sq.txt", "w"); printf (" d2uy_dxy_sq.txt\n"); fp[1] = fopen ("d2uy_dxdy_sq.txt", "w"); printf (" d2uz_dxy_sq.txt\n"); fp[2] = fopen ("d2uz_dxdy_sq.txt", "w"); #endif Plm_timer* timer = new Plm_timer; timer->start (); S = 0.0f; for (k = 1; k < vol->dim[2]-1; k++) { for (j = 1; j < vol->dim[1]-1; j++) { for (i = 1; i < vol->dim[0]-1; i++) { float dc_dv[3] = { 0, 0, 0 }; float dc_dv_in[3] = { 0, 0, 0 }; float dc_dv_ip[3] = { 0, 0, 0 }; float dc_dv_jn[3] = { 0, 0, 0 }; float dc_dv_jp[3] = { 0, 0, 0 }; float dc_dv_kn[3] = { 0, 0, 0 }; float dc_dv_kp[3] = { 0, 0, 0 }; float dc_dv_injn[3] = { 0, 0, 0 }; float dc_dv_injp[3] = { 0, 0, 0 }; float dc_dv_ipjn[3] = { 0, 0, 0 }; float dc_dv_ipjp[3] = { 0, 0, 0 }; float dc_dv_inkn[3] = { 0, 0, 0 }; float dc_dv_inkp[3] = { 0, 0, 0 }; float dc_dv_ipkn[3] = { 0, 0, 0 }; float dc_dv_ipkp[3] = { 0, 0, 0 }; float dc_dv_jnkn[3] = { 0, 0, 0 }; float dc_dv_jnkp[3] = { 0, 0, 0 }; float dc_dv_jpkn[3] = { 0, 0, 0 }; float dc_dv_jpkp[3] = { 0, 0, 0 }; /* Load indicies relevant to current POI */ idx_poi = volume_index (vol->dim, i, j, k); idx_in = volume_index (vol->dim, i-1, j, k); idx_ip = volume_index (vol->dim, i+1, j, k); idx_jn = volume_index (vol->dim, i, j-1, k); idx_jp = volume_index (vol->dim, i, j+1, k); idx_kn = volume_index (vol->dim, i, j, k-1); idx_kp = volume_index (vol->dim, i, j, k+1); idx_injn = volume_index (vol->dim, i-1, j-1, k); idx_injp = volume_index (vol->dim, i-1, j+1, k); idx_ipjn = volume_index (vol->dim, i+1, j-1, k); idx_ipjp = volume_index (vol->dim, i+1, j+1, k); idx_inkn = volume_index (vol->dim, i-1, j, k-1); idx_inkp = volume_index (vol->dim, i-1, j, k+1); idx_ipkn = volume_index (vol->dim, i+1, j, k-1); idx_ipkp = volume_index (vol->dim, i+1, j, k+1); idx_jnkn = volume_index (vol->dim, i, j-1, k-1); idx_jnkp = volume_index (vol->dim, i, j-1, k+1); idx_jpkn = volume_index (vol->dim, i, j+1, k-1); idx_jpkp = volume_index (vol->dim, i, j+1, k+1); /* Load vectors relevant to current POI */ vec_poi = &img[3*idx_poi]; vec_in = &img[3*idx_in]; vec_ip = &img[3*idx_ip]; vec_jn = &img[3*idx_jn]; vec_jp = &img[3*idx_jp]; vec_kn = &img[3*idx_kn]; vec_kp = &img[3*idx_kp]; vec_injn = &img[3*idx_injn]; vec_injp = &img[3*idx_injp]; vec_ipjn = &img[3*idx_ipjn]; vec_ipjp = &img[3*idx_ipjp]; vec_inkn = &img[3*idx_inkn]; vec_inkp = &img[3*idx_inkp]; vec_ipkn = &img[3*idx_ipkn]; vec_ipkp = &img[3*idx_ipkp]; vec_jnkn = &img[3*idx_jnkn]; vec_jnkp = &img[3*idx_jnkp]; vec_jpkn = &img[3*idx_jpkn]; vec_jpkp = &img[3*idx_jpkp]; /* Get stiffness */ float stiffness = 1.0; if (fsimg) { stiffness = fsimg[idx_poi]; } /* Compute components */ d2_sq = 0.0f; for (c=0; c<3; c++) { d2_dx2[c] = inv_dxdx * (vec_ip[c] - 2.0f*vec_poi[c] + vec_in[c]); d2_dy2[c] = inv_dydy * (vec_jp[c] - 2.0f*vec_poi[c] + vec_jn[c]); d2_dz2[c] = inv_dzdz * (vec_kp[c] - 2.0f*vec_poi[c] + vec_kn[c]); d2_dxdy[c] = inv_dxdy * ( vec_injn[c] - vec_injp[c] - vec_ipjn[c] + vec_ipjp[c]); d2_dxdz[c] = inv_dxdz * ( vec_inkn[c] - vec_inkp[c] - vec_ipkn[c] + vec_ipkp[c]); d2_dydz[c] = inv_dydz * ( vec_jnkn[c] - vec_jnkp[c] - vec_jpkn[c] + vec_jpkp[c]); /* Accumulate score for this component, for this voxel */ d2_sq += d2_dx2[c]*d2_dx2[c] + d2_dy2[c]*d2_dy2[c] + d2_dz2[c]*d2_dz2[c] + 2.0f * ( d2_dxdy[c]*d2_dxdy[c] + d2_dxdz[c]*d2_dxdz[c] + d2_dydz[c]*d2_dydz[c] ); /* Accumulate grad for this component, for this voxel */ dc_dv[c] = - 4 * dxdydz * inv_dxdx * d2_dx2[c] - 4 * dxdydz * inv_dydy * d2_dy2[c] - 4 * dxdydz * inv_dzdz * d2_dz2[c]; dc_dv_in[c] = 2 * dxdydz * inv_dxdx * d2_dx2[c]; dc_dv_ip[c] = 2 * dxdydz * inv_dxdx * d2_dx2[c]; dc_dv_jn[c] = 2 * dxdydz * inv_dydy * d2_dy2[c]; dc_dv_jp[c] = 2 * dxdydz * inv_dydy * d2_dy2[c]; dc_dv_kn[c] = 2 * dxdydz * inv_dzdz * d2_dz2[c]; dc_dv_kp[c] = 2 * dxdydz * inv_dzdz * d2_dz2[c]; dc_dv_injn[c] = + 4 * dxdydz * inv_dxdy * d2_dxdy[c]; dc_dv_injp[c] = - 4 * dxdydz * inv_dxdy * d2_dxdy[c]; dc_dv_ipjn[c] = - 4 * dxdydz * inv_dxdy * d2_dxdy[c]; dc_dv_ipjp[c] = + 4 * dxdydz * inv_dxdy * d2_dxdy[c]; dc_dv_inkn[c] = + 4 * dxdydz * inv_dxdz * d2_dxdz[c]; dc_dv_inkp[c] = - 4 * dxdydz * inv_dxdz * d2_dxdz[c]; dc_dv_ipkn[c] = - 4 * dxdydz * inv_dxdz * d2_dxdz[c]; dc_dv_ipkp[c] = + 4 * dxdydz * inv_dxdz * d2_dxdz[c]; dc_dv_jnkn[c] = + 4 * dxdydz * inv_dydz * d2_dydz[c]; dc_dv_jnkp[c] = - 4 * dxdydz * inv_dydz * d2_dydz[c]; dc_dv_jpkn[c] = - 4 * dxdydz * inv_dydz * d2_dydz[c]; dc_dv_jpkp[c] = + 4 * dxdydz * inv_dydz * d2_dydz[c]; /* Apply stiffness to components */ if (fsimg) { dc_dv[c] *= stiffness; dc_dv_in[c] *= stiffness; dc_dv_ip[c] *= stiffness; dc_dv_jn[c] *= stiffness; dc_dv_jp[c] *= stiffness; dc_dv_kn[c] *= stiffness; dc_dv_kp[c] *= stiffness; dc_dv_injn[c] *= stiffness; dc_dv_injp[c] *= stiffness; dc_dv_ipjn[c] *= stiffness; dc_dv_ipjp[c] *= stiffness; dc_dv_inkn[c] *= stiffness; dc_dv_inkp[c] *= stiffness; dc_dv_ipkn[c] *= stiffness; dc_dv_ipkp[c] *= stiffness; dc_dv_jnkn[c] *= stiffness; dc_dv_jnkp[c] *= stiffness; dc_dv_jpkn[c] *= stiffness; dc_dv_jpkp[c] *= stiffness; } #if defined (DEBUG) fprintf (fp[c], "(%i,%i,%i) : %15e\n", i,j,k, (d2_dxdy[c]*d2_dxdy[c])); #endif } /* Update score */ S += stiffness * d2_sq; /* Update gradient */ int pidx, qidx; pidx = get_region_index (i , j , k , bxf); qidx = get_region_offset (i , j , k , bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv); pidx = get_region_index (i-1, j , k , bxf); qidx = get_region_offset (i-1, j , k , bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_in); pidx = get_region_index (i+1, j , k , bxf); qidx = get_region_offset (i+1, j , k , bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_ip); pidx = get_region_index (i , j-1, k , bxf); qidx = get_region_offset (i , j-1, k , bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_jn); pidx = get_region_index (i , j+1, k , bxf); qidx = get_region_offset (i , j+1, k , bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_jp); pidx = get_region_index (i , j , k-1, bxf); qidx = get_region_offset (i , j , k-1, bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_kn); pidx = get_region_index (i , j , k+1, bxf); qidx = get_region_offset (i , j , k+1, bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_kp); pidx = get_region_index (i-1, j-1, k , bxf); qidx = get_region_offset (i-1, j-1, k , bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_injn); pidx = get_region_index (i-1, j+1, k , bxf); qidx = get_region_offset (i-1, j+1, k , bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_injp); pidx = get_region_index (i+1, j-1, k , bxf); qidx = get_region_offset (i+1, j-1, k , bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_ipjn); pidx = get_region_index (i+1, j+1, k , bxf); qidx = get_region_offset (i+1, j+1, k , bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_ipjp); pidx = get_region_index (i-1, j , k-1, bxf); qidx = get_region_offset (i-1, j , k-1, bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_inkn); pidx = get_region_index (i-1, j , k+1, bxf); qidx = get_region_offset (i-1, j , k+1, bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_inkp); pidx = get_region_index (i+1, j , k-1, bxf); qidx = get_region_offset (i+1, j , k-1, bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_ipkn); pidx = get_region_index (i+1, j , k+1, bxf); qidx = get_region_offset (i+1, j , k+1, bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_ipkp); pidx = get_region_index (i , j-1, k-1, bxf); qidx = get_region_offset (i , j-1, k-1, bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_jnkn); pidx = get_region_index (i , j-1, k+1, bxf); qidx = get_region_offset (i , j-1, k+1, bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_jnkp); pidx = get_region_index (i , j+1, k-1, bxf); qidx = get_region_offset (i , j+1, k-1, bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_jpkn); pidx = get_region_index (i , j+1, k+1, bxf); qidx = get_region_offset (i , j+1, k+1, bxf); bscore->update_total_grad_b (bxf, pidx, qidx, dc_dv_jpkp); } } } /* Integrate */ S *= dx*dy*dz; #if defined (DEBUG) for (i=0; i<3; i++) { fclose(fp[i]); } #endif bscore->rmetric += S; bscore->time_rmetric = timer->report (); delete timer; } void Bspline_regularize::compute_score_numeric ( Bspline_score *bscore, const Regularization_parms *parms, const Bspline_regularize *rst, const Bspline_xform* bxf) { Volume *vf = bspline_compute_vf (bxf); bscore->rmetric = 0.0; compute_score_numeric_internal (bscore, parms, rst, bxf, vf); delete vf; } void Bspline_regularize::numeric_init ( const Bspline_xform* bxf ) { } bspline_regularize_numeric.h000066400000000000000000000004721321604176500341470ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_regularize_numeric_h_ #define _bspline_regularize_numeric_h_ #endif bspline_regularize_semi_analytic.cxx000066400000000000000000000361461321604176500357100ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include "bspline_regularize.h" #include "bspline_score.h" #include "bspline_xform.h" #include "logfile.h" #include "plm_timer.h" #include "print_and_exit.h" /* Flavor 'd' */ void Bspline_regularize::create_qlut_grad ( const Bspline_xform* bxf, /* Output: bxf with new LUTs */ const float img_spacing[3], /* Image spacing (in mm) */ const plm_long vox_per_rgn[3]) /* Knot spacing (in vox) */ { plm_long i, j, k, p; int tx, ty, tz; float *A, *B, *C; float *Ax, *By, *Cz, *Axx, *Byy, *Czz; size_t q_lut_size; q_lut_size = sizeof(float) * bxf->vox_per_rgn[0] * bxf->vox_per_rgn[1] * bxf->vox_per_rgn[2] * 64; logfile_printf("Creating gradient multiplier LUTs, %d bytes each\n", q_lut_size); this->q_dxdyz_lut = (float*) malloc ( q_lut_size ); if (!this->q_dxdyz_lut) print_and_exit ("Error allocating memory for q_grad_lut\n"); this->q_xdydz_lut = (float*) malloc ( q_lut_size ); if (!this->q_xdydz_lut) print_and_exit ("Error allocating memory for q_grad_lut\n"); this->q_dxydz_lut = (float*) malloc ( q_lut_size ); if (!this->q_dxydz_lut) print_and_exit ("Error allocating memory for q_grad_lut\n"); this->q_d2xyz_lut = (float*) malloc ( q_lut_size ); if (!this->q_d2xyz_lut) print_and_exit ("Error allocating memory for q_grad_lut\n"); this->q_xd2yz_lut = (float*) malloc ( q_lut_size ); if (!this->q_xd2yz_lut) print_and_exit ("Error allocating memory for q_grad_lut\n"); this->q_xyd2z_lut = (float*) malloc ( q_lut_size ); if (!this->q_xyd2z_lut) print_and_exit ("Error allocating memory for q_grad_lut\n"); A = (float*) malloc (sizeof(float) * bxf->vox_per_rgn[0] * 4); B = (float*) malloc (sizeof(float) * bxf->vox_per_rgn[1] * 4); C = (float*) malloc (sizeof(float) * bxf->vox_per_rgn[2] * 4); Ax = (float*) malloc (sizeof(float) * bxf->vox_per_rgn[0] * 4); By = (float*) malloc (sizeof(float) * bxf->vox_per_rgn[1] * 4); Cz = (float*) malloc (sizeof(float) * bxf->vox_per_rgn[2] * 4); Axx = (float*) malloc (sizeof(float) * bxf->vox_per_rgn[0] * 4); Byy = (float*) malloc (sizeof(float) * bxf->vox_per_rgn[1] * 4); Czz = (float*) malloc (sizeof(float) * bxf->vox_per_rgn[2] * 4); for (i = 0; i < bxf->vox_per_rgn[0]; i++) { float ii = ((float) i) / bxf->vox_per_rgn[0]; float t3 = ii*ii*ii; float t2 = ii*ii; float t1 = ii; A[i*4+0] = (1.0/6.0) * (- 1.0 * t3 + 3.0 * t2 - 3.0 * t1 + 1.0); A[i*4+1] = (1.0/6.0) * (+ 3.0 * t3 - 6.0 * t2 + 4.0); A[i*4+2] = (1.0/6.0) * (- 3.0 * t3 + 3.0 * t2 + 3.0 * t1 + 1.0); A[i*4+3] = (1.0/6.0) * (+ 1.0 * t3); Ax[i*4+0] =(1.0/6.0) * (- 3.0 * t2 + 6.0 * t1 - 3.0 ); Ax[i*4+1] =(1.0/6.0) * (+ 9.0 * t2 - 12.0* t1 ); Ax[i*4+2] =(1.0/6.0) * (- 9.0 * t2 + 6.0 * t1 + 3.0 ); Ax[i*4+3] =(1.0/6.0) * (+ 3.0 * t2); Axx[i*4+0]=(1.0/6.0) * (- 6.0 * t1 + 6.0 ); Axx[i*4+1]=(1.0/6.0) * (+18.0 * t1 - 12.0 ); Axx[i*4+2]=(1.0/6.0) * (-18.0 * t1 + 6.0 ); Axx[i*4+3]=(1.0/6.0) * (+ 6.0 * t1); } for (j = 0; j < bxf->vox_per_rgn[1]; j++) { float jj = ((float) j) / bxf->vox_per_rgn[1]; float t3 = jj*jj*jj; float t2 = jj*jj; float t1 = jj; B[j*4+0] = (1.0/6.0) * (- 1.0 * t3 + 3.0 * t2 - 3.0 * t1 + 1.0); B[j*4+1] = (1.0/6.0) * (+ 3.0 * t3 - 6.0 * t2 + 4.0); B[j*4+2] = (1.0/6.0) * (- 3.0 * t3 + 3.0 * t2 + 3.0 * t1 + 1.0); B[j*4+3] = (1.0/6.0) * (+ 1.0 * t3); By[j*4+0] =(1.0/6.0) * (- 3.0 * t2 + 6.0 * t1 - 3.0 ); By[j*4+1] =(1.0/6.0) * (+ 9.0 * t2 - 12.0* t1 ); By[j*4+2] =(1.0/6.0) * (- 9.0 * t2 + 6.0 * t1 + 3.0 ); By[j*4+3] =(1.0/6.0) * (+ 3.0 * t2); Byy[j*4+0]=(1.0/6.0) * (- 6.0 * t1 + 6.0 ); Byy[j*4+1]=(1.0/6.0) * (+18.0 * t1 - 12.0 ); Byy[j*4+2]=(1.0/6.0) * (-18.0 * t1 + 6.0 ); Byy[j*4+3]=(1.0/6.0) * (+ 6.0 * t1); } for (k = 0; k < bxf->vox_per_rgn[2]; k++) { float kk = ((float) k) / bxf->vox_per_rgn[2]; float t3 = kk*kk*kk; float t2 = kk*kk; float t1 = kk; C[k*4+0] = (1.0/6.0) * (- 1.0 * t3 + 3.0 * t2 - 3.0 * t1 + 1.0); C[k*4+1] = (1.0/6.0) * (+ 3.0 * t3 - 6.0 * t2 + 4.0); C[k*4+2] = (1.0/6.0) * (- 3.0 * t3 + 3.0 * t2 + 3.0 * t1 + 1.0); C[k*4+3] = (1.0/6.0) * (+ 1.0 * t3); Cz[k*4+0] =(1.0/6.0) * (- 3.0 * t2 + 6.0 * t1 - 3.0 ); Cz[k*4+1] =(1.0/6.0) * (+ 9.0 * t2 - 12.0* t1 ); Cz[k*4+2] =(1.0/6.0) * (- 9.0 * t2 + 6.0 * t1 + 3.0 ); Cz[k*4+3] =(1.0/6.0) * (+ 3.0 * t2); Czz[k*4+0]=(1.0/6.0) * (- 6.0 * t1 + 6.0 ); Czz[k*4+1]=(1.0/6.0) * (+18.0 * t1 - 12.0 ); Czz[k*4+2]=(1.0/6.0) * (-18.0 * t1 + 6.0 ); Czz[k*4+3]=(1.0/6.0) * (+ 6.0 * t1); } p = 0; for (k = 0; k < bxf->vox_per_rgn[2]; k++) { for (j = 0; j < bxf->vox_per_rgn[1]; j++) { for (i = 0; i < bxf->vox_per_rgn[0]; i++) { for (tz = 0; tz < 4; tz++) { for (ty = 0; ty < 4; ty++) { for (tx = 0; tx < 4; tx++) { this->q_dxdyz_lut[p] = Ax[i*4+tx] * By[j*4+ty] * C[k*4+tz]; this->q_xdydz_lut[p] = A[i*4+tx] * By[j*4+ty] * Cz[k*4+tz]; this->q_dxydz_lut[p] = Ax[i*4+tx] * B[j*4+ty] * Cz[k*4+tz]; this->q_d2xyz_lut[p] = Axx[i*4+tx] * B[j*4+ty] * C[k*4+tz]; this->q_xd2yz_lut[p] = A[i*4+tx] * Byy[j*4+ty] * C[k*4+tz]; this->q_xyd2z_lut[p] = A[i*4+tx] * B[j*4+ty] * Czz[k*4+tz]; p++; } } } } } } free (C); free (B); free (A); free (Ax); free(By); free(Cz); free(Axx); free(Byy); free(Czz); } #define USE_FAST_CODE 1 /*internal use only - get k-th component (k=0,1,2) of the vector field at location r using pre-rendered vf */ static float f2 (int k, int r[3], float *vf, int *dims) { int d; d = r[2] * dims[0] * dims[1] + r[1] * dims[0] + r[0]; return vf[3*d+k]; } /* first derivative of the vector field du_i/dx_i using pre-rendered vf calculated at position r[3] = (ri rj rk) in voxels */ float bspline_regularize_1st_derivative ( int i, int r[3], float h[3], float *vf, int *dims ) { int r1[3], r2[3]; int d; for(d=0; d<3; d++) { r1[d]=r[d]; r2[d]=r[d]; } r1[i] ++; r2[i] --; return (f2(i,r1, vf, dims)-f2(i,r2, vf, dims))/(2.*h[i]); } /* second derivative of k-th component of vector field wrt x_i and x_j, d2u_k/(dx_i dx_j) calculated at position r[3] = (ri rj rk) in voxels using pre-rendered vf */ float bspline_regularize_2nd_derivative ( int k, int i, int j, int r[3], float h[3], float *vf, int *dims ) { int r1[3], r2[3], r3[3], r4[3], r5[3], r6[3]; int d; if (i==j) { for(d=0; d<3; d++) { r1[d]=r[d]; r2[d]=r[d]; } r1[i] ++; r2[i] --; return ( f2(k, r1, vf, dims) + f2(k, r2, vf, dims) - 2*f2(k, r, vf, dims ) ) / (h[i]*h[i]); } else { for(d=0; d<3; d++) { r1[d]=r[d]; r2[d]=r[d]; r3[d]=r[d]; r4[d]=r[d]; r5[d]=r[d]; r6[d]=r[d]; } /* voxel not used*/ r1[j]++; r2[j]++; r2[i]++; r3[i]--; /* r[] */ r4[i]++; r5[i]--; r5[j]--; r6[j]--; /*voxel not used */ return ( -f2(k,r1,vf, dims)+f2(k,r2,vf,dims)-f2(k,r3,vf,dims) +2*f2(k,r,vf,dims) -f2(k,r4,vf, dims)+f2(k,r5,vf,dims)-f2(k,r6,vf,dims))/(2.*h[i]*h[j]); } } /* out[i] = 2nd derivative of i-th component (i=0,1,2<->x,y,z) of the vector field with respect to variables derive1 and derive2 (0,1,2<->x,y,z), or (derive1,derive2)th element of the Hessian of the i-th component of the vector field */ void Bspline_regularize::hessian_component ( float out[3], const Bspline_xform* bxf, plm_long p[3], plm_long qidx, int derive1, int derive2 ) { int i, j, k, m; int cidx; float* q_lut = 0; if (derive1==0 && derive2==0) q_lut = &this->q_d2xyz_lut[qidx*64]; if (derive1==1 && derive2==1) q_lut = &this->q_xd2yz_lut[qidx*64]; if (derive1==2 && derive2==2) q_lut = &this->q_xyd2z_lut[qidx*64]; if (derive1==0 && derive2==1) q_lut = &this->q_dxdyz_lut[qidx*64]; if (derive1==1 && derive2==0) q_lut = &this->q_dxdyz_lut[qidx*64]; if (derive1==0 && derive2==2) q_lut = &this->q_dxydz_lut[qidx*64]; if (derive1==2 && derive2==0) q_lut = &this->q_dxydz_lut[qidx*64]; if (derive1==1 && derive2==2) q_lut = &this->q_xdydz_lut[qidx*64]; if (derive1==2 && derive2==1) q_lut = &this->q_xdydz_lut[qidx*64]; out[0] = out[1] = out[2] = 0; m = 0; for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cidx = (p[2] + k) * bxf->cdims[1] * bxf->cdims[0] + (p[1] + j) * bxf->cdims[0] + (p[0] + i); cidx = cidx * 3; out[0] += q_lut[m] * bxf->coeff[cidx+0] ; out[1] += q_lut[m] * bxf->coeff[cidx+1] ; out[2] += q_lut[m] * bxf->coeff[cidx+2] ; m ++; } } } } void bspline_regularize_hessian_component_b ( float out[3], const Bspline_xform* bxf, plm_long p[3], plm_long qidx, float *q_lut ) { int i, j, k, m; int cidx; out[0] = out[1] = out[2] = 0; m = 0; for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cidx = (p[2] + k) * bxf->cdims[1] * bxf->cdims[0] + (p[1] + j) * bxf->cdims[0] + (p[0] + i); cidx = cidx * 3; out[0] += q_lut[m] * bxf->coeff[cidx+0]; out[1] += q_lut[m] * bxf->coeff[cidx+1]; out[2] += q_lut[m] * bxf->coeff[cidx+2]; m ++; } } } } void Bspline_regularize::hessian_update_grad ( Bspline_score *bscore, const Bspline_xform* bxf, plm_long p[3], plm_long qidx, float dc_dv[3], int derive1, int derive2) { int i, j, k, m; int cidx; float* q_lut = 0; if (derive1==0 && derive2==0) q_lut = &this->q_d2xyz_lut[qidx*64]; if (derive1==1 && derive2==1) q_lut = &this->q_xd2yz_lut[qidx*64]; if (derive1==2 && derive2==2) q_lut = &this->q_xyd2z_lut[qidx*64]; if (derive1==0 && derive2==1) q_lut = &this->q_dxdyz_lut[qidx*64]; if (derive1==1 && derive2==0) q_lut = &this->q_dxdyz_lut[qidx*64]; if (derive1==0 && derive2==2) q_lut = &this->q_dxydz_lut[qidx*64]; if (derive1==2 && derive2==0) q_lut = &this->q_dxydz_lut[qidx*64]; if (derive1==1 && derive2==2) q_lut = &this->q_xdydz_lut[qidx*64]; if (derive1==2 && derive2==1) q_lut = &this->q_xdydz_lut[qidx*64]; m = 0; for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cidx = (p[2] + k) * bxf->cdims[1] * bxf->cdims[0] + (p[1] + j) * bxf->cdims[0] + (p[0] + i); cidx = cidx * 3; bscore->total_grad[cidx+0] += dc_dv[0] * q_lut[m]; bscore->total_grad[cidx+1] += dc_dv[1] * q_lut[m]; bscore->total_grad[cidx+2] += dc_dv[2] * q_lut[m]; m ++; } } } } void bspline_regularize_hessian_update_grad_b ( Bspline_score *bscore, const Bspline_xform* bxf, plm_long p[3], plm_long qidx, float dc_dv[3], float *q_lut ) { int i, j, k, m; int cidx; m = 0; for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cidx = (p[2] + k) * bxf->cdims[1] * bxf->cdims[0] + (p[1] + j) * bxf->cdims[0] + (p[0] + i); cidx = cidx * 3; bscore->total_grad[cidx+0] += dc_dv[0] * q_lut[m]; bscore->total_grad[cidx+1] += dc_dv[1] * q_lut[m]; bscore->total_grad[cidx+2] += dc_dv[2] * q_lut[m]; m ++; } } } } #if defined (USE_FAST_CODE) static double update_score_and_grad ( Bspline_score *bscore, const Bspline_xform* bxf, plm_long p[3], plm_long qidx, float grad_coeff, float weight, // 2 or 1 for cross/non-cross derivatives float *qlut ) { int d3; float dxyz[3]; float dc_dv[3]; double score = 0.0; bspline_regularize_hessian_component_b (dxyz, bxf, p, qidx, qlut); for (d3=0; d3<3; d3++) { score += weight * (dxyz[d3]*dxyz[d3]); dc_dv[d3] = weight * grad_coeff * dxyz[d3]; } bspline_regularize_hessian_update_grad_b (bscore, bxf, p, qidx, dc_dv, qlut); return score; } #endif void Bspline_regularize::compute_score_semi_analytic ( Bspline_score *bscore, const Regularization_parms *parms, const Bspline_regularize *rst, const Bspline_xform* bxf ) { double grad_score; plm_long ri, rj, rk; plm_long fi, fj, fk; plm_long p[3]; plm_long q[3]; plm_long qidx; plm_long num_vox; //double interval; float grad_coeff; //float raw_score; grad_score = 0; num_vox = bxf->roi_dim[0] * bxf->roi_dim[1] * bxf->roi_dim[2]; grad_coeff = parms->lambda / num_vox; Plm_timer* timer = new Plm_timer; timer->start (); bscore->rmetric = 0.; //printf("---- YOUNG MODULUS %f\n", parms->lambda); for (rk = 0, fk = bxf->roi_offset[2]; rk < bxf->roi_dim[2]; rk++, fk++) { p[2] = rk / bxf->vox_per_rgn[2]; q[2] = rk % bxf->vox_per_rgn[2]; for (rj = 0, fj = bxf->roi_offset[1]; rj < bxf->roi_dim[1]; rj++, fj++) { p[1] = rj / bxf->vox_per_rgn[1]; q[1] = rj % bxf->vox_per_rgn[1]; for (ri = 0, fi = bxf->roi_offset[0]; ri < bxf->roi_dim[0]; ri++, fi++) { p[0] = ri / bxf->vox_per_rgn[0]; q[0] = ri % bxf->vox_per_rgn[0]; qidx = volume_index (bxf->vox_per_rgn, q); #if defined (USE_FAST_CODE) grad_score += update_score_and_grad ( bscore, bxf, p, qidx, grad_coeff, 1, &this->q_d2xyz_lut[qidx*64]); grad_score += update_score_and_grad ( bscore, bxf, p, qidx, grad_coeff, 1, &this->q_xd2yz_lut[qidx*64]); grad_score += update_score_and_grad ( bscore, bxf, p, qidx, grad_coeff, 1, &this->q_xyd2z_lut[qidx*64]); grad_score += update_score_and_grad ( bscore, bxf, p, qidx, grad_coeff, 2, &this->q_dxdyz_lut[qidx*64]); grad_score += update_score_and_grad ( bscore, bxf, p, qidx, grad_coeff, 2, &this->q_dxydz_lut[qidx*64]); grad_score += update_score_and_grad ( bscore, bxf, p, qidx, grad_coeff, 2, &this->q_xdydz_lut[qidx*64]); #else for (int d1=0;d1<3;d1++) { for (int d2=d1;d2<3;d2++) { //six different components only float dxyz[3]; float dc_dv[3]; bspline_regularize_hessian_component ( dxyz, bxf, p, qidx, d1, d2); /* Note: dxyz[i] = du_i/(dx_d1 dx_d2) */ float weight; if (d1!=d2) weight = 2 ; else weight = 1; for (int d3=0;d3<3;d3++) { grad_score += weight*(dxyz[d3]*dxyz[d3]); } dc_dv[0] = weight * grad_coeff * dxyz[0]; dc_dv[1] = weight * grad_coeff * dxyz[1]; dc_dv[2] = weight * grad_coeff * dxyz[2]; bspline_regularize_hessian_update_grad ( bscore, bxf, p, qidx, dc_dv, d1, d2); } } #endif } } bscore->time_rmetric = timer->report (); //raw_score = grad_score / num_vox; grad_score *= (parms->lambda / num_vox); //printf (" GRAD_COST %.4f RAW_GRAD %.4f [%.3f secs]\n", grad_score, raw_score, interval); bscore->rmetric += grad_score; } //printf ("SCORE=%.4f\n", bscore->score); delete timer; } void Bspline_regularize::semi_analytic_init ( const Bspline_xform* bxf ) { this->create_qlut_grad (bxf, bxf->img_spacing, bxf->vox_per_rgn); } bspline_score.cxx000066400000000000000000000076641321604176500317540ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "bspline_score.h" #include "bspline_xform.h" Bspline_score::Bspline_score () { this->total_score = 0; this->total_grad = 0; this->lmetric = 0; this->rmetric = 0; this->num_coeff = 0; this->curr_num_vox = 0; this->curr_smetric = 0; this->curr_smetric_grad = 0; this->time_rmetric = 0; } Bspline_score::~Bspline_score () { delete[] curr_smetric_grad; delete[] total_grad; } void Bspline_score::set_num_coeff (plm_long num_coeff) { this->num_coeff = num_coeff; delete[] this->curr_smetric_grad; delete[] this->total_grad; this->curr_smetric_grad = new float[num_coeff]; this->total_grad = new float[num_coeff]; } void Bspline_score::reset_smetric_grad () { memset (this->curr_smetric_grad, 0, this->num_coeff * sizeof(float)); } void Bspline_score::reset_score () { this->total_score = 0; memset (this->total_grad, 0, this->num_coeff * sizeof(float)); this->lmetric = 0; this->rmetric = 0; this->metric_record.clear(); this->curr_num_vox = 0; this->curr_smetric = 0; memset (this->curr_smetric_grad, 0, this->num_coeff * sizeof(float)); this->time_rmetric = 0; } void Bspline_score::accumulate (float lambda) { this->total_score += lambda * this->curr_smetric; for (plm_long i = 0; i < this->num_coeff; i++) { this->total_grad[i] += lambda * this->curr_smetric_grad[i]; } this->curr_smetric = 0; this->curr_num_vox = 0; this->reset_smetric_grad (); } void Bspline_score::update_smetric_grad ( const Bspline_xform* bxf, const plm_long p[3], plm_long qidx, const float dc_dv[3]) { this->update_grad (this->curr_smetric_grad, bxf, p, qidx, dc_dv); } void Bspline_score::update_total_grad ( const Bspline_xform* bxf, const plm_long p[3], plm_long qidx, const float dc_dv[3]) { this->update_grad (this->total_grad, bxf, p, qidx, dc_dv); } void Bspline_score::update_smetric_grad_b ( const Bspline_xform* bxf, plm_long pidx, plm_long qidx, const float dc_dv[3]) { this->update_grad_b (this->curr_smetric_grad, bxf, pidx, qidx, dc_dv); } void Bspline_score::update_total_grad_b ( const Bspline_xform* bxf, plm_long pidx, plm_long qidx, const float dc_dv[3]) { this->update_grad_b (this->total_grad, bxf, pidx, qidx, dc_dv); } void Bspline_score::update_grad ( float *grad, const Bspline_xform* bxf, const plm_long p[3], plm_long qidx, const float dc_dv[3]) { plm_long i, j, k, m; plm_long cidx; float* q_lut = &bxf->q_lut[qidx*64]; m = 0; for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cidx = (p[2] + k) * bxf->cdims[1] * bxf->cdims[0] + (p[1] + j) * bxf->cdims[0] + (p[0] + i); cidx = cidx * 3; grad[cidx+0] += dc_dv[0] * q_lut[m]; grad[cidx+1] += dc_dv[1] * q_lut[m]; grad[cidx+2] += dc_dv[2] * q_lut[m]; m ++; } } } } void Bspline_score::update_grad_b ( float *grad, const Bspline_xform* bxf, plm_long pidx, plm_long qidx, const float dc_dv[3]) { plm_long i, j, k, m; plm_long cidx; float* q_lut = &bxf->q_lut[qidx*64]; plm_long* c_lut = &bxf->c_lut[pidx*64]; m = 0; for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cidx = 3 * c_lut[m]; grad[cidx+0] += dc_dv[0] * q_lut[m]; grad[cidx+1] += dc_dv[1] * q_lut[m]; grad[cidx+2] += dc_dv[2] * q_lut[m]; m ++; } } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_score.h000066400000000000000000000051651321604176500314520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_score_h_ #define _bspline_score_h_ #include "plmregister_config.h" #include #include "plm_int.h" class Bspline_xform; class PLMREGISTER_API Metric_score { public: Metric_score () { score = 0.f; time = 0.f; num_vox = 0; } Metric_score (float score, float time, plm_long num_vox) : score(score), time(time), num_vox(num_vox) { score = 0.f; time = 0.f; num_vox = 0; } public: float score; double time; plm_long num_vox; }; class PLMREGISTER_API Bspline_score { public: Bspline_score (); ~Bspline_score (); public: float total_score; /* Total Score (sent to optimizer) */ float* total_grad; /* Total cost function gradient */ float lmetric; /* Landmark metric */ float rmetric; /* Regularization metric */ /*! \brief The metric_record keeps track of score statistics for reporting purposes */ std::vector metric_record; plm_long num_coeff; /* Size of gradient vector = num coefficents */ float curr_smetric; /* Current smetric value */ float* curr_smetric_grad; /* Gradient of score for current smetric */ plm_long curr_num_vox; /* Number of voxel with correspondence */ /* Time to compute regularization metric */ double time_rmetric; public: void set_num_coeff (plm_long num_coeff); void reset_smetric_grad (); void reset_score (); void accumulate (float lambda); void update_smetric_grad ( const Bspline_xform* bxf, const plm_long p[3], plm_long qidx, const float dc_dv[3]); void update_total_grad ( const Bspline_xform* bxf, const plm_long p[3], plm_long qidx, const float dc_dv[3]); void update_smetric_grad_b ( const Bspline_xform* bxf, plm_long pidx, plm_long qidx, const float dc_dv[3]); void update_total_grad_b ( const Bspline_xform* bxf, plm_long pidx, plm_long qidx, const float dc_dv[3]); protected: void update_grad ( float *grad, const Bspline_xform* bxf, const plm_long p[3], plm_long qidx, const float dc_dv[3]); void update_grad_b ( float *grad, const Bspline_xform *bxf, plm_long pidx, plm_long qidx, const float dc_dv[3]); }; #endif bspline_stage.cxx000066400000000000000000000266231321604176500317400ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include "bspline.h" #include "bspline_interpolate.h" #include "bspline_landmarks.h" #include "bspline_optimize.h" #include "bspline_regularize.h" #include "bspline_parms.h" #include "bspline_stage.h" #include "bspline_xform.h" #include "logfile.h" #include "mha_io.h" #include "plm_image_header.h" #include "plm_image.h" #include "plm_math.h" #include "print_and_exit.h" #include "registration_data.h" #include "registration_parms.h" #include "registration_resample.h" #include "shared_parms.h" #include "stage_parms.h" #include "string_util.h" #include "volume.h" #include "volume_grad.h" #include "volume_header.h" #include "volume_resample.h" #include "xform.h" class Bspline_stage_private { public: Registration_data *regd; const Stage_parms *stage; Xform *xf_in; Xform::Pointer xf_out; Bspline_parms parms; Bspline_optimize bod; Volume::Pointer f_stiffness_ss; public: Bspline_stage_private () { xf_out = Xform::New (); } }; Bspline_stage::Bspline_stage ( Registration_data *regd, const Stage_parms *stage, Xform *xf_in) { d_ptr = new Bspline_stage_private; d_ptr->regd = regd; d_ptr->stage = stage; d_ptr->xf_in = xf_in; initialize (); } Bspline_stage::~Bspline_stage () { this->cleanup (); delete d_ptr; } static void update_roi (Volume::Pointer& roi, Volume::Pointer& image, float min_val, float max_val, bool fill_empty_roi) { plm_long p=0; float* image_temp = (float*)image->img; unsigned char* roi_temp = roi->get_raw (); for (unsigned int i=0; i < roi->dim[2]; i++) { for (unsigned int j=0; j < roi->dim[1]; j++) { for (unsigned int k=0; k < roi->dim[0]; k++) { if (fill_empty_roi && (image_temp[p]>=min_val && image_temp[p]<=max_val)) { roi_temp[p]=(unsigned char)1; } else if ((image_temp[p]max_val) && roi_temp[p]>0) { roi_temp[p]=(unsigned char)0; } p++; } } } } void Bspline_stage::run_stage () { /* Run bspline optimization */ d_ptr->bod.optimize (); } void Bspline_stage::initialize () { Registration_data *regd = d_ptr->regd; const Stage_parms *stage = d_ptr->stage; const Shared_parms *shared = d_ptr->stage->get_shared_parms(); Xform *xf_in = d_ptr->xf_in; Xform *xf_out = d_ptr->xf_out.get(); Bspline_optimize *bod = &d_ptr->bod; Bspline_parms *parms = &d_ptr->parms; Bspline_state *bst = bod->get_bspline_state (); /* Tell bod what parameters to use */ d_ptr->bod.set_bspline_parms (parms); /* Set up metric state */ populate_similarity_list (bst->similarity_data, regd, stage); /* Transform input xform to bspline and give to bod */ Plm_image_header pih; pih.set (bst->similarity_data.front()->fixed_ss); xform_to_gpuit_bsp (xf_out, xf_in, &pih, stage->grid_spac); Bspline_xform *bxf = xf_out->get_gpuit_bsp(); d_ptr->bod.set_bspline_xform (bxf); /* Set roi's */ Volume::Pointer m_roi; Volume::Pointer f_roi; if (shared->fixed_roi_enable && regd->get_fixed_roi()) { f_roi = regd->get_fixed_roi()->get_volume_uchar(); } if (shared->moving_roi_enable && regd->get_moving_roi()) { m_roi = regd->get_moving_roi()->get_volume_uchar(); } /* Copy parameters from stage_parms to bspline_parms */ parms->mi_fixed_image_minVal = stage->mi_fixed_image_minVal; parms->mi_fixed_image_maxVal = stage->mi_fixed_image_maxVal; parms->mi_moving_image_minVal = stage->mi_moving_image_minVal; parms->mi_moving_image_maxVal = stage->mi_moving_image_maxVal; /* GCS FIX BEGIN */ /* BSpline code needs work to support multi-planar imaging until that is done, this should maintain the old behavior */ Volume::Pointer fixed = regd->get_fixed_image()->get_volume_float(); Volume::Pointer moving = regd->get_moving_image()->get_volume_float(); // Check if min/max values for moving image are set (correctly) if ((parms->mi_moving_image_minVal!=0 || parms->mi_moving_image_maxVal!=0) && (parms->mi_moving_image_minVal < parms->mi_moving_image_maxVal)) { bool fill=!m_roi; // create new moving roi if not available if (!m_roi) { m_roi = Volume::New (); m_roi->create (moving->dim, moving->origin, moving->spacing, moving->direction_cosines, PT_UCHAR); } // Modify fixed roi according to min and max values for moving image update_roi (m_roi, moving, parms->mi_moving_image_minVal, parms->mi_moving_image_maxVal,fill); } // Check if min/max values for fixed image are set (correctly) if ((parms->mi_fixed_image_minVal!=0 || parms->mi_fixed_image_maxVal!=0) && (parms->mi_fixed_image_minVal < parms->mi_fixed_image_maxVal)) { bool fill=!f_roi; // create new fixed roi if not available if (!f_roi) { f_roi = Volume::New (); f_roi->create (fixed->dim, fixed->origin, fixed->spacing, fixed->direction_cosines, PT_UCHAR); } // Modify fixed roi according to min and max values for fixed image update_roi (f_roi, fixed, parms->mi_fixed_image_minVal, parms->mi_fixed_image_maxVal, fill); } /* Subsample rois (if we are using them) */ if (m_roi) { Volume::Pointer m_roi_ss = volume_subsample_vox_legacy_nn ( m_roi, stage->resample_rate_moving); bst->similarity_data.front()->moving_roi = m_roi_ss; } if (f_roi) { Volume::Pointer f_roi_ss = volume_subsample_vox_legacy_nn ( f_roi, stage->resample_rate_fixed); bst->similarity_data.front()->fixed_roi = f_roi_ss; } /* GCS FIX END */ /* Subsample stiffness */ if (shared->fixed_stiffness_enable && regd->fixed_stiffness) { Volume::Pointer& stiffness = regd->fixed_stiffness->get_volume_float (); d_ptr->f_stiffness_ss = registration_resample_volume ( stiffness, stage, stage->resample_rate_fixed); } /* Stiffness image */ if (d_ptr->f_stiffness_ss) { parms->fixed_stiffness = d_ptr->f_stiffness_ss.get(); } /* Optimization */ if (stage->optim_type == OPTIMIZATION_STEEPEST) { parms->optimization = BOPT_STEEPEST; } else if (stage->optim_type == OPTIMIZATION_LIBLBFGS) { parms->optimization = BOPT_LIBLBFGS; } else { parms->optimization = BOPT_LBFGSB; } parms->lbfgsb_pgtol = stage->pgtol; parms->lbfgsb_mmax = stage->lbfgsb_mmax; /* Threading */ switch (stage->threading_type) { case THREADING_CPU_SINGLE: if (stage->alg_flavor == 0) { parms->implementation = 'h'; } else { parms->implementation = stage->alg_flavor; } parms->threading = BTHR_CPU; break; case THREADING_CPU_OPENMP: if (stage->alg_flavor == 0) { parms->implementation = 'g'; } else { parms->implementation = stage->alg_flavor; } parms->threading = BTHR_CPU; break; case THREADING_CUDA: if (stage->alg_flavor == 0) { parms->implementation = 'j'; } else { parms->implementation = stage->alg_flavor; } parms->threading = BTHR_CUDA; break; default: print_and_exit ("Undefined impl type in gpuit_bspline\n"); } logfile_printf ("Algorithm flavor = %c\n", parms->implementation); logfile_printf ("Threading = %d\n", parms->threading); if (stage->threading_type == THREADING_CUDA) { parms->gpuid = stage->gpuid; logfile_printf ("GPU ID = %d\n", parms->gpuid); } /* Regularization */ parms->reg_parms->lambda = stage->regularization_lambda; switch (stage->regularization_type) { case REGULARIZATION_NONE: parms->reg_parms->lambda = 0.0f; break; case REGULARIZATION_BSPLINE_ANALYTIC: if (stage->threading_type == THREADING_CPU_OPENMP) { parms->reg_parms->implementation = 'c'; } else { parms->reg_parms->implementation = 'b'; } break; case REGULARIZATION_BSPLINE_SEMI_ANALYTIC: parms->reg_parms->implementation = 'd'; break; case REGULARIZATION_BSPLINE_NUMERIC: parms->reg_parms->implementation = 'a'; break; default: print_and_exit ("Undefined regularization type in gpuit_bspline\n"); } if (stage->regularization_lambda != 0) { parms->reg_parms->lambda = stage->regularization_lambda; } logfile_printf ("Regularization: flavor = %c lambda = %f\n", parms->reg_parms->implementation, parms->reg_parms->lambda); /* Mutual information histograms */ parms->mi_hist_type = stage->mi_hist_type; parms->mi_hist_fixed_bins = stage->mi_hist_fixed_bins; parms->mi_hist_moving_bins = stage->mi_hist_moving_bins; /* Other stuff */ parms->min_its = stage->min_its; parms->max_its = stage->max_its; parms->max_feval = stage->max_its; parms->convergence_tol = stage->convergence_tol; /* Landmarks */ if (regd->fixed_landmarks && regd->moving_landmarks) { logfile_printf ("Landmarks: %d fixed, %d moving, lambda = %f\n", regd->fixed_landmarks->get_count(), regd->moving_landmarks->get_count(), stage->landmark_stiffness); parms->blm->set_landmarks (regd->fixed_landmarks, regd->moving_landmarks); parms->blm->landmark_implementation = stage->landmark_flavor; parms->blm->landmark_stiffness = stage->landmark_stiffness; } /* Set debugging directory */ if (stage->debug_dir != "") { parms->debug = 1; parms->debug_dir = stage->debug_dir; parms->debug_stage = stage->stage_no; logfile_printf ("Set debug directory to %s (%d)\n", parms->debug_dir.c_str(), parms->debug_stage); /* Write fixed, moving, moving_grad */ std::string fn; fn = string_format ("%s/%02d/fixed.mha", parms->debug_dir.c_str(), parms->debug_stage); write_mha (fn.c_str(), bst->similarity_data.front()->fixed_ss.get()); fn = string_format ("%s/%02d/moving.mha", parms->debug_dir.c_str(), parms->debug_stage); write_mha (fn.c_str(), bst->similarity_data.front()->moving_ss.get()); fn = string_format ("%s/%02d/moving_grad.mha", parms->debug_dir.c_str(), parms->debug_stage); write_mha (fn.c_str(), bst->similarity_data.front()->moving_grad.get()); } } void Bspline_stage::cleanup () { } Xform::Pointer do_gpuit_bspline_stage ( Registration_data* regd, const Xform::Pointer& xf_in, const Stage_parms* stage) { Xform::Pointer xf_out = Xform::New (); Bspline_stage pb (regd, stage, xf_in.get()); pb.run_stage (); xf_out = pb.d_ptr->xf_out; return xf_out; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_stage.h000066400000000000000000000016111321604176500314320ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_stage_h_ #define _bspline_stage_h_ #include "plmregister_config.h" #include "xform.h" class Bspline_stage_private; class Registration_parms; class Registration_data; class Stage_parms; class Volume; class PLMREGISTER_API Bspline_stage { public: Bspline_stage_private *d_ptr; public: Bspline_stage ( Registration_data *regd, const Stage_parms *stage, Xform *xf_in); ~Bspline_stage (); public: void run_stage (); protected: void initialize (); void cleanup (); }; Xform::Pointer do_gpuit_bspline_stage ( Registration_data* regd, const Xform::Pointer& xf_in, const Stage_parms* stage); #endif bspline_state.cxx000066400000000000000000000203141321604176500317440ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #ifndef _WIN32 #include #endif #include "bspline.h" #if (CUDA_FOUND) #include "bspline_cuda.h" #include "cuda_util.h" #endif #include "bspline_interpolate.h" #include "bspline_landmarks.h" #include "bspline_mi.h" #include "bspline_mse.h" #include "bspline_parms.h" #include "bspline_regularize.h" #include "bspline_state.h" #include "bspline_xform.h" #include "delayload.h" #include "file_util.h" #include "interpolate_macros.h" #include "joint_histogram.h" #include "logfile.h" #include "plm_math.h" #include "string_util.h" #include "similarity_metric_type.h" #include "volume.h" #include "volume_macros.h" static void bspline_cuda_state_create ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform* bxf ); static void bspline_cuda_state_destroy ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform* bxf ); class Bspline_state_private { public: Bspline_parms *parms; Bspline_xform *bxf; public: Bspline_state_private () { parms = 0; bxf = 0; } ~Bspline_state_private () { /* Members not owned by this class */ } }; Bspline_state::Bspline_state () { d_ptr = new Bspline_state_private; mi_hist = 0; } Bspline_state::~Bspline_state () { bspline_cuda_state_destroy (d_ptr->parms, this, d_ptr->bxf); delete d_ptr; } void Bspline_state::initialize ( Bspline_xform *bxf, Bspline_parms *parms) { Regularization_parms* reg_parms = parms->reg_parms; Bspline_regularize* rst = &this->rst; Bspline_landmarks* blm = parms->blm; d_ptr->bxf = bxf; d_ptr->parms = parms; this->sm = 0; this->it = 0; this->feval = 0; this->dev_ptrs = 0; this->mi_hist = 0; this->ssd.set_num_coeff (bxf->num_coeff); if (reg_parms->lambda > 0.0f) { rst->fixed_stiffness = parms->fixed_stiffness; rst->initialize (reg_parms, bxf); } /* Initialize MI histograms */ printf (">> Checking JH allocation\n"); std::list::const_iterator it; for (it = this->similarity_data.begin(); it != this->similarity_data.end(); ++it) { const Metric_state::Pointer& ms = *it; if (ms->metric_type == SIMILARITY_METRIC_MI_MATTES) { printf (">> Performing JH allocation\n"); ms->mi_hist = new Joint_histogram ( parms->mi_hist_type, parms->mi_hist_fixed_bins, parms->mi_hist_moving_bins); } } /* Landmarks */ blm->initialize (bxf); } void Bspline_state::initialize_similarity_images () { /* GCS FIX: The below function also does other initializations which do not require the similarity images, and therefore could be done once per stage rather than once per image */ /* Copy images into CUDA memory */ bspline_cuda_state_create (d_ptr->parms, this, d_ptr->bxf); } void Bspline_state::initialize_mi_histograms () { std::list::const_iterator it; for (it = this->similarity_data.begin(); it != this->similarity_data.end(); ++it) { const Metric_state::Pointer& ms = *it; if (ms->metric_type == SIMILARITY_METRIC_MI_MATTES) { printf (">> Performing JH initialization\n"); ms->mi_hist->initialize ( ms->fixed_ss.get(), ms->moving_ss.get()); } } } void Bspline_state::set_metric_state (const Metric_state::Pointer& ms) { this->fixed = ms->fixed_ss.get(); this->moving = ms->moving_ss.get(); this->moving_grad = ms->moving_grad.get(); this->fixed_roi = ms->fixed_roi.get(); this->moving_roi = ms->moving_roi.get(); this->mi_hist = ms->mi_hist; } static void bspline_cuda_state_create ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform *bxf ) { #if (CUDA_FOUND) if (parms->threading != BTHR_CUDA) { return; } if (bst->dev_ptrs) { bspline_cuda_state_destroy (parms, bst, bxf); } /* Set the gpuid */ LOAD_LIBRARY_SAFE (libplmcuda); LOAD_SYMBOL (CUDA_selectgpu, libplmcuda); CUDA_selectgpu (parms->gpuid); UNLOAD_LIBRARY (libplmcuda); Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *moving_grad = bst->moving_grad; Dev_Pointers_Bspline* dev_ptrs = (Dev_Pointers_Bspline*) malloc (sizeof (Dev_Pointers_Bspline)); bst->dev_ptrs = dev_ptrs; /* GCS FIX: You cannot have more than one CUDA metric because dev_ptrs is not defined per metric */ if (bst->has_metric_type (SIMILARITY_METRIC_MSE)) { /* Be sure we loaded the CUDA plugin */ LOAD_LIBRARY_SAFE (libplmregistercuda); LOAD_SYMBOL (CUDA_bspline_mse_init_j, libplmregistercuda); switch (parms->implementation) { case 'j': case '\0': /* Default */ CUDA_bspline_mse_init_j (dev_ptrs, fixed, moving, moving_grad, bxf, parms); break; default: printf ("Warning: option -f %c unavailble. Switching to -f j\n", parms->implementation); CUDA_bspline_mse_init_j (dev_ptrs, fixed, moving, moving_grad, bxf, parms); break; } UNLOAD_LIBRARY (libplmregistercuda); } else if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) { /* Be sure we loaded the CUDA plugin */ LOAD_LIBRARY_SAFE (libplmregistercuda); LOAD_SYMBOL (CUDA_bspline_mi_init_a, libplmregistercuda); switch (parms->implementation) { case 'a': CUDA_bspline_mi_init_a (bxf, bst, dev_ptrs, fixed, moving, moving_grad); break; default: printf ("Warning: option -f %c unavailble. Defaulting to -f a\n", parms->implementation); CUDA_bspline_mi_init_a (bxf, bst, dev_ptrs, fixed, moving, moving_grad); break; } UNLOAD_LIBRARY (libplmregistercuda); } else { printf ("No cuda initialization performed.\n"); } #endif } static void bspline_cuda_state_destroy ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform *bxf ) { #if (CUDA_FOUND) if (parms->threading != BTHR_CUDA) { return; } Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *moving_grad = bst->moving_grad; if (bst->has_metric_type (SIMILARITY_METRIC_MSE)) { LOAD_LIBRARY_SAFE (libplmregistercuda); LOAD_SYMBOL (CUDA_bspline_mse_cleanup_j, libplmregistercuda); CUDA_bspline_mse_cleanup_j ((Dev_Pointers_Bspline *) bst->dev_ptrs, fixed, moving, moving_grad); UNLOAD_LIBRARY (libplmregistercuda); } else if (bst->has_metric_type (SIMILARITY_METRIC_MI_MATTES)) { LOAD_LIBRARY_SAFE (libplmregistercuda); LOAD_SYMBOL (CUDA_bspline_mi_cleanup_a, libplmregistercuda); CUDA_bspline_mi_cleanup_a ((Dev_Pointers_Bspline *) bst->dev_ptrs, fixed, moving, moving_grad); UNLOAD_LIBRARY (libplmregistercuda); } free (bst->dev_ptrs); bst->dev_ptrs = 0; #endif } bool Bspline_state::has_metric_type (Similarity_metric_type metric_type) { std::list::iterator it; for (it = this->similarity_data.begin(); it != this->similarity_data.end(); ++it) { if ((*it)->metric_type == metric_type) { return true; } } return false; } void Bspline_state::log_metric () { printf ("BST METRICS\n"); std::list::iterator it; for (it = this->similarity_data.begin(); it != this->similarity_data.end(); ++it) { printf ("MET %c%c%c%c%c%c %s %f\n", (*it)->fixed_ss ? '1' : '0', (*it)->moving_ss ? '1' : '0', (*it)->fixed_grad ? '1' : '0', (*it)->moving_grad ? '1' : '0', (*it)->fixed_roi ? '1' : '0', (*it)->moving_roi ? '1' : '0', (*it)->metric_string(), (*it)->metric_lambda ); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/bspline_state.h000066400000000000000000000037141321604176500314550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_state_h_ #define _bspline_state_h_ #include "plmregister_config.h" #include #include #include "bspline_regularize.h" #include "bspline_score.h" #include "metric_state.h" #include "plm_int.h" #include "smart_pointer.h" class Bspline_state_private; class Bspline_parms; class Joint_histogram; class PLMREGISTER_API Bspline_state { public: SMART_POINTER_SUPPORT (Bspline_state); Bspline_state_private *d_ptr; public: Bspline_state (); ~Bspline_state (); public: int sm; /* Current smetric */ int it; /* Current iterations */ int feval; /* Number of function evaluations */ Bspline_score ssd; /* Score and Gradient */ void* dev_ptrs; /* GPU Device Pointers */ /* Similarity metric */ std::list similarity_data; /*! \brief Current similarity images. These are raw pointers because they are passed to CUDA code. */ Volume *fixed; Volume *moving; Volume *moving_grad; Volume *fixed_roi; Volume *moving_roi; Bspline_regularize rst; protected: /*! \brief Current joint histogram. This is raw pointer because it is passed to CUDA code. */ Joint_histogram *mi_hist; public: void initialize (Bspline_xform *bxf, Bspline_parms *parms); void initialize_similarity_images (); void initialize_mi_histograms (); void set_metric_state (const Metric_state::Pointer& ms); Bspline_score* get_bspline_score () { return &ssd; } Joint_histogram* get_mi_hist () { return mi_hist; } bool has_metric_type (Similarity_metric_type metric_type); void log_metric (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/000077500000000000000000000000001321604176500273575ustar00rootroot00000000000000CMakeLists.txt000066400000000000000000000073761321604176500320550ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_register_cuda) set_directory_properties (PROPERTIES INCLUDE_DIRECTORIES "") set_directory_properties (PROPERTIES COMPILE_DEFINITIONS "") include_directories (BEFORE ${CMAKE_BINARY_DIR}) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/base) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/cuda) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/register) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/sys) include_directories (BEFORE ${CMAKE_SOURCE_DIR}/src/plastimatch/util) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (AFTER ${DLIB_INCLUDE_DIR}) include_directories (AFTER ${MSINTTYPES_INCLUDE_DIR}) include_directories (AFTER ${CUDA_INCLUDE_DIRS}) if (THRUST_INCLUDE_DIR) include_directories (AFTER ${THRUST_INCLUDE_DIR}) endif () set (PLMREGISTERCUDA_SRC bspline_cuda.cu bspline_cuda_kernels.h demons_cuda.cu # demons_cuda_kernel.cu ) set (PLMREGISTERCUDA_IFACE_SRC bspline_cuda.cxx ) if (PLM_BUILD_VISCOUS) set (PLMREGISTERCUDA_SRC ${PLMREGISTERCUDA_SRC} viscous_compute.cu viscous_convolution.cu viscous_finalize.cu viscous_funcHistogram.cu viscous_funcImageDomain.cu viscous_initialize.cu viscous_main.cu ) endif () set (PLMREGISTERCUDA_LIBRARY_SRC ${PLMREGISTERCUDA_IFACE_SRC} ${PLMREGISTERCUDA_SRC} ) ##----------------------------------------------------------------------------- ## LIBRARY DEPENDENCIES ##----------------------------------------------------------------------------- set (PLMREGISTERCUDA_LIBRARY_DEPENDENCIES plmutil plmbase plmcuda ${PLM_CUDA_LIBRARIES}) if (PLM_BUILD_VISCOUS) set (PLMREGISTERCUDA_LIBRARY_DEPENDENCIES ${PLMREGISTERCUDA_LIBRARY_DEPENDENCIES} ${CUDA_CUBLAS_LIBRARIES}) endif () ##----------------------------------------------------------------------------- ## SPECIAL BUILD RULES: CUDA ##----------------------------------------------------------------------------- if (CUDA_FOUND) if (PLM_USE_GPU_PLUGINS) # build CUDA as separate plmregistercuda shared library plm_add_gpu_plugin_library (plmregistercuda "${PLMREGISTERCUDA_LIBRARY_SRC}") # GCS 2013-03-21. Why can't we link plmregistercuda against plmbase? # I'm going to try it and see. target_link_libraries (plmregistercuda ${PLMREGISTERCUDA_LIBRARY_DEPENDENCIES}) # set dependencies that plmregister library needs if (WIN32 AND NOT CYGWIN AND NOT MINGW) # windows needs to delayload it set (PLMREGISTER_LIBRARY_DEPENDENCIES ${PLMREGISTER_LIBRARY_DEPENDENCIES} plmregistercuda) set (PLMREGISTER_LIBRARY_LDFLAGS "${PLMREGISTER_LIBRARY_LDFLAGS} /DELAYLOAD:plmregistercuda.dll") endif () if (NOT WIN32 AND LIBDL_FOUND) # and unix needs dlopen() set (PLMREGISTER_LIBRARY_DEPENDENCIES ${PLMREGISTER_LIBRARY_DEPENDENCIES} -ldl) endif () else () # building CUDA into plmregister cuda_compile (CUDA_WRAPPERS ${PLMREGISTERCUDA_SRC}) # set (PLMREGISTER_LIBRARY_SRC # ${PLMREGISTER_LIBRARY_SRC} # ${PLMREGISTERCUDA_IFACE_SRC} # ${CUDA_WRAPPERS} # ) # set (PLMREGISTER_LIBRARY_DEPENDENCIES # ${PLMREGISTER_LIBRARY_DEPENDENCIES} # ${CUDA_LIBRARIES} # ) set (PLMREGISTERCUDA_LIBRARY_SRC ${CUDA_WRAPPERS} ${PLMREGISTERCUDA_IFACE_SRC} ) plm_add_library (plmregistercuda "${PLMREGISTERCUDA_LIBRARY_SRC}" "${PLMREGISTERCUDA_LIBRARY_DEPENDENCIES}" "" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "") endif () endif () bspline_cuda.cu000066400000000000000000004045331321604176500322720ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #if defined (_WIN32) #include #endif #include "bspline.h" #include "bspline_cuda.h" #include "bspline_cuda_kernels.h" #include "bspline_state.h" #include "bspline_xform.h" #include "cuda_util.h" #include "cuda_mem.h" #include "cuda_kernel_util.h" #include "joint_histogram.h" #include "plm_int.h" #include "volume.h" // For CUDA Toolkits < 4.0 #ifndef cudaTextureType1D #define cudaTextureType1D 0x01 #endif // Define file-scope textures texture tex_moving_image; texture tex_coeff; texture tex_LUT_Bspline_x; texture tex_LUT_Bspline_y; texture tex_LUT_Bspline_z; //////////////////////////////////////////////////////////// // Constructs the GPU Bspline Data structure void build_gbd ( GPU_Bspline_Data* gbd, Bspline_xform* bxf, Volume* fixed, Volume* moving) { if (bxf != NULL) { // populate bxf entries CUDA_array2vec_int3 (&gbd->rdims, bxf->rdims); CUDA_array2vec_int3 (&gbd->cdims, bxf->cdims); CUDA_array2vec_float3 (&gbd->img_origin, bxf->img_origin); CUDA_array2vec_float3 (&gbd->img_spacing, bxf->img_spacing); CUDA_array2vec_int3 (&gbd->roi_dim, bxf->roi_dim); CUDA_array2vec_int3 (&gbd->roi_offset, bxf->roi_offset); CUDA_array2vec_int3 (&gbd->vox_per_rgn, bxf->vox_per_rgn); } if (fixed != NULL) { // populate fixed volume entries CUDA_array2vec_int3 (&gbd->fix_dim, fixed->dim); } if (moving != NULL) { // populate moving volume entries CUDA_array2vec_int3 (&gbd->mov_dim, moving->dim); CUDA_array2vec_float3 (&gbd->mov_origin, moving->origin); CUDA_array2vec_float3 (&gbd->mov_spacing, moving->spacing); } } void CUDA_bspline_mi_init_a ( Bspline_xform* bxf, Bspline_state* bst, Dev_Pointers_Bspline* dev_ptrs, Volume* fixed, Volume* moving, Volume* moving_grad ) { Joint_histogram* mi_hist = bst->get_mi_hist(); // Keep track of how much memory we allocated in the GPU global memory. long unsigned GPU_Memory_Bytes = 0; printf ("Allocating GPU Memory\n"); // Fixed Image // ---------------------------------------------------------- dev_ptrs->fixed_image_size = fixed->npix * fixed->pix_size; CUDA_alloc_copy ((void **)&dev_ptrs->fixed_image, (void **)&fixed->img, dev_ptrs->fixed_image_size); GPU_Memory_Bytes += dev_ptrs->fixed_image_size; printf("."); // ---------------------------------------------------------- // Moving Image // ---------------------------------------------------------- dev_ptrs->moving_image_size = moving->npix * moving->pix_size; CUDA_alloc_copy ((void **)&dev_ptrs->moving_image, (void **)&moving->img, dev_ptrs->moving_image_size); GPU_Memory_Bytes += dev_ptrs->moving_image_size; printf("."); // ---------------------------------------------------------- // Skipped Voxels // ---------------------------------------------------------- dev_ptrs->skipped_size = sizeof(unsigned int); CUDA_alloc_zero ((void**)&dev_ptrs->skipped_atomic, dev_ptrs->skipped_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->skipped_size; printf("."); // ---------------------------------------------------------- // Histograms // ---------------------------------------------------------- dev_ptrs->f_hist_size = mi_hist->fixed.bins * sizeof(float); dev_ptrs->m_hist_size = mi_hist->moving.bins * sizeof(float); dev_ptrs->j_hist_size = mi_hist->fixed.bins * mi_hist->moving.bins * sizeof(float); cudaMalloc ((void**)&dev_ptrs->f_hist, dev_ptrs->f_hist_size); cudaMalloc ((void**)&dev_ptrs->m_hist, dev_ptrs->m_hist_size); cudaMalloc ((void**)&dev_ptrs->j_hist, dev_ptrs->j_hist_size); GPU_Memory_Bytes += dev_ptrs->f_hist_size; GPU_Memory_Bytes += dev_ptrs->m_hist_size; GPU_Memory_Bytes += dev_ptrs->j_hist_size; printf("..."); // ---------------------------------------------------------- // Coefficient LUT // ---------------------------------------------------------- dev_ptrs->coeff_size = sizeof(float) * bxf->num_coeff; CUDA_alloc_zero ((void **)&dev_ptrs->coeff, dev_ptrs->coeff_size, cudaAllocStern); cudaBindTexture(0, tex_coeff, dev_ptrs->coeff, dev_ptrs->coeff_size); CUDA_check_error("Failed to bind dev_ptrs->coeff to texture reference!"); GPU_Memory_Bytes += dev_ptrs->coeff_size; printf("."); // ---------------------------------------------------------- // Score // ---------------------------------------------------------- dev_ptrs->score_size = sizeof(float) * fixed->npix; CUDA_alloc_zero ((void **)&dev_ptrs->score, dev_ptrs->score_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->score_size; printf("."); // ---------------------------------------------------------- // Gradient (dC_cP) // ---------------------------------------------------------- dev_ptrs->grad_size = sizeof(float) * bxf->num_coeff; CUDA_alloc_zero ((void **)&dev_ptrs->grad, dev_ptrs->grad_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->grad_size; printf("."); // ---------------------------------------------------------- // dc_dv_x, dc_dv_y, and dc_dv_z // ---------------------------------------------------------- int3 vol_dim; vol_dim.x = fixed->dim[0]; vol_dim.y = fixed->dim[1]; vol_dim.z = fixed->dim[2]; int3 tile_dim; tile_dim.x = bxf->vox_per_rgn[0]; tile_dim.y = bxf->vox_per_rgn[1]; tile_dim.z = bxf->vox_per_rgn[2]; int4 num_tile; num_tile.x = (vol_dim.x+tile_dim.x-1) / tile_dim.x; num_tile.y = (vol_dim.y+tile_dim.y-1) / tile_dim.y; num_tile.z = (vol_dim.z+tile_dim.z-1) / tile_dim.z; num_tile.w = num_tile.x * num_tile.y * num_tile.z; int tile_padding = 64 - ((tile_dim.x * tile_dim.y * tile_dim.z) % 64); int tile_bytes = (tile_dim.x * tile_dim.y * tile_dim.z); dev_ptrs->dc_dv_x_size = ((tile_bytes + tile_padding) * num_tile.w) * sizeof(float); dev_ptrs->dc_dv_y_size = dev_ptrs->dc_dv_x_size; dev_ptrs->dc_dv_z_size = dev_ptrs->dc_dv_x_size; CUDA_alloc_zero ((void **)&dev_ptrs->dc_dv_x, dev_ptrs->dc_dv_x_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->dc_dv_x_size; printf("."); CUDA_alloc_zero ((void **)&dev_ptrs->dc_dv_y, dev_ptrs->dc_dv_y_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->dc_dv_y_size; printf("."); CUDA_alloc_zero ((void **)&dev_ptrs->dc_dv_z, dev_ptrs->dc_dv_z_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->dc_dv_z_size; printf("."); // ---------------------------------------------------------- // Condensed dc_dv vectors // ---------------------------------------------------------- dev_ptrs->cond_x_size = 64*bxf->num_knots*sizeof(float); CUDA_alloc_zero ((void **)&dev_ptrs->cond_x, dev_ptrs->cond_x_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->cond_x_size; printf("."); dev_ptrs->cond_y_size = 64*bxf->num_knots*sizeof(float); CUDA_alloc_zero ((void **)&dev_ptrs->cond_y, dev_ptrs->cond_y_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->cond_y_size; printf("."); dev_ptrs->cond_z_size = 64*bxf->num_knots*sizeof(float); CUDA_alloc_zero ((void **)&dev_ptrs->cond_z, dev_ptrs->cond_z_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->cond_z_size; printf("."); // ---------------------------------------------------------- // Tile Offset LUT // ---------------------------------------------------------- int* offsets = CPU_calc_offsets (bxf->vox_per_rgn, bxf->cdims); int num_tiles = (bxf->cdims[0]-3) * (bxf->cdims[1]-3) * (bxf->cdims[2]-3); dev_ptrs->LUT_Offsets_size = num_tiles*sizeof(int); CUDA_alloc_copy ((void **)&dev_ptrs->LUT_Offsets, (void **)&offsets, dev_ptrs->LUT_Offsets_size); GPU_Memory_Bytes += dev_ptrs->LUT_Offsets_size; printf("."); free (offsets); // ---------------------------------------------------------- // Control Point (Knot) LUT // ---------------------------------------------------------- dev_ptrs->LUT_Knot_size = 64*num_tiles*sizeof(int); int* local_set_of_64 = (int*)malloc(64*sizeof(int)); int* LUT_Knot = (int*)malloc(dev_ptrs->LUT_Knot_size); int i,j; for (i = 0; i < num_tiles; i++) { CPU_find_knots(local_set_of_64, i, bxf->rdims, bxf->cdims); for (j = 0; j < 64; j++) { LUT_Knot[64*i + j] = local_set_of_64[j]; } } CUDA_alloc_copy ((void **)&dev_ptrs->LUT_Knot, (void **)&LUT_Knot, dev_ptrs->LUT_Knot_size); free (local_set_of_64); free (LUT_Knot); GPU_Memory_Bytes += dev_ptrs->LUT_Knot_size; printf ("."); // ---------------------------------------------------------- // B-spline LUT // ---------------------------------------------------------- dev_ptrs->LUT_Bspline_x_size = 4*bxf->vox_per_rgn[0]* sizeof(float); dev_ptrs->LUT_Bspline_y_size = 4*bxf->vox_per_rgn[1]* sizeof(float); dev_ptrs->LUT_Bspline_z_size = 4*bxf->vox_per_rgn[2]* sizeof(float); float* LUT_Bspline_x = (float*)malloc(dev_ptrs->LUT_Bspline_x_size); float* LUT_Bspline_y = (float*)malloc(dev_ptrs->LUT_Bspline_y_size); float* LUT_Bspline_z = (float*)malloc(dev_ptrs->LUT_Bspline_z_size); for (j = 0; j < 4; j++) { for (i = 0; i < bxf->vox_per_rgn[0]; i++) { LUT_Bspline_x[j*bxf->vox_per_rgn[0] + i] = CPU_obtain_bspline_basis_function (j, i, bxf->vox_per_rgn[0]); } for (i = 0; i < bxf->vox_per_rgn[1]; i++) { LUT_Bspline_y[j*bxf->vox_per_rgn[1] + i] = CPU_obtain_bspline_basis_function (j, i, bxf->vox_per_rgn[1]); } for (i = 0; i < bxf->vox_per_rgn[2]; i++) { LUT_Bspline_z[j*bxf->vox_per_rgn[2] + i] = CPU_obtain_bspline_basis_function (j, i, bxf->vox_per_rgn[2]); } } CUDA_alloc_copy ((void **)&dev_ptrs->LUT_Bspline_x, (void **)&LUT_Bspline_x, dev_ptrs->LUT_Bspline_x_size); cudaBindTexture(0, tex_LUT_Bspline_x, dev_ptrs->LUT_Bspline_x, dev_ptrs->LUT_Bspline_x_size); GPU_Memory_Bytes += dev_ptrs->LUT_Bspline_x_size; printf("."); CUDA_alloc_copy ((void **)&dev_ptrs->LUT_Bspline_y, (void **)&LUT_Bspline_y, dev_ptrs->LUT_Bspline_y_size); cudaBindTexture(0, tex_LUT_Bspline_y, dev_ptrs->LUT_Bspline_y, dev_ptrs->LUT_Bspline_y_size); GPU_Memory_Bytes += dev_ptrs->LUT_Bspline_y_size; printf("."); CUDA_alloc_copy ((void **)&dev_ptrs->LUT_Bspline_z, (void **)&LUT_Bspline_z, dev_ptrs->LUT_Bspline_z_size); cudaBindTexture(0, tex_LUT_Bspline_z, dev_ptrs->LUT_Bspline_z, dev_ptrs->LUT_Bspline_z_size); GPU_Memory_Bytes += dev_ptrs->LUT_Bspline_z_size; printf("."); free (LUT_Bspline_x); free (LUT_Bspline_y); free (LUT_Bspline_z); // ---------------------------------------------------------- // Inform user we are finished. printf (" done.\n"); // Report global memory allocation. printf(" GPU Memory: %ld MB\n", GPU_Memory_Bytes / 1048576); #if defined (commentout) printf ("---------------------------\n"); printf ("Skipped Voxels: %i MB\n", dev_ptrs->skipped_size / 1048576); printf (" Score: %i MB\n", dev_ptrs->score_size / 1048576); printf (" dc_dv_x: %i MB\n", dev_ptrs->dc_dv_x_size / 1048576); printf (" dc_dv_y: %i MB\n", dev_ptrs->dc_dv_y_size / 1048576); printf (" dc_dv_z: %i MB\n", dev_ptrs->dc_dv_z_size / 1048576); printf (" cond_x: %i MB\n", dev_ptrs->cond_x_size / 1048576); printf (" cond_y: %i MB\n", dev_ptrs->cond_y_size / 1048576); printf (" cond_z: %i MB\n", dev_ptrs->cond_z_size / 1048576); printf (" Fixed Hist: %i KB\n", dev_ptrs->f_hist_size / 1024); printf (" Moving Hist: %i KB\n", dev_ptrs->m_hist_size / 1024); printf (" Joint Hist: %i KB\n", dev_ptrs->j_hist_size / 1024); printf (" q-lut: %i KB\n", dev_ptrs->q_lut_size / 1024); printf (" c-lut: %i KB\n", dev_ptrs->c_lut_size / 1024); printf (" coeff-lut: %i KB\n", dev_ptrs->coeff_size / 1024); printf (" Gradient: %i KB\n", dev_ptrs->grad_size / 1024); printf (" Tile Offsets: %i KB\n", dev_ptrs->LUT_Offsets_size / 1024); printf (" Knot LUT: %i KB\n", dev_ptrs->LUT_Knot_size / 1024); printf ("B-spline LUT-x: %i KB\n", dev_ptrs->LUT_Bspline_x_size / 1024); printf ("B-spline LUT-y: %i KB\n", dev_ptrs->LUT_Bspline_y_size / 1024); printf ("B-spline LUT-z: %i KB\n", dev_ptrs->LUT_Bspline_z_size / 1024); printf ("---------------------------\n"); #endif } // Initialize the GPU to execute CUDA MSE flavor 'j' // Updated to use zero copy when enabled and available // // AUTHOR: James Shackleford // DATE : October 26, 2010 void CUDA_bspline_mse_init_j ( Dev_Pointers_Bspline* dev_ptrs, Volume* fixed, Volume* moving, Volume* moving_grad, Bspline_xform* bxf, Bspline_parms* parms ) { // Keep track of how much memory we allocated // in the GPU global memory. long unsigned GPU_Memory_Bytes = 0; printf ("Allocating GPU Memory"); fflush (stdout); // Fixed Image (zero copy if possible) // ---------------------------------------------------------- dev_ptrs->fixed_image_size = fixed->npix * fixed->pix_size; CUDA_alloc_copy ((void **)&dev_ptrs->fixed_image, (void **)&fixed->img, dev_ptrs->fixed_image_size); GPU_Memory_Bytes += dev_ptrs->fixed_image_size; printf("."); // ---------------------------------------------------------- // Moving Image (must be global) // ---------------------------------------------------------- dev_ptrs->moving_image_size = moving->npix * moving->pix_size; CUDA_alloc_copy ((void **)&dev_ptrs->moving_image, (void **)&moving->img, dev_ptrs->moving_image_size); cudaBindTexture(0, tex_moving_image, dev_ptrs->moving_image, dev_ptrs->moving_image_size); CUDA_check_error("Failed to bind dev_ptrs->moving_image to texture reference!"); GPU_Memory_Bytes += dev_ptrs->moving_image_size; printf("."); // ---------------------------------------------------------- // Moving Image Gradient // ---------------------------------------------------------- dev_ptrs->moving_grad_size = moving_grad->npix * moving_grad->pix_size; CUDA_alloc_copy ((void **)&dev_ptrs->moving_grad, (void **)&moving_grad->img, dev_ptrs->moving_grad_size); GPU_Memory_Bytes += dev_ptrs->moving_grad_size; printf("."); // ---------------------------------------------------------- // Coefficient LUT // ---------------------------------------------------------- dev_ptrs->coeff_size = sizeof(float) * bxf->num_coeff; CUDA_alloc_zero ((void **)&dev_ptrs->coeff, dev_ptrs->coeff_size, cudaAllocStern); cudaBindTexture(0, tex_coeff, dev_ptrs->coeff, dev_ptrs->coeff_size); CUDA_check_error("Failed to bind dev_ptrs->coeff to texture reference!"); GPU_Memory_Bytes += dev_ptrs->coeff_size; printf("."); // ---------------------------------------------------------- // Score // ---------------------------------------------------------- dev_ptrs->score_size = sizeof(float) * fixed->npix; CUDA_alloc_zero ((void **)&dev_ptrs->score, dev_ptrs->score_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->score_size; printf("."); // ---------------------------------------------------------- // Skipped Voxels // ---------------------------------------------------------- dev_ptrs->skipped_size = sizeof(float) * fixed->npix; CUDA_alloc_zero ((void **)&dev_ptrs->skipped, dev_ptrs->skipped_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->skipped_size; printf("."); // ---------------------------------------------------------- // Gradient (dC_cP) // ---------------------------------------------------------- dev_ptrs->grad_size = sizeof(float) * bxf->num_coeff; CUDA_alloc_zero ((void **)&dev_ptrs->grad, dev_ptrs->grad_size, cudaAllocStern); CUDA_check_error("Failed to bind dev_ptrs->grad to texture reference!"); GPU_Memory_Bytes += dev_ptrs->grad_size; printf("."); // ---------------------------------------------------------- // dc_dv_x, dc_dv_y, and dc_dv_z // ---------------------------------------------------------- int3 vol_dim; vol_dim.x = fixed->dim[0]; vol_dim.y = fixed->dim[1]; vol_dim.z = fixed->dim[2]; int3 tile_dim; tile_dim.x = bxf->vox_per_rgn[0]; tile_dim.y = bxf->vox_per_rgn[1]; tile_dim.z = bxf->vox_per_rgn[2]; int4 num_tile; num_tile.x = (vol_dim.x+tile_dim.x-1) / tile_dim.x; num_tile.y = (vol_dim.y+tile_dim.y-1) / tile_dim.y; num_tile.z = (vol_dim.z+tile_dim.z-1) / tile_dim.z; num_tile.w = num_tile.x * num_tile.y * num_tile.z; int tile_padding = 64 - ((tile_dim.x * tile_dim.y * tile_dim.z) % 64); int tile_bytes = (tile_dim.x * tile_dim.y * tile_dim.z); dev_ptrs->dc_dv_x_size = ((tile_bytes + tile_padding) * num_tile.w) * sizeof(float); dev_ptrs->dc_dv_y_size = dev_ptrs->dc_dv_x_size; dev_ptrs->dc_dv_z_size = dev_ptrs->dc_dv_x_size; CUDA_alloc_zero ((void **)&dev_ptrs->dc_dv_x, dev_ptrs->dc_dv_x_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->dc_dv_x_size; printf("."); CUDA_alloc_zero ((void **)&dev_ptrs->dc_dv_y, dev_ptrs->dc_dv_y_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->dc_dv_y_size; printf("."); CUDA_alloc_zero ((void **)&dev_ptrs->dc_dv_z, dev_ptrs->dc_dv_z_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->dc_dv_z_size; printf("."); // ---------------------------------------------------------- // Tile Offset LUT // ---------------------------------------------------------- int* offsets = CPU_calc_offsets(bxf->vox_per_rgn, bxf->cdims); int num_tiles = (bxf->cdims[0]-3) * (bxf->cdims[1]-3) * (bxf->cdims[2]-3); dev_ptrs->LUT_Offsets_size = num_tiles*sizeof(int); CUDA_alloc_copy ((void **)&dev_ptrs->LUT_Offsets, (void **)&offsets, dev_ptrs->LUT_Offsets_size); GPU_Memory_Bytes += dev_ptrs->LUT_Offsets_size; printf("."); free (offsets); // ---------------------------------------------------------- // Control Point (Knot) LUT // ---------------------------------------------------------- dev_ptrs->LUT_Knot_size = 64*num_tiles*sizeof(int); int* local_set_of_64 = (int*)malloc(64*sizeof(int)); int* LUT_Knot = (int*)malloc(dev_ptrs->LUT_Knot_size); int i,j; for (i = 0; i < num_tiles; i++) { CPU_find_knots(local_set_of_64, i, bxf->rdims, bxf->cdims); for (j = 0; j < 64; j++) { LUT_Knot[64*i + j] = local_set_of_64[j]; } } CUDA_alloc_copy ((void **)&dev_ptrs->LUT_Knot, (void **)&LUT_Knot, dev_ptrs->LUT_Knot_size); free (local_set_of_64); free (LUT_Knot); GPU_Memory_Bytes += dev_ptrs->LUT_Knot_size; printf ("."); // ---------------------------------------------------------- // Condensed dc_dv vectors // ---------------------------------------------------------- dev_ptrs->cond_x_size = 64*bxf->num_knots*sizeof(float); CUDA_alloc_zero ((void **)&dev_ptrs->cond_x, dev_ptrs->cond_x_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->cond_x_size; printf("."); dev_ptrs->cond_y_size = 64*bxf->num_knots*sizeof(float); CUDA_alloc_zero ((void **)&dev_ptrs->cond_y, dev_ptrs->cond_y_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->cond_y_size; printf("."); dev_ptrs->cond_z_size = 64*bxf->num_knots*sizeof(float); CUDA_alloc_zero ((void **)&dev_ptrs->cond_z, dev_ptrs->cond_z_size, cudaAllocStern); GPU_Memory_Bytes += dev_ptrs->cond_z_size; printf("."); // ---------------------------------------------------------- // B-spline LUT // ---------------------------------------------------------- dev_ptrs->LUT_Bspline_x_size = 4*bxf->vox_per_rgn[0]* sizeof(float); dev_ptrs->LUT_Bspline_y_size = 4*bxf->vox_per_rgn[1]* sizeof(float); dev_ptrs->LUT_Bspline_z_size = 4*bxf->vox_per_rgn[2]* sizeof(float); float* LUT_Bspline_x = (float*)malloc(dev_ptrs->LUT_Bspline_x_size); float* LUT_Bspline_y = (float*)malloc(dev_ptrs->LUT_Bspline_y_size); float* LUT_Bspline_z = (float*)malloc(dev_ptrs->LUT_Bspline_z_size); for (j = 0; j < 4; j++) { for (i = 0; i < bxf->vox_per_rgn[0]; i++) { LUT_Bspline_x[j*bxf->vox_per_rgn[0] + i] = CPU_obtain_bspline_basis_function (j, i, bxf->vox_per_rgn[0]); } for (i = 0; i < bxf->vox_per_rgn[1]; i++) { LUT_Bspline_y[j*bxf->vox_per_rgn[1] + i] = CPU_obtain_bspline_basis_function (j, i, bxf->vox_per_rgn[1]); } for (i = 0; i < bxf->vox_per_rgn[2]; i++) { LUT_Bspline_z[j*bxf->vox_per_rgn[2] + i] = CPU_obtain_bspline_basis_function (j, i, bxf->vox_per_rgn[2]); } } CUDA_alloc_copy ((void **)&dev_ptrs->LUT_Bspline_x, (void **)&LUT_Bspline_x, dev_ptrs->LUT_Bspline_x_size); cudaBindTexture(0, tex_LUT_Bspline_x, dev_ptrs->LUT_Bspline_x, dev_ptrs->LUT_Bspline_x_size); GPU_Memory_Bytes += dev_ptrs->LUT_Bspline_x_size; printf("."); CUDA_alloc_copy ((void **)&dev_ptrs->LUT_Bspline_y, (void **)&LUT_Bspline_y, dev_ptrs->LUT_Bspline_y_size); cudaBindTexture(0, tex_LUT_Bspline_y, dev_ptrs->LUT_Bspline_y, dev_ptrs->LUT_Bspline_y_size); GPU_Memory_Bytes += dev_ptrs->LUT_Bspline_y_size; printf("."); CUDA_alloc_copy ((void **)&dev_ptrs->LUT_Bspline_z, (void **)&LUT_Bspline_z, dev_ptrs->LUT_Bspline_z_size); cudaBindTexture(0, tex_LUT_Bspline_z, dev_ptrs->LUT_Bspline_z, dev_ptrs->LUT_Bspline_z_size); GPU_Memory_Bytes += dev_ptrs->LUT_Bspline_z_size; printf("."); free (LUT_Bspline_x); free (LUT_Bspline_y); free (LUT_Bspline_z); // ---------------------------------------------------------- // Inform user we are finished. printf("done.\n"); // Report global memory allocation. printf(" GPU Memory: %ld MB\n", GPU_Memory_Bytes / 1048576); } // AUTHOR: James Shackleford // DATE : September 11th, 2009 void CUDA_bspline_mse_cleanup_j ( Dev_Pointers_Bspline* dev_ptrs, Volume* fixed, Volume* moving, Volume* moving_grad ) { // Textures cudaUnbindTexture(tex_moving_image); cudaUnbindTexture(tex_coeff); cudaUnbindTexture(tex_LUT_Bspline_x); cudaUnbindTexture(tex_LUT_Bspline_y); cudaUnbindTexture(tex_LUT_Bspline_z); // Global Memory cudaFree(dev_ptrs->fixed_image); cudaFree(dev_ptrs->moving_image); cudaFree(dev_ptrs->moving_grad); cudaFree(dev_ptrs->coeff); cudaFree(dev_ptrs->score); cudaFree(dev_ptrs->grad); cudaFree(dev_ptrs->dc_dv_x); cudaFree(dev_ptrs->dc_dv_y); cudaFree(dev_ptrs->dc_dv_z); cudaFree(dev_ptrs->LUT_Offsets); cudaFree(dev_ptrs->LUT_Knot); cudaFree(dev_ptrs->cond_x); cudaFree(dev_ptrs->cond_y); cudaFree(dev_ptrs->cond_z); cudaFree(dev_ptrs->LUT_Bspline_x); cudaFree(dev_ptrs->LUT_Bspline_y); cudaFree(dev_ptrs->LUT_Bspline_z); cudaFree(dev_ptrs->skipped); } // AUTHOR: James Shackleford // DATE : October 29th, 2010 void CUDA_bspline_mi_cleanup_a ( Dev_Pointers_Bspline* dev_ptrs, Volume* fixed, Volume* moving, Volume* moving_grad ) { // Textures cudaUnbindTexture(tex_coeff); cudaUnbindTexture(tex_LUT_Bspline_x); cudaUnbindTexture(tex_LUT_Bspline_y); cudaUnbindTexture(tex_LUT_Bspline_z); // Global Memory cudaFree(dev_ptrs->fixed_image); cudaFree(dev_ptrs->moving_image); cudaFree(dev_ptrs->skipped_atomic); cudaFree(dev_ptrs->f_hist); cudaFree(dev_ptrs->m_hist); cudaFree(dev_ptrs->j_hist); cudaFree(dev_ptrs->coeff); cudaFree(dev_ptrs->score); cudaFree(dev_ptrs->grad); cudaFree(dev_ptrs->dc_dv_x); cudaFree(dev_ptrs->dc_dv_y); cudaFree(dev_ptrs->dc_dv_z); cudaFree(dev_ptrs->cond_x); cudaFree(dev_ptrs->cond_y); cudaFree(dev_ptrs->cond_z); cudaFree(dev_ptrs->LUT_Offsets); cudaFree(dev_ptrs->LUT_Knot); cudaFree(dev_ptrs->LUT_Bspline_x); cudaFree(dev_ptrs->LUT_Bspline_y); cudaFree(dev_ptrs->LUT_Bspline_z); } int CUDA_bspline_mi_hist ( Dev_Pointers_Bspline *dev_ptrs, Joint_histogram* mi_hist, Volume* fixed, Volume* moving, Bspline_xform* bxf) { cudaMemset(dev_ptrs->skipped_atomic, 0, dev_ptrs->skipped_size); // Generate the fixed histogram (48 ms) CUDA_bspline_mi_hist_fix (dev_ptrs, mi_hist, fixed, moving, bxf); // Generate the moving histogram (150 ms) CUDA_bspline_mi_hist_mov (dev_ptrs, mi_hist, fixed, moving, bxf); // Generate the joint histogram (~600 ms) return CUDA_bspline_mi_hist_jnt (dev_ptrs, mi_hist, fixed, moving, bxf); } void CUDA_bspline_mi_hist_fix ( Dev_Pointers_Bspline *dev_ptrs, Joint_histogram* mi_hist, Volume* fixed, Volume* moving, Bspline_xform *bxf) { dim3 dimGrid; dim3 dimBlock; int num_blocks; GPU_Bspline_Data gbd; build_gbd (&gbd, bxf, fixed, moving); // Initialize histogram memory on GPU cudaMemset(dev_ptrs->f_hist, 0, dev_ptrs->f_hist_size); CUDA_check_error ("Failed to initialize memory for f_hist"); num_blocks = CUDA_exec_conf_1tpe ( &dimGrid, // OUTPUT: Grid dimensions &dimBlock, // OUTPUT: Block dimensions fixed->npix, // INPUT: Total # of threads 32, // INPUT: Threads per block false // INPUT: Is threads per block negotiable? ); int smemSize = (int) (dimBlock.x * mi_hist->fixed.bins * sizeof(float)); dev_ptrs->f_hist_seg_size = mi_hist->fixed.bins * num_blocks * sizeof(float); cudaMalloc ((void**)&dev_ptrs->f_hist_seg, dev_ptrs->f_hist_seg_size); CUDA_check_error ("Failed to allocate memory for f_hist_seg"); cudaMemset(dev_ptrs->f_hist_seg, 0, dev_ptrs->f_hist_seg_size); CUDA_check_error ("Failed to initialize memory for f_hist_seg"); // Launch kernel with one thread per voxel kernel_bspline_mi_hist_fix <<>> ( dev_ptrs->f_hist_seg, // partial histogram (moving image) dev_ptrs->fixed_image, // moving image voxels mi_hist->fixed.offset, // histogram origin 1.0f/mi_hist->fixed.delta, // histogram delta mi_hist->fixed.bins, // # histogram bins gbd.vox_per_rgn, // voxels per region gbd.fix_dim, // fixed image dimensions gbd.mov_dim, // moving image dimensions gbd.rdims, // region dimensions gbd.cdims, // # control points in x,y,z gbd.img_origin, // image origin gbd.img_spacing, // image spacing gbd.mov_origin, // moving image origin gbd.mov_spacing // moving image pixel spacing ); cudaThreadSynchronize(); CUDA_check_error ("kernel_bspline_mi_hist_fix"); int num_sub_hists = num_blocks; // Merge sub-histograms dim3 dimGrid2 (mi_hist->fixed.bins, 1, 1); dim3 dimBlock2 (512, 1, 1); smemSize = 512 * sizeof(float); // this kernel can be ran with any thread-block size kernel_bspline_mi_hist_merge <<>> ( dev_ptrs->f_hist, dev_ptrs->f_hist_seg, num_sub_hists ); cudaThreadSynchronize(); CUDA_check_error ("kernel hist_fix_merge"); /* copy result back to host * -- Note CPU uses doubles whereas the GPU uses floats * due to lack of double precision floats. This is okay * since the GPU's ability to add small numbers to large * using single precision is more accurate than the CPU. * * -- However, this does result in the little bit of nastiness * found below. We copy these back to the CPU for the score * computation, which the CPU completes very quickly. */ float* f_hist_f = (float*)malloc(dev_ptrs->f_hist_size); cudaMemcpy (f_hist_f, dev_ptrs->f_hist, dev_ptrs->f_hist_size, cudaMemcpyDeviceToHost); CUDA_check_error ("Unable to copy fixed histograms from GPU to CPU!\n"); /* type cast to CPU friendly double */ for (int i=0; i< mi_hist->fixed.bins; i++) { mi_hist->f_hist[i] = (double)f_hist_f[i]; } free (f_hist_f); cudaFree (dev_ptrs->f_hist_seg); CUDA_check_error ("Error freeing sub-histograms from GPU memory!\n"); } void CUDA_bspline_mi_hist_mov ( Dev_Pointers_Bspline *dev_ptrs, Joint_histogram* mi_hist, Volume* fixed, Volume* moving, Bspline_xform *bxf) { dim3 dimGrid; dim3 dimBlock; int num_blocks; GPU_Bspline_Data gbd; build_gbd (&gbd, bxf, fixed, moving); // Initialize histogram memory on GPU cudaMemset(dev_ptrs->m_hist, 0, dev_ptrs->m_hist_size); CUDA_check_error ("Failed to initialize memory for m_hist"); num_blocks = CUDA_exec_conf_1tpe ( &dimGrid, // OUTPUT: Grid dimensions &dimBlock, // OUTPUT: Block dimensions fixed->npix, // INPUT: Total # of threads 32, // INPUT: Threads per block false); // INPUT: Is threads per block negotiable? int smemSize = (int) (dimBlock.x * mi_hist->moving.bins * sizeof(float)); dev_ptrs->m_hist_seg_size = mi_hist->moving.bins * num_blocks * sizeof(float); cudaMalloc ((void**)&dev_ptrs->m_hist_seg, dev_ptrs->m_hist_seg_size); CUDA_check_error ("Failed to allocate memory for m_hist_seg"); cudaMemset(dev_ptrs->m_hist_seg, 0, dev_ptrs->m_hist_seg_size); CUDA_check_error ("Failed to initialize memory for m_hist_seg"); // Launch kernel with one thread per voxel kernel_bspline_mi_hist_mov <<>> ( dev_ptrs->m_hist_seg, // partial histogram (moving image) dev_ptrs->moving_image, // moving image voxels mi_hist->moving.offset, // histogram origin 1.0f/mi_hist->moving.delta, // histogram delta mi_hist->moving.bins, // # histogram bins gbd.vox_per_rgn, // voxels per region gbd.fix_dim, // fixed image dimensions gbd.mov_dim, // moving image dimensions gbd.rdims, // region dimensions gbd.cdims, // # control points in x,y,z gbd.img_origin, // image origin gbd.img_spacing, // image spacing gbd.mov_origin, // moving image origin gbd.mov_spacing // moving image pixel spacing ); cudaThreadSynchronize(); CUDA_check_error ("kernel hist_mov"); int num_sub_hists = num_blocks; // Merge sub-histograms dim3 dimGrid2 (mi_hist->moving.bins, 1, 1); dim3 dimBlock2 (512, 1, 1); smemSize = 512 * sizeof(float); // this kernel can be ran with any thread-block size kernel_bspline_mi_hist_merge <<>> ( dev_ptrs->m_hist, dev_ptrs->m_hist_seg, num_sub_hists ); cudaThreadSynchronize(); CUDA_check_error ("kernel hist_merge"); /* copy result back to host * -- Note CPU uses doubles whereas the GPU uses floats * due to lack of double precision floats. This is okay * since the GPU's ability to add small numbers to large * using single precision is more accurate than the CPU. * * -- However, this does result in the little bit of nastiness * found below. We copy these back to the CPU for the score * computation, which the CPU completes very quickly. */ float* m_hist_f = (float*)malloc(dev_ptrs->m_hist_size); cudaMemcpy (m_hist_f, dev_ptrs->m_hist, dev_ptrs->m_hist_size, cudaMemcpyDeviceToHost); CUDA_check_error ("Unable to copy moving histograms from GPU to CPU!\n"); /* type cast to CPU friendly double */ for (int i=0; i< mi_hist->moving.bins; i++) { mi_hist->m_hist[i] = (double)m_hist_f[i]; } free (m_hist_f); cudaFree (dev_ptrs->m_hist_seg); CUDA_check_error ("Error freeing sub-histograms from GPU memory!\n"); } int CUDA_bspline_mi_hist_jnt ( Dev_Pointers_Bspline *dev_ptrs, Joint_histogram* mi_hist, Volume* fixed, Volume* moving, Bspline_xform *bxf) { GPU_Bspline_Data gbd; build_gbd (&gbd, bxf, fixed, moving); // Initialize histogram memory on GPU cudaMemset(dev_ptrs->j_hist, 0, dev_ptrs->j_hist_size); int num_bins = (int)mi_hist->fixed.bins * (int)mi_hist->moving.bins; // ---------------------- // --- INITIALIZE GRID --- // ---------------------- int i; int Grid_x = 0; int Grid_y = 0; int threads_per_block = 128; int num_threads = fixed->npix; int sqrt_num_blocks; int num_blocks; int smemSize; int found_flag = 0; // Search for a valid execution configuration // for the required # of blocks. for (threads_per_block = 192; threads_per_block > 32; threads_per_block -= 32) { num_blocks = (num_threads + threads_per_block - 1) / threads_per_block; sqrt_num_blocks = (int)sqrt((float)num_blocks); for (i = sqrt_num_blocks; i < 65535; i++) { if (num_blocks % i == 0) { Grid_x = i; Grid_y = num_blocks / Grid_x; found_flag = 1; break; } } if (found_flag == 1) { break; } } // Were we able to find a valid exec config? if (Grid_x == 0) { printf("\n[ERROR] Unable to find suitable kernel_bspline_mi_hist_jnt() configuration!\n"); exit(0); } else { // printf ("Grid [%i,%i], %d threads_per_block.\n", Grid_x, Grid_y, threads_per_block); } dim3 dimGrid1(Grid_x, Grid_y, 1); dim3 dimBlock1(threads_per_block, 1, 1); // ---------------------- // ---------------------- // ---------------------- dev_ptrs->j_hist_seg_size = dev_ptrs->j_hist_size * num_blocks; cudaMalloc ((void**)&dev_ptrs->j_hist_seg, dev_ptrs->j_hist_seg_size); cudaMemset(dev_ptrs->j_hist_seg, 0, dev_ptrs->j_hist_seg_size); CUDA_check_error ("Failed to allocate memory for j_hist_seg"); smemSize = (num_bins + 1) * sizeof(float); // Launch kernel with one thread per voxel kernel_bspline_mi_hist_jnt <<>> ( dev_ptrs->skipped_atomic, // # voxels that map outside moving dev_ptrs->j_hist_seg, // partial histogram (moving image) dev_ptrs->fixed_image, // fixed image voxels dev_ptrs->moving_image, // moving image voxels mi_hist->fixed.offset, // fixed histogram origin mi_hist->moving.offset, // moving histogram origin 1.0f/mi_hist->fixed.delta, // fixed histogram delta 1.0f/mi_hist->moving.delta, // moving histogram delta mi_hist->fixed.bins, // # fixed bins mi_hist->moving.bins, // # moving bins gbd.vox_per_rgn, // voxels per region gbd.fix_dim, // fixed image dimensions gbd.mov_dim, // moving image dimensions gbd.rdims, // region dimensions gbd.cdims, // # control points in x,y,z gbd.img_origin, // image origin gbd.img_spacing, // image spacing gbd.mov_origin, // moving image origin gbd.mov_spacing, // moving image pixel spacing gbd.roi_dim, // region dims gbd.roi_offset // region offset ); cudaThreadSynchronize(); CUDA_check_error ("kernel hist_jnt"); // Merge sub-histograms threads_per_block = 512; dim3 dimGrid2 (num_bins, 1, 1); dim3 dimBlock2 (threads_per_block, 1, 1); smemSize = 512 * sizeof(float); // this kernel can be ran with any thread-block size int num_sub_hists = num_blocks; kernel_bspline_mi_hist_merge <<>> ( dev_ptrs->j_hist, dev_ptrs->j_hist_seg, num_sub_hists ); cudaThreadSynchronize(); CUDA_check_error ("kernel hist_jnt_merge"); /* copy result back to host * -- Note CPU uses doubles whereas the GPU uses floats * due to lack of double precision floats. This is okay * since the GPU's ability to add small numbers to large * using single precision is more accurate than the CPU. * * -- However, this does result in the little bit of nastiness * found below. We copy these back to the CPU for the score * computation, which the CPU completes very quickly. */ float* j_hist_f = (float*)malloc(dev_ptrs->j_hist_size); cudaMemcpy (j_hist_f, dev_ptrs->j_hist, dev_ptrs->j_hist_size, cudaMemcpyDeviceToHost); CUDA_check_error ("Unable to copy joint histograms from GPU to CPU!\n"); /* type cast to CPU friendly double */ for (int i=0; i< mi_hist->moving.bins * mi_hist->fixed.bins; i++) { mi_hist->j_hist[i] = (double)j_hist_f[i]; } free (j_hist_f); cudaFree (dev_ptrs->j_hist_seg); CUDA_check_error ("Error freeing sub-histograms from GPU memory!"); // Get # of skipped voxels and compute num_vox unsigned int skipped; int num_vox; cudaMemcpy(&skipped, dev_ptrs->skipped_atomic, sizeof(unsigned int), cudaMemcpyDeviceToHost); num_vox = (gbd.fix_dim.x * gbd.fix_dim.y * gbd.fix_dim.z) - skipped; // Now, we back compute bin 0,0 for the joint histogram int j = 0; for (i = 1; i < mi_hist->fixed.bins * mi_hist->moving.bins; i++) { j += mi_hist->j_hist[i]; } mi_hist->j_hist[0] = num_vox - j; return num_vox; } void CUDA_bspline_mi_grad ( Bspline_state *bst, Bspline_xform *bxf, Volume* fixed, Volume* moving, float num_vox_f, float score, Dev_Pointers_Bspline *dev_ptrs ) { Joint_histogram* mi_hist = bst->get_mi_hist(); GPU_Bspline_Data gbd; build_gbd (&gbd, bxf, fixed, moving); Bspline_score* ssd = &bst->ssd; float* host_grad = ssd->curr_smetric_grad; if ((mi_hist->fixed.bins > GPU_MAX_BINS) || (mi_hist->moving.bins > GPU_MAX_BINS)) { // Initialize histogram memory on GPU // (only necessary if histograms are CPU generated) float* f_tmp = (float*)malloc(dev_ptrs->f_hist_size); float* m_tmp = (float*)malloc(dev_ptrs->m_hist_size); float* j_tmp = (float*)malloc(dev_ptrs->j_hist_size); for (int i=0; ifixed.bins; i++) { f_tmp[i] = (float)mi_hist->f_hist[i]; } for (int i=0; imoving.bins; i++) { m_tmp[i] = (float)mi_hist->m_hist[i]; } for (int i=0; ijoint.bins; i++) { j_tmp[i] = (float)mi_hist->j_hist[i]; } cudaMemcpy (dev_ptrs->f_hist, f_tmp, dev_ptrs->f_hist_size, cudaMemcpyHostToDevice); CUDA_check_error ("Unable to copy fixed histograms from CPU to GPU!\n"); cudaMemcpy (dev_ptrs->m_hist, m_tmp, dev_ptrs->m_hist_size, cudaMemcpyHostToDevice); CUDA_check_error ("Unable to copy moving histograms from CPU to GPU!\n"); cudaMemcpy (dev_ptrs->j_hist, j_tmp, dev_ptrs->j_hist_size, cudaMemcpyHostToDevice); CUDA_check_error ("Unable to copy joint histograms from CPU to GPU!\n"); free (f_tmp); free (m_tmp); free (j_tmp); } // Initial dc_dv streams cudaMemset(dev_ptrs->dc_dv_x, 0, dev_ptrs->dc_dv_x_size); CUDA_check_error("cudaMemset(): dev_ptrs->dc_dv_x"); cudaMemset(dev_ptrs->dc_dv_y, 0, dev_ptrs->dc_dv_y_size); CUDA_check_error("cudaMemset(): dev_ptrs->dc_dv_y"); cudaMemset(dev_ptrs->dc_dv_z, 0, dev_ptrs->dc_dv_z_size); CUDA_check_error("cudaMemset(): dev_ptrs->dc_dv_z"); // --- INITIALIZE GRID --- int i; int Grid_x = 0; int Grid_y = 0; int threads_per_block = 128; int num_threads = fixed->npix; int sqrt_num_blocks; int num_blocks; int found_flag = 0; // Search for a valid execution configuration // for the required # of blocks. for (threads_per_block = 192; threads_per_block > 32; threads_per_block -= 32) { num_blocks = (num_threads + threads_per_block - 1) / threads_per_block; sqrt_num_blocks = (int)sqrt((float)num_blocks); for (i = sqrt_num_blocks; i < 65535; i++) { if (num_blocks % i == 0) { Grid_x = i; Grid_y = num_blocks / Grid_x; found_flag = 1; break; } } if (found_flag == 1) { break; } } // Were we able to find a valid exec config? if (Grid_x == 0) { // If this happens we should consider falling back to a // CPU implementation, using a different CUDA algorithm, // or padding the input dc_dv stream to work with this // CUDA algorithm. printf("\n[ERROR] Unable to find suitable kernel_bspline_mi_dc_dv() configuration!\n"); exit(0); } else { #if defined (commentout) printf ("Grid [%i,%i], %d threads_per_block.\n", Grid_x, Grid_y, threads_per_block); #endif } dim3 dimGrid1(Grid_x, Grid_y, 1); dim3 dimBlock1(threads_per_block, 1, 1); int tile_padding = 64 - ((gbd.vox_per_rgn.x * gbd.vox_per_rgn.y * gbd.vox_per_rgn.z) % 64); // Launch kernel with one thread per voxel kernel_bspline_mi_dc_dv <<>> ( dev_ptrs->dc_dv_x, dev_ptrs->dc_dv_y, dev_ptrs->dc_dv_z, dev_ptrs->f_hist, dev_ptrs->m_hist, dev_ptrs->j_hist, dev_ptrs->fixed_image, dev_ptrs->moving_image, mi_hist->fixed.offset, mi_hist->moving.offset, 1.0f/mi_hist->fixed.delta, 1.0f/mi_hist->moving.delta, mi_hist->fixed.bins, mi_hist->moving.bins, gbd.vox_per_rgn, gbd.fix_dim, gbd.mov_dim, gbd.rdims, gbd.cdims, gbd.img_origin, gbd.img_spacing, gbd.mov_origin, gbd.mov_spacing, gbd.roi_dim, gbd.roi_offset, num_vox_f, score, tile_padding ); //////////////////////////////// // Prepare for the next kernel cudaThreadSynchronize(); CUDA_check_error("kernel_bspline_mi_dc_dv()"); // Clear out the condensed dc_dv streams cudaMemset(dev_ptrs->cond_x, 0, dev_ptrs->cond_x_size); CUDA_check_error("cudaMemset(): dev_ptrs->cond_x"); cudaMemset(dev_ptrs->cond_y, 0, dev_ptrs->cond_y_size); CUDA_check_error("cudaMemset(): dev_ptrs->cond_y"); cudaMemset(dev_ptrs->cond_z, 0, dev_ptrs->cond_z_size); CUDA_check_error("cudaMemset(): dev_ptrs->cond_z"); // Invoke kernel condense int num_tiles = (bxf->cdims[0]-3) * (bxf->cdims[1]-3) * (bxf->cdims[2]-3); CUDA_bspline_condense ( dev_ptrs, bxf->vox_per_rgn, num_tiles ); // Prepare for the next kernel cudaThreadSynchronize(); CUDA_check_error("kernel_bspline_condense ()"); // Clear out the gradient cudaMemset(dev_ptrs->grad, 0, dev_ptrs->grad_size); CUDA_check_error("cudaMemset(): dev_ptrs->grad"); // Invoke kernel reduce CUDA_bspline_reduce ( dev_ptrs, bxf->num_knots ); // Prepare for the next kernel cudaThreadSynchronize(); CUDA_check_error("[Kernel Panic!] kernel_bspline_mse_condense()"); // --- RETREIVE THE GRAD FROM GPU --------------------------- cudaMemcpy(host_grad, dev_ptrs->grad, sizeof(float) * bxf->num_coeff, cudaMemcpyDeviceToHost); CUDA_check_error("Failed to copy dev_ptrs->grad to CPU"); CUDA_check_error("Failed to copy dev_ptrs->grad to CPU"); // ---------------------------------------------------------- } /** * Calculates the B-spline score and gradient using CUDA implementation J. * * @param fixed The fixed volume * @param moving The moving volume * @param moving_grad The spatial gradient of the moving volume * @param bxf Pointer to the B-spline Xform * @param parms Pointer to the B-spline parameters * @param dev_ptrs Pointer the GPU device pointers * * @see CUDA_bspline_mse_score_dc_dv() * @see CUDA_bspline_condense () * @see CUDA_bspline_reduce() * * @author James A. Shackleford */ void CUDA_bspline_mse_pt1 ( Volume* fixed, Volume* moving, Volume* moving_grad, Bspline_xform* bxf, Bspline_parms* parms, Dev_Pointers_Bspline* dev_ptrs) { #if defined (PROFILE_MSE) cuda_timer my_timer; #endif // Reset our "voxels fallen outside" counter cudaMemset (dev_ptrs->skipped, 0, dev_ptrs->skipped_size); CUDA_check_error ("cudaMemset(): dev_ptrs->skipped"); cudaMemset (dev_ptrs->score, 0, dev_ptrs->score_size); CUDA_check_error ("cudaMemset(): dev_ptrs->score"); #if defined (PROFILE_MSE) CUDA_timer_start (&my_timer); #endif // Calculate the score and dc_dv CUDA_bspline_mse_score_dc_dv (dev_ptrs, bxf, fixed, moving); #if defined (PROFILE_MSE) printf("[%f ms] score & dc_dv\n", CUDA_timer_report (&my_timer)); #endif // Prepare for the next kernel cudaThreadSynchronize(); CUDA_check_error("[Kernel Panic!] kernel_bspline_g_mse_1"); // Clear out the condensed dc_dv streams cudaMemset(dev_ptrs->cond_x, 0, dev_ptrs->cond_x_size); CUDA_check_error("cudaMemset(): dev_ptrs->cond_x"); cudaMemset(dev_ptrs->cond_y, 0, dev_ptrs->cond_y_size); CUDA_check_error("cudaMemset(): dev_ptrs->cond_y"); cudaMemset(dev_ptrs->cond_z, 0, dev_ptrs->cond_z_size); CUDA_check_error("cudaMemset(): dev_ptrs->cond_z"); #if defined (PROFILE_MSE) CUDA_timer_start (&my_timer); #endif // Invoke kernel condense int num_tiles = (bxf->cdims[0]-3) * (bxf->cdims[1]-3) * (bxf->cdims[2]-3); CUDA_bspline_condense ( dev_ptrs, bxf->vox_per_rgn, num_tiles ); cudaThreadSynchronize(); CUDA_check_error("kernel_bspline_mse_condense()"); #if defined (PROFILE_MSE) printf("[%f ms] condense\n", CUDA_timer_report (&my_timer)); CUDA_timer_start (&my_timer); #endif // Clear out the gradient cudaMemset(dev_ptrs->grad, 0, dev_ptrs->grad_size); CUDA_check_error("cudaMemset(): dev_ptrs->grad"); // Invoke kernel reduce CUDA_bspline_reduce (dev_ptrs, bxf->num_knots); #if defined (PROFILE_MSE) printf("[%f ms] reduce\n\n", CUDA_timer_report (&my_timer)); #endif // Prepare for the next kernel cudaThreadSynchronize(); CUDA_check_error("[Kernel Panic!] kernel_bspline_mse_condense()"); } //////////////////////////////////////////////////////////////////////////////// // STUB: CUDA_bspline_mse_pt2 // // KERNELS INVOKED: // kernel_sum_reduction_pt1() // kernel_sum_reduction_pt2() // kernel_bspline_grad_normalize() //////////////////////////////////////////////////////////////////////////////// void CUDA_bspline_mse_pt2 ( Bspline_parms* parms, Bspline_xform* bxf, Volume* fixed, plm_long* vox_per_rgn, plm_long* volume_dim, float* host_score, float* host_grad, float* host_grad_mean, float* host_grad_norm, Dev_Pointers_Bspline* dev_ptrs, plm_long *num_vox) { #if defined (PROFILE_MSE) cuda_timer my_timer; #endif dim3 dimGrid; dim3 dimBlock; int num_elems = volume_dim[0] * volume_dim[1] * volume_dim[2]; int num_blocks = (num_elems + 511) / 512; CUDA_exec_conf_1bpe ( &dimGrid, // OUTPUT: Grid dimensions &dimBlock, // OUTPUT: Block dimensions num_blocks, // INPUT: Number of blocks 512); // INPUT: Threads per block int smemSize = 512*sizeof(float); #if defined (PROFILE_MSE) CUDA_timer_start (&my_timer); #endif // --- REDUCE SCORE VECTOR DOWN TO SINGLE VALUE ------------- kernel_sum_reduction_pt1 <<>> ( dev_ptrs->score, dev_ptrs->score, num_elems ); cudaThreadSynchronize(); CUDA_check_error("kernel_sum_reduction_pt1()"); kernel_sum_reduction_pt2 <<>> ( dev_ptrs->score, dev_ptrs->score, num_elems ); cudaThreadSynchronize(); CUDA_check_error("kernel_sum_reduction_pt2()"); // ---------------------------------------------------------- #if defined (PROFILE_MSE) printf("[%f ms] score reduction\n", CUDA_timer_report (&my_timer)); CUDA_timer_start (&my_timer); #endif // --- RETREIVE THE SCORE FROM GPU -------------------------- cudaMemcpy(host_score, dev_ptrs->score, sizeof(float), cudaMemcpyDeviceToHost); CUDA_check_error("Failed to copy score from GPU to host"); // ---------------------------------------------------------- #if defined (PROFILE_MSE) printf("[%f ms] score memcpy\n", CUDA_timer_report (&my_timer)); CUDA_timer_start (&my_timer); #endif // --- REDUCE SKIPPED VECTOR DOWN TO SINGLE VALUE ----------- kernel_sum_reduction_pt1 <<>> ( dev_ptrs->skipped, dev_ptrs->skipped, num_elems ); cudaThreadSynchronize(); CUDA_check_error("[Kernel Panic!] kernel_sum_reduction_pt1()"); kernel_sum_reduction_pt2 <<>> ( dev_ptrs->skipped, dev_ptrs->skipped, num_elems ); cudaThreadSynchronize(); CUDA_check_error("kernel_sum_reduction_pt2()"); float skipped; cudaMemcpy (&skipped, dev_ptrs->skipped, sizeof(float), cudaMemcpyDeviceToHost); // ---------------------------------------------------------- #if defined (PROFILE_MSE) printf("[%f ms] skipped reduction\n", CUDA_timer_report (&my_timer)); #endif // --- COMPUTE # VOXELS & SCORE ----------------------------- *num_vox = (volume_dim[0] * volume_dim[1] * volume_dim[2]) - skipped; *host_score = *host_score / *num_vox; // ---------------------------------------------------------- // --- COMPUTE THE GRADIENT --------------------------------- num_elems = bxf->num_coeff; num_blocks = (num_elems + 511) / 512; CUDA_exec_conf_1bpe ( &dimGrid, // OUTPUT: Grid dimensions &dimBlock, // OUTPUT: Block dimensions num_blocks, // INPUT: Number of blocks 512); // INPUT: Threads per block #if defined (PROFILE_MSE) CUDA_timer_start (&my_timer); #endif kernel_bspline_grad_normalize <<>> ( dev_ptrs->grad, *num_vox, num_elems ); cudaThreadSynchronize(); CUDA_check_error("kernel_bspline_grad_normalize()"); #if defined (PROFILE_MSE) printf("[%f ms] gradient update\n", CUDA_timer_report (&my_timer)); CUDA_timer_start (&my_timer); #endif cudaMemcpy(host_grad, dev_ptrs->grad, sizeof(float) * bxf->num_coeff, cudaMemcpyDeviceToHost); CUDA_check_error("Failed to copy dev_ptrs->grad to CPU"); #if defined (PROFILE_MSE) printf("[%f ms] gradient memcpy\n", CUDA_timer_report (&my_timer)); #endif // ---------------------------------------------------------- } ////////////////////////////////////////////////////////////////////////////// // STUB: CUDA_bspline_mse_score_dc_dv() // // KERNELS INVOKED: // kernel_bspline_mse_score_dc_dv() // // AUTHOR: James Shackleford // DATE: 19 August, 2009 ////////////////////////////////////////////////////////////////////////////// void CUDA_bspline_mse_score_dc_dv ( Dev_Pointers_Bspline* dev_ptrs, Bspline_xform* bxf, Volume* fixed, Volume* moving) { dim3 dimGrid1; dim3 dimBlock1; GPU_Bspline_Data gbd; build_gbd (&gbd, bxf, fixed, moving); CUDA_exec_conf_1tpe ( &dimGrid1, // OUTPUT: Grid dimensions &dimBlock1, // OUTPUT: Block dimensions fixed->npix, // INPUT: Total # of threads 192, // INPUT: Threads per block true); // INPUT: Is threads per block negotiable? #if defined (commentout) int smemSize = 12 * sizeof(float) * dimBlock1.x; #endif // --- BEGIN KERNEL EXECUTION --- cudaMemset(dev_ptrs->dc_dv_x, 0, dev_ptrs->dc_dv_x_size); CUDA_check_error("cudaMemset(): dev_ptrs->dc_dv_x"); cudaMemset(dev_ptrs->dc_dv_y, 0, dev_ptrs->dc_dv_y_size); CUDA_check_error("cudaMemset(): dev_ptrs->dc_dv_y"); cudaMemset(dev_ptrs->dc_dv_z, 0, dev_ptrs->dc_dv_z_size); CUDA_check_error("cudaMemset(): dev_ptrs->dc_dv_z"); int tile_padding = 64 - ((gbd.vox_per_rgn.x * gbd.vox_per_rgn.y * gbd.vox_per_rgn.z) % 64); kernel_bspline_mse_score_dc_dv <<>> ( dev_ptrs->score, dev_ptrs->skipped, dev_ptrs->dc_dv_x, dev_ptrs->dc_dv_y, dev_ptrs->dc_dv_z, dev_ptrs->fixed_image, dev_ptrs->moving_image, dev_ptrs->moving_grad, gbd.fix_dim, gbd.mov_dim, gbd.rdims, gbd.cdims, gbd.vox_per_rgn, gbd.img_origin, gbd.img_spacing, gbd.mov_origin, gbd.mov_spacing, tile_padding); } ////////////////////////////////////////////////////////////////////////////// // STUB: CUDA_bspline_condense () // // KERNELS INVOKED: // kernel_bspline_condense () // // AUTHOR: James Shackleford // DATE: September 16th, 2009 ////////////////////////////////////////////////////////////////////////////// void CUDA_bspline_condense ( Dev_Pointers_Bspline* dev_ptrs, plm_long* vox_per_rgn, int num_tiles ) { dim3 dimGrid; dim3 dimBlock; int4 vox_per_region; vox_per_region.x = (int) vox_per_rgn[0]; vox_per_region.y = (int) vox_per_rgn[1]; vox_per_region.z = (int) vox_per_rgn[2]; vox_per_region.w = (int) vox_per_region.x * vox_per_region.y * vox_per_region.z; int pad = 64 - (vox_per_region.w % 64); vox_per_region.w += pad; CUDA_exec_conf_1bpe ( &dimGrid, // OUTPUT: Grid dimensions &dimBlock, // OUTPUT: Block dimensions num_tiles, // INPUT: Number of blocks 64); // INPUT: Threads per block int smemSize = 576*sizeof(float); kernel_bspline_condense <<>> ( dev_ptrs->cond_x, // Return: condensed dc_dv_x values dev_ptrs->cond_y, // Return: condensed dc_dv_y values dev_ptrs->cond_z, // Return: condensed dc_dv_z values dev_ptrs->dc_dv_x, // Input : dc_dv_x values dev_ptrs->dc_dv_y, // Input : dc_dv_y values dev_ptrs->dc_dv_z, // Input : dc_dv_z values dev_ptrs->LUT_Offsets, // Input : tile offsets dev_ptrs->LUT_Knot, // Input : linear knot indicies pad, // Input : amount of tile padding vox_per_region, // Input : dims of tiles (float)1/6); // Input : GPU Division is slow } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // STUB: CUDA_bspline_reduce() // // KERNELS INVOKED: // kernel_bspline_reduce() // // AUTHOR: James Shackleford // DATE: 19 August, 2009 //////////////////////////////////////////////////////////////////////////////// void CUDA_bspline_reduce ( Dev_Pointers_Bspline* dev_ptrs, int num_knots ) { dim3 dimGrid; dim3 dimBlock; CUDA_exec_conf_1bpe ( &dimGrid, // OUTPUT: Grid dimensions &dimBlock, // OUTPUT: Block dimensions num_knots, // INPUT: Number of blocks 64); // INPUT: Threads per block int smemSize = 195*sizeof(float); kernel_bspline_reduce <<>> ( dev_ptrs->grad, // Return: interleaved dc_dp values dev_ptrs->cond_x, // Input : condensed dc_dv_x values dev_ptrs->cond_y, // Input : condensed dc_dv_y values dev_ptrs->cond_z // Input : condensed dc_dv_z values ); } //////////////////////////////////////////////////////////////////////////////// // JAS 2010.11.13 // waiting for the cpu to generate large vector fields after a super fast // gpu driven registration was too troublesome. this stub function is called // in the exact same fashion as the cpu equivalent, but is faster. ^_~ void CUDA_bspline_interpolate_vf ( Volume* interp, Bspline_xform* bxf ) { dim3 dimGrid; dim3 dimBlock; // Coefficient LUT // ---------------------------------------------------------- float* coeff; plm_long coeff_size = sizeof(float) * bxf->num_coeff; CUDA_alloc_copy ((void **)&coeff, (void **)&bxf->coeff, coeff_size); cudaBindTexture(0, tex_coeff, coeff, coeff_size); CUDA_check_error("Failed to bind coeff to texture reference!"); // Build B-spline LUTs & attach to textures // ---------------------------------------------------------- plm_long LUT_Bspline_x_size = 4*bxf->vox_per_rgn[0]* sizeof(float); plm_long LUT_Bspline_y_size = 4*bxf->vox_per_rgn[1]* sizeof(float); plm_long LUT_Bspline_z_size = 4*bxf->vox_per_rgn[2]* sizeof(float); float* LUT_Bspline_x_cpu = (float*)malloc(LUT_Bspline_x_size); float* LUT_Bspline_y_cpu = (float*)malloc(LUT_Bspline_y_size); float* LUT_Bspline_z_cpu = (float*)malloc(LUT_Bspline_z_size); for (int j = 0; j < 4; j++) { for (int i = 0; i < bxf->vox_per_rgn[0]; i++) { LUT_Bspline_x_cpu[j*bxf->vox_per_rgn[0] + i] = CPU_obtain_bspline_basis_function (j, i, bxf->vox_per_rgn[0]); } for (int i = 0; i < bxf->vox_per_rgn[1]; i++) { LUT_Bspline_y_cpu[j*bxf->vox_per_rgn[1] + i] = CPU_obtain_bspline_basis_function (j, i, bxf->vox_per_rgn[1]); } for (int i = 0; i < bxf->vox_per_rgn[2]; i++) { LUT_Bspline_z_cpu[j*bxf->vox_per_rgn[2] + i] = CPU_obtain_bspline_basis_function (j, i, bxf->vox_per_rgn[2]); } } float *LUT_Bspline_x, *LUT_Bspline_y, *LUT_Bspline_z; CUDA_alloc_copy ((void **)&LUT_Bspline_x, (void **)&LUT_Bspline_x_cpu, LUT_Bspline_x_size); cudaBindTexture(0, tex_LUT_Bspline_x, LUT_Bspline_x, LUT_Bspline_x_size); CUDA_alloc_copy ((void **)&LUT_Bspline_y, (void **)&LUT_Bspline_y_cpu, LUT_Bspline_y_size); cudaBindTexture(0, tex_LUT_Bspline_y, LUT_Bspline_y, LUT_Bspline_y_size); CUDA_alloc_copy ((void **)&LUT_Bspline_z, (void **)&LUT_Bspline_z_cpu, LUT_Bspline_z_size); cudaBindTexture(0, tex_LUT_Bspline_z, LUT_Bspline_z, LUT_Bspline_z_size); free (LUT_Bspline_x_cpu); free (LUT_Bspline_y_cpu); free (LUT_Bspline_z_cpu); // Get things ready for the kernel // --------------------------------------------------------------- int3 vol_dim, rdim, cdim, vpr; CUDA_array2vec_int3 (&vol_dim, interp->dim); CUDA_array2vec_int3 (&rdim, bxf->rdims); CUDA_array2vec_int3 (&cdim, bxf->cdims); CUDA_array2vec_int3 (&vpr, bxf->vox_per_rgn); plm_long vf_size = interp->npix * 3*sizeof(float); // Kernel setup & execution // --------------------------------------------------------------- int num_blocks = CUDA_exec_conf_1tpe ( &dimGrid, // OUTPUT: Grid dimensions &dimBlock, // OUTPUT: Block dimensions interp->npix, // INPUT: Total # of threads 192, // INPUT: Threads per block true); // INPUT: Is threads per block negotiable? int tpb = dimBlock.x * dimBlock.y * dimBlock.z; size_t sMemSize = tpb * 3*sizeof(float); size_t vf_gpu_size = sMemSize * num_blocks; float* vf_gpu; CUDA_alloc_zero ((void**)&vf_gpu, vf_gpu_size, cudaAllocStern); kernel_bspline_interpolate_vf <<>> ( vf_gpu, // out vol_dim, // in rdim, // in cdim, // in vpr // in ); cudaThreadSynchronize(); CUDA_check_error("kernel_bspline_interpolate_vf()"); // notice that we don't copy the "garbage" at the end of gpu memory cudaMemcpy(interp->img, vf_gpu, vf_size, cudaMemcpyDeviceToHost); CUDA_check_error("error copying vf back to CPU"); // Clean up // --------------------------------------------------------------- cudaUnbindTexture(tex_coeff); cudaUnbindTexture(tex_LUT_Bspline_x); cudaUnbindTexture(tex_LUT_Bspline_y); cudaUnbindTexture(tex_LUT_Bspline_z); cudaFree(vf_gpu); cudaFree(coeff); cudaFree(LUT_Bspline_x); cudaFree(LUT_Bspline_y); cudaFree(LUT_Bspline_z); } // generates many sub-histograms of the fixed image __global__ void kernel_bspline_mi_hist_fix ( float* f_hist_seg, // partial histogram (moving image) float* f_img, // moving image voxels float offset, // histogram offset float delta, // histogram delta long bins, // # histogram bins int3 vpr, // voxels per region int3 fdim, // fixed image dimensions int3 mdim, // moving image dimensions int3 rdim, // region dimensions int3 cdim, // # control points in x,y,z float3 img_origin, // image origin float3 img_spacing, // image spacing float3 mov_origin, // moving image origin float3 mov_ps // moving image pixel spacing ) { // -- Initialize Shared Memory ---------------------------- // Amount: 32 * # bins extern __shared__ float s_Fixed[]; for (long i=0; i < bins; i++) { s_Fixed[threadIdx.x + i*block_size] = 0.0f; } __syncthreads(); // -------------------------------------------------------- // only process threads that map to voxels if (thread_idx_global <= fdim.x * fdim.y * fdim.z) { int4 q; // Voxel index (local) int4 p; // Tile index float3 f; // Distance from origin (in mm ) float3 m; // Voxel Displacement (in mm ) float3 n; // Voxel Displacement (in vox) float3 d; // Deformation vector int fv; // fixed voxel fv = thread_idx_global; setup_indices (&p, &q, &f, fv, fdim, vpr, rdim, img_origin, img_spacing); int fell_out = find_correspondence (&d, &m, &n, f, mov_origin, mov_ps, mdim, cdim, vpr, p, q); // accumulate into segmented histograms int idx_fbin; int f_mem; idx_fbin = (int) floorf ((f_img[fv] - offset) * delta); f_mem = threadIdx.x + idx_fbin*block_size; s_Fixed[f_mem] += !fell_out; } __syncthreads(); // JAS 2010.12.08 // s_Fixed looks like this: // |<---- Bin 0 ---->|<---- Bin 1 ---->|<---- Bin 2 ---->| // +-----------------+-----------------+-----------------+ etc... // | t0 t1 t2 ... tN | t0 t1 t2 ... tN | t0 t1 t2 ... tN | // +-----------------+-----------------+-----------------+ // // Now, we want to merge the bins down to 1 value per bin from // block_size values per bin. // merge segmented histograms if (threadIdx.x < bins) { float sum = 0.0f; // Stagger the starting shared memory bank access for each thread so as // to prevent bank conflicts, which reasult in half warp difergence / // serialization. const int startPos = (threadIdx.x & 0x0F); const int offset = threadIdx.x * block_size; for (int i=0, accumPos = startPos; i < block_size; i++) { sum += s_Fixed[offset + accumPos]; if (++accumPos == block_size) { accumPos = 0; } } f_hist_seg[block_idx*bins + threadIdx.x] = sum; } // JAS 2010.12.08 // What we have done is assign a thread to each bin, but // the starting element within each bin has been staggered // to minimize shared memory bank conflicts. // // If # of bins > # of shared memory banks, conflicts will // occur, but are unavoidable and will at least be minimal. // // |<---- Bin 0 ---->|<---- Bin 1 ---->|<---- Bin 2 ---->| // +-----------------+-----------------+-----------------+ etc... // | t0 t1 t2 ... tN | t0 t1 t2 ... tN | t0 t1 t2 ... tN | // +-----------------+-----------------+-----------------+ // ^ ^ ^ // | t0 start | t1 start | t2 start // // Note here that theadsPerBlock must be a multiple of the // # of shared memory banks for this to work. Either 16 // or 32 for 1.X and 2.X compute capability devices, respectively. // // // Output to global memory is: // |<---- Sub 0 ---->|<---- Sub 1 ---->|<---- Sub 2 ---->| // +-----------------+-----------------+-----------------+ etc... // | b0 b1 b2 ... bN | b0 b1 b2 ... bN | b0 b1 b2 ... bN | // +-----------------+-----------------+-----------------+ // // ...many histograms of non-overlapping image subregions. // Sum up the sub-histograms to get the total image histogram. // There are num_thread_blocks sub-histograms to merge, which // is done by a subsequent kernel. } // generates many sub-histograms of the moving image // this kernel uses an 8-neighborhood partial volume interpolation __global__ void kernel_bspline_mi_hist_mov ( float* m_hist_seg, // partial histogram (moving image) float* m_img, // moving image voxels float offset, // histogram offset float delta, // histogram delta long bins, // # histogram bins int3 vpr, // voxels per region int3 fdim, // fixed image dimensions int3 mdim, // moving image dimensions int3 rdim, // region dimensions int3 cdim, // # control points in x,y,z float3 img_origin, // image origin float3 img_spacing, // image spacing float3 mov_origin, // moving image offset float3 mov_ps // moving image pixel spacing ) { // initialize shared memory // -------------------------------------------------------- // Amount: 32 * # bins extern __shared__ float s_Moving[]; for (long i=0; i < bins; i++) { s_Moving[threadIdx.x + i*block_size] = 0.0f; } // -------------------------------------------------------- __syncthreads(); // only process threads that map to voxels // -------------------------------------------------------- if (thread_idx_global <= fdim.x * fdim.y * fdim.z) { int4 q; // Voxel index (local) int4 p; // Tile index float3 f; // Distance from origin (in mm ) float3 m; // Voxel Displacement (in mm ) float3 n; // Voxel Displacement (in vox) int3 n_f; // Voxel Displacement floor int3 n_r; // Voxel Displacement round float3 d; // Deformation vector int fv; // fixed voxel fv = thread_idx_global; setup_indices (&p, &q, &f, fv, fdim, vpr, rdim, img_origin, img_spacing); int fell_out = find_correspondence (&d, &m, &n, f, mov_origin, mov_ps, mdim, cdim, vpr, p, q); if (!fell_out) { float3 li_1, li_2; clamp_linear_interpolate_3d (&n, &n_f, &n_r, &li_1, &li_2, mdim); int nn[8]; get_nearest_neighbors (nn, n_f, mdim); float w[8]; get_weights (w, li_1, li_2); // (a.k.a. partial volumes) // Accumulate Into Segmented Histograms int idx_mbin, m_mem; #pragma unroll for (int i=0; i<8; i++) { idx_mbin = (int) floorf ((m_img[nn[i]] - offset) * delta); m_mem = threadIdx.x + idx_mbin*block_size; s_Moving[m_mem] += w[i]; } } } // -------------------------------------------------------- __syncthreads(); // merge segmented histograms // -------------------------------------------------------- if (threadIdx.x < bins) { float sum = 0.0f; // Stagger the starting shared memory bank access for each thread so as // to prevent bank conflicts, which reasult in half warp difergence / // serialization. const int startPos = (threadIdx.x & 0x0F); const int offset = threadIdx.x * block_size; for (int i=0, accumPos = startPos; i < block_size; i++) { sum += s_Moving[offset + accumPos]; if (++accumPos == block_size) { accumPos = 0; } } m_hist_seg[block_idx*bins + threadIdx.x] = sum; } // -------------------------------------------------------- // Done. // We now have (num_thread_blocks) partial histograms that need to be // merged. This will be done with another kernel to be ran immediately // following the completion of this kernel. } //////////////////////////////////////////////////////////////////////////////// // Generates the joint histogram // // --- Neightborhood of 8 --- // //////////////////////////////////////////////////////////////////////////////// __global__ void kernel_bspline_mi_hist_jnt ( unsigned int* skipped, // OUTPUT: # of skipped voxels float* j_hist, // OUTPUT: joint histogram float* f_img, // INPUT: fixed image voxels float* m_img, // INPUT: moving image voxels float f_offset, // INPUT: fixed histogram offset float m_offset, // INPUT: moving histogram offset float f_delta, // INPUT: fixed histogram delta float m_delta, // INPUT: moving histogram delta long f_bins, // INPUT: # fixed histogram bins long m_bins, // INPUT: # moving histogram bins int3 vpr, // INPUT: voxels per region int3 fdim, // INPUT: fixed image dimensions int3 mdim, // INPUT: moving image dimensions int3 rdim, // INPUT: region dimensions int3 cdim, // INPUT: # control points in x,y,z float3 img_origin, // INPUT: image origin float3 img_spacing, // INPUT: image spacing float3 mov_origin, // INPUT: moving image offset float3 mov_ps, // INPUT: moving image pixel spacing int3 roi_dim, // INPUT: ROI dimensions int3 roi_offset // INPUT: ROI Offset ) { /* This code requires compute capability 1.2 or greater. * DO NOT compile it for lesser target architectures or * nvcc will complain and stop the build; thus the #if */ #if defined (__CUDA_ARCH__) && __CUDA_ARCH__ >= 120 // -- Initial shared memory for locks --------------------- extern __shared__ float shared_mem[]; float* j_locks = (float*)shared_mem; int total_smem = f_bins * m_bins; shared_memset (shared_mem, 0.0f, total_smem); // -------------------------------------------------------- long j_bins; // # of joint histogram bins j_bins = f_bins * m_bins; // -- Only process threads that map to voxels ------------- if (thread_idx_global <= fdim.x * fdim.y * fdim.z) { int4 q; // Voxel index (local) int4 p; // Tile index float3 f; // Distance from origin (in mm ) float3 m; // Voxel Displacement (in mm ) float3 n; // Voxel Displacement (in vox) float3 d; // Deformation vector int3 n_f; // Voxel Displacement floor int3 n_r; // Voxel Displacement round int fv; // fixed voxel fv = thread_idx_global; setup_indices (&p, &q, &f, fv, fdim, vpr, rdim, img_origin, img_spacing); int fell_out = find_correspondence (&d, &m, &n, f, mov_origin, mov_ps, mdim, cdim, vpr, p, q); // did the voxel map into the moving image? if (fell_out) { atomicAdd (skipped, 1); } else { float3 li_1, li_2; clamp_linear_interpolate_3d (&n, &n_f, &n_r, &li_1, &li_2, mdim); int nn[8]; get_nearest_neighbors (nn, n_f, mdim); float w[8]; get_weights (w, li_1, li_2); // (a.k.a. partial volumes) // -- Read from histograms and compute dC/dp_j * dp_j/dv -- int idx_fbin, offset_fbin; int idx_mbin; int idx_jbin; // Calculate fixed bin offset into joint idx_fbin = (int) floorf ((f_img[fv] - f_offset) * f_delta); offset_fbin = idx_fbin * m_bins; // Maybe one day nvcc will be smart enough to honor this pragma... // regardless, manual unrolling doesn't offer any visible speedup #pragma unroll for (int i=0; i<8; i++) { idx_mbin = (int) floorf ((m_img[nn[i]] - m_offset) * m_delta); idx_jbin = offset_fbin + idx_mbin; if (idx_jbin != 0) { atomic_add_float (&j_locks[idx_jbin], w[i]); } } } } __syncthreads(); // copy histogram segments from shared to global memory int idx; long j_stride = block_idx * j_bins; int chunks = (j_bins + block_size - 1)/block_size; for (int i=0; i> Each thread-block is responsible for a bin number. // // >> A thread-block will use multiple threads to pull down // multiple partial histogram bin values in parallel. // // >> Because there are many more partial histograms than threads, // the threads in a thread-block will have to iterate through // all of the partial histograms using a for-loop. // // >> The # of for-loop iterations is equal to the number of // partial histograms divided by the number of threads in a block. // // >> Therefore, this kernel should be launched with: // // -- num_seg_hist % num_threads = 0 (num_seg_hist % blockDim.x = 0) // -- num_blocks = num_bins // // >> This means that a search must be executed to find the largest # // of threads that can fit within the number of partial histograms // we have. This will exhibit the largest amount of parallelism. // //////////////////////////////////////////////////////////////////////////////// __global__ void kernel_bspline_mi_hist_merge ( float *f_hist, float *f_hist_seg, long num_seg_hist ) { extern __shared__ float data[]; float sum = 0.0f; // -- Work through all the sub-histograms ------------------------ for (long i = threadIdx.x; i < num_seg_hist; i += blockDim.x) { sum += f_hist_seg[blockIdx.x + i * gridDim.x]; } data[threadIdx.x] = sum; // --------------------------------------------------------------- __syncthreads(); // -- Sum all of the thread sums for this bin -------------------- for (long s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { data[threadIdx.x] += data[threadIdx.x + s]; } __syncthreads(); } // --------------------------------------------------------------- // -- Write the final bin value to Global ------------------------ if (threadIdx.x == 0) { f_hist[blockIdx.x] = data[0]; } // --------------------------------------------------------------- // Done. } //////////////////////////////////////////////////////////////////////////////// // Computes dC/dv for MI using PVI-8 interpolation // // --- Neightborhood of 8 --- // //////////////////////////////////////////////////////////////////////////////// __global__ void kernel_bspline_mi_dc_dv ( float* dc_dv_x, // OUTPUT: dC / dv (x-component) float* dc_dv_y, // OUTPUT: dC / dv (y-component) float* dc_dv_z, // OUTPUT: dC / dv (z-component) float* f_hist, // INPUT: fixed histogram float* m_hist, // INPUT: moving histogram float* j_hist, // INPUT: joint histogram float* f_img, // INPUT: fixed image voxels float* m_img, // INPUT: moving image voxels float f_offset, // INPUT: fixed histogram offset float m_offset, // INPUT: moving histogram offset float f_delta, // INPUT: fixed histogram delta float m_delta, // INPUT: moving histogram delta long f_bins, // INPUT: # fixed histogram bins long m_bins, // INPUT: # moving histogram bins int3 vpr, // INPUT: voxels per region int3 fdim, // INPUT: fixed image dimensions int3 mdim, // INPUT: moving image dimensions int3 rdim, // INPUT: region dimensions int3 cdim, // INPUT: # control points in x,y,z float3 img_origin, // INPUT: image origin float3 img_spacing, // INPUT: image spacing float3 mov_origin, // INPUT: moving image offset float3 mov_ps, // INPUT: moving image pixel spacing int3 roi_dim, // INPUT: ROI dimensions int3 roi_offset, // INPUT: ROI Offset float num_vox_f, // INPUT: # of voxels float score, // INPUT: evaluated MI cost function int pad // INPUT: Tile padding ) { // -- Only process threads that map to voxels ------------- if (thread_idx_global > fdim.x * fdim.y * fdim.z) { return; } // -------------------------------------------------------- // -------------------------------------------------------- int3 r; // Voxel index (global) int4 q; // Voxel index (local) int4 p; // Tile index float3 f; // Distance from origin (in mm ) float3 m; // Voxel Displacement (in mm ) float3 n; // Voxel Displacement (in vox) float3 d; // Deformation vector int3 n_f; // Voxel Displacement floor int3 n_r; // Voxel Displacement round int fv; // fixed voxel // -------------------------------------------------------- fv = thread_idx_global; r.z = fv / (fdim.x * fdim.y); r.y = (fv - (r.z * fdim.x * fdim.y)) / fdim.x; r.x = fv - r.z * fdim.x * fdim.y - (r.y * fdim.x); setup_indices (&p, &q, &f, fv, fdim, vpr, rdim, img_origin, img_spacing); if (r.x > (roi_offset.x + roi_dim.x) || r.y > (roi_offset.y + roi_dim.y) || r.z > (roi_offset.z + roi_dim.z)) { return; } int fell_out = find_correspondence (&d, &m, &n, f, mov_origin, mov_ps, mdim, cdim, vpr, p, q); if (fell_out) { return; } float3 li_1, li_2; clamp_linear_interpolate_3d (&n, &n_f, &n_r, &li_1, &li_2, mdim); int nn[8]; get_nearest_neighbors (nn, n_f, mdim); float3 dw[8]; get_weight_derivatives (dw, li_1, li_2); // (a.k.a. partial volumes) __syncthreads(); // -- Read from histograms and compute dC/dp_j * dp_j/dv -- float dS_dP; float3 dc_dv; int idx_fbin, offset_fbin; int idx_mbin; int idx_jbin; float ht = 0.000001f; dc_dv.x = 0.0f; dc_dv.y = 0.0f; dc_dv.z = 0.0f; idx_fbin = (int) floorf ((f_img[fv] - f_offset) * f_delta); offset_fbin = idx_fbin * m_bins; // JAS 2010.11.13 // nvcc is unable too honor "#pragma unroll" due to the conditional. // Unrolling gives somewhat significant speed up for compute < 2.0 devices // and a barely noticable speed up for 2.0 devices. #if defined (commentout) #pragma unroll for (int i=0; i<8; i++) { idx_mbin = (int) floorf ((m_img[nn[i]] - m_offset) * m_delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > ht && f_hist[idx_fbin] > ht && m_hist[idx_mbin] > ht) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - score; dc_dv.x -= dw[i].x * dS_dP; dc_dv.y -= dw[i].y * dS_dP; dc_dv.z -= dw[i].z * dS_dP; } } #endif // PV w1 idx_mbin = (int) floorf ((m_img[nn[0]] - m_offset) * m_delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > ht && f_hist[idx_fbin] > ht && m_hist[idx_mbin] > ht) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - score; dc_dv.x -= dw[0].x * dS_dP; dc_dv.y -= dw[0].y * dS_dP; dc_dv.z -= dw[0].z * dS_dP; } // PV w2 idx_mbin = (int) floorf ((m_img[nn[1]] - m_offset) * m_delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > ht && f_hist[idx_fbin] > ht && m_hist[idx_mbin] > ht) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - score; dc_dv.x -= dw[1].x * dS_dP; dc_dv.y -= dw[1].y * dS_dP; dc_dv.z -= dw[1].z * dS_dP; } // PV w3 idx_mbin = (int) floorf ((m_img[nn[2]] - m_offset) * m_delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > ht && f_hist[idx_fbin] > ht && m_hist[idx_mbin] > ht) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - score; dc_dv.x -= dw[2].x * dS_dP; dc_dv.y -= dw[2].y * dS_dP; dc_dv.z -= dw[2].z * dS_dP; } // PV w4 idx_mbin = (int) floorf ((m_img[nn[3]] - m_offset) * m_delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > ht && f_hist[idx_fbin] > ht && m_hist[idx_mbin] > ht) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - score; dc_dv.x -= dw[3].x * dS_dP; dc_dv.y -= dw[3].y * dS_dP; dc_dv.z -= dw[3].z * dS_dP; } // PV w5 idx_mbin = (int) floorf ((m_img[nn[4]] - m_offset) * m_delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > ht && f_hist[idx_fbin] > ht && m_hist[idx_mbin] > ht) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - score; dc_dv.x -= dw[4].x * dS_dP; dc_dv.y -= dw[4].y * dS_dP; dc_dv.z -= dw[4].z * dS_dP; } // PV w6 idx_mbin = (int) floorf ((m_img[nn[5]] - m_offset) * m_delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > ht && f_hist[idx_fbin] > ht && m_hist[idx_mbin] > ht) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - score; dc_dv.x -= dw[5].x * dS_dP; dc_dv.y -= dw[5].y * dS_dP; dc_dv.z -= dw[5].z * dS_dP; } // PV w7 idx_mbin = (int) floorf ((m_img[nn[6]] - m_offset) * m_delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > ht && f_hist[idx_fbin] > ht && m_hist[idx_mbin] > ht) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - score; dc_dv.x -= dw[6].x * dS_dP; dc_dv.y -= dw[6].y * dS_dP; dc_dv.z -= dw[6].z * dS_dP; } // PV w8 idx_mbin = (int) floorf ((m_img[nn[7]] - m_offset) * m_delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > ht && f_hist[idx_fbin] > ht && m_hist[idx_mbin] > ht) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - score; dc_dv.x -= dw[7].x * dS_dP; dc_dv.y -= dw[7].y * dS_dP; dc_dv.z -= dw[7].z * dS_dP; } #if defined (commentout) #endif // -------------------------------------------------------- // -- Convert from voxels to mm --------------------------- dc_dv.x = dc_dv.x / mov_ps.x / num_vox_f; dc_dv.y = dc_dv.y / mov_ps.y / num_vox_f; dc_dv.z = dc_dv.z / mov_ps.z / num_vox_f; // -------------------------------------------------------- __syncthreads(); // -- Finally, write out dc_dv ---------------------------- float* dc_dv_element_x; float* dc_dv_element_y; float* dc_dv_element_z; dc_dv_element_x = &dc_dv_x[((vpr.x * vpr.y * vpr.z) + pad) * p.w]; dc_dv_element_y = &dc_dv_y[((vpr.x * vpr.y * vpr.z) + pad) * p.w]; dc_dv_element_z = &dc_dv_z[((vpr.x * vpr.y * vpr.z) + pad) * p.w]; dc_dv_element_x = &dc_dv_element_x[q.w]; dc_dv_element_y = &dc_dv_element_y[q.w]; dc_dv_element_z = &dc_dv_element_z[q.w]; dc_dv_element_x[0] = dc_dv.x; dc_dv_element_y[0] = dc_dv.y; dc_dv_element_z[0] = dc_dv.z; // -------------------------------------------------------- } /* JAS 05.27.2010 * * This kernel was written as an intended replacement for * bspline_cuda_score_j_mse_kernel1(). The intended goal * was to produce a kernel with neater notation and code * structure that also shared the LUT_Bspline_x,y,z textured * lookup table that is utilized by the hyper-fast gradient * kernel kernel_bspline_condense (). * * It should be noted that the LUT_Bspline texture differs * from the CPU based q_lut in both structure and philosophy. * LUT_Bspline is three separate look-up-tables which contain * the pre-computed basis function values in each dimension, * whereas the q_lut has already pre-multiplied all of these * results. For the GPU, the q-LUT requires in too many memory * load operations, even when employing the cacheing mechanisms * provided by textures. The LUT_Bspline textures rely on the GPU * to perform these multiplications, thus achieving superior * run times. * * This code was authored with the intention of unifying the * design philosophy of the MSE B-spline GPU implementation, * which was spurred by my attempts to write the upcoming * GPU Gems 4 chapter. * * The code now also shares more similarities with * the CPU code. So, now if you know one you know the other. * * This is about 6.5% faster (on my GTX 285) than * bspline_cuda_score_j_mse_kernel1() */ __global__ void kernel_bspline_mse_score_dc_dv ( float* score, // OUTPUT float* skipped, // OUTPUT float* dc_dv_x, // OUTPUT float* dc_dv_y, // OUTPUT float* dc_dv_z, // OUTPUT float* f_img, // fixed image voxels float* m_img, // moving image voxels float* m_grad, // moving image gradient int3 fdim, // fixed image dimensions int3 mdim, // moving image dimensions int3 rdim, // region dimensions int3 cdim, // # control points in x,y,z int3 vpr, // voxels per region float3 img_origin, // image origin float3 img_spacing, // image spacing float3 mov_origin, // moving image offset float3 mov_ps, // moving image pixel spacing int pad // tile padding ) { /* Only process threads that map to voxels */ if (thread_idx_global > fdim.x * fdim.y * fdim.z) { return; } int4 p; // Tile index int4 q; // Local Voxel index (within tile) float3 f; // Distance from origin (in mm ) float3 m; // Voxel Displacement (in mm ) float3 n; // Voxel Displacement (in vox) int3 n_f; // Voxel Displacement floor int3 n_r; // Voxel Displacement round float3 d; // Deformation vector int fv; // fixed voxel fv = thread_idx_global; setup_indices (&p, &q, &f, fv, fdim, vpr, rdim, img_origin, img_spacing); int fell_out = find_correspondence (&d, &m, &n, f, mov_origin, mov_ps, mdim, cdim, vpr, p, q); if (fell_out) { skipped[fv]++; return; } float3 li_1, li_2; clamp_linear_interpolate_3d (&n, &n_f, &n_r, &li_1, &li_2, mdim); float m_val = get_moving_value (n_f, mdim, li_1, li_2); float diff = m_val - f_img[fv]; score[fv] = diff * diff; write_dc_dv (dc_dv_x, dc_dv_y, dc_dv_z, m_grad, diff, n_r, mdim, vpr, pad, p, q); } /** * This kernel partially computes the gradient by generating condensed dc_dv values. * * @warning It is required that input data tiles be aligned to 64 byte boundaries. * * @see CUDA_pad_64() * @see kernel_pad_64() * * @param cond_x Pointer to condensed dc_dv x-values * @param cond_y Pointer to condensed dc_dv y-values * @param cond_z Pointer to condensed dc_dv z-values * @param dc_dv_x Pointer to dc_dv x-values * @param dc_dv_y Pointer to dc_dv y-values * @param dc_dv_z Pointer to dc_dv z-values * @param LUT_Tile_Offsets Pointer to offset lookup table * @param LUT_Knot Pointer to linear knot indices * @param pad Amount of tile padding, in bytes * @param tile_dim Dimensions of input volume tiles * @param one_over_six The value 1/6 * * @author: James A. Shackleford */ __global__ void kernel_bspline_condense ( float* cond_x, // Return: condensed dc_dv_x values float* cond_y, // Return: condensed dc_dv_y values float* cond_z, // Return: condensed dc_dv_z values float* dc_dv_x, // Input : dc_dv_x values float* dc_dv_y, // Input : dc_dv_y values float* dc_dv_z, // Input : dc_dv_z values int* LUT_Tile_Offsets, // Input : tile offsets int* LUT_Knot, // Input : linear knot indicies int pad, // Input : amount of tile padding int4 tile_dim, // Input : dims of tiles float one_over_six) // Input : Precomputed (GPU division is slow) { int tileOffset; int voxel_cluster; int voxel_idx; float3 voxel_val; int3 voxel_loc; int4 tile_pos; float A,B,C; // -- Setup Shared Memory --------------------------------- // -- SIZE: 9*64*sizeof(float) // -------------------------------------------------------- extern __shared__ float sdata[]; float* sBuffer_x = (float*)sdata; // sBuffer_x[64] float* sBuffer_y = (float*)&sBuffer_x[64]; // sBuffer_y[64] float* sBuffer_z = (float*)&sBuffer_y[64]; // sBuffer_z[64] float* sBuffer_redux_x = (float*)&sBuffer_z[64]; // sBuffer_redux_x[64] float* sBuffer_redux_y = (float*)&sBuffer_redux_x[64]; // sBuffer_redux_y[64] float* sBuffer_redux_z = (float*)&sBuffer_redux_y[64]; // sBuffer_redux_z[64] float* sBuffer_redux_x2 = (float*)&sBuffer_redux_z[64]; // sBuffer_redux_x2[64] float* sBuffer_redux_y2 = (float*)&sBuffer_redux_x2[64];// sBuffer_redux_y2[64] float* sBuffer_redux_z2 = (float*)&sBuffer_redux_y2[64];// sBuffer_redux_z2[64] // -------------------------------------------------------- // Clear Shared Memory!! sBuffer_x[threadIdx.x] = 0.0f; sBuffer_y[threadIdx.x] = 0.0f; sBuffer_z[threadIdx.x] = 0.0f; // First, get the offset of where our tile starts in memory. tileOffset = LUT_Tile_Offsets[block_idx]; // Main Loop for Warp Work // (Here we condense a tile into 64x3 floats) for (voxel_cluster=0; voxel_cluster < tile_dim.w; voxel_cluster+=64) { // ---------------------------------------------------------- // STAGE 1 IN POWERPOINT // ---------------------------------------------------------- // Second, we pulldown the current voxel cluster. // Each thread in the warp pulls down 1 voxel (3 values) // ---------------------------------------------------------- voxel_val.x = dc_dv_x[tileOffset + voxel_cluster + threadIdx.x]; voxel_val.y = dc_dv_y[tileOffset + voxel_cluster + threadIdx.x]; voxel_val.z = dc_dv_z[tileOffset + voxel_cluster + threadIdx.x]; // ---------------------------------------------------------- // Third, find the [x,y,z] location within the current tile // for the voxel this thread is processing. voxel_idx = (voxel_cluster + threadIdx.x); voxel_loc.z = voxel_idx / (tile_dim.x * tile_dim.y); voxel_loc.y = (voxel_idx - (voxel_loc.z * tile_dim.x * tile_dim.y)) / tile_dim.x; voxel_loc.x = voxel_idx - voxel_loc.z * tile_dim.x * tile_dim.y - (voxel_loc.y * tile_dim.x); // Fourth, we will perform all 64x3 calculations on the current voxel cluster. // (Every thead in the warp will be doing this at the same time for its voxel) tile_pos.w = 0; // Current tile position within [0,63] for (tile_pos.z = 0; tile_pos.z < 4; tile_pos.z++) { C = tex1Dfetch(tex_LUT_Bspline_z, tile_pos.z * tile_dim.z + voxel_loc.z); for (tile_pos.y = 0; tile_pos.y < 4; tile_pos.y++) { B = C * tex1Dfetch(tex_LUT_Bspline_y, tile_pos.y * tile_dim.y + voxel_loc.y); tile_pos.x = 0; // #### FIRST HALF #### // --------------------------------------------------------------------------------- // Do the 1st two x-positions out of four using our two // blocks of shared memory for reduction // Calculate the b-spline multiplier for this voxel @ this tile // position relative to a given control knot. // --------------------------------------------------------------------------------- A = B * tex1Dfetch(tex_LUT_Bspline_x, tile_pos.x * tile_dim.x + voxel_loc.x); // Perform the multiplication and store to redux shared memory sBuffer_redux_x[threadIdx.x] = voxel_val.x * A; sBuffer_redux_y[threadIdx.x] = voxel_val.y * A; sBuffer_redux_z[threadIdx.x] = voxel_val.z * A; tile_pos.x++; // Calculate the b-spline multiplier for this voxel @ the next tile // position relative to a given control knot. A = B * tex1Dfetch(tex_LUT_Bspline_x, tile_pos.x * tile_dim.x + voxel_loc.x); // Perform the multiplication and store to redux shared memory // for the second position sBuffer_redux_x2[threadIdx.x] = voxel_val.x * A; sBuffer_redux_y2[threadIdx.x] = voxel_val.y * A; sBuffer_redux_z2[threadIdx.x] = voxel_val.z * A; __syncthreads(); // --------------------------------------------------------------------------------- // --------------------------------------------------------------------------------- // All 64 dc_dv values in the current cluster have been processed // for the current 2 tile positions (out of 64 total tile positions). // We now perform a sum reduction on these 64 dc_dv values to // condense the data down to one value. // --------------------------------------------------------------------------------- if (threadIdx.x < 32) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 32]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 32]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 32]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 32]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 32]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 32]; } __syncthreads(); if (threadIdx.x < 16) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 16]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 16]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 16]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 16]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 16]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 16]; } __syncthreads(); if (threadIdx.x < 8) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 8]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 8]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 8]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 8]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 8]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 8]; } __syncthreads(); if (threadIdx.x < 4) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 4]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 4]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 4]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 4]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 4]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 4]; } __syncthreads(); if (threadIdx.x < 2) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 2]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 2]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 2]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 2]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 2]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 2]; } __syncthreads(); if (threadIdx.x < 1) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 1]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 1]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 1]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 1]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 1]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 1]; } __syncthreads(); // --------------------------------------------------------------------------------- // --------------------------------------------------------------------------------- // We then accumulate this single condensed value into the element of // shared memory that correlates to the current tile position. // --------------------------------------------------------------------------------- if (threadIdx.x == 0) { sBuffer_x[tile_pos.w] += sBuffer_redux_x[0]; sBuffer_y[tile_pos.w] += sBuffer_redux_y[0]; sBuffer_z[tile_pos.w] += sBuffer_redux_z[0]; tile_pos.w++; sBuffer_x[tile_pos.w] += sBuffer_redux_x2[0]; sBuffer_y[tile_pos.w] += sBuffer_redux_y2[0]; sBuffer_z[tile_pos.w] += sBuffer_redux_z2[0]; tile_pos.w++; } __syncthreads(); // --------------------------------------------------------------------------------- // #### SECOND HALF #### // --------------------------------------------------------------------------------- // Do the 2nd two x-positions out of four using our two // blocks of shared memory for reduction // --------------------------------------------------------------------------------- tile_pos.x++; A = B * tex1Dfetch(tex_LUT_Bspline_x, tile_pos.x * tile_dim.x + voxel_loc.x); // Perform the multiplication and store to redux shared memory sBuffer_redux_x[threadIdx.x] = voxel_val.x * A; sBuffer_redux_y[threadIdx.x] = voxel_val.y * A; sBuffer_redux_z[threadIdx.x] = voxel_val.z * A; tile_pos.x++; // Calculate the b-spline multiplier for this voxel @ the next tile // position relative to a given control knot. A = B * tex1Dfetch(tex_LUT_Bspline_x, tile_pos.x * tile_dim.x + voxel_loc.x); // Perform the multiplication and store to redux shared memory // for the second position sBuffer_redux_x2[threadIdx.x] = voxel_val.x * A; sBuffer_redux_y2[threadIdx.x] = voxel_val.y * A; sBuffer_redux_z2[threadIdx.x] = voxel_val.z * A; __syncthreads(); // --------------------------------------------------------------------------------- // --------------------------------------------------------------------------------- // All 64 dc_dv values in the current cluster have been processed // for the current 2 tile positions (out of 64 total tile positions). // // We now perform a sum reduction on these 64 dc_dv values to // condense the data down to one value. // --------------------------------------------------------------------------------- if (threadIdx.x < 32) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 32]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 32]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 32]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 32]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 32]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 32]; } __syncthreads(); if (threadIdx.x < 16) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 16]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 16]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 16]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 16]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 16]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 16]; } __syncthreads(); if (threadIdx.x < 8) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 8]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 8]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 8]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 8]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 8]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 8]; } __syncthreads(); if (threadIdx.x < 4) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 4]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 4]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 4]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 4]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 4]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 4]; } __syncthreads(); if (threadIdx.x < 2) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 2]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 2]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 2]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 2]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 2]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 2]; } __syncthreads(); if (threadIdx.x < 1) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + 1]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + 1]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + 1]; sBuffer_redux_x2[threadIdx.x] += sBuffer_redux_x2[threadIdx.x + 1]; sBuffer_redux_y2[threadIdx.x] += sBuffer_redux_y2[threadIdx.x + 1]; sBuffer_redux_z2[threadIdx.x] += sBuffer_redux_z2[threadIdx.x + 1]; } __syncthreads(); // --------------------------------------------------------------------------------- // --------------------------------------------------------------------------------- // We then accumulate this single condensed value into the element of // shared memory that correlates to the current tile position. // --------------------------------------------------------------------------------- if (threadIdx.x == 0) { sBuffer_x[tile_pos.w] += sBuffer_redux_x[0]; sBuffer_y[tile_pos.w] += sBuffer_redux_y[0]; sBuffer_z[tile_pos.w] += sBuffer_redux_z[0]; tile_pos.w++; sBuffer_x[tile_pos.w] += sBuffer_redux_x2[0]; sBuffer_y[tile_pos.w] += sBuffer_redux_y2[0]; sBuffer_z[tile_pos.w] += sBuffer_redux_z2[0]; tile_pos.w++; } __syncthreads(); // --------------------------------------------------------------------------------- } } // LOOP: 64 B-Spline Values for current voxel_cluster } // LOOP: voxel_clusters // ---------------------------------------------------------- // STAGE 3 IN POWERPOINT // ---------------------------------------------------------- // By this point every voxel cluster within the tile has been // processed for every possible tile position (there are 64). // ---------------------------------------------------------- // HERE, EACH WARP OPERATES ON A SINGLE TILE'S SET OF 64!! // ---------------------------------------------------------- tileOffset = 64*block_idx; tile_pos.x = 63 - threadIdx.x; int knot_num; knot_num = LUT_Knot[tileOffset + threadIdx.x]; cond_x[ (64*knot_num) + tile_pos.x ] = sBuffer_x[threadIdx.x]; cond_y[ (64*knot_num) + tile_pos.x ] = sBuffer_y[threadIdx.x]; cond_z[ (64*knot_num) + tile_pos.x ] = sBuffer_z[threadIdx.x]; // ---------------------------------------------------------- // Done with tile. // END OF KERNEL } //////////////////////////////////////////////////////////////////////////////// // KERNEL: kernel_bspline_reduce() // // * Each threadblock contains only 2 warps. // * Each threadblock operates on 32 knots (1 at a time) // // * Each knot in a condense stream contains 64 single precision floats // * Each knot is spread across the 3 condense streams [x,y,z] // * The "high warp" will handle floats 32-63 // * The "low warp" will handle floats 0-31 // // * The 2 warps will work together to sum reduce the 64 floats to 1 float // * The sum reduction result is stored in shared memory // // AUTHOR: James Shackleford // DATE : August 27th, 2009 //////////////////////////////////////////////////////////////////////////////// __global__ void kernel_bspline_reduce ( float* grad, // Return: interleaved dc_dp values float* cond_x, // Input : condensed dc_dv_x values float* cond_y, // Input : condensed dc_dv_y values float* cond_z) // Input : condensed dc_dv_z values { // -- Setup Shared Memory --------------------------------- // -- SIZE: ((3*64)+3)*sizeof(float) // -------------------------------------------------------- extern __shared__ float sdata[]; float* sBuffer = (float*)sdata; // sBuffer[3] float* sBuffer_redux_x = (float*)&sBuffer[3]; // sBuffer_redux_x[64] float* sBuffer_redux_y = (float*)&sBuffer_redux_x[64]; // sBuffer_redux_y[64] float* sBuffer_redux_z = (float*)&sBuffer_redux_y[64]; // sBuffer_redux_z[64] // -------------------------------------------------------- // Pull down the 64 condensed dc_dv values for the knot this warp pair is working on sBuffer_redux_x[threadIdx.x] = cond_x[64*block_idx + threadIdx.x]; sBuffer_redux_y[threadIdx.x] = cond_y[64*block_idx + threadIdx.x]; sBuffer_redux_z[threadIdx.x] = cond_z[64*block_idx + threadIdx.x]; // This thread barrier is very important! __syncthreads(); // Perform sum reduction on the 64 condensed dc_dv values for(unsigned int s = 32; s > 0; s >>= 1) { if (threadIdx.x < s) { sBuffer_redux_x[threadIdx.x] += sBuffer_redux_x[threadIdx.x + s]; sBuffer_redux_y[threadIdx.x] += sBuffer_redux_y[threadIdx.x + s]; sBuffer_redux_z[threadIdx.x] += sBuffer_redux_z[threadIdx.x + s]; } // Wait for all threads in to complete the current tier. __syncthreads(); } // Store 3 resulting floats into the output buffer (shared memory) // These 3 floats are the dc_dp value [x,y,z] for the current knot // This shared memory store is interleaved so that the final global // memory store will be coalaced. if (threadIdx.x == 0) { sBuffer[0] = sBuffer_redux_x[0]; } if (threadIdx.x == 1) { sBuffer[1] = sBuffer_redux_y[0]; } if (threadIdx.x == 2) { sBuffer[2] = sBuffer_redux_z[0]; } // Prevent read before write race condition __syncthreads(); if (threadIdx.x < 3) { grad[3*block_idx + threadIdx.x] = sBuffer[threadIdx.x]; } } // This kernel normalizes each of the gradient values by the // number of voxels before the final gradient sum reduction. __global__ void kernel_bspline_grad_normalize ( float *grad, int num_vox, int num_elems ) { if (thread_idx_global < num_elems) { grad[thread_idx_global] = 2.0 * grad[thread_idx_global] / num_vox; } } // JAS 2010.11.13 // waiting for the cpu to generate large vector fields after a super fast // gpu driven registration was too troublesome. this kernel function allows // us to also generate vector fields with the gpu. much faster on my machine. __global__ void kernel_bspline_interpolate_vf ( float* vf, // OUTPUT int3 fdim, // fixed image dimensions int3 rdim, // region dimensions int3 cdim, // # control points in x,y,z int3 vpr // voxels per region ) { extern __shared__ float shared_mem[]; /* Only process threads that map to voxels */ if (thread_idx_global <= fdim.x * fdim.y * fdim.z) { int4 p; // Tile index int4 q; // Local Voxel index (within tile) float3 f; // Distance from origin (in mm ) float3 d; // Deformation vector int fv; // fixed voxel float3 null = {0.0f, 0.0f, 0.0f}; fv = thread_idx_global; setup_indices (&p, &q, &f, fv, fdim, vpr, rdim, null, null); bspline_interpolate (&d, cdim, vpr, p, q); shared_mem[3*threadIdx.x + 0] = d.x; shared_mem[3*threadIdx.x + 1] = d.y; shared_mem[3*threadIdx.x + 2] = d.z; } __syncthreads(); stog_memcpy (vf, shared_mem, 3*block_size); } // This kernel will reduce a stream to a single value. It will work for // a stream with an arbitrary number of elements. It is the same as // bspline_cuda_compute_score_kernel, with the exception that it assumes // all values in the stream are valid and should be included in the final // reduced value. __global__ void kernel_sum_reduction_pt1 ( float *idata, float *odata, int num_elems ) { // Shared memory is allocated on a per block basis. Therefore, only allocate // (sizeof(data) * blocksize) memory when calling the kernel. extern __shared__ float sdata[]; // Load data into shared memory. if (thread_idx_global >= num_elems) { sdata[thread_idx_local] = 0.0; } else { sdata[thread_idx_local] = idata[thread_idx_global]; } // Wait for all threads in the block to reach this point. __syncthreads(); // Perform the reduction in shared memory. Stride over the block and reduce // parts until it is down to a single value (stored in sdata[0]). for (unsigned int s = block_size / 2; s > 0; s >>= 1) { if (thread_idx_local < s) { sdata[thread_idx_local] += sdata[thread_idx_local + s]; } // Wait for all threads to complete this stride. __syncthreads(); } // Write the result for this block back to global memory. if (thread_idx_local == 0) { odata[thread_idx_global] = sdata[0]; } } // This kernel sums together the remaining partial sums that are created // by kernel_sum_reduction_pt1() __global__ void kernel_sum_reduction_pt2 ( float *idata, float *odata, int num_elems ) { if (thread_idx_global == 0) { float sum = 0.0; for(int i = 0; i < num_elems; i += block_size) { sum += idata[i]; } odata[0] = sum; } } // This function overwries the coefficient LUT to the GPU global memory with // the new coefficient LUT generated by the optimizer in preparation for the // next iteration. void CUDA_bspline_push_coeff (Dev_Pointers_Bspline* dev_ptrs, Bspline_xform* bxf) { // Copy the coefficient LUT to the GPU. cudaMemcpy(dev_ptrs->coeff, bxf->coeff, dev_ptrs->coeff_size, cudaMemcpyHostToDevice); CUDA_check_error("Failed to copy coefficients to GPU"); } // This function sets all elements in the score (located on the GPU) to zero in // preparation for the next iteration of the kernel. extern "C" void CUDA_bspline_zero_score (Dev_Pointers_Bspline* dev_ptrs) { cudaMemset(dev_ptrs->score, 0, dev_ptrs->score_size); CUDA_check_error("Failed to clear the score stream on GPU\n"); } // This function sets all elemtns in the gradients (located on the GPU) to // zero in preparation for the next iteration of the kernel. extern "C" void CUDA_bspline_zero_grad (Dev_Pointers_Bspline* dev_ptrs) { cudaMemset(dev_ptrs->grad, 0, dev_ptrs->grad_size); CUDA_check_error("Failed to clear the grad stream on GPU\n"); } //////////////////////////////////////////////////////////////////////////////// // FUNCTION: CPU_obtain_bspline_basis_function() // // AUTHOR: James Shackleford // DATE : 09.04.2009 //////////////////////////////////////////////////////////////////////////////// float CPU_obtain_bspline_basis_function ( int t_idx, int vox_idx, int vox_per_rgn) { float i = (float)vox_idx / vox_per_rgn; float C; switch(t_idx) { case 0: C = (1.0/6.0) * (- 1.0 * i*i*i + 3.0 * i*i - 3.0 * i + 1.0); break; case 1: C = (1.0/6.0) * (+ 3.0 * i*i*i - 6.0 * i*i + 4.0); break; case 2: C = (1.0/6.0) * (- 3.0 * i*i*i + 3.0 * i*i + 3.0 * i + 1.0); break; case 3: C = (1.0/6.0) * (+ 1.0 * i*i*i); break; default: C = 0.0; break; } return C; } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // FUNCTION: CPU_calc_offsets() // // This function accepts the number or voxels per control region // and the dimensions of the control grid to generate where the linear // memory offsets lie for the beginning of each tile in a 32-byte // aligned tile-major data organization scheme (such as that which // is produced by kernel_row_to_tile_major(). // // Author: James Shackleford // Data: July 30th, 2009 //////////////////////////////////////////////////////////////////////////////// int* CPU_calc_offsets (plm_long* tile_dims, plm_long* cdims) { int vox_per_tile = (tile_dims[0] * tile_dims[1] * tile_dims[2]); int pad = 32 - (vox_per_tile % 32); int num_tiles = (cdims[0]-3)*(cdims[1]-3)*(cdims[2]-3); int* output = (int*)malloc(num_tiles*sizeof(int)); int i; for(i = 0; i < num_tiles; i++) output[i] = (vox_per_tile + pad) * i; return output; } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // FUNCTION: CPU_find_knots() // // This function takes a tile index as an input and generates // the indicies of the 64 control knots that it affects. // // Inputs: // rdims[3] - The number of regions in (x,y,x) // (i.e. bxf->rdims) [See: bspline_xform.h] // // cdims[3] - The number of control points in (x,y,x) // (i.e. bxf->cdims) [See: bspline_xform.h] // // tile_num - The tile index of interest -- is affected by 64 local // control points (knots). // // Returns: // knots[idx] - idx is [0,63] and is the index of a local control point // affecting tile_num. knots[idx] holds the global index // of the control point specified by time_num & idx. // // Author: James Shackleford // Data: July 13th, 2009 //////////////////////////////////////////////////////////////////////////////// void CPU_find_knots(int* knots, int tile_num, plm_long* rdims, plm_long* cdims) { int tile_loc[3]; int i, j, k; int idx = 0; int num_tiles_x = cdims[0] - 3; int num_tiles_y = cdims[1] - 3; int num_tiles_z = cdims[2] - 3; // First get the [x,y,z] coordinate of // the tile in the control grid. tile_loc[0] = tile_num % num_tiles_x; tile_loc[1] = ((tile_num - tile_loc[0]) / num_tiles_x) % num_tiles_y; tile_loc[2] = ((((tile_num - tile_loc[0]) / num_tiles_x) / num_tiles_y) % num_tiles_z); /* tile_loc[0] = tile_num % rdims[0]; tile_loc[1] = ((tile_num - tile_loc[0]) / rdims[0]) % rdims[1]; tile_loc[2] = ((((tile_num - tile_loc[0]) / rdims[0]) / rdims[1]) % rdims[2]); */ // Tiles do not start on the edges of the grid, so we // push them to the center of the control grid. tile_loc[0]++; tile_loc[1]++; tile_loc[2]++; // Find 64 knots' [x,y,z] coordinates // and convert into a linear knot index for (k = -1; k < 3; k++) for (j = -1; j < 3; j++) for (i = -1; i < 3; i++) { knots[idx++] = (cdims[0]*cdims[1]*(tile_loc[2]+k)) + (cdims[0]*(tile_loc[1]+j)) + (tile_loc[0]+i); } } //////////////////////////////////////////////////////////////////////////////// __device__ inline void clamp_linear_interpolate_3d ( float3* n, int3* n_f, int3* n_r, float3* li_1, float3* li_2, int3 mdim ) { /* x-dimension */ n_f->x = (int) floorf (n->x); n_r->x = (int) rintf (n->x); li_2->x = n->x - n_f->x; if (n_f->x < 0) { n_f->x = 0; n_r->x = 0; li_2->x = 0.0f; } else if (n_f->x >= (mdim.x - 1)) { n_f->x = mdim.x - 2; n_r->x = mdim.x - 1; li_2->x = 1.0f; } li_1->x = 1.0f - li_2->x; /* y-dimension */ n_f->y = (int) floorf (n->y); n_r->y = (int) rintf (n->y); li_2->y = n->y - n_f->y; if (n_f->y < 0) { n_f->y = 0; n_r->y = 0; li_2->y = 0.0f; } else if (n_f->y >= (mdim.y - 1)) { n_f->y = mdim.y - 2; n_r->y = mdim.y - 1; li_2->y = 1.0f; } li_1->y = 1.0f - li_2->y; /* z-dimension */ n_f->z = (int) floorf (n->z); n_r->z = (int) rintf (n->z); li_2->z = n->z - n_f->z; if (n_f->z < 0) { n_f->z = 0; n_r->z = 0; li_2->z = 0.0f; } else if (n_f->z >= (mdim.z - 1)) { n_f->z = mdim.z - 2; n_r->z = mdim.z - 1; li_2->z = 1.0f; } li_1->z = 1.0f - li_2->z; } __device__ inline int find_correspondence ( float3 *d, float3 *m, float3 *n, float3 f, float3 mov_origin, float3 mov_ps, int3 mdim, int3 cdim, int3 vpr, int4 p, int4 q ) { // -- Get the deformation vector d ------------------------ bspline_interpolate (d, cdim, vpr, p, q); // -- Correspondence -------------------------------------- m->x = f.x + d->x; // Displacement in mm m->y = f.y + d->y; m->z = f.z + d->z; // Displacement in voxels n->x = (m->x - mov_origin.x) / mov_ps.x; n->y = (m->y - mov_origin.y) / mov_ps.y; n->z = (m->z - mov_origin.z) / mov_ps.z; if (n->x < -0.5 || n->x > mdim.x - 0.5 || n->y < -0.5 || n->y > mdim.y - 0.5 || n->z < -0.5 || n->z > mdim.z - 0.5) { return 1; } return 0; // -------------------------------------------------------- } __device__ inline float get_moving_value ( int3 n_f, int3 mdim, float3 li_1, float3 li_2 ) { // -- Compute coordinates of 8 nearest neighbors ---------- int nn[8]; get_nearest_neighbors (nn, n_f, mdim); // -------------------------------------------------------- // -- Compute Moving Image Intensity ---------------------- float w[8]; get_weights (w, li_1, li_2); w[0] *= tex1Dfetch(tex_moving_image, nn[0]); w[1] *= tex1Dfetch(tex_moving_image, nn[1]); w[2] *= tex1Dfetch(tex_moving_image, nn[2]); w[3] *= tex1Dfetch(tex_moving_image, nn[3]); w[4] *= tex1Dfetch(tex_moving_image, nn[4]); w[5] *= tex1Dfetch(tex_moving_image, nn[5]); w[6] *= tex1Dfetch(tex_moving_image, nn[6]); w[7] *= tex1Dfetch(tex_moving_image, nn[7]); return w[0] + w[1] + w[2] + w[3] + w[4] + w[5] + w[6] + w[7]; // -------------------------------------------------------- } __device__ inline void setup_indices ( int4 *p, int4 *q, float3 *f, int fv, int3 fdim, int3 vpr, int3 rdim, float3 img_origin, float3 img_spacing ) { /* Setup Global Voxel Indices */ int3 r; // Voxel index (global) r.z = fv / (fdim.x * fdim.y); r.y = (fv - (r.z * fdim.x * fdim.y)) / fdim.x; r.x = fv - r.z * fdim.x * fdim.y - (r.y * fdim.x); /* Setup Tile Indicies */ p->x = r.x / vpr.x; p->y = r.y / vpr.y; p->z = r.z / vpr.z; p->w = ((p->z * rdim.y + p->y) * rdim.x) + p->x; /* Setup Local Voxel Indices */ q->x = r.x - p->x * vpr.x; q->y = r.y - p->y * vpr.y; q->z = r.z - p->z * vpr.z; q->w = ((q->z * vpr.y + q->y) * vpr.x) + q->x; /* Set up fixed image coordinates (mm) */ f->x = img_origin.x + img_spacing.x * r.x; f->y = img_origin.y + img_spacing.y * r.y; f->z = img_origin.z + img_spacing.z * r.z; } __device__ inline void write_dc_dv ( float* dc_dv_x, float* dc_dv_y, float* dc_dv_z, float* m_grad, float diff, int3 n_r, int3 mdim, int3 vpr, int pad, int4 p, int4 q ) { float* m_grad_element; float* dc_dv_element_x; float* dc_dv_element_y; float* dc_dv_element_z; m_grad_element = &m_grad[3 * n_r.z * mdim.y * mdim.x]; m_grad_element = &m_grad_element[3 * n_r.y * mdim.x]; m_grad_element = &m_grad_element[3 * n_r.x]; dc_dv_element_x = &dc_dv_x[((vpr.x * vpr.y * vpr.z) + pad) * p.w]; dc_dv_element_y = &dc_dv_y[((vpr.x * vpr.y * vpr.z) + pad) * p.w]; dc_dv_element_z = &dc_dv_z[((vpr.x * vpr.y * vpr.z) + pad) * p.w]; dc_dv_element_x = &dc_dv_element_x[q.w]; dc_dv_element_y = &dc_dv_element_y[q.w]; dc_dv_element_z = &dc_dv_element_z[q.w]; dc_dv_element_x[0] = diff * m_grad_element[0]; dc_dv_element_y[0] = diff * m_grad_element[1]; dc_dv_element_z[0] = diff * m_grad_element[2]; } __device__ inline void get_nearest_neighbors ( int* nn, int3 n_f, int3 mdim ) { nn[0] = (n_f.z * mdim.y + n_f.y) * mdim.x + n_f.x; nn[1] = nn[0] + 1; nn[2] = nn[0] + mdim.x; nn[3] = nn[0] + mdim.x + 1; nn[4] = nn[0] + mdim.x * mdim.y; nn[5] = nn[0] + mdim.x * mdim.y + 1; nn[6] = nn[0] + mdim.x * mdim.y + mdim.x; nn[7] = nn[0] + mdim.x * mdim.y + mdim.x + 1; } __device__ inline void get_weights ( float* w, float3 li_1, float3 li_2 ) { w[0] = li_1.x * li_1.y * li_1.z; w[1] = li_2.x * li_1.y * li_1.z; w[2] = li_1.x * li_2.y * li_1.z; w[3] = li_2.x * li_2.y * li_1.z; w[4] = li_1.x * li_1.y * li_2.z; w[5] = li_2.x * li_1.y * li_2.z; w[6] = li_1.x * li_2.y * li_2.z; w[7] = li_2.x * li_2.y * li_2.z; } __device__ inline void get_weight_derivatives ( float3* dw, float3 li_1, float3 li_2 ) { dw[0].x = -1.0f * li_1.y * li_1.z; dw[0].y = li_1.x * -1.0f * li_1.z; dw[0].z = li_1.x * li_1.y * -1.0f; dw[1].x = +1.0f * li_1.y * li_1.z; dw[1].y = li_2.x * -1.0f * li_1.z; dw[1].z = li_2.x * li_1.y * -1.0f; dw[2].x = -1.0f * li_2.y * li_1.z; dw[2].y = li_1.x * +1.0f * li_1.z; dw[2].z = li_1.x * li_2.y * -1.0f; dw[3].x = +1.0f * li_2.y * li_1.z; dw[3].y = li_2.x * +1.0f * li_1.z; dw[3].z = li_2.x * li_2.y * -1.0f; dw[4].x = -1.0f * li_1.y * li_2.z; dw[4].y = li_1.x * -1.0f * li_2.z; dw[4].z = li_1.x * li_1.y * +1.0f; dw[5].x = +1.0f * li_1.y * li_2.z; dw[5].y = li_2.x * -1.0f * li_2.z; dw[5].z = li_2.x * li_1.y * +1.0f; dw[6].x = -1.0f * li_2.y * li_2.z; dw[6].y = li_1.x * +1.0f * li_2.z; dw[6].z = li_1.x * li_2.y * +1.0f; dw[7].x = +1.0f * li_2.y * li_2.z; dw[7].y = li_2.x * +1.0f * li_2.z; dw[7].z = li_2.x * li_2.y * +1.0f; } __device__ inline void bspline_interpolate ( float3* d, int3 cdim, int3 vpr, int4 p, int4 q ) { int i, j, k, z, cidx; double A,B,C,P; d->x = 0.0f; d->y = 0.0f; d->z = 0.0f; z = 0; for (k = 0; k < 4; k++) { C = tex1Dfetch (tex_LUT_Bspline_z, k * vpr.z + q.z); for (j = 0; j < 4; j++) { B = tex1Dfetch (tex_LUT_Bspline_y, j * vpr.y + q.y); for (i = 0; i < 4; i++) { A = tex1Dfetch (tex_LUT_Bspline_x, i * vpr.x + q.x); P = A * B * C; cidx = 3 * ((p.z + k) * cdim.x * cdim.y + (p.y + j) * cdim.x + (p.x + i)); d->x += P * tex1Dfetch (tex_coeff, cidx + 0); d->y += P * tex1Dfetch (tex_coeff, cidx + 1); d->z += P * tex1Dfetch (tex_coeff, cidx + 2); z++; } } } } // JAS 11.04.2010 // nvcc has the limitation of not being able to use // functions from other object files. So in order // to share device functions, we resort to this. :-/ #include "cuda_kernel_util.inc" bspline_cuda.cxx000066400000000000000000000652031321604176500324620ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #define PLM_CUDA_COMPILE 1 #include "plmregister_config.h" #include #include #include #include #if defined (_WIN32) #include #endif #include "bspline.h" #if (CUDA_FOUND) #include "bspline_cuda.h" #include "cuda_util.h" #endif #include "bspline_correspond.h" #include "bspline_interpolate.h" #include "bspline_optimize.h" #include "bspline_parms.h" #include "bspline_state.h" #include "bspline_xform.h" #include "compiler_warnings.h" #include "interpolate.h" #include "interpolate_macros.h" #include "logfile.h" #include "plm_math.h" #include "volume.h" #include "volume_macros.h" /*********************************************************************** * A few of the CPU functions are reproduced here for testing purposes. * Once the CPU code is removed from the functions below, these * functions can be deleted. ***********************************************************************/ // #define ROUND_INT(x) ((x)>=0?(long)((x)+0.5):(long)(-(-(x)+0.5))) // JAS 2010.11.23 // Sorry about this... these functions are reproductions of stuff that lives in // bspline.c These common functions will need to be eventually moved to their // own object in order for linking to work nicely for shared libs... // (like the CUDA plugin) #if defined (PLM_USE_GPU_PLUGINS) void clamp_linear_interpolate ( float ma, /* Input: (Unrounded) pixel coordinate (in vox) */ int dmax, /* Input: Maximum coordinate in this dimension */ int* maf, /* Output: x, y, or z coord of "floor" pixel in moving img */ int* mar, /* Output: x, y, or z coord of "round" pixel in moving img */ float* fa1, /* Output: Fraction of interpolant for lower index voxel */ float* fa2 /* Output: Fraction of interpolant for upper index voxel */ ) { float maff = floor(ma); *maf = (int) maff; *mar = ROUND_INT (ma); *fa2 = ma - maff; if (*maf < 0) { *maf = 0; *mar = 0; *fa2 = 0.0f; } else if (*maf >= dmax) { *maf = dmax - 1; *mar = dmax; *fa2 = 1.0f; } *fa1 = 1.0f - *fa2; } void bspline_interp_pix_b ( float out[3], Bspline_xform* bxf, plm_long pidx, plm_long qidx ) { plm_long i, j, k, m; plm_long cidx; float* q_lut = &bxf->q_lut[qidx*64]; plm_long* c_lut = &bxf->c_lut[pidx*64]; out[0] = out[1] = out[2] = 0; m = 0; for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cidx = 3 * c_lut[m]; out[0] += q_lut[m] * bxf->coeff[cidx+0]; out[1] += q_lut[m] * bxf->coeff[cidx+1]; out[2] += q_lut[m] * bxf->coeff[cidx+2]; m ++; } } } } int bspline_find_correspondence ( float *mxyz, /* Output: xyz coordinates in moving image (mm) */ float *mijk, /* Output: ijk indices in moving image (vox) */ const float *fxyz, /* Input: xyz coordinates in fixed image (mm) */ const float *dxyz, /* Input: displacement from fixed to moving (mm) */ const Volume *moving /* Input: moving image */ ) { mxyz[0] = fxyz[0] + dxyz[0]; mijk[0] = (mxyz[0] - moving->origin[0]) / moving->spacing[0]; if (mijk[0] < -0.5 || mijk[0] > moving->dim[0] - 0.5) return 0; mxyz[1] = fxyz[1] + dxyz[1]; mijk[1] = (mxyz[1] - moving->origin[1]) / moving->spacing[1]; if (mijk[1] < -0.5 || mijk[1] > moving->dim[1] - 0.5) return 0; mxyz[2] = fxyz[2] + dxyz[2]; mijk[2] = (mxyz[2] - moving->origin[2]) / moving->spacing[2]; if (mijk[2] < -0.5 || mijk[2] > moving->dim[2] - 0.5) return 0; return 1; } #endif static inline void bspline_mi_hist_add_pvi_8 ( Joint_histogram* mi_hist, Volume *fixed, Volume *moving, int fv, int mvf, float li_1[3], /* Fraction of interpolant in lower index */ float li_2[3]) /* Fraction of interpolant in upper index */ { float w1, w2, w3, w4, w5, w6, w7, w8; int n1, n2, n3, n4, n5, n6, n7, n8; int idx_fbin, idx_mbin, idx_jbin; int offset_fbin; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; double *f_hist = mi_hist->f_hist; double *m_hist = mi_hist->m_hist; double *j_hist = mi_hist->j_hist; w1 = li_1[0] * li_1[1] * li_1[2]; // Partial Volume w1 w2 = li_2[0] * li_1[1] * li_1[2]; // Partial Volume w2 w3 = li_1[0] * li_2[1] * li_1[2]; // Partial Volume w3 w4 = li_2[0] * li_2[1] * li_1[2]; // Partial Volume w4 w5 = li_1[0] * li_1[1] * li_2[2]; // Partial Volume w5 w6 = li_2[0] * li_1[1] * li_2[2]; // Partial Volume w6 w7 = li_1[0] * li_2[1] * li_2[2]; // Partial Volume w7 w8 = li_2[0] * li_2[1] * li_2[2]; // Partial Volume w8 // Note that Sum(wN) for N within [1,8] should = 1 (checked OK) // Calculate Point Indices for 8 neighborhood n1 = mvf; n2 = n1 + 1; n3 = n1 + moving->dim[0]; n4 = n1 + moving->dim[0] + 1; n5 = n1 + moving->dim[0]*moving->dim[1]; n6 = n1 + moving->dim[0]*moving->dim[1] + 1; n7 = n1 + moving->dim[0]*moving->dim[1] + moving->dim[0]; n8 = n1 + moving->dim[0]*moving->dim[1] + moving->dim[0] + 1; // Calculate fixed histogram bin and increment it idx_fbin = floor ((f_img[fv] - mi_hist->fixed.offset) / mi_hist->fixed.delta); f_hist[idx_fbin]++; offset_fbin = idx_fbin * mi_hist->moving.bins; // Add PV w1 to moving & joint histograms idx_mbin = floor ((m_img[n1] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; m_hist[idx_mbin] += w1; j_hist[idx_jbin] += w1; // Add PV w2 to moving & joint histograms idx_mbin = floor ((m_img[n2] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; m_hist[idx_mbin] += w2; j_hist[idx_jbin] += w2; // Add PV w3 to moving & joint histograms idx_mbin = floor ((m_img[n3] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; m_hist[idx_mbin] += w3; j_hist[idx_jbin] += w3; // Add PV w4 to moving & joint histograms idx_mbin = floor ((m_img[n4] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; m_hist[idx_mbin] += w4; j_hist[idx_jbin] += w4; // Add PV w5 to moving & joint histograms idx_mbin = floor ((m_img[n5] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; m_hist[idx_mbin] += w5; j_hist[idx_jbin] += w5; // Add PV w6 to moving & joint histograms idx_mbin = floor ((m_img[n6] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; m_hist[idx_mbin] += w6; j_hist[idx_jbin] += w6; // Add PV w7 to moving & joint histograms idx_mbin = floor ((m_img[n7] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; m_hist[idx_mbin] += w7; j_hist[idx_jbin] += w7; // Add PV w8 to moving & joint histograms idx_mbin = floor ((m_img[n8] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; m_hist[idx_mbin] += w8; j_hist[idx_jbin] += w8; } static inline void bspline_mi_pvi_8_dc_dv ( float dc_dv[3], /* Output */ Joint_histogram* mi_hist, /* Input */ Bspline_state *bst, /* Input */ Volume *fixed, /* Input */ Volume *moving, /* Input */ int fv, /* Input */ int mvf, /* Input */ float mijk[3], /* Input */ float num_vox_f, /* Input */ float li_1[3], /* Input */ float li_2[3] /* Input */ ) { float dS_dP; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; Bspline_score* ssd = &bst->ssd; int n1, n2, n3, n4, n5, n6, n7, n8; int idx_fbin, idx_mbin, idx_jbin; int offset_fbin; float dw1[3], dw2[3], dw3[3], dw4[3], dw5[3], dw6[3], dw7[3], dw8[3]; dc_dv[0] = dc_dv[1] = dc_dv[2] = 0.0f; // Calculate Point Indices for 8 neighborhood n1 = mvf; n2 = n1 + 1; n3 = n1 + moving->dim[0]; n4 = n1 + moving->dim[0] + 1; n5 = n1 + moving->dim[0]*moving->dim[1]; n6 = n1 + moving->dim[0]*moving->dim[1] + 1; n7 = n1 + moving->dim[0]*moving->dim[1] + moving->dim[0]; n8 = n1 + moving->dim[0]*moving->dim[1] + moving->dim[0] + 1; // Pre-compute differential PV slices dw1[0] = ( -1 ) * li_1[1] * li_1[2]; dw1[1] = li_1[0] * ( -1 ) * li_1[2]; dw1[2] = li_1[0] * li_1[1] * ( -1 ); dw2[0] = ( +1 ) * li_1[1] * li_1[2]; dw2[1] = li_2[0] * ( -1 ) * li_1[2]; dw2[2] = li_2[0] * li_1[1] * ( -1 ); dw3[0] = ( -1 ) * li_2[1] * li_1[2]; dw3[1] = li_1[0] * ( +1 ) * li_1[2]; dw3[2] = li_1[0] * li_2[1] * ( -1 ); dw4[0] = ( +1 ) * li_2[1] * li_1[2]; dw4[1] = li_2[0] * ( +1 ) * li_1[2]; dw4[2] = li_2[0] * li_2[1] * ( -1 ); dw5[0] = ( -1 ) * li_1[1] * li_2[2]; dw5[1] = li_1[0] * ( -1 ) * li_2[2]; dw5[2] = li_1[0] * li_1[1] * ( +1 ); dw6[0] = ( +1 ) * li_1[1] * li_2[2]; dw6[1] = li_2[0] * ( -1 ) * li_2[2]; dw6[2] = li_2[0] * li_1[1] * ( +1 ); dw7[0] = ( -1 ) * li_2[1] * li_2[2]; dw7[1] = li_1[0] * ( +1 ) * li_2[2]; dw7[2] = li_1[0] * li_2[1] * ( +1 ); dw8[0] = ( +1 ) * li_2[1] * li_2[2]; dw8[1] = li_2[0] * ( +1 ) * li_2[2]; dw8[2] = li_2[0] * li_2[1] * ( +1 ); // Fixed image voxel's histogram index idx_fbin = floor ((f_img[fv] - mi_hist->fixed.offset) / mi_hist->fixed.delta); offset_fbin = idx_fbin * mi_hist->moving.bins; // Partial Volume w1's Contribution idx_mbin = floor ((m_img[n1] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > 0.0001) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric; dc_dv[0] -= dw1[0] * dS_dP; dc_dv[1] -= dw1[1] * dS_dP; dc_dv[2] -= dw1[2] * dS_dP; } // Partial Volume w2 idx_mbin = floor ((m_img[n2] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > 0.0001) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric; dc_dv[0] -= dw2[0] * dS_dP; dc_dv[1] -= dw2[1] * dS_dP; dc_dv[2] -= dw2[2] * dS_dP; } // Partial Volume w3 idx_mbin = floor ((m_img[n3] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > 0.0001) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric; dc_dv[0] -= dw3[0] * dS_dP; dc_dv[1] -= dw3[1] * dS_dP; dc_dv[2] -= dw3[2] * dS_dP; } // Partial Volume w4 idx_mbin = floor ((m_img[n4] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > 0.0001) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric; dc_dv[0] -= dw4[0] * dS_dP; dc_dv[1] -= dw4[1] * dS_dP; dc_dv[2] -= dw4[2] * dS_dP; } // Partial Volume w5 idx_mbin = floor ((m_img[n5] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > 0.0001) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric; dc_dv[0] -= dw5[0] * dS_dP; dc_dv[1] -= dw5[1] * dS_dP; dc_dv[2] -= dw5[2] * dS_dP; } // Partial Volume w6 idx_mbin = floor ((m_img[n6] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > 0.0001) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric; dc_dv[0] -= dw6[0] * dS_dP; dc_dv[1] -= dw6[1] * dS_dP; dc_dv[2] -= dw6[2] * dS_dP; } // Partial Volume w7 idx_mbin = floor ((m_img[n7] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > 0.0001) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric; dc_dv[0] -= dw7[0] * dS_dP; dc_dv[1] -= dw7[1] * dS_dP; dc_dv[2] -= dw7[2] * dS_dP; } // Partial Volume w8 idx_mbin = floor ((m_img[n8] - mi_hist->moving.offset) / mi_hist->moving.delta); idx_jbin = offset_fbin + idx_mbin; if (j_hist[idx_jbin] > 0.0001) { dS_dP = logf((num_vox_f * j_hist[idx_jbin]) / (f_hist[idx_fbin] * m_hist[idx_mbin])) - ssd->curr_smetric; dc_dv[0] -= dw8[0] * dS_dP; dc_dv[1] -= dw8[1] * dS_dP; dc_dv[2] -= dw8[2] * dS_dP; } dc_dv[0] = dc_dv[0] / num_vox_f / moving->spacing[0]; dc_dv[1] = dc_dv[1] / num_vox_f / moving->spacing[1]; dc_dv[2] = dc_dv[2] / num_vox_f / moving->spacing[2]; } #if defined (MI_GRAD_CPU) inline void bspline_update_grad_b_inline (Bspline_state* bst, Bspline_xform* bxf, int pidx, int qidx, float dc_dv[3]) { Bspline_score* ssd = &bst->ssd; int i, j, k, m; int cidx; float* q_lut = &bxf->q_lut[qidx*64]; int* c_lut = &bxf->c_lut[pidx*64]; m = 0; for (k = 0; k < 4; k++) { for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { cidx = 3 * c_lut[m]; ssd->grad[cidx+0] += dc_dv[0] * q_lut[m]; ssd->grad[cidx+1] += dc_dv[1] * q_lut[m]; ssd->grad[cidx+2] += dc_dv[2] * q_lut[m]; m ++; } } } } #endif #if defined (commentout) static void display_hist_totals (Joint_histogram *mi_hist) { plm_long i; double tmp = 0; for (i=0, tmp=0; i < mi_hist->fixed.bins; i++) { tmp += mi_hist->f_hist[i]; } printf ("f_hist total: %f\n", tmp); for (i=0, tmp=0; i < mi_hist->moving.bins; i++) { tmp += mi_hist->m_hist[i]; } printf ("m_hist total: %f\n", tmp); for (i=0, tmp=0; i < mi_hist->moving.bins * mi_hist->fixed.bins; i++) { tmp += mi_hist->j_hist[i]; } printf ("j_hist total: %f\n", tmp); } #endif //////////////////////////////////////////////////////////////////////////////// size_t CPU_MI_Hist (Joint_histogram *mi_hist, // OUTPUT: Histograms Bspline_xform *bxf, // INPUT: Bspline X-Form Volume* fixed, // INPUT: Fixed Image Volume* moving) // INPUT: Moving Image { plm_long rijk[3]; plm_long fijk[3]; plm_long fv; plm_long p[3]; plm_long q[3]; float fxyz[3]; plm_long pidx, qidx; float dxyz[3]; float mxyz[3]; float mijk[3]; plm_long mijk_f[3]; // floor: mijk plm_long mijk_r[3]; // round: mijk plm_long mvf; // floor: mv float li_1[3]; float li_2[3]; plm_long num_vox = 0; for (rijk[2] = 0, fijk[2] = bxf->roi_offset[2]; rijk[2] < bxf->roi_dim[2]; rijk[2]++, fijk[2]++) { p[2] = rijk[2] / bxf->vox_per_rgn[2]; q[2] = rijk[2] % bxf->vox_per_rgn[2]; fxyz[2] = bxf->img_origin[2] + bxf->img_spacing[2] * fijk[2]; for (rijk[1] = 0, fijk[1] = bxf->roi_offset[1]; rijk[1] < bxf->roi_dim[1]; rijk[1]++, fijk[1]++) { p[1] = rijk[1] / bxf->vox_per_rgn[1]; q[1] = rijk[1] % bxf->vox_per_rgn[1]; fxyz[1] = bxf->img_origin[1] + bxf->img_spacing[1] * fijk[1]; for (rijk[0] = 0, fijk[0] = bxf->roi_offset[0]; rijk[0] < bxf->roi_dim[0]; rijk[0]++, fijk[0]++) { int rc; p[0] = rijk[0] / bxf->vox_per_rgn[0]; q[0] = rijk[0] % bxf->vox_per_rgn[0]; fxyz[0] = bxf->img_origin[0] + bxf->img_spacing[0] * fijk[0]; // Get B-spline deformation vector pidx = volume_index (bxf->rdims, p); qidx = volume_index (bxf->vox_per_rgn, q); bspline_interp_pix_b (dxyz, bxf, pidx, qidx); // Find correspondence in moving image rc = bspline_find_correspondence_dcos (mxyz, mijk, fxyz, dxyz, moving); // If voxel is not inside moving image if (!rc) continue; // Compute tri-linear interpolation weights li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); // Find linear index of fixed image voxel fv = volume_index (fixed->dim, fijk); // Find linear index of "corner voxel" in moving image mvf = volume_index (moving->dim, mijk_f); // PARTIAL VALUE INTERPOLATION - 8 neighborhood bspline_mi_hist_add_pvi_8 (mi_hist, fixed, moving, fv, mvf, li_1, li_2); // Increment the voxel count num_vox ++; } } } return num_vox; } //////////////////////////////////////////////////////////////////////////////// static float CPU_MI_Score (Joint_histogram* mi_hist, int num_vox) { double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; plm_long i, j, v; double fnv = (double) num_vox; double score = 0; float hist_thresh = 0.001 / (mi_hist->moving.bins * mi_hist->fixed.bins); /* Compute cost */ for (i = 0, v = 0; i < mi_hist->fixed.bins; i++) { for (j = 0; j < mi_hist->moving.bins; j++, v++) { if (j_hist[v] > hist_thresh) { score -= j_hist[v] * logf (fnv * j_hist[v] / (m_hist[j] * f_hist[i])); } } } score = score / fnv; return (float) score; } #if defined (MI_GRAD_CPU) void CPU_MI_Grad (Joint_histogram *mi_hist, // OUTPUT: Histograms Bspline_state *bst, // INPUT: Bspline State Bspline_xform *bxf, // INPUT: Bspline X-Form Volume* fixed, // INPUT: Fixed Image Volume* moving, // INPUT: Moving Image float num_vox_f) // INPUT: Number of voxels { int rijk[3]; int fijk[3]; int fv; int p[3]; int q[3]; float fxyz[3]; int pidx, qidx; float dxyz[3]; float mxyz[3]; float mijk[3]; int mijk_f[3]; // floor: mijk int mijk_r[3]; // round: mijk int mvf; // floor: mv float li_1[3]; float li_2[3]; float dc_dv[3]; for (rijk[2] = 0, fijk[2] = bxf->roi_offset[2]; rijk[2] < bxf->roi_dim[2]; rijk[2]++, fijk[2]++) { p[2] = rijk[2] / bxf->vox_per_rgn[2]; q[2] = rijk[2] % bxf->vox_per_rgn[2]; fxyz[2] = bxf->img_origin[2] + bxf->img_spacing[2] * fijk[2]; for (rijk[1] = 0, fijk[1] = bxf->roi_offset[1]; rijk[1] < bxf->roi_dim[1]; rijk[1]++, fijk[1]++) { p[1] = rijk[1] / bxf->vox_per_rgn[1]; q[1] = rijk[1] % bxf->vox_per_rgn[1]; fxyz[1] = bxf->img_origin[1] + bxf->img_spacing[1] * fijk[1]; for (rijk[0] = 0, fijk[0] = bxf->roi_offset[0]; rijk[0] < bxf->roi_dim[0]; rijk[0]++, fijk[0]++) { int rc; p[0] = rijk[0] / bxf->vox_per_rgn[0]; q[0] = rijk[0] % bxf->vox_per_rgn[0]; fxyz[0] = bxf->img_origin[0] + bxf->img_spacing[0] * fijk[0]; /* Get B-spline deformation vector */ pidx = volume_index (bxf->rdims, p); qidx = volume_index (bxf->vox_per_rgn, q); bspline_interp_pix_b (dxyz, bxf, pidx, qidx); /* Find linear index of fixed image voxel */ fv = volume_index (fixed->dim, fijk); /* Find correspondence in moving image */ rc = bspline_find_correspondence (mxyz, mijk, fxyz, dxyz, moving); /* If voxel is not inside moving image */ if (!rc) continue; /* PARTIAL VALUE INTERPOLATION - 8 neighborhood */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Find linear index of fixed image voxel */ fv = volume_index (fixed->dim, fijk); /* Find linear index of "corner voxel" in moving image */ mvf = volume_index (moving->dim, mijk_f); // Partial Volume Interpolation 8-neighbor Gradient bspline_mi_pvi_8_dc_dv (dc_dv, mi_hist, bst, fixed, moving, fv, mvf, mijk, num_vox_f, li_1, li_2); // B-Spline parameterization bspline_update_grad_b_inline (bst, bxf, pidx, qidx, dc_dv); } } } } #endif void CUDA_bspline_mi_a ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform *bxf ) { Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *moving_grad = bst->moving_grad; UNUSED_VARIABLE (moving_grad); Dev_Pointers_Bspline* dev_ptrs = (Dev_Pointers_Bspline*)bst->dev_ptrs; // --- DECLARE LOCAL VARIABLES ------------------------------ Bspline_score* ssd; // Holds the SSD "Score" information Joint_histogram* mi_hist = bst->get_mi_hist(); double* f_hist = mi_hist->f_hist; double* m_hist = mi_hist->m_hist; double* j_hist = mi_hist->j_hist; static int it=0; // Holds Iteration Number char debug_fn[1024]; // Debug message buffer FILE* fp = NULL; // File Pointer to Debug File //int i; // Good ol' i // ---------------------------------------------------------- // --- CHECK COMPUTE CAPABILITY (NEED SHARED/GLOBAL ATOMICS)- if (CUDA_getarch(parms->gpuid) < 120) { printf ("\n******************* NOTICE *******************\n"); printf (" A GPU of Compute Capability 1.2 or greater\n"); printf (" is required to for GPU accelerated MI\n"); printf ("\n"); printf (" Unfortunately, your current GPU does not\n"); printf (" satisfy this requirement. Sorry.\n"); printf ("***************************************************\n\n"); exit(0); } // ---------------------------------------------------------- // --- INITIALIZE LOCAL VARIABLES --------------------------- ssd = &bst->ssd; if (parms->debug) { sprintf (debug_fn, "dump_mse_%02d.txt", it++); fp = fopen (debug_fn, "w"); } // ---------------------------------------------------------- #if defined (MI_HISTS_CPU) || defined (MI_SCORE_CPU) // --- INITIALIZE CPU MEMORY -------------------------------- memset(f_hist, 0, mi_hist->fixed.bins * sizeof (double)); memset(m_hist, 0, mi_hist->moving.bins * sizeof (double)); memset(j_hist, 0, mi_hist->moving.bins * mi_hist->fixed.bins * sizeof (double)); // ---------------------------------------------------------- #endif // --- INITIALIZE GPU MEMORY -------------------------------- CUDA_bspline_push_coeff (dev_ptrs, bxf); CUDA_bspline_zero_score (dev_ptrs); CUDA_bspline_zero_grad (dev_ptrs); // ---------------------------------------------------------- // --- GENERATE HISTOGRMS ----------------------------------- if ((mi_hist->fixed.bins > GPU_MAX_BINS) || (mi_hist->moving.bins > GPU_MAX_BINS)) { ssd->curr_num_vox = CPU_MI_Hist (mi_hist, bxf, fixed, moving); } else { ssd->curr_num_vox = CUDA_bspline_mi_hist (dev_ptrs, mi_hist, fixed, moving, bxf); } // ---------------------------------------------------------- // dump histogram images? #if !defined (PLM_USE_GPU_PLUGINS) if (parms->xpm_hist_dump) { dump_xpm_hist (mi_hist, parms->xpm_hist_dump, bst->it); } #endif if (parms->debug) { // dump_hist (mi_hist, bst->it); } #if defined (commentout) display_hist_totals (mi_hist); #endif // --- COMPUTE SCORE ---------------------------------------- #if defined (MI_SCORE_CPU) ssd->curr_smetric = CPU_MI_Score(mi_hist, ssd->curr_num_vox); #else // Doing this on the GPU may be silly. // The CPU generally completes this computation extremely quickly #endif // ---------------------------------------------------------- // --- COMPUTE GRADIENT ------------------------------------- #if defined (MI_GRAD_CPU) CPU_MI_Grad(mi_hist, bst, bxf, fixed, moving, (float)ssd->num_vox); #else float score = ssd->curr_smetric; CUDA_bspline_mi_grad ( bst, bxf, fixed, moving, (float) ssd->curr_num_vox, score, dev_ptrs ); #endif // ---------------------------------------------------------- if (parms->debug) { fclose (fp); } } void CUDA_bspline_mse_j ( Bspline_parms *parms, Bspline_state *bst, Bspline_xform *bxf ) { Volume *fixed = bst->fixed; Volume *moving = bst->moving; Volume *moving_grad = bst->moving_grad; Dev_Pointers_Bspline* dev_ptrs = (Dev_Pointers_Bspline*)bst->dev_ptrs; // --- DECLARE LOCAL VARIABLES ------------------------------ Bspline_score* ssd; // Holds the SSD "Score" information float ssd_grad_norm; // Holds the SSD Gradient's Norm float ssd_grad_mean; // Holds the SSD Gradient's Mean static int it=0; // Holds Iteration Number char debug_fn[1024]; // Debug message buffer FILE* fp = NULL; // File Pointer to Debug File // ---------------------------------------------------------- // --- INITIALIZE LOCAL VARIABLES --------------------------- ssd = &bst->ssd; if (parms->debug) { sprintf (debug_fn, "dump_mse_%02d.txt", it++); fp = fopen (debug_fn, "w"); } // ---------------------------------------------------------- // --- INITIALIZE GPU MEMORY -------------------------------- CUDA_bspline_push_coeff (dev_ptrs, bxf); CUDA_bspline_zero_score (dev_ptrs); CUDA_bspline_zero_grad (dev_ptrs); // ---------------------------------------------------------- // --- LAUNCH STUB FUNCTIONS -------------------------------- // Populate the score, dc_dv, and gradient CUDA_bspline_mse_pt1 ( fixed, moving, moving_grad, bxf, parms, dev_ptrs ); // Calculate the score and gradient // via sum reduction CUDA_bspline_mse_pt2 ( parms, bxf, fixed, bxf->vox_per_rgn, fixed->dim, &(ssd->curr_smetric), bst->ssd.curr_smetric_grad, &ssd_grad_mean, &ssd_grad_norm, dev_ptrs, &(ssd->curr_num_vox) ); if (parms->debug) { fclose (fp); } } //////////////////////////////////////////////////////////////////////////////// bspline_cuda.h000066400000000000000000000176171321604176500321150ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_cuda_h_ #define _bspline_cuda_h_ #include "plmregister_config.h" #if (CUDA_FOUND) #include #include #include #include #include #include #include "cuda_mem.h" #include "delayload.h" #include "plm_int.h" /* B-Spline CUDA MI Switches */ //#define MI_HISTS_CPU //#define MI_GRAD_CPU #define MI_SCORE_CPU /* Uncomment to profile CUDA MSE */ //#define PROFILE_MSE /* HARDWARE IMPOSED CONSTANTS */ #define GPU_MAX_BINS 32 class Joint_histogram; class Bspline_optimize; class Bspline_parms; class Bspline_state; class Bspline_xform; class Volume; typedef struct dev_pointers_bspline Dev_Pointers_Bspline; struct dev_pointers_bspline { // IMPORTANT! // Each member of this struct is a POINTER TO // AN ADDRESS RESIDING IN THE GPU'S GLOBAL // MEMORY! Care must be taken when referencing // and dereferencing members of this structure! float* fixed_image; // Fixed Image Voxels float* moving_image; // Moving Image Voxels float* moving_grad; // dc_dp (Gradient) Volume float* coeff; // B-Spline coefficients (p) float* score; // The "Score" float* dc_dv_x; // dc_dv (De-Interleaved) float* dc_dv_y; // dc_dv (De-Interleaved) float* dc_dv_z; // dc_dv (De-Interleaved) float* cond_x; // dc_dv_x (Condensed) float* cond_y; // dc_dv_y (Condensed) float* cond_z; // dc_dv_z (Condensed) float* grad; // dc_dp float* f_hist_seg; // "Segmented" fixed histogram float* m_hist_seg; // "Segmented" moving histogram float* j_hist_seg; // "Segmented" joint histogram float* f_hist; // fixed image histogram float* m_hist; // moving image histogram float* j_hist; // joint histogram int* LUT_Knot; // Control Point LUT int* LUT_Offsets; // Tile Offset LUT float* LUT_Bspline_x; // Pre-computed Bspline evaluations float* LUT_Bspline_y; // ------------ '' ---------------- float* LUT_Bspline_z; // ------------ '' ---------------- // # of voxels that do not have a correspondence float* skipped; // Legacy (for GPU w/o atomics) unsigned int* skipped_atomic; // New (for GPU w/ Global atomics) // Head of linked list tracking pinned CPU memory // NOTE: This is the only pointer in this struct containing // a pointer from the CPU memory map. Vmem_Entry* vmem_list; // Sizes of allocations for above pointers. plm_long fixed_image_size; plm_long moving_image_size; plm_long moving_grad_size; plm_long coeff_size; plm_long score_size; plm_long dc_dv_x_size; plm_long dc_dv_y_size; plm_long dc_dv_z_size; plm_long cond_x_size; plm_long cond_y_size; plm_long cond_z_size; plm_long grad_size; plm_long f_hist_seg_size; plm_long m_hist_seg_size; plm_long j_hist_seg_size; plm_long f_hist_size; plm_long m_hist_size; plm_long j_hist_size; plm_long LUT_Knot_size; plm_long LUT_Offsets_size; plm_long LUT_Bspline_x_size; plm_long LUT_Bspline_y_size; plm_long LUT_Bspline_z_size; plm_long skipped_size; }; #if defined __cplusplus extern "C" { #endif // ------------------------------------------------------------------- // Prototypes: bspline_cuda.cpp PLMREGISTERCUDA_API DELAYLOAD_WRAP ( void CUDA_bspline_mi_a, Bspline_parms *parms, Bspline_state *bst, Bspline_xform *bxf ); PLMREGISTERCUDA_API DELAYLOAD_WRAP ( void CUDA_bspline_mse_j, Bspline_parms *parms, Bspline_state *bst, Bspline_xform *bxf ); // // ------------------------------------------------------------------- // ------------------------------------------------------------------- // Prototypes: bspline_cuda.cu void CUDA_bspline_mse_pt1 ( Volume* fixed, Volume* moving, Volume* moving_grad, Bspline_xform* bxf, Bspline_parms* parms, Dev_Pointers_Bspline* dev_ptrs ); void CUDA_bspline_mse_pt2 ( Bspline_parms* parms, Bspline_xform* bxf, Volume* fixed, plm_long* vox_per_rgn, plm_long* volume_dim, float* host_score, float* host_grad, float* host_grad_mean, float* host_grad_norm, Dev_Pointers_Bspline* dev_ptrs, plm_long* num_vox ); PLMREGISTERCUDA_API DELAYLOAD_WRAP ( void CUDA_bspline_mse_init_j, Dev_Pointers_Bspline* dev_ptrs, Volume* fixed, Volume* moving, Volume* moving_grad, Bspline_xform* bxf, Bspline_parms* parms ); PLMREGISTERCUDA_API DELAYLOAD_WRAP ( void CUDA_bspline_mse_cleanup_j, Dev_Pointers_Bspline* dev_ptrs, Volume* fixed, Volume* moving, Volume* moving_grad ); PLMREGISTERCUDA_API DELAYLOAD_WRAP ( void CUDA_bspline_mi_cleanup_a, Dev_Pointers_Bspline* dev_ptrs, Volume* fixed, Volume* moving, Volume* moving_grad ); void CUDA_bspline_push_coeff ( Dev_Pointers_Bspline* dev_ptrs, Bspline_xform* bxf ); void CUDA_bspline_zero_score ( Dev_Pointers_Bspline* dev_ptrs ); void CUDA_bspline_zero_grad ( Dev_Pointers_Bspline* dev_ptrs ); void CUDA_bspline_mse_score_dc_dv ( Dev_Pointers_Bspline* dev_ptrs, Bspline_xform* bxf, Volume* fixed, Volume* moving ); void CUDA_bspline_condense ( Dev_Pointers_Bspline* dev_ptrs, plm_long* vox_per_rgn, int num_tiles ); void CUDA_bspline_reduce ( Dev_Pointers_Bspline* dev_ptrs, int num_knots ); float CPU_obtain_bspline_basis_function ( int t_idx, int vox_idx, int vox_per_rgn ); void CPU_find_knots ( int* knots, int tile_num, plm_long* rdims, plm_long* cdims ); int* CPU_calc_offsets ( plm_long* tile_dims, plm_long* cdims ); PLMREGISTERCUDA_API DELAYLOAD_WRAP ( void CUDA_bspline_mi_init_a, Bspline_xform* bxf, Bspline_state* bst, Dev_Pointers_Bspline* dev_ptrs, Volume* fixed, Volume* moving, Volume* moving_grad ); int CUDA_bspline_mi_hist ( Dev_Pointers_Bspline *dev_ptrs, Joint_histogram* mi_hist, Volume* fixed, Volume* moving, Bspline_xform *bxf ); void CUDA_bspline_mi_hist_fix ( Dev_Pointers_Bspline *dev_ptrs, Joint_histogram* mi_hist, Volume* fixed, Volume* moving, Bspline_xform *bxf ); void CUDA_bspline_mi_hist_mov ( Dev_Pointers_Bspline *dev_ptrs, Joint_histogram* mi_hist, Volume* fixed, Volume* moving, Bspline_xform *bxf ); int CUDA_bspline_mi_hist_jnt ( Dev_Pointers_Bspline *dev_ptrs, Joint_histogram* mi_hist, Volume* fixed, Volume* moving, Bspline_xform *bxf ); void CUDA_bspline_mi_grad ( Bspline_state *bst, Bspline_xform *bxf, Volume* fixed, Volume* moving, float num_vox_f, float score, Dev_Pointers_Bspline *dev_ptrs ); PLMREGISTERCUDA_API DELAYLOAD_WRAP ( void CUDA_bspline_interpolate_vf, Volume* interp, Bspline_xform* bxf ); // // ------------------------------------------------------------------- #if defined __cplusplus } #endif #endif /* CUDA_FOUND */ #endif bspline_cuda_kernels.h000066400000000000000000000231411321604176500336250ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_cuda_kernels_h_ #define _bspline_cuda_kernels_h_ // NOTE: Cannot be included in C or C++ files due to // special CUDA types such as int4, dim3, etc. // Can only be included in CUDA files. typedef struct gpu_bspline_data GPU_Bspline_Data; struct gpu_bspline_data { // bxf items int3 rdims; int3 cdims; float3 img_origin; float3 img_spacing; int3 roi_dim; int3 roi_offset; int3 vox_per_rgn; // fixed volume items int3 fix_dim; // moving volume items int3 mov_dim; float3 mov_origin; float3 mov_spacing; }; /* Function prototypes of kernels */ __global__ void kernel_bspline_condense ( float* cond_x, // Return: condensed dc_dv_x values float* cond_y, // Return: condensed dc_dv_y values float* cond_z, // Return: condensed dc_dv_z values float* dc_dv_x, // Input : dc_dv_x values float* dc_dv_y, // Input : dc_dv_y values float* dc_dv_z, // Input : dc_dv_z values int* LUT_Tile_Offsets, // Input : tile offsets int* LUT_Knot, // Input : linear knot indicies int pad, // Input : amount of tile padding int4 tile_dim, // Input : dims of tiles float one_over_six // Input : Precomputed (GPU division is slow) ); __global__ void kernel_bspline_reduce ( float* grad, // Return: interleaved dc_dp values float* cond_x, // Input : condensed dc_dv_x values float* cond_y, // Input : condensed dc_dv_y values float* cond_z // Input : condensed dc_dv_z values ); __global__ void kernel_bspline_grad_normalize ( float *grad, int num_vox, int num_elems ); __global__ void kernel_bspline_interpolate_vf ( float* vf, int3 fdim, int3 rdim, int3 cdim, int3 vpr ); __global__ void kernel_sum_reduction_pt1 ( float *idata, float *odata, int num_elems ); __global__ void kernel_sum_reduction_pt2 ( float *idata, float *odata, int num_elems ); __global__ void kernel_bspline_mi_hist_fix ( float* f_hist_seg, // partial histogram (fixed image) float* f_img, // moving image voxels float offset, // histogram offset float delta, // histogram delta long bins, // # histogram bins int3 vpr, // voxels per region int3 fdim, // fixed image dimensions int3 mdim, // moving image dimensions int3 rdim, // region dimensions int3 cdim, // # control points in x,y,z float3 img_origin, // image origin float3 img_spacing, // image spacing float3 mov_origin, // moving image offset float3 mov_ps // moving image pixel spacing ); __global__ void kernel_bspline_mi_hist_mov ( float* m_hist_seg, // partial histogram (moving image) float* m_img, // moving image voxels float offset, // histogram offset float delta, // histogram delta long bins, // # histogram bins int3 vpr, // voxels per region int3 fdim, // fixed image dimensions int3 mdim, // moving image dimensions int3 rdim, // region dimensions int3 cdim, // # control points in x,y,z float3 img_origin, // image origin float3 img_spacing, // image spacing float3 mov_origin, // moving image offset float3 mov_ps // moving image pixel spacing ); __global__ void kernel_bspline_mi_hist_jnt ( unsigned int* skipped, // OUTPUT: # of skipped voxels float* j_hist, // OUTPUT: joint histogram float* f_img, // INPUT: fixed image voxels float* m_img, // INPUT: moving image voxels float f_offset, // INPUT: fixed histogram offset float m_offset, // INPUT: moving histogram offset float f_delta, // INPUT: fixed histogram delta float m_delta, // INPUT: moving histogram delta long f_bins, // INPUT: # fixed histogram bins long m_bins, // INPUT: # moving histogram bins int3 vpr, // INPUT: voxels per region int3 fdim, // INPUT: fixed image dimensions int3 mdim, // INPUT: moving image dimensions int3 rdim, // INPUT: region dimensions int3 cdim, // INPUT: # control points in x,y,z float3 img_origin, // INPUT: image origin float3 img_spacing, // INPUT: image spacing float3 mov_origin, // INPUT: moving image offset float3 mov_ps, // INPUT: moving image pixel spacing int3 roi_dim, // INPUT: ROI dimensions int3 roi_offset // INPUT: ROI Offset ); __global__ void kernel_bspline_mi_hist_merge ( float *f_hist, float *f_hist_seg, long num_seg_hist ); __global__ void kernel_bspline_mi_dc_dv ( float* dc_dv_x, // OUTPUT: dC / dv (x-component) float* dc_dv_y, // OUTPUT: dC / dv (y-component) float* dc_dv_z, // OUTPUT: dC / dv (z-component) float* f_hist, // INPUT: fixed histogram float* m_hist, // INPUT: moving histogram float* j_hist, // INPUT: joint histogram float* f_img, // INPUT: fixed image voxels float* m_img, // INPUT: moving image voxels float f_offset, // INPUT: fixed histogram offset float m_offset, // INPUT: moving histogram offset float f_delta, // INPUT: fixed histogram delta float m_delta, // INPUT: moving histogram delta long f_bins, // INPUT: # fixed histogram bins long m_bins, // INPUT: # moving histogram bins int3 vpr, // INPUT: voxels per region int3 fdim, // INPUT: fixed image dimensions int3 mdim, // INPUT: moving image dimensions int3 rdim, // INPUT: region dimensions int3 cdim, // INPUT: # control points in x,y,z float3 img_origin, // INPUT: image origin float3 img_spacing, // INPUT: image spacing float3 mov_origin, // INPUT: moving image offset float3 mov_ps, // INPUT: moving image pixel spacing int3 roi_dim, // INPUT: ROI dimensions int3 roi_offset, // INPUT: ROI Offset float num_vox_f, // INPUT: # of voxels float score, // INPUT: evaluated MI cost function int pad // INPUT: Tile Paddign ); __global__ void kernel_bspline_mse_score_dc_dv ( float* score, // OUTPUT float* skipped, // OUTPUT float* dc_dv_x, // OUTPUT float* dc_dv_y, // OUTPUT float* dc_dv_z, // OUTPUT float* f_img, // fixed image voxels float* m_img, // moving image voxels float* m_grad, // moving image gradient int3 fdim, // fixed image dimensions int3 mdim, // moving image dimensions int3 rdim, // region dimensions int3 cdim, // # control points in x,y,z int3 vpr, // voxels per region float3 img_origin, // image origin float3 img_spacing, // image spacing float3 mov_origin, // moving image offset float3 mov_ps, // moving image pixel spacing int pad); // tile padding __device__ inline void clamp_linear_interpolate_3d ( float3* n, int3* n_f, int3* n_r, float3* li_1, float3* li_2, int3 mdim ); __device__ inline int find_correspondence ( float3 *d, float3 *m, float3 *n, float3 f, float3 mov_origin, float3 mov_ps, int3 mdim, int3 cdim, int3 vpr, int4 p, int4 q ); __device__ inline float get_moving_value ( int3 n_f, int3 mdim, float3 li_1, float3 li_2 ); __device__ inline void setup_indices ( int4 *p, int4 *q, float3 *f, int fv, int3 fdim, int3 vpr, int3 rdim, float3 img_origin, float3 img_spacing ); __device__ inline void write_dc_dv ( float* dc_dv_x, float* dc_dv_y, float* dc_dv_z, float* m_grad, float diff, int3 n_r, int3 mdim, int3 vpr, int pad, int4 p, int4 q ); __device__ inline void get_nearest_neighbors ( int* nn, int3 n_f, int3 mdim ); __device__ inline void get_weights ( float* w, float3 li_1, float3 li_2 ); __device__ inline void get_weight_derivatives ( float3* dw, float3 li_1, float3 li_2 ); __device__ inline void bspline_interpolate ( float3* d, int3 cdim, int3 vpr, int4 p, int4 q ); #endif demons_cuda.cu000066400000000000000000000527701321604176500321250ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include "cuda_util.h" #include "demons.h" #include "demons_cuda.h" #include "demons_state.h" #include "gaussian.h" #include "plm_cuda_math.h" #include "plm_timer.h" #include "volume.h" /* Constants */ #define BLOCK_SIZE 256 /* Texture Memory */ texture tex_fixed; texture tex_moving; texture tex_grad; texture tex_grad_mag; texture tex_vf_est; texture tex_vf_smooth; /* Constant Memory */ __constant__ int c_dim[3]; __constant__ int c_moving_dim[3]; __constant__ float c_spacing_div2[3]; __constant__ float c_f2mo[3]; __constant__ float c_f2ms[3]; __constant__ float c_invmps[3]; /* Constant Memory Functions */ void setConstantDimension (plm_long *h_dim) { int i_dim[3] = { h_dim[0], h_dim[1], h_dim[2] }; cudaMemcpyToSymbol (c_dim, i_dim, sizeof(int3)); //cudaMemcpyToSymbol(c_dim, h_dim, sizeof(int3)); } void setConstantMovingDimension (plm_long *h_dim) { int i_dim[3] = { h_dim[0], h_dim[1], h_dim[2] }; cudaMemcpyToSymbol (c_moving_dim, i_dim, sizeof(int3)); } void setConstantPixelSpacing(float *h_spacing_div2) { cudaMemcpyToSymbol(c_spacing_div2, h_spacing_div2, sizeof(float3)); } void setConstantF2mo(float *h_f2mo) { cudaMemcpyToSymbol(c_f2mo, h_f2mo, sizeof(float3)); } void setConstantF2ms(float *h_f2ms) { cudaMemcpyToSymbol(c_f2ms, h_f2ms, sizeof(float3)); } void setConstantInvmps(float *h_invmps) { cudaMemcpyToSymbol(c_invmps, h_invmps, sizeof(float3)); } /* Device Functions */ __device__ int volume_index_cuda (int *dims, int i, int j, int k) { return i + (dims[0] * (j + dims[1] * k)); } /* Kernels */ __global__ void calculate_gradient_magnitude_image_kernel (float *grad_mag, int blockY, float invBlockY) { /* Find position in volume */ int blockIdx_z = __float2int_rd(blockIdx.y * invBlockY); int blockIdx_y = blockIdx.y - __mul24(blockIdx_z, blockY); int x = __mul24(blockIdx.x, blockDim.x) + threadIdx.x; int y = __mul24(blockIdx_y, blockDim.y) + threadIdx.y; int z = __mul24(blockIdx_z, blockDim.z) + threadIdx.z; if (x >= c_dim[0] || y >= c_dim[1] || z >= c_dim[2]) return; long v = (z * c_dim[1] * c_dim[0]) + (y * c_dim[0]) + x; long v3 = v * 3; float vox_grad_x = tex1Dfetch(tex_grad, v3); float vox_grad_y = tex1Dfetch(tex_grad, v3 + 1); float vox_grad_z = tex1Dfetch(tex_grad, v3 + 2); grad_mag[v] = vox_grad_x * vox_grad_x + vox_grad_y * vox_grad_y + vox_grad_z * vox_grad_z; } __global__ void estimate_kernel ( float *vf_est_img, float *ssd, int *inliers, float homog, float denominator_eps, float accel, int blockY, float invBlockY ) { /* Find position in volume */ int blockIdx_z = __float2int_rd(blockIdx.y * invBlockY); int blockIdx_y = blockIdx.y - __mul24(blockIdx_z, blockY); int i = __mul24(blockIdx.x, blockDim.x) + threadIdx.x; int j = __mul24(blockIdx_y, blockDim.y) + threadIdx.y; int k = __mul24(blockIdx_z, blockDim.z) + threadIdx.z; if (i >= c_dim[0] || j >= c_dim[1] || k >= c_dim[2]) return; long fv = (k * c_dim[1] * c_dim[0]) + (j * c_dim[0]) + i; long f3v = 3 * fv; float mi = c_f2mo[0] + i * c_f2ms[0]; float mj = c_f2mo[1] + j * c_f2ms[1]; float mk = c_f2mo[2] + k * c_f2ms[2]; /* Find correspondence with nearest neighbor interpolation and boundary checking */ int mz = __float2int_rn (mk + c_invmps[2] * tex1Dfetch(tex_vf_smooth, f3v + 2)); /* pixels (moving) */ if (mz < 0 || mz >= c_moving_dim[2]) return; int my = __float2int_rn (mj + c_invmps[1] * tex1Dfetch(tex_vf_smooth, f3v + 1)); /* pixels (moving) */ if (my < 0 || my >= c_moving_dim[1]) return; int mx = __float2int_rn (mi + c_invmps[0] * tex1Dfetch(tex_vf_smooth, f3v)); /* pixels (moving) */ if (mx < 0 || mx >= c_moving_dim[0]) return; int mv = (mz * c_moving_dim[1] + my) * c_moving_dim[0] + mx; int m3v = 3 * mv; /* Find image difference at this correspondence */ float diff = tex1Dfetch(tex_fixed, fv) - tex1Dfetch(tex_moving, mv); /* intensity */ /* Compute denominator */ float denom = tex1Dfetch(tex_grad_mag, mv) + homog * diff * diff; /* intensity^2 per mm^2 */ /* Compute SSD for statistics */ inliers[fv] = 1; ssd[fv] = diff * diff; /* Threshold the denominator to stabilize estimation */ if (denom < denominator_eps) return; /* Compute new estimate of displacement */ float mult = accel * diff / denom; /* per intensity^2 */ vf_est_img[f3v] += mult * tex1Dfetch(tex_grad, m3v); /* mm */ vf_est_img[f3v + 1] += mult * tex1Dfetch(tex_grad, m3v + 1); vf_est_img[f3v + 2] += mult * tex1Dfetch(tex_grad, m3v + 2); } template __global__ void reduction(T *vectorData, int totalElements) { __shared__ T vector[BLOCK_SIZE * 2]; /* Find position in vector */ int threadID = threadIdx.x; int blockID = blockIdx.x; int xInVector = BLOCK_SIZE * blockID * 2 + threadID; vector[threadID] = (xInVector < totalElements) ? vectorData[xInVector] : 0; vector[threadID + BLOCK_SIZE] = (xInVector + BLOCK_SIZE < totalElements) ? vectorData[xInVector + BLOCK_SIZE] : 0; __syncthreads(); /* Calculate partial sum */ for (int stride = BLOCK_SIZE; stride > 0; stride >>= 1) { if (threadID < stride) vector[threadID] += vector[threadID + stride]; __syncthreads(); } __syncthreads(); if (threadID == 0) vectorData[blockID] = vector[0]; } __global__ void vf_convolve_x_kernel (float *vf_out, float *ker, int half_width, int blockY, float invBlockY) { int i, i1; /* i is the offset in the vf */ int j, j1, j2; /* j is the index of the kernel */ int d; /* d is the vector field direction */ /* Find position in volume */ int blockIdx_z = __float2int_rd(blockIdx.y * invBlockY); int blockIdx_y = blockIdx.y - __mul24(blockIdx_z, blockY); int x = __mul24(blockIdx.x, blockDim.x) + threadIdx.x; int y = __mul24(blockIdx_y, blockDim.y) + threadIdx.y; int z = __mul24(blockIdx_z, blockDim.z) + threadIdx.z; if (x >= c_dim[0] || y >= c_dim[1] || z >= c_dim[2]) return; long v3 = 3 * ((z * c_dim[1] * c_dim[0]) + (y * c_dim[0]) + x); j1 = x - half_width; j2 = x + half_width; if (j1 < 0) j1 = 0; if (j2 >= c_dim[0]) { j2 = c_dim[0] - 1; } i1 = j1 - x; j1 = j1 - x + half_width; j2 = j2 - x + half_width; long index; for (d = 0; d < 3; d++) { float sum = 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { index = v3 + (3 * i) + d; sum += ker[j] * tex1Dfetch(tex_vf_est, index); } vf_out[v3 + d] = sum; } } __global__ void vf_convolve_y_kernel (float *vf_out, float *ker, int half_width, int blockY, float invBlockY) { int i, i1; /* i is the offset in the vf */ int j, j1, j2; /* j is the index of the kernel */ int d; /* d is the vector field direction */ /* Find position in volume */ int blockIdx_z = __float2int_rd(blockIdx.y * invBlockY); int blockIdx_y = blockIdx.y - __mul24(blockIdx_z, blockY); int x = __mul24(blockIdx.x, blockDim.x) + threadIdx.x; int y = __mul24(blockIdx_y, blockDim.y) + threadIdx.y; int z = __mul24(blockIdx_z, blockDim.z) + threadIdx.z; if (x >= c_dim[0] || y >= c_dim[1] || z >= c_dim[2]) return; long v3 = 3 * ((z * c_dim[1] * c_dim[0]) + (y * c_dim[0]) + x); j1 = y - half_width; j2 = y + half_width; if (j1 < 0) j1 = 0; if (j2 >= c_dim[1]) { j2 = c_dim[1] - 1; } i1 = j1 - y; j1 = j1 - y + half_width; j2 = j2 - y + half_width; long index; for (d = 0; d < 3; d++) { float sum = 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { index = v3 + (3 * i * c_dim[0]) + d; sum += ker[j] * tex1Dfetch(tex_vf_smooth, index); } vf_out[v3 + d] = sum; } } __global__ void vf_convolve_z_kernel (float *vf_out, float *ker, int half_width, int blockY, float invBlockY) { int i, i1; /* i is the offset in the vf */ int j, j1, j2; /* j is the index of the kernel */ int d; /* d is the vector field direction */ /* Find position in volume */ int blockIdx_z = __float2int_rd(blockIdx.y * invBlockY); int blockIdx_y = blockIdx.y - __mul24(blockIdx_z, blockY); int x = __mul24(blockIdx.x, blockDim.x) + threadIdx.x; int y = __mul24(blockIdx_y, blockDim.y) + threadIdx.y; int z = __mul24(blockIdx_z, blockDim.z) + threadIdx.z; if (x >= c_dim[0] || y >= c_dim[1] || z >= c_dim[2]) return; long v3 = 3 * ((z * c_dim[1] * c_dim[0]) + (y * c_dim[0]) + x); j1 = z - half_width; j2 = z + half_width; if (j1 < 0) j1 = 0; if (j2 >= c_dim[2]) { j2 = c_dim[2] - 1; } i1 = j1 - z; j1 = j1 - z + half_width; j2 = j2 - z + half_width; long index; for (d = 0; d < 3; d++) { float sum = 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { index = v3 + (3 * i * c_dim[0] * c_dim[1]) + d; sum += ker[j] * tex1Dfetch(tex_vf_est, index); } vf_out[v3 + d] = sum; } } __global__ void volume_calc_grad_kernel (float *out_img, unsigned int blockY, float invBlockY) { /* Find position in volume */ int blockIdx_z = __float2int_rd(blockIdx.y * invBlockY); int blockIdx_y = blockIdx.y - __mul24(blockIdx_z, blockY); int i = __mul24(blockIdx.x, blockDim.x) + threadIdx.x; int j = __mul24(blockIdx_y, blockDim.y) + threadIdx.y; int k = __mul24(blockIdx_z, blockDim.z) + threadIdx.z; if (i >= c_dim[0] || j >= c_dim[1] || k >= c_dim[2]) return; /* p is prev, n is next */ int i_p = (i == 0) ? 0 : i - 1; int i_n = (i == c_dim[0] - 1) ? c_dim[0] - 1 : i + 1; int j_p = (j == 0) ? 0 : j - 1; int j_n = (j == c_dim[1] - 1) ? c_dim[1] - 1 : j + 1; int k_p = (k == 0) ? 0 : k - 1; int k_n = (k == c_dim[2] - 1) ? c_dim[2] - 1 : k + 1; long v3 = 3 * ((k * c_dim[1] * c_dim[0]) + (j * c_dim[0]) + i); long gi = v3; long gj = v3 + 1; long gk = v3 + 2; int idx_p, idx_n; idx_p = volume_index_cuda (c_dim, i_p, j, k); idx_n = volume_index_cuda (c_dim, i_n, j, k); out_img[gi] = (float) (tex1Dfetch(tex_moving, idx_n) - tex1Dfetch(tex_moving, idx_p)) * c_spacing_div2[0]; idx_p = volume_index_cuda (c_dim, i, j_p, k); idx_n = volume_index_cuda (c_dim, i, j_n, k); out_img[gj] = (float) (tex1Dfetch(tex_moving, idx_n) - tex1Dfetch(tex_moving, idx_p)) * c_spacing_div2[1]; idx_p = volume_index_cuda (c_dim, i, j, k_p); idx_n = volume_index_cuda (c_dim, i, j, k_n); out_img[gk] = (float) (tex1Dfetch(tex_moving, idx_n) - tex1Dfetch(tex_moving, idx_p)) * c_spacing_div2[2]; } //Volume* void demons_cuda ( Demons_state *demons_state, Volume* fixed, Volume* moving, Volume* moving_grad, Volume* vf_init, Demons_parms* parms ) { int i; int it; /* Iterations */ float f2mo[3]; /* Origin difference (in cm) from fixed to moving */ float f2ms[3]; /* Slope to convert fixed to moving */ float invmps[3]; /* 1/pixel spacing of moving image */ float *kerx, *kery, *kerz; int fw[3]; double diff_run, gpu_time, kernel_time; //Volume *vf_est, *vf_smooth; int inliers; float ssd; Plm_timer* timer = new Plm_timer; Plm_timer* gpu_timer = new Plm_timer; Plm_timer* kernel_timer = new Plm_timer; int threadX, threadY, threadZ, blockX, blockY, blockZ, num_elements, half_num_elements, reductionBlocks; size_t vol_size, interleaved_vol_size, inlier_size; int *d_inliers; float total_runtime, spacing_div2[3]; float *d_vf_est, *d_vf_smooth, *d_moving, *d_fixed, *d_m_grad, *d_m_grad_mag, *d_kerx, *d_kery, *d_kerz, *d_swap, *d_ssd; dim3 block, grid, reductionGrid; #if defined (commentout) /* Allocate memory for vector fields */ if (vf_init) { /* If caller has an initial estimate, we copy it */ vf_smooth = volume_clone(vf_init); vf_convert_to_interleaved(vf_smooth); } else { /* Otherwise initialize to zero */ vf_smooth = new Volume (fixed->dim, fixed->origin, fixed->spacing, fixed->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3, 0); } vf_est = new Volume (fixed->dim, fixed->origin, fixed->spacing, fixed->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3, 0); #endif printf ("Hello from demons_cuda()\n"); /* Initialize GPU timers */ gpu_time = 0; kernel_time = 0; /* Determine GPU execution environment */ threadX = BLOCK_SIZE; threadY = 1; threadZ = 1; blockX = (fixed->dim[0] + threadX - 1) / threadX; blockY = (fixed->dim[1] + threadY - 1) / threadY; blockZ = (fixed->dim[2] + threadZ - 1) / threadZ; block = dim3(threadX, threadY, threadZ); grid = dim3(blockX, blockY * blockZ); /* Calculate Moving Gradient */ for (i = 0; i < 3; i++) spacing_div2[i] = 0.5 / moving->spacing[i]; /* Determine size of device memory */ vol_size = moving->dim[0] * moving->dim[1] * moving->dim[2] * sizeof(float); interleaved_vol_size = 3 * fixed->dim[0] * fixed->dim[1] * fixed->dim[2] * sizeof(float); inlier_size = moving->dim[0] * moving->dim[1] * moving->dim[2] * sizeof(int); /* Allocate device memory */ gpu_timer->start (); cudaMalloc((void**)&d_vf_est, interleaved_vol_size); cudaMalloc((void**)&d_vf_smooth, interleaved_vol_size); cudaMalloc((void**)&d_fixed, vol_size); cudaMalloc((void**)&d_moving, vol_size); cudaMalloc((void**)&d_m_grad, interleaved_vol_size); cudaMalloc((void**)&d_m_grad_mag, vol_size); cudaMalloc((void**)&d_ssd, vol_size); cudaMalloc((void**)&d_inliers, inlier_size); /* Copy/Initialize device memory */ cudaMemcpy(d_vf_est, demons_state->vf_est->img, interleaved_vol_size, cudaMemcpyHostToDevice); cudaMemcpy(d_vf_smooth, demons_state->vf_est->img, interleaved_vol_size, cudaMemcpyHostToDevice); cudaMemcpy(d_fixed, fixed->img, vol_size, cudaMemcpyHostToDevice); cudaMemcpy(d_moving, moving->img, vol_size, cudaMemcpyHostToDevice); cudaMemset(d_m_grad, 0, interleaved_vol_size); cudaMemset(d_m_grad_mag, 0, vol_size); gpu_time += gpu_timer->report (); /* Set device constant memory */ setConstantDimension(fixed->dim); setConstantMovingDimension(moving->dim); setConstantPixelSpacing(spacing_div2); /* Bind device texture memory */ cudaBindTexture(0, tex_fixed, d_fixed, vol_size); cudaBindTexture(0, tex_moving, d_moving, vol_size); gpu_time += gpu_timer->report (); /* Check for any errors prekernel execution */ CUDA_check_error("Error before kernel execution"); /* Call kernel */ kernel_timer->start (); volume_calc_grad_kernel<<< grid, block>>>(d_m_grad, blockY, 1.0f / (float)blockY); cudaThreadSynchronize(); kernel_time += kernel_timer->report (); /* Check for any errors postkernel execution */ CUDA_check_error("Kernel execution failed"); /* Bind device texture memory */ gpu_timer->start (); cudaBindTexture(0, tex_grad, d_m_grad, interleaved_vol_size); gpu_time += gpu_timer->report (); /* Check for any errors prekernel execution */ CUDA_check_error("Error before kernel execution"); /* Call kernel */ kernel_timer->start (); calculate_gradient_magnitude_image_kernel<<< grid, block>>> ( d_m_grad_mag, blockY, 1.0f / (float)blockY); cudaThreadSynchronize(); kernel_time += kernel_timer->report (); /* Check for any errors postkernel execution */ CUDA_check_error("Kernel execution failed"); /* Validate filter widths */ validate_filter_widths (fw, parms->filter_width); /* Create the seperable smoothing kernels for the x, y, and z directions */ kerx = create_ker (parms->filter_std / fixed->spacing[0], fw[0]/2); kery = create_ker (parms->filter_std / fixed->spacing[1], fw[1]/2); kerz = create_ker (parms->filter_std / fixed->spacing[2], fw[2]/2); kernel_stats (kerx, kery, kerz, fw); /* Compute some variables for converting pixel sizes / origins */ for (i = 0; i < 3; i++) { invmps[i] = 1 / moving->spacing[i]; f2mo[i] = (fixed->origin[i] - moving->origin[i]) / moving->spacing[i]; f2ms[i] = fixed->spacing[i] / moving->spacing[i]; } /* Allocate device memory */ gpu_timer->start (); printf ("Doing cudaMalloc\n"); cudaMalloc ((void**)&d_kerx, fw[0] * sizeof(float)); cudaMalloc ((void**)&d_kery, fw[1] * sizeof(float)); cudaMalloc ((void**)&d_kerz, fw[2] * sizeof(float)); /* Copy/Initialize device memory */ printf ("Doing cudaMemcpy\n"); cudaMemcpy (d_kerx, kerx, fw[0] * sizeof(float), cudaMemcpyHostToDevice); cudaMemcpy (d_kery, kery, fw[1] * sizeof(float), cudaMemcpyHostToDevice); cudaMemcpy (d_kerz, kerz, fw[2] * sizeof(float), cudaMemcpyHostToDevice); /* Set device constant memory */ setConstantF2ms (f2mo); setConstantF2ms (f2ms); setConstantInvmps (invmps); /* Bind device texture memory */ printf ("Doing cudaBindTexture\n"); cudaBindTexture (0, tex_grad_mag, d_m_grad_mag, vol_size); gpu_time += gpu_timer->report (); timer->start (); /* Main loop through iterations */ for (it = 0; it < parms->max_its; it++) { printf ("Looping...\n"); /* Estimate displacement, store into vf_est */ inliers = 0; ssd = 0.0; /* Check for any errors prekernel execution */ CUDA_check_error ("Error before kernel execution"); gpu_timer->start (); cudaBindTexture(0, tex_vf_smooth, d_vf_smooth, interleaved_vol_size); cudaMemset(d_ssd, 0, vol_size); cudaMemset(d_inliers, 0, inlier_size); gpu_time += gpu_timer->report (); /* Call kernel */ kernel_timer->start (); estimate_kernel<<< grid, block >>> ( d_vf_est, d_ssd, d_inliers, parms->homog, parms->denominator_eps, parms->accel, blockY, 1.0f / (float)blockY); cudaThreadSynchronize (); kernel_time += kernel_timer->report (); /* Check for any errors postkernel execution */ CUDA_check_error ("Kernel execution failed"); num_elements = moving->dim[0] * moving->dim[1] * moving->dim[2]; while (num_elements > 1) { half_num_elements = num_elements / 2; reductionBlocks = (half_num_elements + BLOCK_SIZE - 1) / BLOCK_SIZE; /* Invoke kernels */ dim3 reductionGrid(reductionBlocks, 1); kernel_timer->start (); reduction<<< reductionGrid, block >>>(d_ssd, num_elements); cudaThreadSynchronize(); reduction<<< reductionGrid, block >>>(d_inliers, num_elements); cudaThreadSynchronize(); kernel_time += kernel_timer->report (); /* Check for any errors postkernel execution */ CUDA_check_error("Kernel execution failed"); num_elements = reductionBlocks; } /* Smooth the estimate into vf_smooth. The volumes are ping-ponged. */ gpu_timer->start (); cudaUnbindTexture(tex_vf_smooth); cudaBindTexture(0, tex_vf_est, d_vf_est, interleaved_vol_size); cudaMemcpy(&ssd, d_ssd, sizeof(float), cudaMemcpyDeviceToHost); cudaMemcpy(&inliers, d_inliers, sizeof(int), cudaMemcpyDeviceToHost); gpu_time += gpu_timer->report (); /* Print statistics */ printf ("----- SSD = %.01f (%d/%d)\n", ssd/inliers, inliers, fixed->npix); /* Check for any errors prekernel execution */ CUDA_check_error("Error before kernel execution"); /* Call kernel */ kernel_timer->start (); vf_convolve_x_kernel<<< grid, block >>>(d_vf_smooth, d_kerx, fw[0] / 2, blockY, 1.0f / (float)blockY); cudaThreadSynchronize(); kernel_time += kernel_timer->report (); /* Check for any errors postkernel execution */ CUDA_check_error("Kernel execution failed"); gpu_timer->start (); cudaUnbindTexture(tex_vf_est); cudaBindTexture(0, tex_vf_smooth, d_vf_smooth, interleaved_vol_size); gpu_time += gpu_timer->report (); /* Call kernel */ kernel_timer->start (); vf_convolve_y_kernel<<< grid, block >>>(d_vf_est, d_kery, fw[1] / 2, blockY, 1.0f / (float)blockY); cudaThreadSynchronize(); kernel_time += kernel_timer->report (); /* Check for any errors postkernel execution */ CUDA_check_error("Kernel execution failed"); gpu_timer->start (); cudaUnbindTexture(tex_vf_smooth); cudaBindTexture(0, tex_vf_est, d_vf_est, interleaved_vol_size); gpu_time += gpu_timer->report (); /* Call kernel */ kernel_timer->start (); vf_convolve_z_kernel<<< grid, block >>>(d_vf_smooth, d_kerz, fw[2] / 2, blockY, 1.0f / (float)blockY); cudaThreadSynchronize(); kernel_time += kernel_timer->report (); /* Check for any errors postkernel execution */ CUDA_check_error("Kernel execution failed"); /* Ping pong between estimate and smooth in each iteration*/ d_swap = d_vf_est; d_vf_est = d_vf_smooth; d_vf_smooth = d_swap; } /* Copy final output from device to host */ gpu_timer->start (); cudaMemcpy (demons_state->vf_smooth->img, d_vf_est, interleaved_vol_size, cudaMemcpyDeviceToHost); gpu_time += gpu_timer->report (); free(kerx); free(kery); free(kerz); //delete vf_est; diff_run = timer->report (); printf("Time for %d iterations = %f (%f sec / it)\n", parms->max_its, diff_run, diff_run / parms->max_its); /* Print statistics */ total_runtime = gpu_time + kernel_time; printf("\nTransfer run time: %f ms\n", gpu_time * 1000); printf("Kernel run time: %f ms\n", kernel_time * 1000); printf("Total CUDA run time: %f s\n\n", total_runtime); delete timer; delete kernel_timer; delete gpu_timer; /* Unbind device texture memory */ cudaUnbindTexture(tex_vf_est); cudaUnbindTexture(tex_grad_mag); cudaUnbindTexture(tex_grad); cudaUnbindTexture(tex_moving); cudaUnbindTexture(tex_fixed); /* Free device global memory */ cudaFree(d_vf_est); cudaFree(d_vf_smooth); cudaFree(d_moving); cudaFree(d_fixed); cudaFree(d_m_grad); cudaFree(d_m_grad_mag); cudaFree(d_ssd); cudaFree(d_inliers); //return vf_smooth; } demons_cuda.h000066400000000000000000000012161321604176500317320ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _demons_cuda_h_ #define _demons_cuda_h_ #include "plmregister_config.h" #include "delayload.h" class Demons_state; class Demons_parms; class Volume; #if defined __cplusplus extern "C" { #endif plmcuda_EXPORT ( void demons_cuda, Demons_state *demons_state, Volume* fixed, Volume* moving, Volume* moving_grad, Volume* vf_init, Demons_parms* parms ); #if defined __cplusplus } #endif #endif demons_cuda_kernel.cu000066400000000000000000000711041321604176500334550ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ // declare texture reference for nabla computation texture tex; // declare texture reference for filter computation texture tex_filter; // declare texture references for vector field estimation texture tex_nabla_x; texture tex_nabla_y; texture tex_nabla_z; texture tex_moving_image; texture tex_static_image; //////////////////////////////////////////////////////////////////////////////// // Kernel Functions //////////////////////////////////////////////////////////////////////////////// __global__ void k_initial_vector(float* idata, unsigned int size) { unsigned int index = blockIdx.y*4096 + blockIdx.x*256 + threadIdx.y*16 + threadIdx.x; if(indexdimen.x-1) || (tempx1<0) || (tempy1>dimen.y-1) || (tempy1<0) || (tempz1>dimen.z-1) || (tempz1<0)) { // retrieve data from texture float nabla_x = texfetch(tex_nabla_x,(int)linear_address); float nabla_y = texfetch(tex_nabla_y,(int)linear_address); float nabla_z = texfetch(tex_nabla_z,(int)linear_address); float static_image = texfetch(tex_static_image,(int)linear_address); // perform calculations float nabla_squared = nabla_x*nabla_x + nabla_y*nabla_y + nabla_z*nabla_z; float diff = (static_image + (float)1000); float ns = nabla_squared + diff*diff; if( ns == 0) { // calculate result result_x = current_vector_in_mm_x[linear_address]; result_y = current_vector_in_mm_y[linear_address]; result_z = current_vector_in_mm_z[linear_address]; } else { // calculate result denom = ((float)diff)/(ns); result_x = current_vector_in_mm_x[linear_address] + denom*nabla_x; result_y = current_vector_in_mm_y[linear_address] + denom*nabla_y; result_z = current_vector_in_mm_z[linear_address] + denom*nabla_z; } } else{ // retrieve data from texture float nabla_x = texfetch(tex_nabla_x,(int)linear_address); float nabla_y = texfetch(tex_nabla_y,(int)linear_address); float nabla_z = texfetch(tex_nabla_z,(int)linear_address); float static_image = texfetch(tex_static_image,(int)linear_address); float moving_image = texfetch(tex_moving_image,(int)temp); // perform calculations float nabla_squared = nabla_x*nabla_x + nabla_y*nabla_y + nabla_z*nabla_z; float diff = (static_image - moving_image); float ns = nabla_squared + diff*diff; if(ns == 0) { // calculate result result_x = current_vector_in_mm_x[linear_address]; result_y = current_vector_in_mm_y[linear_address]; result_z = current_vector_in_mm_z[linear_address]; } else{ // calculate result denom = ((float)diff)/(ns); result_x = current_vector_in_mm_x[linear_address] + denom*nabla_x; result_y = current_vector_in_mm_y[linear_address] + denom*nabla_y; result_z = current_vector_in_mm_z[linear_address] + denom*nabla_z; } } } // synchronize threads between reading and writing __syncthreads(); thread_id[linear_address] = my_thread_id; voxel_id[linear_address] = my_linear_address; if((x_indexdimen.x-1) || (tempx1<0) || (tempy1>dimen.y-1) || (tempy1<0) || (tempz1>dimen.z-1) || (tempz1<0)) { // retrieve data from texture float nabla_x = texfetch(tex_nabla_x,(int)linear_address); float nabla_y = texfetch(tex_nabla_y,(int)linear_address); float nabla_z = texfetch(tex_nabla_z,(int)linear_address); float static_image = texfetch(tex_static_image,(int)linear_address); // perform calculations float nabla_squared = nabla_x*nabla_x + nabla_y*nabla_y + nabla_z*nabla_z; float diff = (static_image + (float)1000); float ns = nabla_squared + diff*diff; if( ns == 0) { // calculate result result_x = current_vector_in_mm_x[linear_address]; result_y = current_vector_in_mm_y[linear_address]; result_z = current_vector_in_mm_z[linear_address]; } else { // calculate result denom = ((float)diff)/(ns); result_x = current_vector_in_mm_x[linear_address] + denom*nabla_x; result_y = current_vector_in_mm_y[linear_address] + denom*nabla_y; result_z = current_vector_in_mm_z[linear_address] + denom*nabla_z; } } else{ // retrieve data from texture float nabla_x = texfetch(tex_nabla_x,(int)linear_address); float nabla_y = texfetch(tex_nabla_y,(int)linear_address); float nabla_z = texfetch(tex_nabla_z,(int)linear_address); float static_image = texfetch(tex_static_image,(int)linear_address); float moving_image = texfetch(tex_moving_image,(int)temp); // perform calculations float nabla_squared = nabla_x*nabla_x + nabla_y*nabla_y + nabla_z*nabla_z; float diff = (static_image - moving_image); float ns = nabla_squared + diff*diff; if(ns == 0) { // calculate result result_x = current_vector_in_mm_x[linear_address]; result_y = current_vector_in_mm_y[linear_address]; result_z = current_vector_in_mm_z[linear_address]; } else{ // calculate result denom = ((float)diff)/(ns); result_x = current_vector_in_mm_x[linear_address] + denom*nabla_x; result_y = current_vector_in_mm_y[linear_address] + denom*nabla_y; result_z = current_vector_in_mm_z[linear_address] + denom*nabla_z; } } } // synchronize threads between reading and writing __syncthreads(); if((x_index #include #include #include #include #include "demons_misc.h" /* This function creates the smoothing kernel */ float* create_ker (float coeff, int half_width) { int i,j=0; float sum = 0.0; int width = 2*half_width + 1; float* ker = (float*) malloc (sizeof(float) * width); if (!ker) { printf("Allocation failed 5.....Exiting\n"); exit(-1); } for (i = -half_width, j = 0; i <= half_width; i++, j++) { ker[j] = exp((((float)(-(i*i)))/(2*coeff*coeff))); sum = sum + ker[j]; } for (i = 0; i < width; i++) { ker[i] = ker[i] / sum; } return ker; } void validate_filter_widths (int *fw_out, int *fw_in) { int i; for (i = 0; i < 3; i++) { if (fw_in[i] < 3) { fw_out[i] = 3; } else { fw_out[i] = 2 * (fw_in[i] / 2) + 1; } } } void kernel_stats (float* kerx, float* kery, float* kerz, int fw[]) { int i; printf ("kerx: "); for (i = 0; i < fw[0]; i++) { printf ("%.10f ", kerx[i]); } printf ("\n"); printf ("kery: "); for (i = 0; i < fw[1]; i++) { printf ("%.10f ", kery[i]); } printf ("\n"); printf ("kerz: "); for (i = 0; i < fw[2]; i++) { printf ("%.10f ", kerz[i]); } printf ("\n"); } viscous_compute.cu000066400000000000000000000415671321604176500330750ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/******************************************************************* c* Multimodal Deformable Image Registration * c* via Mutual Information or Bhattacharyya Distantce * c* Version: 1.0 * c* Language: C, CUDA * c* * c* Developer: Yifei Lou * c* Email: yifei.lou@ece.gatech.edu * c* * c* School of Electrical and Computer Engineering * c* Georgia Institute of Technology * c* Atlanta, GA, 30318 * c* Website: http://groups.bme.gatech.edu/groups/bil/ * c* * c* Copyright (c) 2011 * c* All rights reserved. * c* * c* Permission to use, copy, or modify this code and its * c* documentation for scientific purpose is hereby granted * c* without fee, provided that this copyright notice appear in * c* all copies and that both that copyright notice and this * c* permission notice appear in supporting documentation. The use * c* for commercial purposes is prohibited without permission. * c* * c* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * c* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * c* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * c* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * c* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * c* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * c* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING, BUT NOT * c* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF* c* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * c* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * c* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * c* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * c* THE POSSIBILITY OF SUCH DAMAGE. * c* * c******************************************************************/ /******************************************************************* c* Short discription * c* main function to register two images on the current scale * c* including upsample and downsample * c******************************************************************/ #include #include #include #include #include #include #include #include "viscous_convolution.h" #include "viscous_global.h" // hash a point in the unit square to the index of // the grid bucket that contains it struct point_to_bucket_index : public thrust::unary_function { __host__ __device__ point_to_bucket_index(unsigned int width, unsigned int height) :w(width),h(height){} __host__ __device__ unsigned int operator()(float2 p) const { // find the raster indices of p's bucket unsigned int x = static_cast(p.x * (w-1)); unsigned int y = static_cast(p.y * (h-1)); // return the bucket's linear index return y * w + x; } unsigned int w, h; }; __global__ void downSample(float *src, float *dest, int NX, int NY, int NZ, int s) { const int tid = (blockIdx.y*NBLOCKX + blockIdx.x)*blockDim.x + threadIdx.x; if(tid < NX*NY*NZ) { int z = tid/(NX*NY); int y = (tid%(NX*NY))/NX; int x = tid%NX; float sum =0.0f; for(int xs = 0; xs(); cutilSafeCall( cudaMalloc3DArray(&d_im_move_array, &channelDesc, volumeSize) ); cudaMemcpy3DParms copyParams = {0}; copyParams.srcPtr = make_cudaPitchedPtr((void*)d_im_move, volumeSize.width*sizeof(float), volumeSize.width, volumeSize.height); copyParams.dstArray = d_im_move_array; copyParams.extent = volumeSize; copyParams.kind = cudaMemcpyDeviceToDevice; cutilSafeCall( cudaMemcpy3D(©Params) ); d_im_move_tex.normalized = false; d_im_move_tex.filterMode = cudaFilterModeLinear; cutilSafeCall(cudaBindTextureToArray(d_im_move_tex, d_im_move_array, channelDesc)); // bind vector flows to texture cutilSafeCall( cudaMalloc3DArray(&d_mv_x_array, &channelDesc, volumeSize) ); cudaMemcpy3DParms copyParams_x = {0}; copyParams_x.srcPtr = make_cudaPitchedPtr((void*)d_mv_x, volumeSize.width*sizeof(float), volumeSize.width, volumeSize.height); copyParams_x.dstArray = d_mv_x_array; copyParams_x.extent = volumeSize; copyParams_x.kind = cudaMemcpyDeviceToDevice; cutilSafeCall( cudaMemcpy3D(©Params_x) ); d_mv_x_tex.normalized = false; d_mv_x_tex.filterMode = cudaFilterModeLinear; cutilSafeCall( cudaMalloc3DArray(&d_mv_y_array, &channelDesc, volumeSize) ); cudaMemcpy3DParms copyParams_y = {0}; copyParams_y.srcPtr = make_cudaPitchedPtr((void*)d_mv_y, volumeSize.width*sizeof(float), volumeSize.width, volumeSize.height); copyParams_y.dstArray = d_mv_y_array; copyParams_y.extent = volumeSize; copyParams_y.kind = cudaMemcpyDeviceToDevice; cutilSafeCall( cudaMemcpy3D(©Params_y) ); d_mv_y_tex.normalized = false; d_mv_y_tex.filterMode = cudaFilterModeLinear; cutilSafeCall( cudaMalloc3DArray(&d_mv_z_array, &channelDesc, volumeSize) ); cudaMemcpy3DParms copyParams_z = {0}; copyParams_z.srcPtr = make_cudaPitchedPtr((void*)d_mv_z, volumeSize.width*sizeof(float), volumeSize.width, volumeSize.height); copyParams_z.dstArray = d_mv_z_array; copyParams_z.extent = volumeSize; copyParams_z.kind = cudaMemcpyDeviceToDevice; cutilSafeCall( cudaMemcpy3D(©Params_z) ); d_mv_z_tex.normalized = false; d_mv_z_tex.filterMode = cudaFilterModeLinear; float *d_im_out; cutilSafeCall( cudaMalloc((void **)&d_im_out, sDATA_SIZE) ); // velocity float *d_v_x, *d_v_x_copy; float *d_v_y, *d_v_y_copy; float *d_v_z, *d_v_z_copy; cutilSafeCall( cudaMalloc((void **)&d_v_x, sDATA_SIZE) ); cutilSafeCall( cudaMalloc((void **)&d_v_y, sDATA_SIZE) ); cutilSafeCall( cudaMalloc((void **)&d_v_z, sDATA_SIZE) ); cutilSafeCall( cudaMalloc((void **)&d_v_x_copy, sDATA_SIZE) ); cutilSafeCall( cudaMalloc((void **)&d_v_y_copy, sDATA_SIZE) ); cutilSafeCall( cudaMalloc((void **)&d_v_z_copy, sDATA_SIZE) ); // setup for computing joint histogram via thrust // the grid data structure keeps a range per grid bucket: // each bucket_begin[i] indexes the first element of bucket i's list of points // each bucket_end[i] indexes one past the last element of bucket i's list of points thrust::device_vector bucket_begin(nBin*nBin); thrust::device_vector bucket_end(nBin*nBin); // allocate storage for each point's bucket index thrust::device_vector bucket_indices(NX*NY*NZ); // allocate space to hold per-bucket sizes thrust::device_vector bucket_sizes(nBin*nBin); // allocate float2 vector float2 *d_points; cudaMalloc((void**) &d_points, sizeof(float2)*NX*NY*NZ); int regrid = 0; float MI[1000]; int3 Dims; Dims.x = NX; Dims.y = NY; Dims.z = NZ; for(int it=0; it>>(d_mv_x, d_mv_y, d_mv_z, d_im_out, NX, NY, NZ); // joint histogram via thrust ----- begin // convert to float2 vector transToFloat2<<>>(d_im_out, d_im_static, d_points, NX*NY*NZ); // use a thrust ptr to wrap the raw pointer thrust::device_ptr points_t(d_points); // transform the points to their bucket indices thrust::transform(points_t, points_t+NX*NY*NZ, bucket_indices.begin(), point_to_bucket_index(nBin,nBin)); // sort the bucket index thrust::sort(bucket_indices.begin(), bucket_indices.end()); // find the beginning of each bucket's list of points thrust::counting_iterator search_begin(0); thrust::lower_bound(bucket_indices.begin(), bucket_indices.end(), search_begin, search_begin + nBin*nBin, bucket_begin.begin()); // find the end of each bucket's list of points thrust::upper_bound(bucket_indices.begin(), bucket_indices.end(), search_begin, search_begin + nBin*nBin, bucket_end.begin()); // take the difference between bounds to find each bucket size thrust::transform(bucket_end.begin(), bucket_end.end(), bucket_begin.begin(), bucket_sizes.begin(), thrust :: minus()); // now hist contains the histogram unsigned int *hist = thrust::raw_pointer_cast(&bucket_sizes[0]); copyHist<<>>(hist, d_jointHistogram); // joint histogram via thrust ----- end // compute the convolution of joint histogram myconv2dGPU<<>>(d_jointHistogram, d_jointHistogram_conv, GaussKernelH, nBin, nBin, 3*hValue); // normalize joint histogram float sum = cublasSasum (nBin*nBin, d_jointHistogram_conv , 1); cublasSscal (nBin*nBin, 1.0f/sum, d_jointHistogram_conv, 1); // compute mutual info by GPU marginalDist<<>>(d_jointHistogram_conv, d_probx, d_proby); switch (METHOD) { case 1: marginalBnorm_sum<<>>(d_jointHistogram_conv, d_probx, d_proby, d_jointHistogram); marginalDistAlongY<<>>(d_jointHistogram, d_Bsum); BnormGPU<<>>(d_jointHistogram_conv, d_probx, d_proby,d_Bsum, d_jointHistogram); break; case 2: mutualInfoGPU<<>>(d_jointHistogram_conv, d_probx, d_proby, d_jointHistogram); break; } MI[it] = cublasSasum (nBin*nBin, d_jointHistogram_conv, 1); printf("mutual information (%d)= %f\n", it, MI[it]); // NOTE: after this step, jointHistogram becomes the likelihood // compute the first derivative w.r.t. x-dim of joint histogram myconv2dGPU<<>>(d_jointHistogram, d_jointHistogram_conv, GaussKernelHx, nBin, nBin,3*hValue); // compute the force forceComp<<>>(d_im_out, d_im_static, d_jointHistogram_conv, d_v_x, d_v_y, d_v_z, NX, NY, NZ); ImageSmooth(d_v_x, d_v_x_copy,Dims); ImageSmooth(d_v_y, d_v_y_copy,Dims); ImageSmooth(d_v_z, d_v_z_copy,Dims); flowComp<<>>(d_mv_x, d_mv_y, d_mv_z, d_v_x_copy, d_v_y_copy, d_v_z_copy, d_v_x, d_v_y, NX, NY, NZ); // NOTE: d_v_x is Jacobian, d_v_y is the max flow // d_v_x_copy, d_v_y_copy, d_v_z_copy are the displacement thrust :: device_ptr data_ptr(d_v_y); int maxInd = cublasIsamax(NX*NY*NZ, d_v_y, 1) -1; float maxflow = data_ptr[maxInd]; float dt = (du/maxflow); // > 1) ? 1 : du/maxflow; printf("dt = %f \n", dt); flowUpdate<<>>(d_mv_x, d_mv_y, d_mv_z, d_v_x_copy, d_v_y_copy, d_v_z_copy,dt, NX, NY, NZ); // regridding if Jacobian < threshJaco sum = cublasSasum(NX*NY*NZ, d_v_x, 1); if (sum>0.5) { regrid ++; printf("regrid = %d\n", regrid); // save d_im_move to be d_im_out cudaUnbindTexture(d_im_move_tex); cudaMemcpy3DParms copyParams = {0}; copyParams.srcPtr = make_cudaPitchedPtr((void*)d_im_out, volumeSize.width*sizeof(float), volumeSize.width, volumeSize.height); copyParams.dstArray = d_im_move_array; copyParams.extent = volumeSize; copyParams.kind = cudaMemcpyDeviceToDevice; cutilSafeCall( cudaMemcpy3D(©Params) ); cutilSafeCall(cudaBindTextureToArray(d_im_move_tex, d_im_move_array)); // update vector flow ImageWarp_mv<<>>(d_mv_x, d_mv_y, d_mv_z, NX, NY, NZ); cudaMemcpy3DParms copyParams_x = {0}; copyParams_x.srcPtr = make_cudaPitchedPtr((void*)d_mv_x, volumeSize.width*sizeof(float), volumeSize.width, volumeSize.height); copyParams_x.dstArray = d_mv_x_array; copyParams_x.extent = volumeSize; copyParams_x.kind = cudaMemcpyDeviceToDevice; cutilSafeCall( cudaMemcpy3D(©Params_x) ); cutilSafeCall(cudaBindTextureToArray(d_mv_x_tex, d_mv_x_array)); cudaMemcpy3DParms copyParams_y = {0}; copyParams_y.srcPtr = make_cudaPitchedPtr((void*)d_mv_y, volumeSize.width*sizeof(float), volumeSize.width, volumeSize.height); copyParams_y.dstArray = d_mv_y_array; copyParams_y.extent = volumeSize; copyParams_y.kind = cudaMemcpyDeviceToDevice; cutilSafeCall( cudaMemcpy3D(©Params_y) ); cutilSafeCall(cudaBindTextureToArray(d_mv_y_tex, d_mv_y_array)); cudaMemcpy3DParms copyParams_z = {0}; copyParams_z.srcPtr = make_cudaPitchedPtr((void*)d_mv_z, volumeSize.width*sizeof(float), volumeSize.width, volumeSize.height); copyParams_z.dstArray = d_mv_z_array; copyParams_z.extent = volumeSize; copyParams_z.kind = cudaMemcpyDeviceToDevice; cutilSafeCall( cudaMemcpy3D(©Params_z) ); cutilSafeCall(cudaBindTextureToArray(d_mv_z_tex, d_mv_z_array)); cutilSafeCall( cudaMemset(d_mv_x, 0, sDATA_SIZE) ); cutilSafeCall( cudaMemset(d_mv_y, 0, sDATA_SIZE) ); cutilSafeCall( cudaMemset(d_mv_z, 0, sDATA_SIZE) ); } // end for regridding } // for-loop iteration if (!regrid) { ImageWarp<<>>(d_mv_x, d_mv_y, d_mv_z, d_im_move, NX, NY, NZ); } else { cudaMemcpy3DParms copyParams = {0}; cudaUnbindTexture(d_im_move_tex); copyParams.srcPtr = make_cudaPitchedPtr((void*)d_im_move, volumeSize.width*sizeof(float), volumeSize.width, volumeSize.height); copyParams.dstArray = d_im_move_array; copyParams.extent = volumeSize; copyParams.kind = cudaMemcpyDeviceToDevice; cutilSafeCall( cudaMemcpy3D(©Params) ); cutilSafeCall(cudaBindTextureToArray(d_im_move_tex, d_im_move_array)); ImageWarp_final<<>>(d_mv_x, d_mv_y, d_mv_z,d_im_move, NX, NY, NZ); } cudaFree(d_points); cudaFree(d_v_x); cudaFree(d_v_y); cudaFree(d_v_z); cudaFree(d_v_x_copy); cudaFree(d_v_y_copy); cudaFree(d_v_z_copy); cudaUnbindTexture(d_im_move_tex); cudaFreeArray(d_im_move_array); cudaUnbindTexture(d_mv_x_tex); cudaFreeArray(d_mv_x_array); cudaUnbindTexture(d_mv_y_tex); cudaFreeArray(d_mv_y_array); cudaUnbindTexture(d_mv_z_tex); cudaFreeArray(d_mv_z_array); cudaFree(d_im_out); } __global__ void transToFloat2(const float *input1, const float *input2, float2 *output, const int n) { const int tid = (blockIdx.y*NBLOCKX + blockIdx.x)*blockDim.x + threadIdx.x; // obtain current id on thread if (tid < n) { output[tid] = make_float2(input1[tid], input2[tid]); } } viscous_convolution.cu000066400000000000000000000331751321604176500337740ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/******************************************************************* c* Multimodal Deformable Image Registration * c* via Mutual Information or Bhattacharyya Distantce * c* Version: 1.0 * c* Language: C, CUDA * c* * c* Developer: Yifei Lou * c* Email: yifei.lou@ece.gatech.edu * c* * c* School of Electrical and Computer Engineering * c* Georgia Institute of Technology * c* Atlanta, GA, 30318 * c* Website: http://groups.bme.gatech.edu/groups/bil/ * c* * c* Copyright (c) 2011 * c* All rights reserved. * c* * c* Permission to use, copy, or modify this code and its * c* documentation for scientific purpose is hereby granted * c* without fee, provided that this copyright notice appear in * c* all copies and that both that copyright notice and this * c* permission notice appear in supporting documentation. The use * c* for commercial purposes is prohibited without permission. * c* * c* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * c* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * c* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * c* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * c* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * c* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * c* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING, BUT NOT * c* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF* c* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * c* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * c* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * c* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * c* THE POSSIBILITY OF SUCH DAMAGE. * c* * c******************************************************************/ /******************************************************************* c* Short discription * c* convolution related support functions * c* in SDK as well as developped by Xuejun Gu and Yifei Lou * c******************************************************************/ /* * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ #include #include "viscous_global.h" #include "viscous_convolution.h" //////////////////////////////////////////////////////////////////////////////// // Row convolution filter by Frame //////////////////////////////////////////////////////////////////////////////// __global__ void convolutionRowGPU_byframe( float *d_Result, float *d_Data, int dataW, int dataH, int nF ){ //Data cache __shared__ float data[KERNEL_RADIUS + ROW_TILE_W + KERNEL_RADIUS]; //Current tile and apron limits, relative to row start const int tileStart = IMUL(blockIdx.x, ROW_TILE_W); const int tileEnd = tileStart + ROW_TILE_W - 1; const int apronStart = tileStart - KERNEL_RADIUS; const int apronEnd = tileEnd + KERNEL_RADIUS; //Clamp tile and apron limits by image borders const int tileEndClamped = min(tileEnd, dataW - 1); const int apronStartClamped = max(apronStart, 0); const int apronEndClamped = min(apronEnd, dataW - 1); //Row start index in d_Data[] const int rowStart = nF*dataW*dataH+IMUL(blockIdx.y, dataW); //Aligned apron start. Assuming dataW and ROW_TILE_W are multiples //of half-warp size, rowStart + apronStartAligned is also a //multiple of half-warp size, thus having proper alignment //for coalesced d_Data[] read. const int apronStartAligned = tileStart - KERNEL_RADIUS_ALIGNED; const int loadPos = apronStartAligned + threadIdx.x; //Set the entire data cache contents //Load global memory values, if indices are within the image borders, //or initialize with zeroes otherwise if(loadPos >= apronStart){ const int smemPos = loadPos - apronStart; data[smemPos] = ((loadPos >= apronStartClamped) && (loadPos <= apronEndClamped)) ? d_Data[rowStart + loadPos] : 0; } //Ensure the completness of the loading stage //because results, emitted by each thread depend on the data, //loaded by another threads __syncthreads(); const int writePos = tileStart + threadIdx.x; //Assuming dataW and ROW_TILE_W are multiples of half-warp size, //rowStart + tileStart is also a multiple of half-warp size, //thus having proper alignment for coalesced d_Result[] write. if(writePos <= tileEndClamped){ const int smemPos = writePos - apronStart; float sum = 0; sum = convolutionRow<2 * KERNEL_RADIUS>(data + smemPos); d_Result[rowStart + writePos] = sum; } } //////////////////////////////////////////////////////////////////////////////// // Column convolution filter //////////////////////////////////////////////////////////////////////////////// __global__ void convolutionColumnGPU( float *d_Result, float *d_Data, int dataW, int dataH, int smemStride, int gmemStride, int nF ){ //Data cache __shared__ float data[COLUMN_TILE_W * (KERNEL_RADIUS + COLUMN_TILE_H + KERNEL_RADIUS)]; //Current tile and apron limits, in rows const int tileStart = IMUL(blockIdx.y, COLUMN_TILE_H); const int tileEnd = tileStart + COLUMN_TILE_H - 1; const int apronStart = tileStart - KERNEL_RADIUS; const int apronEnd = tileEnd + KERNEL_RADIUS; //Clamp tile and apron limits by image borders const int tileEndClamped = min(tileEnd, dataH - 1); const int apronStartClamped = max(apronStart, 0); const int apronEndClamped = min(apronEnd, dataH - 1); //Current column index const int columnStart = IMUL(blockIdx.x, COLUMN_TILE_W) + threadIdx.x; //Shared and global memory indices for current column int smemPos = IMUL(threadIdx.y, COLUMN_TILE_W) + threadIdx.x; //int gmemPos = IMUL(apronStart + threadIdx.y, dataW) + columnStart; int gmemPos = IMUL(apronStart + threadIdx.y, dataW) + columnStart + nF *dataH *dataW; // added by xuejun //Cycle through the entire data cache //Load global memory values, if indices are within the image borders, //or initialize with zero otherwise for(int y = apronStart + threadIdx.y; y <= apronEnd; y += blockDim.y){ data[smemPos] = ((y >= apronStartClamped) && (y <= apronEndClamped)) ? d_Data[gmemPos] : 0; smemPos += smemStride; gmemPos += gmemStride; } //Ensure the completness of the loading stage //because results, emitted by each thread depend on the data, //loaded by another threads __syncthreads(); //Shared and global memory indices for current column smemPos = IMUL(threadIdx.y + KERNEL_RADIUS, COLUMN_TILE_W) + threadIdx.x; //gmemPos = IMUL(tileStart + threadIdx.y , dataW) + columnStart; gmemPos = IMUL(tileStart + threadIdx.y , dataW) + columnStart + nF *dataH *dataW; // added by xuejun //Cycle through the tile body, clamped by image borders //Calculate and output the results for(int y = tileStart + threadIdx.y; y <= tileEndClamped; y += blockDim.y){ float sum = 0; sum = convolutionColumn<2 * KERNEL_RADIUS>(data + smemPos); d_Result[gmemPos] = sum; smemPos += smemStride; gmemPos += gmemStride; } } //////////////////////////////////////////////////////////////////////////////// // Frame convolution filter //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Frame convolution filter //////////////////////////////////////////////////////////////////////////////// __global__ void convolutionFrameGPU( float *d_Result, float *d_Data, int dataW, int dataH, int smemStride, int gmemStride ){ //Data cache __shared__ float data[COLUMN_TILE_W * (KERNEL_RADIUS + COLUMN_TILE_H + KERNEL_RADIUS)]; //Current tile and apron limits, in rows const int tileStart = IMUL(blockIdx.y, COLUMN_TILE_H); const int tileEnd = tileStart + COLUMN_TILE_H - 1; const int apronStart = tileStart - KERNEL_RADIUS; const int apronEnd = tileEnd + KERNEL_RADIUS; //Clamp tile and apron limits by image borders const int tileEndClamped = min(tileEnd, dataH - 1); const int apronStartClamped = max(apronStart, 0); const int apronEndClamped = min(apronEnd, dataH - 1); //Current column index const int columnStart = IMUL(blockIdx.x, COLUMN_TILE_W) + threadIdx.x; //Shared and global memory indices for current column int smemPos = IMUL(threadIdx.y, COLUMN_TILE_W) + threadIdx.x; int gmemPos = IMUL(apronStart + threadIdx.y, dataW) + columnStart; //Cycle through the entire data cache //Load global memory values, if indices are within the image borders, //or initialize with zero otherwise for(int y = apronStart + threadIdx.y; y <= apronEnd; y += blockDim.y){ data[smemPos] = ((y >= apronStartClamped) && (y <= apronEndClamped)) ? d_Data[gmemPos] : 0; smemPos += smemStride; gmemPos += gmemStride; } //Ensure the completness of the loading stage //because results, emitted by each thread depend on the data, //loaded by another threads __syncthreads(); //Shared and global memory indices for current column smemPos = IMUL(threadIdx.y + KERNEL_RADIUS, COLUMN_TILE_W) + threadIdx.x; gmemPos = IMUL(tileStart + threadIdx.y , dataW) + columnStart; //Cycle through the tile body, clamped by image borders //Calculate and output the results for(int y = tileStart + threadIdx.y; y <= tileEndClamped; y += blockDim.y){ float sum = 0; sum = convolutionColumn<2 * KERNEL_RADIUS>(data + smemPos); d_Result[gmemPos] = sum; smemPos += smemStride; gmemPos += gmemStride; } } /**************************************************************************/ /********** Doing low pass filter on an image function ****************/ /**************************************************************************/ void ImageSmooth(float *d_image, float *d_image_conv, int3 Dims) { //Dims: size of image int DATA_W = Dims.x, DATA_H = Dims.y, DATA_F = Dims.z; float *d_temp; int SDATA_SIZE = DATA_W*DATA_H*DATA_F*sizeof(float); cudaMalloc((void**)&d_temp, SDATA_SIZE); // row convolution: dim3 blockGridRows(iDivUp(DATA_W, ROW_TILE_W), DATA_H, 1); dim3 threadBlockRows(KERNEL_RADIUS_ALIGNED + ROW_TILE_W + KERNEL_RADIUS, 1); cudaMemset((void*)d_image_conv, 0, SDATA_SIZE); for (int nF = 0; nF < DATA_F; nF++){ convolutionRowGPU_byframe<<>>(d_image_conv, d_image,DATA_W, DATA_H, nF); cutilCheckMsg("convolutionRowGPU() execution failed\n"); } //column convolution dim3 blockGridColumns(iDivUp(DATA_W, COLUMN_TILE_W),iDivUp(DATA_H, COLUMN_TILE_H), 1); dim3 threadBlockColumns(COLUMN_TILE_W, 8); cudaMemset((void*)d_temp, 0, SDATA_SIZE); for (int nF = 0; nF < DATA_F; nF++){ convolutionColumnGPU<<>> (d_temp, d_image_conv, DATA_W, DATA_H, COLUMN_TILE_W * threadBlockColumns.y,DATA_W * threadBlockColumns.y,nF); cutilCheckMsg("convolutionColumnGPU() execution failed\n"); } // frame convolution dim3 blockGridFrames(iDivUp(DATA_W *DATA_H , COLUMN_TILE_W),iDivUp(DATA_F, COLUMN_TILE_H),1) ; dim3 threadBlockFrames(COLUMN_TILE_W, 8); cudaMemset((void*)d_image_conv, 0, SDATA_SIZE); convolutionFrameGPU<<>> (d_image_conv, d_temp, DATA_W *DATA_H, DATA_F, COLUMN_TILE_W * threadBlockFrames.y,DATA_W*DATA_H * threadBlockFrames.y); cutilCheckMsg("convolutionFrameGPU() execution failed\n"); cudaFree(d_temp); } __global__ void myconv2dGPU(float *src, float *dest, float *kernel, int M, int N, int kn) // [M,N] = size(src); kernel size = 2*kn +1 // symmetric boundary condition { const int tid = (blockIdx.y*NBLOCKX + blockIdx.x)*blockDim.x + threadIdx.x; if (tid= M) x0 = 2*M-1-x+2*i; for(int j = -kn; j<=kn; j++) { y0 = y; if(y-j<0) y0 = -1+2*j-y; if(y-j>=N) y0 = 2*N-1-y+2*j; sum += kernel[(j+kn)*(2*kn+1)+(i+kn)]*src[(y0-j)*M+(x0-i)]; } } dest[tid] = sum; } } viscous_cuda.h000066400000000000000000000010341321604176500321360ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _viscous_cuda_h_ #define _viscous_cuda_h_ #include "plmregister_config.h" #include "delayload.h" #if defined __cplusplus extern "C" { #endif PLMREGISTERCUDA_API DELAYLOAD_WRAP ( int CUDA_viscous_main, int argc, char** argv ); #if defined __cplusplus } #endif #endif viscous_finalize.cu000066400000000000000000000116301321604176500332060ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/******************************************************************* c* Multimodal Deformable Image Registration * c* via Mutual Information or Bhattacharyya Distantce * c* Version: 1.0 * c* Language: C, CUDA * c* * c* Developer: Yifei Lou * c* Email: yifei.lou@ece.gatech.edu * c* * c* School of Electrical and Computer Engineering * c* Georgia Institute of Technology * c* Atlanta, GA, 30318 * c* Website: http://groups.bme.gatech.edu/groups/bil/ * c* * c* Copyright (c) 2011 * c* All rights reserved. * c* * c* Permission to use, copy, or modify this code and its * c* documentation for scientific purpose is hereby granted * c* without fee, provided that this copyright notice appear in * c* all copies and that both that copyright notice and this * c* permission notice appear in supporting documentation. The use * c* for commercial purposes is prohibited without permission. * c* * c* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * c* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * c* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * c* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * c* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * c* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * c* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING, BUT NOT * c* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF* c* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * c* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * c* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * c* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * c* THE POSSIBILITY OF SUCH DAMAGE. * c* * c******************************************************************/ /******************************************************************* c* Short discription * c* Finalize the reconstruction on the current scale and for the * c* entire program, output results, release memory spaces for * c* global variables, etc. * c******************************************************************/ #include #include #include #include #include "viscous_global.h" void fina() { // map output image to its original scale nblocks.x = NBLOCKX; nblocks.y = ((1 + (NX0*NY0*NZ0 - 1)/NTHREAD_PER_BLOCK) - 1) / NBLOCKX + 1; printf("moving image: max = %f, min = %f\n", max_im_move, min_im_move); intensityRescale<<>>(d_im_move[0], max_im_move, min_im_move, -1); // output results outputData(d_im_move[0], DATA_SIZE, outputfilename); outputData(d_mv_x[0], DATA_SIZE, output_mv_x); outputData(d_mv_y[0], DATA_SIZE, output_mv_y); outputData(d_mv_z[0], DATA_SIZE, output_mv_z); // free up the host and device // image pyramid for(int scale =0; scale 0) { if(probx[i]>0 && proby[j]>0) likelihood[tid] = log2f(likelihood[tid]/probx[i]/proby[j]); else likelihood[tid] = log2f(likelihood[tid]); jointHist[tid] = jointHist[tid]*likelihood[tid]; } } } __global__ void marginalBnorm_sum(float *jointHist, float *probx, float *proby, float *Bsum) { const int tid = (blockIdx.y*NBLOCKX + blockIdx.x)*blockDim.x + threadIdx.x; if (tid=0) x = ImageGradient(d_im_out[zmin*NX*NY + ymin*NX + (xmin-1) ], d_im_out[zmin*NX*NY +ymin*NX + xmin], d_im_out[zmin*NX*NY +ymin*NX + (xmin+1)]); else x = 0; if(ymin+1 < NY && ymin-1>=0) y = ImageGradient(d_im_out[zmin*NX*NY +(ymin-1)*NX + xmin], d_im_out[zmin*NX*NY +ymin*NX+ xmin], d_im_out[zmin*NX*NY +(ymin+1)*NX+xmin]); else y = 0; if(zmin+1 =0) z = ImageGradient(d_im_out[(zmin-1)*NX*NY + ymin*NX + xmin], d_im_out[zmin*NX*NY + ymin*NX + xmin],d_im_out[(zmin+1)*NX*NY + ymin*NX + xmin]); else z = 0; d_v_x[tid] = -ALPHA*dLx*x; d_v_y[tid] = -ALPHA*dLx*y; d_v_z[tid] = -ALPHA*dLx*z; } } __global__ void flowComp(float *d_mv_x, float *d_mv_y, float *d_mv_z, float *d_v_x, float *d_v_y, float *d_v_z, float *jacobian, float *flow, int NX, int NY, int NZ) { const int tid = (blockIdx.y*NBLOCKX + blockIdx.x)*blockDim.x + threadIdx.x; if (tid=0) { u1x = ImageGradient(d_mv_x[z*NX*NY+y*NX+x-1], d_mv_x[z*NX*NY+y*NX+x], d_mv_x[z*NX*NY+y*NX+x+1]); u2x = ImageGradient(d_mv_y[z*NX*NY+y*NX+x-1], d_mv_y[z*NX*NY+y*NX+x], d_mv_y[z*NX*NY+y*NX+x+1]); u3x = ImageGradient(d_mv_z[z*NX*NY+y*NX+x-1], d_mv_z[z*NX*NY+y*NX+x], d_mv_y[z*NX*NY+y*NX+x+1]); } else { u1x = 0; u2x = 0; u3x = 0; } if(y+1=0) { u1y = ImageGradient(d_mv_x[z*NX*NY+(y-1)*NX+x], d_mv_x[z*NX*NY+y*NX+x], d_mv_x[z*NX*NY+(y+1)*NX+x]); u2y = ImageGradient(d_mv_y[z*NX*NY+(y-1)*NX+x], d_mv_y[z*NX*NY+y*NX+x], d_mv_y[z*NX*NY+(y+1)*NX+x]); u3y = ImageGradient(d_mv_z[z*NX*NY+(y-1)*NX+x], d_mv_z[z*NX*NY+y*NX+x], d_mv_z[z*NX*NY+(y+1)*NX+x]); } else { u1y = 0; u2y = 0; u3y = 0; } if(z+1=0) { u1z = ImageGradient(d_mv_x[(z-1)*NX*NY+y*NX+x], d_mv_x[z*NX*NY+y*NX+x], d_mv_x[(z+1)*NX*NY+y*NX+x]); u2z = ImageGradient(d_mv_y[(z-1)*NX*NY+y*NX+x], d_mv_y[z*NX*NY+y*NX+x], d_mv_y[(z+1)*NX*NY+y*NX+x]); u3z = ImageGradient(d_mv_z[(z-1)*NX*NY+y*NX+x], d_mv_z[z*NX*NY+y*NX+x], d_mv_z[(z+1)*NX*NY+y*NX+x]); } else { u1z = 0; u2z = 0; u3z = 0; } float R1 = d_v_x[tid] - d_v_x[tid]*u1x - d_v_y[tid]*u1y - d_v_z[tid]*u1z; float R2 = d_v_y[tid] - d_v_x[tid]*u2x - d_v_y[tid]*u2y - d_v_z[tid]*u2z; float R3 = d_v_z[tid] - d_v_x[tid]*u3x - d_v_y[tid]*u3y - d_v_z[tid]*u3z; float jaco = (1.0f-u1x)*(1.0f-u2y)*(1.0f-u3z)-u3x*u1y*u2z - u2x*u3y*u1z -(1.0f-u1x)*u3y*u2z - u3x*(1.0f-u2y)*u1z - u2x*u1y*(1.0f-u3z); jacobian[tid] = (fabs(jaco)<= threshJaco) ? 1.0f : 0.0f; flow[tid] = sqrtf(R1 * R1 + R2 * R2 + R3 * R3); // d_v_x, d_v_y, d_v_z become displacement d_v_x[tid] = R1; d_v_y[tid] = R2; d_v_z[tid] = R3; } } __global__ void flowUpdate(float *d_mv_x, float *d_mv_y, float *d_mv_z, float *d_disp_x, float *d_disp_y, float *d_disp_z, float dt, int NX, int NY, int NZ) { const int tid = (blockIdx.y*NBLOCKX + blockIdx.x)*blockDim.x + threadIdx.x; if (tid0) { if(x>y) return y; else return x; } else { if(x>y) return x; else return y; } } viscous_initialize.cu000066400000000000000000000227021321604176500335500ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/******************************************************************* c* Multimodal Deformable Image Registration * c* via Mutual Information or Bhattacharyya Distantce * c* Version: 1.0 * c* Language: C, CUDA * c* * c* Developer: Yifei Lou * c* Email: yifei.lou@ece.gatech.edu * c* * c* School of Electrical and Computer Engineering * c* Georgia Institute of Technology * c* Atlanta, GA, 30318 * c* Website: http://groups.bme.gatech.edu/groups/bil/ * c* * c* Copyright (c) 2011 * c* All rights reserved. * c* * c* Permission to use, copy, or modify this code and its * c* documentation for scientific purpose is hereby granted * c* without fee, provided that this copyright notice appear in * c* all copies and that both that copyright notice and this * c* permission notice appear in supporting documentation. The use * c* for commercial purposes is prohibited without permission. * c* * c* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * c* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * c* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * c* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * c* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * c* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * c* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING, BUT NOT * c* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF* c* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * c* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * c* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * c* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * c* THE POSSIBILITY OF SUCH DAMAGE. * c* * c******************************************************************/ /******************************************************************* c* Short discription * c* initialization of the entire program including * c* data preprocessing, construction of image pyramid * c* and Gaussian smoothing kernels * c******************************************************************/ #include #include #include #include #include #include "viscous_convolution.h" #include "viscous_global.h" void dataPreprocessing(float *image, float *maxValue, float *minValue) { thrust :: device_ptr data_ptr(image); int maxInd = cublasIsamax(NX0*NY0*NZ0, image, 1) -1; int minInd = cublasIsamin(NX0*NY0*NZ0, image, 1) -1; *maxValue = data_ptr[maxInd]; *minValue = data_ptr[minInd]; nblocks.x = NBLOCKX; nblocks.y = ((1 + (NX0*NY0*NZ0 - 1)/NTHREAD_PER_BLOCK) - 1) / NBLOCKX + 1; intensityRescale<<>>(image, *maxValue, *minValue, 1); } __global__ void intensityRescale(float *image, float maxValue, float minValue, int type) // type > 0: forward // type < 0: backward { const int tid = (blockIdx.y*NBLOCKX + blockIdx.x)*blockDim.x + threadIdx.x; if(tid < NX0*NY0*NZ0) { if(type>0) image[tid] = (image[tid] - minValue)/(maxValue-minValue); else image[tid] = image[tid]*(maxValue-minValue) + minValue; } } __global__ void short2float(short *raw, float *image, int type) { const int tid = (blockIdx.y*NBLOCKX + blockIdx.x)*blockDim.x + threadIdx.x; if(tid < NX0*NY0*NZ0) { if (type>0) image[tid] = (float) raw[tid]; else raw[tid] = (short) image[tid]; } } void initData() { // load static and moving images on host float *h_im_static = (float*)malloc(DATA_SIZE); loadData(h_im_static, DATA_SIZE, inputfilename_static); float *h_im_move = (float *)malloc(DATA_SIZE); loadData(h_im_move, DATA_SIZE, inputfilename_move); // create image pyramid on device // finest level 0 cutilSafeCall( cudaMalloc((void**) &d_im_move[0], DATA_SIZE ) ); cutilSafeCall( cudaMalloc((void**) &d_im_static[0],DATA_SIZE) ); cutilSafeCall( cudaMemcpy(d_im_static[0], h_im_static, DATA_SIZE, cudaMemcpyHostToDevice) ); cutilSafeCall( cudaMemcpy(d_im_move[0], h_im_move, DATA_SIZE, cudaMemcpyHostToDevice) ); free(h_im_static); free(h_im_move); // scale intensity to [0, 1] dataPreprocessing(d_im_static[0],&max_im_move, &min_im_move); dataPreprocessing(d_im_move[0], &max_im_move, &min_im_move); // vector flow cutilSafeCall( cudaMalloc((void **)&d_mv_x[0], DATA_SIZE) ); cutilSafeCall( cudaMalloc((void **)&d_mv_y[0], DATA_SIZE) ); cutilSafeCall( cudaMalloc((void **)&d_mv_z[0], DATA_SIZE) ); cutilSafeCall( cudaMemset(d_mv_x[0], 0, DATA_SIZE) ); cutilSafeCall( cudaMemset(d_mv_y[0], 0, DATA_SIZE) ); cutilSafeCall( cudaMemset(d_mv_z[0], 0, DATA_SIZE) ); // coarse levels for(int scale = 1; scale < NSCALE; scale ++) { NX = NX0/pow(2, scale); NY = NY0/pow(2, scale); NZ = (NZ0-1)/pow(2, scale) +1; sDATA_SIZE = sizeof(float)*NX*NY*NZ; cutilSafeCall( cudaMalloc((void**) &d_im_move[scale], sDATA_SIZE ) ); cutilSafeCall( cudaMalloc((void**) &d_im_static[scale], sDATA_SIZE ) ); nblocks.x = NBLOCKX; nblocks.y = ((1 + (NX*NY*NZ - 1)/NTHREAD_PER_BLOCK) - 1) / NBLOCKX + 1; int s = pow(2, scale); downSample<<>>(d_im_move[0], d_im_move[scale], NX, NY, NZ, s); downSample<<>>(d_im_static[0], d_im_static[scale],NX, NY, NZ, s); cutilSafeCall( cudaMalloc((void **)&d_mv_x[scale], sDATA_SIZE ) ); cutilSafeCall( cudaMalloc((void **)&d_mv_y[scale], sDATA_SIZE ) ); cutilSafeCall( cudaMalloc((void **)&d_mv_z[scale], sDATA_SIZE ) ); cutilSafeCall( cudaMemset(d_mv_x[scale], 0, sDATA_SIZE ) ); cutilSafeCall( cudaMemset(d_mv_y[scale], 0, sDATA_SIZE ) ); cutilSafeCall( cudaMemset(d_mv_z[scale], 0, sDATA_SIZE ) ); } std::cout << "Load data successfully.\n\n"; // allocate space for histogram related variables cutilSafeCall( cudaMalloc(&d_jointHistogram, HIST_SIZE) ); cutilSafeCall( cudaMalloc(&d_jointHistogram_conv, HIST_SIZE) ); cutilSafeCall( cudaMalloc((void **)&d_probx, sizeof(float)*nBin) ); cutilSafeCall( cudaMalloc((void **)&d_proby, sizeof(float)*nBin) ); cutilSafeCall( cudaMalloc((void **)&d_Bsum,sizeof(float)*nBin ) ); } void initGaussKernel() { std::cout << "Initializing Gaussian kernel..." << std::endl; float *h_GaussKernelH = (float *)malloc(sizeof(float)*(6*hValue+1)*(6*hValue+1)); float *h_GaussKernelHx = (float *)malloc(sizeof(float)*(6*hValue+1)*(6*hValue+1)); cutilSafeCall( cudaMalloc(&GaussKernelH, sizeof(float)*(6*hValue+1)*(6*hValue+1) ) ); cutilSafeCall( cudaMalloc(&GaussKernelHx, sizeof(float)*(6*hValue+1)*(6*hValue+1) ) ); float sum = 0.0; for(int i = -3*hValue; i <= 3*hValue; i++) { for(int j = -3*hValue; j <= 3*hValue; j++) { float temp = expf(-(i*i+j*j)/2.0/hValue/hValue); h_GaussKernelH[(i+3*hValue)+(j+3*hValue)*(6*hValue+1)] = temp; sum += temp; h_GaussKernelHx[(i+3*hValue)+(j+3*hValue)*(6*hValue+1)] = -i*temp/hValue/hValue; } } for(int i = -3*hValue; i <= 3*hValue; i++) { for(int j = -3*hValue; j <= 3*hValue; j++) { h_GaussKernelH[(i+3*hValue)+(j+3*hValue)*(6*hValue+1)] /= sum; h_GaussKernelHx[(i+3*hValue)+(j+3*hValue)*(6*hValue+1)] /= sum; } } cutilSafeCall( cudaMemcpy(GaussKernelH, h_GaussKernelH, sizeof(float)*(6*hValue+1)*(6*hValue+1), cudaMemcpyHostToDevice) ); cutilSafeCall( cudaMemcpy(GaussKernelHx, h_GaussKernelHx, sizeof(float)*(6*hValue+1)*(6*hValue+1), cudaMemcpyHostToDevice) ); free(h_GaussKernelH); free(h_GaussKernelHx); float *h_GaussKernel1D = (float *)malloc(sizeof(float)*KERNEL_W); float sumK = 0.0; for(int i = 0; i < KERNEL_W; i++) { h_GaussKernel1D[i] = expf(-(i-KERNEL_RADIUS)*(i-KERNEL_RADIUS)/2.0/sValue/sValue); sumK += h_GaussKernel1D[i]; } for(int i = 0; i < KERNEL_W; i++) h_GaussKernel1D[i] /= sumK; cudaMemcpyToSymbol(d_Kernel, h_GaussKernel1D, KERNEL_W * sizeof(float)); free(h_GaussKernel1D); } void loadData(float *dest, int sizeInByte, const char *filename) // load data { FILE *fp = fopen(filename,"rb"); if( fp == NULL ) { printf(" File \'%s\' could not be opened!\n", filename); exit(1); } else{ printf("Reading File \'%s\' ... \n", filename); size_t temp = fread(dest, 1, sizeInByte, fp); fclose(fp); } } viscous_main.cu000066400000000000000000000242211321604176500323310ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/cuda/******************************************************************* c* Multimodal Deformable Image Registration * c* via Mutual Information or Bhattacharyya Distantce * c* Version: 1.0 * c* Language: C, CUDA * c* * c* Developer: Yifei Lou * c* Email: yifei.lou@ece.gatech.edu * c* * c* School of Electrical and Computer Engineering * c* Georgia Institute of Technology * c* Atlanta, GA, 30318 * c* Website: http://groups.bme.gatech.edu/groups/bil/ * c* * c* Copyright (c) 2011 * c* All rights reserved. * c* * c* Permission to use, copy, or modify this code and its * c* documentation for scientific purpose is hereby granted * c* without fee, provided that this copyright notice appear in * c* all copies and that both that copyright notice and this * c* permission notice appear in supporting documentation. The use * c* for commercial purposes is prohibited without permission. * c* * c* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * c* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * c* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * c* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * c* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * c* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * c* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING, BUT NOT * c* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF* c* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * c* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * c* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * c* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * c* THE POSSIBILITY OF SUCH DAMAGE. * c* * c******************************************************************/ /******************************************************************* c* Short discription * c* main code of the multi-modal deformable registration * c* it calls all the other components * c******************************************************************/ // includes, system #include #include #include #include #define GCS_REPRESS_EXTERNS // includes, gloable variables #include "viscous_global.h" //#include "convolution.cu" #include "viscous_cuda.h" // includes, project #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for float2 using namespace std; using namespace thrust; // include files //#include "initialize.cu" //#include "funcHistogram.cu" //#include "funcImageDomain.cu" //#include "compute.cu" //#include "finalize.cu" /* Global variables */ /*************************************** * global variables declaration ***************************************/ char inputfilename_move[100] = "./inputDTI.raw"; // image move char inputfilename_static[100] = "./inputT2.raw"; // image static char outputfilename[100] = "./outputDTI.raw"; // image out char output_mv_x[100] = "./output_xFlow.dat"; char output_mv_y[100] = "./output_yFlow.dat"; char output_mv_z[100] = "./output_zFlow.dat"; float *h_im_static, *h_im_move; // image pyramid float *d_im_static[NSCALE], *d_im_move[NSCALE]; // vector flow float *d_mv_x[NSCALE], *d_mv_y[NSCALE], *d_mv_z[NSCALE]; // gaussian kernel float *GaussKernelH, *GaussKernelHx; // histogram related float *d_jointHistogram; float *d_jointHistogram_conv; float *d_probx, *d_proby; float *d_Bsum; dim3 nblocks; dim3 nblocks_hist; int NX, NY, NZ, sDATA_SIZE; // dimension at current pyramid level float max_im_move, min_im_move; // max and min intensity of the moving image cudaArray *d_im_move_array; texture d_im_move_tex; cudaArray *d_mv_x_array, *d_mv_y_array, *d_mv_z_array; texture d_mv_x_tex; texture d_mv_y_tex; texture d_mv_z_tex; int deviceCount; cudaDeviceProp dP; /**************************************************** main program ****************************************************/ int CUDA_viscous_main ( int argc, char** argv ) { cout << endl << "****************************************" << endl; cout << "Computation parameters..." << endl; cout << "****************************************" << endl ; int device = DEVICENUMBER; // device number cudaSetDevice(device); cout << "Using device # " << device << endl; // choose which device to use cudaGetDeviceCount(&deviceCount); cudaGetDeviceProperties(&dP,device); cout<<"Max threads per block: "<=0; scale--) { NX = NX0/pow(2, scale); NY = NY0/pow(2, scale); NZ = (NZ0-1)/pow(2, scale) + 1; sDATA_SIZE = (NX*NY*NZ)* sizeof(float); nblocks.x = NBLOCKX; nblocks.y = ((1 + (NX*NY*NZ - 1)/NTHREAD_PER_BLOCK) - 1) / NBLOCKX + 1; printf ("current scale = %d, size of image = %d x %d x %d ... \n", scale, NX, NY, NZ); if(scale>>( d_mv_x[scale+1], d_mv_x[scale], NX, NY, NZ); upSample<<>>( d_mv_y[scale+1], d_mv_y[scale], NX, NY, NZ); upSample<<>>( d_mv_z[scale+1], d_mv_z[scale], NX, NY, NZ); } compute ( d_im_move[scale], d_im_static[scale], d_mv_x[scale], d_mv_y[scale], d_mv_z[scale], MAX_ITER); printf("\n\n"); } cudaThreadSynchronize(); #if defined (commentout) cutilCheckError( cutStopTimer( timer)); printf("\n\n****************************************\n"); printf( "Computing time: %f (ms)\n", cutGetTimerValue( timer)); printf("****************************************\n\n\n"); cutilCheckError( cutDeleteTimer( timer)); #endif // mark the end timer and print /****************************************************** finalize ******************************************************/ printf("Finalizing program...\n\n"); fina(); /**** shut down CBLAS ********/ status = cublasShutdown(); if (status != CUBLAS_STATUS_SUCCESS) { fprintf (stderr, "!!!! shutdown error (A)\n"); getchar(); exit(0); } // Shut down CUBLAS cudaThreadSynchronize(); // mark the end total timer #if defined (commentout) cutilCheckError( cutStopTimer( totalTimer)); printf("\n\n****************************************\n"); printf( "Entire program time: %f (ms)\n", cutGetTimerValue( totalTimer)); printf("****************************************\n\n\n"); cutilCheckError( cutDeleteTimer( totalTimer)); #endif printf("Have a nice day!\n"); cudaThreadExit(); #if defined (commentout) cutilExit(argc, argv); #endif return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/demons.cxx000066400000000000000000000036321321604176500304600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #ifndef _WIN32 #include #endif #include "delayload.h" #include "demons.h" #include "demons_cuda.h" #include "demons_state.h" void demons_default_parms (Demons_parms* parms) { parms->threading = THREADING_CPU_OPENMP; parms->accel = 1.0; parms->denominator_eps = 1.0; parms->filter_width[0] = 3; parms->filter_width[1] = 3; parms->filter_width[2] = 3; /* GCS FIX: ITK uses sum_d(pix_spacing[d]^2) / (#dim) for homog */ parms->homog = 1.0; parms->max_its = 10; parms->filter_std = 5.0; } Volume* demons ( Volume* fixed, Volume* moving, Volume* moving_grad, Volume* vf_init, Demons_parms* parms ) { #if (CUDA_FOUND || OPENCL_FOUND) Volume* tmp; #endif switch (parms->threading) { #if CUDA_FOUND case THREADING_CUDA: { /* Eventually, all implementation should use demons_state */ Demons_state demons_state; demons_state.init (fixed, moving, moving_grad, vf_init, parms); LOAD_LIBRARY_SAFE (libplmregistercuda); LOAD_SYMBOL (demons_cuda, libplmregistercuda); demons_cuda (&demons_state, fixed, moving, moving_grad, vf_init, parms); UNLOAD_LIBRARY (libplmregistercuda); /* GCS FIX: This leaks vf_est... */ tmp = demons_state.vf_smooth; return tmp; } #endif #if OPENCL_FOUND case THREADING_OPENCL: tmp = demons_opencl (fixed, moving, moving_grad, vf_init, parms); return tmp; #endif case THREADING_CPU_SINGLE: case THREADING_CPU_OPENMP: default: return demons_c (fixed, moving, moving_grad, vf_init, parms); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/demons.h000066400000000000000000000020541321604176500301020ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _demons_h_ #define _demons_h_ #include "plmregister_config.h" #include "threading.h" class Volume; class Demons_parms { public: Threading threading; float denominator_eps; float homog; float accel; int filter_width[3]; int max_its; float filter_std; }; PLMREGISTER_API void demons_default_parms (Demons_parms* parms); PLMREGISTER_API Volume* demons ( Volume* fixed, Volume* moving, Volume* moving_grad, Volume* vf_init, Demons_parms* parms ); Volume* demons_c ( Volume* fixed, Volume* moving, Volume* moving_grad, Volume* vf_init, Demons_parms* parms ); //plmopencl_EXPORT ( Volume* demons_opencl ( Volume* fixed, Volume* moving, Volume* moving_grad, Volume* vf_init, Demons_parms* parms ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/demons_cpu.cxx000066400000000000000000000137121321604176500313270ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include "demons.h" #include "gaussian.h" #include "plm_int.h" #include "plm_math.h" #include "plm_timer.h" #include "vf_convolve.h" #include "volume.h" /* Vector fields are all in mm units */ Volume* demons_c ( Volume* fixed, Volume* moving, Volume* moving_grad, Volume* vf_init, Demons_parms* parms) { plm_long i, j, k, v; int it; /* Iterations */ plm_long fi, fj, fk, fv; /* Indices into fixed image */ float f2mo[3]; /* Origin difference (in mm) from fixed to moving */ float f2ms[3]; /* Slope to convert fixed to moving */ float invmps[3]; /* 1/pixel spacing of moving image */ float *kerx, *kery, *kerz; float *dxyz; float mi, mj, mk; int mx, my, mz; plm_long mv; int fw[3]; double diff_run; Volume *vf_est, *vf_smooth; Volume *m_grad_mag; float *f_img = (float*) fixed->img; float *m_img = (float*) moving->img; float *m_grad_img = (float*) moving_grad->img; float *m_grad_mag_img; float *vox_grad, vox_grad_mag; float diff, mult, denom; float *vf_est_img, *vf_smooth_img; size_t inliers; float ssd; /* Allocate memory for vector fields */ if (vf_init) { /* If caller has an initial estimate, we copy it */ vf_smooth = volume_clone (vf_init); vf_convert_to_interleaved (vf_smooth); } else { /* Otherwise initialize to zero */ vf_smooth = new Volume (fixed->dim, fixed->origin, fixed->spacing, fixed->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); } vf_est = new Volume (fixed->dim, fixed->origin, fixed->spacing, fixed->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); vf_est_img = (float*) vf_est->img; vf_smooth_img = (float*) vf_smooth->img; m_grad_mag = new Volume (moving->dim, moving->origin, moving->spacing, moving->direction_cosines, PT_FLOAT, 1); m_grad_mag_img = (float*) m_grad_mag->img; /* Create gradient magnitude image */ for (v = 0, k = 0; k < moving->dim[2]; k++) { for (j = 0; j < moving->dim[1]; j++) { for (i = 0; i < moving->dim[0]; i++, v++) { vox_grad = &m_grad_img[3*v]; m_grad_mag_img[v] = vox_grad[0] * vox_grad[0] + vox_grad[1] * vox_grad[1] + vox_grad[2] * vox_grad[2]; } } } /* Validate filter widths */ validate_filter_widths (fw, parms->filter_width); /* Create the seperable smoothing kernels for the x, y, and z directions */ kerx = create_ker (parms->filter_std / fixed->spacing[0], fw[0]/2); kery = create_ker (parms->filter_std / fixed->spacing[1], fw[1]/2); kerz = create_ker (parms->filter_std / fixed->spacing[2], fw[2]/2); kernel_stats (kerx, kery, kerz, fw); /* Compute some variables for converting pixel sizes / origins */ for (i = 0; i < 3; i++) { invmps[i] = 1 / moving->spacing[i]; f2mo[i] = (fixed->origin[i] - moving->origin[i]) / moving->spacing[i]; f2ms[i] = fixed->spacing[i] / moving->spacing[i]; } Plm_timer* timer = new Plm_timer; Plm_timer* it_timer = new Plm_timer; timer->start (); it_timer->start (); /* Main loop through iterations */ for (it = 0; it < parms->max_its; it++) { /* Estimate displacement, store into vf_est */ inliers = 0; ssd = 0.0; memcpy (vf_est_img, vf_smooth_img, vf_est->npix * vf_est->pix_size); for (fv = 0, fk = 0, mk = f2mo[2]; fk < fixed->dim[2]; fk++, mk+=f2ms[2]) { for (fj = 0, mj = f2mo[1]; fj < fixed->dim[1]; fj++, mj+=f2ms[1]) { for (fi = 0, mi = f2mo[0]; fi < fixed->dim[0]; fi++, mi+=f2ms[0], fv++) { /* Find correspondence with nearest neighbor interpolation & boundary checking */ dxyz = &vf_smooth_img [3*fv]; /* mm */ mz = ROUND_INT(mk + invmps[2] * dxyz[2]); /* pixels (moving) */ if (mz < 0 || mz >= moving->dim[2]) continue; my = ROUND_INT(mj + invmps[1] * dxyz[1]); /* pixels (moving) */ if (my < 0 || my >= moving->dim[1]) continue; mx = ROUND_INT(mi + invmps[0] * dxyz[0]); /* pixels (moving) */ if (mx < 0 || mx >= moving->dim[0]) continue; mv = moving->index (mx, my, mz); /* Find image difference at this correspondence */ diff = f_img[fv] - m_img[mv]; /* intensity */ /* Find spatial gradient at this correspondece */ vox_grad = &m_grad_img[3*mv]; /* intensity per mm */ vox_grad_mag = m_grad_mag_img[mv]; /* intensity^2 per mm^2 */ /* Compute denominator */ denom = vox_grad_mag + parms->homog * diff * diff; /* intensity^2 per mm^2 */ /* Compute SSD for statistics */ inliers++; ssd += diff * diff; /* Threshold the denominator to stabilize estimation */ if (denom < parms->denominator_eps) continue; /* Compute new estimate of displacement */ mult = parms->accel * diff / denom; /* per intensity^2 */ vf_est_img[3*fv + 0] += mult * vox_grad[0]; /* mm */ vf_est_img[3*fv + 1] += mult * vox_grad[1]; vf_est_img[3*fv + 2] += mult * vox_grad[2]; } } } //vf_print_stats (vf_est); /* Smooth the estimate into vf_smooth. The volumes are ping-ponged. */ vf_convolve_x (vf_smooth, vf_est, kerx, fw[0]); vf_convolve_y (vf_est, vf_smooth, kery, fw[1]); vf_convolve_z (vf_smooth, vf_est, kerz, fw[2]); //vf_print_stats (vf_smooth); double duration = it_timer->report (); printf ("MSE [%4d] %.01f (%.03f) [%6.3f secs]\n", it, ssd/inliers, ((float) inliers / fixed->npix), duration); it_timer->start (); } free (kerx); free (kery); free (kerz); delete vf_est; delete m_grad_mag; diff_run = timer->report (); printf ("Time for %d iterations = %f (%f sec / it)\n", parms->max_its, diff_run, diff_run / parms->max_its); delete timer; delete it_timer; return vf_smooth; } demons_opencl.cl000066400000000000000000000266071321604176500315440ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #define BLOCK_SIZE 256 /* Define image/texture sampling parameters */ const sampler_t img_sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; __kernel void calculate_gradient_magnitude_image_kernel ( __write_only __global float *grad_mag, __read_only image3d_t grad_img_x, __read_only image3d_t grad_img_y, __read_only image3d_t grad_img_z, __constant int4 *dim ) { /* Find position in volume */ uint x = get_global_id(0); uint y = get_global_id(1); uint z = get_global_id(2); if (x >= (*dim).x || y >= (*dim).y || z >= (*dim).z) return; long v = (z * (*dim).y * (*dim).x) + (y * (*dim).x) + x; int4 vPos = {x, y, z, 0}; float4 vox_grad_x = read_imagef(grad_img_x, img_sampler, vPos); float4 vox_grad_y = read_imagef(grad_img_y, img_sampler, vPos); float4 vox_grad_z = read_imagef(grad_img_z, img_sampler, vPos); grad_mag[v] = vox_grad_x.x * vox_grad_x.x + vox_grad_y.x * vox_grad_y.x + vox_grad_z.x * vox_grad_z.x; } __kernel void estimate_kernel ( __global float *vf_est_x_img, __global float *vf_est_y_img, __global float *vf_est_z_img, __read_only image3d_t vf_smooth_x_img, __read_only image3d_t vf_smooth_y_img, __read_only image3d_t vf_smooth_z_img, __read_only image3d_t fixed_img, __read_only image3d_t moving_img, __read_only image3d_t grad_mag_img, __read_only image3d_t grad_x_img, __read_only image3d_t grad_y_img, __read_only image3d_t grad_z_img, __global float *ssd, __global int *inliers, __constant int4 *dim, __constant int4 *moving_dim, __constant float4 *f2mo, __constant float4 *f2ms, __constant float4 *invmps, float homog, float denominator_eps, float accel ) { /* Find position in volume */ uint i = get_global_id(0); uint j = get_global_id(1); uint k = get_global_id(2); if (i >= (*dim).x || j >= (*dim).y || k >= (*dim).z) return; long fv = (k * (*dim).y * (*dim).x) + (j * (*dim).x) + i; int4 fvPos = {i, j, k, 0}; float4 smooth_voxel_x = read_imagef(vf_smooth_x_img, img_sampler, fvPos); float4 smooth_voxel_y = read_imagef(vf_smooth_y_img, img_sampler, fvPos); float4 smooth_voxel_z = read_imagef(vf_smooth_z_img, img_sampler, fvPos); float mi = (*f2mo).x + i * (*f2ms).x; float mj = (*f2mo).y + j * (*f2ms).y; float mk = (*f2mo).z + k * (*f2ms).z; /* Find correspondence with nearest neighbor interpolation & boundary checking */ int mz = convert_int_rte(mk + (*invmps).z * smooth_voxel_z.x); /* pixels (moving) */ if (mz < 0 || mz >= (*moving_dim).z) return; int my = convert_int_rte(mj + (*invmps).y * smooth_voxel_y.x); /* pixels (moving) */ if (my < 0 || my >= (*moving_dim).y) return; int mx = convert_int_rte(mi + (*invmps).x * smooth_voxel_x.x); /* pixels (moving) */ if (mx < 0 || mx >= (*moving_dim).x) return; int4 mvPos = {mx, my, mz, 0}; /* Find image difference at this correspondence */ float4 fixed_voxel = read_imagef(fixed_img, img_sampler, fvPos); float4 moving_voxel = read_imagef(moving_img, img_sampler, mvPos); float diff = fixed_voxel.x - moving_voxel.x; /* intensity */ /* Compute denominator */ float4 grad_mag_voxel = read_imagef(grad_mag_img, img_sampler, mvPos); float denom = grad_mag_voxel.x + homog * diff * diff; /* intensity^2 per mm^2 */ /* Compute SSD for statistics */ inliers[fv] = 1; ssd[fv] = diff * diff; /* Threshold the denominator to stabilize estimation */ if (denom < denominator_eps) return; /* Compute new estimate of displacement */ float mult = accel * diff / denom; /* per intensity^2 */ float4 grad_voxel_x = read_imagef(grad_x_img, img_sampler, mvPos); float4 grad_voxel_y = read_imagef(grad_y_img, img_sampler, mvPos); float4 grad_voxel_z = read_imagef(grad_z_img, img_sampler, mvPos); vf_est_x_img[fv] += mult * grad_voxel_x.x; /* mm */ vf_est_y_img[fv] += mult * grad_voxel_y.x; vf_est_z_img[fv] += mult * grad_voxel_z.x; } __kernel void vf_convolve_x_kernel ( __write_only __global float *vf_smooth_x, __write_only __global float *vf_smooth_y, __write_only __global float *vf_smooth_z, __read_only image3d_t vf_est_x_img, __read_only image3d_t vf_est_y_img, __read_only image3d_t vf_est_z_img, __constant float *ker, __constant int4 *dim, int half_width ) { int i, i1; /* i is the offset in the vf */ int j, j1, j2; /* j is the index of the kernel */ int d; /* d is the vector field direction */ /* Find position in volume */ uint x = get_global_id(0); uint y = get_global_id(1); uint z = get_global_id(2); if (x >= (*dim).x || y >= (*dim).y || z >= (*dim).z) return; long v = (z * (*dim).y * (*dim).x) + (y * (*dim).x) + x; j1 = x - half_width; j2 = x + half_width; if (j1 < 0) j1 = 0; if (j2 >= (*dim).x) { j2 = (*dim).x - 1; } i1 = j1 - x; j1 = j1 - x + half_width; j2 = j2 - x + half_width; int4 index; float sum_x = 0.0; float sum_y = 0.0; float sum_z = 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { index.x = x + i; index.y = y; index.z = z; float4 partial_x = read_imagef(vf_est_x_img, img_sampler, index); float4 partial_y = read_imagef(vf_est_y_img, img_sampler, index); float4 partial_z = read_imagef(vf_est_z_img, img_sampler, index); sum_x += ker[j] * partial_x.x; sum_y += ker[j] * partial_y.x; sum_z += ker[j] * partial_z.x; } vf_smooth_x[v] = sum_x; vf_smooth_y[v] = sum_y; vf_smooth_z[v] = sum_z; } __kernel void vf_convolve_y_kernel ( __write_only __global float *vf_est_x, __write_only __global float *vf_est_y, __write_only __global float *vf_est_z, __read_only image3d_t vf_smooth_x_img, __read_only image3d_t vf_smooth_y_img, __read_only image3d_t vf_smooth_z_img, __constant float *ker, __constant int4 *dim, int half_width ) { int i, i1; /* i is the offset in the vf */ int j, j1, j2; /* j is the index of the kernel */ int d; /* d is the vector field direction */ /* Find position in volume */ uint x = get_global_id(0); uint y = get_global_id(1); uint z = get_global_id(2); if (x >= (*dim).x || y >= (*dim).y || z >= (*dim).z) return; long v = (z * (*dim).y * (*dim).x) + (y * (*dim).x) + x; j1 = y - half_width; j2 = y + half_width; if (j1 < 0) j1 = 0; if (j2 >= (*dim).y) { j2 = (*dim).y - 1; } i1 = j1 - y; j1 = j1 - y + half_width; j2 = j2 - y + half_width; int4 index; float sum_x = 0.0; float sum_y = 0.0; float sum_z = 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { index.x = x; index.y = y + i; index.z = z; float4 partial_x = read_imagef(vf_smooth_x_img, img_sampler, index); float4 partial_y = read_imagef(vf_smooth_y_img, img_sampler, index); float4 partial_z = read_imagef(vf_smooth_z_img, img_sampler, index); sum_x += ker[j] * partial_x.x; sum_y += ker[j] * partial_y.x; sum_z += ker[j] * partial_z.x; } vf_est_x[v] = sum_x; vf_est_y[v] = sum_y; vf_est_z[v] = sum_z; } __kernel void vf_convolve_z_kernel ( __write_only __global float *vf_smooth_x, __write_only __global float *vf_smooth_y, __write_only __global float *vf_smooth_z, __read_only image3d_t vf_est_x_img, __read_only image3d_t vf_est_y_img, __read_only image3d_t vf_est_z_img, __constant float *ker, __constant int4 *dim, int half_width ) { int i, i1; /* i is the offset in the vf */ int j, j1, j2; /* j is the index of the kernel */ int d; /* d is the vector field direction */ /* Find position in volume */ uint x = get_global_id(0); uint y = get_global_id(1); uint z = get_global_id(2); if (x >= (*dim).x || y >= (*dim).y || z >= (*dim).z) return; long v = (z * (*dim).y * (*dim).x) + (y * (*dim).x) + x; j1 = z - half_width; j2 = z + half_width; if (j1 < 0) j1 = 0; if (j2 >= (*dim).z) { j2 = (*dim).z - 1; } i1 = j1 - z; j1 = j1 - z + half_width; j2 = j2 - z + half_width; int4 index; float sum_x = 0.0; float sum_y = 0.0; float sum_z = 0.0; for (i = i1, j = j1; j <= j2; i++, j++) { index.x = x; index.y = y; index.z = z + i; float4 partial_x = read_imagef(vf_est_x_img, img_sampler, index); float4 partial_y = read_imagef(vf_est_y_img, img_sampler, index); float4 partial_z = read_imagef(vf_est_z_img, img_sampler, index); sum_x += ker[j] * partial_x.x; sum_y += ker[j] * partial_y.x; sum_z += ker[j] * partial_z.x; } vf_smooth_x[v] = sum_x; vf_smooth_y[v] = sum_y; vf_smooth_z[v] = sum_z; } __kernel void reduction_float_kernel ( __global float *vectorData, int totalElements, __local float *vector ) { /* Find position in vector */ int threadID = get_local_id(0); int groupID = get_group_id(0); int xInVector = BLOCK_SIZE * groupID * 2 + threadID; /* Populate shared memory */ vector[threadID] = (xInVector < totalElements) ? vectorData[xInVector] : 0; vector[threadID + BLOCK_SIZE] = (xInVector + BLOCK_SIZE < totalElements) ? vectorData[xInVector + BLOCK_SIZE] : 0; barrier(CLK_LOCAL_MEM_FENCE); /* Calculate partial sum */ for (int stride = BLOCK_SIZE; stride > 0; stride >>= 1) { if (threadID < stride) vector[threadID] += vector[threadID + stride]; barrier(CLK_LOCAL_MEM_FENCE); } barrier(CLK_LOCAL_MEM_FENCE); /* Store sum reduction for group */ if (threadID == 0) vectorData[groupID] = vector[0]; } __kernel void reduction_int_kernel ( __global int *vectorData, int totalElements, __local int *vector ) { /* Find position in vector */ int threadID = get_local_id(0); int groupID = get_group_id(0); int xInVector = BLOCK_SIZE * groupID * 2 + threadID; /* Populate shared memory */ vector[threadID] = (xInVector < totalElements) ? vectorData[xInVector] : 0; vector[threadID + BLOCK_SIZE] = (xInVector + BLOCK_SIZE < totalElements) ? vectorData[xInVector + BLOCK_SIZE] : 0; barrier(CLK_LOCAL_MEM_FENCE); /* Calculate partial sum */ for (int stride = BLOCK_SIZE; stride > 0; stride >>= 1) { if (threadID < stride) vector[threadID] += vector[threadID + stride]; barrier(CLK_LOCAL_MEM_FENCE); } barrier(CLK_LOCAL_MEM_FENCE); /* Store sum reduction for group */ if (threadID == 0) vectorData[groupID] = vector[0]; } __kernel void volume_calc_grad_kernel ( __write_only __global float *moving_grad_x, __write_only __global float *moving_grad_y, __write_only __global float *moving_grad_z, __read_only image3d_t moving_img, __constant int4 *dim, __constant float4 *pix_spacing_div2 ) { /* Find position in volume */ uint i = get_global_id(0); uint j = get_global_id(1); uint k = get_global_id(2); if (i >= (*dim).x || j >= (*dim).y || k >= (*dim).z) return; /* p is prev, n is next */ int i_p = (i == 0) ? 0 : i - 1; int i_n = (i == (*dim).x - 1) ? (*dim).x - 1 : i + 1; int j_p = (j == 0) ? 0 : j - 1; int j_n = (j == (*dim).y - 1) ? (*dim).y - 1 : j + 1; int k_p = (k == 0) ? 0 : k - 1; int k_n = (k == (*dim).z - 1) ? (*dim).z - 1 : k + 1; long v = (k * (*dim).y * (*dim).x) + (j * (*dim).x) + i; int4 idx_p, idx_n; float4 p, n; idx_p = (int4)(i_p, j, k, 0); p = read_imagef(moving_img, img_sampler, idx_p); idx_n = (int4)(i_n, j, k, 0); n = read_imagef(moving_img, img_sampler, idx_n); moving_grad_x[v] = (n.x - p.x) * (*pix_spacing_div2).x; idx_p = (int4)(i, j_p, k, 0); p = read_imagef(moving_img, img_sampler, idx_p); idx_n = (int4)(i, j_n, k, 0); n = read_imagef(moving_img, img_sampler, idx_n); moving_grad_y[v] = (n.x - p.x) * (*pix_spacing_div2).y; idx_p = (int4)(i, j, k_p, 0); p = read_imagef(moving_img, img_sampler, idx_p); idx_n = (int4)(i, j, k_n, 0); n = read_imagef(moving_img, img_sampler, idx_n); moving_grad_z[v] = (n.x - p.x) * (*pix_spacing_div2).z; } demons_opencl.cxx000066400000000000000000001146541321604176500317500ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include "demons.h" #include "demons_opencl_p.h" #include "opencl_util.h" #include "volume.h" Volume* demons_opencl ( Volume* fixed, Volume* moving, Volume* moving_grad, Volume* vf_init, Demons_parms* parms) { #if defined (commentout) int it; /* Iterations */ float f2mo[3]; /* Offset difference (in cm) from fixed to moving */ float f2ms[3]; /* Slope to convert fixed to moving */ float invmps[3]; /* 1/pixel spacing of moving image */ int vol_size, interleaved_vol_size, inlier_size, inliers, num_elements; int *inliers_null; int fw[3]; float ssd, overall_runtime, estimate_kernel_runtime, convolve_kernel, other_kernels, global_copy_runtime, image_copy_runtime, total_runtime; float *kerx, *kery, *kerz, *vf_x, *vf_y, *vf_z, *vf_est_img, *vf_smooth_img, *ssd_null; double diff_run; char device_name[256]; /* Device names */ char *source_path, *source; Volume *vf_est, *vf_smooth; Plm_timer* timer = new Plm_timer; /* Declare global memory */ cl_mem g_moving_grad_x, g_moving_grad_y, g_moving_grad_z; cl_mem g_moving_grad_mag; cl_mem g_vf_est_x_img, g_vf_est_y_img, g_vf_est_z_img; cl_mem g_vf_smooth_x_img, g_vf_smooth_y_img, g_vf_smooth_z_img; cl_mem g_ssd; cl_mem g_inliers; /* Declare image/texture memory */ cl_mem t_fixed_img; cl_mem t_moving_img; cl_mem t_moving_grad_x_img, t_moving_grad_y_img, t_moving_grad_z_img; cl_mem t_moving_grad_mag_img; cl_mem t_vf_est_x_img, t_vf_est_y_img, t_vf_est_z_img; cl_mem t_vf_smooth_x_img, t_vf_smooth_y_img, t_vf_smooth_z_img; /* Declare constant memory */ cl_mem c_dim; cl_mem c_moving_dim; cl_mem c_pix_spacing_div2; cl_mem c_invmps; cl_mem c_f2mo; cl_mem c_f2ms; cl_mem c_kerx, c_kery, c_kerz; /* Declare OpenCL kernels */ cl_kernel moving_gradient_kernel; cl_kernel gradient_magnitude_kernel; cl_kernel estimate_kernel; cl_kernel reduction_float_kernel; cl_kernel reduction_int_kernel; cl_kernel convolve_x_kernel; cl_kernel convolve_y_kernel; cl_kernel convolve_z_kernel; /* Declare other OpenCL variables */ float4 pix_spacing_div2; cl_event volume_calc_grad_event, moving_grad_mag_event, estimate_event, reduction_event, convolve_event, global_x_event, global_y_event, global_z_event, copy_x_event, copy_y_event, copy_z_event; cl_ulong volume_calc_grad_total, moving_grad_mag_total, estimate_total, reduction_total, convolve_total, global_total, copy_total; size_t program_length, vol_row_pitch, vol_slice_pitch, reduction_global_work_size, reduction_local_work_size; size_t demons_local_work_size[3]; size_t demons_global_work_size[3]; cl_int error; /* Use for error checking */ cl_uint device_count; /* Number of devices available */ cl_context context; /* Context from device */ cl_command_queue command_queue; /* Command Queue from Context */ cl_image_format texture_format; /* Format for reading textures */ cl_platform_id platform; /* Platform for system */ cl_program program; /* Program from .cl file */ cl_device_id device; /* Object for individual device in 'for loop' */ cl_device_id *devices; /* Pointer to devices */ /**************************************************************** * STEP 1: Setup OpenCL * ****************************************************************/ /* Set logfile name and start logs */ shrSetLogFileName("demons_opencl.txt"); shrLog("\nStarting Demons OpenCL...\n"); /* Get the OpenCL platform */ error = oclGetPlatformID(&platform); oclCheckError(error, CL_SUCCESS); /* Get devices of type GPU */ error = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, NULL, &device_count); oclCheckError(error, CL_SUCCESS); devices = (cl_device_id *)malloc(device_count * sizeof(cl_device_id) ); error = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, device_count, devices, NULL); oclCheckError(error, CL_SUCCESS); /* Create context properties */ cl_context_properties properties[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0}; context = clCreateContext(properties, device_count, devices, NULL, NULL, &error); oclCheckError(error, CL_SUCCESS); shrLog("Found %d device(s):\n", device_count); for (cl_uint i = 0; i < device_count; i++) { /* Device info */ device = oclGetDev(context, i); clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_name), device_name, NULL); oclCheckError(error, CL_SUCCESS); shrLog("\tDevice %d: %s\n", i, device_name); } /* Command queue */ device = oclGetMaxFlopsDev(context); command_queue = clCreateCommandQueue(context, device, CL_QUEUE_PROFILING_ENABLE, &error); oclCheckError(error, CL_SUCCESS); /* Program setup */ source_path = shrFindFilePath("demons_opencl.cl", ""); oclCheckError(source_path != NULL, shrTRUE); source = oclLoadProgSource(source_path, "", &program_length); oclCheckError(source != NULL, shrTRUE); /* Create the program */ program = clCreateProgramWithSource(context, 1, (const char **)&source, &program_length, &error); oclCheckError(error, CL_SUCCESS); /* Build the program */ error = clBuildProgram(program, 0, NULL, NULL, NULL, NULL); if (error != CL_SUCCESS) { /* write out standard error, Build Log and PTX, then return error */ shrLogEx(LOGBOTH | ERRORMSG, error, STDERROR); oclLogBuildInfo(program, oclGetFirstDev(context)); oclLogPtx(program, oclGetFirstDev(context), "demons_opencl.ptx"); exit(-1); } shrLog("\n"); /***************************************************************/ /**************************************************************** * STEP 2: Perform Demons Algorithm * ****************************************************************/ /* Allocate memory for vector fields */ if (vf_init) { /* If caller has an initial estimate, we copy it */ vf_smooth = volume_clone (vf_init); vf_convert_to_interleaved (vf_smooth); } else { /* Otherwise initialize to zero */ vf_smooth = new Volume (fixed->dim, fixed->offset, fixed->pix_spacing, PT_VF_FLOAT_INTERLEAVED, fixed->direction_cosines, 0); } vf_est = new Volume (fixed->dim, fixed->offset, fixed->pix_spacing, PT_VF_FLOAT_INTERLEAVED, fixed->direction_cosines, 0); vf_est_img = (float*) vf_est->img; vf_smooth_img = (float*) vf_smooth->img; /* Make sure volume is not too large for OpenCL image size */ if (fixed->dim[0] > CL_DEVICE_IMAGE3D_MAX_WIDTH || fixed->dim[1] > CL_DEVICE_IMAGE3D_MAX_HEIGHT || fixed->dim[2] > CL_DEVICE_IMAGE3D_MAX_DEPTH) { shrLog("Volume dimensions too large for %s\n", CL_DEVICE_NAME); shrLog("Maximum height, width and depth: %d x %d x %d\n", CL_DEVICE_IMAGE3D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_WIDTH, CL_DEVICE_IMAGE3D_MAX_DEPTH); shrLog("Volume height, width and depth: %d x %d x %d\n", fixed->dim[1], fixed->dim[0], fixed->dim[2]); shrLog("Exiting...\n\n"); exit(-1); } /* Set global and local work sizes */ demons_local_work_size[0] = BLOCK_SIZE; demons_local_work_size[1] = 1; demons_local_work_size[2] = 1; demons_global_work_size[0] = shrRoundUp((int)demons_local_work_size[0], fixed->dim[0]); demons_global_work_size[1] = shrRoundUp((int)demons_local_work_size[1], fixed->dim[1]); demons_global_work_size[2] = shrRoundUp((int)demons_local_work_size[2], fixed->dim[2]); reduction_local_work_size = BLOCK_SIZE; /* Calculate Moving Gradient */ /* Calculate half pixel spacing */ pix_spacing_div2.x = (float)(0.5 / moving->pix_spacing[0]); pix_spacing_div2.y = (float)(0.5 / moving->pix_spacing[1]); pix_spacing_div2.z = (float)(0.5 / moving->pix_spacing[2]); /* Calculate dynamic size of memory buffers */ vol_size = moving->dim[0] * moving->dim[1] * moving->dim[2] * sizeof(float); interleaved_vol_size = 3 * fixed->dim[0] * fixed->dim[1] * fixed->dim[2] * sizeof(float); inlier_size = moving->dim[0] * moving->dim[1] * moving->dim[2] * sizeof(int); /* Determine image memory parameters */ size_t vol_origin[3] = {0, 0, 0}; size_t vol_region[3] = {moving->dim[0], moving->dim[1], moving->dim[2]}; vol_row_pitch = moving->dim[0] * sizeof(float); vol_slice_pitch = moving->dim[0] * moving->dim[1] * sizeof(float); texture_format.image_channel_order = CL_R; texture_format.image_channel_data_type = CL_FLOAT; /* Create volume memory buffers on each device */ g_moving_grad_x = clCreateBuffer(context, CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, vol_size, NULL, &error); oclCheckError(error, CL_SUCCESS); g_moving_grad_y = clCreateBuffer(context, CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, vol_size, NULL, &error); oclCheckError(error, CL_SUCCESS); g_moving_grad_z = clCreateBuffer(context, CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, vol_size, NULL, &error); oclCheckError(error, CL_SUCCESS); /* Create texture/image memory buffers on each device */ t_fixed_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, &texture_format, fixed->dim[0], fixed->dim[1], fixed->dim[2], 0, 0, fixed->img, &error); oclCheckError(error, CL_SUCCESS); t_moving_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, &texture_format, moving->dim[0], moving->dim[1], moving->dim[2], 0, 0, moving->img, &error); oclCheckError(error, CL_SUCCESS); /* Create constant memory buffers on each device */ c_dim = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float4), fixed->dim, &error); oclCheckError(error, CL_SUCCESS); c_moving_dim = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float4), moving->dim, &error); oclCheckError(error, CL_SUCCESS); c_pix_spacing_div2 = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float4), &pix_spacing_div2, &error); oclCheckError(error, CL_SUCCESS); /* Create volume calc grad kernel on each device */ moving_gradient_kernel = clCreateKernel(program, "volume_calc_grad_kernel", &error); oclCheckError(error, CL_SUCCESS); /* Wait for command queue to finish */ clFinish(command_queue); /* Initialize timing totals */ volume_calc_grad_total = 0; moving_grad_mag_total = 0; estimate_total = 0; reduction_total = 0; convolve_total = 0; global_total = 0; copy_total = 0; /* Set kernel arguments */ error |= clSetKernelArg(moving_gradient_kernel, 0, sizeof(cl_mem), (void *) &g_moving_grad_x); error |= clSetKernelArg(moving_gradient_kernel, 1, sizeof(cl_mem), (void *) &g_moving_grad_y); error |= clSetKernelArg(moving_gradient_kernel, 2, sizeof(cl_mem), (void *) &g_moving_grad_z); error |= clSetKernelArg(moving_gradient_kernel, 3, sizeof(cl_mem), (void *) &t_moving_img); error |= clSetKernelArg(moving_gradient_kernel, 4, sizeof(cl_mem), (void *) &c_dim); error |= clSetKernelArg(moving_gradient_kernel, 5, sizeof(cl_mem), (void *) &c_pix_spacing_div2); oclCheckError(error, CL_SUCCESS); /* Wait for command queue to finish */ clFinish(command_queue); /* Invoke all kernels */ error = clEnqueueNDRangeKernel(command_queue, moving_gradient_kernel, 3, NULL, demons_global_work_size, demons_local_work_size, 0, NULL, &volume_calc_grad_event); oclCheckError(error, CL_SUCCESS); /* Wait for kernel to finish */ clFinish(command_queue); /* Calculate kernel runtime */ volume_calc_grad_total += opencl_timer (volume_calc_grad_event); /* Create volume memory buffer on each device */ g_moving_grad_mag = clCreateBuffer(context, CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, vol_size, NULL, &error); oclCheckError(error, CL_SUCCESS); /* Create texture/image memory buffer on each device */ t_moving_grad_x_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &texture_format, moving->dim[0], moving->dim[1], moving->dim[2], 0, 0, NULL, &error); oclCheckError(error, CL_SUCCESS); t_moving_grad_y_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &texture_format, moving->dim[0], moving->dim[1], moving->dim[2], 0, 0, NULL, &error); oclCheckError(error, CL_SUCCESS); t_moving_grad_z_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &texture_format, moving->dim[0], moving->dim[1], moving->dim[2], 0, 0, NULL, &error); /* Copy from global memory buffer to texture/image memory buffer */ error = clEnqueueCopyBufferToImage(command_queue, g_moving_grad_x, t_moving_grad_x_img, 0, vol_origin, vol_region, 0, NULL, ©_x_event); error |= clEnqueueCopyBufferToImage(command_queue, g_moving_grad_y, t_moving_grad_y_img, 0, vol_origin, vol_region, 0, NULL, ©_y_event); error |= clEnqueueCopyBufferToImage(command_queue, g_moving_grad_z, t_moving_grad_z_img, 0, vol_origin, vol_region, 0, NULL, ©_z_event); oclCheckError(error, CL_SUCCESS); /* Release unneeded global memory buffers */ clReleaseMemObject(g_moving_grad_z); clReleaseMemObject(g_moving_grad_y); clReleaseMemObject(g_moving_grad_x); /* Create the calculate gradient magnitude image kernel on each device */ gradient_magnitude_kernel = clCreateKernel(program, "calculate_gradient_magnitude_image_kernel", &error); oclCheckError(error, CL_SUCCESS); /* Wait for command queue to finish */ clFinish(command_queue); /* Calculate global/image copy runtime */ copy_total += opencl_timer (copy_x_event); copy_total += opencl_timer (copy_y_event); copy_total += opencl_timer (copy_z_event); /* Create gradient magnitude image */ /* Set kernel arguments */ error |= clSetKernelArg(gradient_magnitude_kernel, 0, sizeof(cl_mem), (void *) &g_moving_grad_mag); error |= clSetKernelArg(gradient_magnitude_kernel, 1, sizeof(cl_mem), (void *) &t_moving_grad_x_img); error |= clSetKernelArg(gradient_magnitude_kernel, 2, sizeof(cl_mem), (void *) &t_moving_grad_y_img); error |= clSetKernelArg(gradient_magnitude_kernel, 3, sizeof(cl_mem), (void *) &t_moving_grad_z_img); error |= clSetKernelArg(gradient_magnitude_kernel, 4, sizeof(cl_mem), (void *) &c_dim); oclCheckError(error, CL_SUCCESS); /* Wait for command queue to finish */ clFinish(command_queue); /* Invoke all kernels */ error = clEnqueueNDRangeKernel(command_queue, gradient_magnitude_kernel, 3, NULL, demons_global_work_size, demons_local_work_size, 0, NULL, &moving_grad_mag_event); oclCheckError(error, CL_SUCCESS); /* Wait for kernel to finish */ clFinish(command_queue); /* Calculate kernel runtime */ moving_grad_mag_total += opencl_timer (moving_grad_mag_event); /* Create texture memory buffer on each device */ t_moving_grad_mag_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &texture_format, moving->dim[0], moving->dim[1], moving->dim[2], 0, 0, NULL, &error); oclCheckError(error, CL_SUCCESS); /* Copy from global memory buffer to image memory buffer */ error = clEnqueueCopyBufferToImage(command_queue, g_moving_grad_mag, t_moving_grad_mag_img, 0, vol_origin, vol_region, 0, NULL, ©_x_event); oclCheckError(error, CL_SUCCESS); /* Release unneeded global memory buffers */ clReleaseMemObject(g_moving_grad_mag); /* Create the estimate and convolve kernels on each device */ estimate_kernel = clCreateKernel(program, "estimate_kernel", &error); oclCheckError(error, CL_SUCCESS); reduction_float_kernel = clCreateKernel(program, "reduction_float_kernel", &error); oclCheckError(error, CL_SUCCESS); reduction_int_kernel = clCreateKernel(program, "reduction_int_kernel", &error); oclCheckError(error, CL_SUCCESS); convolve_x_kernel = clCreateKernel(program, "vf_convolve_x_kernel", &error); oclCheckError(error, CL_SUCCESS); convolve_y_kernel = clCreateKernel(program, "vf_convolve_y_kernel", &error); oclCheckError(error, CL_SUCCESS); convolve_z_kernel = clCreateKernel(program, "vf_convolve_z_kernel", &error); oclCheckError(error, CL_SUCCESS); /* Calculate global/image copy runtime */ copy_total += opencl_timer (copy_x_event); /* Validate filter widths */ validate_filter_widths (fw, parms->filter_width); /* Create the seperable smoothing kernels for the x, y, and z directions */ kerx = create_ker (parms->filter_std / fixed->pix_spacing[0], fw[0]/2); kery = create_ker (parms->filter_std / fixed->pix_spacing[1], fw[1]/2); kerz = create_ker (parms->filter_std / fixed->pix_spacing[2], fw[2]/2); kernel_stats (kerx, kery, kerz, fw); /* Calculate width of smoothing kernels */ int kerx_size = sizeof(float) * ((fw[0] / 2) * 2 + 1); int kery_size = sizeof(float) * ((fw[1] / 2) * 2 + 1); int kerz_size = sizeof(float) * ((fw[2] / 2) * 2 + 1); /* Compute some variables for converting pixel sizes / offsets */ for (int i = 0; i < 3; i++) { invmps[i] = 1 / moving->pix_spacing[i]; f2mo[i] = (fixed->offset[i] - moving->offset[i]) / moving->pix_spacing[i]; f2ms[i] = fixed->pix_spacing[i] / moving->pix_spacing[i]; } /* Initialize memory and split interleaved volume to linear */ vf_x = (float*)malloc(vol_size); vf_y = (float*)malloc(vol_size); vf_z = (float*)malloc(vol_size); for (int i = 0; i < vf_smooth->npix; i++) { vf_x[i] = vf_est_img[3 * i]; vf_y[i] = vf_est_img[3 * i + 1]; vf_z[i] = vf_est_img[3 * i + 2]; } /* Allocate and set zero arrays for ssd and inliers */ ssd_null = (float*)malloc(vol_size); memset(ssd_null, 0, vol_size); inliers_null = (int*)malloc(inlier_size); memset(inliers_null, 0, inlier_size); /* Create global memory buffer on each device */ g_vf_est_x_img = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, vol_size, NULL, &error); oclCheckError(error, CL_SUCCESS); g_vf_est_y_img = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, vol_size, NULL, &error); oclCheckError(error, CL_SUCCESS); g_vf_est_z_img = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, vol_size, NULL, &error); oclCheckError(error, CL_SUCCESS); g_vf_smooth_x_img = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, vol_size, vf_x, &error); oclCheckError(error, CL_SUCCESS); g_vf_smooth_y_img = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, vol_size, vf_x, &error); oclCheckError(error, CL_SUCCESS); g_vf_smooth_z_img = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, vol_size, vf_x, &error); oclCheckError(error, CL_SUCCESS); g_ssd = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, vol_size, NULL, &error); oclCheckError(error, CL_SUCCESS); g_inliers = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, inlier_size, NULL, &error); oclCheckError(error, CL_SUCCESS); /* Create texture memory buffer on each device */ t_vf_est_x_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &texture_format, fixed->dim[0], fixed->dim[1], fixed->dim[2], 0, 0, NULL, &error); oclCheckError(error, CL_SUCCESS); t_vf_est_y_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &texture_format, fixed->dim[0], fixed->dim[1], fixed->dim[2], 0, 0, NULL, &error); oclCheckError(error, CL_SUCCESS); t_vf_est_z_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &texture_format, fixed->dim[0], fixed->dim[1], fixed->dim[2], 0, 0, NULL, &error); oclCheckError(error, CL_SUCCESS); t_vf_smooth_x_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &texture_format, fixed->dim[0], fixed->dim[1], fixed->dim[2], 0, 0, NULL, &error); oclCheckError(error, CL_SUCCESS); t_vf_smooth_y_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &texture_format, fixed->dim[0], fixed->dim[1], fixed->dim[2], 0, 0, NULL, &error); oclCheckError(error, CL_SUCCESS); t_vf_smooth_z_img = clCreateImage3D(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, &texture_format, fixed->dim[0], fixed->dim[1], fixed->dim[2], 0, 0, NULL, &error); oclCheckError(error, CL_SUCCESS); /* Create constant memory buffer on each device */ c_f2mo = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float4), f2mo, &error); oclCheckError(error, CL_SUCCESS); c_f2ms = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float4), f2ms, &error); oclCheckError(error, CL_SUCCESS); c_invmps = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float4), invmps, &error); oclCheckError(error, CL_SUCCESS); c_kerx = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, kerx_size, kerx, &error); oclCheckError(error, CL_SUCCESS); c_kery = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, kery_size, kery, &error); oclCheckError(error, CL_SUCCESS); c_kerz = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, kerz_size, kerz, &error); oclCheckError(error, CL_SUCCESS); int half_width_x = fw[0] / 2; int half_width_y = fw[1] / 2; int half_width_z = fw[2] / 2; timer->start (); /* Set kernel arguments */ error |= clSetKernelArg(estimate_kernel, 0, sizeof(cl_mem), (void *) &g_vf_est_x_img); error |= clSetKernelArg(estimate_kernel, 1, sizeof(cl_mem), (void *) &g_vf_est_y_img); error |= clSetKernelArg(estimate_kernel, 2, sizeof(cl_mem), (void *) &g_vf_est_z_img); error |= clSetKernelArg(estimate_kernel, 3, sizeof(cl_mem), (void *) &t_vf_smooth_x_img); error |= clSetKernelArg(estimate_kernel, 4, sizeof(cl_mem), (void *) &t_vf_smooth_y_img); error |= clSetKernelArg(estimate_kernel, 5, sizeof(cl_mem), (void *) &t_vf_smooth_z_img); error |= clSetKernelArg(estimate_kernel, 6, sizeof(cl_mem), (void *) &t_fixed_img); error |= clSetKernelArg(estimate_kernel, 7, sizeof(cl_mem), (void *) &t_moving_img); error |= clSetKernelArg(estimate_kernel, 8, sizeof(cl_mem), (void *) &t_moving_grad_mag_img); error |= clSetKernelArg(estimate_kernel, 9, sizeof(cl_mem), (void *) &t_moving_grad_x_img); error |= clSetKernelArg(estimate_kernel, 10, sizeof(cl_mem), (void *) &t_moving_grad_y_img); error |= clSetKernelArg(estimate_kernel, 11, sizeof(cl_mem), (void *) &t_moving_grad_z_img); error |= clSetKernelArg(estimate_kernel, 12, sizeof(cl_mem), (void *) &g_ssd); error |= clSetKernelArg(estimate_kernel, 13, sizeof(cl_mem), (void *) &g_inliers); error |= clSetKernelArg(estimate_kernel, 14, sizeof(cl_mem), (void *) &c_dim); error |= clSetKernelArg(estimate_kernel, 15, sizeof(cl_mem), (void *) &c_moving_dim); error |= clSetKernelArg(estimate_kernel, 16, sizeof(cl_mem), (void *) &c_f2mo); error |= clSetKernelArg(estimate_kernel, 17, sizeof(cl_mem), (void *) &c_f2ms); error |= clSetKernelArg(estimate_kernel, 18, sizeof(cl_mem), (void *) &c_invmps); error |= clSetKernelArg(estimate_kernel, 19, sizeof(cl_float), &parms->homog); error |= clSetKernelArg(estimate_kernel, 20, sizeof(cl_float), &parms->denominator_eps); error |= clSetKernelArg(estimate_kernel, 21, sizeof(cl_float), &parms->accel); oclCheckError(error, CL_SUCCESS); /* Set kernel arguments */ error |= clSetKernelArg(reduction_float_kernel, 0, sizeof(cl_mem), (void *) &g_ssd); error |= clSetKernelArg(reduction_float_kernel, 1, sizeof(cl_int), &num_elements); error |= clSetKernelArg(reduction_float_kernel, 2, sizeof(cl_float) * BLOCK_SIZE * 2, NULL); oclCheckError(error, CL_SUCCESS); /* Set kernel arguments */ error |= clSetKernelArg(reduction_int_kernel, 0, sizeof(cl_mem), (void *) &g_inliers); error |= clSetKernelArg(reduction_int_kernel, 1, sizeof(cl_int), &num_elements); error |= clSetKernelArg(reduction_int_kernel, 2, sizeof(cl_int) * BLOCK_SIZE * 2, NULL); oclCheckError(error, CL_SUCCESS); /* Set kernel arguments */ error |= clSetKernelArg(convolve_x_kernel, 0, sizeof(cl_mem), (void *) &g_vf_smooth_x_img); error |= clSetKernelArg(convolve_x_kernel, 1, sizeof(cl_mem), (void *) &g_vf_smooth_y_img); error |= clSetKernelArg(convolve_x_kernel, 2, sizeof(cl_mem), (void *) &g_vf_smooth_z_img); error |= clSetKernelArg(convolve_x_kernel, 3, sizeof(cl_mem), (void *) &t_vf_est_x_img); error |= clSetKernelArg(convolve_x_kernel, 4, sizeof(cl_mem), (void *) &t_vf_est_y_img); error |= clSetKernelArg(convolve_x_kernel, 5, sizeof(cl_mem), (void *) &t_vf_est_z_img); error |= clSetKernelArg(convolve_x_kernel, 6, sizeof(cl_mem), (void *) &c_kerx); error |= clSetKernelArg(convolve_x_kernel, 7, sizeof(cl_mem), (void *) &c_dim); error |= clSetKernelArg(convolve_x_kernel, 8, sizeof(cl_int), &half_width_x); oclCheckError(error, CL_SUCCESS); /* Set kernel arguments */ error |= clSetKernelArg(convolve_y_kernel, 0, sizeof(cl_mem), (void *) &g_vf_est_x_img); error |= clSetKernelArg(convolve_y_kernel, 1, sizeof(cl_mem), (void *) &g_vf_est_y_img); error |= clSetKernelArg(convolve_y_kernel, 2, sizeof(cl_mem), (void *) &g_vf_est_z_img); error |= clSetKernelArg(convolve_y_kernel, 3, sizeof(cl_mem), (void *) &t_vf_smooth_x_img); error |= clSetKernelArg(convolve_y_kernel, 4, sizeof(cl_mem), (void *) &t_vf_smooth_y_img); error |= clSetKernelArg(convolve_y_kernel, 5, sizeof(cl_mem), (void *) &t_vf_smooth_z_img); error |= clSetKernelArg(convolve_y_kernel, 6, sizeof(cl_mem), (void *) &c_kery); error |= clSetKernelArg(convolve_y_kernel, 7, sizeof(cl_mem), (void *) &c_dim); error |= clSetKernelArg(convolve_y_kernel, 8, sizeof(cl_int), &half_width_y); oclCheckError(error, CL_SUCCESS); /* Set kernel arguments */ error |= clSetKernelArg(convolve_z_kernel, 0, sizeof(cl_mem), (void *) &g_vf_smooth_x_img); error |= clSetKernelArg(convolve_z_kernel, 1, sizeof(cl_mem), (void *) &g_vf_smooth_y_img); error |= clSetKernelArg(convolve_z_kernel, 2, sizeof(cl_mem), (void *) &g_vf_smooth_z_img); error |= clSetKernelArg(convolve_z_kernel, 3, sizeof(cl_mem), (void *) &t_vf_est_x_img); error |= clSetKernelArg(convolve_z_kernel, 4, sizeof(cl_mem), (void *) &t_vf_est_y_img); error |= clSetKernelArg(convolve_z_kernel, 5, sizeof(cl_mem), (void *) &t_vf_est_z_img); error |= clSetKernelArg(convolve_z_kernel, 6, sizeof(cl_mem), (void *) &c_kerz); error |= clSetKernelArg(convolve_z_kernel, 7, sizeof(cl_mem), (void *) &c_dim); error |= clSetKernelArg(convolve_z_kernel, 8, sizeof(cl_int), &half_width_z); oclCheckError(error, CL_SUCCESS); /* Main loop through iterations */ for (it = 0; it < parms->max_its; it++) { /* Estimate displacement, store into vf_est */ inliers = 0; ssd = 0.0; /* Clear out sdd and inlier global memory buffers */ error = clEnqueueWriteBuffer(command_queue, g_ssd, CL_FALSE, 0, vol_size, ssd_null, 0, NULL, NULL); error |= clEnqueueWriteBuffer(command_queue, g_inliers, CL_FALSE, 0, inlier_size, inliers_null, 0, NULL, NULL); oclCheckError(error, CL_SUCCESS); /* Copy old smooth memory buffer to estimate memory buffer */ error = clEnqueueCopyBuffer(command_queue, g_vf_smooth_x_img, g_vf_est_x_img, 0, 0, vol_size, 0, NULL, &global_x_event); error |= clEnqueueCopyBuffer(command_queue, g_vf_smooth_y_img, g_vf_est_y_img, 0, 0, vol_size, 0, NULL, &global_y_event); error |= clEnqueueCopyBuffer(command_queue, g_vf_smooth_z_img, g_vf_est_z_img, 0, 0, vol_size, 0, NULL, &global_z_event); oclCheckError(error, CL_SUCCESS); /* Copy from global memory buffer to image memory buffer */ error = clEnqueueCopyBufferToImage(command_queue, g_vf_smooth_x_img, t_vf_smooth_x_img, 0, vol_origin, vol_region, 0, NULL, ©_x_event); error |= clEnqueueCopyBufferToImage(command_queue, g_vf_smooth_y_img, t_vf_smooth_y_img, 0, vol_origin, vol_region, 0, NULL, ©_y_event); error |= clEnqueueCopyBufferToImage(command_queue, g_vf_smooth_z_img, t_vf_smooth_z_img, 0, vol_origin, vol_region, 0, NULL, ©_z_event); oclCheckError(error, CL_SUCCESS); /* Wait for all memory events to finish */ clFinish(command_queue); /* Calculate memory runtimes */ global_total += opencl_timer (global_x_event); global_total += opencl_timer (global_x_event); global_total += opencl_timer (global_x_event); copy_total += opencl_timer (copy_x_event); copy_total += opencl_timer (copy_x_event); copy_total += opencl_timer (copy_x_event); /* Wait for command queue to finish */ clFinish(command_queue); /* Invoke all kernels */ error = clEnqueueNDRangeKernel(command_queue, estimate_kernel, 3, NULL, demons_global_work_size, demons_local_work_size, 0, NULL, &estimate_event); oclCheckError(error, CL_SUCCESS); /* Wait for kernel to finish */ clFinish(command_queue); /* Calculate kernel runtime */ estimate_total += opencl_timer (estimate_event); num_elements = moving->dim[0] * moving->dim[1] * moving->dim[2]; while (num_elements > 1) { error |= clSetKernelArg(reduction_float_kernel, 1, sizeof(cl_int), &num_elements); error |= clSetKernelArg(reduction_int_kernel, 1, sizeof(cl_int), &num_elements); reduction_global_work_size = ((num_elements + (2 * BLOCK_SIZE) - 1) / (BLOCK_SIZE * 2)) * BLOCK_SIZE; /* Invoke all kernels */ error = clEnqueueNDRangeKernel(command_queue, reduction_int_kernel, 1, NULL, &reduction_global_work_size, &reduction_local_work_size, 0, NULL, &reduction_event); oclCheckError(error, CL_SUCCESS); /* Wait for kernel to finish */ clFinish(command_queue); /* Calculate kernel runtime */ reduction_total += opencl_timer (reduction_event); /* Invoke all kernels */ error = clEnqueueNDRangeKernel(command_queue, reduction_float_kernel, 1, NULL, &reduction_global_work_size, &reduction_local_work_size, 0, NULL, &reduction_event); oclCheckError(error, CL_SUCCESS); /* Wait for kernel to finish */ clFinish(command_queue); /* Calculate kernel runtime */ reduction_total += opencl_timer (reduction_event); num_elements = (num_elements + (2 * BLOCK_SIZE) - 1) / (BLOCK_SIZE * 2); } /* Copy global memory buffers to host on each device */ error = clEnqueueReadBuffer(command_queue, g_ssd, CL_FALSE, 0, sizeof(float), &ssd, 0, NULL, NULL); error |= clEnqueueReadBuffer(command_queue, g_inliers, CL_FALSE, 0, sizeof(int), &inliers, 0, NULL, NULL); oclCheckError(error, CL_SUCCESS); /* Wait for command queue to finish */ clFinish(command_queue); /* Print estimate statistics */ printf ("----- SSD = %.01f (%d/%d)\n", ssd/inliers, inliers, fixed->npix); /* Smooth the estimate into vf_smooth. The volumes are ping-ponged. */ /* Copy from global memory buffer to image memory buffer */ error = clEnqueueCopyBufferToImage(command_queue, g_vf_est_x_img, t_vf_est_x_img, 0, vol_origin, vol_region, 0, NULL, ©_x_event); error |= clEnqueueCopyBufferToImage(command_queue, g_vf_est_y_img, t_vf_est_y_img, 0, vol_origin, vol_region, 0, NULL, ©_y_event); error |= clEnqueueCopyBufferToImage(command_queue, g_vf_est_z_img, t_vf_est_z_img, 0, vol_origin, vol_region, 0, NULL, ©_z_event); oclCheckError(error, CL_SUCCESS); /* Wait for all memory events to finish */ clFinish(command_queue); /* Calculate memory runtimes */ copy_total += opencl_timer (copy_x_event); copy_total += opencl_timer (copy_x_event); copy_total += opencl_timer (copy_x_event); /* Wait for command queue to finish */ clFinish(command_queue); /* Invoke all kernels */ error = clEnqueueNDRangeKernel(command_queue, convolve_x_kernel, 3, NULL, demons_global_work_size, demons_local_work_size, 0, NULL, &convolve_event); oclCheckError(error, CL_SUCCESS); /* Wait for kernel to finish */ clFinish(command_queue); /* Calculate kernel runtime */ convolve_total += opencl_timer (convolve_event); /* Copy from global memory buffer to image memory buffer */ error = clEnqueueCopyBufferToImage(command_queue, g_vf_smooth_x_img, t_vf_smooth_x_img, 0, vol_origin, vol_region, 0, NULL, ©_x_event); error |= clEnqueueCopyBufferToImage(command_queue, g_vf_smooth_y_img, t_vf_smooth_y_img, 0, vol_origin, vol_region, 0, NULL, ©_y_event); error |= clEnqueueCopyBufferToImage(command_queue, g_vf_smooth_z_img, t_vf_smooth_z_img, 0, vol_origin, vol_region, 0, NULL, ©_z_event); oclCheckError(error, CL_SUCCESS); /* Wait for all memory events to finish */ clFinish(command_queue); /* Calculate memory runtimes */ copy_total += opencl_timer (copy_x_event); copy_total += opencl_timer (copy_x_event); copy_total += opencl_timer (copy_x_event); /* Wait for command queue to finish */ clFinish(command_queue); /* Invoke all kernels */ error = clEnqueueNDRangeKernel(command_queue, convolve_y_kernel, 3, NULL, demons_global_work_size, demons_local_work_size, 0, NULL, &convolve_event); oclCheckError(error, CL_SUCCESS); /* Wait for kernel to finish */ clFinish(command_queue); /* Calculate kernel runtime */ convolve_total += opencl_timer (convolve_event); /* Create volume buffer */ error = clEnqueueCopyBufferToImage(command_queue, g_vf_est_x_img, t_vf_est_x_img, 0, vol_origin, vol_region, 0, NULL, ©_x_event); error |= clEnqueueCopyBufferToImage(command_queue, g_vf_est_y_img, t_vf_est_y_img, 0, vol_origin, vol_region, 0, NULL, ©_y_event); error |= clEnqueueCopyBufferToImage(command_queue, g_vf_est_z_img, t_vf_est_z_img, 0, vol_origin, vol_region, 0, NULL, ©_z_event); oclCheckError(error, CL_SUCCESS); /* Wait for all memory events to finish */ clFinish(command_queue); /* Calculate memory runtimes */ copy_total += opencl_timer (copy_x_event); copy_total += opencl_timer (copy_x_event); copy_total += opencl_timer (copy_x_event); /* Wait for command queue to finish */ clFinish(command_queue); /* Invoke all kernels */ error = clEnqueueNDRangeKernel(command_queue, convolve_z_kernel, 3, NULL, demons_global_work_size, demons_local_work_size, 0, NULL, &convolve_event); oclCheckError(error, CL_SUCCESS); /* Wait for kernel to finish */ clFinish(command_queue); /* Calculate kernel runtime */ convolve_total += opencl_timer (convolve_event); } /* Copy global memory buffers to host on each device */ error = clEnqueueReadBuffer(command_queue, g_vf_smooth_x_img, CL_FALSE, 0, vol_size, vf_x, 0, NULL, &global_x_event); error = clEnqueueReadBuffer(command_queue, g_vf_smooth_y_img, CL_FALSE, 0, vol_size, vf_y, 0, NULL, &global_y_event); error = clEnqueueReadBuffer(command_queue, g_vf_smooth_z_img, CL_FALSE, 0, vol_size, vf_z, 0, NULL, &global_z_event); oclCheckError(error, CL_SUCCESS); /* Wait for all memory events to finish */ clFinish(command_queue); /* Calculate memory runtimes */ global_total += opencl_timer (global_x_event); global_total += opencl_timer (global_y_event); global_total += opencl_timer (global_z_event); /* Combine linear memory to interleaved */ for (int i = 0; i < vf_smooth->npix; i++) { vf_smooth_img[3 * i] = vf_x[i]; vf_smooth_img[3 * i + 1] = vf_y[i]; vf_smooth_img[3 * i + 2] = vf_z[i]; } free (kerx); free (kery); free (kerz); delete vf_est; /***************************************************************/ /**************************************************************** * STEP 3: Print statistics * ****************************************************************/ diff_run = timer->report (); printf ("Time for %d iterations = %f (%f sec / it)\n", parms->max_its, diff_run, diff_run / parms->max_its); shrLog("\n"); overall_runtime = 0; estimate_kernel_runtime = estimate_total * 1.0e-6f; convolve_kernel = convolve_total * 1.0e-6f; other_kernels = (volume_calc_grad_total + moving_grad_mag_total + reduction_total) * 1.0e-6f; global_copy_runtime = global_total * 1.0e-6f; image_copy_runtime = copy_total * 1.0e-6f; total_runtime = (estimate_kernel_runtime + convolve_kernel + other_kernels + global_copy_runtime + image_copy_runtime) * 1.0e-3f; overall_runtime += total_runtime; shrLog("Estimate kernel run time: %f ms\n", estimate_kernel_runtime); shrLog("Convolve kernels run time: %f ms\n", convolve_kernel); shrLog("Other kernels run time: %f ms\n", other_kernels); shrLog("Global memory copy run time: %f ms\n", global_copy_runtime); shrLog("Image memory copy run time: %f ms\n", image_copy_runtime); shrLog("Total OpenCL run time: %f s\n\n", total_runtime); /***************************************************************/ /**************************************************************** * STEP 4: Cleanup OpenCL and finish * ****************************************************************/ /* Release kernels */ clReleaseKernel(convolve_z_kernel); clReleaseKernel(convolve_y_kernel); clReleaseKernel(convolve_x_kernel); clReleaseKernel(estimate_kernel); clReleaseKernel(gradient_magnitude_kernel); clReleaseKernel(moving_gradient_kernel); /* Release constant memory buffers */ clReleaseMemObject(c_kerz); clReleaseMemObject(c_kery); clReleaseMemObject(c_kerx); clReleaseMemObject(c_invmps); clReleaseMemObject(c_f2ms); clReleaseMemObject(c_f2mo); clReleaseMemObject(c_moving_dim); clReleaseMemObject(c_pix_spacing_div2); clReleaseMemObject(c_dim); /* Release texture/image memory buffers */ clReleaseMemObject(t_vf_smooth_z_img); clReleaseMemObject(t_vf_smooth_y_img); clReleaseMemObject(t_vf_smooth_x_img); clReleaseMemObject(t_vf_est_z_img); clReleaseMemObject(t_vf_est_y_img); clReleaseMemObject(t_vf_est_x_img); clReleaseMemObject(t_moving_grad_mag_img); clReleaseMemObject(t_moving_grad_z_img); clReleaseMemObject(t_moving_grad_y_img); clReleaseMemObject(t_moving_grad_x_img); clReleaseMemObject(t_moving_img); clReleaseMemObject(t_fixed_img); /* Release global memory buffers */ clReleaseMemObject(g_inliers); clReleaseMemObject(g_ssd); clReleaseMemObject(g_vf_smooth_z_img); clReleaseMemObject(g_vf_smooth_y_img); clReleaseMemObject(g_vf_smooth_x_img); clReleaseMemObject(g_vf_est_z_img); clReleaseMemObject(g_vf_est_y_img); clReleaseMemObject(g_vf_est_x_img); /* Cleanup OpenCL */ clReleaseProgram(program); clReleaseCommandQueue(command_queue); clReleaseContext(context); shrLog("Done Demons OpenCL...\n\n"); delete timer; /****************************************************************/ return vf_smooth; #endif return (Volume*) 0; } demons_opencl_p.h000066400000000000000000000010531321604176500317000ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _DEMONS_OPENCL_P_H_ #define _DEMONS_OPENCL_P_H_ /* Constants */ #define BLOCK_SIZE 256 #define MAX_GPU_COUNT 8 /* Data Structures */ struct int2 { int x; int y; }; struct int4 { int x; int y; int z; int w; }; struct float2 { float x; float y; }; struct float4 { float x; float y; float z; float w; }; #endifdemons_state.cxx000066400000000000000000000021231321604176500315730ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include "demons_state.h" #include "volume.h" Demons_state::Demons_state (void) { } Demons_state::~Demons_state (void) { } void Demons_state::init ( Volume* fixed, Volume* moving, Volume* moving_grad, Volume* vf_init, Demons_parms* parms) { /* Allocate memory for vector fields */ if (vf_init) { /* If caller has an initial estimate, we copy it */ this->vf_smooth = volume_clone (vf_init); vf_convert_to_interleaved (this->vf_smooth); } else { /* Otherwise initialize to zero */ vf_smooth = new Volume (fixed->dim, fixed->origin, fixed->spacing, fixed->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); } vf_est = new Volume (fixed->dim, fixed->origin, fixed->spacing, fixed->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/demons_state.h000066400000000000000000000011611321604176500313000ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _demons_state_h_ #define _demons_state_h_ #include "plmregister_config.h" class Volume; class Demons_parms; class PLMREGISTER_API Demons_state { public: Volume *vf_smooth; Volume *vf_est; public: Demons_state (void); ~Demons_state (void); void init ( Volume* fixed, Volume* moving, Volume* moving_grad, Volume* vf_init, Demons_parms* parms); }; #endif gpuit_demons.cxx000066400000000000000000000057061321604176500316150ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include "demons.h" #include "gpuit_demons.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "registration_data.h" #include "stage_parms.h" #include "volume.h" #include "volume_grad.h" #include "volume_resample.h" #include "xform.h" Xform::Pointer do_gpuit_demons_stage_internal ( Registration_data* regd, const Xform::Pointer& xf_in, const Stage_parms* stage) { Xform::Pointer xf_out = Xform::New (); int d; Demons_parms parms; Plm_image_header pih; Plm_image::Pointer fixed_image = regd->get_fixed_image(); Plm_image::Pointer moving_image = regd->get_moving_image(); Volume::Pointer& fixed = fixed_image->get_volume_float (); Volume::Pointer& moving = moving_image->get_volume_float (); Volume::Pointer moving_ss; Volume::Pointer fixed_ss; Volume::Pointer moving_grad; Volume* vf_out = 0; Volume* vf_in = 0; fixed->convert (PT_FLOAT); /* Maybe not necessary? */ moving->convert (PT_FLOAT); /* Maybe not necessary? */ lprintf ("SUBSAMPLE: (%g %g %g), (%g %g %g)\n", stage->resample_rate_fixed[0], stage->resample_rate_fixed[1], stage->resample_rate_fixed[2], stage->resample_rate_moving[0], stage->resample_rate_moving[1], stage->resample_rate_moving[2] ); moving_ss = volume_subsample_vox_legacy ( moving, stage->resample_rate_moving); fixed_ss = volume_subsample_vox_legacy ( fixed, stage->resample_rate_fixed); moving_grad = Volume::New (volume_make_gradient (moving_ss.get())); demons_default_parms (&parms); parms.max_its = stage->max_its; parms.filter_std = stage->demons_std; parms.accel = stage->demons_acceleration; parms.homog = stage->demons_homogenization; parms.threading = stage->threading_type; for (d = 0; d < 3; d++) { parms.filter_width[d] = stage->demons_filter_width[d]; } /* Transform input xform to gpuit vector field */ if (xf_in->m_type == XFORM_NONE) { vf_in = 0; } else { pih.set_from_gpuit (fixed_ss->dim, fixed_ss->origin, fixed_ss->spacing, fixed_ss->direction_cosines); xf_out = xform_to_gpuit_vf (xf_in, &pih); vf_in = xf_out->get_gpuit_vf().get(); } /* Run demons */ vf_out = demons (fixed_ss.get(), moving_ss.get(), moving_grad.get(), vf_in, &parms); /* Do something with output vector field */ xf_out->set_gpuit_vf (Volume::Pointer(vf_out)); return xf_out; } Xform::Pointer do_gpuit_demons_stage ( Registration_data* regd, const Xform::Pointer& xf_in, const Stage_parms* stage) { return do_gpuit_demons_stage_internal (regd, xf_in, stage); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/gpuit_demons.h000066400000000000000000000010041321604176500313040ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gpuit_demons_h_ #define _gpuit_demons_h_ #include "plmregister_config.h" #include "xform.h" class Registration_data; class Stage_parms; Xform::Pointer do_gpuit_demons_stage ( Registration_data* regd, const Xform::Pointer& xf_in, const Stage_parms* stage); #endif groupwise_parms.cxx000066400000000000000000000005631321604176500323420ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "groupwise_parms.h" Groupwise_parms::Groupwise_parms() { } Groupwise_parms::~Groupwise_parms() { } groupwise_parms.h000066400000000000000000000006631321604176500317700ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _groupwise_parms_h_ #define _groupwise_parms_h_ #include "plmregister_config.h" class PLMREGISTER_API Groupwise_parms { public: Groupwise_parms (); ~Groupwise_parms (); public: }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/histogram.cxx000066400000000000000000000014151321604176500311650ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include "file_util.h" #include "histogram.h" #include "logfile.h" #include "plm_math.h" #include "print_and_exit.h" #include "string_util.h" #include "volume.h" Histogram::Histogram ( Mi_hist_type type, plm_long bins) { this->type = type; this->bins = bins; this->offset = 0.f; this->big_bin = 0; this->delta = 0.f; this->keys = 0; this->key_lut = 0; } Histogram::~Histogram () { if (this->key_lut) { free (this->key_lut); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/histogram.h000066400000000000000000000022151321604176500306110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _histogram_h_ #define _histogram_h_ #include "plmregister_config.h" #include #include "plm_int.h" /* Maximum # of bins for a vopt histogram */ #define VOPT_RES 1000 enum Mi_hist_type { HIST_EQSP, HIST_VOPT }; class PLMREGISTER_API Histogram { public: Histogram ( Mi_hist_type type = HIST_EQSP, plm_long bins = 32); ~Histogram (); public: /* Used by all histogram types */ enum Mi_hist_type type; /* Type of histograms */ plm_long bins; /* # of bins in histogram */ float offset; /* minimum voxel intensity */ plm_long big_bin; /* fullest bin index */ float delta; /* bin OR key spacing */ /* For V-Optimal Histograms */ plm_long keys; /* # of keys */ int* key_lut; /* bin keys lookup table */ }; #endif itk_align_center.cxx000066400000000000000000000062451321604176500324200ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "itkImageMomentsCalculator.h" #include "logfile.h" #include "print_and_exit.h" #include "registration_data.h" #include "shared_parms.h" #include "stage_parms.h" #include "xform.h" static void itk_align_center ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, const Stage_parms* stage); static void itk_align_center_of_gravity ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, const Stage_parms* stage); static void itk_align_center ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, const Stage_parms* stage) { Plm_image::Pointer fixed_image = regd->get_fixed_image(); Plm_image::Pointer moving_image = regd->get_moving_image(); float fixed_center[3]; float moving_center[3]; itk_volume_center (fixed_center, fixed_image->itk_float()); itk_volume_center (moving_center, moving_image->itk_float()); itk::Array trn_parms (3); trn_parms[0] = moving_center[0] - fixed_center[0]; trn_parms[1] = moving_center[1] - fixed_center[1]; trn_parms[2] = moving_center[2] - fixed_center[2]; xf_out->set_trn (trn_parms); } static void itk_align_center_of_gravity ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, const Stage_parms* stage) { if (regd->get_fixed_roi() && regd->get_moving_roi()) { typedef itk::ImageMomentsCalculator ImageMomentsCalculatorType; ImageMomentsCalculatorType::Pointer fixedCalculator = ImageMomentsCalculatorType::New(); fixedCalculator->SetImage(regd->get_fixed_roi()->itk_uchar()); fixedCalculator->Compute(); ImageMomentsCalculatorType::Pointer movingCalculator = ImageMomentsCalculatorType::New(); movingCalculator->SetImage(regd->get_moving_roi()->itk_uchar()); movingCalculator->Compute(); ImageMomentsCalculatorType::VectorType fixedCenter; ImageMomentsCalculatorType::VectorType movingCenter; fixedCenter = fixedCalculator->GetCenterOfGravity(); movingCenter = movingCalculator->GetCenterOfGravity(); itk::Array trn_parms (3); trn_parms[0] = movingCenter[0] - fixedCenter[0]; trn_parms[1] = movingCenter[1] - fixedCenter[1]; trn_parms[2] = movingCenter[2] - fixedCenter[2]; xf_out->set_trn (trn_parms); } else { print_and_exit("NO ROIs SET!"); } } Xform::Pointer do_itk_align_center ( Registration_data* regd, const Xform::Pointer& xf_in, Stage_parms* stage ) { Xform::Pointer xf_out = Xform::New (); itk_align_center (regd, xf_out.get(), xf_in.get(), stage); return xf_out; } Xform::Pointer do_itk_align_center_of_gravity ( Registration_data* regd, const Xform::Pointer& xf_in, Stage_parms* stage ) { Xform::Pointer xf_out = Xform::New (); itk_align_center_of_gravity (regd, xf_out.get(), xf_in.get(), stage); return xf_out; } itk_align_center.h000066400000000000000000000011741321604176500320410ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_align_center_h_ #define _itk_align_center_h_ #include "plmregister_config.h" #include "xform.h" class Registration_data; class Stage_parms; Xform::Pointer do_itk_align_center ( Registration_data* regd, const Xform::Pointer& xf_in, Stage_parms* stage); Xform::Pointer do_itk_align_center_of_gravity ( Registration_data* regd, const Xform::Pointer& xf_in, Stage_parms* stage); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/itk_demons.cxx000066400000000000000000000173161321604176500313330ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "itkArray.h" #include "itkCommand.h" #include "itkHistogramMatchingImageFilter.h" #include "itkPDEDeformableRegistrationWithMaskFilter.h" #include "itk_demons.h" #include "itk_diff_demons.h" #include "itk_log_demons.h" #include "itk_sym_log_demons.h" #include "itk_fsf_demons.h" #include "itk_demons_util.h" #include "itk_demons_registration_filter.h" #include "itk_resample.h" #include "logfile.h" #include "plm_image.h" #include "plm_timer.h" #include "print_and_exit.h" #include "registration_data.h" #include "stage_parms.h" #include "xform.h" typedef itk::PDEDeformableRegistrationWithMaskFilter PDEDeformableRegistrationFilterType; typedef itk::ImageMaskSpatialObject< 3 > MaskType; typedef itk::HistogramMatchingImageFilter HistogramMatchingFilter; HistogramMatchingFilter::Pointer histo_equ; PDEDeformableRegistrationFilterType::Pointer m_filter; class Demons_Observer : public itk::Command { public: typedef Demons_Observer Self; typedef itk::Command Superclass; typedef itk::SmartPointer Pointer; itkNewMacro (Demons_Observer); public: Plm_timer* timer; int m_feval; protected: Demons_Observer() { timer = new Plm_timer; timer->start (); m_feval = 0; }; ~Demons_Observer () { delete timer; } unsigned int filtertype; public: void SetFilterType(unsigned int f){filtertype=f;} void Execute(itk::Object *caller, const itk::EventObject & event) { Execute( (const itk::Object *)caller, event); } void Execute(const itk::Object * object, const itk::EventObject & event) { //using update version of PDEDeformableRegistrationFilter class const PDEDeformableRegistrationFilterType * filter=dynamic_cast< const PDEDeformableRegistrationFilterType* >(object); double val = filter->GetMetric(); double duration = timer->report (); if (typeid(event) == typeid(itk::IterationEvent)) { logfile_printf ("MSE [%4d] %9.3f [%6.3f secs]\n", m_feval, val, duration); timer->start (); m_feval++; } else { std::cout << "Unknown event type." << std::endl; event.Print(std::cout); } } }; //*Setting fixed and moving image masks if available static void set_and_subsample_masks ( Registration_data* regd, const Stage_parms* stage) { /* Subsample fixed & moving images */ if (regd->get_fixed_roi()) { MaskType::Pointer fixedSpatialObjectMask = MaskType::New(); UCharImageType::Pointer fixed_mask = subsample_image (regd->get_fixed_roi()->itk_uchar(), stage->resample_rate_fixed[0], stage->resample_rate_fixed[1], stage->resample_rate_fixed[2], 0); fixedSpatialObjectMask->SetImage(fixed_mask); fixedSpatialObjectMask->Update(); m_filter->SetFixedImageMask (fixedSpatialObjectMask); } if(regd->get_moving_roi()) { MaskType::Pointer movingSpatialObjectMask = MaskType::New(); UCharImageType::Pointer moving_mask = subsample_image (regd->get_moving_roi()->itk_uchar(), stage->resample_rate_fixed[0], stage->resample_rate_fixed[1], stage->resample_rate_fixed[2], 0); movingSpatialObjectMask->SetImage(moving_mask); movingSpatialObjectMask->Update(); m_filter->SetMovingImageMask(movingSpatialObjectMask); } } //*Setting fixed and moving image masks if available static void set_general_parameters (const Stage_parms* stage) { m_filter->SetNumberOfIterations (stage->max_its); m_filter->SetStandardDeviations (stage->demons_std); m_filter->SetUpdateFieldStandardDeviations(stage->demons_std_update_field); m_filter->SetSmoothUpdateField(stage->demons_smooth_update_field); } static void do_demons_stage_internal ( Registration_data* regd, Xform *xf_out, Xform *xf_in, const Stage_parms* stage) { /* Subsample fixed & moving images */ Plm_image::Pointer fixed_image = regd->get_fixed_image(); Plm_image::Pointer moving_image = regd->get_moving_image(); FloatImageType::Pointer fixed_ss = subsample_image (fixed_image->itk_float(), stage->resample_rate_fixed[0], stage->resample_rate_fixed[1], stage->resample_rate_fixed[2], stage->default_value); FloatImageType::Pointer moving_ss = subsample_image (moving_image->itk_float(), stage->resample_rate_moving[0], stage->resample_rate_moving[1], stage->resample_rate_moving[2], stage->default_value); if (stage->histoeq) { histo_equ=HistogramMatchingFilter::New(); histo_equ->SetInput(moving_ss); histo_equ->SetReferenceImage(fixed_ss); histo_equ->SetNumberOfHistogramLevels(stage->num_hist_levels); histo_equ->SetNumberOfMatchPoints(stage->num_matching_points); m_filter->SetMovingImage (histo_equ->GetOutput()); } else { m_filter->SetMovingImage (moving_ss); } m_filter->SetFixedImage (fixed_ss); /* Get vector field of matching resolution */ if (xf_in->m_type != XFORM_NONE) { xform_to_itk_vf (xf_out, xf_in, fixed_ss); //Set initial deformation field m_filter->SetInput (xf_out->get_itk_vf()); } if (stage->max_its <= 0) { print_and_exit ("Error demons iterations must be greater than 0\n"); } if (stage->demons_std <= 0.0001) { print_and_exit ("Error demons std must be greater than 0\n"); } printf ("Ready to start registration.\n"); m_filter->Update(); printf ("Done with registration. Writing output...\n"); DeformationFieldType::Pointer output_field=m_filter->GetOutput(); output_field->DisconnectPipeline(); xf_out->set_itk_vf (output_field); histo_equ=NULL; } Xform::Pointer do_itk_demons_stage ( Registration_data* regd, const Xform::Pointer& xf_in, const Stage_parms* stage) { Xform::Pointer xf_out = Xform::New (); itk_demons_registration_filter* demons_filter = NULL; if(stage->optim_subtype == OPTIMIZATION_SUB_FSF) { demons_filter = new itk_fsf_demons_filter(); } else if(stage->optim_subtype == OPTIMIZATION_SUB_DIFF_ITK) { demons_filter = new itk_diffeomorphic_demons_filter(); } else if(stage->optim_subtype ==OPTIMIZATION_SUB_LOGDOM_ITK) { demons_filter = new itk_log_domain_demons_filter(); } else if(stage->optim_subtype ==OPTIMIZATION_SUB_SYM_LOGDOM_ITK) { demons_filter = new itk_sym_log_domain_demons_filter(); } m_filter=demons_filter->get_demons_filter_impl(); //Set mask if available for implementation set_and_subsample_masks(regd,stage); //Set paramters that are used by all demons implementations set_general_parameters(stage); //Adding observer Demons_Observer::Pointer observer = Demons_Observer::New(); m_filter->AddObserver (itk::IterationEvent(), observer); //Let filter set filter specific parameters demons_filter->update_specific_parameters(stage); do_demons_stage_internal (regd, xf_out.get(), xf_in.get(), stage); printf ("Deformation stats (out)\n"); itk_demons_util::deformation_stats (xf_out->get_itk_vf()); delete demons_filter; return xf_out; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/itk_demons.h000066400000000000000000000010221321604176500307430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_demons_h_ #define _itk_demons_h_ #include "plmregister_config.h" #include "itk_image_type.h" #include "xform.h" class Registration_data; class Stage_parms; Xform::Pointer do_itk_demons_stage (Registration_data* regd, const Xform::Pointer& xf_in, const Stage_parms* stage); #endif itk_demons_registration_filter.h000066400000000000000000000015241321604176500350320ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register#ifndef ITK_DEMONS_REGISTRATION_FILTER_H #define ITK_DEMONS_REGISTRATION_FILTER_H class Stage_parms; #include "itkPDEDeformableRegistrationWithMaskFilter.h" //#include "itkLogDomainDeformableRegistrationFilter.h" #include "itk_image_type.h" struct itk_demons_registration_filter { protected: typedef itk::PDEDeformableRegistrationWithMaskFilter PDEDeformableRegistrationFilterType; PDEDeformableRegistrationFilterType::Pointer m_demons_filter; public: virtual void update_specific_parameters (const Stage_parms* parms)=0; virtual ~itk_demons_registration_filter(){}; PDEDeformableRegistrationFilterType::Pointer get_demons_filter_impl() { return this->m_demons_filter; } }; #endif // ITK_DEMONS_REGISTRATION_FILTER_H itk_demons_util.cxx000066400000000000000000000015411321604176500323020ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register#include #include "itkImageRegionIterator.h" void itk_demons_util::deformation_stats (DeformationFieldType::Pointer vf) { typedef itk::ImageRegionIterator< DeformationFieldType > FieldIterator; FieldIterator fi (vf, vf->GetLargestPossibleRegion()); const DeformationFieldType::SizeType vf_size = vf->GetLargestPossibleRegion().GetSize(); double max_sq_len = 0.0; double avg_sq_len = 0.0; for (fi.GoToBegin(); !fi.IsAtEnd(); ++fi) { //index = fi.GetIndex(); const FloatVector3DType& d = fi.Get(); double sq_len = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; if (sq_len > max_sq_len) { max_sq_len = sq_len; } avg_sq_len += sq_len; } avg_sq_len /= (vf_size[0] * vf_size[1] * vf_size[2]); printf ("VF_MAX = %g VF_AVG = %g\n", max_sq_len, avg_sq_len); } itk_demons_util.h000066400000000000000000000003121321604176500317220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register#ifndef ITK_DEMONS_UTIL_H #define ITK_DEMONS_UTIL_H #include class itk_demons_util { public: static void deformation_stats (DeformationFieldType::Pointer vf); }; #endif itk_diff_demons.cxx000066400000000000000000000020261321604176500322340ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "itk_diff_demons.h" #include "stage_parms.h" itk_diffeomorphic_demons_filter::itk_diffeomorphic_demons_filter() { m_demons_filter = DiffeomorphicDemonsFilterType::New(); } itk_diffeomorphic_demons_filter::~itk_diffeomorphic_demons_filter() { } void itk_diffeomorphic_demons_filter::update_specific_parameters(const Stage_parms* stage) { //Setting gradient type DiffeomorphicDemonsFilterType* diff_demons_filter=dynamic_cast(m_demons_filter.GetPointer()); diff_demons_filter->SetSmoothDeformationField(stage->demons_smooth_deformation_field); diff_demons_filter->SetUseGradientType(static_cast(stage->demons_gradient_type)); diff_demons_filter->SetMaximumUpdateStepLength(stage->demons_step_length); } itk_diff_demons.h000066400000000000000000000017341321604176500316660ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_diff_demons_h_ #define _itk_diff_demons_h_ #include "itkDiffeomorphicDemonsRegistrationWithMaskFilter.h" #include class itk_diffeomorphic_demons_filter: public itk_demons_registration_filter { typedef itk::DiffeomorphicDemonsRegistrationWithMaskFilter< FloatImageType, FloatImageType, DeformationFieldType> DiffeomorphicDemonsFilterType; typedef DiffeomorphicDemonsFilterType::DemonsRegistrationFunctionType DiffeomorphicDemonsFunctionType; typedef DiffeomorphicDemonsFunctionType::GradientType GradientType; public: itk_diffeomorphic_demons_filter(); ~itk_diffeomorphic_demons_filter(); void update_specific_parameters(const Stage_parms* stage); }; #endif itk_fsf_demons.cxx000066400000000000000000000023541321604176500321060ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include "itkArray.h" #include "itkCommand.h" #include "itk_fsf_demons.h" #include "itk_demons_util.h" #include "itk_image.h" #include "itk_resample.h" #include "logfile.h" #include "plm_image.h" #include "plm_timer.h" #include "print_and_exit.h" #include "registration_data.h" #include "stage_parms.h" #include "xform.h" #include "itkESMDemonsRegistrationWithMaskFunction.h" itk_fsf_demons_filter::itk_fsf_demons_filter() { m_demons_filter = FastSymForcesDemonsFilterType::New(); } itk_fsf_demons_filter::~itk_fsf_demons_filter() { } void itk_fsf_demons_filter::update_specific_parameters(const Stage_parms* stage) { FastSymForcesDemonsFilterType* fsf_demons_filter=dynamic_cast(m_demons_filter.GetPointer()); fsf_demons_filter->SetUseGradientType(static_cast(stage->demons_gradient_type)); fsf_demons_filter->SetMaximumUpdateStepLength(stage->demons_step_length); } itk_fsf_demons.h000066400000000000000000000020261321604176500315270ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_fsf_demons_h_ #define _itk_fsf_demons_h_ #include "itkFastSymmetricForcesDemonsRegistrationWithMaskFilter.h" class Registration_data; class Xform; class Stage_parms; class itk_demons_util; #include class itk_fsf_demons_filter: public itk_demons_registration_filter { typedef itk::FastSymmetricForcesDemonsRegistrationWithMaskFilter< FloatImageType, FloatImageType, DeformationFieldType> FastSymForcesDemonsFilterType; typedef FastSymForcesDemonsFilterType::DemonsRegistrationFunctionType DemonsRegFunctionType; typedef DemonsRegFunctionType::GradientType GradientType; public: itk_fsf_demons_filter(); ~itk_fsf_demons_filter(); void update_specific_parameters(const Stage_parms* stage); }; #endif itk_log_demons.cxx000066400000000000000000000020211321604176500321000ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "itk_log_demons.h" #include "stage_parms.h" itk_log_domain_demons_filter::itk_log_domain_demons_filter() { m_demons_filter = LogDomainDemonsFilterType::New(); } itk_log_domain_demons_filter::~itk_log_domain_demons_filter() { } void itk_log_domain_demons_filter::update_specific_parameters(const Stage_parms* stage) { LogDomainDemonsFilterType* log_filter=dynamic_cast(m_demons_filter.GetPointer()); log_filter->SetNumberOfBCHApproximationTerms(stage->num_approx_terms_log_demons); log_filter->SetSmoothVelocityField(stage->demons_smooth_deformation_field); log_filter->SetUseGradientType(static_cast(stage->demons_gradient_type)); log_filter->SetMaximumUpdateStepLength(stage->demons_step_length); } itk_log_demons.h000066400000000000000000000017131321604176500315340ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_log_demons_h_ #define _itk_log_demons_h_ #include "itkLogDomainDemonsRegistrationFilterWithMaskExtension.h" #include class itk_log_domain_demons_filter: public itk_demons_registration_filter { typedef itk::LogDomainDemonsRegistrationFilterWithMaskExtension< FloatImageType, FloatImageType, DeformationFieldType> LogDomainDemonsFilterType; typedef LogDomainDemonsFilterType::DemonsRegistrationFunctionType LogDomainDemonsFunctionType; typedef LogDomainDemonsFunctionType::GradientType GradientType; public: itk_log_domain_demons_filter(); ~itk_log_domain_demons_filter(); void update_specific_parameters(const Stage_parms* stage); }; #endif itk_optimizer.cxx000066400000000000000000000571151321604176500320120ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include "itkImage.h" #include "itkArray.h" #include "itkCenteredTransformInitializer.h" #include "itkVersorRigid3DTransformOptimizer.h" #include "itkCommand.h" #include "itkMultiResolutionImageRegistrationMethod.h" #include "itkImageRegistrationMethod.h" #include "itkRegularStepGradientDescentOptimizer.h" #include "itkQuaternionRigidTransformGradientDescentOptimizer.h" #include "itkAmoebaOptimizer.h" #include "itkOnePlusOneEvolutionaryOptimizer.h" #include "itkLBFGSOptimizer.h" #include "itkLBFGSBOptimizer.h" #include "itkNormalVariateGenerator.h" #include "itkFRPROptimizer.h" #include "itk_optimizer.h" #include "itk_registration.h" #include "itk_registration_private.h" #include "logfile.h" #include "print_and_exit.h" #include "stage_parms.h" /* Types of optimizers */ typedef itk::OnePlusOneEvolutionaryOptimizer OnePlusOneOptimizerType; typedef itk::FRPROptimizer FRPROptimizerType; typedef itk::AmoebaOptimizer AmoebaOptimizerType; typedef itk::RegularStepGradientDescentOptimizer RSGOptimizerType; typedef itk::VersorRigid3DTransformOptimizer VersorOptimizerType; typedef itk::QuaternionRigidTransformGradientDescentOptimizer QuatOptimizerType; typedef itk::LBFGSOptimizer LBFGSOptimizerType; typedef itk::LBFGSBOptimizer LBFGSBOptimizerType; typedef itk::Statistics::NormalVariateGenerator OptimizerNormalGeneratorType; void Itk_registration_private::optimizer_set_max_iterations (int its) { if (stage->optim_type == OPTIMIZATION_AMOEBA) { typedef AmoebaOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); optimizer->SetMaximumNumberOfIterations(its); } else if (stage->optim_type == OPTIMIZATION_ONEPLUSONE) { typedef OnePlusOneOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); optimizer->SetMaximumIteration(its); } else if (stage->optim_type == OPTIMIZATION_FRPR) { typedef FRPROptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); optimizer->SetMaximumIteration(its); } else if (stage->optim_type == OPTIMIZATION_RSG) { typedef RSGOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); optimizer->SetNumberOfIterations(its); } else if (stage->optim_type == OPTIMIZATION_VERSOR) { typedef VersorOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); optimizer->SetNumberOfIterations(its); } else if (stage->optim_type == OPTIMIZATION_QUAT) { typedef QuatOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); optimizer->SetNumberOfIterations(its); } else if (stage->optim_type == OPTIMIZATION_LBFGS) { typedef LBFGSOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); optimizer->SetMaximumNumberOfFunctionEvaluations (its); } else if (stage->optim_type == OPTIMIZATION_LBFGSB) { typedef LBFGSBOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); optimizer->SetMaximumNumberOfIterations (its); optimizer->SetMaximumNumberOfEvaluations (its); } else { print_and_exit ("Error: Unknown optimizer value.\n"); } } double Itk_registration_private::optimizer_get_value () { if (stage->optim_type == OPTIMIZATION_AMOEBA) { typedef AmoebaOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCachedValue(); } else if (stage->optim_type == OPTIMIZATION_ONEPLUSONE) { typedef OnePlusOneOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetValue(); } else if (stage->optim_type == OPTIMIZATION_FRPR) { typedef FRPROptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetValue(); } else if (stage->optim_type == OPTIMIZATION_RSG) { typedef RSGOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetValue(); } else if (stage->optim_type == OPTIMIZATION_VERSOR) { typedef VersorOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetValue(); } else if (stage->optim_type == OPTIMIZATION_QUAT) { typedef QuatOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetValue(); } else if (stage->optim_type == OPTIMIZATION_LBFGS) { typedef LBFGSOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCachedValue(); } else if (stage->optim_type == OPTIMIZATION_LBFGSB) { typedef LBFGSBOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCachedValue(); } else { print_and_exit ("Error: Unknown optimizer value.\n"); } return 0.0; /* Suppress compiler warning */ } double Itk_registration_private::optimizer_get_step_length () { if (stage->optim_type == OPTIMIZATION_AMOEBA) { #if defined (commentout) typedef AmoebaOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); #endif return -1.0; } else if (stage->optim_type == OPTIMIZATION_ONEPLUSONE) { return -1.0; } else if (stage->optim_type == OPTIMIZATION_FRPR) { typedef FRPROptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetStepLength(); } else if (stage->optim_type == OPTIMIZATION_RSG) { typedef RSGOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentStepLength(); } else if (stage->optim_type == OPTIMIZATION_VERSOR) { typedef VersorOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentStepLength(); } else if (stage->optim_type == OPTIMIZATION_QUAT) { #if defined (commentout) typedef QuatOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); #endif return -1.0; } else if (stage->optim_type == OPTIMIZATION_LBFGS) { #if defined (commentout) typedef LBFGSOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); #endif return -1.0; } else if (stage->optim_type == OPTIMIZATION_LBFGSB) { typedef LBFGSBOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetInfinityNormOfProjectedGradient(); } else { print_and_exit ("Error: Unknown optimizer value.\n"); } return 0.0; /* Suppress compiler warning */ } int Itk_registration_private::optimizer_get_current_iteration () { if (stage->optim_type == OPTIMIZATION_AMOEBA) { #if defined (commentout) typedef AmoebaOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); #endif return -1; } if (stage->optim_type == OPTIMIZATION_ONEPLUSONE) { typedef OnePlusOneOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentIteration(); } else if (stage->optim_type == OPTIMIZATION_FRPR) { typedef FRPROptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentIteration(); } else if (stage->optim_type == OPTIMIZATION_RSG) { typedef RSGOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentIteration(); } else if (stage->optim_type == OPTIMIZATION_VERSOR) { typedef VersorOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentIteration(); } else if (stage->optim_type == OPTIMIZATION_QUAT) { typedef QuatOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentIteration(); } else if (stage->optim_type == OPTIMIZATION_LBFGS) { #if defined (commentout) typedef LBFGSOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); #endif return -1; } else if (stage->optim_type == OPTIMIZATION_LBFGSB) { typedef LBFGSBOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentIteration(); } else { print_and_exit ("Error: Unknown optimizer value.\n"); } return 0; /* Suppress compiler warning */ } const itk::Array& Itk_registration_private::optimizer_get_current_position () { if (stage->optim_type == OPTIMIZATION_AMOEBA) { typedef AmoebaOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCachedCurrentPosition(); } else if (stage->optim_type == OPTIMIZATION_ONEPLUSONE) { typedef OnePlusOneOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentPosition(); } else if (stage->optim_type == OPTIMIZATION_FRPR) { typedef FRPROptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentPosition(); } else if (stage->optim_type == OPTIMIZATION_RSG) { return registration->GetTransform()->GetParameters(); } else if (stage->optim_type == OPTIMIZATION_VERSOR) { typedef VersorOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentPosition(); } else if (stage->optim_type == OPTIMIZATION_QUAT) { typedef QuatOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentPosition(); } else if (stage->optim_type == OPTIMIZATION_LBFGS) { typedef LBFGSOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentPosition(); } else if (stage->optim_type == OPTIMIZATION_LBFGSB) { typedef LBFGSBOptimizerType * OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( registration->GetOptimizer()); return optimizer->GetCurrentPosition(); } else { print_and_exit ("Error: Unknown optimizer value.\n"); } exit (1); /* Suppress compiler warning */ } void Itk_registration_private::optimizer_stop () { /* calling StopOptimization() doesn't always stop optimization */ if (stage->optim_type == OPTIMIZATION_RSG) { /* calling optimizer_set_max_iterations () doesn't seem to always stop rsg. */ typedef itk::RegularStepGradientDescentOptimizer *OptimizerPointer; OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >(registration->GetOptimizer()); optimizer->StopOptimization(); } else { optimizer_set_max_iterations (1); } } void set_optimization_amoeba (RegistrationType::Pointer registration, Stage_parms* stage) { AmoebaOptimizerType::Pointer optimizer = AmoebaOptimizerType::New(); optimizer->SetParametersConvergenceTolerance(stage->amoeba_parameter_tol); optimizer->SetFunctionConvergenceTolerance(stage->convergence_tol); // Was 10000 optimizer->SetMaximumNumberOfIterations(stage->max_its); registration->SetOptimizer(optimizer); } void set_optimization_rsg (RegistrationType::Pointer registration, Stage_parms* stage) { RSGOptimizerType::Pointer optimizer = RSGOptimizerType::New(); optimizer->SetMaximumStepLength(stage->max_step); optimizer->SetMinimumStepLength(stage->min_step); optimizer->SetNumberOfIterations(stage->max_its); optimizer->SetGradientMagnitudeTolerance (stage->rsg_grad_tol); registration->SetOptimizer(optimizer); } void set_optimization_oneplusone ( RegistrationType::Pointer registration, Stage_parms* stage) { OnePlusOneOptimizerType::Pointer optimizer = OnePlusOneOptimizerType::New(); optimizer->SetNormalVariateGenerator(OptimizerNormalGeneratorType::New() ); optimizer->SetMaximumIteration(stage->max_its); optimizer->SetEpsilon(stage->opo_epsilon); optimizer->Initialize(stage->opo_initial_search_rad); // Initial search radius registration->SetOptimizer(optimizer); } void set_optimization_frpr(RegistrationType::Pointer registration, Stage_parms* stage) { FRPROptimizerType::Pointer optimizer = FRPROptimizerType::New(); optimizer->SetMaximize(false); optimizer->SetStepLength(5); optimizer->SetStepTolerance(stage->frpr_step_tol); optimizer->SetMaximumIteration(stage->max_its); optimizer->SetMaximumLineIteration(stage->frpr_max_line_its); registration->SetOptimizer(optimizer); } void set_optimization_versor (RegistrationType::Pointer registration, Stage_parms* stage) { VersorOptimizerType::Pointer optimizer = VersorOptimizerType::New(); optimizer->SetMaximumStepLength(stage->max_step); optimizer->SetMinimumStepLength(stage->min_step); optimizer->SetNumberOfIterations(stage->max_its); optimizer->SetGradientMagnitudeTolerance (stage->rsg_grad_tol); registration->SetOptimizer(optimizer); } void set_optimization_quat (RegistrationType::Pointer registration, Stage_parms* stage) { QuatOptimizerType::Pointer optimizer = QuatOptimizerType::New(); optimizer->SetLearningRate(stage->learn_rate); lprintf ("Learning Rate was set to : %f\n", optimizer->GetLearningRate()); optimizer->SetNumberOfIterations(stage->max_its); registration->SetOptimizer(optimizer); } void set_optimization_lbfgs (RegistrationType::Pointer registration, Stage_parms* stage) { LBFGSOptimizerType::Pointer optimizer = LBFGSOptimizerType::New(); optimizer->SetGradientConvergenceTolerance (stage->grad_tol); optimizer->SetLineSearchAccuracy (0.9); optimizer->SetDefaultStepLength (5.0); #if defined (commentout) optimizer->SetMaximumNumberOfFunctionEvaluations (100); optimizer->SetMaximumNumberOfFunctionEvaluations (50); optimizer->SetMaximumNumberOfFunctionEvaluations (10); #endif optimizer->SetMaximumNumberOfFunctionEvaluations (50); optimizer->TraceOn(); registration->SetOptimizer(optimizer); } void set_optimization_lbfgsb (RegistrationType::Pointer registration, Stage_parms* stage) { LBFGSBOptimizerType::Pointer optimizer = LBFGSBOptimizerType::New(); LBFGSBOptimizerType::BoundSelectionType boundSelect ( registration->GetTransform()->GetNumberOfParameters()); LBFGSBOptimizerType::BoundValueType upperBound ( registration->GetTransform()->GetNumberOfParameters()); LBFGSBOptimizerType::BoundValueType lowerBound ( registration->GetTransform()->GetNumberOfParameters()); boundSelect.Fill(0); upperBound.Fill(0.0); lowerBound.Fill(0.0); optimizer->SetBoundSelection(boundSelect); optimizer->SetUpperBound(upperBound); optimizer->SetLowerBound(lowerBound); /* GCS FIX: I think this is right for # of evaluations. Not at all sure about # of corrections or cost fn convergence factor. */ optimizer->SetCostFunctionConvergenceFactor (1e+7); optimizer->SetProjectedGradientTolerance (stage->pgtol); optimizer->SetMaximumNumberOfIterations (stage->max_its); optimizer->SetMaximumNumberOfEvaluations (2 * stage->max_its); optimizer->SetMaximumNumberOfCorrections (5); registration->SetOptimizer(optimizer); } void set_optimization_scales_translation (RegistrationType::Pointer registration, Stage_parms* stage) { itk::Array optimizerScales(3); const double translationScale = 1.0 / (double) stage->translation_scale_factor; optimizerScales[0] = translationScale; optimizerScales[1] = translationScale; optimizerScales[2] = translationScale; registration->GetOptimizer()->SetScales(optimizerScales); } void set_optimization_scales_versor ( RegistrationType::Pointer registration, Stage_parms* stage) { double rotation_scale, translation_scale; itk::Array optimizerScales(6); if (stage->optim_type == OPTIMIZATION_AMOEBA) { rotation_scale = 1.0; translation_scale = 1.0; } else { rotation_scale = 1.0 / (double) stage->rotation_scale_factor; translation_scale = 1.0 / (double) stage->translation_scale_factor; } optimizerScales[0] = rotation_scale; optimizerScales[1] = rotation_scale; optimizerScales[2] = rotation_scale; optimizerScales[3] = translation_scale; optimizerScales[4] = translation_scale; optimizerScales[5] = translation_scale; registration->GetOptimizer()->SetScales(optimizerScales); } void set_optimization_scales_quaternion ( RegistrationType::Pointer registration, Stage_parms* stage) { double rotation_scale, translation_scale; itk::Array optimizerScales(7); rotation_scale = 1.0 / (double) stage->rotation_scale_factor; translation_scale = 1.0 / (double) stage->translation_scale_factor; /* GCS FIX: Changing the scale fudge_factor is one way to avoid ITK "Too many samples..." problem */ //double fudge_factor = 1000000.0; double fudge_factor = 1.0; rotation_scale = rotation_scale * fudge_factor; translation_scale = translation_scale * fudge_factor; optimizerScales[0] = rotation_scale; optimizerScales[1] = rotation_scale; optimizerScales[2] = rotation_scale; optimizerScales[3] = rotation_scale; optimizerScales[4] = translation_scale; optimizerScales[5] = translation_scale; optimizerScales[6] = translation_scale; registration->GetOptimizer()->SetScales(optimizerScales); } void set_optimization_scales_affine (RegistrationType::Pointer registration, Stage_parms* stage) { itk::Array optimizerScales(12); const double matrix_scale = 1.0; //const double translationScale = 1.0 / 10000.0; const double translation_scale = 1.0 / (double) stage->translation_scale_factor; //const double translation_scale = 1.0 / 1000000.0; optimizerScales[0] = matrix_scale; optimizerScales[1] = matrix_scale; optimizerScales[2] = matrix_scale; optimizerScales[3] = matrix_scale; optimizerScales[4] = matrix_scale; optimizerScales[5] = matrix_scale; optimizerScales[6] = matrix_scale; optimizerScales[7] = matrix_scale; optimizerScales[8] = matrix_scale; optimizerScales[9] = translation_scale; optimizerScales[10] = translation_scale; optimizerScales[11] = translation_scale; registration->GetOptimizer()->SetScales(optimizerScales); } void set_optimization_scales_similarity (RegistrationType::Pointer registration, Stage_parms* stage) { itk::Array optimizerScales(7); const double rotation_scale = 1.0 / (double) stage->rotation_scale_factor; const double translation_scale = 1.0/ (double) stage->translation_scale_factor; const double scaling_scale = 1.0/ (double) stage->scaling_scale_factor; optimizerScales[0] = rotation_scale; optimizerScales[1] = rotation_scale; optimizerScales[2] = rotation_scale; optimizerScales[3] = translation_scale; optimizerScales[4] = translation_scale; optimizerScales[5] = translation_scale; optimizerScales[6] = scaling_scale; registration->GetOptimizer()->SetScales(optimizerScales); } void Itk_registration_private::set_optimization () { if (stage->xform_type == STAGE_TRANSFORM_QUATERNION) { stage->optim_type = OPTIMIZATION_QUAT; } else if (stage->optim_type == OPTIMIZATION_VERSOR && (stage->xform_type == STAGE_TRANSFORM_TRANSLATION || stage->xform_type == STAGE_TRANSFORM_AFFINE || stage->xform_type == STAGE_TRANSFORM_SIMILARITY)) { stage->optim_type = OPTIMIZATION_RSG; } else if (stage->xform_type == STAGE_TRANSFORM_BSPLINE && (stage->optim_type != OPTIMIZATION_LBFGS && stage->optim_type != OPTIMIZATION_LBFGSB)) { stage->optim_type = OPTIMIZATION_LBFGSB; } switch (stage->optim_type) { case OPTIMIZATION_AMOEBA: set_optimization_amoeba(registration,stage); break; case OPTIMIZATION_ONEPLUSONE: set_optimization_oneplusone(registration,stage); break; case OPTIMIZATION_FRPR: set_optimization_frpr(registration,stage); break; case OPTIMIZATION_RSG: set_optimization_rsg(registration,stage); break; case OPTIMIZATION_VERSOR: set_optimization_versor(registration,stage); break; case OPTIMIZATION_QUAT: set_optimization_quat(registration,stage); break; case OPTIMIZATION_LBFGS: set_optimization_lbfgs(registration,stage); break; case OPTIMIZATION_LBFGSB: set_optimization_lbfgsb(registration,stage); break; default: print_and_exit ("Unknown optimizer used in ITK optimization\n"); break; } switch (stage->xform_type) { case STAGE_TRANSFORM_TRANSLATION: set_optimization_scales_translation (registration, stage); break; case STAGE_TRANSFORM_VERSOR: set_optimization_scales_versor (registration, stage); break; case STAGE_TRANSFORM_QUATERNION: set_optimization_scales_quaternion (registration, stage); break; case STAGE_TRANSFORM_AFFINE: set_optimization_scales_affine (registration, stage); break; case STAGE_TRANSFORM_SIMILARITY: set_optimization_scales_similarity (registration, stage); break; case STAGE_TRANSFORM_BSPLINE: /* LBFGS/LBFGSB only. No optimizer scales. */ break; default: print_and_exit ("Unknown xform type used in ITK optimization\n"); break; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/itk_optimizer.h000066400000000000000000000005111321604176500315020ustar00rootroot00000000000000/* =======================================================================* Copyright (c) 2004-2006 Massachusetts General Hospital. All rights reserved. * =======================================================================*/ #ifndef _itk_optimizer_h_ #define _itk_optimizer_h_ #include "plmregister_config.h" #endif itk_registration.cxx000066400000000000000000000717301321604176500325010ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include "itkCenteredTransformInitializer.h" #include "itkImageMaskSpatialObject.h" #include #include "itkLinearInterpolateImageFunction.h" #include "itkMutualInformationImageToImageMetric.h" #include "itkNormalizedMutualInformationHistogramImageToImageMetric.h" #include "itkRegularStepGradientDescentOptimizer.h" #if defined (ITK_USE_OPTIMIZED_REGISTRATION_METHODS) \ && defined (PLM_CONFIG_USE_PATCHED_ITK) #include "plm_OptMattesMutualInformationImageToImageMetric.h" #include "itkOptMeanSquaresImageToImageMetric.h" #elif defined (ITK_USE_OPTIMIZED_REGISTRATION_METHODS) #include "itkOptMattesMutualInformationImageToImageMetric.h" #include "itkOptMeanSquaresImageToImageMetric.h" #else #include "itkMattesMutualInformationImageToImageMetric.h" #include "itkMeanSquaresImageToImageMetric.h" #endif #include "compiler_warnings.h" #include "itk_image.h" #include "itk_image_type.h" #include "itk_optimizer.h" #include "itk_registration.h" #include "itk_registration_private.h" #include "itk_resample.h" #include "logfile.h" #include "metric_parms.h" #include "plm_image.h" #include "plm_image_header.h" #include "print_and_exit.h" #include "registration_data.h" #include "registration_util.h" #include "shared_parms.h" #include "stage_parms.h" #include "xform.h" typedef itk::MeanSquaresImageToImageMetric < FloatImageType, FloatImageType > MSEMetricType; typedef itk::MutualInformationImageToImageMetric < FloatImageType, FloatImageType > MIMetricType; typedef itk::NormalizedMutualInformationHistogramImageToImageMetric < FloatImageType, FloatImageType > NMIMetricType; #if defined (ITK_USE_OPTIMIZED_REGISTRATION_METHODS) \ && defined (PLM_CONFIG_USE_PATCHED_ITK) typedef itk::plm_MattesMutualInformationImageToImageMetric < FloatImageType, FloatImageType > MattesMIMetricType; #else typedef itk::MattesMutualInformationImageToImageMetric < FloatImageType, FloatImageType > MattesMIMetricType; #endif typedef itk::ImageToImageMetric < FloatImageType, FloatImageType > MetricType; typedef itk::ImageMaskSpatialObject< 3 > Mask_SOType; typedef itk::LinearInterpolateImageFunction < FloatImageType, double >InterpolatorType; static void itk_align_center ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, const Stage_parms* stage); static void itk_align_center_of_gravity ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, const Stage_parms* stage); Itk_registration_private::Itk_registration_private ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, Stage_parms* stage ) { this->regd = regd; this->xf_in = xf_in; this->xf_out = xf_out; this->stage = stage; this->best_value = DBL_MAX; this->xf_best = new Xform (*xf_in); } Itk_registration_private::~Itk_registration_private () { delete this->xf_best; } static bool itk_unnecessary_exception (const itk::ExceptionObject& err) { std::string err_string = err.GetDescription(); /* ITK throws exceptions when evaluating metrics with overlap of less that 25%. Identify these so we can continue processing. */ const char *t1 = "Too many samples map outside moving image buffer"; if (err_string.find (t1) != std::string::npos) { return true; } /* ITK throws exceptions when MI joint PDF is zero. Identify these so we can continue processing. */ const char *t2 = "Joint PDF summed to zero"; if (err_string.find (t2) != std::string::npos) { return true; } return false; } double Itk_registration_private::evaluate_initial_transform () { double value = DBL_MAX; MetricType *metric = registration->GetMetric(); try { value = metric->GetValue ( registration->GetInitialTransformParameters()); } catch (itk::ExceptionObject & err) { if (itk_unnecessary_exception (err)) { lprintf ("ITK failed with too few samples.\n"); return value; } lprintf ("Exception caught in evaluate_initial_transform()\n"); std::stringstream ss; ss << err << "\n"; lprintf (ss.str().c_str()); exit (-1); } return value; } unsigned int Itk_registration_private::compute_num_samples ( FloatImageType::Pointer& fixed_ss) { if (stage->mi_num_spatial_samples > 0) { lprintf ("Setting spatial samples to %d\n", stage->mi_num_spatial_samples); return stage->mi_num_spatial_samples; } plm_long num_voxels = count_fixed_voxels (regd, stage, fixed_ss); unsigned int num_samples = stage->mi_num_spatial_samples_pct * num_voxels; lprintf ("Setting spatial samples to %f x %d = %u\n", stage->mi_num_spatial_samples_pct, (int) num_voxels, (unsigned int) (stage->mi_num_spatial_samples_pct * num_voxels)); return num_samples; } void Itk_registration_private::set_best_xform () { switch (stage->xform_type) { case STAGE_TRANSFORM_TRANSLATION: xf_best->set_trn ( registration->GetTransform()->GetParameters()); break; case STAGE_TRANSFORM_VERSOR: xf_best->set_vrs ( registration->GetTransform()->GetParameters()); break; case STAGE_TRANSFORM_QUATERNION: xf_best->set_quat ( registration->GetTransform()->GetParameters()); break; case STAGE_TRANSFORM_AFFINE: xf_best->set_aff ( registration->GetTransform()->GetParameters()); break; case STAGE_TRANSFORM_SIMILARITY: xf_best->set_similarity ( registration->GetTransform()->GetParameters()); break; case STAGE_TRANSFORM_BSPLINE: { /* GCS FIX: The B-spline method still gives the last xform, not the best xform */ #if defined (commentout) typedef BsplineTransformType * XfPtr; XfPtr transform = static_cast(registration->GetTransform()); xf_best->set_itk_bsp (transform); #endif } break; default: print_and_exit ("Error: unknown case in set_best_xform()\n"); break; } } void Itk_registration_private::set_metric (FloatImageType::Pointer& fixed_ss) { /* GCS FIX, split metric vector into separate items in Stage_similarity_data list */ Metric_parms metric_parms; const Shared_parms *shared = stage->get_shared_parms(); std::map::const_iterator metric_it; for (metric_it = shared->metric.begin(); metric_it != shared->metric.end(); ++metric_it) { metric_parms = metric_it->second; break; } switch (metric_parms.metric_type) { case SIMILARITY_METRIC_MSE: { MSEMetricType::Pointer metric = MSEMetricType::New(); registration->SetMetric(metric); } break; case SIMILARITY_METRIC_MI_VW: { /* The metric requires a number of parameters to be selected, including the standard deviation of the Gaussian kernel for the fixed image density estimate, the standard deviation of the kernel for the moving image density and the number of samples use to compute the densities and entropy values. Details on the concepts behind the computation of the metric can be found in Section \ref{sec:MutualInformationMetric}. Experience has shown that a kernel standard deviation of $0.4$ works well for images which have been normalized to a mean of zero and unit variance. We will follow this empirical rule in this example. */ MIMetricType::Pointer metric = MIMetricType::New(); metric->SetFixedImageStandardDeviation( 0.4 ); metric->SetMovingImageStandardDeviation( 0.4 ); registration->SetMetric(metric); } break; case SIMILARITY_METRIC_MI_MATTES: { /* The metric requires two parameters to be selected: the number of bins used to compute the entropy and the number of spatial samples used to compute the density estimates. In typical application, 50 histogram bins are sufficient and the metric is relatively insensitive to changes in the number of bins. The number of spatial samples to be used depends on the content of the image. If the images are smooth and do not contain much detail, then using approximately $1$ percent of the pixels will do. On the other hand, if the images are detailed, it may be necessary to use a much higher proportion, such as $20$ percent. */ MattesMIMetricType::Pointer metric = MattesMIMetricType::New(); metric->SetNumberOfHistogramBins( stage->mi_hist_fixed_bins); metric->SetNumberOfSpatialSamples ( this->compute_num_samples (fixed_ss)); #if defined (ITK_USE_OPTIMIZED_REGISTRATION_METHODS) \ && defined (PLM_CONFIG_USE_PATCHED_ITK) /* Setting maxVal and minVal for MI calculation (default==0 --> minVal and maxVal will be calculated from images) */ metric->SetFixedImageMin(stage->mi_fixed_image_minVal); metric->SetMovingImageMin(stage->mi_moving_image_minVal); metric->SetFixedImageMax(stage->mi_fixed_image_maxVal); metric->SetMovingImageMax(stage->mi_moving_image_maxVal); #endif registration->SetMetric(metric); } break; case SIMILARITY_METRIC_NMI: { NMIMetricType::Pointer metric = NMIMetricType::New(); //NMIMetricType::HistogramSizeType hist; NMIMetricType::HistogramType::SizeType hist; #if defined (ITK_USE_REVIEW_STATISTICS) || (ITK_VERSION_MAJOR >= 4) hist.SetSize(2); #endif hist[0] = stage->mi_hist_fixed_bins; hist[1] = stage->mi_hist_moving_bins; metric->SetHistogramSize (hist); /* Apparently sampling is not implemented in ITK 3 unless optimized registration methods are specified. */ #if ITK_VERSION_MAJOR >= 4 \ || (defined (ITK_USE_OPTIMIZED_REGISTRATION_METHODS) \ && defined (PLM_CONFIG_USE_PATCHED_ITK)) metric->SetNumberOfSpatialSamples ( this->compute_num_samples (fixed_ss)); #endif #if defined (commentout) /* The ITK example program has this, but it's out of order compared to existing sequence (transform hasn't yet been set)... */ NMIMetricType::ScalesType scales ( registration->GetTransform()->GetNumberOfParameters()); scales.Fill (1.0); metric->SetDerivativeStepLengthScales (scales); #endif registration->SetMetric(metric); } break; default: print_and_exit ("Error: metric is not implemented"); break; } } void Itk_registration_private::set_roi_images () { const Shared_parms *shared = stage->get_shared_parms(); if (shared->fixed_roi_enable && regd->get_fixed_roi()) { Mask_SOType::Pointer roi_so = Mask_SOType::New(); roi_so->SetImage(regd->get_fixed_roi()->itk_uchar()); roi_so->Update(); registration->GetMetric()->SetFixedImageMask (roi_so); } if (shared->moving_roi_enable && regd->get_moving_roi()) { Mask_SOType::Pointer roi_so = Mask_SOType::New(); roi_so->SetImage(regd->get_moving_roi()->itk_uchar()); roi_so->Update(); registration->GetMetric()->SetMovingImageMask (roi_so); } } /* This helps speed up the registration, by setting the bounding box to the smallest size needed. To find the bounding box, either use the extent of the fixed_roi (if one is used), or by eliminating excess air by thresholding */ void set_fixed_image_region_new_unfinished ( RegistrationType::Pointer registration, Registration_data* regd, Stage_parms* stage ) { FloatImageType::RegionType valid_region; FloatImageType::RegionType::IndexType valid_index; FloatImageType::RegionType::SizeType valid_size; FloatImageType::ConstPointer fi = static_cast < FloatImageType::ConstPointer > (registration->GetFixedImage()); for (int d = 0; d < 3; d++) { float ori = regd->fixed_region_origin[d] + regd->fixed_region.GetIndex()[d] * regd->fixed_region_spacing[d]; int idx = (int) floor (ori - (fi->GetOrigin()[d] - 0.5 * fi->GetSpacing()[d]) / fi->GetSpacing()[d]); if (idx < 0) { fprintf (stderr, "set_fixed_image_region conversion error.\n"); exit (-1); } float last_pix_center = ori + (regd->fixed_region.GetSize()[d]-1) * regd->fixed_region_spacing[d]; int siz = (int) floor (last_pix_center - (fi->GetOrigin()[d] - 0.5 * fi->GetSpacing()[d]) / fi->GetSpacing()[d]); siz = siz - idx + 1; valid_index[d] = idx; valid_size[d] = siz; } valid_region.SetIndex (valid_index); valid_region.SetSize (valid_size); registration->SetFixedImageRegion (valid_region); } void Itk_registration_private::set_fixed_image_region () { /* GCS 2013-07-19. The automatic region setting appears to be buggy let's comment it out until it can be fixed. */ registration->SetFixedImageRegion ( registration->GetFixedImage()->GetLargestPossibleRegion()); #if defined (commentout) int use_magic_value = 0; if (regd->fixed_roi) { FloatImageType::RegionType valid_region; FloatImageType::RegionType::IndexType valid_index; FloatImageType::RegionType::SizeType valid_size; valid_index[0] = 0; valid_index[1] = 0; valid_index[2] = 0; valid_size[0] = 1; valid_size[1] = 1; valid_size[2] = 1; /* Search for bounding box of fixed roi */ typedef Mask_SOType* Mask_SOPointer; Mask_SOPointer so = (Mask_SOPointer) registration->GetMetric()->GetFixedImageMask(); typedef itk::ImageRegionConstIteratorWithIndex < UCharImageType > IteratorType; UCharImageType::RegionType region = registration->GetFixedImage()->GetLargestPossibleRegion(); IteratorType it (so->GetImage(), region); int first = 1; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { unsigned char c = it.Get(); if (c) { UCharImageType::RegionType::IndexType idx = it.GetIndex(); if (first) { first = 0; valid_index = idx; valid_size[0] = 1; valid_size[1] = 1; valid_size[2] = 1; } else { int updated = 0; for (int i = 0; i < 3; i++) { if (valid_index[i] > idx[i]) { valid_size[i] += valid_index[i] - idx[i]; valid_index[i] = idx[i]; updated = 1; } if (idx[i] - valid_index[i] >= (long) valid_size[i]) { valid_size[i] = idx[i] - valid_index[i] + 1; updated = 1; } } UNUSED_VARIABLE (updated); } } } valid_region.SetIndex(valid_index); valid_region.SetSize(valid_size); registration->SetFixedImageRegion(valid_region); } else if (use_magic_value) { FloatImageType::RegionType valid_region; FloatImageType::RegionType::IndexType valid_index; FloatImageType::RegionType::SizeType valid_size; /* Search for bounding box of patient */ typedef itk::ImageRegionConstIteratorWithIndex < FloatImageType > IteratorType; FloatImageType::RegionType region = registration->GetFixedImage()->GetLargestPossibleRegion(); IteratorType it (registration->GetFixedImage(), region); int first = 1; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { float c = it.Get(); if (c > stage->background_max) { FloatImageType::RegionType::IndexType idx = it.GetIndex(); if (first) { first = 0; valid_index = idx; valid_size[0] = 1; valid_size[1] = 1; valid_size[2] = 1; } else { int updated = 0; for (int i = 0; i < 3; i++) { if (valid_index[i] > idx[i]) { valid_size[i] += valid_index[i] - idx[i]; valid_index[i] = idx[i]; updated = 1; } if (idx[i] - valid_index[i] >= (long) valid_size[i]) { valid_size[i] = idx[i] - valid_index[i] + 1; updated = 1; } } UNUSED_VARIABLE (updated); } } } /* Try to include a margin of at least one air pixel everywhere */ for (int i = 0; i < 3; i++) { if (valid_index[i] > 0) { valid_index[i]--; valid_size[i]++; } if (valid_size[i] + valid_index[i] < registration->GetFixedImage()->GetLargestPossibleRegion().GetSize()[i]) { valid_size[i]++; } } valid_region.SetIndex(valid_index); valid_region.SetSize(valid_size); registration->SetFixedImageRegion(valid_region); } else { registration->SetFixedImageRegion ( registration->GetFixedImage()->GetLargestPossibleRegion()); } #endif } template void show_image_stats (T image) { typedef typename T::ObjectType Img; const typename Img::SizeType& sz = image->GetLargestPossibleRegion().GetSize(); const typename Img::PointType& ori = image->GetOrigin(); const typename Img::SpacingType& sp = image->GetSpacing(); const typename Img::DirectionType& di = image->GetDirection(); lprintf ("Dim = %d %d %d\n", sz[0], sz[1], sz[2]); lprintf ("Origin = %g %g %g\n", ori[0], ori[1], ori[2]); lprintf ("Spacing = %g %g %g\n", sp[0], sp[1], sp[2]); lprintf ("Direction Cosines =\n"); for (unsigned int d1 = 0; d1 < 3; d1++) { for (unsigned int d2 = 0; d2 < 3; d2++) { lprintf (" %g", di[d1][d2]); } lprintf ("\n"); } } void Itk_registration_private::show_stats () { lprintf ("Fixed image for this stage:\n"); show_image_stats(static_cast < FloatImageType::ConstPointer > ( registration->GetFixedImage())); lprintf ("Moving image for this stage:\n"); show_image_stats(static_cast < FloatImageType::ConstPointer > ( registration->GetMovingImage())); } static void set_transform_translation ( RegistrationType::Pointer registration, Xform *xf_out, const Xform *xf_in, Stage_parms* stage) { Plm_image_header pih; pih.set_from_itk_image (registration->GetFixedImage()); xform_to_trn (xf_out, xf_in, &pih); registration->SetTransform (xf_out->get_trn()); } static void set_transform_versor ( RegistrationType::Pointer registration, Xform *xf_out, const Xform *xf_in, Stage_parms* stage) { Plm_image_header pih; pih.set_from_itk_image (registration->GetFixedImage()); xform_to_vrs (xf_out, xf_in, &pih); registration->SetTransform (xf_out->get_vrs()); } static void set_transform_quaternion ( RegistrationType::Pointer registration, Xform *xf_out, const Xform *xf_in, Stage_parms* stage) { Plm_image_header pih; pih.set_from_itk_image (registration->GetFixedImage()); xform_to_quat (xf_out, xf_in, &pih); registration->SetTransform (xf_out->get_quat()); } static void set_transform_affine ( RegistrationType::Pointer registration, Xform *xf_out, const Xform *xf_in, Stage_parms* stage) { Plm_image_header pih; pih.set_from_itk_image (registration->GetFixedImage()); xform_to_aff (xf_out, xf_in, &pih); registration->SetTransform (xf_out->get_aff()); } void set_transform_similarity ( RegistrationType::Pointer registration, Xform *xf_out, const Xform *xf_in, Stage_parms* stage) { Plm_image_header pih; pih.set_from_itk_image (registration->GetFixedImage()); xform_to_similarity (xf_out, xf_in, &pih); registration->SetTransform (xf_out->get_similarity()); } static void set_transform_bspline ( RegistrationType::Pointer registration, Xform *xf_out, const Xform *xf_in, Stage_parms* stage ) { Plm_image_header pih; pih.set_from_itk_image (registration->GetFixedImage()); /* GCS FIX: Need to set ROI from registration->GetFixedImageRegion(), */ xform_to_itk_bsp (xf_out, xf_in, &pih, stage->grid_spac); registration->SetTransform (xf_out->get_itk_bsp()); } void Itk_registration_private::set_transform () { xf_out->clear(); switch (stage->xform_type) { case STAGE_TRANSFORM_TRANSLATION: set_transform_translation (registration, xf_out, xf_in, stage); break; case STAGE_TRANSFORM_VERSOR: set_transform_versor (registration, xf_out, xf_in, stage); break; case STAGE_TRANSFORM_QUATERNION: set_transform_quaternion (registration, xf_out, xf_in, stage); break; case STAGE_TRANSFORM_SIMILARITY: set_transform_similarity (registration, xf_out, xf_in, stage); break; case STAGE_TRANSFORM_AFFINE: set_transform_affine (registration, xf_out, xf_in, stage); break; case STAGE_TRANSFORM_BSPLINE: set_transform_bspline (registration, xf_out, xf_in, stage); break; case STAGE_TRANSFORM_ALIGN_CENTER: set_transform_versor(registration, xf_out, xf_in, stage); break; case STAGE_TRANSFORM_ALIGN_CENTER_OF_GRAVITY: set_transform_versor(registration, xf_out, xf_in, stage); break; default: print_and_exit ("Error: unknown case in set_transform()\n"); break; } registration->SetInitialTransformParameters ( registration->GetTransform()->GetParameters()); if (stage->xform_type != STAGE_TRANSFORM_BSPLINE) { std::stringstream ss; ss << "Initial Parameters = " << registration->GetTransform()->GetParameters() << "\n"; lprintf (ss.str().c_str()); } } void Itk_registration_private::set_xf_out () { if (stage->xform_type == STAGE_TRANSFORM_BSPLINE) { /* Do nothing */ } else { *xf_out = *xf_best; } } static void itk_registration_stage ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, Stage_parms* stage ) { /* center_align is handled separately */ if (stage->xform_type == STAGE_TRANSFORM_ALIGN_CENTER) { return itk_align_center (regd, xf_out, xf_in, stage); } /* align_center_of_gravity is handled separately */ if (stage->xform_type == STAGE_TRANSFORM_ALIGN_CENTER_OF_GRAVITY) { return itk_align_center_of_gravity (regd, xf_out, xf_in, stage); } Itk_registration_private irp (regd, xf_out, xf_in, stage); irp.registration = RegistrationType::New(); /* Subsample fixed & moving images */ Plm_image::Pointer fixed_image = regd->get_fixed_image(); Plm_image::Pointer moving_image = regd->get_moving_image(); FloatImageType::Pointer fixed_ss = subsample_image ( fixed_image->itk_float(), stage->resample_rate_fixed[0], stage->resample_rate_fixed[1], stage->resample_rate_fixed[2], stage->default_value); FloatImageType::Pointer moving_ss = subsample_image ( moving_image->itk_float(), stage->resample_rate_moving[0], stage->resample_rate_moving[1], stage->resample_rate_moving[2], stage->default_value); irp.registration->SetFixedImage (fixed_ss); irp.registration->SetMovingImage (moving_ss); irp.set_metric (fixed_ss); // must be after setting images irp.set_roi_images (); // must be after set_metric irp.set_fixed_image_region (); // must be after set_roi_images irp.show_stats (); irp.set_transform (); // must be after set_fixed_image_region irp.set_optimization (); InterpolatorType::Pointer interpolator = InterpolatorType::New(); irp.registration->SetInterpolator (interpolator); irp.set_observer (); try { if (stage->optim_type != OPTIMIZATION_NO_REGISTRATION) { lprintf ("Starting ITK registration\n"); irp.registration->Update (); lprintf ("ITK registration complete\n"); } } catch (itk::ExceptionObject & err) { if (itk_unnecessary_exception (err)) { lprintf ("ITK failed with too few samples.\n"); } else { lprintf ("Exception caught in itk registration.\n"); std::stringstream ss; ss << err << "\n"; lprintf (ss.str().c_str()); exit (-1); } } irp.set_xf_out (); /* There is an ITK bug which deletes the internal memory of a BSplineDeformableTransform when the RegistrationMethod is destructed. This is a workaround for that bug. */ if (irp.stage->xform_type == STAGE_TRANSFORM_BSPLINE) { xf_out->get_itk_bsp()->SetParametersByValue ( xf_out->get_itk_bsp()->GetParameters ()); } } static void itk_align_center ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, const Stage_parms* stage) { Plm_image::Pointer fixed_image = regd->get_fixed_image(); Plm_image::Pointer moving_image = regd->get_moving_image(); float fixed_center[3]; float moving_center[3]; itk_volume_center (fixed_center, fixed_image->itk_float()); itk_volume_center (moving_center, moving_image->itk_float()); itk::Array trn_parms (3); trn_parms[0] = moving_center[0] - fixed_center[0]; trn_parms[1] = moving_center[1] - fixed_center[1]; trn_parms[2] = moving_center[2] - fixed_center[2]; xf_out->set_trn (trn_parms); } static void itk_align_center_of_gravity ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, const Stage_parms* stage) { if (regd->get_fixed_roi() && regd->get_moving_roi()) { typedef itk::ImageMomentsCalculator ImageMomentsCalculatorType; ImageMomentsCalculatorType::Pointer fixedCalculator = ImageMomentsCalculatorType::New(); fixedCalculator->SetImage(regd->get_fixed_roi()->itk_uchar()); fixedCalculator->Compute(); ImageMomentsCalculatorType::Pointer movingCalculator = ImageMomentsCalculatorType::New(); movingCalculator->SetImage(regd->get_moving_roi()->itk_uchar()); movingCalculator->Compute(); ImageMomentsCalculatorType::VectorType fixedCenter; ImageMomentsCalculatorType::VectorType movingCenter; fixedCenter = fixedCalculator->GetCenterOfGravity(); movingCenter = movingCalculator->GetCenterOfGravity(); itk::Array trn_parms (3); trn_parms[0] = movingCenter[0] - fixedCenter[0]; trn_parms[1] = movingCenter[1] - fixedCenter[1]; trn_parms[2] = movingCenter[2] - fixedCenter[2]; xf_out->set_trn (trn_parms); } else { print_and_exit("NO ROIs SET!"); } } /* Greg's notes about itk problems (ITK 3.20.1) There are two ways to set the ITK bspline parameters: SetParameters() SetCoefficientImage() SetParameters() --------------- You pass in a (const ParametersType&), and then it stashes a pointer to that in m_InputParametersPointer. Finally it calls WrapAsImages(), which maps m_CoefficientImage[] arrays into memory of m_InputParametersPointer SetCoefficientImage() --------------------- You pass in a (ImagePointer[]), and these get copied into m_CoefficientImage[] arrays. m_InputParametersPointer gets reset to zero. SetParametersByValue() ---------------------- You pass in a (const ParametersType&), and then it allocates a new memory to contain the array. It initializes m_InputParametersPointer with the internal buffer. Finally it calls WrapAsImages(), which maps m_CoefficientImage[] arrays into memory of m_InputParametersPointer xform_to_itk_bsp (xf_out, xf_in, &pih, stage->grid_spac); ----------------------- Computes the grid parameters using bsp_grid_from_img_grid(), then copies these into BSplineTransform using xform_itk_bsp_set_grid (). Note: SetGridRegion() will zero the region, but does not allocate it. */ Xform::Pointer do_itk_registration_stage ( Registration_data* regd, const Xform::Pointer& xf_in, Stage_parms* stage ) { Xform::Pointer xf_out = Xform::New (); itk_registration_stage (regd, xf_out.get(), xf_in.get(), stage); return xf_out; } itk_registration.h000066400000000000000000000010021321604176500321070ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_registration_h_ #define _itk_registration_h_ #include "plmregister_config.h" #include "xform.h" class Registration_data; class Stage_parms; Xform::Pointer do_itk_registration_stage (Registration_data* regd, const Xform::Pointer& xf_in, Stage_parms* stage); #endif itk_registration_observer.cxx000066400000000000000000000166621321604176500344130ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include "itkRegularStepGradientDescentOptimizer.h" #include "compiler_warnings.h" #include "itk_image_type.h" #include "itk_optimizer.h" #include "itk_registration.h" #include "itk_registration_private.h" #include "logfile.h" #include "metric_parms.h" #include "plm_math.h" #include "plm_timer.h" #include "shared_parms.h" #include "stage_parms.h" /* Lots of ITK algorithms don't behave uniformly. We're going to keep all this state in the observer, and the registration should query the observer to find the best registration. RSG - Invokes itk::IterationEvent - Current position at time of itk::IterationEvent is next position So we need to check registration->GetTransform() instead - Final transform is not optimal Amoeba - Invokes itk::FunctionValueIterationEvent - Current position is not valid at StartEvent - Initial transform is evaluated - Final transform is optimal LBFGS - Invokes itk::FunctionAndGradientEvaluationIterationEvent - Current position is not valid at StartEvent LBFGSB - StartEvent is not invoked */ class Optimization_observer : public itk::Command { public: typedef Optimization_observer Self; typedef itk::Command Superclass; typedef itk::SmartPointer < Self > Pointer; itkNewMacro(Self); public: Itk_registration_private *irp; double m_prev_value; int m_feval; Plm_timer* timer; protected: Optimization_observer() { m_prev_value = -DBL_MAX; m_feval = 0; timer = new Plm_timer; timer->start (); }; ~Optimization_observer() { delete timer; } public: void set_irp (Itk_registration_private *irp) { this->irp = irp; } void Execute (itk::Object * caller, const itk::EventObject & event) { Execute((const itk::Object *) caller, event); } void Execute (const itk::Object * object, const itk::EventObject & event) { /* GCS FIX, split metric vector into separate items in Stage_similarity_data list */ Metric_parms metric_parms; const Shared_parms *shared = irp->stage->get_shared_parms(); std::map::const_iterator metric_it; for (metric_it = shared->metric.begin(); metric_it != shared->metric.end(); ++metric_it) { metric_parms = metric_it->second; break; } if (typeid(event) == typeid(itk::StartEvent)) { m_feval = 0; m_prev_value = -DBL_MAX; lprintf ("StartEvent: "); if (irp->stage->xform_type != STAGE_TRANSFORM_BSPLINE) { std::stringstream ss; ss << irp->optimizer_get_current_position (); lprintf ("%s", ss.str().c_str()); } lprintf ("\n"); timer->start (); } else if (typeid(event) == typeid(itk::InitializeEvent)) { lprintf ("InitializeEvent: \n"); timer->start (); } else if (typeid(event) == typeid(itk::EndEvent)) { lprintf ("EndEvent: "); if (irp->stage->xform_type != STAGE_TRANSFORM_BSPLINE) { std::stringstream ss; ss << irp->optimizer_get_current_position (); lprintf ("%s", ss.str().c_str()); } lprintf ("\n"); lprintf ("%s\n", irp->registration->GetOptimizer() ->GetStopConditionDescription().c_str()); } else if (typeid(event) == typeid(itk::FunctionAndGradientEvaluationIterationEvent)) { int it = irp->optimizer_get_current_iteration(); double val = irp->optimizer_get_value(); double duration = timer->report (); lprintf ("%s [%2d,%3d] %9.3f [%6.3f secs]\n", (metric_parms.metric_type == SIMILARITY_METRIC_MSE) ? "MSE" : "MI", it, m_feval, val, duration); timer->start (); m_feval++; } else if (typeid(event) == typeid(itk::IterationEvent) || typeid(event) == typeid(itk::FunctionEvaluationIterationEvent)) { int it = irp->optimizer_get_current_iteration(); double val = irp->optimizer_get_value(); double ss = irp->optimizer_get_step_length(); /* ITK amoeba generates spurious events */ if (irp->stage->optim_type == OPTIMIZATION_AMOEBA) { if (m_feval % 2 == 1) { m_feval ++; return; } } /* Print out score & optimizer stats */ if (irp->stage->optim_type == OPTIMIZATION_AMOEBA) { lprintf ("%s [%3d] %9.3f ", (metric_parms.metric_type == SIMILARITY_METRIC_MSE) ? "MSE" : "MI", m_feval / 2, val); } else { lprintf ("%s [%2d,%3d,%5.2f] %9.3f ", (metric_parms.metric_type == SIMILARITY_METRIC_MSE) ? "MSE" : "MI", it, m_feval, ss, val); } if (irp->stage->xform_type != STAGE_TRANSFORM_BSPLINE) { std::stringstream ss; ss << std::setprecision(3); ss << irp->optimizer_get_current_position (); lprintf ("%s", ss.str().c_str()); } if (m_prev_value != -DBL_MAX) { double diff = fabs(m_prev_value - val); lprintf (" %10.2f", val - m_prev_value); if (it >= irp->stage->min_its && diff < irp->stage->convergence_tol) { lprintf (" (tol)"); irp->optimizer_stop (); } } m_prev_value = val; if (val < irp->best_value) { irp->best_value = val; irp->set_best_xform (); lprintf (" *"); } lprintf ("\n"); m_feval ++; } else if (typeid(event) == typeid(itk::ProgressEvent)) { lprintf ("ProgressEvent: "); if (irp->stage->xform_type != STAGE_TRANSFORM_BSPLINE) { std::stringstream ss; ss << irp->optimizer_get_current_position (); lprintf ("%s", ss.str().c_str()); } lprintf ("\n"); } else { lprintf ("Unknown event type: %s\n", event.GetEventName()); } } }; void Itk_registration_private::set_observer () { typedef Optimization_observer OOType; OOType::Pointer observer = OOType::New(); observer->set_irp (this); registration->GetOptimizer()->AddObserver(itk::StartEvent(), observer); registration->GetOptimizer()->AddObserver(itk::InitializeEvent(), observer); registration->GetOptimizer()->AddObserver(itk::IterationEvent(), observer); registration->GetOptimizer()->AddObserver(itk::FunctionEvaluationIterationEvent(), observer); registration->GetOptimizer()->AddObserver(itk::ProgressEvent(), observer); registration->GetOptimizer()->AddObserver(itk::EndEvent(), observer); } itk_registration_private.h000066400000000000000000000032621321604176500336530ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_registration_private_h_ #define _itk_registration_private_h_ #include "plmregister_config.h" #include "itkExceptionObject.h" #include "itkImageRegistrationMethod.h" #include "itk_image_type.h" #include "stage_parms.h" class Registration_data; class Stage_parms; class Xform; typedef itk::ImageRegistrationMethod < FloatImageType, FloatImageType > RegistrationType; class Itk_registration_private { public: Itk_registration_private ( Registration_data* regd, Xform *xf_out, const Xform *xf_in, Stage_parms* stage ); ~Itk_registration_private (); public: Registration_data *regd; Xform *xf_out; const Xform *xf_in; Stage_parms *stage; RegistrationType::Pointer registration; double best_value; Xform *xf_best; public: double evaluate_initial_transform (); const itk::Array& optimizer_get_current_position (); int optimizer_get_current_iteration (); double optimizer_get_value (); double optimizer_get_step_length (); void optimizer_stop (); void optimizer_set_max_iterations (int its); unsigned int compute_num_samples (FloatImageType::Pointer& fixed_ss); void set_best_xform (); void set_fixed_image_region (); void set_roi_images (); void set_metric (FloatImageType::Pointer& fixed_ss); void set_observer (); void set_optimization (); void set_transform (); void set_xf_out (); void show_stats (); }; #endif itk_sym_log_demons.cxx000066400000000000000000000020761321604176500330020ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "itk_sym_log_demons.h" #include "stage_parms.h" itk_sym_log_domain_demons_filter::itk_sym_log_domain_demons_filter() { m_demons_filter = SymmetricLogDomainDemonsFilterType::New(); } itk_sym_log_domain_demons_filter::~itk_sym_log_domain_demons_filter() { } void itk_sym_log_domain_demons_filter::update_specific_parameters(const Stage_parms* stage) { SymmetricLogDomainDemonsFilterType* log_filter=dynamic_cast(m_demons_filter.GetPointer()); log_filter->SetNumberOfBCHApproximationTerms(stage->num_approx_terms_log_demons); log_filter->SetSmoothVelocityField(stage->demons_smooth_deformation_field); log_filter->SetUseGradientType(static_cast(stage->demons_gradient_type)); log_filter->SetMaximumUpdateStepLength(stage->demons_step_length); } itk_sym_log_demons.h000066400000000000000000000020261321604176500324220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_sym_log_demons_h_ #define _itk_sym_log_demons_h_ #include "itkSymmetricLogDomainDemonsRegistrationFilterWithMaskExtension.h" #include class itk_sym_log_domain_demons_filter: public itk_demons_registration_filter { typedef itk::SymmetricLogDomainDemonsRegistrationFilterWithMaskExtension< FloatImageType, FloatImageType, DeformationFieldType> SymmetricLogDomainDemonsFilterType; typedef SymmetricLogDomainDemonsFilterType::DemonsRegistrationFunctionType SymmetricLogDomainDemonsFunctionType; typedef SymmetricLogDomainDemonsFunctionType::GradientType GradientType; public: itk_sym_log_domain_demons_filter(); ~itk_sym_log_domain_demons_filter(); void update_specific_parameters (const Stage_parms* stage); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/itk_tps.cxx000066400000000000000000000133231321604176500306460ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "landmark_warp.h" #include "itk_image_save.h" #include "itk_pointset.h" #include "itk_tps.h" #include "itk_warp.h" #include "plm_image.h" #include "plm_image_header.h" #include "raw_pointset.h" #include "xform.h" #define BUFLEN 2048 template static void do_tps_core ( Landmark_warp *lw, /* Input and output */ DoublePointSetType::Pointer mov_lm, /* Input */ DoublePointSetType::Pointer fix_lm, /* Input */ T default_val /* Input */ ) { TpsTransformType::Pointer tps = TpsTransformType::New (); Xform xform_tps; printf ("Setting landmarks to TPS\n"); tps->SetSourceLandmarks (fix_lm); tps->SetTargetLandmarks (mov_lm); printf ("Computing matrix\n"); tps->ComputeWMatrix (); printf ("Setting xform\n"); xform_tps.set_itk_tps (tps); printf ("Converting to VF\n"); lw->m_vf = new Xform; xform_to_itk_vf (lw->m_vf, &xform_tps, &lw->m_pih); printf ("Warping...\n"); typename DeformationFieldType::Pointer vf = DeformationFieldType::New (); vf = lw->m_vf->get_itk_vf (); typename itk::Image::Pointer im_warped = itk_warp_image (lw->m_input_img->itk_float (), vf, 1, default_val); /* Set outputs */ lw->m_warped_img = new Plm_image; lw->m_warped_img->set_itk (im_warped); } template void do_tps ( TPS_parms* parms, typename itk::Image::Pointer img_fixed, typename itk::Image::Pointer img_moving, T default_val ) { typedef typename itk::Image ImgType; typedef typename TpsTransformType::PointSetType PointSetType; typedef typename PointSetType::Pointer PointSetPointer; typedef typename PointSetType::PointIdentifier PointIdType; Plm_image_header pih; DoublePoint3DType p1; DoublePoint3DType p2; char line[BUFLEN]; Xform xform_tmp, xform; FILE* reference; FILE* target; pih.set_from_itk_image (img_fixed); typename PointSetType::Pointer sourceLandMarks = PointSetType::New (); typename PointSetType::Pointer targetLandMarks = PointSetType::New (); typename PointSetType::PointsContainer::Pointer sourceLandMarkContainer = sourceLandMarks->GetPoints (); typename PointSetType::PointsContainer::Pointer targetLandMarkContainer = targetLandMarks->GetPoints (); PointIdType id = itk::NumericTraits< PointIdType >::Zero; PointIdType id2 = itk::NumericTraits< PointIdType >::Zero; reference = fopen (parms->reference, "r"); target = fopen (parms->target, "r"); if (!reference || !target) { fprintf (stderr, "An error occurred while opening the landmark files!"); exit (-1); } while (fgets (line, BUFLEN, reference)) { if (sscanf (line, "%lf %lf %lf", &p1[0], &p1[1], &p1[2]) == 3) { sourceLandMarkContainer->InsertElement (id++, p1); printf ("reference Landmark: %f %f %f\n", p1[0], p1[1], p1[2]); } else { printf ("Error! can't read the reference landmarks file"); exit (-1); } } id = itk::NumericTraits< PointIdType >::Zero; while (fgets (line, BUFLEN, target)) { if (sscanf (line, "%lf %lf %lf", &p2[0], &p2[1], &p2[2]) == 3) { targetLandMarkContainer->InsertElement (id2++, p2); printf ("target Landmark: %f %f %f \n", p2[0], p2[1], p2[2]); } else { printf ("Error! can't read the target landmarks file"); exit (-1); } } fclose (reference); fclose (target); TpsTransformType::Pointer tps = TpsTransformType::New (); tps->SetSourceLandmarks (sourceLandMarks); tps->SetTargetLandmarks (targetLandMarks); tps->ComputeWMatrix (); xform.set_itk_tps (tps); xform_to_itk_vf (&xform_tmp, &xform, &pih); typename DeformationFieldType::Pointer vf = DeformationFieldType::New (); vf = xform_tmp.get_itk_vf (); printf ("Warping...\n"); typename ImgType::Pointer im_warped = itk_warp_image (img_moving, vf, 1, default_val); printf ("Saving...\n"); itk_image_save (im_warped, parms->warped); itk_image_save (vf, parms->vf); } void itk_tps_warp ( Landmark_warp *lw ) { printf ("Hello world\n"); /* Convert image to itk float */ if (lw->m_input_img) { lw->m_input_img->itk_float (); } printf ("Gonna convert pointsets\n"); lw->m_fixed_landmarks.debug (); /* Convert pointsets to itk pointsets */ DoublePointSetType::Pointer mov_lm = itk_double_pointset_from_pointset (lw->m_moving_landmarks); DoublePointSetType::Pointer fix_lm = itk_double_pointset_from_pointset (lw->m_fixed_landmarks); printf ("Conversion complete.\n"); itk_pointset_debug (fix_lm); /* Run ITK TPS warper */ do_tps_core ( lw, mov_lm, fix_lm, (float) lw->default_val ); } /* Explicit instantiations */ /* RMK: Visual studio 2005 without service pack requires specifier on the explicit extantiations. The current hypothesis is that this is because the template is nested. */ template PLMREGISTER_API void do_tps(TPS_parms* parms, itk::Image::Pointer img_fixed, itk::Image::Pointer img_moving, unsigned char); template PLMREGISTER_API void do_tps(TPS_parms* parms, itk::Image::Pointer img_fixed, itk::Image::Pointer img_moving, float); template PLMREGISTER_API void do_tps(TPS_parms* parms, itk::Image::Pointer img_fixed, itk::Image::Pointer img_moving, short); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/itk_tps.h000066400000000000000000000016301321604176500302710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_tps_h_ #define _itk_tps_h_ #include "plmregister_config.h" #include #include #include #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkPoint.h" #include "itkPointSet.h" #include "itkThinPlateSplineKernelTransform.h" class Landmark_warp; class TPS_parms { public: char* reference; char* target; char* fixed; char* moving; char* warped; char* vf; }; template PLMREGISTER_API void do_tps (TPS_parms* parms,typename itk::Image::Pointer img_fixed, typename itk::Image::Pointer img_moving,T); PLMREGISTER_API void itk_tps_warp (Landmark_warp *lw); #endif joint_histogram.cxx000066400000000000000000000523351321604176500323200ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include "file_util.h" #include "joint_histogram.h" #include "logfile.h" #include "plm_math.h" #include "print_and_exit.h" #include "string_util.h" #include "volume.h" #include "xpm.h" Joint_histogram::Joint_histogram () { this->m_hist = 0; this->f_hist = 0; this->j_hist = 0; } Joint_histogram::Joint_histogram (Mi_hist_type type, plm_long fixed_bins, plm_long moving_bins) : moving (type, moving_bins), fixed (type, fixed_bins), joint (type, moving_bins * fixed_bins) { this->allocate (); } Joint_histogram::~Joint_histogram () { delete[] this->f_hist; delete[] this->m_hist; delete[] this->j_hist; } void Joint_histogram::allocate () { this->m_hist = new double [this->moving.bins](); this->f_hist = new double [this->fixed.bins](); this->j_hist = new double [this->joint.bins](); } void Joint_histogram::reset_histograms () { memset (this->f_hist, 0, this->fixed.bins * sizeof(double)); memset (this->m_hist, 0, this->moving.bins * sizeof(double)); memset (this->j_hist, 0, this->fixed.bins * this->moving.bins * sizeof(double)); } /* ----------------------------------------------------------------------- Initialization and teardown ----------------------------------------------------------------------- */ static inline double vopt_bin_error (int start, int end, double* s_lut, double* ssq_lut, double* cnt_lut) { double sq_diff; double diff; double delta; double v, n; sq_diff = ssq_lut[end] - ssq_lut[start]; diff = s_lut[end] - s_lut[start]; delta = (double)end - (double)start + 1.0; n = cnt_lut[end] - cnt_lut[start]; v = sq_diff - (diff*diff)/delta; /* Penalize solutions that have bins with less than one voxel */ if (n < 1.0) { return DBL_MAX; } return v; } static void bspline_initialize_mi_bigbin ( double* hist, Histogram* hparms, Volume* vol ) { int idx_bin; float* img = (float*) vol->img; if (!img) { logfile_printf ("ERROR: trying to pre-scan empty image!\n"); exit (-1); } /* build a quick histogram */ for (plm_long i=0; inpix; i++) { idx_bin = floor ((img[i] - hparms->offset) / hparms->delta); if (hparms->type == HIST_VOPT) { idx_bin = hparms->key_lut[idx_bin]; } hist[idx_bin]++; } /* look for biggest bin */ for (plm_long i=0; ibins; i++) { if (hist[i] > hist[hparms->big_bin]) { hparms->big_bin = i; } } // printf ("big_bin: %i\n", hparms->big_bin); } static void bspline_initialize_mi_hist_eqsp (Histogram* hparms, Volume* vol) { plm_long i; float min_vox, max_vox; float* img = (float*) vol->img; if (!img) { logfile_printf ("Error trying to create histogram from empty image\n"); exit (-1); } min_vox = max_vox = img[0]; for (i = 0; i < vol->npix; i++) { if (img[i] < min_vox) { min_vox = img[i]; } else if (img[i] > max_vox) { max_vox = img[i]; } } /* To avoid rounding issues, top and bottom bin are only half full */ hparms->delta = (max_vox - min_vox) / (hparms->bins - 1); hparms->offset = min_vox - 0.5 * hparms->delta; } #if defined (commentout) static void bspline_mi_hist_vopt_dump_ranges ( Bspline_mi_hist* hparms, Volume* vol, const std::string& prefix ) { FILE* fp; std::string fn; char buff[1024]; plm_long i, j; fn = prefix + "_vopt_ranges.txt"; fp = fopen (fn.c_str(), "wb"); if (!fp) return; printf ("Writing %s vopt debug files to disk...\n", prefix.c_str()); int old_bin = hparms->key_lut[0]; float left = hparms->offset; float right = left; j = 0; for (i=0; ikeys; i++) { if (hparms->key_lut[i] == old_bin) { right += hparms->delta; } else { fprintf (fp, "Bin %u [%6.2f .. %6.2f]\n", (unsigned int) j, left, right); sprintf (buff, "%s_vopt_lvl_%03u.mha", prefix.c_str(), (unsigned int) j); dump_vol_clipped (buff, vol, left, right); old_bin = hparms->key_lut[i]; left = right; right += hparms->delta; j++; } } /* Pick up the last bin */ fprintf (fp, "Bin %u [%6.2f .. %6.2f]\n", (unsigned int) j, left, right); sprintf (buff, "%s_vopt_lvl_%03u.mha", prefix.c_str(), (unsigned int) j); dump_vol_clipped (buff, vol, left, right); fclose (fp); } #endif /* JAS - 2011.08.08 * Experimental implementation of V-Optimal Histograms * ref: * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.92.3195&rep=rep1&type=pdf */ static void bspline_initialize_mi_hist_vopt (Histogram* hparms, Volume* vol) { int idx_bin; plm_long curr, next, bottom; float min_vox, max_vox; int* tracker; double* tmp_hist; double* tmp_avg; double* s_lut; double* ssq_lut; double* err_lut; double* cnt_lut; double candidate; float* img = (float*) vol->img; if (!img) { logfile_printf ("Error trying to create histogram from empty image\n"); exit (-1); } hparms->keys = VOPT_RES; tmp_hist = (double*) malloc (hparms->keys * sizeof (double)); tmp_avg = (double*) malloc (hparms->keys * sizeof (double)); memset (tmp_hist, 0, hparms->keys * sizeof (double)); memset (tmp_avg, 0, hparms->keys * sizeof (double)); s_lut = (double*) malloc (hparms->keys * sizeof (double)); ssq_lut = (double*) malloc (hparms->keys * sizeof (double)); err_lut = (double*) malloc (hparms->bins * hparms->keys * sizeof (double)); cnt_lut = (double*) malloc (hparms->keys* sizeof (double)); memset (err_lut, 0, hparms->bins * hparms->keys * sizeof (double)); tracker = (int*) malloc (hparms->bins * hparms->keys * sizeof (int)); memset (tracker, 0, hparms->bins * hparms->keys * sizeof (int)); /* Determine input image value range */ min_vox = max_vox = img[0]; for (plm_long i=1; i < vol->npix; i++) { if (img[i] < min_vox) { min_vox = img[i]; } else if (img[i] > max_vox) { max_vox = img[i]; } } /* To avoid rounding issues, top and bottom bin are only half full */ hparms->delta = (max_vox - min_vox) / (hparms->keys - 1); hparms->offset = min_vox - 0.5 * hparms->delta; /* Construct high resolution histogram w/ bin contribution averages*/ for (plm_long i=0; inpix; i++) { idx_bin = floor ((img[i] - hparms->offset) / hparms->delta); tmp_hist[idx_bin]++; tmp_avg[idx_bin] += img[i] - hparms->offset; } /* Sorted estimation table */ for (plm_long i=0; ikeys; i++) { if (tmp_hist[i] > 0) { tmp_avg[i] = tmp_avg[i] / tmp_hist[i]; } else if (i > 0) { tmp_avg[i] = tmp_avg[i-1]; } } /* Create lookup tables for error computations */ s_lut[0] = tmp_avg[0]; ssq_lut[0] = (tmp_avg[0] * tmp_avg[0]); cnt_lut[0] = tmp_hist[0]; for (plm_long i=1; ikeys; i++) { s_lut[i] = s_lut[i-1] + tmp_avg[i]; ssq_lut[i] = ssq_lut[i-1] + (tmp_avg[i] * tmp_avg[i]); cnt_lut[i] = cnt_lut[i-1] + tmp_hist[i]; // printf ("[%i] %f\n", i, tmp_avg[i]); } free (tmp_avg); free (tmp_hist); /* Compute the one-bin scores */ for (plm_long i=0; ikeys; i++) { err_lut[i] = vopt_bin_error (0, i, s_lut, ssq_lut, cnt_lut); } /* Compute best multi-bin scores */ for (plm_long j=1; jbins; j++) { for (plm_long i=0; ikeys; i++) { err_lut[hparms->keys*j+i] = DBL_MAX; tracker[hparms->keys*j+i] = 0; for (plm_long k=0; kkeys*(j-1)+k] + vopt_bin_error (k+1, i, s_lut, ssq_lut, cnt_lut); if (candidate <= err_lut[hparms->keys*j+i]) { err_lut[hparms->keys*j+i] = candidate; tracker[hparms->keys*j+i] = k; } } } } free (s_lut); free (ssq_lut); free (err_lut); free (cnt_lut); /* Build the linear key table */ hparms->key_lut = (int*) malloc (hparms->keys * sizeof (int)); memset (hparms->key_lut, 0, hparms->keys * sizeof (int)); curr = hparms->keys-1; for (plm_long j=hparms->bins-1; j>=0; j--) { next = tracker[hparms->keys*j+curr]; bottom = next+1; if (j == 0) { bottom = 0; } // printf ("[%i] from %i to %i\tErr: %6.2e\n", // j, bottom, curr, err_lut[hparms->keys*j+curr]); for (plm_long i=bottom; i<=curr; i++) { hparms->key_lut[i] = j; } curr = next; } free (tracker); } static void bspline_initialize_mi_hist (Histogram* hparms, Volume* vol) { /* If user wants more than VOPT can offer, fallback to EQSP */ if ((hparms->bins > VOPT_RES) && (hparms->type == HIST_VOPT)) { printf ("WARNING: Falling back to EQSP histograms.\n" " (Reason: # bins > %i)\n", VOPT_RES); hparms->type = HIST_EQSP; } /* Histogram type specific init procedures */ if (hparms->type == HIST_EQSP) { bspline_initialize_mi_hist_eqsp (hparms, vol); } else if (hparms->type == HIST_VOPT) { bspline_initialize_mi_hist_vopt (hparms, vol); } else { print_and_exit ("Error: Encountered invalid histogram type. " "Terminating...\n"); } } void Joint_histogram::initialize (Volume *fixed, Volume *moving) { bspline_initialize_mi_hist (&this->fixed, fixed); bspline_initialize_mi_hist (&this->moving, moving); #if defined (commentout) if (parms->debug) { bspline_mi_hist_vopt_dump_ranges (&mi_hist->fixed, fixed, "fixed"); bspline_mi_hist_vopt_dump_ranges (&mi_hist->moving, moving, "moving"); } #endif /* Initialize biggest bin trackers for OpenMP MI */ bspline_initialize_mi_bigbin (this->f_hist, &this->fixed, fixed); bspline_initialize_mi_bigbin (this->m_hist, &this->moving, moving); /* This estimate /could/ be wrong for certain image sets */ /* Will be auto corrected after first evaluation if incorrect */ this->joint.big_bin = this->fixed.big_bin * this->moving.bins + this->moving.big_bin; } void Joint_histogram::dump_hist (int it, const std::string& prefix) { double* f_hist = this->f_hist; double* m_hist = this->m_hist; double* j_hist = this->j_hist; plm_long i, j, v; FILE *fp; std::string fn; std::string buf; buf = string_format ("hist_fix_%02d.csv", it); //sprintf (buf, "hist_fix_%02d.csv", it); fn = prefix + buf; make_parent_directories (fn.c_str()); fp = fopen (fn.c_str(), "wb"); if (!fp) return; for (plm_long i = 0; i < this->fixed.bins; i++) { fprintf (fp, "%u %f\n", (unsigned int) i, f_hist[i]); } fclose (fp); //sprintf (buf, "hist_mov_%02d.csv", it); buf = string_format ("hist_mov_%02d.csv", it); fn = prefix + buf; make_parent_directories (fn.c_str()); fp = fopen (fn.c_str(), "wb"); if (!fp) return; for (i = 0; i < this->moving.bins; i++) { fprintf (fp, "%u %f\n", (unsigned int) i, m_hist[i]); } fclose (fp); //sprintf (buf, "hist_jnt_%02d.csv", it); buf = string_format ("hist_jnt_%02d.csv", it); fn = prefix + buf; make_parent_directories (fn.c_str()); fp = fopen (fn.c_str(), "wb"); if (!fp) return; for (i = 0, v = 0; i < this->fixed.bins; i++) { for (j = 0; j < this->moving.bins; j++, v++) { if (j_hist[v] > 0) { fprintf (fp, "%u %u %u %g\n", (unsigned int) i, (unsigned int) j, (unsigned int) v, j_hist[v]); } } } fclose (fp); } void Joint_histogram::add_pvi_8 ( const Volume *fixed, const Volume *moving, int fidx, int mvf, float li_1[3], /* Fraction of interpolant in lower index */ float li_2[3]) /* Fraction of interpolant in upper index */ { float w[8]; int n[8]; int idx_fbin, idx_mbin, idx_jbin, idx_pv; int offset_fbin; float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; double *f_hist = this->f_hist; double *m_hist = this->m_hist; double *j_hist = this->j_hist; /* Compute partial volumes from trilinear interpolation weights */ w[0] = li_1[0] * li_1[1] * li_1[2]; // Partial Volume w0 w[1] = li_2[0] * li_1[1] * li_1[2]; // Partial Volume w1 w[2] = li_1[0] * li_2[1] * li_1[2]; // Partial Volume w2 w[3] = li_2[0] * li_2[1] * li_1[2]; // Partial Volume w3 w[4] = li_1[0] * li_1[1] * li_2[2]; // Partial Volume w4 w[5] = li_2[0] * li_1[1] * li_2[2]; // Partial Volume w5 w[6] = li_1[0] * li_2[1] * li_2[2]; // Partial Volume w6 w[7] = li_2[0] * li_2[1] * li_2[2]; // Partial Volume w7 /* Note that Sum(wN) for N within [0,7] should = 1 */ // Calculate Point Indices for 8 neighborhood n[0] = mvf; n[1] = n[0] + 1; n[2] = n[0] + moving->dim[0]; n[3] = n[2] + 1; n[4] = n[0] + moving->dim[0]*moving->dim[1]; n[5] = n[4] + 1; n[6] = n[4] + moving->dim[0]; n[7] = n[6] + 1; // Calculate fixed histogram bin and increment it idx_fbin = floor ((f_img[fidx] - this->fixed.offset) / this->fixed.delta); if (this->fixed.type == HIST_VOPT) { idx_fbin = this->fixed.key_lut[idx_fbin]; } f_hist[idx_fbin]++; offset_fbin = idx_fbin * this->moving.bins; // Add PV weights to moving & joint histograms for (idx_pv=0; idx_pv<8; idx_pv++) { idx_mbin = floor ((m_img[n[idx_pv]] - this->moving.offset) / this->moving.delta); if (this->moving.type == HIST_VOPT) { idx_mbin = this->moving.key_lut[idx_mbin]; } idx_jbin = offset_fbin + idx_mbin; m_hist[idx_mbin] += w[idx_pv]; j_hist[idx_jbin] += w[idx_pv]; } } /* This algorithm uses a un-normalized score. */ float Joint_histogram::compute_score (int num_vox) { double* f_hist = this->f_hist; double* m_hist = this->m_hist; double* j_hist = this->j_hist; plm_long i, j; plm_long v; double fnv = (double) num_vox; double score = 0; double hist_thresh = 0.001 / (this->moving.bins * this->fixed.bins); /* Compute cost */ for (i = 0, v = 0; i < this->fixed.bins; i++) { for (j = 0; j < this->moving.bins; j++, v++) { if (j_hist[v] > hist_thresh) { score -= j_hist[v] * logf (fnv * j_hist[v] / (m_hist[j] * f_hist[i])); } } } score = score / fnv; return (float) score; } void dump_xpm_hist (Joint_histogram* mi_hist, char* file_base, int iter) { int z; char c; // Graph Properties int graph_offset_x = 10; int graph_offset_y = 10; int graph_padding = 20; int graph_bar_height = 100; int graph_bar_width = 5; int graph_bar_spacing = (int)((float)graph_bar_width * (7.0/5.0)); plm_long graph_color_levels = 22; // int fixed_bar_height; // max bar height (pixels) // int moving_bar_height; plm_long joint_color; float fixed_scale; // pixels per amt float moving_scale; float joint_scale; float moving_max_val=0; float fixed_max_val=0; float joint_max_val=0; int fixed_total_width = mi_hist->fixed.bins * graph_bar_spacing; int moving_total_width = mi_hist->moving.bins * graph_bar_spacing; int graph_moving_x_pos = graph_offset_x + graph_bar_height + graph_padding; int graph_moving_y_pos = graph_offset_y + fixed_total_width + graph_padding + graph_bar_height; int graph_fixed_x_pos = graph_offset_x; int graph_fixed_y_pos = graph_offset_y + fixed_total_width; int border_padding = 5; int border_width = moving_total_width + 2*border_padding; int border_height = fixed_total_width + 2*border_padding; int border_x_pos = graph_moving_x_pos - border_padding; int border_y_pos = graph_offset_y - border_padding + (int)((float)graph_bar_width * (2.0/5.0)); int canvas_width = 2*graph_offset_x + graph_bar_height + moving_total_width + graph_padding; int canvas_height = 2*graph_offset_y + graph_bar_height + fixed_total_width + graph_padding; double *m_hist = mi_hist->m_hist; double *f_hist = mi_hist->f_hist; double *j_hist = mi_hist->j_hist; char filename[20]; sprintf(filename, "%s_%04i.xpm", file_base, iter); // ---------------------------------------------- // Find max value for fixed for(plm_long i=0; ifixed.bins; i++) if (f_hist[i] > fixed_max_val) fixed_max_val = f_hist[i]; // Find max value for moving for(plm_long i=0; imoving.bins; i++) if (m_hist[i] > moving_max_val) moving_max_val = m_hist[i]; // Find max value for joint // (Ignoring bin 0) for(plm_long j=0; jfixed.bins; j++) { for(plm_long i=0; imoving.bins; i++) { if ( (i > 0) && (j > 1) ) if (j_hist[j*mi_hist->moving.bins + i] > joint_max_val) joint_max_val = j_hist[j*mi_hist->moving.bins + i]; } } // Generate scaling factors fixed_scale = (float)graph_bar_height / fixed_max_val; moving_scale = (float)graph_bar_height / moving_max_val; joint_scale = (float)graph_color_levels / joint_max_val; // ---------------------------------------------- // ---------------------------------------------- // Pull out a canvas and brush! Xpm_canvas* xpm = new Xpm_canvas (canvas_width, canvas_height, 1); Xpm_brush* brush = new Xpm_brush; // setup the palette xpm->add_color ('a', 0xFFFFFF); // white xpm->add_color ('b', 0x000000); // black xpm->add_color ('z', 0xFFCC00); // orange // generate a nice BLUE->RED gradient c = 'c'; z = 0x0000FF; for (plm_long i=0; i<(graph_color_levels+1); i++) { xpm->add_color (c, z); z -= 0x00000B; // BLUE-- z += 0x0B0000; // RED++ c = (char)((int)c + 1); // LETTER++ } // Prime the XPM Canvas xpm->prime ('a'); // ---------------------------------------------- printf("Drawing Histograms... "); /* Generate Moving Histogram */ brush->set_type (XPM_BOX); brush->set_color ('b'); brush->set_pos (graph_moving_x_pos, graph_moving_y_pos); brush->set_width (graph_bar_width); brush->set_height (0); int tmp_h; for(plm_long i=0; imoving.bins; i++) { tmp_h = (int)(m_hist[i] * moving_scale); brush->set_height (tmp_h); brush->set_y (graph_moving_y_pos - tmp_h); xpm->draw (brush); brush->inc_x (graph_bar_spacing); } /* Generate Fixed Histogram */ brush->set_type (XPM_BOX); brush->set_color ('b'); brush->set_pos (graph_fixed_x_pos, graph_fixed_y_pos); brush->set_width (0); brush->set_height (graph_bar_width); for (plm_long i=0; ifixed.bins; i++) { brush->set_width ((int)(f_hist[i] * fixed_scale)); xpm->draw (brush); brush->inc_x ((-1)*graph_bar_spacing); } /* Generate Joint Histogram */ brush->set_type (XPM_BOX); brush->set_color ('b'); brush->set_pos (graph_moving_x_pos, graph_fixed_y_pos); brush->set_width (graph_bar_width); brush->set_height (graph_bar_width); z = 0; for(plm_long j=0; jfixed.bins; j++) { for(plm_long i=0; imoving.bins; i++) { joint_color = (size_t)(j_hist[z++] * joint_scale); if (joint_color > 0) { // special handling for bin 0 if (joint_color > graph_color_levels) { // printf ("Clamp @ P(%i,%i)\n", i, j); // brush.color = (char)(graph_color_levels + 99); brush->set_color ('z'); } else { brush->set_color ((char)(joint_color + 99)); } } else { brush->set_color ('a'); } xpm->draw (brush); brush->inc_x (graph_bar_spacing); } // get ready to render new row brush->set_x (graph_moving_x_pos); brush->inc_y ((-1)*graph_bar_spacing); } /* Generate Joint Histogram Border */ brush->set_type (XPM_BOX); // top brush->set_color ('b'); brush->set_pos (border_x_pos, border_y_pos); brush->set_width (border_width); brush->set_height (1); xpm->draw (brush); brush->set_width (1); // left brush->set_height (border_height); xpm->draw (brush); brush->set_width (border_width); // bottom brush->set_height (1); brush->inc_y (border_height); xpm->draw (brush); brush->set_width (1); // right brush->set_height (border_height); brush->set_pos (border_width, border_y_pos); xpm->draw (brush); printf("done.\n"); // Write to file xpm->write (filename); delete xpm; delete brush; } joint_histogram.h000066400000000000000000000024321321604176500317360ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _joint_histogram_h_ #define _joint_histogram_h_ #include "plmregister_config.h" #include #include "histogram.h" #include "plm_int.h" class Volume; class PLMREGISTER_API Joint_histogram { public: Joint_histogram (); Joint_histogram ( Mi_hist_type type, plm_long fixed_bins, plm_long moving_bins); ~Joint_histogram (); public: void initialize (Volume *fixed, Volume *moving); void reset_histograms (); void dump_hist (int it, const std::string& prefix); void add_pvi_8 ( const Volume *fixed, const Volume *moving, int fidx, int mvf, float li_1[3], /* Fraction of interpolant in lower index */ float li_2[3]); /* Fraction of interpolant in upper index */ float compute_score (int num_vox); public: Histogram moving; Histogram fixed; Histogram joint; double* m_hist; double* f_hist; double* j_hist; protected: void allocate (); }; void dump_xpm_hist (Joint_histogram* mi_hist, char* file_base, int iter); #endif landmark_warp.cxx000066400000000000000000000342621321604176500317410ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include "landmark_warp.h" #include "raw_pointset.h" Landmark_warp::Landmark_warp (void) { default_val = 0; rbf_radius = 0; young_modulus = 0; num_clusters = 0; cluster_id = 0; adapt_radius = 0; m_warped_img = 0; m_vf = 0; } Landmark_warp::~Landmark_warp (void) { if (cluster_id) free(cluster_id); if (adapt_radius) free(adapt_radius); } Landmark_warp* landmark_warp_create (void) { return new Landmark_warp; } void landmark_warp_destroy (Landmark_warp *lw) { delete lw; } /* GCS FIX: Oops. This doesn't work because tps_xform is c++ code. If needed, we need to separate out Tps_xform as a separate c file. */ Landmark_warp* landmark_warp_load_xform (const char *fn) { #if defined (commentout) Landmark_warp *lw; Tps_xform *tps; int i; tps = tps_xform_load (options->input_xform_fn); if (!tps) return 0; if (tps->num_tps_nodes <= 0) { tps_xform_destroy (tps); return 0; } lw = landmark_warp_create (); lw->fixed = pointset_create (); pointset_resize (lw->fixed, tps->num_tps_nodes); lw->moving = pointset_create (); pointset_resize (lw->moving, tps->num_tps_nodes); for (i = 0; i < tps->num_tps_nodes; i++) { lw->fixed[i*3 + 0] = tps->src[0]; lw->fixed[i*3 + 1] = tps->src[1]; lw->fixed[i*3 + 2] = tps->src[2]; lw->moving[i*3 + 0] = tps->tgt[0]; lw->moving[i*3 + 1] = tps->tgt[1]; lw->moving[i*3 + 2] = tps->tgt[2]; } /* Discard alpha values and image header. */ #endif return 0; } void Landmark_warp::load_pointsets ( const char *fixed_lm_fn, const char *moving_lm_fn ) { m_fixed_landmarks.load (fixed_lm_fn); m_moving_landmarks.load (moving_lm_fn); } Landmark_warp* landmark_warp_load_pointsets (const char *fixed_lm_fn, const char *moving_lm_fn) { Landmark_warp *lw; lw = landmark_warp_create (); lw->load_pointsets (fixed_lm_fn, moving_lm_fn); if (lw->m_fixed_landmarks.get_count() == 0 || lw->m_moving_landmarks.get_count() == 0) { landmark_warp_destroy (lw); return 0; } return lw; } /* NSh 2013-02-13 - moved the code below from cli/landmark_warp_main.cxx */ /* calculate voxel positions of landmarks given origin and pix_spacing output: landvox input: landmarks_mm and origin/spacing/dim NOTE: ROTATION IS NOT SUPPORTED! direction_cosines assumed to be 100 010 001. */ static void landmark_convert_mm_to_voxel ( int *landvox, const Labeled_pointset& landmarks_mm, float *origin, float *pix_spacing, plm_long *dim, const float *direction_cosines) { for (size_t i = 0; i < landmarks_mm.get_count(); i++) { for (int d = 0; d < 3; d++) { landvox[i*3 + d] = ROUND_INT ( ( landmarks_mm.point(i,d) - origin[d]) / pix_spacing[d]); if (landvox[i*3 + d] < 0 || landvox[i*3 + d] >= dim[d]) { print_and_exit ( "Error, landmark %d outside of image for dim %d.\n" "Location in vox = %d\n" "Image boundary in vox = (%d %d)\n", i, d, landvox[i*3 + d], 0, dim[d]-1); } } } } /*Moves moving landmarks according to the current vector field. Output goes into lw->m_warped_landmarks LW = warped landmark We must solve LW + u(LW) = LM to get new LW, corresponding to current vector field. Adapted from bspline_landmarks_warp(...) in bspline_landmarks.c to use Landmark_warp */ void calculate_warped_landmarks (Landmark_warp *lw) { plm_long ri, rj, rk; plm_long fi, fj, fk, fv; plm_long mi, mj, mk; float fx, fy, fz; float mx, my, mz; int i, d, lidx; float dd, *vf, dxyz[3], *dd_min; int num_landmarks; int *landvox_mov, *landvox_fix, *landvox_warp; float *warped_landmarks; float *landmark_dxyz; Volume *vector_field; Volume::Pointer moving; plm_long fixed_dim[3]; float fixed_spacing[3], fixed_origin[3], fixed_direction_cosines[9]; num_landmarks = lw->m_fixed_landmarks.get_count(); landvox_mov = (int *)malloc( 3*num_landmarks * sizeof(int)); landvox_fix = (int *)malloc( 3*num_landmarks * sizeof(int)); landvox_warp = (int *)malloc( 3*num_landmarks * sizeof(int)); landmark_dxyz = (float *)malloc( 3*num_landmarks * sizeof(float)); warped_landmarks = (float *)malloc( 3*num_landmarks * sizeof(float)); if (lw->m_vf->get_type() != XFORM_GPUIT_VECTOR_FIELD) { Plm_image_header pih = lw->m_vf->get_plm_image_header(); xform_to_gpuit_vf (lw->m_vf, lw->m_vf, &pih); } vector_field = lw->m_vf->get_gpuit_vf().get(); moving = lw->m_input_img->get_volume_float (); // fixed dimensions set come from lw->m_pih // lw->m_pih.get_dim (fixed_dim); lw->m_pih.get_spacing (fixed_spacing); lw->m_pih.get_origin (fixed_origin); lw->m_pih.get_direction_cosines (fixed_direction_cosines); if (vector_field->pix_type != PT_VF_FLOAT_INTERLEAVED) print_and_exit ("Sorry, this type of vector field is not supported in landmarks_warp\n"); vf = (float *)vector_field->img; // fill in landvox'es // landmark_convert_mm_to_voxel (landvox_fix, lw->m_fixed_landmarks, fixed_origin, fixed_spacing, fixed_dim, fixed_direction_cosines); landmark_convert_mm_to_voxel (landvox_mov, lw->m_moving_landmarks, moving->origin, moving->spacing, moving->dim, moving->direction_cosines); dd_min = (float *)malloc( num_landmarks * sizeof(float)); for (d=0;ddim[0] * vector_field->dim[1] + fj * vector_field->dim[0] +fi ; for (d=0;d<3;d++) dxyz[d] = vf[3*fv+d]; // Find correspondence in moving image // mx = fx + dxyz[0]; mi = ROUND_INT ((mx - moving->origin[0]) / moving->spacing[0]); if (mi < 0 || mi >= moving->dim[0]) continue; my = fy + dxyz[1]; mj = ROUND_INT ((my - moving->origin[1]) / moving->spacing[1]); if (mj < 0 || mj >= moving->dim[1]) continue; mz = fz + dxyz[2]; mk = ROUND_INT ((mz - moving->origin[2]) / moving->spacing[2]); if (mk < 0 || mk >= moving->dim[2]) continue; //saving vector field in a voxel which is the closest to landvox_mov //after being displaced by the vector field for (lidx = 0; lidx < num_landmarks; lidx++) { dd = (mi - landvox_mov[lidx*3+0]) * (mi - landvox_mov[lidx*3+0]) +(mj - landvox_mov[lidx*3+1]) * (mj - landvox_mov[lidx*3+1]) +(mk - landvox_mov[lidx*3+2]) * (mk - landvox_mov[lidx*3+2]); if (dd < dd_min[lidx]) { dd_min[lidx]=dd; for (d=0;d<3;d++) { landmark_dxyz[3*lidx+d] = vf[3*fv+d]; } } } } } } for (i = 0; i < num_landmarks; i++) { for (d=0; d<3; d++) { warped_landmarks[3*i+d] = lw->m_moving_landmarks.point(i,d) - landmark_dxyz[3*i+d]; } } // calculate voxel positions of warped landmarks // for (lidx = 0; lidx < num_landmarks; lidx++) { for (d = 0; d < 3; d++) { landvox_warp[lidx*3 + d] = ROUND_INT ((warped_landmarks[lidx*3 + d] - fixed_origin[d]) / fixed_spacing[d]); if (landvox_warp[lidx*3 + d] < 0 || landvox_warp[lidx*3 + d] >= fixed_dim[d]) { print_and_exit ( "Error, warped landmark %d outside of fixed image for dim %d.\n" "Location in vox = %d\n" "Image boundary in vox = (%d %d)\n", lidx, d, landvox_warp[lidx*3 + d], 0, fixed_dim[d]-1); } } lw->m_warped_landmarks.insert_lps (&warped_landmarks[3*lidx]); } //debug only fy = 0; for (lidx = 0; lidx < num_landmarks; lidx++) { fx=0; for (d = 0; d < 3; d++) { fz = lw->m_fixed_landmarks.point(lidx,d) - lw->m_warped_landmarks.point(lidx,d); fx += fz*fz; } printf("landmark %3d err %f mm\n", lidx, sqrt(fx)); fy+=fx; } printf("landmark RMS err %f mm\n", sqrt(fy/num_landmarks)); // end debug only free (dd_min); free (landvox_mov); free (landvox_warp); free (landvox_fix); free (landmark_dxyz); free (warped_landmarks); } void calculate_warped_landmarks_by_vf (Landmark_warp *lw , Volume *vector_field) // same as calculate_warped_landmarks, but accepts vector_field directly, // not through Xform lw->m_vf /*Moves moving landmarks according to the current vector field. Output goes into lw->m_warped_landmarks LW = warped landmark We must solve LW + u(LW) = LM to get new LW, corresponding to current vector field. Adapted from bspline_landmarks_warp(...) in bspline_landmarks.c to use Landmark_warp */ { plm_long ri, rj, rk; plm_long fi, fj, fk, fv; plm_long mi, mj, mk; float fx, fy, fz; float mx, my, mz; int i, d, lidx; float dd, *vf, dxyz[3], *dd_min; int num_landmarks; int *landvox_mov, *landvox_fix, *landvox_warp; float *warped_landmarks; float *landmark_dxyz; Volume::Pointer moving; plm_long fixed_dim[3]; float fixed_spacing[3], fixed_origin[3], fixed_direction_cosines[9]; num_landmarks = lw->m_fixed_landmarks.get_count(); landvox_mov = (int *)malloc( 3*num_landmarks * sizeof(int)); landvox_fix = (int *)malloc( 3*num_landmarks * sizeof(int)); landvox_warp = (int *)malloc( 3*num_landmarks * sizeof(int)); landmark_dxyz = (float *)malloc( 3*num_landmarks * sizeof(float)); warped_landmarks = (float *)malloc( 3*num_landmarks * sizeof(float)); moving = lw->m_input_img->get_volume_float (); // fixed dimensions set come from lw->m_pih // lw->m_pih.get_dim (fixed_dim); lw->m_pih.get_spacing (fixed_spacing); lw->m_pih.get_origin (fixed_origin); lw->m_pih.get_direction_cosines (fixed_direction_cosines); if (vector_field->pix_type != PT_VF_FLOAT_INTERLEAVED) print_and_exit ("Sorry, this type of vector field is not supported in landmarks_warp\n"); vf = (float *)vector_field->img; // fill in landvox'es // landmark_convert_mm_to_voxel (landvox_fix, lw->m_fixed_landmarks, fixed_origin, fixed_spacing, fixed_dim, fixed_direction_cosines); landmark_convert_mm_to_voxel (landvox_mov, lw->m_moving_landmarks, moving->origin, moving->spacing, moving->dim, moving->direction_cosines); printf("done landvox; n=%d\n", num_landmarks); printf("fix offs %f %f %f\n", fixed_origin[0],fixed_origin[1],fixed_origin[2]); printf("fix dim %d %d %d\n", (int) fixed_dim[0], (int) fixed_dim[1], (int) fixed_dim[2]); printf("mov offs %f %f %f\n", moving->origin[0], moving->origin[1], moving->origin[2]); printf("vf dim %d %d %d\n", (int) vector_field->dim[0], (int) vector_field->dim[1], (int) vector_field->dim[2]); for(i=0;idim[0] * vector_field->dim[1] + fj * vector_field->dim[0] +fi ; for (d=0;d<3;d++) dxyz[d] = vf[3*fv+d]; // Find correspondence in moving image // mx = fx + dxyz[0]; mi = ROUND_INT ((mx - moving->origin[0]) / moving->spacing[0]); if (mi < 0 || mi >= moving->dim[0]) continue; my = fy + dxyz[1]; mj = ROUND_INT ((my - moving->origin[1]) / moving->spacing[1]); if (mj < 0 || mj >= moving->dim[1]) continue; mz = fz + dxyz[2]; mk = ROUND_INT ((mz - moving->origin[2]) / moving->spacing[2]); if (mk < 0 || mk >= moving->dim[2]) continue; //saving vector field in a voxel which is the closest to landvox_mov //after being displaced by the vector field for (lidx = 0; lidx < num_landmarks; lidx++) { dd = (mi - landvox_mov[lidx*3+0]) * (mi - landvox_mov[lidx*3+0]) +(mj - landvox_mov[lidx*3+1]) * (mj - landvox_mov[lidx*3+1]) +(mk - landvox_mov[lidx*3+2]) * (mk - landvox_mov[lidx*3+2]); if (dd < dd_min[lidx]) { dd_min[lidx]=dd; for (d=0;d<3;d++) { landmark_dxyz[3*lidx+d] = vf[3*fv+d]; } } } } } } for (i = 0; i < num_landmarks; i++) { for (d=0; d<3; d++) { warped_landmarks[3*i+d] = lw->m_moving_landmarks.point(3,d) - landmark_dxyz[3*i+d]; } } // calculate voxel positions of warped landmarks // for (lidx = 0; lidx < num_landmarks; lidx++) { for (d = 0; d < 3; d++) { landvox_warp[lidx*3 + d] = ROUND_INT ((warped_landmarks[lidx*3 + d] - fixed_origin[d]) / fixed_spacing[d]); if (landvox_warp[lidx*3 + d] < 0 || landvox_warp[lidx*3 + d] >= fixed_dim[d]) { print_and_exit ( "Error, warped landmark %d outside of fixed image for dim %d.\n" "Location in vox = %d\n" "Image boundary in vox = (%d %d)\n", lidx, d, landvox_warp[lidx*3 + d], 0, fixed_dim[d]-1); } } lw->m_warped_landmarks.insert_lps (&warped_landmarks[3*lidx]); } printf("done warping, printing rms\n"); //debug only fy = 0; for (lidx = 0; lidx < num_landmarks; lidx++) { fx=0; for (d = 0; d < 3; d++) { fz = (lw->m_fixed_landmarks.point(lidx,d) - lw->m_warped_landmarks.point(lidx,d)); fx += fz*fz; } printf("landmark %3d err %f mm\n", lidx, sqrt(fx)); fy+=fx; } printf("landmark RMS err %f mm\n", sqrt(fy/num_landmarks)); // end debug only free (dd_min); free (landvox_mov); free (landvox_warp); free (landvox_fix); free (landmark_dxyz); free (warped_landmarks); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/landmark_warp.h000066400000000000000000000037111321604176500314400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _landmark_warp_h_ #define _landmark_warp_h_ #include "plmregister_config.h" #include "pointset.h" #include "plm_image.h" #include "plm_image_header.h" #include "print_and_exit.h" #include "volume.h" #include "xform.h" class Plm_image; class Xform; class PLMREGISTER_API Landmark_warp { public: /* Inputs */ #if defined (commentout) Raw_pointset *m_fixed_landmarks; Raw_pointset *m_moving_landmarks; #endif Labeled_pointset m_fixed_landmarks; Labeled_pointset m_moving_landmarks; Plm_image::Pointer m_input_img; Plm_image_header m_pih; /* Config */ float default_val; float rbf_radius; float young_modulus; int num_clusters; // if >0, use adaptive radius of RBF /* Internals */ int *cluster_id; // index of cluster the landmark belongs to float *adapt_radius; // adaptively found radius of RBF of each landmark /* Outputs */ Plm_image *m_warped_img; Xform *m_vf; //also, INPUT vf for calculate_warped_landmarks() // if regularized, warped landmarks may not exactly match fixed Labeled_pointset m_warped_landmarks; public: Landmark_warp (); ~Landmark_warp (); void load_pointsets ( const char *fixed_lm_fn, const char *moving_lm_fn ); }; PLMREGISTER_C_API Landmark_warp* landmark_warp_create (void); PLMREGISTER_C_API void landmark_warp_destroy (Landmark_warp *lw); PLMREGISTER_C_API Landmark_warp* landmark_warp_load_xform (const char *fn); PLMREGISTER_C_API Landmark_warp* landmark_warp_load_pointsets ( const char *fixed_lm_fn, const char *moving_lm_fn ); PLMREGISTER_C_API void calculate_warped_landmarks( Landmark_warp *lw ); PLMREGISTER_C_API void calculate_warped_landmarks_by_vf( Landmark_warp *lw, Volume *vf ); #endif metric_parms.cxx000066400000000000000000000030351321604176500315760ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include "logfile.h" #include "metric_parms.h" #include "string_util.h" Metric_parms::Metric_parms () { metric_type = SIMILARITY_METRIC_MSE; metric_lambda = 1.0; } Plm_return_code Metric_parms::set_metric_type (const std::string& val) { if (val == "dm" || val == "dmap") { this->metric_type = SIMILARITY_METRIC_DMAP; return PLM_SUCCESS; } else if (val == "gm") { this->metric_type = SIMILARITY_METRIC_GM; return PLM_SUCCESS; } else if (val == "mattes") { this->metric_type = SIMILARITY_METRIC_MI_MATTES; return PLM_SUCCESS; } else if (val == "mse" || val == "MSE") { this->metric_type = SIMILARITY_METRIC_MSE; return PLM_SUCCESS; } else if (val == "mi" || val == "MI") { #if PLM_CONFIG_LEGACY_MI_METRIC this->metric_type = SIMILARITY_METRIC_MI_VW; #else this->metric_type = SIMILARITY_METRIC_MI_MATTES; #endif return PLM_SUCCESS; } else if (val == "mi_vw" || val == "viola-wells") { this->metric_type = SIMILARITY_METRIC_MI_VW; return PLM_SUCCESS; } else if (val == "nmi" || val == "NMI") { this->metric_type = SIMILARITY_METRIC_NMI; return PLM_SUCCESS; } else { return PLM_ERROR; } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/metric_parms.h000066400000000000000000000013541321604176500313040ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _metric_parms_h_ #define _metric_parms_h_ #include "plmregister_config.h" #include #include #include "plm_return_code.h" #include "similarity_metric_type.h" class PLMREGISTER_API Metric_parms { public: Metric_parms (); public: Similarity_metric_type metric_type; float metric_lambda; std::string fixed_fn; std::string moving_fn; std::string fixed_roi_fn; std::string moving_roi_fn; public: Plm_return_code set_metric_type (const std::string& val); }; #endif metric_state.cxx000066400000000000000000000007751321604176500316040ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "joint_histogram.h" #include "metric_state.h" Metric_state::Metric_state () { metric_type = SIMILARITY_METRIC_MSE; metric_lambda = 1.f; mi_hist = 0; } Metric_state::~Metric_state () { delete mi_hist; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/metric_state.h000066400000000000000000000016611321604176500313030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _metric_state_h_ #define _metric_state_h_ #include "plmregister_config.h" #include "similarity_metric_type.h" #include "volume.h" class Joint_histogram; class PLMREGISTER_API Metric_state { public: SMART_POINTER_SUPPORT (Metric_state); public: Metric_state (); ~Metric_state (); public: Volume::Pointer fixed_ss; Volume::Pointer moving_ss; Volume::Pointer fixed_grad; Volume::Pointer moving_grad; Volume::Pointer fixed_roi; Volume::Pointer moving_roi; Similarity_metric_type metric_type; float metric_lambda; Joint_histogram *mi_hist; public: const char *metric_string () { return similarity_metric_type_string (metric_type); } }; #endif plmregister_config.h.in000066400000000000000000000021021321604176500330170ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plmregister_config_h__ #define __plmregister_config_h__ #include "plm_config.h" #if ((defined(_WIN32) || defined(WIN32)) && (defined (PLM_BUILD_SHARED_LIBS))) # ifdef plmregister_EXPORTS # define PLMREGISTER_C_API EXTERNC __declspec(dllexport) # define PLMREGISTER_API __declspec(dllexport) # else # define PLMREGISTER_C_API EXTERNC __declspec(dllimport) # define PLMREGISTER_API __declspec(dllimport) # endif # ifdef plmregistercuda_EXPORTS # define PLMREGISTERCUDA_C_API EXTERNC __declspec(dllexport) # define PLMREGISTERCUDA_API __declspec(dllexport) # else # define PLMREGISTERCUDA_C_API EXTERNC __declspec(dllimport) # define PLMREGISTERCUDA_API __declspec(dllimport) # endif #else # define PLMREGISTERCUDA_C_API EXTERNC # define PLMREGISTERCUDA_API # define PLMREGISTER_C_API EXTERNC # define PLMREGISTER_API #endif #endif process_parms.cxx000066400000000000000000000056551321604176500320030ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include "itk_adjust.h" #include "logfile.h" #include "shared_parms.h" #include "print_and_exit.h" #include "process_parms.h" #include "registration_data.h" typedef std::list > Key_value_list; class Process_parms_private { public: Shared_parms *shared; std::string action; Key_value_list key_value_list; public: Process_parms_private () { shared = new Shared_parms; } Process_parms_private (const Process_parms_private& s) { this->shared = new Shared_parms (*s.shared); } ~Process_parms_private () { delete shared; } }; Process_parms::Process_parms () { d_ptr = new Process_parms_private; } Process_parms::Process_parms (const Process_parms& s) { d_ptr = new Process_parms_private (*s.d_ptr); } Process_parms::~Process_parms () { delete d_ptr; } void Process_parms::set_action (const std::string& action) { d_ptr->action = action; } void Process_parms::set_key_value (const std::string& key, const std::string& value) { d_ptr->key_value_list.push_back ( make_pair (key, value)); } void Process_parms::execute_process (Registration_data::Pointer& regd) const { if (d_ptr->action == "adjust") { lprintf ("*** Executing adjust process ***\n"); bool adjust_fixed = false; bool adjust_moving = false; std::string parms = ""; for (Key_value_list::iterator it = d_ptr->key_value_list.begin(); it != d_ptr->key_value_list.end(); it++) { const std::string& key = it->first; const std::string& value = it->second; if (key == "parms") { parms = value; } else if (key == "images") { if (value == "fixed") { adjust_fixed = true; } else if (value == "moving") { adjust_moving = true; } else if (value == "fixed,moving") { adjust_fixed = true; adjust_moving = true; } else { print_and_exit ("Unknown adjustment line\n"); } } else { print_and_exit ("Unknown adjustment line\n"); } } if (adjust_fixed) { Plm_image::Pointer& fixed = regd->get_fixed_image(); fixed->set_itk (itk_adjust (fixed->itk_float(), parms)); } if (adjust_moving) { Plm_image::Pointer& moving = regd->get_moving_image(); moving->set_itk (itk_adjust (moving->itk_float(), parms)); } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/process_parms.h000066400000000000000000000016121321604176500314740ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _process_parms_h_ #define _process_parms_h_ #include "plmregister_config.h" #include #include #include #include #include "registration_data.h" #include "smart_pointer.h" class Process_parms_private; class PLMREGISTER_API Process_parms { public: SMART_POINTER_SUPPORT (Process_parms); Process_parms_private *d_ptr; public: Process_parms (); Process_parms (const Process_parms& s); ~Process_parms (); public: void set_action (const std::string& action); void set_key_value (const std::string& key, const std::string& value); void execute_process (Registration_data::Pointer& regd) const; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/rbf_cluster.cxx000066400000000000000000000170371321604176500315110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include "compiler_warnings.h" #include "landmark_warp.h" #include "plm_math.h" #include "raw_pointset.h" #include "rbf_cluster.h" //k-means++ clustering algorithm to separate landmarks into user-specified number of clusters void rbf_cluster_kmeans_plusplus(Landmark_warp *lw) { int num_landmarks = lw->m_fixed_landmarks.get_count(); int num_clusters = lw->num_clusters; float *mx, *my, *mz; float *D, *DD; int i; float r, d, dmin = FLT_MAX; int clust_id = 0; int kcurrent, count, reassigned, iter_count =0; mx = (float *)malloc(num_clusters*sizeof(float)); my = (float *)malloc(num_clusters*sizeof(float)); mz = (float *)malloc(num_clusters*sizeof(float)); D = (float *)malloc(num_landmarks*sizeof(float)); DD = (float *)malloc(num_landmarks*sizeof(float)); for(i=0;icluster_id[i]=-1; //kmeans++ initialization i = (int)((double)rand()/RAND_MAX*(num_landmarks-1.)); #if defined (commentout) mx[0]=lw->m_fixed_landmarks->points[i*3+0]; my[0]=lw->m_fixed_landmarks->points[i*3+1]; mz[0]=lw->m_fixed_landmarks->points[i*3+2]; #endif mx[0] = lw->m_fixed_landmarks.point(i,0); my[0] = lw->m_fixed_landmarks.point(i,1); mz[0] = lw->m_fixed_landmarks.point(i,2); kcurrent=1; do { for(i=0;im_fixed_landmarks.point(i,0)-mx[j]) * (lw->m_fixed_landmarks.point(i,0)-mx[j]) + (lw->m_fixed_landmarks.point(i,1)-my[j]) * (lw->m_fixed_landmarks.point(i,1)-my[j]) + (lw->m_fixed_landmarks.point(i,2)-mz[j]) * (lw->m_fixed_landmarks.point(i,2)-mz[j]); if (j==0) { dmin=d; } if (d<=dmin) { D[i]=dmin; } } } //DD is a normalized cumulative sum of D d=0; for(i=0;i0 && DD[i-1]m_fixed_landmarks.point(j,0); my[kcurrent] = lw->m_fixed_landmarks.point(j,1); mz[kcurrent] = lw->m_fixed_landmarks.point(j,2); kcurrent++; } while(kcurrent < num_clusters); //standard k-means algorithm do { reassigned = 0; // assign for(i=0;im_fixed_landmarks.point(i,0)-mx[j]) *(lw->m_fixed_landmarks.point(i,0)-mx[j]) + (lw->m_fixed_landmarks.point(i,1)-my[j]) *(lw->m_fixed_landmarks.point(i,1)-my[j]) + (lw->m_fixed_landmarks.point(i,2)-mz[j]) *(lw->m_fixed_landmarks.point(i,2)-mz[j]); if (j==0) { dmin=d; clust_id = 0; } if (d<=dmin) { dmin =d; clust_id = j; } } if ( lw->cluster_id[i] != clust_id) reassigned = 1; lw->cluster_id[i] = clust_id; } // calculate new means for(int j=0;jcluster_id[i]==j) { mx[j]+=lw->m_fixed_landmarks.point(i,0); my[j]+=lw->m_fixed_landmarks.point(i,1); mz[j]+=lw->m_fixed_landmarks.point(i,2); count++; } } mx[j]/=count; my[j]/=count; mz[j]/=count; } iter_count++; } while(reassigned && (iter_count<10000)); fprintf(stderr,"iter count %d\n", iter_count); free(D); free(DD); free(mx); free(my); free(mz); } //calculate adaptive radius of each RBF void rbf_cluster_find_adapt_radius(Landmark_warp *lw) { int i,j,k, count; int num_clusters = lw->num_clusters; int num_landmarks = lw->m_fixed_landmarks.get_count(); float d, D, dmax; float *d_nearest_neighb; // NB what to do if there is just one landmark in a cluster?? for(k=0; kcluster_id[i]==k) num_landm_in_clust++;} if (num_landm_in_clust>1){ D = 0; count = 0; dmax=-1; for(i=0; icluster_id[i] == k && lw->cluster_id[j] == k && j != i ) { d = (lw->m_fixed_landmarks.point(i,0)-lw->m_fixed_landmarks.point(j,0)) *(lw->m_fixed_landmarks.point(i,0)-lw->m_fixed_landmarks.point(j,0)) + (lw->m_fixed_landmarks.point(i,1)-lw->m_fixed_landmarks.point(j,1)) *(lw->m_fixed_landmarks.point(i,1)-lw->m_fixed_landmarks.point(j,1)) + (lw->m_fixed_landmarks.point(i,2)-lw->m_fixed_landmarks.point(j,2)) *(lw->m_fixed_landmarks.point(i,2)-lw->m_fixed_landmarks.point(j,2)); D += sqrt(d); if (sqrt(d)>dmax) dmax = sqrt(d); count++; } } } D /= count; D = D ; //a magic number printf("nclust %d nland %d dmax = %f D = %f\n", num_clusters, num_landm_in_clust, dmax, D); // single long cluster needs other treatment // if ( (num_clusters == 1) && (dmax/(D) > 1.5) ) { if ( (dmax/(D) > 2) ) { printf("long cluster, dmax %f D %f\n", dmax, D); //D = dmax/2.1; // radius is the max distance between nearest neighbors d_nearest_neighb = (float *)malloc(num_landmarks*sizeof(float)); for(i=0;icluster_id[i]==k) d_nearest_neighb[i]=1e20; for(i=0;icluster_id[i]!=k || lw->cluster_id[j] !=k ) continue; d = (lw->m_fixed_landmarks.point(i,0)-lw->m_fixed_landmarks.point(j,0)) *(lw->m_fixed_landmarks.point(i,0)-lw->m_fixed_landmarks.point(j,0)) + (lw->m_fixed_landmarks.point(i,1)-lw->m_fixed_landmarks.point(j,1)) *(lw->m_fixed_landmarks.point(i,1)-lw->m_fixed_landmarks.point(j,1)) + (lw->m_fixed_landmarks.point(i,2)-lw->m_fixed_landmarks.point(j,2)) *(lw->m_fixed_landmarks.point(i,2)-lw->m_fixed_landmarks.point(j,2)); d = sqrt(d); if (dD && lw->cluster_id[i]==k ) D = d_nearest_neighb[i]; } free(d_nearest_neighb); } // end if dmax/D>..., long cluster } //end if many landmarks in a cluster else {D=50;}//clusters of one landmark get a magic radius for(i=0; icluster_id[i] == k) lw->adapt_radius[i] = D; } } // end for k=0..num_clusters return; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/rbf_cluster.h000066400000000000000000000007421321604176500311310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rbf_cluster_h_ #define _rbf_cluster_h_ #include "plmregister_config.h" class Landmark_warp; PLMREGISTER_API void rbf_cluster_kmeans_plusplus (Landmark_warp *lw); PLMREGISTER_API void rbf_cluster_find_adapt_radius (Landmark_warp *lw); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/rbf_gauss.cxx000066400000000000000000000374201321604176500311500ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include "vnl/vnl_matrix_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/vnl_vector.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/algo/vnl_svd.h" #include "vnl/vnl_sample.h" #include "landmark_warp.h" #include "plm_image.h" #include "plm_math.h" #include "print_and_exit.h" #include "raw_pointset.h" #include "rbf_cluster.h" #include "rbf_gauss.h" #include "vf.h" #include "volume.h" #include "volume_macros.h" #include "xform.h" typedef struct rbf_params Rbf_parms; struct rbf_params { // used to pass information to bspline_rbf_score float radius; // radius of the RBF Bspline_parms *bparms; Volume *vector_field; }; static float rbf_value (const float *rbf_center, const float *loc, float radius) { float val, r, dx, dy, dz; dx = rbf_center[0]-loc[0]; dy = rbf_center[1]-loc[1]; dz = rbf_center[2]-loc[2]; r = sqrt (dx*dx + dy*dy + dz*dz); r = r / radius; // if (r>1) return 0.; // val = (1-r)*(1-r)*(1-r)*(1-r)*(4*r+1.); // Wendland val = exp( -r*r ); return val; } /* Analytic expression for the integral of squared second derivatives of the vector field of a single Gaussian RBF of radius c */ #if defined (commentout) static float rbf_gauss_secderiv_self (float c) { float factor = 1.968701243; // pow( M_PI/2, 3./2); return 15*factor/c; } #endif /* Analytic expression for the integral of squared second derivatives of the vector field of two Gaussian RBFs of radii c, separated by squared distance a2 = (x1-x2)*(x1-x2)+... (one-half of the overlap integral only). */ #if defined (commentout) static float rbf_gauss_secderiv_cross (float c, float a2) { float factor = 1.968701243; // pow( M_PI/2, 3./2); return factor/c*exp(-a2/(2*c*c))*(-10. + ( a2/(c*c)-5.)*(a2/(c*c)-5.) ); } #endif #if defined (commentout) static float bspline_rbf_analytic_integral (Bspline_parms *parms, float *pix_spacing) { Bspline_landmarks *blm = parms->landmarks; int i,j,d; float a2, s = 0.; for(i=0;inum_landmarks;i++) for(d=0;d<3;d++) s += blm->rbf_coeff[3*i+d] * blm->rbf_coeff[3*i+d] * rbf_gauss_secderiv_self( parms->rbf_radius ); if (blm->num_landmarks>1) for(i=0;inum_landmarks;i++) for(j=i+1;jnum_landmarks;j++) for(d=0;d<3;d++) { a2 = (blm->landvox_fix[3*i+0]-blm->landvox_fix[3*j+0])* (blm->landvox_fix[3*i+0]-blm->landvox_fix[3*j+0])* pix_spacing[0] * pix_spacing[0] + (blm->landvox_fix[3*i+1]-blm->landvox_fix[3*j+1])* (blm->landvox_fix[3*i+1]-blm->landvox_fix[3*j+1])* pix_spacing[1] * pix_spacing[1] + (blm->landvox_fix[3*i+2]-blm->landvox_fix[3*j+2])* (blm->landvox_fix[3*i+2]-blm->landvox_fix[3*j+2])* pix_spacing[2] * pix_spacing[2]; s += 2. * blm->rbf_coeff[3*i+d] * blm->rbf_coeff[3*j+d] * rbf_gauss_secderiv_cross( parms->rbf_radius, a2 ); } return s; } #endif #if defined (commentout) /* Test RBF solution by calculating the residual error of landmark matching */ static void bspline_rbf_test_solution(Volume *vector_field, Bspline_parms *parms) { Bspline_landmarks *blm = parms->landmarks; float *vf; float totdist, dx, dist, maxdist; int i, j, d, dd, fv, rbfcenter[3]; Rbf_parms *rbf_par; rbf_par = (Rbf_parms *)malloc( sizeof(Rbf_parms)); rbf_par->radius = parms->rbf_radius; rbf_par->bparms = parms; rbf_par->vector_field = vector_field; if (vector_field->pix_type != PT_VF_FLOAT_INTERLEAVED ) print_and_exit("Sorry, this type of vector field is not supported\n"); //fill in vector field at fixed landmark location vf = (float*) vector_field->img; for(i=0;inum_landmarks;i++) { fv = blm->landvox_fix[3*i+2] * vector_field->dim[0] * vector_field->dim[1] +blm->landvox_fix[3*i+1] * vector_field->dim[0] +blm->landvox_fix[3*i+0] ; for(d=0;d<3;d++) blm->landmark_dxyz[3*i+d] = vf[3*fv+d]; } maxdist = -1; totdist = 0; for(i=0;inum_landmarks;i++) { dist = 0; for(d = 0; d<3; d++) { dx = blm->fixed_landmarks->points[3*i+d] + blm->landmark_dxyz[3*i+d] - blm->moving_landmarks->points[3*i+d]; for(j=0;jnum_landmarks;j++) { for(dd=0;dd<3;dd++) rbfcenter[dd] = blm->landvox_fix[3*j+dd]; dx += blm->rbf_coeff[3*j+d]* rbf_value( rbfcenter, blm->landvox_fix[3*i+0], blm->landvox_fix[3*i+1], blm->landvox_fix[3*i+2], rbf_par->radius, rbf_par->vector_field->pix_spacing ); } dist = dist + dx*dx; } dist = sqrt(dist); totdist += dist; if (dist>maxdist) maxdist = dist; //printf("L%2d %f\n", i, dist); } totdist/=blm->num_landmarks; printf("Landmark mismatch: AVERAGE %f, MAX %f\n", totdist, maxdist); } #endif // find RBF coeff by solving the linear equations using ITK's SVD routine // using analytical regularization of Gaussian exp(-r*r) RBFs to minimize // the sum of squares of second derivatives. // Output: // parms->blm->rbf_coeff contains RBF coefficients static void bspline_rbf_find_coeffs_reg ( float *coeff, /* Output */ Landmark_warp *lw /* Input */ ) { float rbfv1, rbfv2; int i, j, k, d; float rbf_prefactor, reg_term, r2, tmp; int num_landmarks = lw->m_fixed_landmarks.get_count(); typedef vnl_matrix Vnl_matrix; typedef vnl_svd SVDSolverType; Vnl_matrix A, b; //printf("Finding RBF coeffs, radius %.2f, Young modulus %e\n", //lw->rbf_radius, lw->young_modulus); A.set_size (3 * num_landmarks, 3 * num_landmarks); A.fill(0.); b.set_size (3 * num_landmarks, 1); b.fill (0.0); // right-hand side for (i=0; im_fixed_landmarks.point(i,d); } rbfv1 = rbf_value (rbf_center, lw->m_fixed_landmarks.point(j).p, lw->adapt_radius[j]); for (d=0;d<3;d++) { b (3*i +d, 0) -= rbfv1 * (lw->m_fixed_landmarks.point(j,d) - lw->m_moving_landmarks.point(j,d)); } } } // matrix for (i = 0; i < num_landmarks; i++) { for (j = 0; j < num_landmarks; j++) { tmp = 0; for (k = 0; k < num_landmarks; k++) { float rbf_center[3]; for (d=0; d<3; d++) { rbf_center[d] = lw->m_fixed_landmarks.point(k,d); } rbfv1 = rbf_value (rbf_center, lw->m_fixed_landmarks.point(i).p, lw->adapt_radius[k]); rbfv2 = rbf_value (rbf_center, lw->m_fixed_landmarks.point(j).p, lw->adapt_radius[k]); tmp += rbfv1*rbfv2; } for (d=0;d<3;d++) { A(3*i+d, 3*j+d) = tmp; //printf("i j d = %d %d %d A = %f\n", i,j,d, A(3*i+d, 3*j+d)); } } } //add regularization terms to the matrix rbf_prefactor = sqrt(M_PI/2.)*sqrt(M_PI/2.)*sqrt(M_PI/2.)/lw->rbf_radius; for (d=0;d<3;d++) { for (i=0;im_fixed_landmarks.point(i,0) - lw->m_fixed_landmarks.point(j,0); float dy = lw->m_fixed_landmarks.point(i,1) - lw->m_fixed_landmarks.point(j,1); float dz = lw->m_fixed_landmarks.point(i,2) - lw->m_fixed_landmarks.point(j,2); // r2 = sq distance between landmarks i,j in mm r2 = dx * dx + dy * dy + dz * dz; r2 = r2 / (lw->adapt_radius[i] * lw->adapt_radius[j]); reg_term = rbf_prefactor * exp(-r2/2.) * (-10 + (r2-5.)*(r2-5.)); } //printf("i j d = %d %d %d regterm = %f\n", i,j,d, reg_term); A (3*i+d,3*j+d) = tmp + reg_term * lw->young_modulus; } } } // A.print (std::cout); // b.print (std::cout); SVDSolverType svd (A, 1e-6); Vnl_matrix x = svd.solve (b); // x.print (std::cout); for (i=0; i<3*num_landmarks; i++) { coeff[i] = x(i,0); } } #if defined (commentout) // find RBF coeff by solving the linear equations using ITK's SVD routine // Output: // parms->blm->rbf_coeff contains RBF coefficients static void bspline_rbf_find_coeffs_noreg ( Volume *vector_field, Bspline_parms *parms ) { Bspline_landmarks *blm = parms->landmarks; float *vf; float rbfv; int i, j, d, fv, rbfcenter[3]; typedef vnl_matrix Vnl_matrix; typedef vnl_svd SVDSolverType; Vnl_matrix A, b; Rbf_parms *rbf_par; rbf_par = (Rbf_parms *)malloc( sizeof(Rbf_parms)); rbf_par->radius = parms->rbf_radius; rbf_par->bparms = parms; rbf_par->vector_field = vector_field; if (vector_field->pix_type != PT_VF_FLOAT_INTERLEAVED ) print_and_exit("Sorry, this type of vector field is not supported\n"); //fill in vector field at fixed landmark location vf = (float*) vector_field->img; for(i=0;inum_landmarks;i++) { fv = blm->landvox_fix[3*i+2] * vector_field->dim[0] * vector_field->dim[1] +blm->landvox_fix[3*i+1] * vector_field->dim[0] +blm->landvox_fix[3*i+0] ; for(d=0;d<3;d++) blm->landmark_dxyz[3*i+d] = vf[3*fv+d]; } A.set_size (3 * blm->num_landmarks, 3 * blm->num_landmarks); A.set_identity (); b.set_size (3 * blm->num_landmarks, 1); b.fill (0.0); // right-hand side for(i=0;inum_landmarks;i++) { for(d=0;d<3;d++) { b (3*i +d, 0) = -(blm->fixed_landmarks.point(i,d) + blm->landmark_dxyz[3*i+d] - blm->moving_landmarks.point(i,d)); } } // matrix for(i=0;inum_landmarks;i++) { for(j=0;jnum_landmarks;j++) { for(d=0;d<3;d++) rbfcenter[d] = blm->landvox_fix[3*j+d]; rbfv = rbf_value( rbfcenter, blm->landvox_fix[3*i+0], blm->landvox_fix[3*i+1], blm->landvox_fix[3*i+2], rbf_par->radius, rbf_par->vector_field->pix_spacing ); for(d=0;d<3;d++) A(3*i+d, 3*j+d) = rbfv ; } } // A.print (std::cout); // b.print (std::cout); SVDSolverType svd (A, 1e-6); Vnl_matrix x = svd.solve (b); // x.print (std::cout); for(i=0;i<3*blm->num_landmarks;i++) blm->rbf_coeff[i] = x(i,0); } #endif // find RBF coeff by solving the linear equations using ITK's SVD routine // Output: // parms->blm->rbf_coeff contains RBF coefficients static void bspline_rbf_find_coeffs ( float *coeff, /* Output */ Landmark_warp *lw /* Input */ ) { bspline_rbf_find_coeffs_reg (coeff, lw); for (size_t i = 0; i < lw->m_fixed_landmarks.get_count(); i++) { printf("coeff %4d %.4f %.4f %.4f\n", (int) i, coeff[3*i+0], coeff[3*i+1], coeff[3*i+2]); } #if defined (commentout) float s; //bspline_rbf_test_solution( vector_field, parms); s = bspline_rbf_analytic_integral( parms, vector_field->pix_spacing ); printf("Analytic INTSECDER %f\n",s); #endif } /* Adds RBF contributions to the vector field landmark_dxyz is not updated by this function Version without truncation: scan over the entire vf and add up all RBFs in each voxel NOW SUPPORTS DIRECTION COSINES */ void rbf_gauss_update_vf ( Volume *vf, /* Modified */ Landmark_warp *lw, /* Input */ float *coeff /* Input */ ) { int lidx, d; plm_long ijk[3]; float fxyz[3]; float *vf_img; float rbf; int num_landmarks = lw->m_fixed_landmarks.get_count(); printf("Gauss RBF, updating the vector field\n"); if (vf->pix_type != PT_VF_FLOAT_INTERLEAVED ) print_and_exit("Sorry, this type of vector field is not supported\n"); vf_img = (float*) vf->img; LOOP_Z (ijk, fxyz, vf) { LOOP_Y (ijk, fxyz, vf) { LOOP_X (ijk, fxyz, vf) { /* Compute linear index of voxel */ plm_long fv = volume_index (vf->dim, ijk); for (lidx=0; lidx < num_landmarks; lidx++) { rbf = rbf_value ( lw->m_fixed_landmarks.point(lidx).p, fxyz, lw->adapt_radius[lidx]); for (d=0; d<3; d++) { vf_img[3*fv+d] += coeff[3*lidx+d] * rbf; #if defined (commentout) printf ("Adding: %d (%d %d %d) (%g * %g) %g\n", lidx, ijk[0], ijk[1], ijk[2], coeff[3*lidx+d], rbf, coeff[3*lidx+d] * rbf); #endif } } } } } } /* Adds RBF contributions to the vector field landmark_dxyz is not updated by this function Version without truncation: scan over the entire vf and add up all RBFs in each voxel VERSION WITHOUT DIRECTION COSINES (correct for 100 010 001 only) */ void rbf_gauss_update_vf_no_dircos ( Volume *vf, /* Modified */ Landmark_warp *lw, /* Input */ float *coeff /* Input */ ) { int lidx, d; plm_long fi, fj, fk, fv; float fxyz[3]; float *vf_img; float rbf; int num_landmarks = lw->m_fixed_landmarks.get_count(); printf("Gauss RBF, updating the vector field\n"); if (vf->pix_type != PT_VF_FLOAT_INTERLEAVED ) print_and_exit("Sorry, this type of vector field is not supported\n"); vf_img = (float*) vf->img; for (fk = 0; fk < vf->dim[2]; fk++) { fxyz[2] = vf->origin[2] + fk * vf->spacing[2]; for (fj = 0; fj < vf->dim[1]; fj++) { fxyz[1] = vf->origin[1] + fj * vf->spacing[1]; for (fi = 0; fi < vf->dim[0]; fi++) { fxyz[0] = vf->origin[0] + fi * vf->spacing[0]; for (lidx=0; lidx < num_landmarks; lidx++) { fv = fk * vf->dim[0] * vf->dim[1] + fj * vf->dim[0] + fi; rbf = rbf_value ( lw->m_fixed_landmarks.point(lidx).p, fxyz, lw->adapt_radius[lidx]); for (d=0; d<3; d++) { vf_img[3*fv+d] += coeff[3*lidx+d] * rbf; #if defined (commentout) printf ("Adding: %d (%d %d %d) (%g * %g) %g\n", lidx, fi, fj, fk, blm->rbf_coeff[3*lidx+d], rbf, blm->rbf_coeff[3*lidx+d] * rbf); #endif } } } } } } void rbf_gauss_warp (Landmark_warp *lw) { float *coeff; float origin[3], spacing[3]; float direction_cosines[9]; plm_long dim[3]; Volume::Pointer moving; Volume *vf_out, *warped_out; lw->adapt_radius = (float *)malloc(lw->m_fixed_landmarks.get_count()*sizeof(float)); lw->cluster_id = (int *)malloc(lw->m_fixed_landmarks.get_count()*sizeof(int)); if (lw->num_clusters > 0) { rbf_cluster_kmeans_plusplus( lw ); rbf_cluster_find_adapt_radius( lw ); } else { for (size_t i = 0; i < lw->m_fixed_landmarks.get_count(); i++) lw->adapt_radius[i]=lw->rbf_radius; } for (size_t i = 0; i < lw->m_fixed_landmarks.get_count(); i++) { printf("%f\n", lw->adapt_radius[i]); } /* Solve for RBF weights */ coeff = (float*) malloc ( 3 * lw->m_fixed_landmarks.get_count() * sizeof(float)); bspline_rbf_find_coeffs (coeff, lw); /* Create output vector field */ printf ("Creating output vf\n"); lw->m_pih.get_origin (origin); lw->m_pih.get_spacing (spacing); lw->m_pih.get_dim (dim); lw->m_pih.get_direction_cosines (direction_cosines); vf_out = new Volume (dim, origin, spacing, direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); printf ("Rendering vector field\n"); rbf_gauss_update_vf (vf_out, lw, coeff); /* Create output (warped) image */ printf ("Converting volume to float\n"); moving = lw->m_input_img->get_volume_float (); printf ("Creating output vol\n"); warped_out = new Volume (dim, origin, spacing, direction_cosines, PT_FLOAT, 1); printf ("Warping image\n"); vf_warp (warped_out, moving.get(), vf_out); printf ("Freeing coeff\n"); free (coeff); /* Copy outputs to lw structure */ lw->m_vf = new Xform; //lw->m_vf->set_gpuit_vf (vf_out); lw->m_vf->set_gpuit_vf (Volume::Pointer(vf_out)); lw->m_warped_img = new Plm_image; lw->m_warped_img->set_volume (warped_out); printf ("Done with rbf_gauss_warp\n"); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/rbf_gauss.h000066400000000000000000000011521321604176500305660ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rbf_gauss_h_ #define _rbf_gauss_h_ #include "plmregister_config.h" class Bspline_parms; class Landmark_warp; class Volume; PLMREGISTER_API void bspline_rbf_find_coeffs (Volume *vector_field, Bspline_parms *parms); PLMREGISTER_API void bspline_rbf_update_vector_field (Volume *vector_field, Bspline_parms *parms); PLMREGISTER_API void rbf_gauss_warp (Landmark_warp *lw); #endif rbf_wendland.cxx000066400000000000000000000166531321604176500315500ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include "vnl/vnl_matrix_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/vnl_vector.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/algo/vnl_svd.h" #include "vnl/vnl_sample.h" #include "landmark_warp.h" #include "plm_image.h" #include "plm_math.h" #include "print_and_exit.h" #include "raw_pointset.h" #include "rbf_cluster.h" #include "rbf_wendland.h" #include "vf.h" #include "volume.h" #include "volume_macros.h" #include "xform.h" typedef struct rbf_params Rbf_parms; struct rbf_params { // used to pass information to bspline_rbf_score float radius; // radius of the RBF Bspline_parms *bparms; Volume *vector_field; }; static float rbf_wendland_value (const float *rbf_center, const float *loc, float radius) { float val, r, dx, dy, dz; dx = rbf_center[0]-loc[0]; dy = rbf_center[1]-loc[1]; dz = rbf_center[2]-loc[2]; r = sqrt (dx*dx + dy*dy + dz*dz); r = r / radius; if (r>1) return 0.; val = (1-r)*(1-r)*(1-r)*(1-r)*(4*r+1.); // Wendland return val; } // find RBF coeff by solving the linear equations using ITK's SVD routine // Output: // parms->blm->rbf_coeff contains RBF coefficients static void bspline_rbf_find_coeffs_noreg ( float *coeff, /* Output */ Landmark_warp *lw /* Input */ ) { float rbfv; int i, j, d; int num_landmarks = lw->m_fixed_landmarks.get_count(); typedef vnl_matrix Vnl_matrix; typedef vnl_svd SVDSolverType; Vnl_matrix A, b; //printf("Finding RBF coeffs, radius %.2f, Young modulus %e\n", //lw->rbf_radius, lw->young_modulus); A.set_size (3 * num_landmarks, 3 * num_landmarks); A.fill(0.); b.set_size (3 * num_landmarks, 1); b.fill (0.0); // right-hand side for(i=0;im_fixed_landmarks.point(i,d) - lw->m_moving_landmarks.point(i,d)); } } // matrix for(i=0;im_fixed_landmarks.point(j,d); } rbfv = rbf_wendland_value (rbf_center, lw->m_fixed_landmarks.point(i).p, lw->adapt_radius[j]); for(d=0;d<3;d++) A(3*i+d, 3*j+d) = rbfv ; } } // A.print (std::cout); // b.print (std::cout); SVDSolverType svd (A, 1e-6); Vnl_matrix x = svd.solve (b); // x.print (std::cout); for (i=0; i<3*num_landmarks; i++) { coeff[i] = x(i,0); } } // find RBF coeff by solving the linear equations using ITK's SVD routine // Output: // parms->blm->rbf_coeff contains RBF coefficients static void bspline_rbf_find_coeffs ( float *coeff, /* Output */ Landmark_warp *lw /* Input */ ) { // Regularization for Wendland RBF not yet implemented // bspline_rbf_find_coeffs_reg (coeff, lw); bspline_rbf_find_coeffs_noreg( coeff, lw); for (size_t i = 0; i < lw->m_fixed_landmarks.get_count(); i++) { printf("coeff %4d %.4f %.4f %.4f\n", (int) i, coeff[3*i+0], coeff[3*i+1], coeff[3*i+2]); } } /* Adds RBF contributions to the vector field landmark_dxyz is not updated by this function Version without truncation: scan over the entire vf and add up all RBFs in each voxel */ void rbf_wendland_update_vf ( Volume *vf, /* Modified */ Landmark_warp *lw, /* Input */ float *coeff /* Input */ ) { int lidx, d; plm_long ijk[3]; float fxyz[3]; float *vf_img; float rbf; int num_landmarks = lw->m_fixed_landmarks.get_count(); printf("Wendland RBF, updating the vector field\n"); if (vf->pix_type != PT_VF_FLOAT_INTERLEAVED ) print_and_exit("Sorry, this type of vector field is not supported\n"); vf_img = (float*) vf->img; LOOP_Z (ijk, fxyz, vf) { LOOP_Y (ijk, fxyz, vf) { LOOP_X (ijk, fxyz, vf) { /* Compute linear index of voxel */ plm_long fv = volume_index (vf->dim, ijk); for (lidx=0; lidx < num_landmarks; lidx++) { rbf = rbf_wendland_value ( lw->m_fixed_landmarks.point(lidx).p, fxyz, lw->adapt_radius[lidx]); for (d=0; d<3; d++) { vf_img[3*fv+d] += coeff[3*lidx+d] * rbf; #if defined (commentout) printf ("Adding: %d (%d %d %d) (%g * %g) %g\n", lidx, ijk[0], ijk[1], ijk[2], coeff[3*lidx+d], rbf, coeff[3*lidx+d] * rbf); #endif } } } } } } void rbf_wendland_warp (Landmark_warp *lw) { float *coeff; float origin[3], spacing[3]; plm_long dim[3]; float direction_cosines[9]; Volume::Pointer moving; Volume *vf_out, *warped_out; //printf ("Wendland Radial basis functions requested, radius %.2f\n", lw->rbf_radius); lw->adapt_radius = (float *)malloc(lw->m_fixed_landmarks.get_count() * sizeof(float)); lw->cluster_id = (int *)malloc(lw->m_fixed_landmarks.get_count() * sizeof(int)); if (lw->num_clusters > 0) { // cluster the landmarks; result in lw->cluster_id rbf_cluster_kmeans_plusplus( lw ); // using cluster_id, fill in lw->adapt_radius rbf_cluster_find_adapt_radius( lw ); } else { // use the specified radius for (size_t i = 0; i < lw->m_fixed_landmarks.get_count(); i++) { lw->adapt_radius[i]=lw->rbf_radius; } } for (size_t i = 0; i < lw->m_fixed_landmarks.get_count(); i++) { lw->adapt_radius[i]*=2; printf("%f\n", lw->adapt_radius[i]); } /* Solve for RBF weights */ coeff = (float*) malloc ( 3 * lw->m_fixed_landmarks.get_count() * sizeof(float)); bspline_rbf_find_coeffs (coeff, lw); /* Create output vector field */ printf ("Creating output vf\n"); lw->m_pih.get_origin (origin); lw->m_pih.get_spacing (spacing); lw->m_pih.get_dim (dim); lw->m_pih.get_direction_cosines (direction_cosines); vf_out = new Volume (dim, origin, spacing, direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); printf ("Rendering vector field\n"); rbf_wendland_update_vf (vf_out, lw, coeff); /* Create output (warped) image */ printf ("Converting volume to float\n"); moving = lw->m_input_img->get_volume_float (); printf ("Creating output vol\n"); warped_out = new Volume (dim, origin, spacing, direction_cosines, PT_FLOAT, 1); printf ("Warping image\n"); vf_warp (warped_out, moving.get(), vf_out); printf ("Freeing coeff\n"); free (coeff); /* Copy outputs to lw structure */ lw->m_vf = new Xform; //lw->m_vf->set_gpuit_vf (vf_out); lw->m_vf->set_gpuit_vf (Volume::Pointer(vf_out)); lw->m_warped_img = new Plm_image; lw->m_warped_img->set_volume (warped_out); printf ("Done with rbf_wendland_warp\n"); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/rbf_wendland.h000066400000000000000000000012511321604176500312400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rbf_wendland_h_ #define _rbf_wendland_h_ #include "plmregister_config.h" class Bspline_parms; class Landmark_warp; class Volume; PLMREGISTER_API void bspline_rbf_wendland_find_coeffs ( Volume *vector_field, Bspline_parms *parms ); PLMREGISTER_API void bspline_rbf_wendland_update_vector_field ( Volume *vector_field, Bspline_parms *parms ); PLMREGISTER_API void rbf_wendland_warp (Landmark_warp *lw); #endif registration.cxx000066400000000000000000000520211321604176500316220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include "itkImageRegionConstIteratorWithIndex.h" #include "itkMultiThreader.h" #include "bspline_stage.h" #include "bspline_xform.h" #include "dlib_threads.h" #include "gpuit_demons.h" #include "itk_align_center.h" #include "itk_demons.h" #include "itk_image_save.h" #include "itk_image_stats.h" #include "itk_registration.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_timer.h" #include "plm_warp.h" #include "pointset_warp.h" #include "registration.h" #include "registration_data.h" #include "registration_parms.h" #include "shared_parms.h" #include "stage_parms.h" #include "translation_grid_search.h" #include "volume.h" #include "xform.h" class Registration_private { public: Registration_data::Pointer rdata; Registration_parms::Pointer rparms; Xform::Pointer xf_in; Xform::Pointer xf_out; itk::MultiThreader::Pointer threader; Dlib_master_slave master_slave; Dlib_semaphore worker_running; int thread_no; bool time_to_quit; public: Registration_private () { rdata = Registration_data::New (); rparms = Registration_parms::New (); xf_in = Xform::New (); xf_out = Xform::New (); threader = itk::MultiThreader::New (); thread_no = -1; time_to_quit = false; } ~Registration_private () { this->time_to_quit = true; // do something more here ... wait for running threads to exit } }; Registration::Registration () { d_ptr = new Registration_private; } Registration::~Registration () { delete d_ptr; } Plm_return_code Registration::set_command_file (const std::string& command_file) { return d_ptr->rparms->parse_command_file (command_file.c_str()); } Plm_return_code Registration::set_command_string (const std::string& command_string) { return d_ptr->rparms->set_command_string (command_string); } void Registration::set_fixed_image (Plm_image::Pointer& fixed) { d_ptr->rdata->set_fixed_image (fixed); } void Registration::set_moving_image (Plm_image::Pointer& moving) { d_ptr->rdata->set_moving_image (moving); } void Registration::set_fixed_roi (Plm_image::Pointer& fixed_roi) { d_ptr->rdata->set_fixed_roi (fixed_roi); } void Registration::set_moving_roi (Plm_image::Pointer& moving_roi) { d_ptr->rdata->set_moving_roi (moving_roi); } Registration_data::Pointer Registration::get_registration_data () { return d_ptr->rdata; } Registration_parms::Pointer Registration::get_registration_parms () { return d_ptr->rparms; } /* This helps speed up the registration, by setting the bounding box to the smallest size needed. To find the bounding box, either use the extent of the fixed_roi (if one is used), or by eliminating excess air by thresholding */ static void set_fixed_image_region_global (Registration_data::Pointer& regd) { int use_magic_value = 1; Plm_image::Pointer fixed_image = regd->get_fixed_image(); regd->fixed_region_origin = fixed_image->itk_float()->GetOrigin(); regd->fixed_region_spacing = fixed_image->itk_float()->GetSpacing(); if (regd->get_fixed_roi()) { FloatImageType::RegionType::IndexType valid_index; FloatImageType::RegionType::SizeType valid_size; /* Search for bounding box of fixed roi */ typedef itk::ImageRegionConstIteratorWithIndex< UCharImageType > IteratorType; UCharImageType::RegionType region = regd->get_fixed_roi()->itk_uchar()->GetLargestPossibleRegion(); IteratorType it (regd->get_fixed_roi()->itk_uchar(), region); int first = 1; valid_index[0] = 0; valid_index[1] = 0; valid_index[2] = 0; valid_size[0] = 0; valid_size[1] = 0; valid_size[2] = 0; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { unsigned char c = it.Get(); if (c) { UCharImageType::RegionType::IndexType idx = it.GetIndex(); if (first) { first = 0; valid_index = idx; valid_size[0] = 1; valid_size[1] = 1; valid_size[2] = 1; } else { for (int i = 0; i < 3; i++) { if (valid_index[i] > idx[i]) { valid_size[i] += valid_index[i] - idx[i]; valid_index[i] = idx[i]; } if (idx[i] - valid_index[i] >= (long) valid_size[i]) { valid_size[i] = idx[i] - valid_index[i] + 1; } } } } } regd->fixed_region.SetIndex(valid_index); regd->fixed_region.SetSize(valid_size); } else if (use_magic_value) { FloatImageType::RegionType::IndexType valid_index; FloatImageType::RegionType::SizeType valid_size; valid_index[0] = 0; valid_index[1] = 0; valid_index[2] = 0; valid_size[0] = 1; valid_size[1] = 1; valid_size[2] = 1; /* Make sure the image is ITK float */ Plm_image::Pointer fixed_image = regd->get_fixed_image(); FloatImageType::Pointer fixed = fixed_image->itk_float(); /* Search for bounding box of patient */ typedef itk::ImageRegionConstIteratorWithIndex < FloatImageType > IteratorType; FloatImageType::RegionType region = fixed->GetLargestPossibleRegion(); IteratorType it (fixed, region); int first = 1; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { float c = it.Get(); #define FIXME_BACKGROUND_MAX (-1200) if (c > FIXME_BACKGROUND_MAX) { FloatImageType::RegionType::IndexType idx = it.GetIndex(); if (first) { first = 0; valid_index = idx; valid_size[0] = 1; valid_size[1] = 1; valid_size[2] = 1; } else { for (int i = 0; i < 3; i++) { if (valid_index[i] > idx[i]) { valid_size[i] += valid_index[i] - idx[i]; valid_index[i] = idx[i]; } if (idx[i] - valid_index[i] >= (long) valid_size[i]) { valid_size[i] = idx[i] - valid_index[i] + 1; } } } } } /* Try to include a margin of at least one air pixel everywhere */ for (int i = 0; i < 3; i++) { if (valid_index[i] > 0) { valid_index[i]--; valid_size[i]++; } if (valid_size[i] + valid_index[i] < fixed->GetLargestPossibleRegion().GetSize()[i]) { valid_size[i]++; } } regd->fixed_region.SetIndex(valid_index); regd->fixed_region.SetSize(valid_size); } else { regd->fixed_region = fixed_image->itk_float()->GetLargestPossibleRegion(); } } static void save_output ( Registration_data* regd, Xform::Pointer& xf_out, const std::list& xf_out_fn, bool xf_out_itk, int img_out_fmt, Plm_image_type img_out_type, float default_value, const std::string& img_out_fn, const std::string& vf_out_fn, const std::string& warped_landmarks_fn, const std::string& valid_roi_out_fn ) { Plm_image::Pointer fixed_image = regd->get_fixed_image(); Plm_image::Pointer moving_image = regd->get_moving_image(); /* Handle null xf, make it zero translation */ if (xf_out->m_type == XFORM_NONE) { xf_out->init_trn (); } /* Save xf to all filenames in list */ std::list::const_iterator it; for (it = xf_out_fn.begin(); it != xf_out_fn.end(); ++it) { logfile_printf ("Writing transformation ...\n"); if (xf_out_itk && xf_out->m_type == XFORM_GPUIT_BSPLINE) { Plm_image_header pih; pih.set_from_plm_image (fixed_image); Xform::Pointer xf_tmp = xform_to_itk_bsp (xf_out, &pih, 0); xf_tmp->save (*it); } else { xf_out->save (*it); } } if (img_out_fn[0] || vf_out_fn[0] || warped_landmarks_fn[0] || valid_roi_out_fn[0]) { DeformationFieldType::Pointer vf; DeformationFieldType::Pointer *vfp; Plm_image::Pointer im_warped; Plm_image_header pih; if (vf_out_fn[0] || warped_landmarks_fn[0]) { vfp = &vf; } else { vfp = 0; } if (img_out_fn[0]) { im_warped = Plm_image::New(); } pih.set_from_plm_image (fixed_image); logfile_printf ("Warping...\n"); Plm_image::Pointer moving_image = regd->get_moving_image(); plm_warp (im_warped, vfp, xf_out, &pih, moving_image, default_value, 0, 1); if (img_out_fn[0]) { logfile_printf ("Saving image...\n"); if (img_out_fmt == IMG_OUT_FMT_AUTO) { if (img_out_type == PLM_IMG_TYPE_UNDEFINED) { im_warped->save_image (img_out_fn); } else { im_warped->convert_and_save (img_out_fn, img_out_type); } } else { im_warped->save_short_dicom (img_out_fn, 0); } } if (warped_landmarks_fn[0]) { Labeled_pointset warped_pointset; logfile_printf ("Saving warped landmarks...\n"); pointset_warp (&warped_pointset, regd->moving_landmarks, vf); warped_pointset.save (warped_landmarks_fn.c_str()); } if (vf_out_fn[0]) { logfile_printf ("Saving vf...\n"); itk_image_save (vf, vf_out_fn); } if (valid_roi_out_fn[0]) { logfile_printf ("Warping valid ROI...\n"); Plm_image::Pointer valid_roi = Plm_image::clone (moving_image); #if defined (commentout) plm_warp (im_warped, vfp, xf_out, &pih, regd->moving_image, default_value, 0, 1); #endif } } } Xform::Pointer Registration::do_registration_stage ( Stage_parms* stage ) { Registration_data::Pointer regd = d_ptr->rdata; Registration_parms::Pointer regp = d_ptr->rparms; const Xform::Pointer& xf_in = d_ptr->xf_in; Xform::Pointer xf_out = Xform::New (); lprintf ("[1] xf_in->m_type = %d, xf_out->m_type = %d\n", xf_in->m_type, xf_out->m_type); /* Run registration */ switch (stage->xform_type) { case STAGE_TRANSFORM_ALIGN_CENTER: xf_out = do_itk_align_center (regd.get(), xf_in, stage); break; case STAGE_TRANSFORM_ALIGN_CENTER_OF_GRAVITY: xf_out = do_itk_align_center_of_gravity (regd.get(), xf_in, stage); break; case STAGE_TRANSFORM_TRANSLATION: if (stage->optim_type == OPTIMIZATION_ALIGN_CENTER) { xf_out = do_itk_align_center (regd.get(), xf_in, stage); } else if (stage->optim_type == OPTIMIZATION_ALIGN_ROI_CENTER) { xf_out = do_itk_align_center_of_gravity (regd.get(), xf_in, stage); } else if (stage->impl_type == IMPLEMENTATION_ITK) { xf_out = do_itk_registration_stage (regd.get(), xf_in, stage); } else if (stage->impl_type == IMPLEMENTATION_PLASTIMATCH) { xf_out = translation_grid_search_stage (regd.get(), xf_in, stage); } else { if (stage->optim_type == OPTIMIZATION_GRID_SEARCH) { xf_out = translation_grid_search_stage ( regd.get(), xf_in, stage); } else { xf_out = do_itk_registration_stage (regd.get(), xf_in, stage); } } break; case STAGE_TRANSFORM_NONE: case STAGE_TRANSFORM_VERSOR: case STAGE_TRANSFORM_QUATERNION: case STAGE_TRANSFORM_SIMILARITY: case STAGE_TRANSFORM_AFFINE: xf_out = do_itk_registration_stage (regd.get(), xf_in, stage); break; case STAGE_TRANSFORM_BSPLINE: if (stage->impl_type == IMPLEMENTATION_ITK) { xf_out = do_itk_registration_stage (regd.get(), xf_in, stage); } else { xf_out = do_gpuit_bspline_stage (regd.get(), xf_in, stage); } break; case STAGE_TRANSFORM_VECTOR_FIELD: if (stage->impl_type == IMPLEMENTATION_ITK) { xf_out = do_itk_demons_stage (regd.get(), xf_in, stage); } else { xf_out = do_gpuit_demons_stage (regd.get(), xf_in, stage); } break; } lprintf ("[2] xf_out->m_type = %d, xf_in->m_type = %d\n", xf_out->m_type, xf_in->m_type); return xf_out; } static void set_auto_resample (float subsample_rate[], Plm_image *pli) { Plm_image_header pih (pli); for (int d = 0; d < 3; d++) { subsample_rate[d] = (float) ((pih.dim(d)+99) / 100); } } static void set_automatic_parameters ( Registration_data::Pointer& regd, Registration_parms::Pointer& regp) { Plm_image::Pointer fixed_image = regd->get_fixed_image(); Plm_image::Pointer moving_image = regd->get_moving_image(); std::list& stages = regp->get_stages(); std::list::iterator it; for (it = stages.begin(); it != stages.end(); it++) { Stage_parms* sp = *it; if (sp->resample_type == RESAMPLE_AUTO) { set_auto_resample ( sp->resample_rate_fixed, fixed_image.get()); set_auto_resample ( sp->resample_rate_moving, moving_image.get()); } } } static void check_output_resolution ( Xform::Pointer& xf_out, Registration_data::Pointer& regd) { Plm_image::Pointer fixed_image = regd->get_fixed_image(); Plm_image::Pointer moving_image = regd->get_moving_image(); Volume *fixed = fixed_image->get_vol (); int ss[3]; Plm_image_header pih; float grid_spacing[3]; if (xf_out->get_type() != XFORM_GPUIT_BSPLINE) { return; } Bspline_xform *bxf_out = xf_out->get_gpuit_bsp(); if ( (bxf_out->img_dim[0] != fixed->dim[0]) || (bxf_out->img_dim[1] != fixed->dim[1]) || (bxf_out->img_dim[2] != fixed->dim[2]) ) { ss[0] = fixed->dim[0] / bxf_out->img_dim[0]; ss[1] = fixed->dim[1] / bxf_out->img_dim[1]; ss[2] = fixed->dim[2] / bxf_out->img_dim[2]; /* last stage was not [1 1 1], un-subsample the final xform */ logfile_printf ("RESTORE NATIVE RESOLUTION: (%d %d %d), (1 1 1)\n", ss[0], ss[1], ss[2]); /* Transform input xform to gpuit vector field */ pih.set_from_gpuit ( fixed->dim, fixed->origin, fixed->spacing, fixed->direction_cosines ); xf_out->get_grid_spacing (grid_spacing); xform_to_gpuit_bsp (xf_out.get(), xf_out.get(), &pih, grid_spacing); } } void Registration::load_global_inputs () { d_ptr->rdata->load_global_input_files (d_ptr->rparms); } void Registration::run_main_thread () { Registration_data::Pointer regd = d_ptr->rdata; Registration_parms::Pointer regp = d_ptr->rparms; /* Load initial guess of xform */ if (regp->xf_in_fn[0]) { d_ptr->xf_out = xform_load (regp->xf_in_fn); } /* Set fixed image region */ set_fixed_image_region_global (regd); /* Set automatic parameters based on image size */ set_automatic_parameters (regd, regp); std::list& stages = regp->get_stages(); std::list::iterator it; for (it = stages.begin(); it != stages.end(); it++) { Stage_parms* stage = *it; const Shared_parms *shared = stage->get_shared_parms(); if (stage->get_stage_type() == STAGE_TYPE_PROCESS) { #if defined (commentout) int non_zero, num_vox; double min_val, max_val, avg; itk_image_stats (regd->moving_image->itk_float (), &min_val, &max_val, &avg, &non_zero, &num_vox); printf ("min = %g, max = %g\n", min_val, max_val); #endif const Process_parms::Pointer& pp = stage->get_process_parms (); pp->execute_process (regd); #if defined (commentout) itk_image_stats (regd->moving_image->itk_float (), &min_val, &max_val, &avg, &non_zero, &num_vox); printf ("min = %g, max = %g\n", min_val, max_val); #endif } else if (stage->get_stage_type() == STAGE_TYPE_REGISTER) { /* Check if parent wants us to pause */ d_ptr->master_slave.slave_grab_resource (); /* Load stage images */ regd->load_stage_input_files (stage); /* Run registation, results are stored in xf_out */ printf ("Doing registration stage\n"); for (int substage = 0; substage < stage->num_substages; substage++) { /* Swap xf_in and xf_out. Memory for previous xf_in gets released at this time. */ d_ptr->xf_in = d_ptr->xf_out; /* Do the registration */ d_ptr->xf_out = this->do_registration_stage (stage); } /* Save intermediate output */ save_output (regd.get(), d_ptr->xf_out, stage->xf_out_fn, stage->xf_out_itk, stage->img_out_fmt, stage->img_out_type, stage->default_value, stage->img_out_fn, stage->vf_out_fn, shared->warped_landmarks_fn, shared->valid_roi_out_fn); /* Tell the parent thread that we finished a stage, so it can wake up if needed. */ d_ptr->master_slave.slave_release_resource (); if (d_ptr->time_to_quit) { break; } } } /* JAS 2012.03.29 - for GPUIT Bspline * make output match input resolution - not final stage resolution */ check_output_resolution (d_ptr->xf_out, regd); /* Done. */ d_ptr->worker_running.release (); } static ITK_THREAD_RETURN_TYPE registration_main_thread (void* param) { itk::MultiThreader::ThreadInfoStruct *info = (itk::MultiThreader::ThreadInfoStruct*) param; Registration* reg = (Registration*) info->UserData; printf ("Inside registration worker thread\n"); reg->run_main_thread (); printf ("** Registration worker thread finished.\n"); return ITK_THREAD_RETURN_VALUE; } void Registration::start_registration () { /* Otherwise, start a new job */ d_ptr->time_to_quit = false; printf ("Launching registration worker thread\n"); d_ptr->worker_running.grab (); d_ptr->thread_no = d_ptr->threader->SpawnThread ( registration_main_thread, (void*) this); } void Registration::pause_registration () { d_ptr->master_slave.master_grab_resource (); } void Registration::resume_registration () { d_ptr->master_slave.master_release_resource (); } void Registration::wait_for_complete () { d_ptr->worker_running.grab (); d_ptr->worker_running.release (); } Xform::Pointer Registration::get_current_xform () { return d_ptr->xf_out; } void Registration::save_global_outputs () { Registration_data::Pointer regd = d_ptr->rdata; Registration_parms::Pointer regp = d_ptr->rparms; const Shared_parms* shared = regp->get_shared_parms (); save_output (regd.get(), d_ptr->xf_out, regp->xf_out_fn, regp->xf_out_itk, regp->img_out_fmt, regp->img_out_type, regp->default_value, regp->img_out_fn, regp->vf_out_fn, shared->warped_landmarks_fn, shared->valid_roi_out_fn); } Xform::Pointer Registration::do_registration_pure () { this->start_registration (); this->wait_for_complete (); return this->get_current_xform (); } void Registration::do_registration () { Registration_data::Pointer regd = d_ptr->rdata; Registration_parms::Pointer regp = d_ptr->rparms; Xform::Pointer xf_out = Xform::New (); Plm_timer timer1, timer2, timer3; /* Start logging */ logfile_open (regp->log_fn.c_str()); timer1.start(); this->load_global_inputs (); timer1.stop(); timer2.start(); this->start_registration (); this->wait_for_complete (); xf_out = this->get_current_xform (); timer2.stop(); /* RMK: If no stages, we still generate output (same as input) */ timer3.start(); this->save_global_outputs (); timer3.stop(); logfile_open (regp->log_fn.c_str()); logfile_printf ( "Load: %g\n" "Run: %g\n" "Save: %g\n" "Total: %g\n", (double) timer1.report(), (double) timer2.report(), (double) timer3.report(), (double) timer1.report() + (double) timer2.report() + (double) timer3.report()); /* Done logging */ logfile_printf ("Finished!\n"); logfile_close (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/registration.h000066400000000000000000000031361321604176500313310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _registration_h_ #define _registration_h_ #include "plmregister_config.h" #include "registration_data.h" #include "registration_parms.h" #include "xform.h" class Registration_private; class PLMREGISTER_API Registration { public: SMART_POINTER_SUPPORT (Registration); Registration_private *d_ptr; public: Registration (); ~Registration (); public: Plm_return_code set_command_file (const std::string& command_file); Plm_return_code set_command_string (const std::string& command_string); void set_fixed_image (Plm_image::Pointer& fixed); void set_moving_image (Plm_image::Pointer& moving); void set_fixed_roi (Plm_image::Pointer& fixed_roi); void set_moving_roi (Plm_image::Pointer& moving_roi); Registration_data::Pointer get_registration_data (); Registration_parms::Pointer get_registration_parms (); /* New API */ void load_global_inputs (); void start_registration (); void pause_registration (); void resume_registration (); void wait_for_complete (); /* Wrapper around new API, to emulate old API */ void do_registration (); Xform::Pointer do_registration_pure (); Xform::Pointer get_current_xform (); void save_global_outputs (); /* This is called by worker thread */ void run_main_thread (); protected: Xform::Pointer do_registration_stage (Stage_parms* stage); }; #endif registration_data.cxx000066400000000000000000000243511321604176500326200ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "distance_map.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_type.h" #include "print_and_exit.h" #include "registration_data.h" #include "registration_parms.h" #include "registration_resample.h" #include "shared_parms.h" #include "stage_parms.h" #include "volume_grad.h" class Registration_data_private { public: Stage_parms auto_parms; std::map similarity_images; std::list similarity_indices; public: Registration_data_private () { } ~Registration_data_private () { } }; Registration_data::Registration_data () { fixed_landmarks = 0; moving_landmarks = 0; d_ptr = new Registration_data_private; } Registration_data::~Registration_data () { if (fixed_landmarks) delete fixed_landmarks; if (moving_landmarks) delete moving_landmarks; delete d_ptr; } void Registration_data::load_global_input_files (Registration_parms::Pointer& regp) { this->load_shared_input_files (regp->get_shared_parms()); } void Registration_data::load_stage_input_files (const Stage_parms* stage) { this->load_shared_input_files (stage->get_shared_parms()); } void Registration_data::load_shared_input_files (const Shared_parms* shared) { std::map::const_iterator metric_it; for (metric_it = shared->metric.begin(); metric_it != shared->metric.end(); ++metric_it) { const std::string& index = metric_it->first; const Metric_parms& mp = metric_it->second; /* Sanity check -- there should be at least a fixed and moving */ if (mp.fixed_fn == "") { continue; } if (mp.moving_fn == "") { continue; } /* Load images */ logfile_printf ("Loading fixed image [%s]: %s\n", index.c_str(), mp.fixed_fn.c_str()); this->set_fixed_image (index, Plm_image::New (mp.fixed_fn, PLM_IMG_TYPE_ITK_FLOAT)); logfile_printf ("Loading moving image [%s]: %s\n", index.c_str(), mp.moving_fn.c_str()); this->set_moving_image (index, Plm_image::New (mp.moving_fn, PLM_IMG_TYPE_ITK_FLOAT)); /* Load rois */ if (mp.fixed_roi_fn != "") { logfile_printf ("Loading fixed roi [%s]: %s\n", index.c_str(), mp.fixed_roi_fn.c_str()); this->set_fixed_roi (index, Plm_image::New (mp.fixed_roi_fn, PLM_IMG_TYPE_ITK_UCHAR)); } if (mp.moving_roi_fn != "") { logfile_printf ("Loading moving roi [%s]: %s\n", index.c_str(), mp.moving_roi_fn.c_str()); this->set_moving_roi (index, Plm_image::New (mp.moving_roi_fn, PLM_IMG_TYPE_ITK_UCHAR)); } } /* load stiffness */ if (shared->fixed_stiffness_fn != "") { logfile_printf ("Loading fixed stiffness: %s\n", shared->fixed_stiffness_fn.c_str()); this->fixed_stiffness = Plm_image::New ( shared->fixed_stiffness_fn, PLM_IMG_TYPE_ITK_FLOAT); } /* load landmarks */ if (shared->fixed_landmarks_fn != "") { if (shared->moving_landmarks_fn != "") { logfile_printf ("Loading fixed landmarks: %s\n", shared->fixed_landmarks_fn.c_str()); fixed_landmarks = new Labeled_pointset; fixed_landmarks->load_fcsv ( shared->fixed_landmarks_fn.c_str()); logfile_printf ("Loading moving landmarks: %s\n", shared->moving_landmarks_fn.c_str()); moving_landmarks = new Labeled_pointset; moving_landmarks->load_fcsv ( shared->moving_landmarks_fn.c_str()); } else { print_and_exit ( "Sorry, you need to specify both fixed and moving landmarks"); } } else if (shared->moving_landmarks_fn != "") { print_and_exit ( "Sorry, you need to specify both fixed and moving landmarks"); } else if (shared->fixed_landmarks_list != "" && shared->moving_landmarks_list != "") { fixed_landmarks = new Labeled_pointset; moving_landmarks = new Labeled_pointset; fixed_landmarks->insert_ras (shared->fixed_landmarks_list.c_str()); moving_landmarks->insert_ras (shared->moving_landmarks_list.c_str()); } } Registration_similarity_data::Pointer& Registration_data::get_similarity_images ( std::string index) { if (index == "") { index = DEFAULT_IMAGE_KEY; } if (!d_ptr->similarity_images[index]) { d_ptr->similarity_images[index] = Registration_similarity_data::New(); } return d_ptr->similarity_images[index]; } void Registration_data::set_fixed_image (const Plm_image::Pointer& image) { this->set_fixed_image (DEFAULT_IMAGE_KEY, image); } void Registration_data::set_fixed_image ( const std::string& index, const Plm_image::Pointer& image) { this->get_similarity_images(index)->fixed = image; } void Registration_data::set_moving_image (const Plm_image::Pointer& image) { this->set_moving_image (DEFAULT_IMAGE_KEY, image); } void Registration_data::set_moving_image ( const std::string& index, const Plm_image::Pointer& image) { this->get_similarity_images(index)->moving = image; } void Registration_data::set_fixed_roi (const Plm_image::Pointer& image) { this->set_fixed_roi (DEFAULT_IMAGE_KEY, image); } void Registration_data::set_fixed_roi ( const std::string& index, const Plm_image::Pointer& image) { this->get_similarity_images(index)->fixed_roi = image; } void Registration_data::set_moving_roi (const Plm_image::Pointer& image) { this->set_moving_roi (DEFAULT_IMAGE_KEY, image); } void Registration_data::set_moving_roi ( const std::string& index, const Plm_image::Pointer& image) { this->get_similarity_images(index)->moving_roi = image; } Plm_image::Pointer& Registration_data::get_fixed_image () { return this->get_fixed_image(DEFAULT_IMAGE_KEY); } Plm_image::Pointer& Registration_data::get_fixed_image ( const std::string& index) { return this->get_similarity_images(index)->fixed; } Plm_image::Pointer& Registration_data::get_moving_image () { return this->get_moving_image(DEFAULT_IMAGE_KEY); } Plm_image::Pointer& Registration_data::get_moving_image ( const std::string& index) { return this->get_similarity_images(index)->moving; } Plm_image::Pointer& Registration_data::get_fixed_roi () { return this->get_fixed_roi(DEFAULT_IMAGE_KEY); } Plm_image::Pointer& Registration_data::get_fixed_roi ( const std::string& index) { return this->get_similarity_images(index)->fixed_roi; } Plm_image::Pointer& Registration_data::get_moving_roi () { return this->get_moving_roi(DEFAULT_IMAGE_KEY); } Plm_image::Pointer& Registration_data::get_moving_roi ( const std::string& index) { return this->get_similarity_images(index)->moving_roi; } const std::list& Registration_data::get_similarity_indices () { d_ptr->similarity_indices.clear (); std::map::const_iterator it; for (it = d_ptr->similarity_images.begin(); it != d_ptr->similarity_images.end(); ++it) { if (it->second->fixed && it->second->moving) { if (it->first == DEFAULT_IMAGE_KEY) { d_ptr->similarity_indices.push_front (it->first); } else { d_ptr->similarity_indices.push_back (it->first); } } } return d_ptr->similarity_indices; } Stage_parms* Registration_data::get_auto_parms () { return &d_ptr->auto_parms; } static Volume::Pointer make_dmap (const Volume::Pointer& image) { Plm_image::Pointer pi = Plm_image::New (image); Distance_map dm; dm.set_input_image (pi); dm.run (); Plm_image im_out (dm.get_output_image()); return im_out.get_volume_float (); } void populate_similarity_list ( std::list& similarity_data, Registration_data *regd, const Stage_parms *stage ) { const Shared_parms *shared = stage->get_shared_parms(); /* Clear out the list */ similarity_data.clear (); const std::list& similarity_indices = regd->get_similarity_indices (); std::list::const_iterator ind_it; for (ind_it = similarity_indices.begin(); ind_it != similarity_indices.end(); ++ind_it) { Plm_image::Pointer fixed_image = regd->get_fixed_image (*ind_it); Plm_image::Pointer moving_image = regd->get_moving_image (*ind_it); Volume::Pointer& fixed = fixed_image->get_volume_float (); Volume::Pointer& moving = moving_image->get_volume_float (); Metric_state::Pointer ssi = Metric_state::New(); /* Subsample images */ ssi->fixed_ss = registration_resample_volume ( fixed, stage, stage->resample_rate_fixed); ssi->moving_ss = registration_resample_volume ( moving, stage, stage->resample_rate_moving); /* Metric */ const Metric_parms& metric_parms = shared->metric.find(*ind_it)->second; ssi->metric_type = metric_parms.metric_type; if (ssi->metric_type == SIMILARITY_METRIC_MI_VW) { ssi->metric_type = SIMILARITY_METRIC_MI_MATTES; } ssi->metric_lambda = metric_parms.metric_lambda; /* Gradient magnitude is MSE on gradient image */ if (ssi->metric_type == SIMILARITY_METRIC_GM) { ssi->fixed_ss = volume_gradient_magnitude (ssi->fixed_ss); ssi->moving_ss = volume_gradient_magnitude (ssi->moving_ss); } /* Distance map is MSE on distance map images */ if (ssi->metric_type == SIMILARITY_METRIC_DMAP) { ssi->fixed_ss = make_dmap (ssi->fixed_ss); ssi->moving_ss = make_dmap (ssi->moving_ss); } /* Make spatial gradient image */ ssi->moving_grad = volume_gradient (ssi->moving_ss); /* Append to list */ similarity_data.push_back (ssi); } } registration_data.h000066400000000000000000000062431321604176500322450ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _registration_data_h_ #define _registration_data_h_ #include "plmregister_config.h" #include "itk_image_type.h" #include "metric_state.h" #include "plm_image.h" #include "pointset.h" #include "registration_parms.h" #include "registration_similarity_data.h" #include "smart_pointer.h" class Plm_image; class Registration_data_private; class Shared_parms; class Stage_parms; /*! \brief * The Registration_data class holds global data shared across multiple * registration stages. These data include images, landmarks, * ROIs, and automatic parameters. */ class PLMREGISTER_API Registration_data { public: SMART_POINTER_SUPPORT (Registration_data); Registration_data_private *d_ptr; public: Registration_data (); ~Registration_data (); public: /* Regularization stiffness image */ Plm_image::Pointer fixed_stiffness; /* Input landmarks */ Labeled_pointset *fixed_landmarks; Labeled_pointset *moving_landmarks; /* Region of interest */ FloatImageType::RegionType fixed_region; FloatImageType::PointType fixed_region_origin; FloatImageType::SpacingType fixed_region_spacing; public: void load_global_input_files (Registration_parms::Pointer& regp); void load_stage_input_files (const Stage_parms* regp); void load_shared_input_files (const Shared_parms* shared); Registration_similarity_data::Pointer& get_similarity_images (std::string index); void set_fixed_image (const Plm_image::Pointer& image); void set_fixed_image (const std::string& index, const Plm_image::Pointer& image); void set_moving_image (const Plm_image::Pointer& image); void set_moving_image (const std::string& index, const Plm_image::Pointer& image); void set_fixed_roi (const Plm_image::Pointer& image); void set_fixed_roi (const std::string& index, const Plm_image::Pointer& image); void set_moving_roi (const Plm_image::Pointer& image); void set_moving_roi (const std::string& index, const Plm_image::Pointer& image); Plm_image::Pointer& get_fixed_image (); Plm_image::Pointer& get_fixed_image (const std::string& index); Plm_image::Pointer& get_moving_image (); Plm_image::Pointer& get_moving_image (const std::string& index); Plm_image::Pointer& get_fixed_roi (); Plm_image::Pointer& get_fixed_roi (const std::string& index); Plm_image::Pointer& get_moving_roi (); Plm_image::Pointer& get_moving_roi (const std::string& index); /*! \brief Get list of indices which have both a fixed and moving image. The default image (index "0") will be the first index in the list. The remaining indices will be sorted in order they appear in the command file. */ const std::list& get_similarity_indices (); Stage_parms* get_auto_parms (); }; void populate_similarity_list ( std::list& similarity_data, Registration_data *regd, const Stage_parms *stage ); #endif registration_parms.cxx000066400000000000000000001047511321604176500330340ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include #include #include #include #include #include "groupwise_parms.h" #include "logfile.h" #include "parameter_parser.h" #include "plm_return_code.h" #include "registration_parms.h" #include "shared_parms.h" #include "stage_parms.h" #include "string_util.h" class Registration_parms_private { public: std::list stages; Shared_parms *shared; Groupwise_parms *gw_parms; public: Registration_parms_private () { shared = new Shared_parms; gw_parms = 0; } ~Registration_parms_private () { delete_all_stages (); delete shared; delete gw_parms; } void delete_all_stages () { std::list::iterator it; for (it = stages.begin(); it != stages.end(); it++) { delete *it; } stages.clear (); } }; class Registration_parms_parser : public Parameter_parser { public: Registration_parms *rp; public: Registration_parms_parser (Registration_parms *rp) { this->rp = rp; this->enable_key_regularization (true); this->set_default_index (DEFAULT_IMAGE_KEY); } public: virtual Plm_return_code begin_section ( const std::string& section) { if (section == "GLOBAL") { return PLM_SUCCESS; } if (section == "STAGE") { rp->append_stage (); return PLM_SUCCESS; } if (section == "COMMENT") { return PLM_SUCCESS; } if (section == "PROCESS") { rp->append_process_stage (); return PLM_SUCCESS; } /* else, unknown section */ return PLM_ERROR; } virtual Plm_return_code end_section ( const std::string& section) { /* Do nothing */ return PLM_SUCCESS; } virtual Plm_return_code set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val) { return this->rp->set_key_value (section, key, index, val); } }; Registration_parms::Registration_parms() { d_ptr = new Registration_parms_private; img_out_fmt = IMG_OUT_FMT_AUTO; img_out_type = PLM_IMG_TYPE_UNDEFINED; xf_out_itk = false; init_type = STAGE_TRANSFORM_NONE; default_value = 0.0; num_stages = 0; } Registration_parms::~Registration_parms() { delete d_ptr; } Plm_return_code Registration_parms::set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val) { int rc; Stage_parms *stage = 0; Shared_parms *shared = 0; Process_parms::Pointer process; bool section_global = false; bool section_stage = false; bool section_process = false; if (section == "COMMENT") { return PLM_SUCCESS; } if (section == "GLOBAL") { shared = d_ptr->shared; section_global = true; } else if (section == "STAGE") { stage = d_ptr->stages.back(); shared = stage->get_shared_parms(); section_stage = true; } else if (section == "PROCESS") { stage = d_ptr->stages.back(); process = stage->get_process_parms(); section_process = true; } /* The following keywords are only allowed globally */ if (key == "xf_in" || key == "xform_in" || key == "vf_in") { if (!section_global) goto key_only_allowed_in_section_global; this->xf_in_fn = val; } else if (key == "log" || key == "logfile") { if (!section_global) goto key_only_allowed_in_section_global; this->log_fn = val; } else if (key == "group_dir") { if (!section_global) goto key_only_allowed_in_section_global; this->group_dir = val; } /* The following keywords are allowed either globally or in stages */ else if (key == "fixed") { if (section_process) goto key_not_allowed_in_section_process; shared->metric[index].fixed_fn = val; } else if (key == "moving") { if (section_process) goto key_not_allowed_in_section_process; shared->metric[index].moving_fn = val; } else if (key == "background_val" || key == "default_value") { float f; if (sscanf (val.c_str(), "%g", &f) != 1) { goto error_exit; } if (section_global) { this->default_value = f; } else if (section_stage) { stage->default_value = f; } else { goto key_not_allowed_in_section_process; } } else if (key == "fixed_mask" || key == "fixed_roi") { if (section_process) goto key_not_allowed_in_section_process; shared->metric[index].fixed_roi_fn = val; } else if (key == "moving_mask" || key == "moving_roi") { if (section_process) goto key_not_allowed_in_section_process; shared->metric[index].moving_roi_fn = val; } else if (key == "fixed_roi_enable") { if (section_process) goto key_not_allowed_in_section_process; shared->fixed_roi_enable = string_value_true (val); } else if (key == "moving_roi_enable") { if (section_process) goto key_not_allowed_in_section_process; shared->moving_roi_enable = string_value_true (val); } else if (key == "fixed_stiffness") { if (section_process) goto key_not_allowed_in_section_process; shared->fixed_stiffness_fn = val; } else if (key == "fixed_stiffness_enable") { if (section_process) goto key_not_allowed_in_section_process; shared->fixed_stiffness_enable = string_value_true (val); } else if (key == "legacy_subsampling") { if (section_process) goto key_not_allowed_in_section_process; shared->legacy_subsampling = string_value_true (val); } else if (key == "img_out" || key == "image_out") { if (section_global) { this->img_out_fn = val; } else if (section_stage) { stage->img_out_fn = val; } else { goto key_not_allowed_in_section_process; } } else if (key == "img_out_fmt") { int fmt = IMG_OUT_FMT_AUTO; if (val == "dicom") { fmt = IMG_OUT_FMT_DICOM; } else { goto error_exit; } if (section_global) { this->img_out_fmt = fmt; } else if (section_stage) { stage->img_out_fmt = fmt; } else { goto key_not_allowed_in_section_process; } } else if (key == "img_out_type") { Plm_image_type type = plm_image_type_parse (val.c_str()); if (type == PLM_IMG_TYPE_UNDEFINED) { goto error_exit; } if (section_global) { this->img_out_type = type; } else if (section_stage) { stage->img_out_type = type; } else { goto key_not_allowed_in_section_process; } } else if (key == "vf_out") { if (section_global) { this->vf_out_fn = val; } else if (section_stage) { stage->vf_out_fn = val; } else { goto key_not_allowed_in_section_process; } } else if (key == "xf_out_itk") { bool value; if (string_value_true (val)) { value = true; } else { value = false; } if (section_global) { this->xf_out_itk = value; } else if (section_stage) { stage->xf_out_itk = value; } else { goto key_not_allowed_in_section_process; } } else if (key == "xf_out" || key == "xform_out") { /* xf_out is special. You can have more than one of these. This capability is used by the slicer plugin. */ if (section_global) { this->xf_out_fn.push_back (val.c_str()); } else if (section_stage) { stage->xf_out_fn.push_back (val.c_str()); } else { goto key_not_allowed_in_section_process; } } else if (key == "valid_roi_out") { if (section_process) goto key_not_allowed_in_section_process; shared->valid_roi_out_fn = val; } else if (key == "fixed_landmarks") { if (section_process) goto key_not_allowed_in_section_process; shared->fixed_landmarks_fn = val; } else if (key == "moving_landmarks") { if (section_process) goto key_not_allowed_in_section_process; shared->moving_landmarks_fn = val; } else if (key == "fixed_landmark_list") { if (section_process) goto key_not_allowed_in_section_process; shared->fixed_landmarks_list = val; } else if (key == "moving_landmark_list") { if (section_process) goto key_not_allowed_in_section_process; shared->moving_landmarks_list = val; } else if (key == "warped_landmarks") { if (section_process) goto key_not_allowed_in_section_process; shared->warped_landmarks_fn = val; } /* The following keywords are only allowed in stages */ else if (key == "num_substages") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->num_substages) != 1) { goto error_exit; } } else if (key == "flavor" || key == "alg_flavor") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val.length() >= 1) { stage->alg_flavor = val[0]; } else { goto error_exit; } } else if (key == "resume") { if (!section_stage) goto key_only_allowed_in_section_stage; if (string_value_true (val)) { stage->resume_stage = true; } } else if (key == "xform") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val == "translation") { stage->xform_type = STAGE_TRANSFORM_TRANSLATION; } else if (val == "rigid" || val == "versor") { stage->xform_type = STAGE_TRANSFORM_VERSOR; } else if (val == "quaternion") { stage->xform_type = STAGE_TRANSFORM_QUATERNION; } else if (val == "affine") { stage->xform_type = STAGE_TRANSFORM_AFFINE; } else if (val == "similarity") { stage->xform_type = STAGE_TRANSFORM_SIMILARITY; } else if (val == "bspline") { stage->xform_type = STAGE_TRANSFORM_BSPLINE; } else if (val == "vf") { stage->xform_type = STAGE_TRANSFORM_VECTOR_FIELD; } else if (val == "align_center") { stage->xform_type = STAGE_TRANSFORM_ALIGN_CENTER; } else if (val == "align_center_of_gravity") { stage->xform_type = STAGE_TRANSFORM_ALIGN_CENTER_OF_GRAVITY; } else { goto error_exit; } } else if (key == "optim") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val == "none") { stage->optim_type = OPTIMIZATION_NO_REGISTRATION; } else if (val == "amoeba") { stage->optim_type = OPTIMIZATION_AMOEBA; } else if (val == "demons") { stage->optim_type = OPTIMIZATION_DEMONS; } else if (val == "frpr") { stage->optim_type = OPTIMIZATION_FRPR; } else if (val == "grid" || val == "grid_search" || val == "gridsearch") { stage->optim_type = OPTIMIZATION_GRID_SEARCH; } else if (val == "lbfgs") { stage->optim_type = OPTIMIZATION_LBFGS; } else if (val == "lbfgsb") { stage->optim_type = OPTIMIZATION_LBFGSB; } else if (val == "liblbfgs") { stage->optim_type = OPTIMIZATION_LIBLBFGS; } else if (val == "nocedal") { stage->optim_type = OPTIMIZATION_LBFGSB; } else if (val == "oneplusone") { stage->optim_type = OPTIMIZATION_ONEPLUSONE; } else if (val == "rsg") { stage->optim_type = OPTIMIZATION_RSG; } else if (val == "steepest") { stage->optim_type = OPTIMIZATION_STEEPEST; } else if (val == "versor") { stage->optim_type = OPTIMIZATION_VERSOR; } else { goto error_exit; } } else if (key == "impl") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val == "none") { stage->impl_type = IMPLEMENTATION_NONE; } else if (val == "itk") { stage->impl_type = IMPLEMENTATION_ITK; } else if (val == "plastimatch") { stage->impl_type = IMPLEMENTATION_PLASTIMATCH; } else { goto error_exit; } } else if (key == "optim_subtype") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val == "fsf") { stage->optim_subtype = OPTIMIZATION_SUB_FSF; } else if (val == "diffeomorphic") { stage->optim_subtype = OPTIMIZATION_SUB_DIFF_ITK; } else if (val == "log_domain") { stage->optim_subtype = OPTIMIZATION_SUB_LOGDOM_ITK; } else if (val == "sym_log_domain") { stage->optim_subtype = OPTIMIZATION_SUB_SYM_LOGDOM_ITK; } else { goto error_exit; } } else if (key == "threading") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val == "single") { stage->threading_type = THREADING_CPU_SINGLE; } else if (val == "openmp") { #if (OPENMP_FOUND) stage->threading_type = THREADING_CPU_OPENMP; #else stage->threading_type = THREADING_CPU_SINGLE; #endif } else if (val == "cuda") { #if (CUDA_FOUND) stage->threading_type = THREADING_CUDA; #elif (OPENMP_FOUND) stage->threading_type = THREADING_CPU_OPENMP; #else stage->threading_type = THREADING_CPU_SINGLE; #endif } else { goto error_exit; } } else if (key == "gpuid") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->gpuid) != 1) { goto error_exit; } } else if (key == "metric" || key == "smetric") { if (!section_stage) goto key_only_allowed_in_section_stage; if (shared->metric[index].set_metric_type (val) != PLM_SUCCESS) { goto error_exit; } } else if (key == "metric_lambda" || key == "smetric_lambda") { if (!section_stage) goto key_only_allowed_in_section_stage; float f; if (sscanf (val.c_str(), "%f", &f) != 1) { goto error_exit; } shared->metric[index].metric_lambda = f; } else if (key == "histogram_type") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val == "eqsp" || val == "EQSP") { stage->mi_hist_type = HIST_EQSP; } else if (val == "vopt" || val == "VOPT") { stage->mi_hist_type = HIST_VOPT; } else { goto error_exit; } } else if (key == "regularization") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val == "none") { stage->regularization_type = REGULARIZATION_NONE; } else if (val == "analytic") { stage->regularization_type = REGULARIZATION_BSPLINE_ANALYTIC; } else if (val == "semi_analytic") { stage->regularization_type = REGULARIZATION_BSPLINE_SEMI_ANALYTIC; } else if (val == "numeric") { stage->regularization_type = REGULARIZATION_BSPLINE_NUMERIC; } else { goto error_exit; } } else if (key == "regularization_lambda" || key == "young_modulus") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%f", &stage->regularization_lambda) != 1) { goto error_exit; } } else if (key == "background_max") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->background_max) != 1) { goto error_exit; } } else if (key == "min_its") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->min_its) != 1) { goto error_exit; } } else if (key == "iterations" || key == "max_iterations" || key == "max_its" || key == "its") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->max_its) != 1) { goto error_exit; } } else if (key == "learn_rate") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->learn_rate) != 1) { goto error_exit; } } else if (key == "grad_tol") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->grad_tol) != 1) { goto error_exit; } } else if (key == "pgtol") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%f", &stage->pgtol) != 1) { goto error_exit; } } else if (key == "lbfgsb_mmax") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->lbfgsb_mmax) != 1) { goto error_exit; } } else if (key == "max_step") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->max_step) != 1) { goto error_exit; } } else if (key == "min_step") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->min_step) != 1) { goto error_exit; } } else if (key == "rsg_grad_tol") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->rsg_grad_tol) != 1) { goto error_exit; } } else if (key == "translation_scale_factor") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->translation_scale_factor) != 1) { goto error_exit; } } else if (key == "rotation_scale_factor") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->rotation_scale_factor) != 1) { goto error_exit; } } else if (key == "scaling_scale_factor") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%f", &stage->scaling_scale_factor) != 1) { goto error_exit; } } else if (key == "convergence_tol") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->convergence_tol) != 1) { goto error_exit; } } else if (key == "opo_epsilon") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->opo_epsilon) != 1) { goto error_exit; } } else if (key == "opo_initial_search_rad") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->opo_initial_search_rad) != 1) { goto error_exit; } } else if (key == "frpr_step_tol") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->frpr_step_tol) != 1) { goto error_exit; } } else if (key == "frpr_step_length") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->frpr_step_length) != 1) { goto error_exit; } } else if (key == "frpr_max_line_its") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->frpr_max_line_its) != 1) { goto error_exit; } } else if (key == "mattes_histogram_bins" || key == "mi_histogram_bins") { if (!section_stage) goto key_only_allowed_in_section_stage; rc = sscanf (val.c_str(), "%d %d", &stage->mi_hist_fixed_bins, &stage->mi_hist_moving_bins); if (rc == 1) { stage->mi_hist_moving_bins = stage->mi_hist_fixed_bins; } else if (rc != 2) { goto error_exit; } } else if (key == "mattes_fixed_minVal" || key == "mi_fixed_minVal") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->mi_fixed_image_minVal) != 1) { goto error_exit; } } else if (key == "mattes_fixed_maxVal" || key == "mi_fixed_maxVal") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->mi_fixed_image_maxVal) != 1) { goto error_exit; } } else if (key == "mattes_moving_minVal" || key == "mi_moving_minVal") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->mi_moving_image_minVal) != 1) { goto error_exit; } } else if (key == "mattes_moving_maxVal" || key == "mi_moving_maxVal") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->mi_moving_image_maxVal) != 1) { goto error_exit; } } else if (key == "num_samples" || key == "mattes_num_spatial_samples" || key == "mi_num_spatial_samples") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->mi_num_spatial_samples) != 1) { goto error_exit; } } else if (key == "num_samples_pct") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%f", &stage->mi_num_spatial_samples_pct) != 1) { goto error_exit; } } else if ((key == "demons_std_deformation_field") || (key == "demons_std")) { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->demons_std) != 1) { goto error_exit; } } else if (key == "demons_std_update_field") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->demons_std_update_field) != 1) { goto error_exit; } } else if (key == "demons_step_length") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->demons_step_length) != 1) { goto error_exit; } } else if (key == "demons_smooth_deformation_field") { if (!section_stage) goto key_only_allowed_in_section_stage; if (string_value_true (val)) { stage->demons_smooth_deformation_field = true; } else stage->demons_smooth_deformation_field = false; } else if (key == "demons_smooth_update_field") { if (!section_stage) goto key_only_allowed_in_section_stage; if (string_value_true (val)) { stage->demons_smooth_update_field = true; } else stage->demons_smooth_update_field = false; } else if (key == "demons_gradient_type") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val == "symmetric") { stage->demons_gradient_type = SYMMETRIC; } else if (val == "fixed") { stage->demons_gradient_type = FIXED_IMAGE; } else if (val == "warped_moving") { stage->demons_gradient_type = WARPED_MOVING; } else if (val == "mapped_moving") { stage->demons_gradient_type = MAPPED_MOVING; } else { goto error_exit; } } else if (key == "num_approx_terms_log_demons") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->num_approx_terms_log_demons) != 1) { goto error_exit; } } else if (key == "demons_acceleration") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->demons_acceleration) != 1) { goto error_exit; } } else if (key == "demons_homogenization") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->demons_homogenization) != 1) { goto error_exit; } } else if (key == "demons_filter_width") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d %d %d", &(stage->demons_filter_width[0]), &(stage->demons_filter_width[1]), &(stage->demons_filter_width[2])) != 3) { goto error_exit; } } else if (key == "amoeba_parameter_tol") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &(stage->amoeba_parameter_tol)) != 1) { goto error_exit; } } else if (key == "gridsearch_min_overlap") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g %g %g", &(stage->gridsearch_min_overlap[0]), &(stage->gridsearch_min_overlap[1]), &(stage->gridsearch_min_overlap[2])) != 3) { goto error_exit; } } else if (key == "gridsearch_min_steps") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d %d %d", &(stage->gridsearch_min_steps[0]), &(stage->gridsearch_min_steps[1]), &(stage->gridsearch_min_steps[2])) != 3) { goto error_exit; } } else if (key == "gridsearch_strategy") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val == "global") { stage->gridsearch_strategy = GRIDSEARCH_STRATEGY_GLOBAL; } else if (val == "local") { stage->gridsearch_strategy = GRIDSEARCH_STRATEGY_LOCAL; } else { goto error_exit; } } else if (key == "stages") { if (!section_stage) goto key_only_allowed_in_section_stage; if (val == "global") { } } else if (key == "landmark_stiffness") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->landmark_stiffness) != 1) { goto error_exit; } } else if (key == "landmark_flavor") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%c", &stage->landmark_flavor) != 1) { goto error_exit; } } else if (key == "overlap_penalty_lambda") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->overlap_penalty_lambda) != 1) { goto error_exit; } } else if (key == "overlap_penalty_fraction") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g", &stage->overlap_penalty_fraction) != 1) { goto error_exit; } } else if (key == "res_vox" || key == "res" || key == "ss") { if (!section_stage) goto key_only_allowed_in_section_stage; Plm_return_code rc = stage->set_resample (val); if (rc != PLM_SUCCESS) { goto error_exit; } stage->resample_type = RESAMPLE_VOXEL_RATE; } else if (key == "res_vox_fixed" || key == "ss_fixed" || key == "fixed_ss") { if (!section_stage) goto key_only_allowed_in_section_stage; Plm_return_code rc = stage->set_resample_fixed (val); if (rc != PLM_SUCCESS) { goto error_exit; } stage->resample_type = RESAMPLE_VOXEL_RATE; } else if (key == "res_vox_moving" || key == "ss_moving" || key == "moving_ss") { if (!section_stage) goto key_only_allowed_in_section_stage; Plm_return_code rc = stage->set_resample_moving (val); if (rc != PLM_SUCCESS) { goto error_exit; } stage->resample_type = RESAMPLE_VOXEL_RATE; } else if (key == "res_mm") { if (!section_stage) goto key_only_allowed_in_section_stage; Plm_return_code rc = stage->set_resample (val); if (rc != PLM_SUCCESS) { goto error_exit; } stage->resample_type = RESAMPLE_MM; } else if (key == "res_mm_fixed") { if (!section_stage) goto key_only_allowed_in_section_stage; Plm_return_code rc = stage->set_resample_fixed (val); if (rc != PLM_SUCCESS) { goto error_exit; } stage->resample_type = RESAMPLE_MM; } else if (key == "res_mm_moving") { if (!section_stage) goto key_only_allowed_in_section_stage; Plm_return_code rc = stage->set_resample_moving (val); if (rc != PLM_SUCCESS) { goto error_exit; } stage->resample_type = RESAMPLE_MM; } else if (key == "res_pct") { if (!section_stage) goto key_only_allowed_in_section_stage; Plm_return_code rc = stage->set_resample (val); if (rc != PLM_SUCCESS) { goto error_exit; } stage->resample_type = RESAMPLE_PCT; } else if (key == "res_pct_fixed") { if (!section_stage) goto key_only_allowed_in_section_stage; Plm_return_code rc = stage->set_resample_fixed (val); if (rc != PLM_SUCCESS) { goto error_exit; } stage->resample_type = RESAMPLE_PCT; } else if (key == "res_pct_moving") { if (!section_stage) goto key_only_allowed_in_section_stage; Plm_return_code rc = stage->set_resample_moving (val); if (rc != PLM_SUCCESS) { goto error_exit; } stage->resample_type = RESAMPLE_PCT; } else if (key == "grid_spac" || key == "grid_spacing") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%g %g %g", &(stage->grid_spac[0]), &(stage->grid_spac[1]), &(stage->grid_spac[2])) != 3) { goto error_exit; } } else if (key == "histo_equ") { if (!section_stage) goto key_only_allowed_in_section_stage; if (string_value_true (val)) { stage->histoeq = true; } else stage->histoeq= false; } else if (key == "thresh_mean_intensity") { if (!section_stage) goto key_only_allowed_in_section_stage; if (string_value_true (val)) { stage->thresh_mean_intensity = true; } else stage->thresh_mean_intensity= false; } else if (key == "num_hist_levels") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->num_hist_levels) != 1) { goto error_exit; } } else if (key == "num_matching_points") { if (!section_stage) goto key_only_allowed_in_section_stage; if (sscanf (val.c_str(), "%d", &stage->num_matching_points) != 1) { goto error_exit; } } else if (key == "debug_dir") { if (!section_stage) goto key_only_allowed_in_section_stage; stage->debug_dir = val; } /* The following keywords are only allowed in process section */ else if (section_process) { Process_parms::Pointer pp = stage->get_process_parms (); if (key == "action") { pp->set_action (val); } else { pp->set_key_value (key, val); } } else { goto error_exit; } return PLM_SUCCESS; key_only_allowed_in_section_global: lprintf ( "This key (%s) is only allowed in a global section\n", key.c_str()); return PLM_ERROR; key_only_allowed_in_section_stage: lprintf ( "This key (%s) is only allowed in a stage section\n", key.c_str()); return PLM_ERROR; key_not_allowed_in_section_process: lprintf ( "This key (%s) not is allowed in a process section\n", key.c_str()); return PLM_ERROR; error_exit: lprintf ( "Unknown (key,val) combination: (%s,%s)\n", key.c_str(), val.c_str()); return PLM_ERROR; } Plm_return_code Registration_parms::set_command_string ( const std::string& command_string ) { this->delete_all_stages (); Registration_parms_parser rpp (this); return rpp.parse_config_string (command_string); } Plm_return_code Registration_parms::parse_command_file (const char* options_fn) { /* Read file into string */ std::ifstream t (options_fn); std::stringstream buffer; buffer << t.rdbuf(); /* Parse the string */ return this->set_command_string (buffer.str()); } Shared_parms* Registration_parms::get_shared_parms () { return d_ptr->shared; } void Registration_parms::delete_all_stages () { d_ptr->delete_all_stages (); this->num_stages = 0; } std::list& Registration_parms::get_stages () { return d_ptr->stages; } Stage_parms* Registration_parms::append_stage () { Stage_parms *sp; this->num_stages ++; if (this->num_stages == 1) { sp = new Stage_parms(); } else { sp = new Stage_parms(*d_ptr->stages.back()); } d_ptr->stages.push_back (sp); /* Some parameters that should be copied from global to the first stage. */ if (this->num_stages == 1) { sp->default_value = this->default_value; } sp->stage_no = this->num_stages; return sp; } Stage_parms* Registration_parms::append_process_stage () { Stage_parms *sp = this->append_stage (); Process_parms::Pointer pp = Process_parms::New (); sp->set_process_parms (pp); return sp; } registration_parms.h000066400000000000000000000040111321604176500324450ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _registration_parms_h_ #define _registration_parms_h_ #include "plmregister_config.h" #include #include #include #include #include "bspline.h" /* for enums */ #include "plm_image_type.h" #include "plm_return_code.h" #include "smart_pointer.h" #include "threading.h" class Groupwise_parms; class Plm_image; class Registration_parms_private; class Shared_parms; class Stage_parms; #define DEFAULT_IMAGE_KEY "0" class PLMREGISTER_API Registration_parms { public: SMART_POINTER_SUPPORT (Registration_parms); Registration_parms_private *d_ptr; public: int num_stages; int img_out_fmt; Plm_image_type img_out_type; std::string img_out_fn; std::string xf_in_fn; bool xf_out_itk; std::list xf_out_fn; std::string vf_out_fn; std::string log_fn; float default_value; /* Replacement when out-of-view */ int init_type; double init[12]; /* for 4D and atlas */ std::string moving_dir; std::string fixed_dir; std::string img_out_dir; std::string vf_out_dir; /* for groupwise registration */ std::string group_dir; public: Registration_parms(); ~Registration_parms(); public: Plm_return_code set_command_string (const std::string& command_string); Plm_return_code set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val); Plm_return_code parse_command_file (const char* options_fn); void set_job_paths (void); public: Shared_parms* get_shared_parms (); void delete_all_stages (); std::list& get_stages (); Stage_parms* append_stage (); Stage_parms* append_process_stage (); Groupwise_parms* get_groupwise_parms (); }; #endif registration_resample.cxx000066400000000000000000000035231321604176500335150ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "logfile.h" #include "print_and_exit.h" #include "registration_resample.h" #include "shared_parms.h" #include "volume_resample.h" Volume::Pointer registration_resample_volume ( const Volume::Pointer& vol, const Stage_parms* stage, const float resample_rate[3] ) { const Shared_parms *shared = stage->get_shared_parms (); lprintf ("RESAMPLE %d %d: (%g %g %g), (%g %g %g)\n", stage->resample_type, shared->legacy_subsampling, stage->resample_rate_fixed[0], stage->resample_rate_fixed[1], stage->resample_rate_fixed[2], stage->resample_rate_moving[0], stage->resample_rate_moving[1], stage->resample_rate_moving[2] ); switch (stage->resample_type) { case RESAMPLE_AUTO: case RESAMPLE_VOXEL_RATE: if (resample_rate[0] == 1.0f && resample_rate[1] == 1.0f && resample_rate[2] == 1.0f) { return vol->clone (); } if (shared->legacy_subsampling) { return volume_subsample_vox_legacy (vol, resample_rate); } else { return volume_subsample_vox (vol, resample_rate); } break; case RESAMPLE_MM: return volume_resample_spacing (vol, resample_rate); break; case RESAMPLE_PCT: return volume_resample_percent (vol, resample_rate); break; default: print_and_exit ("Unhandled resample_type %d " "in registration_resample_volume()\n", stage->resample_type); break; } /* Return null pointer on error */ return Volume::Pointer(); } registration_resample.h000066400000000000000000000010201321604176500331300ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _registration_resample_h_ #define _registration_resample_h_ #include "plmregister_config.h" #include "stage_parms.h" #include "volume.h" Volume::Pointer registration_resample_volume ( const Volume::Pointer& vol, const Stage_parms* stage, const float resample_rate[3] ); #endif registration_similarity_data.h000066400000000000000000000014041321604176500345050ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _registration_similarity_data_h_ #define _registration_similarity_data_h_ #include "plmregister_config.h" /*! \brief * The Registration_similarity_data class holds original or processed * images used for similarity measure calculations over multiple stages. */ class PLMREGISTER_API Registration_similarity_data { public: SMART_POINTER_SUPPORT (Registration_similarity_data); public: Plm_image::Pointer fixed; Plm_image::Pointer moving; Plm_image::Pointer fixed_roi; Plm_image::Pointer moving_roi; }; #endif registration_util.cxx000066400000000000000000000032131321604176500326560ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "registration_util.h" #include "shared_parms.h" plm_long count_fixed_voxels ( Registration_data *regd, Stage_parms* stage, FloatImageType::Pointer& fixed_ss) { // Do simple calculation if there is no ROI const Shared_parms *shared = stage->get_shared_parms(); if (!shared->fixed_roi_enable || !regd->get_fixed_roi()) { plm_long dim[3]; get_image_header (dim, 0, 0, fixed_ss); return dim[0] * dim[1] * dim[2]; } // Else, iterate through image to find voxels where ROI not zero Plm_image::Pointer& fixed_roi = regd->get_fixed_roi (); const UCharImageType::Pointer itk_fixed_roi = fixed_roi->itk_uchar (); typedef itk::ImageRegionConstIteratorWithIndex < FloatImageType > IteratorType; FloatImageType::RegionType region = fixed_ss->GetLargestPossibleRegion(); IteratorType it (fixed_ss, region); plm_long num_voxels = 0; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { FloatImageType::PointType phys_loc; fixed_ss->TransformIndexToPhysicalPoint (it.GetIndex(), phys_loc); UCharImageType::IndexType roi_idx; bool is_inside = itk_fixed_roi->TransformPhysicalPointToIndex ( phys_loc, roi_idx); if (is_inside && itk_fixed_roi->GetPixel (roi_idx)) { num_voxels ++; } } return num_voxels; } registration_util.h000066400000000000000000000010251321604176500323020ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _registration_util_h_ #define _registration_util_h_ #include "plmregister_config.h" #include "itk_image_type.h" #include "registration_data.h" #include "stage_parms.h" plm_long count_fixed_voxels (Registration_data *regd, Stage_parms* stage, FloatImageType::Pointer& fixed_ss); #endif shared_parms.cxx000066400000000000000000000032701321604176500315620ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "logfile.h" #include "registration_parms.h" #include "shared_parms.h" Shared_parms::Shared_parms () { this->metric[DEFAULT_IMAGE_KEY] = Metric_parms (); this->fixed_roi_enable = true; this->moving_roi_enable = true; this->fixed_stiffness_enable = true; /* At some future date, this will be changed to "false" */ // this->legacy_subsampling = false; this->legacy_subsampling = true; } Shared_parms::Shared_parms (const Shared_parms& s) { this->metric = s.metric; this->fixed_roi_enable = s.fixed_roi_enable; this->moving_roi_enable = s.moving_roi_enable; this->fixed_stiffness_enable = s.fixed_stiffness_enable; this->legacy_subsampling = s.legacy_subsampling; /* filenames do not propagate when copied */ } Shared_parms::~Shared_parms () { } void Shared_parms::copy (const Shared_parms *s) { this->metric = s->metric; this->fixed_roi_enable = s->fixed_roi_enable; this->moving_roi_enable = s->moving_roi_enable; this->fixed_stiffness_enable = s->fixed_stiffness_enable; this->legacy_subsampling = s->legacy_subsampling; /* filenames do not propagate when copied */ } void Shared_parms::log () { lprintf ("LOG Shared parms\n"); std::map::iterator it; for (it = this->metric.begin(); it != this->metric.end(); ++it) { lprintf ("Shared metric | %s | %d\n", it->first.c_str(), it->second.metric_type); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/shared_parms.h000066400000000000000000000021431321604176500312640ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _shared_parms_h_ #define _shared_parms_h_ #include "plmregister_config.h" #include #include #include "metric_parms.h" class PLMREGISTER_API Shared_parms { public: Shared_parms (); Shared_parms (const Shared_parms& s); ~Shared_parms (); public: /* Similarity parms */ std::map metric; /* ROI */ bool fixed_roi_enable; bool moving_roi_enable; std::string valid_roi_out_fn; /* Stiffness map */ bool fixed_stiffness_enable; std::string fixed_stiffness_fn; /* Subsampling */ bool legacy_subsampling; /* Landmarks */ std::string fixed_landmarks_fn; std::string moving_landmarks_fn; std::string fixed_landmarks_list; std::string moving_landmarks_list; std::string warped_landmarks_fn; public: void copy (const Shared_parms *s); void log (); }; #endif similarity_metric_type.cxx000066400000000000000000000015351321604176500337060ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "similarity_metric_type.h" const char* similarity_metric_type_string (Similarity_metric_type type) { switch (type) { case SIMILARITY_METRIC_NONE: return "none"; case SIMILARITY_METRIC_DMAP: return "DMAP"; case SIMILARITY_METRIC_GM: return "GM"; case SIMILARITY_METRIC_MI_MATTES: return "MI"; case SIMILARITY_METRIC_MI_VW: return "MIVW"; case SIMILARITY_METRIC_MSE: return "MSE"; case SIMILARITY_METRIC_NMI: return "NMI"; default: return "(unkn)"; } } similarity_metric_type.h000066400000000000000000000011361321604176500333300ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _similarity_metric_type_h_ #define _similarity_metric_type_h_ enum Similarity_metric_type { SIMILARITY_METRIC_NONE, SIMILARITY_METRIC_DMAP, SIMILARITY_METRIC_GM, SIMILARITY_METRIC_MI_MATTES, SIMILARITY_METRIC_MI_VW, SIMILARITY_METRIC_MSE, SIMILARITY_METRIC_NMI }; const char* similarity_metric_type_string (Similarity_metric_type); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/stage_parms.cxx000066400000000000000000000263061321604176500315030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include "shared_parms.h" #include "stage_parms.h" #include "string_util.h" class Stage_parms_private { public: Stage_type stage_type; Process_parms::Pointer process_parms; Shared_parms *shared; public: Stage_parms_private () { this->stage_type = STAGE_TYPE_REGISTER; this->shared = new Shared_parms; } Stage_parms_private (const Stage_parms_private& s) { this->stage_type = STAGE_TYPE_REGISTER; this->shared = new Shared_parms (*s.shared); } ~Stage_parms_private () { delete shared; } }; Stage_parms::Stage_parms () { d_ptr = new Stage_parms_private; /* Stage # */ stage_no = -1; /* Stage resume? */ resume_stage = false; finalize_stage = false; /* Number of substages */ num_substages = 1; /* Generic optimization parms */ xform_type = STAGE_TRANSFORM_VERSOR; optim_type = OPTIMIZATION_VERSOR; impl_type = IMPLEMENTATION_NONE; optim_subtype = OPTIMIZATION_SUB_FSF; alg_flavor = 0; threading_type = THREADING_CPU_OPENMP; gpuid = 0; /* Similarity metric */ regularization_type = REGULARIZATION_BSPLINE_ANALYTIC; demons_gradient_type = SYMMETRIC; regularization_lambda = 0.0f; /* Image resample */ resample_type = RESAMPLE_AUTO; resample_rate_fixed[0] = 4; resample_rate_fixed[1] = 4; resample_rate_fixed[2] = 1; resample_rate_moving[0] = 4; resample_rate_moving[1] = 4; resample_rate_moving[2] = 1; /* Intensity values for air */ background_max = -999.0; default_value = 0.0; /* Generic optimization parms */ min_its = 2; max_its = 25; convergence_tol = 1e-6; /* LBGFG optimizer */ grad_tol = 1.5; /* LBGFGB optimizer */ pgtol = 1.0e-5; lbfgsb_mmax = -1; /* Versor & RSG optimizer */ max_step = 1.00; min_step = 0.001; rsg_grad_tol = 0.0001; translation_scale_factor = 1000.0; rotation_scale_factor = 1; scaling_scale_factor = 10; /*OnePlusOne evolutionary optimizer*/ opo_initial_search_rad=1.01; opo_epsilon=1e-7; /*frpr optimizer*/ frpr_step_tol=0.000001; frpr_step_length=5.0; frpr_max_line_its=100; /* Quaternion optimizer */ learn_rate = 0.01 ; /* Mattes mutual information */ mi_hist_fixed_bins = 20; mi_hist_moving_bins = 20; mi_num_spatial_samples = -1; mi_num_spatial_samples_pct = 0.3; mi_hist_type = HIST_EQSP; /* MI threshold values */ /*Setting values to zero by default. In this case minVal and maxVal will be calculated from image*/ mi_fixed_image_minVal=0; mi_fixed_image_maxVal=0; mi_moving_image_minVal=0; mi_moving_image_maxVal=0; /* ITK & GPUIT demons */ demons_std = 1.0; demons_std_update_field = 1.0; demons_smooth_deformation_field =true; demons_smooth_update_field=false; demons_step_length = 2.0; num_approx_terms_log_demons=2; /* GPUIT demons */ demons_acceleration = 1.0; demons_homogenization = 1.0; demons_filter_width[0] = 3; demons_filter_width[1] = 3; demons_filter_width[2] = 3; /* ITK amoeba */ amoeba_parameter_tol = 1.0; /* Bspline parms */ grid_spac[0] = 20.; grid_spac[1] = 20.; grid_spac[2] = 20.; histoeq = false; // by default, don't do it thresh_mean_intensity=false; num_matching_points=500; num_hist_levels=1000; /* Native grid search */ gridsearch_strategy = GRIDSEARCH_STRATEGY_AUTO; gridsearch_min_overlap[0] = 0.5; gridsearch_min_overlap[1] = 0.5; gridsearch_min_overlap[2] = 0.5; gridsearch_step_size_type = GRIDSEARCH_STEP_SIZE_AUTO; gridsearch_step_size[0] = 10; gridsearch_step_size[1] = 10; gridsearch_step_size[2] = 10; gridsearch_min_steps[0] = 0; gridsearch_min_steps[1] = 0; gridsearch_min_steps[2] = 0; /* Landmarks */ landmark_stiffness = 1.0; landmark_flavor = 'a'; /* Overlap penalty */ overlap_penalty_lambda = 1.0; overlap_penalty_fraction = 0.01; /* Output files */ img_out_fmt = IMG_OUT_FMT_AUTO; img_out_type = PLM_IMG_TYPE_UNDEFINED; xf_out_itk = false; } Stage_parms::Stage_parms (const Stage_parms& s) { d_ptr = new Stage_parms_private (*s.d_ptr); /* Copy most of the parameters ... */ /* Stage # */ stage_no = s.stage_no; /* Stage resume? */ /* ** Do not copy */ /* Number of substages */ num_substages = s.num_substages; /* Generic optimization parms */ xform_type = s.xform_type; optim_type = s.optim_type; impl_type = s.impl_type; optim_subtype = s.optim_subtype; alg_flavor = s.alg_flavor; threading_type = s.threading_type; gpuid = s.gpuid; /* Similarity metric */ regularization_type = s.regularization_type; regularization_lambda = s.regularization_lambda; /* Image resample */ resample_type = s.resample_type; resample_rate_fixed[0] = s.resample_rate_fixed[0]; resample_rate_fixed[1] = s.resample_rate_fixed[1]; resample_rate_fixed[2] = s.resample_rate_fixed[2]; resample_rate_moving[0] = s.resample_rate_moving[0]; resample_rate_moving[1] = s.resample_rate_moving[1]; resample_rate_moving[2] = s.resample_rate_moving[2]; /* Intensity values for air */ background_max = s.background_max; default_value = s.default_value; /* Generic optimization parms */ min_its = s.min_its; max_its = s.max_its; convergence_tol = s.convergence_tol; /* LBGFG optimizer */ grad_tol = s.grad_tol; /* LBGFGB optimizer */ pgtol = s.pgtol; lbfgsb_mmax = s.lbfgsb_mmax; /* Versor & RSG optimizer */ max_step = s.max_step; min_step = s.min_step; rsg_grad_tol = s.rsg_grad_tol; translation_scale_factor = s.translation_scale_factor; rotation_scale_factor = s.rotation_scale_factor; scaling_scale_factor = s.scaling_scale_factor; /*OnePlusOne optmizer*/ opo_epsilon=s.opo_epsilon; opo_initial_search_rad=s.opo_initial_search_rad; /*FRPR optmizer*/ frpr_step_length=s.frpr_step_length; frpr_step_tol=s.frpr_step_tol; frpr_max_line_its=s.frpr_max_line_its; /* Quaternion optimizer */ learn_rate = s.learn_rate; /* Mattes mutual information */ mi_hist_fixed_bins = s.mi_hist_fixed_bins; mi_hist_moving_bins = s.mi_hist_moving_bins; mi_num_spatial_samples = s.mi_num_spatial_samples; mi_num_spatial_samples_pct = s.mi_num_spatial_samples_pct; mi_hist_type = s.mi_hist_type; /* MI threshold values */ mi_fixed_image_minVal = s.mi_fixed_image_minVal; mi_fixed_image_maxVal = s.mi_fixed_image_maxVal; mi_moving_image_minVal = s.mi_moving_image_minVal; mi_moving_image_maxVal = s.mi_moving_image_maxVal; /* ITK & GPUIT demons */ demons_std = s.demons_std; demons_std_update_field=s.demons_std_update_field; demons_smooth_deformation_field=s.demons_smooth_deformation_field; demons_smooth_update_field=s.demons_smooth_update_field; demons_step_length=s.demons_step_length; demons_gradient_type=s.demons_gradient_type; num_approx_terms_log_demons=s.num_approx_terms_log_demons; /* GPUIT demons */ demons_acceleration = s.demons_acceleration; demons_homogenization = s.demons_homogenization; demons_filter_width[0] = s.demons_filter_width[0]; demons_filter_width[1] = s.demons_filter_width[1]; demons_filter_width[2] = s.demons_filter_width[2]; /* ITK amoeba */ amoeba_parameter_tol = s.amoeba_parameter_tol; /* Bspline parms */ grid_spac[0] = s.grid_spac[0]; grid_spac[1] = s.grid_spac[1]; grid_spac[2] = s.grid_spac[2]; histoeq = s.histoeq; thresh_mean_intensity= s.thresh_mean_intensity; num_matching_points= s.num_matching_points; num_hist_levels= s.num_hist_levels; /* Native grid search */ gridsearch_strategy = s.gridsearch_strategy; gridsearch_min_overlap[0] = s.gridsearch_min_overlap[0]; gridsearch_min_overlap[1] = s.gridsearch_min_overlap[1]; gridsearch_min_overlap[2] = s.gridsearch_min_overlap[2]; gridsearch_step_size_type = s.gridsearch_step_size_type; gridsearch_step_size[0] = s.gridsearch_step_size[0]; gridsearch_step_size[1] = s.gridsearch_step_size[1]; gridsearch_step_size[2] = s.gridsearch_step_size[2]; gridsearch_min_steps[0] = s.gridsearch_min_steps[0]; gridsearch_min_steps[1] = s.gridsearch_min_steps[1]; gridsearch_min_steps[2] = s.gridsearch_min_steps[2]; /* Landmarks */ landmark_stiffness = s.landmark_stiffness; landmark_flavor = s.landmark_flavor; /* Overlap penalty */ overlap_penalty_lambda = s.overlap_penalty_lambda; overlap_penalty_fraction = s.overlap_penalty_fraction; /* Output files */ img_out_type = s.img_out_type; xf_out_itk = s.xf_out_itk; /* ...but not the output filenames */ img_out_fmt = IMG_OUT_FMT_AUTO; xf_out_fn.clear (); /* ...and don't to resume/finalize unless specifically requested */ resume_stage = false; finalize_stage = false; } Stage_parms::~Stage_parms () { delete d_ptr; } Stage_type Stage_parms::get_stage_type () const { return d_ptr->stage_type; } Shared_parms* Stage_parms::get_shared_parms () { return d_ptr->shared; } const Shared_parms* Stage_parms::get_shared_parms () const { return d_ptr->shared; } Process_parms::Pointer Stage_parms::get_process_parms () { return d_ptr->process_parms; } const Process_parms::Pointer Stage_parms::get_process_parms () const { return d_ptr->process_parms; } void Stage_parms::set_process_parms (const Process_parms::Pointer& pp) { d_ptr->stage_type = STAGE_TYPE_PROCESS; d_ptr->process_parms = pp; } Plm_return_code Stage_parms::set_resample (const std::string& s) { Plm_return_code rc = parse_float13 (this->resample_rate_fixed, s.c_str()); if (rc != PLM_SUCCESS) { return rc; } this->resample_rate_moving[0] = this->resample_rate_fixed[0]; this->resample_rate_moving[1] = this->resample_rate_fixed[1]; this->resample_rate_moving[2] = this->resample_rate_fixed[2]; return PLM_SUCCESS; } Plm_return_code Stage_parms::set_resample_fixed (const std::string& s) { Plm_return_code rc = parse_float13 (this->resample_rate_fixed, s.c_str()); if (rc != PLM_SUCCESS) { return rc; } if (this->resample_type == RESAMPLE_AUTO) { this->resample_rate_moving[0] = this->resample_rate_fixed[0]; this->resample_rate_moving[1] = this->resample_rate_fixed[1]; this->resample_rate_moving[2] = this->resample_rate_fixed[2]; } return PLM_SUCCESS; } Plm_return_code Stage_parms::set_resample_moving (const std::string& s) { Plm_return_code rc = parse_float13 (this->resample_rate_moving, s.c_str()); if (rc != PLM_SUCCESS) { return rc; } if (this->resample_type == RESAMPLE_AUTO) { this->resample_rate_fixed[0] = this->resample_rate_moving[0]; this->resample_rate_fixed[1] = this->resample_rate_moving[1]; this->resample_rate_fixed[2] = this->resample_rate_moving[2]; } return PLM_SUCCESS; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/stage_parms.h000066400000000000000000000151701321604176500311250ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _stage_parms_h_ #define _stage_parms_h_ #include "plmregister_config.h" #include #include #include #include #include "bspline.h" #include "joint_histogram.h" #include "plm_image_type.h" #include "plm_return_code.h" #include "process_parms.h" #include "similarity_metric_type.h" #include "threading.h" enum Stage_transform_type { STAGE_TRANSFORM_NONE, STAGE_TRANSFORM_ALIGN_CENTER, STAGE_TRANSFORM_ALIGN_CENTER_OF_GRAVITY, STAGE_TRANSFORM_TRANSLATION, STAGE_TRANSFORM_VERSOR, STAGE_TRANSFORM_QUATERNION, STAGE_TRANSFORM_AFFINE, STAGE_TRANSFORM_SIMILARITY, STAGE_TRANSFORM_BSPLINE, STAGE_TRANSFORM_VECTOR_FIELD }; enum Optimization_type { OPTIMIZATION_NO_REGISTRATION, OPTIMIZATION_ALIGN_CENTER, OPTIMIZATION_ALIGN_ROI_CENTER, OPTIMIZATION_AMOEBA, OPTIMIZATION_RSG, OPTIMIZATION_VERSOR, OPTIMIZATION_LBFGS, OPTIMIZATION_LBFGSB, OPTIMIZATION_DEMONS, OPTIMIZATION_STEEPEST, OPTIMIZATION_QUAT, OPTIMIZATION_LIBLBFGS, OPTIMIZATION_ONEPLUSONE, OPTIMIZATION_FRPR, OPTIMIZATION_GRID_SEARCH }; #define IMPLEMENTATION_NONE 0 #define IMPLEMENTATION_ITK 1 #define IMPLEMENTATION_PLASTIMATCH 2 #define OPTIMIZATION_SUB_FSF 0 #define OPTIMIZATION_SUB_DIFF_ITK 1 #define OPTIMIZATION_SUB_LOGDOM_ITK 2 #define OPTIMIZATION_SUB_SYM_LOGDOM_ITK 3 #define IMG_OUT_FMT_AUTO 0 #define IMG_OUT_FMT_DICOM 1 enum Stage_type { STAGE_TYPE_PROCESS, STAGE_TYPE_REGISTER }; enum Resample_type { RESAMPLE_AUTO, RESAMPLE_VOXEL_RATE, /* res, res_vox, ss */ RESAMPLE_MM, /* res_mm */ RESAMPLE_PCT, /* res_pct */ RESAMPLE_DIM /* res_dim */ }; enum Regularization_type { REGULARIZATION_NONE, REGULARIZATION_BSPLINE_ANALYTIC, REGULARIZATION_BSPLINE_SEMI_ANALYTIC, REGULARIZATION_BSPLINE_NUMERIC }; enum Demons_gradient_type { SYMMETRIC, FIXED_IMAGE, WARPED_MOVING, MAPPED_MOVING }; enum Gridsearch_strategy_type { GRIDSEARCH_STRATEGY_AUTO, GRIDSEARCH_STRATEGY_GLOBAL, GRIDSEARCH_STRATEGY_LOCAL }; enum Gridsearch_step_size_type { GRIDSEARCH_STEP_SIZE_AUTO, GRIDSEARCH_STEP_SIZE_MANUAL }; class Plm_image; class Process_parms; class Shared_parms; class Stage_parms_private; class PLMREGISTER_API Stage_parms { public: Stage_parms_private *d_ptr; public: Stage_parms (); Stage_parms (const Stage_parms& s); ~Stage_parms (); public: /* Stage # */ int stage_no; /* Stage resume? */ bool resume_stage; bool finalize_stage; /* Number of substages */ int num_substages; /* Generic optimization parms */ Stage_transform_type xform_type; Optimization_type optim_type; int impl_type; int optim_subtype; /* used for demons types (diffeomorphic, etc.) */ char alg_flavor; Threading threading_type; int gpuid; /* Sets GPU to use for multi-gpu machines */ /* Regularization */ Regularization_type regularization_type; float regularization_lambda; /* Image resampling */ /* The units of fixed_resampling_rate are: voxels for res_vox, mm for res_mm, pct for res_pct, voxels for res_dim */ Resample_type resample_type; float resample_rate_fixed[3]; float resample_rate_moving[3]; /* Intensity values for air */ float background_max; /* Threshold to find the valid region */ float default_value; /* Replacement when out-of-view */ /* Generic optimization parms */ int min_its; int max_its; float convergence_tol; /* LBGFG optimizer */ float grad_tol; /* LBGFGB optimizer */ float pgtol; int lbfgsb_mmax; /* Versor & RSG optimizer */ float max_step; float min_step; float rsg_grad_tol; float translation_scale_factor; int rotation_scale_factor; float scaling_scale_factor; /*OnePlusOne evvolutionary optimizer*/ float opo_epsilon; float opo_initial_search_rad; /*FRPR optimizer*/ float frpr_step_tol; float frpr_step_length; int frpr_max_line_its; /* Quaternion optimizer */ float learn_rate; /* Mutual information */ int mi_hist_fixed_bins; int mi_hist_moving_bins; int mi_num_spatial_samples; float mi_num_spatial_samples_pct; enum Mi_hist_type mi_hist_type; float mi_fixed_image_minVal; float mi_fixed_image_maxVal; float mi_moving_image_minVal; float mi_moving_image_maxVal; /* ITK (& GPUIT) demons */ float demons_std; float demons_std_update_field; float demons_step_length; bool demons_smooth_update_field, demons_smooth_deformation_field; unsigned int num_approx_terms_log_demons; bool histoeq; // histogram matching flag bool thresh_mean_intensity; unsigned int num_matching_points; unsigned int num_hist_levels; Demons_gradient_type demons_gradient_type; /* GPUIT demons */ float demons_acceleration; float demons_homogenization; int demons_filter_width[3]; /* ITK amoeba */ float amoeba_parameter_tol; /* Bspline parms */ float grid_spac[3]; // absolute grid spacing in mm in x,y,z directions /* Native grid search */ Gridsearch_strategy_type gridsearch_strategy; float gridsearch_min_overlap[3]; Gridsearch_step_size_type gridsearch_step_size_type; float gridsearch_step_size[3]; int gridsearch_min_steps[3]; /* Landmarks */ float landmark_stiffness; //strength of attraction between landmarks char landmark_flavor; /* Overlap penalty */ float overlap_penalty_lambda; float overlap_penalty_fraction; /* Output files */ int img_out_fmt; Plm_image_type img_out_type; std::string img_out_fn; bool xf_out_itk; std::list xf_out_fn; std::string vf_out_fn; std::string debug_dir; public: Stage_type get_stage_type () const; Shared_parms *get_shared_parms (); const Shared_parms *get_shared_parms () const; Process_parms::Pointer get_process_parms (); const Process_parms::Pointer get_process_parms () const; void set_process_parms (const Process_parms::Pointer&); Plm_return_code set_resample (const std::string& s); Plm_return_code set_resample_fixed (const std::string& s); Plm_return_code set_resample_moving (const std::string& s); }; #endif translation_grid_search.cxx000066400000000000000000000177731321604176500340170ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include "interpolate.h" #include "interpolate_macros.h" #include "logfile.h" #include "metric_parms.h" #include "mha_io.h" #include "plm_image.h" #include "plm_image_header.h" #include "print_and_exit.h" #include "registration_data.h" #include "registration_resample.h" #include "shared_parms.h" #include "stage_parms.h" #include "string_util.h" #include "translation_grid_search.h" #include "translation_mi.h" #include "translation_mse.h" #include "volume.h" #include "volume_grad.h" #include "volume_macros.h" #include "volume_resample.h" #include "xform.h" class Translation_grid_search { public: std::list similarity_data; float (*translation_score) ( const Stage_parms *stage, const Volume::Pointer& fixed, const Volume::Pointer& moving, const float dxyz[3]); float best_score; float best_translation[3]; public: void do_search ( Xform::Pointer& xf_out, const Stage_parms* stage, Stage_parms* auto_parms); void do_score ( const Stage_parms* stage, const float dxyz[3]); }; void Translation_grid_search::do_search ( Xform::Pointer& xf_out, const Stage_parms* stage, Stage_parms* auto_parms) { /* GCS FIX: region of interest is not used */ /* GCS FIX: This algorithm will not work with tilted images. For these cases, we need to use bounding box to compute search extent. */ Volume::Pointer& fixed = this->similarity_data.front()->fixed_ss; Volume::Pointer& moving = this->similarity_data.front()->moving_ss; /* Compute maximum search extent */ lprintf ("Computing grid search extent.\n"); float search_min[3]; float search_max[3]; for (int d = 0; d < 3; d++) { float mo = stage->gridsearch_min_overlap[d]; if (mo < 0.1) { mo = 0.1; } else if (mo > 0.9) { mo = 0.9; } float mov_siz = moving->dim[d] * moving->spacing[d]; float fix_siz = fixed->dim[d] * fixed->spacing[d]; lprintf ("Dimension %d, mo=%g F=(%g, %g) M=(%g, %g)\n", d, mo, fixed->origin[d], fix_siz, moving->origin[d], mov_siz); if (fix_siz > mov_siz) { search_min[d] = moving->origin[d] - fixed->origin[d] - fix_siz + mo * mov_siz; search_max[d] = moving->origin[d] - fixed->origin[d] + mov_siz - mo * mov_siz; } else { search_min[d] = moving->origin[d] - fixed->origin[d] - fix_siz + mo * fix_siz; search_max[d] = moving->origin[d] - fixed->origin[d] + mov_siz - mo * fix_siz; } } lprintf ("Native grid search extent: " "(%g, %g), (%g, %g), (%g, %g)\n", search_min[0], search_max[0], search_min[1], search_max[1], search_min[2], search_max[2]); /* Get default value */ TranslationTransformType::Pointer old_trn = xf_out->get_trn (); this->best_translation[0] = old_trn->GetParameters()[0]; this->best_translation[1] = old_trn->GetParameters()[1]; this->best_translation[2] = old_trn->GetParameters()[2]; this->best_score = FLT_MAX; this->do_score (stage, this->best_translation); /* Compute search range */ int num_steps[3] = { 0, 0, 0 }; float search_step[3] = { 0.f, 0.f, 0.f }; float max_range = 0.f; for (int d = 0; d < 3; d++) { float search_range = search_max[d] - search_min[d]; if (search_range > max_range) { max_range = search_range; } } /* Identify search strategy, and compute step size */ Gridsearch_strategy_type strategy = stage->gridsearch_strategy; if (strategy == GRIDSEARCH_STRATEGY_AUTO) { strategy = auto_parms->gridsearch_strategy; } if (strategy == GRIDSEARCH_STRATEGY_GLOBAL || strategy == GRIDSEARCH_STRATEGY_AUTO) { lprintf ("Global grid search\n"); float nominal_step = max_range / 5; for (int d = 0; d < 3; d++) { float search_range = search_max[d] - search_min[d]; num_steps[d] = ROUND_INT (search_range / nominal_step) + 1; if (num_steps[d] < stage->gridsearch_min_steps[d]) { num_steps[d] = stage->gridsearch_min_steps[d]; } if (num_steps[d] > 1) { search_step[d] = search_range / (num_steps[d] - 1); } } } else { lprintf ("Local grid search\n"); for (int d = 0; d < 3; d++) { num_steps[d] = 4; if (stage->gridsearch_step_size_type == GRIDSEARCH_STEP_SIZE_AUTO) { search_step[d] = auto_parms->gridsearch_step_size[d]; } else { search_step[d] = stage->gridsearch_step_size[d]; } search_min[d] = this->best_translation[d] - 1.5 * search_step[d]; } } /* Update auto parms */ auto_parms->gridsearch_strategy = GRIDSEARCH_STRATEGY_LOCAL; for (int d = 0; d < 3; d++) { auto_parms->gridsearch_step_size[d] = 0.6 * search_step[d]; } /* Run grid search */ for (plm_long k = 0; k < num_steps[2]; k++) { for (plm_long j = 0; j < num_steps[1]; j++) { for (plm_long i = 0; i < num_steps[0]; i++) { float translation[3] = { search_min[0] + i * search_step[0], search_min[1] + j * search_step[1], search_min[2] + k * search_step[2] }; this->do_score (stage, translation); } } } /* Find the best translation */ TranslationTransformType::ParametersType xfp(3); xfp[0] = this->best_translation[0]; xfp[1] = this->best_translation[1]; xfp[2] = this->best_translation[2]; /* Fixate translation into xform */ TranslationTransformType::Pointer new_trn = TranslationTransformType::New(); new_trn->SetParameters(xfp); xf_out->set_trn (new_trn); } void Translation_grid_search::do_score ( const Stage_parms* stage, const float dxyz[3]) { lprintf ("[%g %g %g]", dxyz[0], dxyz[1], dxyz[2]); std::list::iterator it; float acc_score = 0.f; for (it = this->similarity_data.begin(); it != this->similarity_data.end(); ++it) { const Metric_state::Pointer& ssi = *it; float score = 0.f; switch (ssi->metric_type) { case SIMILARITY_METRIC_MSE: case SIMILARITY_METRIC_GM: score = translation_mse (stage, ssi, dxyz); break; case SIMILARITY_METRIC_MI_MATTES: case SIMILARITY_METRIC_MI_VW: score = translation_mi (stage, ssi, dxyz); break; default: print_and_exit ("Metric %d not implemented with grid search\n"); break; } lprintf (" %g", score); acc_score += score; } if (this->similarity_data.size() > 1) { lprintf (" | %g", acc_score); } if (acc_score < this->best_score) { this->best_score = acc_score; this->best_translation[0] = dxyz[0]; this->best_translation[1] = dxyz[1]; this->best_translation[2] = dxyz[2]; lprintf (" *"); } lprintf ("\n"); } Xform::Pointer translation_grid_search_stage ( Registration_data* regd, const Xform::Pointer& xf_in, const Stage_parms* stage) { Xform::Pointer xf_out = Xform::New (); Plm_image_header pih; Translation_grid_search tgsd; /* Copy similarity images and parms */ populate_similarity_list (tgsd.similarity_data, regd, stage); /* Transform input xform to itk translation */ xform_to_trn (xf_out.get(), xf_in.get(), &pih); /* Run the translation optimizer */ tgsd.do_search (xf_out, stage, regd->get_auto_parms ()); return xf_out; } translation_grid_search.h000066400000000000000000000010571321604176500334300ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _translation_grid_search_h_ #define _translation_grid_search_h_ #include "plmregister_config.h" #include "xform.h" class Registration_data; class Xform; class Stage_parms; Xform::Pointer translation_grid_search_stage ( Registration_data* regd, const Xform::Pointer& xf_in, const Stage_parms* stage); #endif translation_mi.cxx000066400000000000000000000060101321604176500321300ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include "interpolate.h" #include "interpolate_macros.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "registration_data.h" #include "stage_parms.h" #include "translation_mi.h" #include "volume.h" #include "volume_macros.h" #include "volume_resample.h" #include "xform.h" float translation_mi ( const Stage_parms *stage, const Metric_state::Pointer& ssi, const float dxyz[3]) { Volume *fixed = ssi->fixed_ss.get(); Volume *moving = ssi->moving_ss.get(); Joint_histogram *mi_hist = new Joint_histogram ( stage->mi_hist_type, stage->mi_hist_fixed_bins, stage->mi_hist_moving_bins); mi_hist->initialize (fixed, moving); mi_hist->reset_histograms (); plm_long fijk[3], fidx; /* Indices within fixed image (vox) */ float fxyz[3]; /* Position within fixed image (mm) */ float mijk[3]; /* Indices within moving image (vox) */ float mxyz[3]; /* Position within moving image (mm) */ plm_long mijk_f[3], midx_f; /* Floor */ plm_long mijk_r[3]; /* Round */ float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ plm_long num_vox = 0; /* PASS 1 - Accumulate histogram */ LOOP_Z (fijk, fxyz, fixed) { LOOP_Y (fijk, fxyz, fixed) { LOOP_X (fijk, fxyz, fixed) { /* Compute moving image coordinate of fixed image voxel */ mxyz[2] = fxyz[2] + dxyz[2] - moving->origin[2]; mxyz[1] = fxyz[1] + dxyz[1] - moving->origin[1]; mxyz[0] = fxyz[0] + dxyz[0] - moving->origin[0]; mijk[2] = PROJECT_Z (mxyz, moving->proj); mijk[1] = PROJECT_Y (mxyz, moving->proj); mijk[0] = PROJECT_X (mxyz, moving->proj); if (!moving->is_inside (mijk)) continue; /* Get tri-linear interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Find the fixed image linear index */ fidx = volume_index (fixed->dim, fijk); /* Find linear index the corner voxel used to identifiy the * neighborhood of the moving image voxels corresponding * to the current fixed image voxel */ midx_f = volume_index (moving->dim, mijk_f); /* Add to histogram */ mi_hist->add_pvi_8 (fixed, moving, fidx, midx_f, li_1, li_2); num_vox++; } } } /* Compute score */ return mi_hist->compute_score (num_vox); } translation_mi.h000066400000000000000000000007411321604176500315620ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _translation_mi_h_ #define _translation_mi_h_ #include "plmregister_config.h" #include "volume.h" class Stage_parms; float translation_mi ( const Stage_parms *stage, const Metric_state::Pointer& ssi, const float dxyz[3]); #endif translation_mse.cxx000066400000000000000000000063271321604176500323220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include #include #include #include "interpolate.h" #include "interpolate_macros.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "registration_data.h" #include "stage_parms.h" #include "translation_mse.h" #include "volume.h" #include "volume_macros.h" #include "volume_resample.h" #include "xform.h" float translation_mse ( const Stage_parms *stage, const Metric_state::Pointer& ssi, const float dxyz[3]) { plm_long fijk[3], fv; /* Indices within fixed image (vox) */ float fxyz[3]; /* Position within fixed image (mm) */ float mijk[3]; /* Indices within moving image (vox) */ float mxyz[3]; /* Position within moving image (mm) */ float li_1[3]; /* Fraction of interpolant in lower index */ float li_2[3]; /* Fraction of interpolant in upper index */ plm_long mijk_f[3], mvf; /* Floor */ plm_long mijk_r[3]; /* Round */ float m_val; Volume *fixed = ssi->fixed_ss.get(); Volume *moving = ssi->moving_ss.get(); float* f_img = (float*) fixed->img; float* m_img = (float*) moving->img; double score_acc = 0.0; plm_long num_vox = 0; LOOP_Z (fijk, fxyz, fixed) { LOOP_Y (fijk, fxyz, fixed) { LOOP_X (fijk, fxyz, fixed) { /* Compute moving image coordinate of fixed image voxel */ mxyz[2] = fxyz[2] + dxyz[2] - moving->origin[2]; mxyz[1] = fxyz[1] + dxyz[1] - moving->origin[1]; mxyz[0] = fxyz[0] + dxyz[0] - moving->origin[0]; mijk[2] = PROJECT_Z (mxyz, moving->proj); mijk[1] = PROJECT_Y (mxyz, moving->proj); mijk[0] = PROJECT_X (mxyz, moving->proj); if (!moving->is_inside (mijk)) continue; /* Compute interpolation fractions */ li_clamp_3d (mijk, mijk_f, mijk_r, li_1, li_2, moving); /* Find linear index of "corner voxel" in moving image */ mvf = volume_index (moving->dim, mijk_f); /* Compute moving image intensity using linear interpolation */ /* Macro is slightly faster than function */ LI_VALUE (m_val, li_1[0], li_2[0], li_1[1], li_2[1], li_1[2], li_2[2], mvf, m_img, moving); /* Compute linear index of fixed image voxel */ fv = volume_index (fixed->dim, fijk); /* Compute intensity difference */ float diff = m_val - f_img[fv]; score_acc += diff * diff; num_vox++; } } } /* Normalize score */ const int MIN_VOX = 1; float final_metric; if (num_vox < MIN_VOX) { final_metric = FLT_MAX; } else { final_metric = score_acc / num_vox; } return final_metric; } translation_mse.h000066400000000000000000000007201321604176500317360ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _translation_mse_h_ #define _translation_mse_h_ #include "plmregister_config.h" #include "volume.h" float translation_mse ( const Stage_parms *stage, const Metric_state::Pointer& ssi, const float dxyz[3]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/viscous.cxx000066400000000000000000000010471321604176500306640ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "viscous_cuda.h" #include "viscous.h" int viscous (int argc, char *argv[]) { LOAD_LIBRARY_SAFE (libplmregistercuda); LOAD_SYMBOL (CUDA_viscous_main, libplmregistercuda); int rc = CUDA_viscous_main (argc, argv); UNLOAD_LIBRARY (libplmregistercuda); return rc; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/viscous.h000066400000000000000000000005531321604176500303120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _viscous_h_ #define _viscous_h_ #include "plmregister_config.h" PLMREGISTER_API int viscous (int argc, char** argv); #endif viscous_convolution.h000066400000000000000000000116501321604176500326720ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/******************************************************************* c* Multimodal Deformable Image Registration * c* via Mutual Information or Bhattacharyya Distantce * c* Version: 1.0 * c* Language: C, CUDA * c* * c* Developer: Yifei Lou * c* Email: yifei.lou@ece.gatech.edu * c* * c* School of Electrical and Computer Engineering * c* Georgia Institute of Technology * c* Atlanta, GA, 30318 * c* Website: http://groups.bme.gatech.edu/groups/bil/ * c* * c* Copyright (c) 2011 * c* All rights reserved. * c* * c* Permission to use, copy, or modify this code and its * c* documentation for scientific purpose is hereby granted * c* without fee, provided that this copyright notice appear in * c* all copies and that both that copyright notice and this * c* permission notice appear in supporting documentation. The use * c* for commercial purposes is prohibited without permission. * c* * c* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * c* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * c* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * c* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * c* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * c* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * c* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING, BUT NOT * c* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF* c* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * c* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * c* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * c* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * c* THE POSSIBILITY OF SUCH DAMAGE. * c* * c******************************************************************/ #ifndef _3DImageSmooth_H_ #define _3DImageSmooth_H_ #define KERNEL_RADIUS 8 const int KERNEL_W = (2 * KERNEL_RADIUS + 1); // Assuming ROW_TILE_W, KERNEL_RADIUS_ALIGNED and dataW // are multiples of coalescing granularity size, // all global memory operations are coalesced in convolutionRowGPU() #define ROW_TILE_W 128 #define KERNEL_RADIUS_ALIGNED 16 // Assuming COLUMN_TILE_W and dataW are multiples // of coalescing granularity size, all global memory operations // are coalesced in convolutionColumnGPU() #define COLUMN_TILE_W 16 #define COLUMN_TILE_H 48 //#define UNROLL_INNER // for fast convolution //////////////////////////////////////////////////////////////////////////////// // Common host and device functions //////////////////////////////////////////////////////////////////////////////// //Round a / b to nearest higher integer value inline int iDivUp(int a, int b){ return (a % b != 0) ? (a / b + 1) : (a / b); } //24-bit multiplication is faster on G80, //but we must be sure to multiply integers //only within [-8M, 8M - 1] range #define IMUL(a, b) __mul24(a, b) __device__ __constant__ float d_Kernel[KERNEL_W]; //////////////////////////////////////////////////////////////////////////////// // Loop unrolling templates, needed for best performance //////////////////////////////////////////////////////////////////////////////// template __device__ float convolutionRow(float *data){ return data[KERNEL_RADIUS - i] * d_Kernel[i] + convolutionRow(data); } template<> __device__ float convolutionRow<-1>(float *data){ return 0; } template __device__ float convolutionColumn(float *data){ return data[(KERNEL_RADIUS - i) * COLUMN_TILE_W] * d_Kernel[i] + convolutionColumn(data); } template<> __device__ float convolutionColumn<-1>(float *data){ return 0; } //////////////////////////////////////////////////////////////////////////////// // GPU convolution //////////////////////////////////////////////////////////////////////////////// //subroutines void ImageSmooth(float *d_image, float *d_image_conv, int3 Dims); __global__ void myconv2dGPU(float *src, float *dest, float *kernel, int M, int N, int kn); #endif viscous_global.h000066400000000000000000000177531321604176500315650ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/******************************************************************* c* Multimodal Deformable Image Registration * c* via Mutual Information or Bhattacharyya Distantce * c* Version: 1.0 * c* Language: C, CUDA * c* * c* Developer: Yifei Lou * c* Email: yifei.lou@ece.gatech.edu * c* * c* School of Electrical and Computer Engineering * c* Georgia Institute of Technology * c* Atlanta, GA, 30318 * c* Website: http://groups.bme.gatech.edu/groups/bil/ * c* * c* Copyright (c) 2011 * c* All rights reserved. * c* * c* Permission to use, copy, or modify this code and its * c* documentation for scientific purpose is hereby granted * c* without fee, provided that this copyright notice appear in * c* all copies and that both that copyright notice and this * c* permission notice appear in supporting documentation. The use * c* for commercial purposes is prohibited without permission. * c* * c* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * c* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * c* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * c* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * c* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * c* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * c* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING, BUT NOT * c* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF* c* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * c* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * c* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * c* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * c* THE POSSIBILITY OF SUCH DAMAGE. * c* * c******************************************************************/ #ifndef _viscous_global_h_ #define _viscous_global_h_ /************************************** * CUDA parameters **************************************/ #define NTHREAD_PER_BLOCK 256 // number of threads per block along each direction #define NBLOCKX 1024 // the leading dimension of the 2d thread grid #define DEVICENUMBER 0 // device number to be used /************************************** * parameters **************************************/ #define NX0 256 #define NY0 256 #define NZ0 64 #define DATA_SIZE ((NX0*NY0*NZ0)*sizeof(float)) #define NSCALE 2 // number of scales in the image pyramid: 0 is the finest, NSCALE-1 is the coarest #define MAX_ITER 20 // max # of iterations in the finest grid // # of iterations at each level = 2^scale*MAX_ITER // histogram related parameters #define nBin 256 // number of histogram bins #define hValue 4 // int, parameter in the Gaussian for convolution histogram #define HIST_SIZE (nBin*nBin*sizeof(float)) #define sValue 3 // int, parameter in the Gaussian for updating velocity #define sLength (6*sValue+1) // image domain parameters #define ALPHA 500 // parameter in the force calculation #define du 0.6 // parameter to dynamically define dt #define METHOD 1 // 1 for Bnorm, 2 for MI #define threshJaco 0.5 // threshold for Jacobian to regridding #define EPS 0.000001 /*************************************** * global variables declaration ***************************************/ #ifndef GCS_REPRESS_EXTERNS extern char inputfilename_move[100]; // image move extern char inputfilename_static[100]; // image static extern char outputfilename[100]; // image out extern char output_mv_x[100]; extern char output_mv_y[100]; extern char output_mv_z[100]; extern float *h_im_static, *h_im_move; // image pyramid extern float *d_im_static[NSCALE], *d_im_move[NSCALE]; // vector flow extern float *d_mv_x[NSCALE], *d_mv_y[NSCALE], *d_mv_z[NSCALE]; // gaussian kernel extern float *GaussKernelH, *GaussKernelHx; // histogram related extern float *d_jointHistogram; extern float *d_jointHistogram_conv; extern float *d_probx, *d_proby; extern float *d_Bsum; extern dim3 nblocks; extern dim3 nblocks_hist; extern int NX, NY, NZ, sDATA_SIZE; // dimension at current pyramid level extern float max_im_move, min_im_move; // max and min intensity of the moving image extern cudaArray *d_im_move_array; extern texture d_im_move_tex; extern cudaArray *d_mv_x_array, *d_mv_y_array, *d_mv_z_array; extern texture d_mv_x_tex; extern texture d_mv_y_tex; extern texture d_mv_z_tex; extern int deviceCount; extern cudaDeviceProp dP; // device properties #endif /* GCS_REPRESS_EXTERNS */ /************************************* * simple math functions ***************************************/ __host__ __device__ float minmod(float x, float y); __device__ float ImageGradient(float Im, float I, float Ip); /**************************************** * Data processing ****************************************/ void dataPreprocessing(float *image, float *maxValue, float *minValue); __global__ void intensityRescale(float *image, float maxValue, float minValue, int type); // type >0 forward calculation: rescale image intensity to [0,1] // type <0 backward: map intensity to its original scale void loadData(float *dest, int sizeInByte, const char *filename); void outputData(void *src, int size, const char *outputfilename); /*************************************** * function declaration ***************************************/ void initData(); void initGaussKernel(); void fina(); void compute(float *d_im_move, float *d_im_static, float *d_mv_x, float *d_mv_y, float *d_mv_z, int maxIter); /**************************************** * kernel declaration ****************************************/ __global__ void upSample(float *src, float *dest, int NX, int NY, int NZ); __global__ void downSample(float *src, float *dest, int NX, int NY, int NZ, int s); __global__ void ImageWarp(float *mv_x, float *mv_y, float *mv_z, float *dest, int NX, int NY, int NZ); __global__ void ImageWarp_mv(float *mv_x, float *mv_y, float *mv_z, int NX, int NY, int NZ); __global__ void ImageWarp_final(float *mv_x, float *mv_y, float *mv_z, float *dest, int NX, int NY, int NZ); __global__ void forceComp(float *d_im_out, float *d_im_static, float *d_Likelihood, float *d_v_x, float *d_v_y, float *d_v_z, int NX, int NY, int NZ); __global__ void flowComp(float *d_mv_x, float *d_mv_y, float *d_mv_z, float *d_v_x, float *d_v_y, float *d_v_z, float *jacobian, float *flow, int NX, int NY, int NZ); __global__ void flowUpdate(float *d_mv_x, float *d_mv_y, float *d_mv_z, float *d_disp_x, float *d_disp_y, float *d_disp_z, float dt, int NX, int NY, int NZ); __global__ void marginalDist(float *jointHist, float *probx, float *proby); __global__ void mutualInfoGPU(float *jointHist, float *probx, float *proby, float *likelihood); __global__ void copyHist(unsigned int *hist, float *jointHist); __global__ void marginalBnorm_sum(float *jointHist, float *probx, float *proby, float *Bsum); __global__ void marginalDistAlongY(float *jointHist, float *dest); __global__ void BnormGPU(float *jointHist, float *probx, float *proby, float *Bsum, float *likelihood); __global__ void transToFloat2(const float *input1, const float *input2, float2 *output, const int n); #endif viscous_main.cxx000066400000000000000000000010611321604176500316050ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/register/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmregister_config.h" #include "viscous_cuda.h" #include "viscous_main.h" int viscous_main (int argc, char *argv[]) { LOAD_LIBRARY_SAFE (libplmregistercuda); LOAD_SYMBOL (CUDA_viscous_main, libplmregistercuda); int rc = CUDA_viscous_main (argc, argv); UNLOAD_LIBRARY (libplmregistercuda); return rc; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/000077500000000000000000000000001321604176500261235ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/CMakeLists.txt000066400000000000000000000046551321604176500306750ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_script) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/plmscript_config.h.in ${CMAKE_BINARY_DIR}/plmscript_config.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (AFTER ${LUA_INCLUDE_DIR}) ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (PLMSCRIPT_LIBRARY_SRC lua_class_image.cxx lua_class_image.h lua_class_register.cxx lua_class_register.h lua_class_stage.cxx lua_class_stage.h lua_class_structs.cxx lua_class_structs.h lua_class_xform.cxx lua_class_xform.h lua_tty.cxx lua_tty.h lua_tty_commands.cxx lua_tty_commands.h # lua_tty_commands_pcmd.cxx lua_tty_commands_pcmd.h lua_tty_commands_util.cxx lua_tty_commands_util.h lua_util.cxx lua_util.h ) set (PLMSCRIPT_LIBRARY_DEPENDENCIES plmbase plmregister plmsegment plmsys plmutil ${QT_LIBRARIES} lua ) if (READLINE_FOUND) set (PLMSCRIPT_LIBRARY_DEPENDENCIES ${PLMSCRIPT_LIBRARY_DEPENDENCIES} ${READLINE_LIBRARY} ) endif() if (TERMCAP_LIBRARY) set (PLMSCRIPT_LIBRARY_DEPENDENCIES ${PLMSCRIPT_LIBRARY_DEPENDENCIES} ${TERMCAP_LIBRARY} ) endif() if (LIBDL_FOUND) set (PLMSCRIPT_LIBRARY_DEPENDENCIES ${PLMSCRIPT_LIBRARY_DEPENDENCIES} -ldl) endif () ##----------------------------------------------------------------------------- ## SPECIAL BUILD RULES: Qt ##----------------------------------------------------------------------------- # JAS 2012.04.27 # This Qt4 mess here is simply horrible ...note to self, # remember to fix this once we have all the qt code # building as plmqt if (QT4_FOUND) qt4_wrap_cpp (PORTAL_MOC_SRC_HACK ../qt/cview_portal.h ) set (PLMSCRIPT_LIBRARY_SRC ${PLMSCRIPT_LIBRARY_SRC} ${PORTAL_MOC_SRC_HACK} ../qt/cview_portal.cxx lua_tty_preview.cxx ) endif () ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- plm_add_library ( plmscript "${PLMSCRIPT_LIBRARY_SRC}" "${PLMSCRIPT_LIBRARY_DEPENDENCIES}" "" "") lua_class_image.cxx000066400000000000000000000125741321604176500317110ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmscript_config.h" #include #include #include extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #include "itkAddImageFilter.h" #if ITK_VERSION_MAJOR >= 4 #include "itkMultiplyImageFilter.h" #else #include "itkMultiplyByConstantImageFilter.h" #endif #include "lua_classes.h" #include "lua_class_image.h" #include "lua_class_structs.h" #include "lua_util.h" #include "plm_image.h" #include "segment_body.h" /* Name of class as exposed to Lua */ #define THIS_CLASS LUA_CLASS_IMAGE /* Helpers */ void init_image_instance (lua_image* limg) { memset (limg->fn, '\0', sizeof(limg->fn)); limg->pli = NULL; } /*******************************************************/ /* Object Methods */ /*******************************************************/ static int image_automask (lua_State *L) { Segment_body automask; /* 1st arg should be "this" */ lua_image *limg = (lua_image*)get_obj_ptr (L, THIS_CLASS, 1); /* 2nd arg should be threshold */ float thres = (float)luaL_optnumber (L, 2, automask.m_lower_threshold); lua_ss *lss = (lua_ss*)lua_new_instance (L, LUA_CLASS_SS, sizeof(lua_ss)); init_ss_instance (lss); lss->ss_img = new Plm_image; automask.img_in = limg->pli; automask.img_out = lss->ss_img; automask.m_lower_threshold = thres; automask.do_segmentation (); lss->ss_img = automask.img_out; return 1; } static int image_info (lua_State *L) { /* 1st arg should be "this" */ lua_image *limg = (lua_image*)get_obj_ptr (L, THIS_CLASS, 1); limg->pli->print (); return 0; } static int image_load (lua_State *L) { const char* fn = luaL_optlstring (L, 1, NULL, NULL); if (!fn) { fprintf (stderr, "error -- image.load() -- no file specified\n"); return 0; } Plm_image* pli = plm_image_load (fn, PLM_IMG_TYPE_ITK_FLOAT); if (!pli) { fprintf (stderr, "error -- image.load() -- unable to load %s\n", fn); return 0; } lua_image *tmp = (lua_image*)lua_new_instance (L, THIS_CLASS, sizeof(lua_image)); init_image_instance (tmp); strcpy (tmp->fn, fn); tmp->pli = pli; return 1; } static int image_save (lua_State *L) { lua_image *limg = (lua_image*)get_obj_ptr (L, THIS_CLASS, 1); const char* fn = luaL_optlstring (L, 2, NULL, NULL); Plm_image *pli = limg->pli; if (!fn) { if (limg->fn[0] == '\0') { fprintf (stderr, "warning -- image:save() -- filename must be specified when saving derived images\n"); return 0; } else { /* Save over current volume on disk */ pli->save_image (limg->fn); } } else { /* "Save-As" new volume on disk */ pli->save_image (fn); strcpy (limg->fn, fn); } return 0; } /*******************************************************/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Object Actions */ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Action: garbage collection */ static int image_action_gc (lua_State *L) { lua_image *tmp = (lua_image*)get_obj_ptr (L, THIS_CLASS, 1); // fprintf (stderr, "debug -- releasing %s [%p]\n", tmp->fn, tmp); delete tmp->pli; return 0; } /* Action: multiplication on volumes */ static int image_action_mul (lua_State *L) { float factor; lua_image* limg; if (lua_isnumber (L, 1) && lua_isuserdata (L, 2)) { factor = lua_tonumber (L, 1); limg = (lua_image*)get_obj_ptr (L, THIS_CLASS, 2); } else if (lua_isnumber (L, 2) && lua_isuserdata (L, 1)) { factor = lua_tonumber (L, 2); limg = (lua_image*)get_obj_ptr (L, THIS_CLASS, 1); } else { fprintf (stderr, "warning -- image.__mul() -- cannot multiply two images: returning (nil)\n"); return 0; } #if ITK_VERSION_MAJOR >= 4 typedef itk::MultiplyImageFilter< FloatImageType, FloatImageType, FloatImageType > MulFilterType; #else typedef itk::MultiplyByConstantImageFilter< FloatImageType, float, FloatImageType > MulFilterType; #endif MulFilterType::Pointer multiply = MulFilterType::New(); lua_image *out = (lua_image*)lua_new_instance (L, THIS_CLASS, sizeof(lua_image)); init_image_instance (out); out->pli = limg->pli->clone(); multiply->SetConstant (factor); multiply->SetInput (out->pli->itk_float()); multiply->Update(); out->pli->m_itk_float = multiply->GetOutput(); return 1; } /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Object Creation */ /* methods table for object */ static const luaL_reg image_methods[] = { {"automask", image_automask}, {"info", image_info}, {"load", image_load}, {"save", image_save}, {0, 0} }; /* metatable of actions */ static const luaL_reg image_meta[] = { {"__gc", image_action_gc}, {"__mul", image_action_mul}, {0, 0} }; int register_lua_class_image (lua_State *L) { return register_lua_class (L, THIS_CLASS, image_methods, image_meta); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/lua_class_image.h000066400000000000000000000011731321604176500314060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _lua_class_image_h_ #define _lua_class_image_h_ #include "plmscript_config.h" #include "lua.h" #include "lualib.h" #include "lauxlib.h" class Plm_image; typedef struct lua_image_struct lua_image; struct lua_image_struct { std::string fn; Plm_image* pli; }; PLMSCRIPT_C_API int register_lua_class_image (lua_State *L); PLMSCRIPT_C_API void init_image_instance (lua_image* limg); #endif lua_class_register.cxx000066400000000000000000000106261321604176500324470ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmscript_config.h" #include #include #include extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #include "plmregister.h" #include "lua_classes.h" #include "lua_class_register.h" #include "lua_class_xform.h" #include "lua_util.h" /* Name of class as exposed to Lua */ #define THIS_CLASS LUA_CLASS_REGISTER /* Helpers */ void init_register_instance (lua_register* lregister) { memset (lregister->fn, '\0', sizeof (lregister->fn)); lregister->regp = NULL; lregister->moving = NULL; lregister->fixed = NULL; lregister->moving_roi = NULL; lregister->fixed_roi = NULL; } /*******************************************************/ /* Object Methods */ /*******************************************************/ static int register_load (lua_State *L) { const char* fn = luaL_optlstring (L, 1, NULL, NULL); if (!fn) { fprintf (stderr, "error -- register.load() -- no file specified\n"); return 0; } Registration_parms *regp = new Registration_parms; //(Registration_parms*)malloc (sizeof(Registration_parms)); if (regp->parse_command_file (fn) < 0) { fprintf (stderr, "error -- register.load() -- unable to load %s\n", fn); return 0; } lua_register *lreg = (lua_register*)lua_new_instance (L, THIS_CLASS, sizeof(lua_register)); init_register_instance (lreg); strcpy (lreg->fn, fn); lreg->regp = regp; return 1; } /* returns a lua_xform to Lua */ static int register_go (lua_State *L) { lua_register *lreg = (lua_register*)get_obj_ptr (L, THIS_CLASS, 1); Registration_data regd; Registration_parms* regp; if (!lreg->moving) { fprintf (stderr, "warning -- register:go() -- moving image not specified\n"); return 0; } if (!lreg->fixed) { fprintf (stderr, "warning -- register:go() -- fixed image not specified\n"); return 0; } regp = lreg->regp; regd.moving_image = lreg->moving->pli; regd.fixed_image = lreg->fixed->pli; if (lreg->moving_roi) { regd.moving_roi = lreg->moving_roi->ss_img; } if (lreg->fixed_roi) { regd.fixed_roi = lreg->fixed_roi->ss_img; } /* Landmarks not yet implemented - no class */ lua_xform *lxf = (lua_xform*)lua_new_instance (L, LUA_CLASS_XFORM, sizeof(lua_xform)); do_registration_pure (&(lxf->pxf), ®d, regp); return 1; } /*******************************************************/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Object Actions */ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Action: garbage collection */ static int register_action_gc (lua_State *L) { lua_register *lreg = (lua_register*)get_obj_ptr (L, THIS_CLASS, 1); delete lreg->regp; return 0; } /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Super Class Creation */ /* methods table for object */ static const luaL_reg register_methods[] = { {"load", register_load}, {"go", register_go}, {0, 0} }; /* metatable of actions */ static const luaL_reg register_meta[] = { {"__gc", register_action_gc}, {0, 0} }; /* glue to C struct */ static const lua_sc_glue getters[] = { {"moving", sc_get_ptr, offsetof (lua_register, moving) }, {"fixed", sc_get_ptr, offsetof (lua_register, fixed) }, {"moving_mask", sc_get_ptr, offsetof (lua_register, moving_roi) }, {"fixed_mask", sc_get_ptr, offsetof (lua_register, fixed_roi) }, {0, 0} }; static const lua_sc_glue setters[] = { {"moving", sc_set_ptr, offsetof (lua_register, moving) }, {"fixed", sc_set_ptr, offsetof (lua_register, fixed) }, {"moving_mask", sc_set_ptr, offsetof (lua_register, moving_roi) }, {"fixed_mask", sc_set_ptr, offsetof (lua_register, fixed_roi) }, {0, 0} }; int register_lua_class_register (lua_State *L) { return register_lua_super_class (L, THIS_CLASS, register_methods, register_meta, getters, setters); } lua_class_register.h000066400000000000000000000015451321604176500320740ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _lua_class_register_h_ #define _lua_class_register_h_ #include "plmscript_config.h" #include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "lua_class_image.h" #include "lua_class_structs.h" #define _MAX_STAGES 20 class Registration_parms; typedef struct lua_register_struct lua_register; struct lua_register_struct { std::string fn; Registration_parms *regp; lua_image *moving; lua_image *fixed; lua_ss *moving_roi; lua_ss *fixed_roi; }; PLMSCRIPT_C_API int register_lua_class_register (lua_State *L); PLMSCRIPT_C_API void init_register_instance (lua_register* lregister); #endif lua_class_stage.cxx000066400000000000000000000041361321604176500317250ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmscript_config.h" #include #include #include extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #include "lua_class_stage.h" #include "lua_util.h" /* Name of class as exposed to Lua */ #define THIS_CLASS LUA_CLASS_STAGE /* Helpers */ void init_stage_instance (lua_stage* lstage) { lstage->active = false; lstage->foo = 0; lstage->bar = 0; } /*******************************************************/ /* Object Methods */ /*******************************************************/ static int stage_new (lua_State *L) { lua_stage *lstage = (lua_stage*)lua_new_instance (L, LUA_CLASS_STAGE, sizeof(lua_stage)); init_stage_instance (lstage); return 1; } /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Object Actions */ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Action: garbage collection */ static int stage_action_gc (lua_State *L) { return 0; } /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Super Class Creation */ static const luaL_reg stage_methods[] = { {"new", stage_new}, {0, 0} }; /* metatable of actions */ static const luaL_reg stage_meta[] = { {"__gc", stage_action_gc}, {0, 0} }; /* glue to C struct */ static const lua_sc_glue getters[] = { {"foo", sc_get_int, offsetof (lua_stage_struct, foo) }, {"bar", sc_get_int, offsetof (lua_stage_struct, bar) }, {0, 0} }; static const lua_sc_glue setters[] = { {"foo", sc_set_int, offsetof (lua_stage_struct, foo) }, {"bar", sc_set_int, offsetof (lua_stage_struct, bar) }, {0, 0} }; int register_lua_class_stage (lua_State *L) { return register_lua_super_class (L, LUA_CLASS_STAGE, stage_methods, stage_meta, getters, setters); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/lua_class_stage.h000066400000000000000000000012221321604176500314220ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _lua_class_stage_h_ #define _lua_class_stage_h_ #include "plmscript_config.h" #include "lua.h" #include "lualib.h" #include "lauxlib.h" #define LUA_CLASS_STAGE "stage" typedef struct lua_stage_struct lua_stage; struct lua_stage_struct { bool active; int foo; int bar; }; PLMSCRIPT_C_API int register_lua_class_stage (lua_State *L); PLMSCRIPT_C_API void init_stage_instance (lua_stage* lstage); #endif lua_class_structs.cxx000066400000000000000000000063141321604176500323310ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmscript_config.h" #include #include #include extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #include "lua_classes.h" #include "lua_class_structs.h" #include "lua_util.h" #include "plm_image.h" /* Name of class as exposed to Lua */ #define THIS_CLASS LUA_CLASS_SS /* Helpers */ void init_ss_instance (lua_ss* lss) { memset (lss->fn, '\0', sizeof(lss->fn)); lss->ss_img = NULL; } /*******************************************************/ /* Object Methods */ /*******************************************************/ static int ss_info (lua_State *L) { /* 1st arg should be "this" */ lua_ss *lss = (lua_ss*)get_obj_ptr (L, THIS_CLASS, 1); lss->ss_img->print (); return 0; } static int ss_load (lua_State *L) { const char* fn = luaL_optlstring (L, 1, NULL, NULL); if (!fn) { fprintf (stderr, "error -- " LUA_CLASS_SS ".load() -- no file specified\n"); return 0; } Plm_image* ss_img = plm_image_load (fn, PLM_IMG_TYPE_ITK_UCHAR); if (!ss_img) { fprintf (stderr, "error -- " LUA_CLASS_SS ".load() -- unable to load %s\n", fn); return 0; } lua_ss *lss = (lua_ss*)lua_new_instance (L, THIS_CLASS, sizeof(lua_ss)); init_ss_instance (lss); strcpy (lss->fn, fn); lss->ss_img = ss_img; return 1; } static int ss_save (lua_State *L) { lua_ss *lss = (lua_ss*)get_obj_ptr (L, THIS_CLASS, 1); const char* fn = luaL_optlstring (L, 2, NULL, NULL); Plm_image *ss_img = lss->ss_img; if (!fn) { if (lss->fn[0] == '\0') { fprintf (stderr, "warning -- " LUA_CLASS_SS ":save() -- filename must be specified when saving derived images\n"); return 0; } else { fn = lss->fn; } } else { /* "Save-As" new volume on disk */ ss_img->save_image (fn); strcpy (lss->fn, fn); } #if 0 /* save using current format */ if (lss->rtss->m_ss_img) { lss->rtss->save_ss_image (fn); lss->rtss->save_XXX (lss->fn); } #endif return 0; } /*******************************************************/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Object Actions */ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Action: garbage collection */ static int ss_action_gc (lua_State *L) { lua_ss *lss = (lua_ss*)get_obj_ptr (L, THIS_CLASS, 1); delete lss->ss_img; return 0; } /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Object Creation */ /* methods table for object */ static const luaL_reg ss_methods[] = { {"info", ss_info}, {"load", ss_load}, {"save", ss_save}, {0, 0} }; /* metatable of actions */ static const luaL_reg ss_meta[] = { {"__gc", ss_action_gc}, {0, 0} }; int register_lua_class_ss (lua_State *L) { return register_lua_class (L, THIS_CLASS, ss_methods, ss_meta); } lua_class_structs.h000066400000000000000000000011571321604176500317560ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _lua_class_structs_h_ #define _lua_class_structs_h_ #include "plmscript_config.h" #include "lua.h" #include "lualib.h" #include "lauxlib.h" class Plm_image; typedef struct lua_ss_struct lua_ss; struct lua_ss_struct { std::string fn; Plm_image* ss_img; }; PLMSCRIPT_C_API int register_lua_class_ss (lua_State *L); PLMSCRIPT_C_API void init_ss_instance (lua_ss* lss); #endif lua_class_xform.cxx000066400000000000000000000172351321604176500317610ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmscript_config.h" #include #include #include extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #include "lua_classes.h" #include "lua_class_image.h" #include "lua_class_structs.h" #include "lua_class_xform.h" #include "lua_util.h" #include "pcmd_script.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_warp.h" #include "xform.h" #include "xform_convert.h" /* Name of class as exposed to Lua */ #define THIS_CLASS LUA_CLASS_XFORM /* Helpers */ void init_xform_instance (lua_xform* lxf) { memset (lxf->fn, '\0', sizeof(lxf->fn)); lxf->pxf = NULL; } /*******************************************************/ /* Object Methods */ /*******************************************************/ static int xform_load (lua_State *L) { const char* fn = luaL_optlstring (L, 1, NULL, NULL); if (!fn) { fprintf (stderr, "error -- xform.load() -- no file specified\n"); return 0; } Xform* pxf = new Xform; xform_load (pxf, fn); if (!pxf) { fprintf (stderr, "error -- xform.load() -- unable to load %s\n", fn); return 0; } lua_xform *lxf = (lua_xform*)lua_new_instance (L, THIS_CLASS, sizeof(lua_xform)); init_xform_instance (lxf); strcpy (lxf->fn, fn); lxf->pxf = pxf; return 1; } static int xform_save (lua_State *L) { lua_xform *lxf = (lua_xform*)get_obj_ptr (L, THIS_CLASS, 1); const char* fn = luaL_optlstring (L, 2, NULL, NULL); if (!fn) { if (lxf->fn[0] == '\0') { fprintf (stderr, "warning -- xform:save() -- filename must be specified when saving derived transforms\n"); return 0; } else { /* Save over current transform on disk */ xform_save (lxf->pxf, lxf->fn); } } else { /* "Save-As" new transform on disk */ xform_save (lxf->pxf, fn); strcpy (lxf->fn, fn); } return 0; } static int xform_export_vf (lua_State *L) { lua_xform *lxf = (lua_xform*)get_obj_ptr (L, THIS_CLASS, 1); const char* fn = luaL_optlstring (L, 2, NULL, NULL); if (!fn) { fprintf (stderr, "warning -- xform:save_vf() -- filename must be specified\n"); return 0; } Xform_convert xfc; xfc.m_xf_out_type = XFORM_ITK_VECTOR_FIELD; xfc.m_xf_out = new Xform; xfc.m_xf_in = lxf->pxf; (xfc.m_xf_in)->get_volume_header (&(xfc.m_volume_header)); xform_convert (&xfc); xform_save (xfc.m_xf_out, fn); /* JAS 2012.03.06 -- m_xf_out is automatically deleted in the Xform_convert * destructor. I feel that if that is the case, then m_xf_out should * probably be handled by the constructor as well. I just lost an hour * debugging a backtrace due to this asymmetric design. Furthermore, I * have to do strange looking things like this to prevent stuff I want to * keep from magically disappearing... ::ugh:: */ xfc.m_xf_in = NULL; return 0; } /*******************************************************/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Object Actions */ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Action: garbage collection */ static int xform_action_gc (lua_State *L) { lua_xform *lxf = (lua_xform*)get_obj_ptr (L, THIS_CLASS, 1); // fprintf (stderr, "debug -- xform.__gc -- releasing %s [%p]\n", lxf->fn, lxf); delete lxf->pxf; return 0; } /* Action: add * [1] xform + image = warp * [2] ????? + ????? = ???? */ static int xform_action_add (lua_State *L) { lua_xform* lxf; lua_image* limg_in; lua_image* limg_out; lua_ss *lss_in; lua_ss *lss_out; Plm_image_header pih; /* xform + image */ if ( (lua_check_type (L, THIS_CLASS, 1) && lua_check_type (L, LUA_CLASS_IMAGE, 2)) || (lua_check_type (L, THIS_CLASS, 2) && lua_check_type (L, LUA_CLASS_IMAGE, 1)) ) { /* Load the parms, but which is which? */ if (lua_check_type (L, THIS_CLASS, 1)) { lxf = (lua_xform*)get_obj_ptr (L, THIS_CLASS, 1); limg_in = (lua_image*)get_obj_ptr (L, LUA_CLASS_IMAGE, 2); } else if (lua_check_type (L, LUA_CLASS_IMAGE, 1)) { lxf = (lua_xform*)get_obj_ptr (L, THIS_CLASS, 2); limg_in = (lua_image*)get_obj_ptr (L, LUA_CLASS_IMAGE, 1); } else { fprintf (stderr, "internal error -- xform.__add() -- please file bug report\n"); exit (0); } limg_out = (lua_image*)lua_new_instance (L, LUA_CLASS_IMAGE, sizeof(lua_image)); init_image_instance (limg_out); limg_out->pli = new Plm_image; pih.set_from_gpuit_bspline (lxf->pxf->get_gpuit_bsp()); plm_warp ( limg_out->pli, /* output image */ NULL, /* output vf */ lxf->pxf, /* xform */ &pih, /* ouput geometry */ limg_in->pli, /* input image */ -1000, /* default hu value */ 0, /* 1: force ITK warp */ 1 /* 1: Trilinear 0: nn */ ); return 1; } /* xform + ss_img */ if ( (lua_check_type (L, THIS_CLASS, 1) && lua_check_type (L, LUA_CLASS_SS, 2)) || (lua_check_type (L, THIS_CLASS, 2) && lua_check_type (L, LUA_CLASS_SS, 1)) ) { /* Load the parms, but which is which? */ if (lua_check_type (L, THIS_CLASS, 1)) { lxf = (lua_xform*)get_obj_ptr (L, THIS_CLASS, 1); lss_in = (lua_ss*)get_obj_ptr (L, LUA_CLASS_SS, 2); } else if (lua_check_type (L, LUA_CLASS_SS, 1)) { lxf = (lua_xform*)get_obj_ptr (L, THIS_CLASS, 2); lss_in = (lua_ss*)get_obj_ptr (L, LUA_CLASS_SS, 1); } else { fprintf (stderr, "internal error -- xform.__add() -- please file bug report\n"); exit (0); } lss_out = (lua_ss*)lua_new_instance (L, LUA_CLASS_SS, sizeof(lua_ss)); init_ss_instance (lss_out); lss_out->ss_img = new Plm_image; pih.set_from_plm_image (lss_in->ss_img); #if 0 plm_warp ( lss_out->ss_img, /* output image */ NULL, /* output vf */ lxf->pxf, /* xform */ &pih, /* ouput geometry */ lss_in->ss_img, /* input image */ 0, /* default hu value */ 0, /* 1: force ITK warp */ 0 /* 1: Trilinear 0: nn */ ); #endif return 1; } /* unsupported operand */ else { fprintf (stderr, "warning -- xform.__add() -- invalid operand: returning (nil)\n"); return 0; } } /*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Object Creation */ /* methods table for object */ static const luaL_reg xform_methods[] = { {"load", xform_load}, {"save", xform_save}, {"export_vf", xform_export_vf}, {0, 0} }; /* metatable of actions */ static const luaL_reg xform_meta[] = { {"__gc", xform_action_gc}, {"__add", xform_action_add}, {0, 0} }; int register_lua_class_xform (lua_State *L) { return register_lua_class (L, THIS_CLASS, xform_methods, xform_meta); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/lua_class_xform.h000066400000000000000000000011621321604176500314550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _lua_class_xform_h_ #define _lua_class_xform_h_ #include "plmscript_config.h" #include "lua.h" #include "lualib.h" #include "lauxlib.h" class Xform; typedef struct lua_xform_struct lua_xform; struct lua_xform_struct { std::string fn; Xform* pxf; }; PLMSCRIPT_C_API int register_lua_class_xform (lua_State *L); PLMSCRIPT_C_API void init_xform_instance (lua_xform* lxf); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/lua_classes.h000066400000000000000000000012621321604176500305730ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* This file just keeps a registry of all the Lua classes */ #ifndef _lua_classes_h_ #define _lua_classes_h_ #define LUA_CLASS_IMAGE "Image" #define LUA_CLASS_REGISTER "Register" #define LUA_CLASS_SS "Structs" #define LUA_CLASS_XFORM "XForm" static const char* lua_classes[] = { LUA_CLASS_IMAGE, LUA_CLASS_REGISTER, LUA_CLASS_SS, LUA_CLASS_XFORM }; static const int num_lua_classes = sizeof (lua_classes)/sizeof(char*); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/lua_cli_glue.cxx000066400000000000000000000113141321604176500312730ustar00rootroot00000000000000#include "plmscript_config.h" #include #include #include extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #include "lua_cli_glue.h" // JAS 2012.02.2 - Planned for removal in favor of // more elegant Lua objects and classes //------------------------------------------------------------------- /* Command Line Glue */ void lua_cli_glue_init (lua_State* L, int* argc, char*** argv) { /* # of parameters passed via lua stack + 2 */ /* 1 for argv[0] = "plastimatch" */ /* 1 for argv[1] = specified pcmd */ luaL_checktype(L, 1, LUA_TTABLE); *argc = 2*from_lua_count_struct_members (L) + 2; *argv = (char**)malloc (*argc * sizeof(char*)); for (int i=0; i<*argc; i++) { (*argv)[i] = NULL; } (*argv)[0] = (char*)malloc (strlen("plastimatch") * sizeof(char)); strcpy ((*argv)[0], "plastimatch"); } void lua_cli_glue_grow (lua_State* L, int n, int* argc, char*** argv) { char** p = (char**)realloc (*argv, (*argc+n) * sizeof(char*)); if (p) { *argv = p; } for (int i=*argc; i<(*argc)+n; i++) { (*argv)[i] = NULL; } *argc += n; } void lua_cli_glue_add (lua_State* L, char* arg, char** argv) { if (*argv == NULL) { *argv = (char*)malloc (strlen(arg) * sizeof(char)); } else { char* p = (char*)realloc (*argv, strlen(arg) * sizeof(char)); if (p) { *argv = p; } } strcpy (*argv, arg); } void lua_cli_glue_solvent (lua_State* L, char** argv, int argn) { for (int i=0; i #include #include #include extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" } #include "lua_tty.h" #include "lua_tty_commands.h" static lua_State *globalL = NULL; static const char *progname = TTY_PROGNAME; static const char *tty_prompt = TTY_PROMPT; static const char *tty_prompt2 = TTY_PROMPT2; /* SIGNAL HANDLERS */ static void lstop (lua_State *L, lua_Debug *ar) { (void)ar; /* unused arg. */ lua_sethook(L, NULL, 0, 0); luaL_error(L, "interrupted!"); } /* SIGNAL HANDLERS */ static void laction (int i) { signal(i, SIG_DFL); /* if another SIGINT happens before lstop, terminate process (default action) */ lua_sethook (globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } /* HELPER: error handling */ static void l_message (const char *pname, const char *msg) { if (pname) { fprintf(stderr, "%s: ", pname); } fprintf(stderr, "%s\n", msg); fflush(stderr); } static int report (lua_State *L, int status) { if (status && !lua_isnil (L, -1)) { const char *msg = lua_tostring (L, -1); if (msg == NULL) { msg = "(error object is not a string)"; } l_message (progname, msg); lua_pop(L, 1); } return status; } static int traceback (lua_State *L) { /* if 'message' not a string, keep it intact */ if (!lua_isstring(L, 1)) { return 1; } lua_getfield (L, LUA_GLOBALSINDEX, "debug"); if (!lua_istable (L, -1)) { lua_pop (L, 1); return 1; } lua_getfield(L, -1, "traceback"); if (!lua_isfunction(L, -1)) { lua_pop (L, 2); return 1; } lua_pushvalue (L, 1); /* pass error message */ lua_pushinteger (L, 2); /* skip this function and traceback */ lua_call (L, 2, 1); /* call debug.traceback */ return 1; } static int do_call (lua_State *L, int narg, int clear) { int status; int base = lua_gettop (L) - narg; /* function index */ /* push traceback function */ lua_pushcfunction (L, traceback); /* put it under chunk and args */ lua_insert (L, base); signal (SIGINT, laction); status = lua_pcall (L, narg, (clear ? 0 : TTY_MULTRET), base); signal (SIGINT, SIG_DFL); /* remove traceback function */ lua_remove (L, base); /* force a complete garbage collection in case of errors */ if (status != 0) { lua_gc (L, LUA_GCCOLLECT, 0); } return status; } static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring (L, -1, &lmsg); const char *tp = msg + lmsg - (sizeof(TTY_QL("")) - 1); if (strstr (msg, TTY_QL("")) == tp) { lua_pop(L, 1); return 1; } } return 0; } static const char* get_prompt (lua_State *L, int firstline) { const char *p; lua_getfield (L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) { p = (firstline ? tty_prompt : tty_prompt2); } lua_pop(L, 1); /* remove global */ return p; } static int pushline (lua_State *L, int firstline) { int i; char buffer[TTY_MAXINPUT]; char *b = buffer; char tb[TTY_MAXINPUT]; char *token; size_t l; const char *prmt = get_prompt (L, firstline); if (lua_readline (L, b, prmt) == 0) { return 0; /* no input */ } l = strlen (b); /* if line ends with newline, remove it */ if (l > 0 && b[l-1] == '\n') { b[l-1] = '\0'; } if (firstline && l>0) { /* check for TTY commands */ strcpy (tb, b); token = strtok (tb, " "); for (i=0; i " /* * Supplement to valid status return codes * found in lua.h -- for catching non-lua * commands so we can extend the TTY functionality */ #define LUA_COMMAND 0 #define TTY_COMMAND 101 #if defined __cplusplus extern "C" { #endif /* For TTY history */ #if (READLINE_FOUND) #include #include #define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) #define lua_saveline(L,idx) \ if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ add_history(lua_tostring(L, idx)); /* add it to history */ #define lua_freeline(L,b) ((void)L, free(b)) #else #define lua_readline(L,b,p) \ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ fgets(b, TTY_MAXINPUT, stdin) != NULL) /* get line */ #define lua_saveline(L,idx) { (void)L; (void)idx; } #define lua_freeline(L,b) { (void)L; (void)b; } #endif PLMSCRIPT_C_API void do_tty (lua_State *L); PLMSCRIPT_C_API void do_stdin (lua_State *L); #if defined __cplusplus } #endif #endif lua_tty_commands.cxx000066400000000000000000000143611321604176500321370ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmscript_config.h" #include #include #include #include extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" } #include "lua_classes.h" #include "lua_class_image.h" #include "lua_tty.h" #include "lua_tty_commands.h" //#include "lua_tty_commands_pcmd.h" #include "lua_tty_commands_util.h" #include "lua_tty_preview.h" #include "lua_util.h" #include "file_util.h" static void do_tty_command_pwd (lua_State* L, int argc, char** argv); /* JAS 2012.04.27 * pcmd interface has been disabled since the * new plastimatch architecture places the * plastimatch command line at the top of the link * dependencies tree. */ /* displays commands available to user */ static void do_tty_command_help (lua_State* L, int argc, char** argv) { if (argc == 1) { print_command_table (tty_cmds, num_tty_cmds, 60, 3); } else { #if 0 if (!strcmp (argv[1], TTY_CMD_PCMD)) { print_command_table (pcmds, num_pcmds, 60, 3); } #endif if (!strcmp (argv[1], TTY_CMD_CD)) { fprintf (stdout, "change current working directory\n"); } else if (!strcmp (argv[1], TTY_CMD_RUN)) { fprintf (stdout, "execute a script from disk\n"); fprintf (stdout, " Usage: " TTY_CMD_RUN " script_name\n"); } else if ( (!strcmp (argv[1], TTY_CMD_DIR)) || (!strcmp (argv[1], TTY_CMD_LS)) ) { fprintf (stdout, "get listing for current directory\n"); } else if (!strcmp (argv[1], TTY_CMD_LIST)) { fprintf (stdout, "display allocated Plastimatch objects.\n"); fprintf (stdout, " Usage: " TTY_CMD_LIST " [type]\n\n"); fprintf (stdout, "valid types:\n"); print_command_table (lua_classes, num_lua_classes, 60, 3); } } fprintf (stdout, "\n"); } /* change current working directory */ static void do_tty_command_cd (lua_State* L, int argc, char** argv) { int ret; char* path; /* if no arguments, just pwd */ if (argc < 2) { do_tty_command_pwd (L, argc, argv); return; } else { path = argv[1]; } ret = plm_chdir (path); if (ret == -1) { switch (errno) { case EACCES: fprintf (stdout, "cd -- permission denied\n"); break; case ENAMETOOLONG: fprintf (stdout, "cd -- specified path exceeds allowed length\n"); break; case ENOENT: fprintf (stdout, "cd -- specified directory not found\n"); break; case ENOTDIR: fprintf (stdout, "cd -- specified path not a directory\n"); break; #if (UNIX) case ELOOP: fprintf (stdout, "cd -- encountered too many symbolic links\n"); break; #endif } } } /* run a lua script from within the tty environment */ static void do_tty_command_run (lua_State* L, int argc, char** argv) { /* run lua script */ if (argc < 2) return; if (file_exists (argv[1])) { printf ("-- running script : %s\n\n", argv[1]); luaL_dofile (L, argv[1]); } else { printf ("unable to load script: %s\n", argv[1]); } } /* dispaly count and names of allocated Plastimatch objects */ static void do_tty_command_list (lua_State* L, int argc, char** argv) { if (argc < 2) { /* no arguments -- list everything */ for (int i=0; ipli); } else { fprintf (stdout, "%s does not exist\n", img_obj_name); } #else fprintf (stdout, "preview not available -- plastimatch not compiled against QT4.\n"); #endif } static void do_tty_command_pwd (lua_State* L, int argc, char** argv) { char* b = NULL; b = plm_getcwd (NULL, 0); printf ("%s\n", b); free (b); } /* main tty command parser. if you hit this, then * the Lua 'interpreter' is bypassed entirely */ void do_tty_command (lua_State *L) { char cmd[TTY_MAXINPUT]; char** argv; int argc; memset (cmd, '\0', TTY_MAXINPUT * sizeof(char)); strcpy (cmd, lua_tolstring (L, 1, NULL)); lua_pop (L, 1); build_args (&argc, &argv, cmd); if (!strcmp (argv[0], TTY_CMD_HELP)) { do_tty_command_help (L, argc, argv); } else if (!strcmp (argv[0], TTY_CMD_CD)) { do_tty_command_cd (L, argc, argv); } else if (!strcmp (argv[0], TTY_CMD_DIR) || !strcmp (argv[0], TTY_CMD_LS)) { do_tty_command_ls (L, argc, argv); } else if (!strcmp (argv[0], TTY_CMD_LIST)) { do_tty_command_list (L, argc, argv); } #if 0 else if (!strcmp (argv[0], TTY_CMD_PCMD)) { do_tty_command_pcmd (argc, argv); } #endif else if (!strcmp (argv[0], TTY_CMD_PREVIEW)) { do_tty_command_preview (L, argc, argv); } else if (!strcmp (argv[0], TTY_CMD_PWD)) { do_tty_command_pwd (L, argc, argv); } else if (!strcmp (argv[0], TTY_CMD_RUN)) { do_tty_command_run (L, argc, argv); } } lua_tty_commands.h000066400000000000000000000020361321604176500315600ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _lua_tty_commands_h_ #define _lua_tty_commands_h_ #include "plmscript_config.h" #if defined __cplusplus extern "C" { #endif /* Valid TTY command names */ #define TTY_CMD_CD "cd" #define TTY_CMD_DIR "dir" #define TTY_CMD_EXIT "exit" #define TTY_CMD_HELP "help" #define TTY_CMD_LS "ls" #define TTY_CMD_LIST "list" #define TTY_CMD_PCMD "pcmd" #define TTY_CMD_PREVIEW "preview" #define TTY_CMD_PWD "pwd" #define TTY_CMD_RUN "run" static const char* tty_cmds[] = { TTY_CMD_CD, TTY_CMD_DIR, TTY_CMD_HELP, TTY_CMD_LS, TTY_CMD_LIST, TTY_CMD_PCMD, TTY_CMD_PREVIEW, TTY_CMD_PWD, TTY_CMD_RUN }; static const int num_tty_cmds = sizeof (tty_cmds)/sizeof(char*); PLMSCRIPT_C_API void do_tty_command (lua_State *L); #if defined __cplusplus } #endif #endif lua_tty_commands_pcmd.cxx000066400000000000000000000074071321604176500331450ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmscript_config.h" #include "lua_tty_commands_pcmd.h" #include "plmregister.h" #include "pcmd_add.h" #include "pcmd_adjust.h" #include "pcmd_autolabel.h" #include "pcmd_autolabel_train.h" #include "pcmd_compare.h" #include "pcmd_compose.h" #include "pcmd_crop.h" #include "pcmd_diff.h" #include "pcmd_drr.h" #include "pcmd_dvh.h" #include "pcmd_xio_dvh.h" #include "pcmd_mask.h" #include "pcmd_maximum.h" #include "pcmd_multiply.h" #include "pcmd_header.h" #include "pcmd_jacobian.h" #include "pcmd_probe.h" #include "pcmd_resample.h" #include "pcmd_segment.h" #include "pcmd_stats.h" #include "pcmd_synth.h" #include "pcmd_thumbnail.h" #include "pcmd_warp.h" #include "pcmd_xf_convert.h" void do_tty_command_pcmd (int argc, char** argv) { char* command = argv[1]; if (!strcmp (command, PCMD_ADD)) { do_command_add (argc, argv); } else if (!strcmp (command, PCMD_ADJUST)) { do_command_adjust (argc, argv); } else if (!strcmp (command, PCMD_AUTOLABEL)) { do_command_autolabel (argc, argv); } else if (!strcmp (command, PCMD_AUTOLABEL_TRAIN)) { do_command_autolabel_train (argc, argv); } else if (!strcmp (command, PCMD_COMPARE)) { do_command_compare (argc, argv); } else if (!strcmp (command, PCMD_COMPOSE)) { do_command_compose (argc, argv); } else if (!strcmp (command, PCMD_CONVERT)) { /* convert and warp are the same */ do_command_warp (argc, argv); } else if (!strcmp (command, PCMD_CROP)) { do_command_crop (argc, argv); } else if (!strcmp (command, PCMD_DIFF)) { do_command_diff (argc, argv); } else if (!strcmp (command, PCMD_DRR)) { do_command_drr (argc, argv); } else if (!strcmp (command, PCMD_DVH)) { do_command_dvh (argc, argv); } else if (!strcmp (command, PCMD_HEADER)) { do_command_header (argc, argv); } else if (!strcmp (command, PCMD_JACOBIAN)) { do_command_jacobian (argc, argv); } else if (!strcmp (command, PCMD_FILL)) { /* fill and mask are the same */ do_command_mask (argc, argv); } else if (!strcmp (command, PCMD_MASK)) { /* fill and mask are the same */ do_command_mask (argc, argv); } else if (!strcmp (command, PCMD_MAXIMUM)) { do_command_mask (argc, argv); } else if (!strcmp (command, PCMD_MULTIPLY)) { do_command_multiply (argc, argv); } else if (!strcmp (command, PCMD_PROBE)) { do_command_probe (argc, argv); } #if 0 else if (!strcmp (command, PCMD_REGISTER)) { do_command_register (argc, argv); } #endif else if (!strcmp (command, PCMD_RESAMPLE)) { do_command_resample (argc, argv); } else if (!strcmp (command, PCMD_SEGMENT)) { do_command_segment (argc, argv); } else if (!strcmp (command, PCMD_SLICE)) { print_and_exit ("Error: slice command is now called thumbnail.\n"); } else if (!strcmp (command, PCMD_THUMBNAIL)) { do_command_thumbnail (argc, argv); } else if (!strcmp (command, PCMD_STATS)) { do_command_stats (argc, argv); } else if (!strcmp (command, PCMD_SYNTH)) { do_command_synth (argc, argv); } else if (!strcmp (command, PCMD_WARP)) { /* convert and warp are the same */ do_command_warp (argc, argv); } else if (!strcmp (command, PCMD_XF_CONVERT)) { do_command_xf_convert (argc, argv); } else if (!strcmp (command, PCMD_XIO_DVH)) { do_command_xio_dvh (argc, argv); } } lua_tty_commands_pcmd.h000066400000000000000000000042151321604176500325640ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _lua_tty_commands_pcmd_h_ #define _lua_tty_commands_pcmd_h_ #include "plmscript_config.h" #if defined __cplusplus extern "C" { #endif /* Exposed plastimatch command line commands */ #define PCMD_ADD "add" #define PCMD_ADJUST "adjust" #define PCMD_AUTOLABEL "autolabel" #define PCMD_AUTOLABEL_TRAIN "autolabel-train" #define PCMD_COMPARE "compare" #define PCMD_COMPOSE "compose" #define PCMD_CONVERT "convert" #define PCMD_CROP "crop" #define PCMD_DIFF "diff" #define PCMD_DRR "drr" #define PCMD_DVH "dvh" #define PCMD_HEADER "header" #define PCMD_JACOBIAN "jacobian" #define PCMD_FILL "fill" #define PCMD_MASK "mask" #define PCMD_MAXIMUM "maximum" #define PCMD_MULTIPLY "multiply" #define PCMD_PROBE "probe" //#define PCMD_REGISTER "register" #define PCMD_RESAMPLE "resample" #define PCMD_SEGMENT "segment" #define PCMD_SLICE "slice" #define PCMD_THUMBNAIL "thumbnail" #define PCMD_STATS "stats" #define PCMD_SYNTH "synth" #define PCMD_WARP "warp" #define PCMD_XF_CONVERT "xf-convert" #define PCMD_XIO_DVH "xio-dvh" static const char* pcmds[] = { PCMD_ADD, PCMD_ADJUST, PCMD_AUTOLABEL, PCMD_AUTOLABEL_TRAIN, PCMD_COMPARE, PCMD_COMPOSE, PCMD_CONVERT, PCMD_CROP, PCMD_DIFF, PCMD_DRR, PCMD_DVH, PCMD_HEADER, PCMD_JACOBIAN, PCMD_FILL, PCMD_MASK, PCMD_MAXIMUM, PCMD_MULTIPLY, PCMD_PROBE, // PCMD_REGISTER, PCMD_RESAMPLE, PCMD_SEGMENT, PCMD_SLICE, PCMD_THUMBNAIL, PCMD_STATS, PCMD_SYNTH, PCMD_WARP, PCMD_XF_CONVERT, PCMD_XIO_DVH }; static const int num_pcmds = sizeof (pcmds)/sizeof(char*); PLMSCRIPT_C_API void do_tty_command_pcmd (int argc, char** argv); #if defined __cplusplus } #endif #endif lua_tty_commands_util.cxx000066400000000000000000000070011321604176500331650ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmscript_config.h" #include #include #include extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" } #include "lua_tty.h" #include "lua_tty_commands_util.h" #include "lua_util.h" void print_command_table ( const char* cmds[], /* command array */ unsigned int nc, /* # of commands */ unsigned int tw, /* table width */ unsigned int sp /* minimum spacing */ ) { unsigned int i; unsigned int c,w,n; /* col, word, command # */ size_t lc; /* longest command */ lc = 0; for (i=0; i lc) { lc = strlen (cmds[i]); } } c=0;w=0;n=0; while (n=nc) break; } printf ("\n"); c=0; } } void build_args (int* argc, char*** argv, char* cmd) { int i; char tmp[TTY_MAXINPUT]; char* token; /* get argc */ strcpy (tmp, cmd); token = strtok (tmp, " "); *argc=0; while (token) { token = strtok (NULL, " "); (*argc)++; } *argv = (char**)malloc (*argc * sizeof(char*)); /* populate argv */ token = strtok (cmd, " "); (*argv)[0] = (char*)malloc (strlen(token)*sizeof(char)); strcpy ((*argv)[0], token); for (i=1; i<*argc; i++) { token = strtok (NULL, " "); (*argv)[i] = (char*)malloc (strlen(token)*sizeof(char)); strcpy ((*argv)[i], token); } } void list_vars_of_class (lua_State* L, const char* class_name) { int argc; char** argv; char b[9001]; // it's over 9000... memset (b, '\0', 9001*sizeof (char)); lua_pushvalue (L, LUA_GLOBALSINDEX); lua_pushnil (L); while (lua_next (L, -2)) { if (lua_check_type (L, class_name, 3)) { if (b[0] == '\0') { strcpy (b, lua_tostring (L, -2)); } else { strcat (b, " "); strcat (b, lua_tostring (L, -2)); } } lua_pop (L, 1); } lua_pop (L, 1); fprintf (stdout, "[%s] ", class_name); if (b[0] != '\0') { build_args (&argc, &argv, b); fprintf (stdout, "%i item(s)\n", argc); print_command_table ((const char**)argv, argc, 60, 3); } else { fprintf (stdout, "0 items\n"); } } void sort_list (char** c, int n) { int i, j; char* tmp; for (j=0; j<(n-1); j++) { for (i=0; i<(n-(1+j)); i++) { if (c[i][0] > c[i+1][0]) { tmp = c[i+1]; c[i+1] = c[i]; c[i] = tmp; } } } } /* given a variable name, returns ptr */ void* get_obj_ptr_from_name (lua_State* L, const char* name) { void* ptr = NULL; lua_pushvalue (L, LUA_GLOBALSINDEX); lua_pushnil (L); while (lua_next (L, -2)) { if (!strcmp (lua_tostring (L, 2), name)) { ptr = lua_touserdata (L, 3); } lua_pop (L, 1); } lua_pop (L, 1); return ptr; } lua_tty_commands_util.h000066400000000000000000000017461321604176500326240ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _lua_tty_commands_util_h_ #define _lua_tty_commands_util_h_ #include "plmscript_config.h" extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" } #if defined __cplusplus extern "C" { #endif PLMSCRIPT_C_API void print_command_table ( const char* cmds[], /* command array */ unsigned int nc, /* # of commands */ unsigned int tw, /* table width */ unsigned int sp /* minimum spacing */ ); PLMSCRIPT_C_API void build_args (int* argc, char*** argv, char* cmd); PLMSCRIPT_C_API void list_vars_of_class (lua_State* L, const char* class_name); PLMSCRIPT_C_API void sort_list (char** c, int n); PLMSCRIPT_C_API void* get_obj_ptr_from_name (lua_State* L, const char* name); #if defined __cplusplus } #endif #endif lua_tty_preview.cxx000066400000000000000000000040101321604176500320050ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmscript_config.h" #if (UNIX) #include #include #endif #include extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" } #include "cview_portal.h" #include "lua_class_image.h" #include "lua_tty_commands_util.h" #include "lua_tty_preview.h" #include "plm_image.h" ///////////////////////////////////////////////////////// // CrystalWindow : public // #if 0 CrystalWindow::CrystalWindow (int argc, char** argv, QWidget *parent) :QMainWindow (parent) { input_vol = NULL; pli = NULL; createActions (); createMenu (); portalGrid = new PortalGrid; setCentralWidget (portalGrid); /* open mha from command line */ if (argc > 1) { if (!openVol (argv[1])) { std::cout << "Failed to load: " << argv[1] << "\n"; } } } #endif int preview_portal (void* pli_in) { #if (UNIX) int argc = 0; char** argv = NULL; Plm_image* pli = (Plm_image*)pli_in; if (!pli) return -1; /* prevent zombies */ struct sigaction sa; sa.sa_handler = SIG_IGN; sa.sa_flags = SA_NOCLDWAIT; if (sigaction (SIGCHLD, &sa, NULL) == -1) { perror ("sigaction()"); exit (1); } pid_t child_pid; switch (child_pid = fork()) { case -1: perror ("fork()"); exit (1); case 0: QApplication app (argc, argv); PortalWidget* portal = new PortalWidget; //attach pli to portal portal->resetPortal(); portal->setVolume (pli->get_vol_float()); portal->setView (PortalWidget::Axial); portal->show(); app.exec(); exit (0); } return 0; #else fprintf (stdout, "preview not available for non-unix... yet.\n"); return 0; #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/lua_tty_preview.h000066400000000000000000000007031321604176500315160ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _lua_tty_preview_h_ #define _lua_tty_preview_h_ #include "plmscript_config.h" #if defined __cplusplus extern "C" { #endif PLMSCRIPT_C_API int preview_portal (void* pli); #if defined __cplusplus } #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/lua_util.cxx000066400000000000000000000162231321604176500304710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmscript_config.h" #include #include #include extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "lobject.h" } #include "lua_util.h" /* utility functions */ int lua_check_type (lua_State *L, const char* class_name, int index) { void *p = lua_touserdata (L, index); if (p) { if (lua_getmetatable (L, index)) { lua_getfield (L, LUA_REGISTRYINDEX, class_name); if (lua_rawequal(L, -1, -2)) { lua_pop(L, 2); return 1; } lua_pop (L, 1); } lua_pop (L, 1); } return 0; } void* lua_new_instance (lua_State *L, const char* class_name, size_t size) { void *tmp = (void*)lua_newuserdata (L, size); luaL_getmetatable (L, class_name); lua_setmetatable (L, -2); return tmp; } void* get_obj_ptr (lua_State *L, const char* class_name, int index) { void* ptr; luaL_checktype (L, index, LUA_TUSERDATA); ptr = (void*)luaL_checkudata (L, index, class_name); if (ptr == NULL) { luaL_typerror (L, index, class_name); } return ptr; } #if 0 static void stack_dump (lua_State *L) { const char* str; const char* typ; float num; for (int i=-1; i>-21; i--) { num = lua_tonumber (L, i); str = lua_tostring (L, i); typ = lua_typename (L, lua_type(L, i)); printf ("[%i] %s \t %s \t %f \n", i, typ, str, num); } } #endif /* --- Super Class Helpers -------------------------- */ int sc_get_int (lua_State *L, void *v) { lua_pushnumber (L, *(int*)v); return 1; } int sc_set_int (lua_State *L, void *v) { *(int*)v = luaL_checkint (L, 3); return 0; } int sc_get_number (lua_State *L, void *v) { lua_pushnumber (L, *(lua_Number*)v); return 1; } int sc_set_number (lua_State *L, void *v) { *(lua_Number*)v = luaL_checknumber (L, 3); return 0; } int sc_get_string (lua_State *L, void *v) { lua_pushstring(L, (char*)v ); return 1; } int sc_set_string (lua_State *L, void *v) { strcpy ((char*)v, luaL_checkstring (L, 3)); return 0; } int sc_get_ptr (lua_State *L, void *v) { lua_pushlightuserdata (L, *(void**)v); return 1; } int sc_set_ptr (lua_State *L, void *v) { *(void**)v = (size_t*)lua_touserdata (L, 3); return 0; } static void super_class_glue_init (lua_State *L, const lua_sc_glue *scg) { for (; scg->name; scg++) { lua_pushstring (L, scg->name); lua_pushlightuserdata (L, (void*)scg); lua_settable (L, -3); } } static int super_class_call (lua_State *L) { // stack_dump (L); /* for get: stack has userdata, index, lightuserdata */ /* for set: stack has userdata, index, value, lightuserdata */ lua_sc_glue* m = (lua_sc_glue*)lua_touserdata (L, -1); /* member info */ lua_pop (L, 1); /* drop lightuserdata */ luaL_checktype (L, 1, LUA_TUSERDATA); return m->func(L, (void *)((char *)lua_touserdata(L, 1) + m->offset)); } static int super_class_index (lua_State *L) { /* stack has userdata, index */ lua_pushvalue (L, 2); /* dup index */ lua_rawget (L, lua_upvalueindex(1)); /* lookup member by name */ if (!lua_islightuserdata (L, -1)) { lua_pop (L, 1); /* drop value */ lua_pushvalue (L, 2); /* dup index */ lua_gettable (L, lua_upvalueindex(2)); /* else try methods */ if (lua_isnil (L, -1)) { /* invalid member */ luaL_error (L, "warning -- invalid member '%s'", lua_tostring(L, 2)); } return 1; } return super_class_call (L); /* call get function */ } static int super_class_newindex (lua_State *L) { /* stack has userdata, index, value */ lua_pushvalue (L, 2); /* dup index */ lua_rawget (L, lua_upvalueindex(1)); /* lookup member by name */ if (!lua_islightuserdata (L, -1)) { /* invalid member */ luaL_error(L, "warning -- invalid member '%s'", lua_tostring(L, 2)); } return super_class_call (L); /* call set function */ } /* -------------------------------------------------- */ /* create a lua class with custom methods */ int register_lua_class ( lua_State *L, const char* class_name, const luaL_reg* methods, const luaL_reg* metatable ) { /* create methods table, add it to the globals */ luaL_openlib (L, class_name, methods, 0); /* create metatable and add it to the Lua registry */ luaL_newmetatable (L, class_name); /* fill metatable */ luaL_openlib (L, 0, metatable, 0); /* direct calls to non-existant members to methods table */ lua_pushliteral (L, "__index"); lua_pushvalue (L, -3); /* push methods table */ lua_rawset (L, -3); /* metatable.__index = methods */ /* protect our metatable */ lua_pushliteral (L, "__metatable"); lua_pushvalue (L, -3); /* push methods table */ lua_rawset (L, -3); /* metatable.__metatable = methods */ lua_pop (L, 1); /* pop metatable */ lua_pop (L, 1); /* pop methods */ return 0; } /* create a lua class with custom methods * that also has members linking directly * to C struct members */ int register_lua_super_class ( lua_State *L, const char* class_name, const luaL_reg* methods, const luaL_reg* metatable, const lua_sc_glue* getters, const lua_sc_glue* setters ) { int metatable_idx; int methods_idx; /* create methods table, & add it to the table of globals */ luaL_openlib (L, class_name, methods, 0); methods_idx = lua_gettop (L); /* create metatable for your_t, & add it to the registry */ luaL_newmetatable (L, class_name); luaL_openlib (L, 0, metatable, 0); /* fill metatable */ metatable_idx = lua_gettop (L); lua_pushliteral (L, "__metatable"); lua_pushvalue (L, methods_idx); /* dup methods table*/ lua_rawset (L, metatable_idx); /* hide metatable: metatable.__metatable = methods */ lua_pushliteral (L, "__index"); lua_pushvalue (L, metatable_idx); /* upvalue index 1 */ super_class_glue_init (L, getters); /* fill metatable with getters */ lua_pushvalue (L, methods_idx); /* upvalue index 2 */ lua_pushcclosure (L, super_class_index, 2); lua_rawset (L, metatable_idx); /* metatable.__index = super_class_index */ lua_pushliteral (L, "__newindex"); lua_newtable (L); /* table for members you can set */ super_class_glue_init (L, setters); /* fill with setters */ lua_pushcclosure (L, super_class_newindex, 1); lua_rawset(L, metatable_idx); /* metatable.__newindex = super_class_newindex */ lua_pop (L, 1); /* pop metatable */ lua_pop (L, 1); /* pop methods */ return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/lua_util.h000066400000000000000000000033561321604176500301210ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _lua_util_h_ #define _lua_util_h_ #include "plmscript_config.h" #include "lua.h" #include "lualib.h" #include "lauxlib.h" typedef int (*Xet_func) (lua_State *L, void *v); typedef struct lua_sc_glue_struct lua_sc_glue; struct lua_sc_glue_struct { const char *name; /* member name */ Xet_func func; /* set/get function for member's type */ size_t offset; /* offset of member in the interfacing C struct */ }; PLMSCRIPT_C_API int sc_get_int (lua_State *L, void *v); PLMSCRIPT_C_API int sc_set_int (lua_State *L, void *v); PLMSCRIPT_C_API int sc_get_number (lua_State *L, void *v); PLMSCRIPT_C_API int sc_set_number (lua_State *L, void *v); PLMSCRIPT_C_API int sc_get_string (lua_State *L, void *v); PLMSCRIPT_C_API int sc_set_string (lua_State *L, void *v); PLMSCRIPT_C_API int sc_get_ptr (lua_State *L, void *v); PLMSCRIPT_C_API int sc_set_ptr (lua_State *L, void *v); PLMSCRIPT_C_API int lua_check_type (lua_State *L, const char* class_name, int index); PLMSCRIPT_C_API void* lua_new_instance (lua_State *L, const char* class_name, size_t size); PLMSCRIPT_C_API void* get_obj_ptr (lua_State *L, const char* class_name, int index); PLMSCRIPT_C_API int register_lua_class ( lua_State *L, const char* class_name, const luaL_reg* methods, const luaL_reg* metatable ); PLMSCRIPT_C_API int register_lua_super_class ( lua_State *L, const char* class_name, const luaL_reg* methods, const luaL_reg* metatable, const lua_sc_glue* getters, const lua_sc_glue* setters ); #endif plmscript_config.h.in000066400000000000000000000013231321604176500321630ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/script/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plmscript_config_h__ #define __plmscript_config_h__ #include "plm_config.h" #if ((defined(_WIN32) || defined(WIN32)) && (defined (PLM_BUILD_SHARED_LIBS))) # ifdef plmscript_EXPORTS # define PLMSCRIPT_C_API EXTERNC __declspec(dllexport) # define PLMSCRIPT_API __declspec(dllexport) # else # define PLMSCRIPT_C_API EXTERNC __declspec(dllimport) # define PLMSCRIPT_API __declspec(dllimport) # endif #else # define PLMSCRIPT_C_API EXTERNC # define PLMSCRIPT_API #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/000077500000000000000000000000001321604176500262615ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/CMakeLists.txt000066400000000000000000000034741321604176500310310ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_segment) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/plmsegment_config.h.in ${CMAKE_BINARY_DIR}/plmsegment_config.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (PLMSEGMENT_LIBRARY_DEPENDENCIES plmregister plmutil plmbase plmsys ${ITK_LIBRARIES} ) set (PLMSEGMENT_LIBRARY_SRC autolabel.cxx autolabel_feature.cxx autolabel_parms.cxx autolabel_ransac_est.cxx autolabel_task.cxx autolabel_thumbnailer.cxx autolabel_trainer.cxx dlib_trainer.cxx mabs.cxx mabs_atlas_selection.cxx mabs_parms.cxx mabs_seg_weights.cxx mabs_seg_weights.h mabs_stats.cxx mabs_staple.cxx mabs_vote.cxx ml_convert.cxx segment_body.cxx ) ##----------------------------------------------------------------------------- ## SPECIAL BUILD RULES: OpenMP ##----------------------------------------------------------------------------- if (OPENMP_FOUND) set (PLMSEGMENT_LIBRARY_LDFLAGS "${OPENMP_LDFLAGS}") set_source_files_properties (mabs_vote.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) endif () ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- plm_add_library ( plmsegment "${PLMSEGMENT_LIBRARY_SRC}" "${PLMSEGMENT_LIBRARY_DEPENDENCIES}" "${PLMSEGMENT_LIBRARY_LDFLAGS}" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "") plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/autolabel.cxx000066400000000000000000000132301321604176500307540ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include "dlib/data_io.h" #include "dlib/svm.h" #include "itkImageRegionIterator.h" #include "autolabel.h" #include "autolabel_parms.h" #include "autolabel_ransac_est.h" #include "autolabel_thumbnailer.h" #include "compiler_warnings.h" #include "dlib_trainer.h" #include "plm_image_header.h" #include "pointset.h" #include "print_and_exit.h" #include "string_util.h" /* ITK typedefs */ typedef itk::ImageRegionConstIterator< FloatImageType > FloatIteratorType; /* Load the network into "dlib_network" (first argument) */ static void load_dlib_network ( dlib::decision_function< Dlib_trainer::Kernel_type > *dlib_network, const std::string& network_fn) { std::ifstream fin (network_fn.c_str(), std::ios::binary); deserialize (*dlib_network, fin); } static void autolabel_la1 (Autolabel_parms *parms) { FILE *fp; std::string network_fn; /* Load network */ network_fn = string_format ("%s/la1.net", parms->network_dir.c_str()); dlib::decision_function< Dlib_trainer::Kernel_type > dlib_network; load_dlib_network (&dlib_network, network_fn); /* Load input image */ Autolabel_thumbnailer thumb; thumb.set_input_image (parms->input_fn); /* Open output file (txt format) */ fp = fopen (parms->output_csv_fn.c_str(), "w"); if (!fp) { print_and_exit ("Failure to open file for write: %s\n", parms->output_csv_fn.c_str()); } /* Loop through slices, and compute score for each slice */ Plm_image_header pih (thumb.pli); float best_score = FLT_MAX; float best_slice = 0.f; UNUSED_VARIABLE (best_slice); for (int i = 0; i < pih.dim(2); i++) { /* Create slice thumbnail and dlib sample */ float loc = pih.origin(2) + i * pih.spacing(2); Dlib_trainer::Dense_sample_type d = thumb.make_sample (loc); /* Predict the value */ float this_score = dlib_network (d); /* Save the (debugging) output to a file */ fprintf (fp, "%g,%g\n", loc, this_score); /* Look for lowest score */ if (this_score < best_score) { best_slice = loc; best_score = this_score; } } fclose (fp); } static void autolabel_tsv1 (Autolabel_parms *parms) { FILE *fp; std::string network_fn; /* Load network */ network_fn = string_format ("%s/tsv1.net", parms->network_dir.c_str()); dlib::decision_function< Dlib_trainer::Kernel_type > dlib_network; load_dlib_network (&dlib_network, network_fn); /* Load input image */ Autolabel_thumbnailer thumb; thumb.set_input_image (parms->input_fn); /* Open output file (txt format) */ fp = fopen (parms->output_csv_fn.c_str(), "w"); if (!fp) { print_and_exit ("Failure to open file for write: %s\n", parms->output_csv_fn.c_str()); } /* Create a vector to hold the results */ Autolabel_point_vector apv; /* Loop through slices, and predict location for each slice */ Plm_image_header pih (thumb.pli); for (int i = 0; i < pih.dim(2); i++) { /* Create slice thumbnail and dlib sample */ float loc = pih.origin(2) + i * pih.spacing(2); Dlib_trainer::Dense_sample_type d = thumb.make_sample (loc); /* Predict the value */ Autolabel_point ap; ap[0] = loc; ap[1] = dlib_network (d); ap[2] = 0.; apv.push_back (ap); } /* Run RANSAC to refine the estimate */ if (parms->enforce_anatomic_constraints) { autolabel_ransac_est (apv); } /* Save the (debugging) output to a file */ Autolabel_point_vector::iterator it; for (it = apv.begin(); it != apv.end(); it++) { fprintf (fp, "%g,%g,%g\n", (*it)[0], (*it)[1], (*it)[2]); } fclose (fp); } static void autolabel_tsv2 (Autolabel_parms *parms) { Labeled_pointset points; std::string network_fn; /* Load x & y networks */ network_fn = string_format ("%s/tsv2_x.net", parms->network_dir.c_str()); dlib::decision_function< Dlib_trainer::Kernel_type > dlib_network_x; load_dlib_network (&dlib_network_x, network_fn); network_fn = string_format ("%s/tsv2_y.net", parms->network_dir.c_str()); dlib::decision_function< Dlib_trainer::Kernel_type > dlib_network_y; load_dlib_network (&dlib_network_y, network_fn); /* Load input image */ Autolabel_thumbnailer thumb; thumb.set_input_image (parms->input_fn); /* Loop through slices, and predict location for each slice */ Plm_image_header pih (thumb.pli); for (int i = 0; i < pih.dim(2); i++) { /* Create slice thumbnail and dlib sample */ float loc = pih.origin(2) + i * pih.spacing(2); Dlib_trainer::Dense_sample_type d = thumb.make_sample (loc); /* Predict the value */ std::string label = string_format ("P_%02d", i); points.insert_lps (label.c_str(), dlib_network_x (d), dlib_network_y (d), loc); } /* Save the pointset output to a file */ if (parms->output_fcsv_fn != "") { points.save_fcsv (parms->output_fcsv_fn); } } void autolabel (Autolabel_parms *parms) { parms->parse_command_file (); if (parms->task == "la1") { autolabel_la1 (parms); } else if (parms->task == "tsv1") { autolabel_tsv1 (parms); } else if (parms->task == "tsv2") { autolabel_tsv2 (parms); } else { printf ("Error, unknown autolabel task?\n"); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/autolabel.h000066400000000000000000000006111321604176500304000ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _autolabel_h_ #define _autolabel_h_ #include "plmsegment_config.h" class Autolabel_parms; PLMSEGMENT_API void autolabel (Autolabel_parms *parms); #endif autolabel_feature.cxx000066400000000000000000000005771321604176500324220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include "autolabel_feature.h" Autolabel_feature::Autolabel_feature () { } Autolabel_feature::~Autolabel_feature () { } autolabel_feature.h000066400000000000000000000010561321604176500320400ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _autolabel_feature_h_ #define _autolabel_feature_h_ #include "plmsegment_config.h" #include #include #include class PLMSEGMENT_API Autolabel_feature { public: Autolabel_feature (); ~Autolabel_feature (); public: int feature_type; int gabor_uv[2]; float gauss_width; }; #endif autolabel_parms.cxx000066400000000000000000000272371321604176500321130ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include #include #include #include #include #include "autolabel_feature.h" #include "file_util.h" #include "parameter_parser.h" #include "autolabel_parms.h" #include "plm_math.h" #include "print_and_exit.h" #include "string_util.h" class Autolabel_parms_parser : public Parameter_parser { public: Autolabel_parms *mp; public: Autolabel_parms_parser (Autolabel_parms *mp) { this->mp = mp; } public: virtual Plm_return_code begin_section ( const std::string& section) { if (section == "PREALIGN" || section == "PREALIGNMENT") { this->enable_key_regularization (true); return PLM_SUCCESS; } if (section == "ATLAS-SELECTION") { this->enable_key_regularization (true); return PLM_SUCCESS; } if (section == "TRAINING") { this->enable_key_regularization (true); return PLM_SUCCESS; } if (section == "REGISTRATION") { this->enable_key_regularization (true); return PLM_SUCCESS; } if (section == "STRUCTURES") { this->enable_key_regularization (false); return PLM_SUCCESS; } if (section == "LABELING") { this->enable_key_regularization (true); return PLM_SUCCESS; } if (section == "OPTIMIZATION_RESULT") { this->enable_key_regularization (true); return PLM_SUCCESS; } /* else, unknown section */ return PLM_ERROR; } virtual Plm_return_code end_section ( const std::string& section) { return PLM_SUCCESS; } virtual Plm_return_code set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val) { return this->mp->set_key_value (section, key, index, val); } }; class Autolabel_parms_private { public: std::list feature_list; public: Autolabel_parms_private () {} ~Autolabel_parms_private () { delete_all_features (); } void delete_all_features () { std::list::iterator it; for (it = feature_list.begin(); it != feature_list.end(); it++) { delete *it; } feature_list.clear (); } }; Autolabel_parms::Autolabel_parms () { this->enforce_anatomic_constraints = false; this->d_ptr = new Autolabel_parms_private (); } Autolabel_parms::~Autolabel_parms () { delete this->d_ptr; } Plm_return_code Autolabel_parms::set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val ) { #if defined (commentout) /* [PREALIGNMENT] */ if (section == "PREALIGN" || section == "PREALIGNMENT") { if (key == "mode") { if (val == "DISABLED" || val == "disabled" || val == "Disabled" || val == "0") { this->prealign_mode = "disabled"; } else if (val == "DEFAULT" || val == "default" || val == "Default") { this->prealign_mode = "default"; } else if (val == "CUSTOM" || val == "custom" || val == "Custom") { this->prealign_mode = "custom"; } } else if (key == "reference") { this->prealign_reference = val; } else if (key == "spacing") { this->prealign_spacing = val; } else if (key == "registration_config") { this->prealign_registration_config = val; } else { goto error_exit; } } /* [ATLAS-SELECTION] */ if (section == "ATLAS-SELECTION") { if (key == "enable_atlas_selection") { if (val == "True" || val == "true" || val == "1") { this->enable_atlas_selection = true; } else { this->enable_atlas_selection = false; } } else if (key == "atlas_selection_criteria") { if (val == "nmi" || val == "NMI") { this->atlas_selection_criteria="nmi"; } else if (val == "nmi-post" || val == "NMI-POST") { this->atlas_selection_criteria="nmi-post"; } else if (val == "nmi-ratio" || val == "NMI-RATIO") { this->atlas_selection_criteria="nmi-ratio"; } else if (val == "mse" || val == "MSE") { this->atlas_selection_criteria="mse"; } else if (val == "mse-post" || val == "MSE-POST") { this->atlas_selection_criteria="mse-post"; } else if (val == "mse-ratio" || val == "MSE-RATIO") { this->atlas_selection_criteria="mse-ratio"; } else if (val == "random" || val == "RANDOM") { this->atlas_selection_criteria="random"; } else if (val == "precomputed" || val == "PRECOMPUTED") { this->atlas_selection_criteria="precomputed"; } } else if (key == "similarity_percent_threshold") { sscanf (val.c_str(), "%g", &this->similarity_percent_threshold); } else if (key == "atlases_from_ranking") { sscanf (val.c_str(), "%d", &this->atlases_from_ranking); } else if (key == "mi_histogram_bins") { sscanf (val.c_str(), "%d", &this->mi_histogram_bins); } else if (key == "percentage_nmi_random_sample") { sscanf (val.c_str(), "%g", &this->percentage_nmi_random_sample); } else if (key == "roi_mask_fn" || key == "roi_mask") { this->roi_mask_fn = val; } else if (key == "selection_reg_parms") { this->selection_reg_parms_fn = val; } else if (key == "lower_mi_value_subject") { sscanf (val.c_str(), "%d", &this->lower_mi_value_sub); this->lower_mi_value_sub_defined = true; } else if (key == "upper_mi_value_subject") { sscanf (val.c_str(), "%d", &this->upper_mi_value_sub); this->upper_mi_value_sub_defined = true; } else if (key == "lower_mi_value_atlas") { sscanf (val.c_str(), "%d", &this->lower_mi_value_atl); this->lower_mi_value_atl_defined = true; } else if (key == "upper_mi_value_atlas") { sscanf (val.c_str(), "%d", &this->upper_mi_value_atl); this->upper_mi_value_atl_defined = true; } else if (key == "min_random_atlases") { sscanf (val.c_str(), "%d", &this->min_random_atlases); } else if (key == "max_random_atlases") { sscanf (val.c_str(), "%d", &this->max_random_atlases); } else if (key == "precomputed_ranking") { this->precomputed_ranking_fn = val; } else { goto error_exit; } } /* [TRAINING] */ if (section == "TRAINING") { if (key == "atlas_dir") { this->atlas_dir = val; } else if (key == "fusion_criteria") { if (val == "gaussian" || val == "GAUSSIAN" || val == "Gaussian") { this->fusion_criteria = "gaussian"; } else if (val == "staple" || val == "STAPLE" || val == "Staple") { this->fusion_criteria = "staple"; } else if (val == "gaussian,staple" || val == "GAUSSIAN,STAPLE" || val == "Gaussian,Staple" || val == "staple,gaussian" || val == "STAPLE,GAUSSIAN" || val == "Staple,Gaussian") { this->fusion_criteria = "gaussian_and_staple"; } } else if (key == "distance_map_algorithm") { this->distance_map_algorithm = val; } else if (key == "minimum_similarity") { this->minsim_values = val; } else if (key == "rho_values") { this->rho_values = val; } else if (key == "sigma_values") { this->sigma_values = val; } else if (key == "threshold_values") { this->threshold_values = val; } else if (key == "confidence_weight") { this->confidence_weight = val; } else if (key == "training_dir") { this->training_dir = val; } else if (key == "write_distance_map_files") { if (val == "0") { this->write_distance_map_files = false; } } else if (key == "write_thresholded_files") { if (val == "0") { this->write_thresholded_files = false; } } else if (key == "write_weight_files") { if (val == "0") { this->write_weight_files = false; } } else if (key == "write_warped_images") { if (val == "0") { this->write_warped_images = false; } } else if (key == "write_warped_structures") { if (val == "0") { this->write_warped_structures = false; } } else { goto error_exit; } } /* [REGISTRATION] */ if (section == "REGISTRATION") { if (key == "registration_config") { this->registration_config = val; } else { goto error_exit; } } /* [STRUCTURES] */ if (section == "STRUCTURES") { /* Add key to list of structures */ this->structure_map[key] = key; if (val != "") { /* Key/value pair, so add for renaming */ this->structure_map[val] = key; } /* There is no filtering of structures values */ } /* [LABELING] */ if (section == "LABELING") { if (key == "input") { this->labeling_input_fn = val; } else if (key == "output") { this->labeling_output_fn = val; } else { goto error_exit; } } /* [OPTIMIZATION-RESULT] */ if (section == "OPTIMIZATION_RESULT") { if (key == "registration") { this->optimization_result_reg = val; } else if (key == "gaussian_weighting_voting_rho") { sscanf (val.c_str(), "%g", &this->optimization_result_seg_rho); } else if (key == "gaussian_weighting_voting_sigma") { sscanf (val.c_str(), "%g", &this->optimization_result_seg_sigma); } else if (key == "gaussian_weighting_voting_minsim") { sscanf (val.c_str(), "%g", &this->optimization_result_seg_minsim); } else if (key == "optimization_result_confidence_weight") { sscanf (val.c_str(), "%g", &this->optimization_result_confidence_weight); } else if (key == "gaussian_weighting_voting_thresh") { this->optimization_result_seg_thresh = val; } else { goto error_exit; } } return 0; error_exit: print_and_exit ("Unknown (sec,key,val) combination: (%s,%s,%s)\n", section.c_str(), key.c_str(), val.c_str()); return -1; #endif return PLM_SUCCESS; } void Autolabel_parms::parse_command_file () { Autolabel_parms_parser mpp (this); /* Parse the main config file */ mpp.parse_config_file (this->cmd_file_fn); } autolabel_parms.h000066400000000000000000000021221321604176500315220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _autolabel_parms_h_ #define _autolabel_parms_h_ #include "plmsegment_config.h" #include #include #include #include "plm_return_code.h" #include "smart_pointer.h" class Autolabel_feature; class Autolabel_parms_private; class PLMSEGMENT_API Autolabel_parms { public: SMART_POINTER_SUPPORT (Autolabel_parms); Autolabel_parms_private *d_ptr; public: Autolabel_parms (); ~Autolabel_parms (); public: void parse_command_file (); Plm_return_code set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val); public: std::string cmd_file_fn; std::string input_fn; std::string network_dir; std::string output_csv_fn; std::string output_fcsv_fn; std::string task; bool enforce_anatomic_constraints; }; #endif autolabel_ransac_est.cxx000066400000000000000000000260261321604176500331060ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* In this code, x is the location (in mm), and y is the thoracic vertebra number (1 to 12 for T1 to T12). Slopes are measured in units of vertebra per millimeter. ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include #include "autolabel_ransac_est.h" #include "RANSAC.h" #include "PlaneParametersEstimator.h" #include "RandomNumberGenerator.h" #include "itk_point.h" typedef itk::RANSAC< Autolabel_point, double> Ransac_type; //#define DELTA (0.5) #define DELTA (1.0) #define DELTA_SQUARED (DELTA * DELTA) static double est_piecewise_spline_point ( Autolabel_point& data, std::vector& piecewise_parms ) { double slope_a = piecewise_parms[0]; double t4_loc = piecewise_parms[1]; double t7_loc = piecewise_parms[2]; double slope_c = piecewise_parms[3]; double x = data[0]; double yest; if (x > t4_loc) { double intercept = 4. - t4_loc * slope_a; yest = x * slope_a + intercept; } else if (x < t7_loc) { double intercept = 7. - t7_loc * slope_c; yest = x * slope_c + intercept; } else { double xoff = (x - t4_loc) / (t7_loc - t4_loc); yest = 4. * (1. - xoff) + 7. * xoff; } return yest; } static double score_piecewise_spline_point ( Autolabel_point& data, std::vector& piecewise_parms ) { double y = data[1]; double yest = est_piecewise_spline_point (data, piecewise_parms); double ydiff = y - yest; double yscore = ydiff*ydiff / DELTA_SQUARED; if (yscore > 1.) { yscore = 1.; } return yscore; } static double score_piecewise_spline ( Autolabel_point_vector& apv, std::vector& piecewise_parms ) { double score = 0.0; Autolabel_point_vector::iterator it; for (it = apv.begin(); it != apv.end(); it++) { score += score_piecewise_spline_point ((*it), piecewise_parms); } return score; } static void pattern_search ( Autolabel_point_vector& apv, std::vector& piecewise_parms, double& parm, double constraint[2], double adjust, double& curr_score ) { double curr = parm; double test1 = parm - adjust; double test2 = parm + adjust; double score; printf ("[%f %f %f] vs. [%f %f]\n", test1, parm, test2, constraint[0], constraint[1]); if (test1 > constraint[0]) { parm = test1; score = score_piecewise_spline (apv, piecewise_parms); printf (" <%f,%f,%f,%f> %f %s\n", piecewise_parms[0], piecewise_parms[1], piecewise_parms[2], piecewise_parms[3], score, score < curr_score ? "pass" : "fail"); if (score < curr_score) { curr_score = score; return; } else { parm = curr; } } if (test2 < constraint[1]) { parm = test2; score = score_piecewise_spline (apv, piecewise_parms); printf (" <%f,%f,%f,%f> %f %s\n", piecewise_parms[0], piecewise_parms[1], piecewise_parms[2], piecewise_parms[3], score, score < curr_score ? "pass" : "fail"); if (score < curr_score) { curr_score = score; } else { parm = curr; } } } static void optimize_piecewise_spline ( Autolabel_point_vector& apv, std::vector& piecewise_parms ) { const int MAX_ITS = 6; //int changed = 0; double constraints[3][2] = { { -0.070, -0.040 }, { -0.056, -0.037 }, { -0.048, -0.029 } }; /* Double check constraints */ /* GCS FIX: ignoring constraints[1][*] for now. :( */ if (piecewise_parms[0] < constraints[0][0]) { piecewise_parms[0] = constraints[0][0]; } else if (piecewise_parms[0] > constraints[0][1]) { piecewise_parms[0] = constraints[0][1]; } if (piecewise_parms[3] < constraints[2][0]) { piecewise_parms[3] = constraints[2][0]; } else if (piecewise_parms[3] > constraints[2][1]) { piecewise_parms[3] = constraints[2][1]; } double curr_score = score_piecewise_spline (apv, piecewise_parms); printf ("Base score: %f\n", curr_score); for (int it = 0; it < MAX_ITS; it++) { double adjust; double loc_constraint[2]; double t4_loc, t7_loc, t47_slope; /* Search slope_a */ adjust = 0.01 * rand() / (float) RAND_MAX; //adjust = 0.002; printf ("-- A --\n"); pattern_search ( apv, piecewise_parms, piecewise_parms[0], constraints[0], adjust, curr_score); /* Search slope_c */ printf ("-- C --\n"); adjust = 0.01 * rand() / (float) RAND_MAX; pattern_search ( apv, piecewise_parms, piecewise_parms[3], constraints[2], adjust, curr_score); /* Search t4_loc */ printf ("-- T4 --\n"); adjust = 10. * rand() / (float) RAND_MAX; //adjust = 1. t4_loc = piecewise_parms[1]; t7_loc = piecewise_parms[2]; t47_slope = 3. / (t7_loc - t4_loc); loc_constraint[0] = t7_loc + 3. / constraints[1][0]; loc_constraint[1] = t7_loc + 3. / constraints[1][1]; printf ("T4 = %f T7 = %f\n", t4_loc, t7_loc); printf ("t47_slope = %f constraints = [%f,%f]\n", t47_slope, constraints[1][0], constraints[1][1]); printf ("loc_constraint = [%f,%f]\n", loc_constraint[0], loc_constraint[1]); #if defined (commentout) #endif pattern_search ( apv, piecewise_parms, piecewise_parms[1], loc_constraint, adjust, curr_score); /* Search t7_loc */ printf ("-- T7 --\n"); adjust = 10. * rand() / (float) RAND_MAX; t4_loc = piecewise_parms[1]; t7_loc = piecewise_parms[2]; t47_slope = 3. / (t7_loc - t4_loc); loc_constraint[0] = t4_loc - 3. / constraints[1][1]; loc_constraint[1] = t4_loc - 3. / constraints[1][0]; printf ("T4 = %f T7 = %f\n", t4_loc, t7_loc); printf ("t47_slope = %f constraints = [%f,%f]\n", t47_slope, constraints[1][0], constraints[1][1]); printf ("loc_constraint = [%f,%f]\n", loc_constraint[0], loc_constraint[1]); #if defined (commentout) #endif pattern_search ( apv, piecewise_parms, piecewise_parms[2], loc_constraint, adjust, curr_score); } } void autolabel_ransac_est (Autolabel_point_vector& apv) { Autolabel_point_vector tmp; std::vector autolabel_parameters; itk::Autolabel_ransac_est::Pointer estimator = itk::Autolabel_ransac_est::New(); estimator->SetDelta (DELTA); /* Run RANSAC */ double desiredProbabilityForNoOutliers = 0.999; double percentageOfDataUsed; Ransac_type::Pointer ransac_estimator = Ransac_type::New(); ransac_estimator->SetData (apv); ransac_estimator->SetParametersEstimator (estimator.GetPointer()); percentageOfDataUsed = ransac_estimator->Compute ( autolabel_parameters, desiredProbabilityForNoOutliers); if (autolabel_parameters.empty()) { std::cout<<"RANSAC estimate failed, degenerate configuration?\n"; exit (-1); } else { printf ("RANSAC parameters: [s,i] = [%f,%f]\n", autolabel_parameters[0], autolabel_parameters[1]); printf ("Used %f percent of data.\n", percentageOfDataUsed); } /* Use pattern search to fit piecewise linear spline, using RANSAC as initial guess. piecewise_parms[0] = slope in T1-T4 region piecewise_parms[1] = location of T4 piecewise_parms[2] = location of T7 piecewise_parms[3] = slope in T7 region */ std::vector piecewise_parms(4); double slope = autolabel_parameters[0]; double intercept = autolabel_parameters[1]; printf ("Initializing piecewise parms\n"); piecewise_parms[0] = slope; piecewise_parms[1] = (4. - intercept) / slope; piecewise_parms[2] = (7. - intercept) / slope; piecewise_parms[3] = slope; printf ("Optimizing piecewise parms\n"); optimize_piecewise_spline (apv, piecewise_parms); printf ("Done optimizing.\n"); #if defined (commentout) /* Fill in 3rd component of apv with RANSAC estimates */ Autolabel_point_vector::iterator it; for (it = apv.begin(); it != apv.end(); it++) { double x = (*it)[0]; //double y = (*it)[1]; double ry = intercept + slope * x; (*it)[2] = ry; } #endif /* Fill in 3rd component of apv with piecewise estimates */ Autolabel_point_vector::iterator it; for (it = apv.begin(); it != apv.end(); it++) { double ry = est_piecewise_spline_point (*it, piecewise_parms); (*it)[2] = ry; } } namespace itk { Autolabel_ransac_est::Autolabel_ransac_est() { this->deltaSquared = NumericTraits::min(); this->minForEstimate = 2; this->min_slope = -0.079; this->max_slope = -0.030; } Autolabel_ransac_est::~Autolabel_ransac_est() { } void Autolabel_ransac_est::SetDelta( double delta ) { this->deltaSquared = delta*delta; } double Autolabel_ransac_est::GetDelta() { return sqrt( this->deltaSquared ); } void Autolabel_ransac_est::set_slope_constraints ( double min_slope, double max_slope ) { this->min_slope = min_slope; this->max_slope = max_slope; } /* parameters[0] is slope, parameters[1] is offset */ void Autolabel_ransac_est::Estimate ( std::vector &data, std::vector ¶meters ) { const double EPS = 2*NumericTraits::epsilon(); /* Make sure we have two points */ parameters.clear(); if (data.size() < this->minForEstimate) { return; } /* Check x displacement is sufficient */ Autolabel_point& p1 = *(data[0]); Autolabel_point& p2 = *(data[1]); double xdiff = p2[0] - p1[0]; if (fabs(xdiff) < 10 * EPS) { return; } /* Compute slope */ double ydiff = p2[1] - p1[1]; double slope = ydiff / xdiff; double intercept = p1[1] - slope * p1[0]; if (slope < this->min_slope || slope > this->max_slope) { #if defined (commentout) printf ("slope failed (%f,%f) (%f,%f) s=%f, i=%f\n", p1[0],p1[1],p2[0],p2[1],slope,intercept); #endif return; } /* Compute intercept */ parameters.push_back (slope); parameters.push_back (intercept); } /* WTF? */ void Autolabel_ransac_est::Estimate ( std::vector< Autolabel_point > &data, std::vector ¶meters ) { std::vector< Autolabel_point *> usedData; int dataSize = data.size(); for( int i=0; i &data, std::vector ¶meters ) { /* Do something here */ } /* WTF? */ void Autolabel_ransac_est::LeastSquaresEstimate ( std::vector< Autolabel_point > &data, std::vector ¶meters ) { std::vector< Autolabel_point *> usedData; int dataSize = data.size(); for( int i=0; i ¶meters, Autolabel_point &data ) { double slope = parameters[0]; double intercept = parameters[1]; double yest = intercept + slope * data[0]; double ydiff = yest - data[1]; return (ydiff*ydiff < this->deltaSquared); } } // end namespace itk autolabel_ransac_est.h000066400000000000000000000042211321604176500325240ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _autolabel_ransac_est_h_ #define _autolabel_ransac_est_h_ #include "plmsegment_config.h" #include "ParametersEstimator.h" #include #include "itk_point.h" /* GCS FIX: Why can't I remove itk_point.h include, and declare "class DoublePoint3DType;"? */ #include "plmsegment_config.h" typedef DoublePoint3DType Autolabel_point; typedef std::vector< Autolabel_point > Autolabel_point_vector; namespace itk { class PLMSEGMENT_API Autolabel_ransac_est : public ParametersEstimator< Autolabel_point, double > { public: typedef Autolabel_ransac_est Self; typedef ParametersEstimator< Autolabel_point, double > Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkTypeMacro( Autolabel_ransac_est, ParametersEstimator ); itkNewMacro( Self ) virtual void Estimate( std::vector< Autolabel_point *> &data, std::vector ¶meters ); virtual void Estimate( std::vector< Autolabel_point > &data, std::vector ¶meters ); virtual void LeastSquaresEstimate( std::vector< Autolabel_point *> &data, std::vector ¶meters ); virtual void LeastSquaresEstimate( std::vector< Autolabel_point > &data, std::vector ¶meters ); virtual bool Agree( std::vector ¶meters, Autolabel_point &data ); void SetDelta( double delta ); double GetDelta(); void set_slope_constraints (double min_slope, double max_slope); protected: Autolabel_ransac_est(); ~Autolabel_ransac_est(); private: Autolabel_ransac_est(const Self& ); //purposely not implemented void operator=(const Self& ); //purposely not implemented double deltaSquared; double min_slope; double max_slope; }; } // end namespace itk PLMSEGMENT_API void autolabel_ransac_est (Autolabel_point_vector& apv); #endif autolabel_task.cxx000066400000000000000000000005371321604176500317250ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include "itkImageRegionIterator.h" #include "autolabel_task.h" #include "dlib_trainer.h" plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/autolabel_task.h000066400000000000000000000010731321604176500314250ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _autolabel_task_h_ #define _autolabel_task_h_ #include "plmsegment_config.h" #include "dlib_trainer.h" class Autolabel_task { public: Autolabel_task () { } public: enum Task_type { AUTOLABEL_TASK_X_POS, AUTOLABEL_TASK_Y_POS, AUTOLABEL_TASK_Z_POS }; public: Task_type task_type; }; #endif autolabel_thumbnailer.cxx000066400000000000000000000025321321604176500332720ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include "itkImageRegionIterator.h" #include "autolabel_thumbnailer.h" #include "dlib_trainer.h" #include "plm_image.h" #include "thumbnail.h" Autolabel_thumbnailer::Autolabel_thumbnailer () { thumb = new Thumbnail; } Autolabel_thumbnailer::~Autolabel_thumbnailer () { if (thumb) delete thumb; } void Autolabel_thumbnailer::set_input_image (const char* fn) { pli = plm_image_load (fn, PLM_IMG_TYPE_ITK_FLOAT); thumb->set_input_image (pli); thumb->set_thumbnail_dim (16); thumb->set_thumbnail_spacing (25.0f); } void Autolabel_thumbnailer::set_input_image (const std::string& fn) { this->set_input_image (fn.c_str()); } Dlib_trainer::Dense_sample_type Autolabel_thumbnailer::make_sample (float slice_loc) { thumb->set_slice_loc (slice_loc); FloatImageType::Pointer thumb_img = thumb->make_thumbnail (); itk::ImageRegionIterator< FloatImageType > thumb_it ( thumb_img, thumb_img->GetLargestPossibleRegion()); Dlib_trainer::Dense_sample_type d; for (int j = 0; j < 256; j++) { d(j) = thumb_it.Get(); ++thumb_it; } return d; } autolabel_thumbnailer.h000066400000000000000000000013551321604176500327210ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _autolabel_thumbnailer_h_ #define _autolabel_thumbnailer_h_ #include "plmsegment_config.h" #include "dlib_trainer.h" #include "plm_image.h" class Plm_image; class Thumbnail; class Autolabel_thumbnailer { public: Autolabel_thumbnailer (); ~Autolabel_thumbnailer (); public: Plm_image::Pointer pli; Thumbnail *thumb; public: void set_input_image (const char* fn); void set_input_image (const std::string& fn); Dlib_trainer::Dense_sample_type make_sample (float slice_loc); }; #endif autolabel_trainer.cxx000066400000000000000000000243451321604176500324320ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include #include #include "itkDirectory.h" #include "itkImageRegionIterator.h" #include "itkRegularExpressionSeriesFileNames.h" #include "autolabel_task.h" #include "autolabel_thumbnailer.h" #include "autolabel_trainer.h" #include "dlib_trainer.h" #include "file_util.h" #include "path_util.h" #include "plm_image.h" #include "pointset.h" #include "print_and_exit.h" #include "string_util.h" Autolabel_trainer::Autolabel_trainer () { m_dt_la1 = 0; m_dt_tsv1 = 0; m_dt_tsv2_x = 0; m_dt_tsv2_y = 0; } Autolabel_trainer::~Autolabel_trainer () { if (m_dt_la1) delete m_dt_la1; if (m_dt_tsv1) delete m_dt_tsv1; if (m_dt_tsv2_x) delete m_dt_tsv2_x; if (m_dt_tsv2_y) delete m_dt_tsv2_y; } void Autolabel_trainer::set_input_dir (const char* input_dir) { if (!itksys::SystemTools::FileIsDirectory (input_dir)) { print_and_exit ("Error: \'%s\' is not a directory\n", input_dir); } /* We can't load the data yet, since we don't know the task */ m_input_dir = input_dir; } void Autolabel_trainer::load_input_dir_recursive (std::string input_dir) { itksys::Directory itk_dir; if (!itk_dir.Load (input_dir.c_str())) { print_and_exit ("Error loading directory (%s)\n", input_dir.c_str()); } for (unsigned long i = 0; i < itk_dir.GetNumberOfFiles(); i++) { /* Skip "." and ".." */ if (!strcmp (itk_dir.GetFile(i), ".") || !strcmp (itk_dir.GetFile(i), "..")) { continue; } /* Make fully specified filename */ std::string fn = input_dir + "/" + itk_dir.GetFile(i); /* Process directories recursively */ if (itksys::SystemTools::FileIsDirectory (fn.c_str())) { load_input_dir_recursive (fn); } /* Check for .nrrd files */ if (extension_is (fn.c_str(), "nrrd")) { /* Does .nrrd file have a corresponding .fcsv file? */ std::string fcsv_fn = fn; fcsv_fn.replace (fn.length()-4, 4, "fcsv"); if (file_exists (fcsv_fn.c_str())) { load_input_file (fn.c_str(), fcsv_fn.c_str()); } } } } /* This function creates "t_map", a map from t-spine # to (x,y,z) point */ static std::map load_tspine_map (const Labeled_pointset& ps) { std::map t_map; for (unsigned int i = 0; i < ps.point_list.size(); i++) { if (ps.point_list[i].label == "C7") { t_map.insert (std::pair (0, Point (ps.point_list[i].p[0], ps.point_list[i].p[1], ps.point_list[i].p[2]))); } else if (ps.point_list[i].label == "L1") { t_map.insert (std::pair (13, Point (ps.point_list[i].p[0], ps.point_list[i].p[1], ps.point_list[i].p[2]))); } else { float t; int rc = sscanf (ps.point_list[i].label.c_str(), "T%f", &t); if (rc != 1) { /* Not a vertebra point */ continue; } if (t > 0.25 && t < 12.75) { t_map.insert (std::pair (t, Point (ps.point_list[i].p[0], ps.point_list[i].p[1], ps.point_list[i].p[2]))); } } } return t_map; } void Autolabel_trainer::load_input_file ( const char* nrrd_fn, const char* fcsv_fn) { printf ("Loading %s\nLoading %s\n---\n", nrrd_fn, fcsv_fn); /* Load the pointset */ Labeled_pointset ps; ps.load_fcsv (fcsv_fn); /* Load the input image */ #if defined (commentout) Plm_image *pli; pli = plm_image_load (nrrd_fn, PLM_IMG_TYPE_ITK_FLOAT); #endif /* Create thumbnail to be filled in */ Autolabel_thumbnailer thumb; thumb.set_input_image (nrrd_fn); #if defined (commentout) Thumbnail thumb; thumb.set_input_image (pli); thumb.set_thumbnail_dim (16); thumb.set_thumbnail_spacing (25.0f); #endif /* Get the samples and labels for learning tasks that convert slice to location */ if (this->m_dt_tsv1 || this->m_dt_tsv2_x || this->m_dt_tsv2_y) { /* Create map from spine # to point from fcsv file */ std::map t_map = load_tspine_map (ps); /* If we want to use interpolation, we need to sort, and make a "back-map" from z-pos to t-spine here. But this is not currently implemented. */ std::map::iterator it; for (it = t_map.begin(); it != t_map.end(); ++it) { #if defined (commentout) thumb.set_slice_loc (it->second.p[2]); FloatImageType::Pointer thumb_img = thumb.make_thumbnail (); Dlib_trainer::Dense_sample_type d = Autolabel_task::make_sample (thumb_img); #endif Dlib_trainer::Dense_sample_type d = thumb.make_sample (it->second.p[2]); if (this->m_dt_tsv1) { this->m_dt_tsv1->m_samples.push_back (d); this->m_dt_tsv1->m_labels.push_back (it->first); } if (this->m_dt_tsv2_x) { this->m_dt_tsv2_x->m_samples.push_back (d); this->m_dt_tsv2_x->m_labels.push_back (it->second.p[0]); } if (this->m_dt_tsv2_y) { this->m_dt_tsv2_y->m_samples.push_back (d); this->m_dt_tsv2_y->m_labels.push_back (it->second.p[1]); } } } /* Get the samples and labels for learning tasks that iterate through all slices */ if (this->m_dt_la1) { bool have_lla = false; float *lla_point = 0; for (unsigned int i = 0; i < ps.point_list.size(); i++) { if (ps.point_list[i].label == "LLA") { have_lla = true; lla_point = ps.point_list[i].p; } } if (have_lla) { for (size_t i = 0; i < thumb.pli->dim(2); i++) { float loc = thumb.pli->origin(2) + i * thumb.pli->spacing(2); #if defined (commentout) thumb.set_slice_loc (loc); FloatImageType::Pointer thumb_img = thumb.make_thumbnail (); Dlib_trainer::Dense_sample_type d = Autolabel_task::make_sample (thumb_img); #endif Dlib_trainer::Dense_sample_type d = thumb.make_sample (loc); float score = fabs(loc - lla_point[2]); if (score > 30) score = 30; if (this->m_dt_la1) { this->m_dt_la1->m_samples.push_back (d); this->m_dt_la1->m_labels.push_back (score); } } } } //delete pli; } void Autolabel_trainer::load_inputs () { if (m_task == "" || m_input_dir == "") { print_and_exit ("Error: inputs not fully specified.\n"); } if (m_task == "la") { m_dt_la1 = new Dlib_trainer; } else if (m_task == "tsv1") { m_dt_tsv1 = new Dlib_trainer; } else if (m_task == "tsv2") { m_dt_tsv2_x = new Dlib_trainer; m_dt_tsv2_y = new Dlib_trainer; } else { print_and_exit ("Error: unsupported autolabel-train task (%s)\n", m_task.c_str()); } load_input_dir_recursive (m_input_dir); } void Autolabel_trainer::set_task (const char* task) { m_task = task; } void Autolabel_trainer::train () { if (this->m_dt_tsv1) { std::string output_net_fn = string_format ( "%s/tsv1.net", m_output_dir.c_str()); m_dt_tsv1->set_krr_gamma (-9, -6, 0.5); m_dt_tsv1->train_krr (); m_dt_tsv1->save_net (output_net_fn); } if (this->m_dt_tsv2_x) { std::string output_net_fn = string_format ( "%s/tsv2_x.net", m_output_dir.c_str()); m_dt_tsv2_x->set_krr_gamma (-9, -6, 0.5); m_dt_tsv2_x->train_krr (); m_dt_tsv2_x->save_net (output_net_fn); } if (this->m_dt_tsv2_y) { std::string output_net_fn = string_format ( "%s/tsv2_y.net", m_output_dir.c_str()); m_dt_tsv2_y->set_krr_gamma (-9, -6, 0.5); m_dt_tsv2_y->train_krr (); m_dt_tsv2_y->save_net (output_net_fn); } if (this->m_dt_la1) { std::string output_net_fn = string_format ( "%s/la1.net", m_output_dir.c_str()); m_dt_la1->set_krr_gamma (-9, -6, 0.5); m_dt_la1->train_krr (); m_dt_la1->save_net (output_net_fn); } } void Autolabel_trainer::save_csv () { if (this->m_dt_tsv1) { std::string output_csv_fn = string_format ( "%s/tsv1.csv", m_output_dir.c_str()); this->m_dt_tsv1->save_csv (output_csv_fn); } if (this->m_dt_tsv2_x) { std::string output_csv_fn = string_format ( "%s/tsv2_x.csv", m_output_dir.c_str()); this->m_dt_tsv2_x->save_csv (output_csv_fn); } if (this->m_dt_tsv2_y) { std::string output_csv_fn = string_format ( "%s/tsv2_y.csv", m_output_dir.c_str()); this->m_dt_tsv2_y->save_csv (output_csv_fn); } if (this->m_dt_la1) { std::string output_csv_fn = string_format ( "%s/la1.csv", m_output_dir.c_str()); this->m_dt_la1->save_csv (output_csv_fn); } } /* tsacc = testset accuracy */ void Autolabel_trainer::save_tsacc () { /* Save the output files */ if (this->m_dt_tsv1) { std::string output_tsacc_fn = string_format ( "%s/tsv1_tsacc.txt", m_output_dir.c_str()); this->m_dt_tsv1->save_tsacc (output_tsacc_fn); } if (this->m_dt_tsv2_x) { std::string output_tsacc_fn = string_format ( "%s/tsv2_x_tsacc.txt", m_output_dir.c_str()); this->m_dt_tsv2_x->save_tsacc (output_tsacc_fn); } if (this->m_dt_tsv2_y) { std::string output_tsacc_fn = string_format ( "%s/tsv2_y_tsacc.txt", m_output_dir.c_str()); this->m_dt_tsv2_y->save_tsacc (output_tsacc_fn); } if (this->m_dt_la1) { std::string output_tsacc_fn = string_format ( "%s/la1_tsacc.txt", m_output_dir.c_str()); this->m_dt_la1->save_tsacc (output_tsacc_fn); } } void autolabel_train (Autolabel_train_parms *parms) { Autolabel_trainer at; at.set_input_dir (parms->input_dir.c_str()); at.m_output_dir = parms->output_dir; at.set_task (parms->task.c_str()); at.load_inputs (); at.train (); at.save_csv (); at.save_tsacc (); } autolabel_trainer.h000066400000000000000000000023361321604176500320530ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _autolabel_trainer_h_ #define _autolabel_trainer_h_ #include "plmsegment_config.h" #include #include class Dlib_trainer; class PLMSEGMENT_API Autolabel_trainer { public: Autolabel_trainer (); ~Autolabel_trainer (); public: std::string m_output_dir; std::string m_input_dir; std::string m_task; private: Dlib_trainer *m_dt_tsv1; Dlib_trainer *m_dt_tsv2_x; Dlib_trainer *m_dt_tsv2_y; Dlib_trainer *m_dt_la1; public: void load_inputs (); void save_csv (); void save_tsacc (); void set_input_dir (const char* input_dir); void set_task (const char* task); void train (); private: void load_input_dir_recursive (std::string input_dir); void load_input_file (const char* nrrd_fn, const char* fcsv_fn); }; class PLMSEGMENT_API Autolabel_train_parms { public: std::string input_dir; std::string output_dir; std::string task; }; PLMSEGMENT_API void autolabel_train (Autolabel_train_parms *parms); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/dlib_trainer.cxx000066400000000000000000000137241321604176500314520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include #include #include #include "dlib/cmd_line_parser.h" #include "dlib/data_io.h" #include "dlib/mlp.h" #include "dlib/revision.h" #include "dlib/svm.h" #include "dlib_trainer.h" #include "file_util.h" #include "plm_math.h" using namespace dlib; typedef dlib::cmd_line_parser::check_1a_c clp; typedef std::map sparse_sample_type; typedef dlib::matrix< sparse_sample_type::value_type::second_type,0,1 > dense_sample_type; typedef double label_type; /* --------------------------------------------------------------------- option_range class --------------------------------------------------------------------- */ struct option_range { public: bool log_range; float min_value; float max_value; float incr; public: option_range () { log_range = false; min_value = 0; max_value = 100; incr = 10; } void set_option (clp& parser, std::string const& option, float default_val); float get_min_value (); float get_max_value (); float get_next_value (float curr_val); }; void option_range::set_option ( clp& parser, std::string const& option, float default_val ) { int rc; /* No option specified */ if (!parser.option (option)) { log_range = 0; min_value = default_val; max_value = default_val; incr = 1; return; } /* Range specified */ rc = sscanf (parser.option(option).argument().c_str(), "%f:%f:%f", &min_value, &incr, &max_value); if (rc == 3) { log_range = 1; return; } /* Single value specified */ if (rc == 1) { log_range = 0; max_value = min_value; incr = 1; return; } else { std::cerr << "Error parsing option" << option << "\n"; exit (-1); } } float option_range::get_min_value () { if (log_range) { return exp10_ (min_value); } else { return min_value; } } float option_range::get_max_value () { if (log_range) { return exp10_ (max_value); } else { return max_value; } } float option_range::get_next_value (float curr_value) { if (log_range) { curr_value = log10 (curr_value); curr_value += incr; curr_value = exp10_ (curr_value); } else { curr_value += incr; } return curr_value; } /* --------------------------------------------------------------------- training functions --------------------------------------------------------------------- */ void Dlib_trainer::save_csv (const std::string& out_csv_fn) { /* Save the output file */ printf ("Saving csv...\n"); make_parent_directories (out_csv_fn); FILE *fp = plm_fopen (out_csv_fn, "w"); std::vector::iterator s_it = this->m_samples.begin(); std::vector::iterator l_it = this->m_labels.begin(); while (s_it != this->m_samples.end()) { fprintf (fp, "%f,", *l_it); for (int i = 0; i < 256; i++) { fprintf (fp, ",%f", (*s_it)(i)); } fprintf (fp, "\n"); ++s_it, ++l_it; } fclose (fp); printf ("Done.\n"); } void Dlib_trainer::save_net (const std::string& out_net_fn) { make_parent_directories (out_net_fn.c_str()); std::ofstream fout (out_net_fn.c_str(), std::ios::binary); serialize (m_krr_df, fout); fout.close(); #if defined (commentout) for (unsigned int j = 0; j < dense_samples.size(); j++) { printf ("%g %g\n", labels[j], best_network(dense_samples[j])); } #endif } void Dlib_trainer::save_tsacc (const std::string& out_net_fn) { FILE *fp = plm_fopen (out_net_fn, "w"); for (unsigned int j = 0; j < m_samples.size(); j++) { fprintf (fp, "%g %g\n", m_labels[j], m_krr_df(m_samples[j])); } fclose (fp); } void Dlib_trainer::set_krr_gamma ( double gamma_min, double gamma_max, double gamma_step) { m_gamma_search = true; m_gamma_min = gamma_min; m_gamma_max = gamma_max; m_gamma_step = gamma_step; } void Dlib_trainer::train_krr (void) { //typedef radial_basis_kernel kernel_type; krr_trainer trainer; option_range gamma_range; double best_gamma = DBL_MAX; float best_loo = FLT_MAX; //get_rbk_gamma (parser, dense_samples, gamma_range); for (float log_gamma = m_gamma_min; log_gamma <= m_gamma_max; log_gamma += m_gamma_step) { // LOO cross validation double loo_error; if (m_verbose) { trainer.set_search_lambdas(logspace(-9, 4, 100)); trainer.be_verbose(); } double gamma = exp10_ (log_gamma); trainer.set_kernel (Kernel_type (gamma)); #if DLIB_REVISION == 4093 /* dlib 17.34 */ dlib::decision_function krr_df = trainer.train (m_samples, m_labels, loo_error); #elif DLIB_MAJOR_VERSION > 17 || (DLIB_MAJOR_VERSION == 17 && DLIB_MINOR_VERSION >= 44) /* dlib 17.44, dlib 18.7 */ /* GCS FIX: How to get loo_error from loo_values? */ std::vector loo_values; double lambda_used; dlib::decision_function krr_df = trainer.train (m_samples, m_labels, loo_values, lambda_used); loo_error = mean_squared_error (m_labels, loo_values); #else error, unknown DLIB version!; #endif if (loo_error < best_loo) { best_loo = loo_error; best_gamma = gamma; m_krr_df = krr_df; } printf ("10^%f %9.6f\n", log_gamma, loo_error); } printf ("Best result: gamma=10^%f (%g), loo_error=%9.6f\n", log10(best_gamma), best_gamma, best_loo); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/dlib_trainer.h000066400000000000000000000025701321604176500310740ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dlib_trainer_h_ #define _dlib_trainer_h_ #include "plmsegment_config.h" #include #include "dlib/svm.h" class PLMSEGMENT_API Dlib_trainer { public: Dlib_trainer () { m_gamma_search = false; m_gamma_min = -7; m_gamma_max = -7; m_gamma_step = 1; m_verbose = true; } ~Dlib_trainer () {} public: //typedef std::map Sparse_sample_type; typedef dlib::matrix < double, 256, 1 > Dense_sample_type; typedef double Label_type; typedef dlib::radial_basis_kernel < Dlib_trainer::Dense_sample_type > Kernel_type; public: std::string m_algorithm; std::vector m_samples; std::vector m_labels; public: bool m_gamma_search; double m_gamma_min; double m_gamma_max; double m_gamma_step; bool m_verbose; dlib::decision_function m_krr_df; public: void save_csv (const std::string& out_csv_fn); void save_net (const std::string& out_net_fn); void save_tsacc (const std::string& out_net_fn); void set_krr_gamma ( double gamma_min, double gamma_max, double gamma_step); void train_krr (void); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/mabs.cxx000066400000000000000000002715101321604176500277350ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include #include "itkImageMaskSpatialObject.h" #include "itkVotingBinaryIterativeHoleFillingImageFilter.h" #include "dir_list.h" #include "dice_statistics.h" #include "distance_map.h" #include "file_util.h" #include "hausdorff_distance.h" #include "itk_adjust.h" #include "itk_resample.h" #include "itk_image_save.h" #include "itk_threshold.h" #include "logfile.h" #include "mabs.h" #include "mabs_atlas_selection.h" #include "mabs_parms.h" #include "mabs_staple.h" #include "mabs_stats.h" #include "mabs_vote.h" #include "option_range.h" #include "path_util.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_timer.h" #include "plm_warp.h" #include "print_and_exit.h" #include "registration.h" #include "registration_data.h" #include "registration_parms.h" #include "rt_study.h" #include "rtss.h" #include "segmentation.h" #include "string_util.h" #include "xform.h" class Mabs_private { public: /* These are the input parameters */ const Mabs_parms *parms; /* Store the executed command */ std::string executed_command; /* traindir_base is the output directory when we are doing a training task (i.e. not labeling), and is of the form: ".../train_dir */ std::string traindir_base; /* ".../train_dir/convert" */ std::string convert_dir; /* ".../train_dir/prealign" */ std::string prealign_dir; /* prealign_dir, if it exists. Otherwise, convert_dir */ std::string preprocessed_dir; /* ".../train_dir/atlas-train" */ std::string atlas_train_dir; /* ".../train_dir/mabs-train" */ std::string mabs_train_dir; /* segment_input_fn is the input location for a segmentation task */ std::string segment_input_fn; /* outdir_base is the output directory when we are doing a labeling task (i.e. not training) */ std::string segment_outdir_base; /* registration_list is the list of registration parameter files */ std::list registration_list; /* output_dir is ??? */ std::string output_dir; /* Binary structure used to align the center of gravity */ Plm_image::Pointer input_roi_for_cog_prealignment; /* String containing the roi file name passed by command line */ std::string prealign_roi_cmd_name; /* process_dir_list is a list of the input directories which need to be processed, one directory per case - during the atlas_convert stage, it is the list of original (dicom) atlas directories - during the atlas_prealign stage, it is the list of converted atlas directories - */ std::list process_dir_list; /* There is one reference image at a time, which is the image we are segmenting. */ std::string ref_id; Rt_study::Pointer ref_rtds; std::list atlas_list; /* Select atlas parameters */ std::map > > selected_atlases_train; std::list > selected_atlases; /* Convert parameters */ bool convert_resample; float convert_spacing[3]; /* Prealign parameters */ bool prealign_resample; float prealign_spacing[3]; /* Utility class for keeping track of statistics */ Mabs_stats stats; /* Segmentation parameters */ std::string registration_id; /* While segmenting an image, we sometimes loop through the structures for evaluation. This holds the binary image of the current structure which we are evaluating. */ bool have_ref_structure; UCharImageType::Pointer ref_structure_image; /* This configures the trainer to evaluate segmentation parameters, it is set to false when --train-registration is used */ bool train_segmentation; /* Decide whether distance map should be computed during the main registration loop */ bool compute_distance_map; /* You can set these variables to save some intermediate data for debugging and tuning */ bool write_weight_files; bool write_thresholded_files; bool write_distance_map_files; bool write_registration_files; bool write_warped_images; /* This is used when creating a final segmentation */ bool write_dicom_rt_struct; /* While looping through atlases, the gaussin voting/staple information is stored here */ std::map vote_map; std::map staple_map; /* Store timing information for performance evaluation */ double time_atlas_selection; double time_dmap; double time_extract; double time_io; double time_reg; double time_vote; double time_staple; double time_warp_img; double time_warp_str; public: Mabs_private () { parms = 0; train_segmentation = true; have_ref_structure = false; convert_resample = false; prealign_resample = false; registration_id = ""; ref_rtds = Rt_study::New (); compute_distance_map = true; write_weight_files = false; write_thresholded_files = true; write_distance_map_files = true; write_registration_files = true; write_warped_images = true; write_dicom_rt_struct = false; this->reset_timers (); } void reset_timers () { time_atlas_selection = 0; time_dmap = 0; time_extract = 0; time_io = 0; time_reg = 0; time_vote = 0; time_staple = 0; time_warp_img = 0; time_warp_str = 0; } void clear_vote_map () { std::map::iterator it; for (it = vote_map.begin(); it != vote_map.end(); ++it) { delete it->second; } vote_map.clear (); } void clear_staple_map () { std::map::iterator it; for (it = staple_map.begin(); it != staple_map.end(); ++it) { delete it->second; } staple_map.clear (); } public: void print_structure_map (); std::string map_structure_name (const std::string& ori_name); void extract_reference_image (const std::string& mapped_name); void segmentation_threshold_weight ( const std::string& label_output_dir, FloatImageType::Pointer weight_image, const std::string& mapped_name, const std::string& structure_label, const Mabs_seg_weights* msw, float thresh_val); }; /* Print out structure map */ void Mabs_private::print_structure_map () { std::map::const_iterator it; for (it = this->parms->structure_map.begin (); it != this->parms->structure_map.end (); it++) { lprintf ("SM> %s\n", (*it).first.c_str()); } } /* Map an input-specific structure name to a canonical structure name Return "" if no canonical name */ std::string Mabs_private::map_structure_name ( const std::string& ori_name) { if (this->parms->structure_map.size() == 0) { lprintf (" > no structure list specified\n"); return ori_name; } std::map::const_iterator it = this->parms->structure_map.find (ori_name); if (it == this->parms->structure_map.end()) { lprintf (" > irrelevant structure: %s\n", ori_name.c_str()); return ""; } const std::string& mapped_name = it->second; if (mapped_name == "") { lprintf (" > irrelevant structure: %s\n", ori_name.c_str()); } else if (mapped_name == ori_name) { lprintf (" > relevant structure: %s\n", ori_name.c_str()); } else { lprintf (" > relevant structure: %s -> %s\n", ori_name.c_str(), mapped_name.c_str()); } return mapped_name; } /* Extract reference structure as binary mask, and save into the variable d_ptr->ref_structure_image. This image is used when computing dice statistics. GCS FIX: This is inefficient, it could be extracted once at the beginning, and cached. */ void Mabs_private::extract_reference_image (const std::string& mapped_name) { this->have_ref_structure = false; Segmentation::Pointer rtss = this->ref_rtds->get_segmentation(); if (!rtss) { return; } for (size_t j = 0; j < rtss->get_num_structures(); j++) { std::string ref_ori_name = rtss->get_structure_name (j); std::string ref_mapped_name = this->map_structure_name (ref_ori_name); if (ref_mapped_name == mapped_name) { lprintf ("Extracting %d, %s\n", j, ref_ori_name.c_str()); this->ref_structure_image = rtss->get_structure_image (j); this->have_ref_structure = true; break; } } } void Mabs_private::segmentation_threshold_weight ( const std::string& label_output_dir, FloatImageType::Pointer weight_image, const std::string& mapped_name, const std::string& structure_label, const Mabs_seg_weights* msw, float thresh_val ) { Plm_timer timer; /* Threshold the weight image */ timer.start(); UCharImageType::Pointer thresh_img = itk_threshold_above ( weight_image, thresh_val); /* Fill holes and remove islands from the computed contour * PAOLO ZAFFINO July 3th 2015 */ typedef itk::VotingBinaryIterativeHoleFillingImageFilter MorphologicalFilterType; MorphologicalFilterType::Pointer closing_filter = MorphologicalFilterType::New(); MorphologicalFilterType::Pointer island_removing_filter = MorphologicalFilterType::New(); UCharImageType::SizeType indexRadius; indexRadius[0] = 1; indexRadius[1] = 1; indexRadius[2] = 1; closing_filter->SetRadius(indexRadius); island_removing_filter->SetRadius(indexRadius); closing_filter->SetBackgroundValue(0); closing_filter->SetForegroundValue(1); closing_filter->SetMajorityThreshold(2); closing_filter->SetMaximumNumberOfIterations(3); island_removing_filter->SetBackgroundValue(1); island_removing_filter->SetForegroundValue(0); island_removing_filter->SetMajorityThreshold(1); island_removing_filter->SetMaximumNumberOfIterations(3); closing_filter->SetInput(thresh_img); closing_filter->Update(); island_removing_filter->SetInput(closing_filter->GetOutput()); island_removing_filter->Update(); UCharImageType::Pointer clean_structure = island_removing_filter->GetOutput(); this->time_vote += timer.report(); /* Optionally, save the thresholded files */ if (this->write_thresholded_files) { lprintf ("Saving thresholded structures\n"); std::string thresh_img_fn = string_format ( "%s/%s_thresh_%f.nrrd", label_output_dir.c_str(), structure_label.c_str(), thresh_val); timer.start(); itk_image_save (clean_structure, thresh_img_fn.c_str()); this->time_io += timer.report(); } /* Extract reference structure as binary mask. */ timer.start(); this->extract_reference_image (mapped_name); this->time_extract += timer.report(); /* Compute Dice, etc. */ if (this->have_ref_structure) { std::string stats_string = this->stats.compute_statistics ( "segmentation", /* Not used yet */ this->ref_structure_image, clean_structure); std::string seg_log_string = string_format ( "target=%s,reg=%s,struct=%s," "rho=%f,sigma=%f,minsim=%f,thresh=%f," "%s\n", this->ref_id.c_str(), this->registration_id.c_str(), mapped_name.c_str(), msw->rho, msw->sigma, msw->minsim, thresh_val, stats_string.c_str()); lprintf ("%s", seg_log_string.c_str()); /* Update seg_dice file */ std::string seg_dice_log_fn = string_format ( "%s/seg_dice.csv", this->mabs_train_dir.c_str()); FILE *fp = fopen (seg_dice_log_fn.c_str(), "a"); fprintf (fp, "%s", seg_log_string.c_str()); fclose (fp); } /* Or, if we don't have the reference image, then we might want to add it to the referenced rt_study, so it can be saved as a final segmentation. */ else if (this->write_dicom_rt_struct) { this->ref_rtds->add_structure ( clean_structure, mapped_name.c_str(), 0); } } Mabs::Mabs () { d_ptr = new Mabs_private; } Mabs::~Mabs () { delete d_ptr; } void Mabs::load_process_dir_list (const std::string& dir) { /* Clear process_dir_list to avoid multiple entries in case of multiple * calls to this function */ d_ptr->process_dir_list.clear(); Dir_list d (dir); for (int i = 0; i < d.num_entries; i++) { /* Skip "." and ".." */ if (!strcmp (d.entries[i], ".") || !strcmp (d.entries[i], "..")) { continue; } /* Build string containing full path to atlas item */ std::string path = compose_filename (dir, d.entries[i]); /* Only consider directories */ if (!is_directory (path.c_str())) { continue; } /* Add directory to atlas_dir_list */ d_ptr->process_dir_list.push_back (path); } lprintf ("Found %d cases to process from directory %s\n", d_ptr->process_dir_list.size(), dir.c_str()); } bool Mabs::check_seg_checkpoint (std::string folder) { std::string seg_checkpoint_fn = string_format ( "%s/checkpoint.txt", folder.c_str()); if (file_exists (seg_checkpoint_fn)) { lprintf ("Segmentation complete for %s\n", folder.c_str()); return true; } else { return false; } } /* ------------------------------------------------------------------------- * This function runs a registration for a group of atlases against a single reference image. * ------------------------------------------------------------------------- * The following variables should be set before running this: d_ptr->ref_rtds the fixed image and its structure set d_ptr->atlas_list list of images that should be registred d_ptr->output_dir directory containing output results (e.g. .../prealign or .../mabs-train) d_ptr->registration_list list of registration command files * ------------------------------------------------------------------------- */ void Mabs::run_registration_loop () { Plm_timer timer; /* Loop through images in the atlas */ std::list::iterator atl_it; for (atl_it = d_ptr->atlas_list.begin(); atl_it != d_ptr->atlas_list.end(); atl_it++) { Rt_study rtds; std::string path = *atl_it; std::string input_dir = dirname (path); std::string atlas_id = basename (path); printf ("%s\n -> %s\n -> %s\n", path.c_str(), input_dir.c_str(), atlas_id.c_str()); std::string atlas_input_path = string_format ("%s/%s", input_dir.c_str(), atlas_id.c_str()); std::string atlas_output_path = string_format ("%s/%s", d_ptr->output_dir.c_str(), atlas_id.c_str()); /* Load image & structures from "prep" directory */ timer.start(); rtds.load_rt_study_dir (atlas_input_path); d_ptr->time_io += timer.report(); /* Inspect the structures -- we might be able to skip the atlas if it has no relevant structures */ bool can_skip = true; Segmentation::Pointer rtss = rtds.get_segmentation(); for (size_t i = 0; i < rtss->get_num_structures(); i++) { std::string ori_name = rtss->get_structure_name (i); std::string mapped_name = d_ptr->map_structure_name (ori_name); if (mapped_name != "") { can_skip = false; break; } } if (can_skip) { lprintf ("No relevant structures. Skipping.\n"); continue; } /* Loop through each registration parameter set */ std::list::iterator reg_it; for (reg_it = d_ptr->registration_list.begin(); reg_it != d_ptr->registration_list.end(); reg_it++) { /* Set up files & directories for this job */ std::string command_file = *reg_it; std::string curr_output_dir; std::string registration_id; registration_id = basename (command_file); curr_output_dir = string_format ("%s/%s", atlas_output_path.c_str(), registration_id.c_str()); /* Check if this registration is already complete. We might be able to skip it. */ std::string reg_checkpoint_fn = string_format ( "%s/checkpoint.txt", curr_output_dir.c_str()); if (file_exists (reg_checkpoint_fn)) { lprintf ("Registration parms complete for %s\n", curr_output_dir.c_str()); continue; } /* Set up the registration data structure */ Registration reg; Registration_parms::Pointer regp = reg.get_registration_parms (); Registration_data::Pointer regd = reg.get_registration_data (); /* Parse the registration command string */ std::string command_string = slurp_file (command_file); int rc = reg.set_command_string (command_string); if (rc != PLM_SUCCESS) { lprintf ("Skipping command file \"%s\" " "due to parse error.\n", command_file.c_str()); continue; } /* Give some feedback about which registration we are going to run */ lprintf ("** TASK: %s %s %s\n", d_ptr->ref_id.c_str(), atlas_id.c_str(), registration_id.c_str()); /* Set input files */ Plm_image::Pointer fixed_image = Plm_image::New (); fixed_image->set_itk ( d_ptr->ref_rtds->get_image()->itk_float()); reg.set_fixed_image (fixed_image); Plm_image::Pointer moving_image = Plm_image::New (); moving_image->set_itk ( rtds.get_image()->itk_float()); reg.set_moving_image (moving_image); /* PAOLO ZAFFINO: align centers of gravity */ if (d_ptr->input_roi_for_cog_prealignment != NULL) { /* Add STAGE only if a segment command is executed. Is it needed or we can define it into the configuration file? */ std::string command_string_plus_cog = "[STAGE]\nxform=align_center_of_gravity\n"; command_string_plus_cog.append(command_string); int rc_cog = reg.set_command_string (command_string_plus_cog); if (rc_cog != PLM_SUCCESS) { lprintf ("Skipping centers of gravity prealignment addition to command file \"%s\" \n", command_file.c_str()); continue; } /* Set fixed ROI */ reg.set_fixed_roi(d_ptr->input_roi_for_cog_prealignment); /* Set moving ROI*/ std::string target_roi_name; if (d_ptr->executed_command == "segment") { target_roi_name = strip_extension(basename(d_ptr->prealign_roi_cmd_name)); } else if (d_ptr->executed_command == "prealign") { target_roi_name = d_ptr->parms->prealign_roi_cfg_name; } size_t target_roi_index = -1; for (size_t i = 0; i < rtss->get_num_structures(); i++) { std::string struct_name = rtss->get_structure_name (i); if (struct_name == target_roi_name) { target_roi_index = i; break; } } if (target_roi_index != -1) { Plm_image::Pointer moving_roi = Plm_image::New (); moving_roi->set_itk (rtss->get_structure_image (target_roi_index)); reg.set_moving_roi(moving_roi); } else if (target_roi_index == -1) { lprintf("No moving ROI set!\n"); } } /* Run the registration */ lprintf ("DO_REGISTRATION_PURE\n"); lprintf ("regp->num_stages = %d\n", regp->num_stages); timer.start(); Xform::Pointer xf_out = reg.do_registration_pure (); d_ptr->time_reg += timer.report(); /* Warp the output image */ lprintf ("Warp output image...\n"); Plm_image_header fixed_pih (fixed_image); Plm_image::Pointer warped_image = Plm_image::New(); timer.start(); plm_warp (warped_image, 0, xf_out, &fixed_pih, moving_image, regp->default_value, 0, 1); d_ptr->time_warp_img += timer.report(); /* Warp the structures */ lprintf ("Warp structures...\n"); Plm_image_header source_pih (rtds.get_image()); timer.start(); //rtss->warp (xf_out, &fixed_pih); Segmentation::Pointer warped_rtss = rtss->warp_nondestructive (xf_out, &fixed_pih); d_ptr->time_warp_str += timer.report(); /* Save some debugging information */ if (d_ptr->write_registration_files) { timer.start(); std::string fn; lprintf ("Saving registration_files\n"); if (d_ptr->write_warped_images) { fn = string_format ("%s/img.nrrd", curr_output_dir.c_str()); warped_image->save_image (fn.c_str()); } fn = string_format ("%s/xf.txt", curr_output_dir.c_str()); xf_out->save (fn.c_str()); if (d_ptr->parms->write_warped_structures) { fn = string_format ("%s/structures", curr_output_dir.c_str()); warped_rtss->save_prefix (fn, "nrrd"); } d_ptr->time_io += timer.report(); } /* Loop through structures for this atlas image */ lprintf ("Process structures...\n"); for (size_t i = 0; i < warped_rtss->get_num_structures(); i++) { /* Check structure name, make sure it is something we want to segment */ std::string ori_name = warped_rtss->get_structure_name (i); std::string mapped_name = d_ptr->map_structure_name (ori_name); if (mapped_name == "") { continue; } /* Extract structure as binary mask */ timer.start(); UCharImageType::Pointer structure_image = warped_rtss->get_structure_image (i); d_ptr->time_extract += timer.report(); /* Make the distance map */ if (d_ptr->compute_distance_map && d_ptr->parms->fusion_criteria == "gaussian") { timer.start(); lprintf ("Computing distance map...\n"); this->compute_dmap (structure_image, curr_output_dir, mapped_name); } /* Extract reference structure as binary mask. */ timer.start(); lprintf ("Extracting reference image (%s)\n", mapped_name.c_str()); d_ptr->extract_reference_image (mapped_name); lprintf ("Done extracting reference image.\n"); d_ptr->time_extract += timer.report(); /* Compute Dice, etc. */ timer.start(); if (d_ptr->have_ref_structure) { std::string stats_string = d_ptr->stats.compute_statistics ( registration_id, d_ptr->ref_structure_image, structure_image); std::string reg_log_string = string_format ( "target=%s,atlas=%s,reg=%s,struct=%s,%s\n", d_ptr->ref_id.c_str(), atlas_id.c_str(), registration_id.c_str(), mapped_name.c_str(), stats_string.c_str()); lprintf ("%s", reg_log_string.c_str()); /* Update reg_dice file */ std::string reg_dice_log_fn = string_format ( "%s/reg_dice.csv", d_ptr->output_dir.c_str()); FILE *fp = fopen (reg_dice_log_fn.c_str(), "a"); fprintf (fp, "%s", reg_log_string.c_str()); fclose (fp); } } /* Create checkpoint file which means that this registration is complete */ touch_file (reg_checkpoint_fn); } /* end for each registration parameter */ } /* end for each atlas image */ } void Mabs::convert (const std::string& input_dir, const std::string& output_dir) { Rt_study rtds; Plm_timer timer; /* Load the rtds for the atlas */ timer.start(); lprintf ("MABS loading %s\n", input_dir.c_str()); rtds.load (input_dir); lprintf ("MABS load complete\n"); d_ptr->time_io += timer.report(); /* Remove structures which are not part of the atlas */ timer.start(); Segmentation::Pointer seg = rtds.get_segmentation(); seg->prune_empty (); Rtss *cxt = seg->get_structure_set_raw (); for (size_t i = 0; i < seg->get_num_structures(); i++) { /* Check structure name, make sure it is something we want to segment */ std::string ori_name = seg->get_structure_name (i); std::string mapped_name = d_ptr->map_structure_name (ori_name); lprintf ("Structure i (%s), checking for mapped name\n", ori_name.c_str()); if (mapped_name == "") { /* If not, delete it (before rasterizing) */ lprintf ("Deleted structure %s\n"); cxt->delete_structure (i); --i; continue; } lprintf ("Resetting structure name to %s\n", mapped_name.c_str()); seg->set_structure_name (i, mapped_name); } /* Rasterize structure set */ Plm_image_header pih (rtds.get_image().get()); seg->rasterize (&pih, false, false); d_ptr->time_extract += timer.report(); /* If so specified, resample the images */ if (d_ptr->convert_resample) { timer.start(); rtds.resample (d_ptr->convert_spacing); d_ptr->time_extract += timer.report(); } /* Save the image as raw files */ timer.start(); std::string fn = string_format ("%s/img.nrrd", output_dir.c_str()); rtds.get_image()->save_image (fn.c_str()); d_ptr->time_io += timer.report(); /* Save structures which are part of the atlas */ std::string prefix = string_format ("%s/structures", output_dir.c_str()); seg->save_prefix (prefix, "nrrd"); d_ptr->time_io += timer.report(); } void Mabs::atlas_convert () { /* Parse atlas directory */ this->load_process_dir_list (d_ptr->parms->atlas_dir); /* Just a little debugging */ d_ptr->print_structure_map (); /* Loop through atlas_dir, converting file formats */ for (std::list::iterator it = d_ptr->process_dir_list.begin(); it != d_ptr->process_dir_list.end(); it++) { std::string input_dir = *it; std::string atlas_id = basename (input_dir); std::string output_dir = string_format ( "%s/%s", d_ptr->convert_dir.c_str(), atlas_id.c_str()); this->convert (input_dir, output_dir); } lprintf ("Rasterization time: %10.1f seconds\n", d_ptr->time_extract); lprintf ("I/O time: %10.1f seconds\n", d_ptr->time_io); lprintf ("MABS prep complete\n"); } void Mabs::atlas_selection () { /* Create and start timer */ Plm_timer timer; timer.start(); /* Parse atlas directory */ this->load_process_dir_list (d_ptr->preprocessed_dir); /* Define stuff to save ranking */ std::list > ranked_atlases; // Only ranked, not selected std::string atlas_ranking_file_name = string_format ("%s/atlas_ranking.txt", d_ptr->segment_outdir_base.c_str()); bool compute_new_ranking = true; /* Check if a precomputed ranking (not specified by user) can be used */ if (is_directory(d_ptr->segment_outdir_base.c_str()) && file_exists(atlas_ranking_file_name.c_str()) && d_ptr->parms->atlases_from_ranking != -1) { compute_new_ranking = false; } /* Create atlas-train directory */ if (compute_new_ranking) { make_directory(d_ptr->segment_outdir_base.c_str()); } /* Open log file for atlas selection */ std::string atlas_selection_log_file_name = string_format ("%s/log_atlas_seletion.txt", d_ptr->segment_outdir_base.c_str()); FILE *atlas_selection_log_file = plm_fopen (atlas_selection_log_file_name.c_str(), "w"); if (atlas_selection_log_file == NULL) { printf("Error opening atlas selection log file!\n"); exit(1); } /* Create object and set the parameters */ Mabs_atlas_selection* atlas_selector = new Mabs_atlas_selection(); atlas_selector->atlas_selection_criteria = d_ptr->parms->atlas_selection_criteria; atlas_selector->selection_reg_parms_fn = d_ptr->parms->selection_reg_parms_fn; atlas_selector->similarity_percent_threshold = d_ptr->parms->similarity_percent_threshold; atlas_selector->max_random_atlases = d_ptr->parms->max_random_atlases; atlas_selector->min_random_atlases = d_ptr->parms->min_random_atlases; atlas_selector->hist_bins = d_ptr->parms->mi_histogram_bins; atlas_selector->percentage_nmi_random_sample = d_ptr->parms->percentage_nmi_random_sample; atlas_selector->atlases_from_ranking = d_ptr->parms->atlases_from_ranking; atlas_selector->precomputed_ranking_fn = d_ptr->parms->precomputed_ranking_fn; atlas_selector->subject_id = d_ptr->segment_input_fn.c_str(); atlas_selector->atlas_dir = d_ptr->parms->atlas_dir; atlas_selector->number_of_atlases = (int) d_ptr->process_dir_list.size(); if (d_ptr->parms->roi_mask_fn != "") { /* Set the mask if defined */ Plm_image::Pointer mask_plm = plm_image_load (d_ptr->parms->roi_mask_fn, PLM_IMG_TYPE_ITK_UCHAR); typedef itk::ImageMaskSpatialObject<3> MaskType; atlas_selector->mask = MaskType::New(); atlas_selector->mask->SetImage(mask_plm->itk_uchar()); atlas_selector->mask->Update(); } atlas_selector->min_hist_sub_value_defined = d_ptr->parms->lower_mi_value_sub_defined; atlas_selector->min_hist_sub_value = d_ptr->parms->lower_mi_value_sub; atlas_selector->max_hist_sub_value_defined = d_ptr->parms->upper_mi_value_sub_defined; atlas_selector->max_hist_sub_value = d_ptr->parms->upper_mi_value_sub; atlas_selector->min_hist_atl_value_defined = d_ptr->parms->lower_mi_value_atl_defined; atlas_selector->min_hist_atl_value = d_ptr->parms->lower_mi_value_atl; atlas_selector->max_hist_atl_value_defined = d_ptr->parms->upper_mi_value_atl_defined; atlas_selector->max_hist_atl_value = d_ptr->parms->upper_mi_value_atl; /* New selection is required, execute it */ if (compute_new_ranking) { atlas_selector->subject = plm_image_load_native(atlas_selector->subject_id); atlas_selector->atlas_dir_list = d_ptr->process_dir_list; // if set, before the selection, prealign the images (using COG or whatever else) if (d_ptr->parms->prealign_mode == "custom") { Registration reg; Registration_parms::Pointer regp = reg.get_registration_parms (); Registration_data::Pointer regd = reg.get_registration_data (); /* Parse the registration command string */ std::string command_string = slurp_file (d_ptr->parms->prealign_registration_config); int rc = reg.set_command_string (command_string); if (rc != PLM_SUCCESS) { lprintf ("Skipping command file \"%s\" " "due to parse error.\n", d_ptr->parms->prealign_registration_config.c_str()); } /* Set input images */ std::string fixed_image_fn; fixed_image_fn = string_format ("%s/%s/img.nrrd", d_ptr->convert_dir.c_str(), d_ptr->parms->prealign_reference.c_str()); Plm_image::Pointer fixed_image = Plm_image::New (fixed_image_fn); reg.set_fixed_image (fixed_image); Plm_image::Pointer moving_image = Plm_image::New (); moving_image->set_itk (atlas_selector->subject->itk_float()); reg.set_moving_image (moving_image); /* Align centers of gravity */ if (d_ptr->prealign_roi_cmd_name != "") { /* Add STAGE for COG */ std::string command_string_plus_cog = "[STAGE]\nxform=align_center_of_gravity\n"; command_string_plus_cog.append(command_string); int rc_cog = reg.set_command_string (command_string_plus_cog); if (rc_cog != PLM_SUCCESS) { lprintf ("Skipping centers of gravity prealignment addition to command file \"%s\" \n", d_ptr->parms->prealign_registration_config.c_str()); } /* Set moving ROI */ d_ptr->input_roi_for_cog_prealignment = Plm_image::New (d_ptr->prealign_roi_cmd_name); reg.set_moving_roi(d_ptr->input_roi_for_cog_prealignment); /* Set fixed ROI*/ std::string fixed_roi_fn; fixed_roi_fn = string_format ("%s/%s/structures/%s.nrrd", d_ptr->convert_dir.c_str(), d_ptr->parms->prealign_reference.c_str(), d_ptr->parms->prealign_roi_cfg_name.c_str()); Plm_image::Pointer fixed_roi = Plm_image::New (fixed_roi_fn); reg.set_fixed_roi(fixed_roi); } /* Run the registration */ lprintf ("DO_REGISTRATION_PURE\n"); lprintf ("regp->num_stages = %d\n", regp->num_stages); timer.start(); Xform::Pointer xf_out = reg.do_registration_pure (); d_ptr->time_reg += timer.report(); /* Warp the image */ lprintf ("Prealign input image...\n"); Plm_image_header fixed_pih (fixed_image); Plm_image::Pointer warped_image = Plm_image::New(); timer.start(); plm_warp (warped_image, 0, xf_out, &fixed_pih, moving_image, regp->default_value, 0, 1); d_ptr->time_warp_img += timer.report(); atlas_selector->subject = warped_image; } atlas_selector->run_selection(); } /* Use a precomputed ranking */ else if (!compute_new_ranking) { atlas_selector->precomputed_ranking_fn = atlas_ranking_file_name.c_str(); atlas_selector->atlases_from_ranking = d_ptr->parms->atlases_from_ranking; atlas_selector->precomputed_ranking(); } /* Write into the log file preliminary information about the selection process */ fprintf(atlas_selection_log_file, "Patient = %s, initial atlases = %d, selection criteria = %s \n", atlas_selector->subject_id.c_str(), atlas_selector->number_of_atlases, atlas_selector->atlas_selection_criteria.c_str()); if (!compute_new_ranking) { fprintf(atlas_selection_log_file, "SELECTION MADE USING A PRECOMPUTED RANKING\n"); } /* Print into the log file information about the selection process */ fprintf(atlas_selection_log_file, "Selected atlases for patient %s: (%d) \n", atlas_selector->subject_id.c_str(), (int) atlas_selector->selected_atlases.size()); for (std::list >::iterator it_selected_atlases = atlas_selector->selected_atlases.begin(); it_selected_atlases != atlas_selector->selected_atlases.end(); it_selected_atlases++) { fprintf(atlas_selection_log_file, "Atlas %s with score value equal to %f \n", it_selected_atlases->first.c_str(), it_selected_atlases->second); } /* Close log file */ fclose(atlas_selection_log_file); /* Fill the structures */ d_ptr->selected_atlases.assign(atlas_selector->selected_atlases.begin(), atlas_selector->selected_atlases.end()); ranked_atlases.assign(atlas_selector->ranked_atlases.begin(), atlas_selector->ranked_atlases.end()); /* Write the new ranking */ if (compute_new_ranking) { FILE *ranking_file = fopen (atlas_ranking_file_name.c_str(), "w"); fprintf(ranking_file, "%s: ", atlas_selector->subject_id.c_str()); /* Cycle over atlases */ for (std::list >::iterator it_list = ranked_atlases.begin(); it_list != ranked_atlases.end(); it_list++) { fprintf(ranking_file, "%s ", it_list->first.c_str()); } fclose(ranking_file); } /* Delete object */ delete atlas_selector; /* Stop timer */ d_ptr->time_atlas_selection += timer.report(); printf("Atlas selection done! \n"); } void Mabs::train_atlas_selection () { /* Create and start timer */ Plm_timer timer; timer.start(); /* Parse atlas directory */ this->load_process_dir_list (d_ptr->preprocessed_dir); /* Define stuff to save ranking */ std::map > > train_ranked_atlases; // Only ranked, not selected std::string train_atlas_ranking_file_name = string_format ("%s/train_atlas_ranking.txt", d_ptr->atlas_train_dir.c_str()); bool compute_new_ranking = true; /* Check if a precomputed ranking (not specified by user) can be used */ if (is_directory(d_ptr->atlas_train_dir.c_str()) && file_exists(train_atlas_ranking_file_name.c_str()) && d_ptr->parms->atlases_from_ranking != -1) { /* Count lines */ FILE *count_lines_file = fopen (train_atlas_ranking_file_name.c_str(), "r"); char ch; int lines_number = 1; /* The last line doesn't have \n */ while ((ch=getc(count_lines_file)) != EOF) { if (ch == '\n') ++lines_number; } fclose(count_lines_file); /* If number of lines is equal to number of atlases use precomputed ranking */ if (lines_number == (int) d_ptr->process_dir_list.size()) { compute_new_ranking = false; } } /* Create atlas-train directory */ if (compute_new_ranking) { make_directory(d_ptr->atlas_train_dir.c_str()); } /* Open log file for atlas selection */ std::string train_atlas_selection_log_file_name = string_format ("%s/log_train_atlas_seletion.txt", d_ptr->atlas_train_dir.c_str()); FILE *train_atlas_selection_log_file = plm_fopen (train_atlas_selection_log_file_name.c_str(), "w"); if (train_atlas_selection_log_file == NULL) { printf("Error opening train atlas selection log file!\n"); exit(1); } /* Loop through atlas_dir, choosing reference images to segment */ for (std::list::iterator it = d_ptr->process_dir_list.begin(); it != d_ptr->process_dir_list.end(); it++) { /* Create atlas list for this test case */ std::string path = *it; d_ptr->atlas_list = d_ptr->process_dir_list; d_ptr->atlas_list.remove (path); std::string patient_id = basename (path); d_ptr->ref_id = patient_id; /* Load image & structures from "prep" directory */ if (compute_new_ranking) { std::string fn = string_format ("%s/%s/img.nrrd", d_ptr->preprocessed_dir.c_str(), patient_id.c_str()); d_ptr->ref_rtds->load_image (fn.c_str()); } /* Create object and set the parameters */ Mabs_atlas_selection* train_atlas_selector = new Mabs_atlas_selection(); train_atlas_selector->atlas_selection_criteria = d_ptr->parms->atlas_selection_criteria; train_atlas_selector->selection_reg_parms_fn = d_ptr->parms->selection_reg_parms_fn; train_atlas_selector->similarity_percent_threshold = d_ptr->parms->similarity_percent_threshold; train_atlas_selector->max_random_atlases = d_ptr->parms->max_random_atlases; train_atlas_selector->min_random_atlases = d_ptr->parms->min_random_atlases; train_atlas_selector->hist_bins = d_ptr->parms->mi_histogram_bins; train_atlas_selector->percentage_nmi_random_sample = d_ptr->parms->percentage_nmi_random_sample; train_atlas_selector->atlases_from_ranking = d_ptr->parms->atlases_from_ranking; train_atlas_selector->precomputed_ranking_fn = d_ptr->parms->precomputed_ranking_fn; train_atlas_selector->subject_id = patient_id; train_atlas_selector->atlas_dir = d_ptr->parms->atlas_dir; train_atlas_selector->number_of_atlases = (int) d_ptr->process_dir_list.size(); if (d_ptr->parms->roi_mask_fn != "") { /* Set the mask if defined */ Plm_image::Pointer mask_plm = plm_image_load (d_ptr->parms->roi_mask_fn, PLM_IMG_TYPE_ITK_UCHAR); typedef itk::ImageMaskSpatialObject<3> MaskType; train_atlas_selector->mask = MaskType::New(); train_atlas_selector->mask->SetImage(mask_plm->itk_uchar()); train_atlas_selector->mask->Update(); } train_atlas_selector->min_hist_sub_value_defined = d_ptr->parms->lower_mi_value_sub_defined; train_atlas_selector->min_hist_sub_value = d_ptr->parms->lower_mi_value_sub; train_atlas_selector->max_hist_sub_value_defined = d_ptr->parms->upper_mi_value_sub_defined; train_atlas_selector->max_hist_sub_value = d_ptr->parms->upper_mi_value_sub; train_atlas_selector->min_hist_atl_value_defined = d_ptr->parms->lower_mi_value_atl_defined; train_atlas_selector->min_hist_atl_value = d_ptr->parms->lower_mi_value_atl; train_atlas_selector->max_hist_atl_value_defined = d_ptr->parms->upper_mi_value_atl_defined; train_atlas_selector->max_hist_atl_value = d_ptr->parms->upper_mi_value_atl; /* New selection is required, execute it */ if (compute_new_ranking) { train_atlas_selector->subject = d_ptr->ref_rtds->get_image(); train_atlas_selector->atlas_dir_list = d_ptr->process_dir_list; train_atlas_selector->run_selection(); } /* Use a precomputed ranking */ else if (!compute_new_ranking) { train_atlas_selector->precomputed_ranking_fn = train_atlas_ranking_file_name.c_str(); train_atlas_selector->atlases_from_ranking = d_ptr->parms->atlases_from_ranking; train_atlas_selector->precomputed_ranking(); } /* Write into the log file preliminary information about the selection process */ fprintf(train_atlas_selection_log_file, "Patient = %s, initial atlases = %d, selection criteria = %s \n", train_atlas_selector->subject_id.c_str(), train_atlas_selector->number_of_atlases, train_atlas_selector->atlas_selection_criteria.c_str()); if (!compute_new_ranking) { fprintf(train_atlas_selection_log_file, "SELECTION MADE USING A PRECOMPUTED RANKING\n"); } /* Print into the log file information about the selection process */ fprintf(train_atlas_selection_log_file, "Selected atlases for patient %s: (%d) \n", train_atlas_selector->subject_id.c_str(), (int) train_atlas_selector->selected_atlases.size()); for (std::list >::iterator it_selected_atlases = train_atlas_selector->selected_atlases.begin(); it_selected_atlases != train_atlas_selector->selected_atlases.end(); it_selected_atlases++) { fprintf(train_atlas_selection_log_file, "Atlas %s with score value equal to %f \n", it_selected_atlases->first.c_str(), it_selected_atlases->second); } fprintf(train_atlas_selection_log_file, "\n"); /* Fill the map structures */ d_ptr->selected_atlases_train.insert(std::make_pair(train_atlas_selector->subject_id, train_atlas_selector->selected_atlases)); train_ranked_atlases.insert(std::make_pair(train_atlas_selector->subject_id, train_atlas_selector->ranked_atlases)); /* Delete object */ delete train_atlas_selector; } /* Close log file */ fclose(train_atlas_selection_log_file); /* Write the new ranking */ if (compute_new_ranking) { FILE *ranking_file = fopen (train_atlas_ranking_file_name.c_str(), "w"); /* Cycle over reference images */ std::map > >::iterator it_map; for (it_map = train_ranked_atlases.begin(); it_map != train_ranked_atlases.end(); it_map++) { fprintf(ranking_file, "%s: ", it_map->first.c_str()); /* Cycle over atlases */ for (std::list >::iterator it_list = it_map->second.begin(); it_list != it_map->second.end(); it_list++) { fprintf(ranking_file, "%s ", it_list->first.c_str()); } /* If it is not the last subject write on a new line */ if (it_map != (--train_ranked_atlases.end())) fprintf(ranking_file, "\n"); } fclose(ranking_file); } /* Stop timer */ d_ptr->time_atlas_selection += timer.report(); printf("Train atlas selection done! \n"); } void Mabs::atlas_prealign () { /* Open logfile */ std::string logfile_path = string_format ( "%s/%s", d_ptr->prealign_dir.c_str(), "logfile.txt"); logfile_open (logfile_path.c_str(), "a"); /* Parse directory with registration files */ if (d_ptr->parms->prealign_mode == "disabled") { print_and_exit ("Prealignment not enabled in parameters file!\n"); } else if (d_ptr->parms->prealign_mode == "default") { print_and_exit ("No default prealignment implemented yet!\n"); } else if (d_ptr->parms->prealign_mode == "custom") { this->parse_registration_dir (d_ptr->parms->prealign_registration_config); } /* Parse convert directory */ this->load_process_dir_list (d_ptr->convert_dir); if (d_ptr->process_dir_list.size() < 2) { print_and_exit ("Error. Prealignment requires at least two " "images in the convert directory.\n"); } /* Identify directory of reference image */ std::string reference_id; std::string reference_dir; if (d_ptr->parms->prealign_reference != "") { reference_id = d_ptr->parms->prealign_reference; reference_dir = string_format ( "%s/%s", d_ptr->convert_dir.c_str(), d_ptr->parms->prealign_reference.c_str()); if (!is_directory (reference_dir)) { print_and_exit ("Error. Prealignment reference directory (%s) " " was not found.\n", reference_dir.c_str()); } } else { reference_dir = d_ptr->process_dir_list.front(); reference_id = basename (reference_dir); } lprintf ("Prealignment reference directory is %s\n", reference_dir.c_str()); /* Load reference image and structures */ std::string reference_convert_img_fn = string_format ( "%s/img.nrrd", reference_dir.c_str()); std::string reference_convert_structures_dir = string_format ( "%s/structures", reference_dir.c_str()); /* Load reference image -- we assume this is successful */ Rt_study::Pointer ref_rtds = Rt_study::New(); ref_rtds->load_image (reference_convert_img_fn); ref_rtds->load_prefix (reference_convert_structures_dir.c_str()); /* Resample and save reference image and structures */ std::string reference_prealign_img_fn = string_format ( "%s/%s/img.nrrd", d_ptr->prealign_dir.c_str(), reference_id.c_str()); std::string reference_prealign_structures_dir = string_format ( "%s/%s/structures", d_ptr->prealign_dir.c_str(), reference_id.c_str()); if (d_ptr->prealign_resample) { ref_rtds->resample (d_ptr->prealign_spacing); } Plm_image::Pointer reference_image = ref_rtds->get_image (); /* PAOLO ZAFFINO * set fixed ROI if defined into the prealign section */ if (d_ptr->parms->prealign_roi_cfg_name != "") { Segmentation::Pointer fixed_rtss = ref_rtds->get_segmentation(); size_t target_roi_index = -1; for (size_t i = 0; i < fixed_rtss->get_num_structures(); i++) { std::string struct_name = fixed_rtss->get_structure_name (i); if (struct_name == d_ptr->parms->prealign_roi_cfg_name) { target_roi_index = i; break; } } if (target_roi_index != -1) { d_ptr->input_roi_for_cog_prealignment = Plm_image::New (fixed_rtss->get_structure_image (target_roi_index)); } else if (target_roi_index == -1) { lprintf("No fixed ROI set!\n"); } } reference_image->save_image (reference_prealign_img_fn); ref_rtds->save_prefix (reference_prealign_structures_dir, "nrrd"); /* Do it. */ d_ptr->ref_rtds = ref_rtds; d_ptr->ref_id = reference_id; d_ptr->atlas_list = d_ptr->process_dir_list; d_ptr->output_dir = d_ptr->prealign_dir; run_registration_loop (); /* Choose best registration parameter settings based on statistics */ std::string best_registration_name = d_ptr->stats.choose_best (); /* Copy results of best pre-alignment method into prealign base */ std::list::iterator atl_it; for (atl_it = d_ptr->atlas_list.begin(); atl_it != d_ptr->atlas_list.end(); atl_it++) { std::string path = *atl_it; std::string atlas_id = basename (path); /* Don't copy over results for reference image */ if (atlas_id == d_ptr->ref_id) { continue; } std::string src_directory = string_format ("%s/%s/%s", d_ptr->prealign_dir.c_str(), atlas_id.c_str(), best_registration_name.c_str()); std::string dst_directory = string_format ("%s/%s", d_ptr->prealign_dir.c_str(), atlas_id.c_str()); std::string src_img = string_format ("%s/%s", src_directory.c_str(), "img.nrrd"); std::string dst_img = string_format ("%s/%s", dst_directory.c_str(), "img.nrrd"); /* Copy image */ printf ("copying %s <- %s\n", dst_img.c_str(), src_img.c_str()); copy_file (dst_img, src_img); /* Copy structures */ std::string src_structures_dir = string_format ("%s/%s", src_directory.c_str(), "structures"); std::string dst_structures_dir = string_format ("%s/%s", dst_directory.c_str(), "structures"); make_directory (dst_structures_dir.c_str()); Dir_list d (src_structures_dir); for (int i = 0; i < d.num_entries; i++) { /* Skip "." and ".." */ if (!strcmp (d.entries[i], ".") || !strcmp (d.entries[i], "..")) { continue; } std::string src_structure = compose_filename (src_structures_dir, d.entries[i]); std::string dst_structure = compose_filename (dst_structures_dir, d.entries[i]); printf ("copying %s <- %s\n", dst_structure.c_str(), src_structure.c_str()); copy_file (dst_structure, src_structure); } } lprintf ("MABS pre-align complete\n"); logfile_close (); } void Mabs::parse_registration_dir (const std::string& registration_config) { /* Figure out whether we need to do a single registration or multiple registrations (for atlas tuning) */ if (is_directory (registration_config)) { Dir_list dir (registration_config); for (int i = 0; i < dir.num_entries; i++) { std::string full_path = string_format ( "%s/%s", registration_config.c_str(), dir.entries[i]); /* Skip backup files */ if (extension_is (dir.entries[i], "~")) { continue; } /* Skip directories */ if (is_directory (full_path)) { continue; } d_ptr->registration_list.push_back (full_path); } } else { d_ptr->registration_list.push_back (registration_config); } } void Mabs::set_executed_command (const std::string& executed_command) { d_ptr->executed_command = executed_command; } FloatImageType::Pointer Mabs::compute_dmap ( UCharImageType::Pointer& structure_image, const std::string& curr_output_dir, const std::string& mapped_name) { Plm_timer timer; Distance_map dmap; /* Compute the dmap */ timer.start (); dmap.set_input_image (structure_image); dmap.set_inside_is_positive (false); dmap.set_use_squared_distance (false); /* GCS FIX: This should not be hard-coded */ dmap.set_maximum_distance (500); dmap.run (); FloatImageType::Pointer dmap_image = dmap.get_output_image (); /* GCS FIX: The below is no longer needed if set_maximum_distance is implemented for other distance map alternatives */ /* Truncate the dmap. This is to save disk space. Maybe we won't need this if we can crop. */ Float_pair_list al; al.push_back (std::make_pair ( -std::numeric_limits::max(), 0)); al.push_back (std::make_pair (-500, -500)); al.push_back (std::make_pair (500, 500)); al.push_back (std::make_pair ( std::numeric_limits::max(), 0)); itk_adjust (dmap_image, al); d_ptr->time_dmap += timer.report(); if (d_ptr->write_distance_map_files) { timer.start(); std::string fn = string_format ("%s/dmap_%s.nrrd", curr_output_dir.c_str(), mapped_name.c_str()); itk_image_save (dmap_image, fn.c_str()); d_ptr->time_io += timer.report(); } return dmap_image; } void Mabs::no_voting ( const std::string& atlas_id, const std::string& label_output_dir ) { Plm_timer timer; /* Set up files & directories for this job */ std::string atlas_input_path; atlas_input_path = string_format ("%s/%s", d_ptr->preprocessed_dir.c_str(), atlas_id.c_str()); lprintf ("atlas_input_path: %s\n", atlas_input_path.c_str()); std::string atlas_output_path; atlas_output_path = string_format ("%s/%s", d_ptr->output_dir.c_str(), atlas_id.c_str()); lprintf ("atlas_output_path: %s\n", atlas_output_path.c_str()); std::string curr_output_dir; curr_output_dir = string_format ("%s/%s", atlas_output_path.c_str(), d_ptr->registration_id.c_str()); lprintf ("curr_output_dir: %s\n", curr_output_dir.c_str()); /* Load xform */ timer.start(); std::string xf_fn = string_format ("%s/%s", curr_output_dir.c_str(), "xf.txt"); lprintf ("Loading xform: %s\n", xf_fn.c_str()); Xform::Pointer xf = xform_load (xf_fn); d_ptr->time_io += timer.report(); /* Loop through structures for this atlas image */ std::set::const_iterator it; for (it = d_ptr->parms->structure_set.begin (); it != d_ptr->parms->structure_set.end (); it++) { const std::string& mapped_name = *it; lprintf ("Segmenting structure: %s\n", mapped_name.c_str()); /* Load original structure */ timer.start(); std::string atlas_struct_fn; atlas_struct_fn = string_format ("%s/structures/%s.nrrd", atlas_input_path.c_str(), mapped_name.c_str()); Plm_image::Pointer atlas_struct = plm_image_load_native (atlas_struct_fn); d_ptr->time_io += timer.report(); if (!atlas_struct) { lprintf ("Atlas %s doesn't have structure %s\n", atlas_id.c_str(), mapped_name.c_str()); continue; } /* Warp structure */ timer.start(); Plm_image::Pointer warped_structure = Plm_image::New(); Plm_image_header fixed_pih (d_ptr->ref_rtds->get_image()); lprintf ("Warping atlas structure.\n"); plm_warp (warped_structure, 0, xf, &fixed_pih, atlas_struct, 0, 0, 0); d_ptr->time_warp_str += timer.report(); /* Save warped structure */ std::string final_segmentation_img_fn = string_format ( "%s/%s_novoting.nrrd", label_output_dir.c_str(), mapped_name.c_str()); itk_image_save (warped_structure->itk_uchar(), final_segmentation_img_fn.c_str()); /* If required compute statistics */ std::string atl_name = basename (d_ptr->output_dir); std::string ref_stru_fn = string_format ("%s/%s/structures/%s.nrrd", d_ptr->preprocessed_dir.c_str(), atl_name.c_str(), mapped_name.c_str()); Plm_image::Pointer ref_stru = plm_image_load_native (ref_stru_fn); if (!ref_stru) { /* User is not running train, so no statistics */ continue; } /* Compute Dice, etc. */ std::string stats_string = d_ptr->stats.compute_statistics ( "segmentation", /* Not used yet */ ref_stru->itk_uchar(), warped_structure->itk_uchar()); std::string seg_log_string = string_format ( "target=%s,reg=%s,struct=%s," "%s\n", d_ptr->ref_id.c_str(), d_ptr->registration_id.c_str(), mapped_name.c_str(), stats_string.c_str()); lprintf ("%s", seg_log_string.c_str()); /* Update seg_dice file */ std::string seg_dice_log_fn = string_format ( "%s/seg_dice.csv", d_ptr->mabs_train_dir.c_str()); FILE *fp = fopen (seg_dice_log_fn.c_str(), "a"); fprintf (fp, "%s", seg_log_string.c_str()); fclose (fp); } } void Mabs::gaussian_segmentation_vote ( const std::string& atlas_id, const Mabs_seg_weights_list& seg_weights ) { Plm_timer timer; /* Set up files & directories for this job */ std::string atlas_input_path; atlas_input_path = string_format ("%s/%s", d_ptr->preprocessed_dir.c_str(), atlas_id.c_str()); lprintf ("atlas_input_path: %s\n", atlas_input_path.c_str()); std::string atlas_output_path; atlas_output_path = string_format ("%s/%s", d_ptr->output_dir.c_str(), atlas_id.c_str()); lprintf ("atlas_output_path: %s\n", atlas_output_path.c_str()); std::string curr_output_dir; curr_output_dir = string_format ("%s/%s", atlas_output_path.c_str(), d_ptr->registration_id.c_str()); lprintf ("curr_output_dir: %s\n", curr_output_dir.c_str()); /* Load xform */ timer.start(); std::string xf_fn = string_format ("%s/%s", curr_output_dir.c_str(), "xf.txt"); lprintf ("Loading xform: %s\n", xf_fn.c_str()); Xform::Pointer xf = xform_load (xf_fn); d_ptr->time_io += timer.report(); /* Load warped image */ timer.start(); std::string warped_image_fn; warped_image_fn = string_format ( "%s/img.nrrd", curr_output_dir.c_str()); Plm_image::Pointer warped_image = plm_image_load_native (warped_image_fn); d_ptr->time_io += timer.report(); if (!warped_image) { /* Load atlas image */ timer.start(); std::string atlas_image_fn; atlas_image_fn = string_format ("%s/img.nrrd", atlas_input_path.c_str()); lprintf ("That's ok. Loading atlas image instead: %s\n", atlas_image_fn.c_str()); Plm_image::Pointer atlas_image = plm_image_load_native (atlas_image_fn); d_ptr->time_io += timer.report(); /* Warp atlas image */ lprintf ("Warping atlas image.\n"); timer.start(); warped_image = Plm_image::New(); Plm_image_header fixed_pih (d_ptr->ref_rtds->get_image()); plm_warp (warped_image, 0, xf, &fixed_pih, atlas_image, 0, 0, 1); d_ptr->time_warp_img += timer.report(); /* Save warped image */ if (d_ptr->write_warped_images) { timer.start(); lprintf ("Saving warped atlas image: %s\n", warped_image_fn.c_str()); warped_image->save_image (warped_image_fn.c_str()); d_ptr->time_io += timer.report(); } } /* Loop through structures for this atlas image */ std::set::const_iterator it; for (it = d_ptr->parms->structure_set.begin (); it != d_ptr->parms->structure_set.end (); it++) { const std::string& mapped_name = *it; lprintf ("Segmenting structure: %s\n", mapped_name.c_str()); /* Make a new voter if needed */ Mabs_vote *vote; std::map::const_iterator vote_it = d_ptr->vote_map.find (mapped_name); if (vote_it == d_ptr->vote_map.end()) { /* Find fusion weights for this structure */ const Mabs_seg_weights* msw = seg_weights.find (mapped_name); /* Make the voter */ vote = new Mabs_vote; vote->set_rho (msw->rho); vote->set_sigma (msw->sigma); vote->set_minimum_similarity (msw->minsim); d_ptr->vote_map[mapped_name] = vote; vote->set_fixed_image ( d_ptr->ref_rtds->get_image()->itk_float()); } else { vote = vote_it->second; } /* Load dmap */ timer.start(); lprintf ("Loading dmap\n"); std::string dmap_fn = string_format ("%s/dmap_%s.nrrd", curr_output_dir.c_str(), mapped_name.c_str()); Plm_image::Pointer dmap_image = plm_image_load_native ( dmap_fn.c_str()); d_ptr->time_io += timer.report(); if (!dmap_image) { /* Load warped structure */ timer.start(); std::string warped_structure_fn = string_format ( "%s/structures/%s.nrrd", curr_output_dir.c_str(), mapped_name.c_str()); lprintf ("That's ok, loading warped structure instead: %s\n", warped_structure_fn.c_str()); Plm_image::Pointer warped_structure = plm_image_load_native ( warped_structure_fn); d_ptr->time_io += timer.report(); if (!warped_structure) { /* Load original structure */ timer.start(); std::string atlas_struct_fn; atlas_struct_fn = string_format ("%s/structures/%s.nrrd", atlas_input_path.c_str(), mapped_name.c_str()); lprintf ("That's ok, loading atlas structure instead: %s\n", atlas_struct_fn.c_str()); Plm_image::Pointer atlas_struct = plm_image_load_native (atlas_struct_fn); d_ptr->time_io += timer.report(); if (!atlas_struct) { lprintf ("Atlas %s doesn't have structure %s\n", atlas_id.c_str(), mapped_name.c_str()); continue; } /* Warp structure */ timer.start(); warped_structure = Plm_image::New(); Plm_image_header fixed_pih (d_ptr->ref_rtds->get_image()); lprintf ("Warping atlas structure.\n"); plm_warp (warped_structure, 0, xf, &fixed_pih, atlas_struct, 0, 0, 1); d_ptr->time_warp_str += timer.report(); } if (!warped_structure) continue; /* Recompute distance map */ timer.start(); FloatImageType::Pointer dmap_image_itk = this->compute_dmap ( warped_structure->itk_uchar(), curr_output_dir, mapped_name); dmap_image = Plm_image::New (dmap_image_itk); d_ptr->time_dmap += timer.report(); } /* Vote */ timer.start(); lprintf ("Voting\n"); vote->vote (warped_image->itk_float(), dmap_image->itk_float()); d_ptr->time_vote += timer.report(); } } void Mabs::staple_segmentation_prepare ( const std::string& atlas_id, const Mabs_seg_weights_list& seg_weights ) { Plm_timer timer; timer.start(); /* Set up files & directories for this job */ std::string atlas_input_path; atlas_input_path = string_format ("%s/%s", d_ptr->preprocessed_dir.c_str(), atlas_id.c_str()); lprintf ("atlas_input_path: %s\n", atlas_input_path.c_str()); std::string current_dir; current_dir = string_format ("%s/%s/%s", d_ptr->output_dir.c_str(), atlas_id.c_str(), d_ptr->registration_id.c_str()); /* Loop through structures for this atlas image */ std::set::const_iterator it; for (it = d_ptr->parms->structure_set.begin (); it != d_ptr->parms->structure_set.end (); it++) { const std::string& mapped_name = *it; std::string atlas_struct_fn; atlas_struct_fn = string_format ("%s/structures/%s.nrrd", atlas_input_path.c_str(), mapped_name.c_str()); Plm_image::Pointer atlas_struct = plm_image_load_native (atlas_struct_fn); if (!atlas_struct) { lprintf ("Atlas %s doesn't have structure %s\n", atlas_id.c_str(), mapped_name.c_str()); continue; } lprintf ("Preparing structure: %s (atl %s)\n", mapped_name.c_str(), atlas_id.c_str()); std::string warped_structure_fn = string_format ( "%s/structures/%s.nrrd", current_dir.c_str(), mapped_name.c_str()); Plm_image::Pointer warped_structure = plm_image_load_native (warped_structure_fn); /* Find fusion weights for this structure */ const Mabs_seg_weights* msw = seg_weights.find (mapped_name); if (warped_structure) { /* Make a new staple object if needed */ Mabs_staple *staple; std::map::const_iterator staple_it = d_ptr->staple_map.find (mapped_name); if (staple_it == d_ptr->staple_map.end()) { staple = new Mabs_staple; staple->set_confidence_weight(msw->confidence_weight); staple->add_input_structure (warped_structure); d_ptr->staple_map[mapped_name] = staple; } else { d_ptr->staple_map[mapped_name]->add_input_structure (warped_structure); } } } d_ptr->time_staple += timer.report(); } void Mabs::gaussian_segmentation_label ( const std::string& label_output_dir, const Mabs_seg_weights_list& seg_weights ) { Plm_timer timer; /* Get output image for each label */ lprintf ("Extracting and saving final contours (gaussian)\n"); std::map::const_iterator vote_it; for (vote_it = d_ptr->vote_map.begin(); vote_it != d_ptr->vote_map.end(); vote_it++) { const std::string& mapped_name = vote_it->first; Mabs_vote *vote = vote_it->second; lprintf ("Normalizing votes\n"); timer.start(); vote->normalize_votes(); d_ptr->time_vote += timer.report(); /* Get the weight image */ FloatImageType::Pointer weight_image; weight_image = vote->get_weight_image (); /* Optionally, save the weight files */ if (d_ptr->write_weight_files) { lprintf ("Saving weights\n"); std::string fn = string_format ("%s/weight_%s.nrrd", label_output_dir.c_str(), vote_it->first.c_str()); timer.start(); itk_image_save (weight_image, fn.c_str()); d_ptr->time_io += timer.report(); } /* Find fusion weights for this structure */ const Mabs_seg_weights* msw = seg_weights.find (mapped_name); msw->print (); /* threshold values */ Option_range thresh_range; thresh_range.set_range (msw->thresh); /* Loop through each threshold value, do thresholding, and then record score */ const std::list& thresh_list = thresh_range.get_range(); std::list::const_iterator thresh_it; for (thresh_it = thresh_list.begin(); thresh_it != thresh_list.end(); thresh_it++) { d_ptr->segmentation_threshold_weight ( label_output_dir, weight_image, mapped_name, vote_it->first.c_str(), msw, *thresh_it); } } } void Mabs::staple_segmentation_label ( const std::string& label_output_dir, const Mabs_seg_weights_list& seg_weights ) { Plm_timer timer; timer.start(); /* Set up files & directories for this job */ make_directory (label_output_dir); /* Get output image for each label */ lprintf ("Extracting and saving final contours (staple)\n"); for (std::map::const_iterator staple_it = d_ptr->staple_map.begin(); staple_it != d_ptr->staple_map.end(); staple_it++) { const std::string& mapped_name = staple_it->first; std::string atl_name = basename (d_ptr->output_dir); /* Find fusion weights for this structure */ const Mabs_seg_weights* msw = seg_weights.find (mapped_name); std::string ref_stru_fn = string_format ("%s/%s/structures/%s.nrrd", d_ptr->preprocessed_dir.c_str(), atl_name.c_str(), mapped_name.c_str()); std::string final_segmentation_img_fn = string_format ( "%s/%s_staple_%.9f.nrrd", label_output_dir.c_str(), mapped_name.c_str(), msw->confidence_weight); printf("Structure %s \n", final_segmentation_img_fn.c_str()); staple_it->second->run(); itk_image_save (staple_it->second->output_img->itk_uchar(), final_segmentation_img_fn.c_str()); Plm_image::Pointer ref_stru = plm_image_load_native (ref_stru_fn); if (!ref_stru) { /* User is not running train, so no statistics */ continue; } /* Compute Dice, etc. */ std::string stats_string = d_ptr->stats.compute_statistics ( "segmentation", /* Not used yet */ ref_stru->itk_uchar(), staple_it->second->output_img->itk_uchar()); std::string seg_log_string = string_format ( "target=%s,reg=%s,struct=%s," "confidence_weight=%.9f," "%s\n", d_ptr->ref_id.c_str(), d_ptr->registration_id.c_str(), mapped_name.c_str(), msw->confidence_weight, stats_string.c_str()); lprintf ("%s", seg_log_string.c_str()); /* Update seg_dice file */ std::string seg_dice_log_fn = string_format ( "%s/seg_dice.csv", d_ptr->mabs_train_dir.c_str()); FILE *fp = fopen (seg_dice_log_fn.c_str(), "a"); fprintf (fp, "%s", seg_log_string.c_str()); fclose (fp); } d_ptr->time_staple += timer.report(); } void Mabs::run_segmentation (const Mabs_seg_weights_list& seg_weights) { /* Just one atlas and no voting option selected */ if (d_ptr->parms->fusion_criteria == "none" && d_ptr->parms->atlases_from_ranking == 1) { std::string atlas_id = basename (*d_ptr->atlas_list.begin()); std::string label_output_dir = string_format ("%s/segmentations", d_ptr->output_dir.c_str()); no_voting (atlas_id, label_output_dir); return; } /* Clear out internal structures */ d_ptr->clear_vote_map (); d_ptr->clear_staple_map (); /* This function is only run on new examples, so no checkpointing is performed */ /* Loop through images in the atlas */ std::list::iterator atl_it; for (atl_it = d_ptr->atlas_list.begin(); atl_it != d_ptr->atlas_list.end(); atl_it++) { std::string atlas_id = basename (*atl_it); /* If gaussian is chosen (alone or with staple) run its code */ if (d_ptr->parms->fusion_criteria.find("gaussian") != std::string::npos) { gaussian_segmentation_vote (atlas_id, seg_weights); } /* If staple is chosen (alone or with gaussian) run its code */ if (d_ptr->parms->fusion_criteria.find("staple") != std::string::npos) { staple_segmentation_prepare (atlas_id, seg_weights); } } /* If gaussian is chosen (alone or with staple) run its code */ if (d_ptr->parms->fusion_criteria.find("gaussian") != std::string::npos) { /* Threshold images based on weight */ std::string label_output_dir = string_format ("%s/segmentations", d_ptr->output_dir.c_str()); gaussian_segmentation_label (label_output_dir, seg_weights); /* Clear out internal structure */ d_ptr->clear_vote_map (); } /* If staple is chosen (alone or with gaussian) run its code */ if (d_ptr->parms->fusion_criteria.find("staple") != std::string::npos) { /* Threshold images */ std::string label_output_dir = string_format ("%s/segmentations", d_ptr->output_dir.c_str()); staple_segmentation_label (label_output_dir, seg_weights); /* Clear out internal structure */ d_ptr->clear_staple_map (); } } void Mabs::run_segmentation_train (const Mabs_seg_weights& msw) { /* Just one atlas and no voting option selected */ if (d_ptr->parms->fusion_criteria == "none" && d_ptr->parms->atlases_from_ranking == 1) { std::string atlas_id = basename (*d_ptr->atlas_list.begin()); std::string label_output_dir = string_format ("%s/segmentations", d_ptr->output_dir.c_str()); no_voting(atlas_id, label_output_dir); return; } /* Clear out internal structures */ d_ptr->clear_vote_map (); d_ptr->clear_staple_map (); /* Check if this segmentation is already complete. We might be able to skip it. */ std::string gaussian_seg_checkpoint_fn = ""; std::string staple_seg_checkpoint_fn = ""; Mabs_seg_weights_list seg_weights; seg_weights.push_back (msw); /* Gaussian checkpoint */ if (d_ptr->parms->fusion_criteria.find("gaussian") != std::string::npos) { std::string curr_output_dir = string_format ( "%s/segmentations/%s/rho_%f_sig_%f_ms_%f", d_ptr->output_dir.c_str(), d_ptr->registration_id.c_str(), msw.rho, msw.sigma, msw.minsim); if (!this->check_seg_checkpoint(curr_output_dir)) { gaussian_seg_checkpoint_fn = string_format ("%s/checkpoint.txt", curr_output_dir.c_str()); } } /* Staple checkpoint */ if (d_ptr->parms->fusion_criteria.find("staple") != std::string::npos) { std::string curr_output_dir = string_format ( "%s/segmentations/%s/staple_confidence_weight_%.9f", d_ptr->output_dir.c_str(), d_ptr->registration_id.c_str(), msw.confidence_weight); if (!this->check_seg_checkpoint(curr_output_dir)) { staple_seg_checkpoint_fn = string_format ("%s/checkpoint.txt", curr_output_dir.c_str()); } } /* Loop through images in the atlas */ std::list::iterator atl_it; for (atl_it = d_ptr->atlas_list.begin(); atl_it != d_ptr->atlas_list.end(); atl_it++) { std::string atlas_id = basename (*atl_it); /* If gaussian is chosen (alone or with staple) and its segmentations aren't already present run its code */ if (d_ptr->parms->fusion_criteria.find("gaussian") != std::string::npos && gaussian_seg_checkpoint_fn != "") { gaussian_segmentation_vote (atlas_id, seg_weights); } /* If staple is chosen (alone or with gaussian) and its segmentations aren't already present run its code */ if (d_ptr->parms->fusion_criteria.find("staple") != std::string::npos && staple_seg_checkpoint_fn != "") { staple_segmentation_prepare (atlas_id, seg_weights); } } /* If gaussian is chosen (alone or with staple) and its segmentations aren't already present run its code */ if (d_ptr->parms->fusion_criteria.find("gaussian") != std::string::npos && gaussian_seg_checkpoint_fn != "") { /* Threshold images based on weight */ std::string label_output_dir = string_format ("%s/segmentations/%s/rho_%f_sig_%f_ms_%f", d_ptr->output_dir.c_str(), d_ptr->registration_id.c_str(), msw.rho, msw.sigma, msw.minsim); gaussian_segmentation_label (label_output_dir, seg_weights); /* Clear out internal structure */ d_ptr->clear_vote_map (); } /* If staple is chosen (alone or with gaussian) and its segmentations aren't already present run its code */ if (d_ptr->parms->fusion_criteria.find("staple") != std::string::npos && staple_seg_checkpoint_fn != "") { /* Threshold images */ std::string label_output_dir = string_format ("%s/segmentations/%s/staple_confidence_weight_%.9f", d_ptr->output_dir.c_str(), d_ptr->registration_id.c_str(), msw.confidence_weight); staple_segmentation_label (label_output_dir, seg_weights); /* Clear out internal structure */ d_ptr->clear_staple_map (); } /* Create checkpoint files which means that this segmentation is complete */ if (gaussian_seg_checkpoint_fn!="") touch_file (gaussian_seg_checkpoint_fn); if (staple_seg_checkpoint_fn!="") touch_file (staple_seg_checkpoint_fn); } void Mabs::run_segmentation_train_loop () { Option_range minsim_range, rho_range, sigma_range, confidence_weight_range; minsim_range.set_range (d_ptr->parms->minsim_values); rho_range.set_range (d_ptr->parms->rho_values); confidence_weight_range.set_range (d_ptr->parms->confidence_weight); sigma_range.set_range (d_ptr->parms->sigma_values); /* Loop through each registration parameter set */ std::list::iterator reg_it; for (reg_it = d_ptr->registration_list.begin(); reg_it != d_ptr->registration_list.end(); reg_it++) { d_ptr->registration_id = basename (*reg_it); Mabs_seg_weights_list mswl; mswl.push_back (Mabs_seg_weights()); Mabs_seg_weights& msw = mswl.front(); msw.thresh = d_ptr->parms->threshold_values; /* Loop through each training parameter: confidence_weight */ const std::list& confidence_weight_list = confidence_weight_range.get_range(); std::list::const_iterator confidence_weight_it; for (confidence_weight_it = confidence_weight_list.begin(); confidence_weight_it != confidence_weight_list.end(); confidence_weight_it++) { msw.confidence_weight = *confidence_weight_it; /* Loop through each training parameter: rho */ const std::list& rho_list = rho_range.get_range(); std::list::const_iterator rho_it; for (rho_it = rho_list.begin(); rho_it != rho_list.end(); rho_it++) { msw.rho = *rho_it; /* Loop through each training parameter: sigma */ const std::list& sigma_list = sigma_range.get_range(); std::list::const_iterator sigma_it; for (sigma_it = sigma_list.begin(); sigma_it != sigma_list.end(); sigma_it++) { msw.sigma = *sigma_it; /* Loop through each training parameter: minimum similarity */ const std::list& minsim_list = minsim_range.get_range(); std::list::const_iterator minsim_it; for (minsim_it = minsim_list.begin(); minsim_it != minsim_list.end(); minsim_it++) { msw.minsim = *minsim_it; run_segmentation (mswl); } } } } } } void Mabs::set_parms (const Mabs_parms *parms) { Plm_return_code rc; d_ptr->parms = parms; /* Set up directory strings */ d_ptr->segment_input_fn = d_ptr->parms->labeling_input_fn; d_ptr->segment_outdir_base = d_ptr->parms->labeling_output_fn; if (d_ptr->segment_outdir_base == "") { d_ptr->segment_outdir_base = "mabs"; } d_ptr->traindir_base = d_ptr->parms->training_dir; if (d_ptr->traindir_base == "") { d_ptr->traindir_base = "training"; } if (d_ptr->parms->convert_dir != "") { d_ptr->convert_dir = d_ptr->parms->convert_dir; } else { d_ptr->convert_dir = string_format ( "%s/convert", d_ptr->traindir_base.c_str()); } if (d_ptr->parms->convert_dir != "") { d_ptr->prealign_dir = d_ptr->parms->prealign_dir; } else { d_ptr->prealign_dir = string_format ( "%s/prealign", d_ptr->traindir_base.c_str()); } d_ptr->atlas_train_dir = string_format ( "%s/atlas-train", d_ptr->traindir_base.c_str()); d_ptr->mabs_train_dir = string_format ( "%s/mabs-train", d_ptr->traindir_base.c_str()); if (is_directory (d_ptr->prealign_dir)) { d_ptr->preprocessed_dir = d_ptr->prealign_dir; } else { d_ptr->preprocessed_dir = d_ptr->convert_dir; } std::string preprocessed_dir; /* Convert section */ d_ptr->convert_resample = false; rc = parse_float13 (d_ptr->convert_spacing, parms->convert_spacing); if (rc == PLM_SUCCESS) { d_ptr->convert_resample = true; } /* Prealgnment section */ d_ptr->prealign_resample = false; rc = parse_float13 (d_ptr->prealign_spacing, parms->prealign_spacing); if (rc == PLM_SUCCESS) { d_ptr->prealign_resample = true; } /* Training section */ d_ptr->stats.set_distance_map_algorithm (parms->distance_map_algorithm); /* Segmentation training */ d_ptr->write_distance_map_files = parms->write_distance_map_files; d_ptr->write_thresholded_files = parms->write_thresholded_files; d_ptr->write_weight_files = parms->write_weight_files; d_ptr->write_warped_images = parms->write_warped_images; } void Mabs::set_segment_input (const std::string& input_fn) { d_ptr->segment_input_fn = input_fn; } void Mabs::set_segment_output (const std::string& output_dir) { d_ptr->segment_outdir_base = output_dir; } void Mabs::set_segment_output_dicom (const std::string& output_dicom_dir) { /* Not yet implemented */ } void Mabs::set_prealign_roi_cmd_name (const std::string& input_roi_for_cog_prealignment_fn) { d_ptr->prealign_roi_cmd_name = input_roi_for_cog_prealignment_fn; } void Mabs::train_internal () { Plm_timer timer; Plm_timer timer_total; timer_total.start(); /* Open logfile */ std::string logfile_path = string_format ( "%s/%s", d_ptr->mabs_train_dir.c_str(), "logfile.txt"); logfile_open (logfile_path.c_str(), "a"); /* Prepare registration parameters */ if (d_ptr->train_segmentation && d_ptr->parms->optimization_result_reg != "") { /* We get the best registration result from an optimization file */ std::string registration_fn = string_format ("%s/%s", d_ptr->parms->registration_config.c_str(), d_ptr->parms->optimization_result_reg.c_str()); this->parse_registration_dir (registration_fn); lprintf ("Training based on optimized registration result: %s\n", registration_fn.c_str()); } else { /* Else, parse directory with registration files */ this->parse_registration_dir (d_ptr->parms->registration_config); } /* Parse atlas directory */ this->load_process_dir_list (d_ptr->preprocessed_dir); /* If set, run train atlas selection */ if (d_ptr->parms->enable_atlas_selection) { this->train_atlas_selection(); } /* Loop through atlas_dir, choosing reference images to segment */ for (std::list::iterator it = d_ptr->process_dir_list.begin(); it != d_ptr->process_dir_list.end(); it++) { /* Create atlas list for this test case */ std::string path = *it; d_ptr->atlas_list = d_ptr->process_dir_list; d_ptr->atlas_list.remove (path); /* Set output dir for this test case */ std::string patient_id = basename (path); d_ptr->ref_id = patient_id; d_ptr->output_dir = string_format ("%s/%s", d_ptr->mabs_train_dir.c_str(), patient_id.c_str()); lprintf ("outdir = %s\n", d_ptr->output_dir.c_str()); /* Load image & structures from "prep" directory */ timer.start(); std::string fn = string_format ("%s/%s/img.nrrd", d_ptr->preprocessed_dir.c_str(), patient_id.c_str()); d_ptr->ref_rtds->load_image (fn.c_str()); fn = string_format ("%s/%s/structures", d_ptr->preprocessed_dir.c_str(), patient_id.c_str()); d_ptr->ref_rtds->load_prefix (fn.c_str()); d_ptr->time_io += timer.report(); /* Use the atlases coming from the selection step */ if (!d_ptr->selected_atlases_train.empty()) { /* Extract from map structure only the atlases choosen for the current patient*/ std::list atlases_for_train_subject; std::list >::iterator atl_it; for (atl_it = d_ptr->selected_atlases_train[patient_id].begin(); atl_it != d_ptr->selected_atlases_train[patient_id].end(); atl_it++) { std::string complete_atlas_path = string_format("%s/%s", d_ptr->preprocessed_dir.c_str(), atl_it->first.c_str()); atlases_for_train_subject.push_back(complete_atlas_path); } /* Assign the selected atlases */ d_ptr->atlas_list = atlases_for_train_subject; } /* Run the segmentation */ this->run_registration_loop (); if (d_ptr->train_segmentation == true) { this->run_segmentation_train_loop (); } } lprintf ("Atlas selection time: %10.1f seconds\n", d_ptr->time_atlas_selection); lprintf ("Registration time: %10.1f seconds\n", d_ptr->time_reg); lprintf ("Warping time (img): %10.1f seconds\n", d_ptr->time_warp_img); lprintf ("Warping time (str): %10.1f seconds\n", d_ptr->time_warp_str); lprintf ("Extraction time: %10.1f seconds\n", d_ptr->time_extract); lprintf ("Dice time: %10.1f seconds\n", d_ptr->stats.get_time_dice()); lprintf ("Hausdorff time: %10.1f seconds\n", d_ptr->stats.get_time_hausdorff()); lprintf ("Distance map time: %10.1f seconds\n", d_ptr->time_dmap); lprintf ("Voting time: %10.1f seconds\n", d_ptr->time_vote); lprintf ("Staple time: %10.1f seconds\n", d_ptr->time_staple); lprintf ("I/O time: %10.1f seconds\n", d_ptr->time_io); lprintf ("Total time: %10.1f seconds\n", timer_total.report()); lprintf ("MABS training complete\n"); logfile_close (); } void Mabs::segment () { /* Yeah, I guess this is fine. */ d_ptr->write_dicom_rt_struct = true; /* Prepare registration parameters */ if (d_ptr->parms->optimization_result_reg != "") { /* We know the best registration result from an optimization file */ std::string registration_fn = string_format ("%s/%s", d_ptr->parms->registration_config.c_str(), d_ptr->parms->optimization_result_reg.c_str()); this->parse_registration_dir (registration_fn); } else { /* Else, parse directory with registration files */ this->parse_registration_dir (d_ptr->parms->registration_config); } /* Load the image to be labeled. For now, we'll assume this is successful. */ d_ptr->ref_rtds->load (d_ptr->segment_input_fn.c_str()); /* GCS TBD: For now, we delete any existing structures. This avoids (pushes into the future) any additional development needed to update existing structure sets. */ if (d_ptr->ref_rtds->have_segmentation()) { d_ptr->ref_rtds->get_segmentation()->clear (); } /* Parse atlas directory */ this->load_process_dir_list (d_ptr->preprocessed_dir); /* Set atlas_list */ d_ptr->atlas_list = d_ptr->process_dir_list; /* If set, run atlas selection */ if (d_ptr->parms->enable_atlas_selection) { this->atlas_selection(); /* Use the atlases coming from the selection step */ if (!d_ptr->selected_atlases.empty()) { /* Extract from map structure only the atlases choosen for the current patient*/ std::list atlases_for_subject; std::list >::iterator atl_it; for (atl_it = d_ptr->selected_atlases.begin(); atl_it != d_ptr->selected_atlases.end(); atl_it++) { std::string complete_atlas_path = string_format("%s/%s", d_ptr->preprocessed_dir.c_str(), atl_it->first.c_str()); atlases_for_subject.push_back(complete_atlas_path); } /* Assign the selected atlases */ d_ptr->atlas_list = atlases_for_subject; } else { print_and_exit ("Atlas selection not working properly!\n"); } } /* Set output dir for this test case */ d_ptr->output_dir = d_ptr->segment_outdir_base; /* Save it for debugging */ std::string fn = string_format ("%s/%s", d_ptr->segment_outdir_base.c_str(), "img.nrrd"); d_ptr->ref_rtds->get_image()->save_image (fn.c_str()); /* Run the registrations */ d_ptr->write_warped_images = true; /* PAOLO ZAFFINO: if an input ROI has been passed, prealign the centers of gravity before registration */ if (d_ptr->prealign_roi_cmd_name != "" ) { d_ptr->input_roi_for_cog_prealignment = Plm_image::New (d_ptr->prealign_roi_cmd_name); } this->run_registration_loop (); /* Run the segmentation */ /* GCS FIX: 1) registration_id must be set to something sane when optimization results are not available 2) need better default values for rho, etc. 3) need to read optimized values of rho, etc. */ if (d_ptr->parms->optimization_result_reg != "") { d_ptr->registration_id = d_ptr->parms->optimization_result_reg; } else { if (d_ptr->registration_list.empty()) { /* No registration file. Punt. */ print_and_exit ("Error, could not find registration file.\n"); } d_ptr->registration_id = basename ( d_ptr->registration_list.front()); } run_segmentation (d_ptr->parms->optimization_result_seg); /* Save the output */ std::string dicomrt_output_dir = string_format ( "%s/dicom_rt", d_ptr->output_dir.c_str()); d_ptr->ref_rtds->save_dicom (dicomrt_output_dir); } void Mabs::train () { d_ptr->train_segmentation = true; d_ptr->compute_distance_map = true; d_ptr->write_warped_images = true; /* Should be configurable */ this->train_internal (); } void Mabs::train_registration () { d_ptr->train_segmentation = false; d_ptr->compute_distance_map = d_ptr->write_distance_map_files; this->train_internal (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/mabs.h000066400000000000000000000050451321604176500273600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _mabs_h_ #define _mabs_h_ #include "plmsegment_config.h" #include #include "itk_image.h" class Mabs_private; class Mabs_parms; class Mabs_seg_weights; class Mabs_seg_weights_list; class PLMSEGMENT_API Mabs { public: Mabs (); ~Mabs (); public: Mabs_private *d_ptr; protected: bool check_seg_checkpoint (std::string folder); void load_process_dir_list (const std::string& dir); void convert (const std::string& input_dir, const std::string& output_dir); void prealign (const std::string& input_dir, const std::string& output_dir); FloatImageType::Pointer compute_dmap ( UCharImageType::Pointer& structure_image, const std::string& curr_output_dir, const std::string& mapped_name); void run_registration_loop (); void run_single_registration (); void run_segmentation (const Mabs_seg_weights_list& seg_weights); void run_segmentation_train (const Mabs_seg_weights& seg_weights); void run_segmentation_train_loop (); void no_voting ( const std::string& atlas_id, const std::string& label_output_dir); void gaussian_segmentation_vote ( const std::string& atlas_id, const Mabs_seg_weights_list& seg_weights ); void gaussian_segmentation_label ( const std::string& label_output_dir, const Mabs_seg_weights_list& seg_weights ); void staple_segmentation_prepare ( const std::string& atlas_id, const Mabs_seg_weights_list& seg_weights ); void staple_segmentation_label ( const std::string& label_output_dir, const Mabs_seg_weights_list& seg_weights ); void train_internal (); public: void set_parms (const Mabs_parms *parms); void parse_registration_dir (const std::string& registration_config); void set_executed_command (const std::string& executed_command); void set_segment_input (const std::string& input_fn); void set_segment_output (const std::string& output_dir); void set_segment_output_dicom (const std::string& output_dicom_dir); void set_prealign_roi_cmd_name (const std::string& input_roi_fn); void atlas_selection (); void train_atlas_selection (); void atlas_convert (); void atlas_prealign (); void train_registration (); void train (); void segment (); }; #endif mabs_atlas_selection.cxx000066400000000000000000000470341321604176500331110ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include #include #include "itkImage.h" #include "itkImageFileReader.h" #include #include #include #include "itkLinearInterpolateImageFunction.h" #include "dir_list.h" #include "logfile.h" #include "mabs.h" #include "mabs_atlas_selection.h" #include "path_util.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_warp.h" #include "print_and_exit.h" #include "string_util.h" #include "registration.h" #include "registration_parms.h" #include "registration_data.h" #include "rt_study.h" #include "xform.h" /* Utility function to compare similarity value in the list of atlases */ bool compare_similarity_value_from_pairs( const std::pair& first_atlas, const std::pair& second_atlas) { return (first_atlas.second >= second_atlas.second); } Mabs_atlas_selection::Mabs_atlas_selection () { /* constructor */ this->subject_id = ""; this->atlas_selection_criteria = "nmi"; this->selection_reg_parms_fn = ""; this->atlas_dir = ""; this->similarity_percent_threshold = 0.40; this->atlases_from_ranking = -1; this->number_of_atlases = -1; this->hist_bins = 100; this->percentage_nmi_random_sample = -1; this->min_hist_sub_value_defined = false; this->min_hist_sub_value=0; this->max_hist_sub_value_defined = false; this->max_hist_sub_value=0; this->min_hist_atl_value_defined = false; this->min_hist_atl_value=0; this->max_hist_atl_value_defined = false; this->max_hist_atl_value=0; this->max_random_atlases = 14; this->min_random_atlases = 6; this->precomputed_ranking_fn = ""; } Mabs_atlas_selection::~Mabs_atlas_selection () { /* destructor */ } void Mabs_atlas_selection::run_selection() { if (this->atlas_selection_criteria == "nmi" || this->atlas_selection_criteria == "nmi-post" || this->atlas_selection_criteria == "nmi-ratio" || this->atlas_selection_criteria == "mse" || this->atlas_selection_criteria == "mse-post" || this->atlas_selection_criteria == "mse-ratio") { this->similarity_ranking(); } else if (this->atlas_selection_criteria == "random") { this->random_ranking (); } else if (this->atlas_selection_criteria == "precomputed") { this->precomputed_ranking (); } } void Mabs_atlas_selection::similarity_ranking() { lprintf("SIMILARITY RANKING \n"); printf ("Number of initial atlases = %d \n", this->number_of_atlases); /* Loop through images in the atlas and compute similarity value */ std::list > atlas_and_similarity; std::list::iterator atl_it; int i; for (atl_it = this->atlas_dir_list.begin(), i=0; atl_it != this->atlas_dir_list.end(); atl_it++, i++) { Rt_study* rtds_atl= new Rt_study; std::string path_atl = *atl_it; std::string atlas_id = basename (path_atl); std::string atlas_input_path = string_format ("%s/prealign/%s", this->atlas_dir.c_str(), atlas_id.c_str()); std::string fn = string_format ("%s/img.nrrd", atlas_input_path.c_str()); rtds_atl->load_image (fn.c_str()); this->atlas = rtds_atl->get_image(); /* Subject compared with atlas, not subject vs itself */ if (this->subject_id.compare(atlas_id)) { lprintf("Similarity values %s - %s \n", this->subject_id.c_str(), atlas_id.c_str()); /* Compute similarity value */ atlas_and_similarity.push_back( std::make_pair(basename(atlas_id), this->compute_general_similarity_value())); } delete rtds_atl; } /* Sort atlases in basis of the similarity value */ atlas_and_similarity.sort(compare_similarity_value_from_pairs); /* Copy ranked atlases (not selected) */ this->ranked_atlases.assign(atlas_and_similarity.begin(), atlas_and_similarity.end()); /* Find min and max similarity value */ double min_similarity_value = atlas_and_similarity.back().second; double max_similarity_value = atlas_and_similarity.front().second; printf("Minimum similarity value = %g \n", min_similarity_value); printf("Maximum similarity value = %g \n", max_similarity_value); /* Create items to select the atlases */ std::list > most_similar_atlases; std::list >::iterator reg_it; printf("List of the selected atlases for subject %s: \n", this->subject_id.c_str()); /* Find atlas to include in the registration - THRESHOLD - */ if (this->atlases_from_ranking == -1) { for(reg_it = atlas_and_similarity.begin(); reg_it != atlas_and_similarity.end(); reg_it++) { /* Similarity value greater than the threshold, take the atlas */ if (reg_it->second >= (((max_similarity_value-min_similarity_value) * this->similarity_percent_threshold) + min_similarity_value)) { most_similar_atlases.push_back(*reg_it); printf("Atlas %s having similarity value = %f \n", reg_it->first.c_str(), reg_it->second); } /* The list is sorted, all the next atlases have a similarity value lower than the threshold * exit from the cycle * */ else break; } } /* Find atlas to include in the registration - TOP - */ if (this->atlases_from_ranking != -1) { /* Check if atlases_from_ranking is greater than number_of_atlases */ if (this->atlases_from_ranking >= this->number_of_atlases) print_and_exit("Atlases_from_ranking is greater than number of atlases\n"); reg_it = atlas_and_similarity.begin(); printf("Atlas to select = %d \n", this->atlases_from_ranking); for (int i = 1; ((i <= this->atlases_from_ranking) && (i <= (int) atlas_and_similarity.size())); reg_it++, i++) { printf("Atlas %s (# %d) having similarity value = %f \n", reg_it->first.c_str(), i, reg_it->second); most_similar_atlases.push_back(*reg_it); } } /* Prepare to exit from function */ printf("Number of selected atlases = %d \n", (int) most_similar_atlases.size()); this->selected_atlases = most_similar_atlases; } double Mabs_atlas_selection::compute_general_similarity_value() { double score = 0; /* metric: NMI */ if (this->atlas_selection_criteria == "nmi") { score = this->compute_nmi(this->subject, this->atlas); lprintf("NMI value = %g \n", score); } /* metric: MSE */ else if (this->atlas_selection_criteria == "mse") { score = this->compute_mse(this->subject, this->atlas); lprintf("MSE value = %g \n", score); } /* metrics: NMI POST & MSE POST */ else if (this->atlas_selection_criteria == "nmi-post" || this->atlas_selection_criteria == "mse-post") { score = this->compute_similarity_value_post(); } /* metrics: NMI RATIO & MSE RATIO */ else if (this->atlas_selection_criteria == "nmi-ratio" || this->atlas_selection_criteria == "mse-ratio") { score = this->compute_similarity_value_ratio(); } return score; } double Mabs_atlas_selection::compute_similarity_value_post() { Registration reg; Registration_parms::Pointer regp = reg.get_registration_parms (); Registration_data::Pointer regd = reg.get_registration_data (); reg.set_command_file (this->selection_reg_parms_fn); reg.set_fixed_image (this->subject); reg.set_moving_image (this->atlas); Xform::Pointer xf = reg.do_registration_pure (); Plm_image::Pointer deformed_atlas = Plm_image::New (); Plm_image_header fixed_pih (this->subject); plm_warp (deformed_atlas, 0, xf, &fixed_pih, this->atlas, regp->default_value, 0, 1); double similarity_value_post = 0; if (this->atlas_selection_criteria == "nmi-post") { similarity_value_post = this->compute_nmi (this->subject, deformed_atlas); lprintf("NMI post = %g \n", similarity_value_post); } else if (this->atlas_selection_criteria == "mse-post") { similarity_value_post = this->compute_mse (this->subject, deformed_atlas); lprintf("MSE post = %g \n", similarity_value_post); } return similarity_value_post; } double Mabs_atlas_selection::compute_similarity_value_ratio() { double similarity_value_pre = 0; if (this->atlas_selection_criteria == "nmi-ratio") similarity_value_pre = this->compute_nmi(this->subject, this->atlas); else if (this->atlas_selection_criteria == "mse-ratio") similarity_value_pre = this->compute_mse(this->subject, this->atlas); lprintf("Similarity value pre = %g \n", similarity_value_pre); Registration reg; Registration_parms::Pointer regp = reg.get_registration_parms (); Registration_data::Pointer regd = reg.get_registration_data (); reg.set_command_file (this->selection_reg_parms_fn); reg.set_fixed_image (this->subject); reg.set_moving_image (this->atlas); Xform::Pointer xf = reg.do_registration_pure (); Plm_image::Pointer deformed_atlas = Plm_image::New (); Plm_image_header fixed_pih (this->subject); plm_warp (deformed_atlas, 0, xf, &fixed_pih, this->atlas, regp->default_value, 0, 1); double similarity_value_post = 0; if (this->atlas_selection_criteria == "nmi-ratio") similarity_value_post = this->compute_nmi (this->subject, deformed_atlas); else if (this->atlas_selection_criteria == "mse-ratio") similarity_value_post = this->compute_mse (this->subject, deformed_atlas); lprintf("Similarity value post = %g \n", similarity_value_post); return ((similarity_value_post/similarity_value_pre)-1) * similarity_value_post; } double Mabs_atlas_selection::compute_nmi ( const Plm_image::Pointer& img1, /* Subject */ const Plm_image::Pointer& img2) /* Atlas */ { /* Cost function */ typedef float PixelComponentType; const unsigned int Dimension = 3; typedef itk::Image< PixelComponentType, Dimension > ImageType; typedef itk::NormalizedMutualInformationHistogramImageToImageMetric NmiMetricType; NmiMetricType::Pointer nmi_metric = NmiMetricType::New(); /* Identity transformation */ typedef itk::TranslationTransform< double, Dimension > TranslationTransformType; typedef TranslationTransformType::Pointer TranslationTransformPointer; TranslationTransformPointer transform = TranslationTransformType::New(); transform->SetIdentity(); /* Linear Interpolator */ typedef itk::LinearInterpolateImageFunction< ImageType, double > InterpolatorType; InterpolatorType::Pointer interpolator = InterpolatorType::New(); /* Set mask if defined */ if (this->mask) { nmi_metric->SetFixedImageMask(this->mask); } /* Set number of random sample if defined */ if (this->percentage_nmi_random_sample != -1) { /* User set this value */ if (this->percentage_nmi_random_sample <= 0 || this->percentage_nmi_random_sample > 1) { /* The set value is not in the range */ printf("Percentage nmi random sample not set properly. " "User setting will be ignored and the default value will be used\n"); } else { /* The set value is in the range, apply it */ unsigned long number_of_img_voxels = img1->itk_short()->GetLargestPossibleRegion().GetNumberOfPixels(); unsigned long number_spatial_samples = static_cast (number_of_img_voxels * this->percentage_nmi_random_sample); #if defined (ITK_USE_OPTIMIZED_REGISTRATION_METHODS) || (ITK_VERSION_MAJOR >= 4) nmi_metric->SetNumberOfSpatialSamples(number_spatial_samples); #endif } } /* Set histogram interval if defined */ if (this->min_hist_sub_value_defined && this->min_hist_atl_value_defined) { NmiMetricType::MeasurementVectorType lower_bounds; #if ITK_VERSION_MAJOR >= 4 lower_bounds.SetSize(2); #endif lower_bounds.SetElement(0, this->min_hist_sub_value); lower_bounds.SetElement(1, this->min_hist_atl_value); nmi_metric->SetLowerBound(lower_bounds); } if (this->max_hist_sub_value_defined && this->max_hist_atl_value_defined) { NmiMetricType::MeasurementVectorType upper_bounds; #if ITK_VERSION_MAJOR >= 4 upper_bounds.SetSize(2); #endif upper_bounds.SetElement(0, this->max_hist_sub_value); upper_bounds.SetElement(1, this->max_hist_atl_value); nmi_metric->SetUpperBound(upper_bounds); } /* Metric settings */ unsigned int numberOfHistogramBins = this->hist_bins; NmiMetricType::HistogramType::SizeType histogramSize; #if ITK_VERSION_MAJOR >= 4 histogramSize.SetSize(2); #endif histogramSize.Fill(numberOfHistogramBins); nmi_metric->SetHistogramSize(histogramSize); nmi_metric->SetFixedImage(img1->itk_float()); nmi_metric->SetMovingImage(img2->itk_float()); nmi_metric->SetFixedImageRegion(img1->itk_float()->GetLargestPossibleRegion()); nmi_metric->SetTransform(transform); nmi_metric->SetInterpolator(interpolator); nmi_metric->Initialize(); /* NMI compute */ return (double) nmi_metric->GetValue(transform->GetParameters()); } double Mabs_atlas_selection::compute_mse ( const Plm_image::Pointer& img1, /* Subject */ const Plm_image::Pointer& img2) /* Atlas */ { /* Cost function */ typedef float PixelComponentType; const unsigned int Dimension = 3; typedef itk::Image< PixelComponentType, Dimension > ImageType; typedef itk::MeanSquaresImageToImageMetric MseMetricType; MseMetricType::Pointer mse_metric = MseMetricType::New(); /* Identity transformation */ typedef itk::TranslationTransform< double, Dimension > TranslationTransformType; typedef TranslationTransformType::Pointer TranslationTransformPointer; TranslationTransformPointer transform = TranslationTransformType::New(); transform->SetIdentity(); /* Linear Interpolator */ typedef itk::LinearInterpolateImageFunction< ImageType, double > InterpolatorType; InterpolatorType::Pointer interpolator = InterpolatorType::New(); /* Set mask if defined */ if (this->mask) { mse_metric->SetFixedImageMask(this->mask); } /* Metric settings */ mse_metric->SetFixedImage(img1->itk_float()); mse_metric->SetMovingImage(img2->itk_float()); mse_metric->SetFixedImageRegion(img1->itk_float()->GetLargestPossibleRegion()); mse_metric->SetTransform(transform); mse_metric->SetInterpolator(interpolator); mse_metric->Initialize(); /* MSE compute */ return (double) mse_metric->GetValue(transform->GetParameters()); } void Mabs_atlas_selection::random_ranking() { lprintf("RANDOM RANKING \n"); std::list random_atlases; /* Check if atlases_from_ranking is greater than number_of_atlases */ if (this->min_random_atlases < 1 || (this->max_random_atlases + 1) > this->number_of_atlases) print_and_exit("Bounds for random selection are not correct\n"); int random_number_of_atlases = rand() % (this->max_random_atlases + 1 - this->min_random_atlases) + this->min_random_atlases; printf("Selected %d random atlases for the subject %s \n", random_number_of_atlases, this->subject_id.c_str()); /* Select the random atlases */ int i=0; while ((int) random_atlases.size() < random_number_of_atlases) { /* Choose a random atlas */ int random_index = rand() % (this->number_of_atlases); std::list::iterator atlases_iterator = this->atlas_dir_list.begin(); std::advance (atlases_iterator, random_index); /* Check if the random atlas has been already included and if it is different from the subject */ if (find(random_atlases.begin(), random_atlases.end(), basename(*atlases_iterator)) == random_atlases.end() && basename(*atlases_iterator) != this->subject_id) { i++; std::string atlas = basename(*atlases_iterator); printf("Atlas number %d is %s \n", i, atlas.c_str()); random_atlases.push_back(atlas); } } /* Fill this->selected_atlas */ std::list::iterator atl_it; for (atl_it = random_atlases.begin(); atl_it != random_atlases.end(); atl_it++) { this->selected_atlases.push_back(std::make_pair(*atl_it, 0.0)); } } void Mabs_atlas_selection::precomputed_ranking() { /* Check if atlases_from_ranking is greater than number_of_atlases */ if (this->atlases_from_ranking >= this->number_of_atlases) print_and_exit("Atlases_from_ranking is greater than number of atlases\n"); /* Open the file where the precomputed ranking is stored */ std::ifstream ranking_file (this->precomputed_ranking_fn.c_str()); std::string atlases_line; printf("Atlases to select = %d \n", this->atlases_from_ranking); /* Read line by line*/ while(std::getline(ranking_file, atlases_line)) { std::istringstream atlases_line_stream (atlases_line); std::string item; /* item_index is equal to 0 for the first element in the line (the subject id) and * greater than 0 for the atlases */ int item_index = -1; /* Split a line using the spaces */ while(std::getline(atlases_line_stream, item, ' ')) { /* If defined select the first n atlases from the ranking */ if (this->atlases_from_ranking != -1 && (int) this->selected_atlases.size() >= this->atlases_from_ranking) { break; } item_index++; /* Delete space, colon and equal signs from single item name */ char chars_to_remove [] = " :="; for (unsigned int i = 0; i < strlen(chars_to_remove); i++) { item.erase(std::remove(item.begin(), item.end(), chars_to_remove[i]), item.end()); } /* First element in the line is the subject */ if (item_index == 0) { /* This row doesn't contain data regarding the current subject, jump it */ if (item != this->subject_id) break; /* This row contains the data regarding the current subject, * jump just the subject id */ else if (item == this->subject_id) { printf("Subject = %s \n", item.c_str()); continue; } } /* After the first element there are the selected atlases */ else { this->selected_atlases.push_back(std::make_pair(item, 0.0)); printf(" Selected atlas %s \n", item.c_str()); } } } /* Close log file */ ranking_file.close(); } mabs_atlas_selection.h000066400000000000000000000043021321604176500325250ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _mabs_atlas_selection_h_ #define _mabs_atlas_selection_h_ #include "plmsegment_config.h" #include #include #include #include "itkImageMaskSpatialObject.h" #include "plm_image.h" typedef itk::ImageMaskSpatialObject<3> MaskType; typedef MaskType::Pointer MaskTypePointer; class PLMSEGMENT_API Mabs_atlas_selection { public: Mabs_atlas_selection(); ~Mabs_atlas_selection(); void run_selection(); void similarity_ranking(); double compute_general_similarity_value(); double compute_similarity_value_ratio(); double compute_similarity_value_post(); double compute_nmi ( const Plm_image::Pointer& img1, const Plm_image::Pointer& img2); double compute_mse ( const Plm_image::Pointer& img1, const Plm_image::Pointer& img2); void random_ranking(); void precomputed_ranking(); public: Plm_image::Pointer subject; std::string subject_id; std::list atlas_dir_list; std::string atlas_selection_criteria; std::string selection_reg_parms_fn; std::string atlas_dir; float similarity_percent_threshold; int atlases_from_ranking; // -1 if this parameter is not defined int number_of_atlases; Plm_image::Pointer atlas; int hist_bins; float percentage_nmi_random_sample; // -1 if this parameter is not defined MaskTypePointer mask; bool min_hist_sub_value_defined; int min_hist_sub_value; bool max_hist_sub_value_defined; int max_hist_sub_value; bool min_hist_atl_value_defined; int min_hist_atl_value; bool max_hist_atl_value_defined; int max_hist_atl_value; int max_random_atlases; int min_random_atlases; std::string precomputed_ranking_fn; std::list > ranked_atlases; // all the atlases, only ranked std::list > selected_atlases; // selected_atlases, subset of ranked_atlases }; #endif /* #ifndef _mabs_atlases_selection_h_ */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/mabs_parms.cxx000066400000000000000000000363061321604176500311410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include #include #include #include #include #include "file_util.h" #include "parameter_parser.h" #include "mabs_parms.h" #include "plm_math.h" #include "print_and_exit.h" #include "string_util.h" class Mabs_parms_parser : public Parameter_parser { public: Mabs_parms *mp; Mabs_seg_weights ors; public: Mabs_parms_parser (Mabs_parms *mp) { this->mp = mp; } public: virtual Plm_return_code begin_section ( const std::string& section) { if (section == "CONVERT") { this->enable_key_regularization (true); this->allow_empty_values (false); return PLM_SUCCESS; } if (section == "PREALIGN" || section == "PREALIGNMENT") { this->enable_key_regularization (true); this->allow_empty_values (false); return PLM_SUCCESS; } if (section == "ATLAS-SELECTION") { this->enable_key_regularization (true); this->allow_empty_values (false); return PLM_SUCCESS; } if (section == "TRAINING") { this->enable_key_regularization (true); this->allow_empty_values (false); return PLM_SUCCESS; } if (section == "REGISTRATION") { this->enable_key_regularization (true); this->allow_empty_values (false); return PLM_SUCCESS; } if (section == "STRUCTURES") { this->enable_key_regularization (false); this->allow_empty_values (true); return PLM_SUCCESS; } if (section == "LABELING") { this->enable_key_regularization (true); this->allow_empty_values (false); return PLM_SUCCESS; } if (section == "OPTIMIZATION-RESULT-REG") { this->enable_key_regularization (true); this->allow_empty_values (false); return PLM_SUCCESS; } if (section == "OPTIMIZATION-RESULT-SEG") { ors.factory_reset (); this->enable_key_regularization (true); this->allow_empty_values (false); return PLM_SUCCESS; } /* else, unknown section */ return PLM_ERROR; } virtual Plm_return_code end_section ( const std::string& section) { if (section == "OPTIMIZATION-RESULT-SEG") { this->mp->optimization_result_seg.push_back (ors); } return PLM_SUCCESS; } virtual Plm_return_code set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val); }; Plm_return_code Mabs_parms_parser::set_key_value ( const std::string& section, const std::string& key, const std::string& index, const std::string& val) { /* [CONVERT] */ if (section == "CONVERT") { if (key == "spacing") { mp->convert_spacing = val; } else { goto error_exit; } } /* [PREALIGNMENT] */ if (section == "PREALIGN" || section == "PREALIGNMENT") { if (key == "mode") { if (val == "DISABLED" || val == "disabled" || val == "Disabled" || val == "0") { mp->prealign_mode = "disabled"; } else if (val == "DEFAULT" || val == "default" || val == "Default") { mp->prealign_mode = "default"; } else if (val == "CUSTOM" || val == "custom" || val == "Custom") { mp->prealign_mode = "custom"; } } else if (key == "reference") { mp->prealign_reference = val; } else if (key == "spacing") { mp->prealign_spacing = val; } else if (key == "registration_config") { mp->prealign_registration_config = val; } else if (key == "prealign_struct") { mp->prealign_roi_cfg_name = val; } else { goto error_exit; } } /* [ATLAS-SELECTION] */ if (section == "ATLAS-SELECTION") { if (key == "enable_atlas_selection") { if (val == "True" || val == "true" || val == "1") { mp->enable_atlas_selection = true; } else { mp->enable_atlas_selection = false; } } else if (key == "atlas_selection_criteria") { if (val == "nmi" || val == "NMI") { mp->atlas_selection_criteria="nmi"; } else if (val == "nmi-post" || val == "NMI-POST") { mp->atlas_selection_criteria="nmi-post"; } else if (val == "nmi-ratio" || val == "NMI-RATIO") { mp->atlas_selection_criteria="nmi-ratio"; } else if (val == "mse" || val == "MSE") { mp->atlas_selection_criteria="mse"; } else if (val == "mse-post" || val == "MSE-POST") { mp->atlas_selection_criteria="mse-post"; } else if (val == "mse-ratio" || val == "MSE-RATIO") { mp->atlas_selection_criteria="mse-ratio"; } else if (val == "random" || val == "RANDOM") { mp->atlas_selection_criteria="random"; } else if (val == "precomputed" || val == "PRECOMPUTED") { mp->atlas_selection_criteria="precomputed"; } } else if (key == "similarity_percent_threshold") { sscanf (val.c_str(), "%g", &mp->similarity_percent_threshold); } else if (key == "atlases_from_ranking") { sscanf (val.c_str(), "%d", &mp->atlases_from_ranking); } else if (key == "mi_histogram_bins") { sscanf (val.c_str(), "%d", &mp->mi_histogram_bins); } else if (key == "percentage_nmi_random_sample") { sscanf (val.c_str(), "%g", &mp->percentage_nmi_random_sample); } else if (key == "roi_mask_fn" || key == "roi_mask") { mp->roi_mask_fn = val; } else if (key == "selection_reg_parms") { mp->selection_reg_parms_fn = val; } else if (key == "lower_mi_value_subject") { sscanf (val.c_str(), "%d", &mp->lower_mi_value_sub); mp->lower_mi_value_sub_defined = true; } else if (key == "upper_mi_value_subject") { sscanf (val.c_str(), "%d", &mp->upper_mi_value_sub); mp->upper_mi_value_sub_defined = true; } else if (key == "lower_mi_value_atlas") { sscanf (val.c_str(), "%d", &mp->lower_mi_value_atl); mp->lower_mi_value_atl_defined = true; } else if (key == "upper_mi_value_atlas") { sscanf (val.c_str(), "%d", &mp->upper_mi_value_atl); mp->upper_mi_value_atl_defined = true; } else if (key == "min_random_atlases") { sscanf (val.c_str(), "%d", &mp->min_random_atlases); } else if (key == "max_random_atlases") { sscanf (val.c_str(), "%d", &mp->max_random_atlases); } else if (key == "precomputed_ranking") { mp->precomputed_ranking_fn = val; } else { goto error_exit; } } /* [TRAINING] */ if (section == "TRAINING") { if (key == "atlas_dir") { mp->atlas_dir = val; } else if (key == "training_dir") { mp->training_dir = val; } else if (key == "convert_dir") { mp->convert_dir = val; } else if (key == "prealign_dir") { mp->prealign_dir = val; } else if (key == "fusion_criteria") { if (val == "gaussian" || val == "GAUSSIAN" || val == "Gaussian") { mp->fusion_criteria = "gaussian"; } else if (val == "staple" || val == "STAPLE" || val == "Staple") { mp->fusion_criteria = "staple"; } else if (val == "gaussian,staple" || val == "GAUSSIAN,STAPLE" || val == "Gaussian,Staple" || val == "staple,gaussian" || val == "STAPLE,GAUSSIAN" || val == "Staple,Gaussian") { mp->fusion_criteria = "gaussian_and_staple"; } else if (val == "none" || val == "NONE" || val == "None") { mp->fusion_criteria = "none"; } } else if (key == "distance_map_algorithm") { mp->distance_map_algorithm = val; } else if (key == "minimum_similarity") { mp->minsim_values = val; } else if (key == "rho_values") { mp->rho_values = val; } else if (key == "sigma_values") { mp->sigma_values = val; } else if (key == "threshold_values") { mp->threshold_values = val; } else if (key == "confidence_weight") { mp->confidence_weight = val; } else if (key == "write_distance_map_files") { mp->write_distance_map_files = string_value_true (val); } else if (key == "write_thresholded_files") { mp->write_thresholded_files = string_value_true (val); } else if (key == "write_weight_files") { mp->write_weight_files = string_value_true (val); } else if (key == "write_warped_images") { mp->write_warped_images = string_value_true (val); } else if (key == "write_warped_structures") { mp->write_warped_structures = string_value_true (val); } else { goto error_exit; } } /* [REGISTRATION] */ if (section == "REGISTRATION") { if (key == "registration_config") { mp->registration_config = val; } else { goto error_exit; } } /* [STRUCTURES] */ if (section == "STRUCTURES") { /* Add key to list of structures */ mp->structure_map[key] = key; if (val != "") { /* Key/value pair, so add for renaming */ mp->structure_map[val] = key; } /* Add key to the set */ mp->structure_set.insert (key); /* There is no filtering of structures values */ } /* [LABELING] */ if (section == "LABELING") { if (key == "input") { mp->labeling_input_fn = val; } else if (key == "output") { mp->labeling_output_fn = val; } else { goto error_exit; } } /* [OPTIMIZATION-RESULT-REG] */ if (section == "OPTIMIZATION-RESULT-REG") { if (key == "registration") { mp->optimization_result_reg = val; } else { goto error_exit; } } /* [OPTIMIZATION-RESULT-SEG] */ if (section == "OPTIMIZATION-RESULT-SEG") { if (key == "structure") { ors.structure = val; } else if (key == "gaussian_weighting_voting_rho" || key == "rho") { sscanf (val.c_str(), "%g", &ors.rho); } else if (key == "gaussian_weighting_voting_sigma" || key == "sigma") { sscanf (val.c_str(), "%g", &ors.sigma); } else if (key == "gaussian_weighting_voting_minsim" || key == "minsim") { sscanf (val.c_str(), "%g", &ors.minsim); } else if (key == "gaussian_weighting_voting_thresh" || key == "thresh") { ors.thresh = val; } else if (key == "optimization_result_confidence_weight" || key == "confidence_weight") { sscanf (val.c_str(), "%g", &ors.confidence_weight); } else { goto error_exit; } } return PLM_SUCCESS; error_exit: print_and_exit ("Unknown (sec,key,val) combination: (%s,%s,%s)\n", section.c_str(), key.c_str(), val.c_str()); return PLM_ERROR; } Mabs_parms::Mabs_parms () { /* [CONVERT] */ this->convert_spacing = ""; /* [PREALIGNMENT] */ this->prealign_mode="disabled"; this->prealign_reference = ""; this->prealign_spacing = ""; this->prealign_registration_config = ""; this->prealign_roi_cfg_name = ""; /* [ATLAS-SELECTION] */ this->enable_atlas_selection = false; this->atlas_selection_criteria="nmi"; this->similarity_percent_threshold = 0.40; this->atlases_from_ranking = -1; this->mi_histogram_bins = 100; this->percentage_nmi_random_sample = -1; this->roi_mask_fn = ""; this->selection_reg_parms_fn = ""; this->lower_mi_value_sub_defined=false; this->lower_mi_value_sub = 0; this->upper_mi_value_sub_defined=false; this->upper_mi_value_sub = 0; this->lower_mi_value_atl_defined=false; this->lower_mi_value_atl = 0; this->upper_mi_value_atl_defined=false; this->upper_mi_value_atl = 0; this->max_random_atlases = 14; this->min_random_atlases = 6; this->precomputed_ranking_fn = ""; /* [TRAINING] */ this->distance_map_algorithm = ""; this->fusion_criteria = "gaussian"; this->minsim_values = "L 0.0001:1:0.0001"; this->rho_values = "1:1:1"; this->sigma_values = "L 1.7:1:1.7"; this->threshold_values = "0.5"; this->confidence_weight = "1:1:1"; this->write_distance_map_files = true; this->write_thresholded_files = true; this->write_weight_files = true; this->write_warped_images = true; this->write_warped_structures = true; /* [OPTIMIZATION-RESULT-REG] */ this->optimization_result_reg = ""; /* [OPTIMIZATION-RESULT-SEG] */ /* misc */ this->debug = false; } Mabs_parms::~Mabs_parms () { } static void print_usage () { printf ( "Usage: mabs [options] config_file\n" "Options:\n" " --debug Enable various debug output\n" ); exit (1); } void Mabs_parms::parse_config ( const char* config_fn ) { Mabs_parms_parser mpp (this); /* Parse the main config file */ mpp.parse_config_file (config_fn); /* After parsing main config file, also parse optimization result files */ std::string reg_fn = string_format ( "%s/mabs-train/optimization_result_reg.txt", this->training_dir.c_str()); std::string seg_fn = string_format ( "%s/mabs-train/optimization_result_seg.txt", this->training_dir.c_str()); if (file_exists (reg_fn)) { mpp.parse_config_file (reg_fn.c_str()); } if (file_exists (seg_fn)) { mpp.parse_config_file (seg_fn.c_str()); } } bool Mabs_parms::parse_args (int argc, char** argv) { int i; for (i=1; idebug = 1; } else { print_usage (); break; } } if (!argv[i]) { print_usage (); } else { this->parse_config (argv[i]); } return true; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/mabs_parms.h000066400000000000000000000051541321604176500305630ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _mabs_parms_h_ #define _mabs_parms_h_ #include "plmsegment_config.h" #include #include #include #include #include "mabs_seg_weights.h" #include "plm_return_code.h" class PLMSEGMENT_API Mabs_parms { public: Mabs_parms (); ~Mabs_parms (); public: bool parse_args (int argc, char** argv); void parse_config (const char* config_fn); public: /* [CONVERT] */ std::string convert_spacing; /* [PREALIGNMENT] */ std::string prealign_mode; std::string prealign_reference; std::string prealign_spacing; std::string prealign_registration_config; std::string prealign_roi_cfg_name; /* [ATLASES-SELECTION] */ bool enable_atlas_selection; std::string atlas_selection_criteria; float similarity_percent_threshold; int atlases_from_ranking; // -1 if it is not defined int mi_histogram_bins; float percentage_nmi_random_sample; // -1 if it is not defined std::string roi_mask_fn; std::string selection_reg_parms_fn; bool lower_mi_value_sub_defined; int lower_mi_value_sub; bool upper_mi_value_sub_defined; int upper_mi_value_sub; bool lower_mi_value_atl_defined; int lower_mi_value_atl; bool upper_mi_value_atl_defined; int upper_mi_value_atl; int min_random_atlases; int max_random_atlases; std::string precomputed_ranking_fn; /* [TRAINING] */ std::string atlas_dir; std::string training_dir; std::string convert_dir; std::string prealign_dir; std::string fusion_criteria; std::string distance_map_algorithm; std::string minsim_values; std::string rho_values; std::string sigma_values; std::string threshold_values; std::string confidence_weight; bool write_distance_map_files; bool write_thresholded_files; bool write_weight_files; bool write_warped_images; bool write_warped_structures; /* [REGISTRATION] */ std::string registration_config; /* [STRUCTURES] */ std::map structure_map; std::set structure_set; /* [LABELING] */ std::string labeling_input_fn; std::string labeling_output_fn; /* [OPTIMIZATION-RESULT-REG] */ std::string optimization_result_reg; /* [OPTIMIZATION-RESULT-SEG] */ Mabs_seg_weights_list optimization_result_seg; /* misc */ bool debug; }; #endif /* #ifndef _mabs_parms_h_ */ mabs_seg_weights.cxx000066400000000000000000000026101321604176500322370ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include "logfile.h" #include "mabs_seg_weights.h" void Mabs_seg_weights::print () const { lprintf ("MSW (%s): %f %f %f %f %s\n", structure == "" ? "default" : structure.c_str(), rho, sigma, minsim, confidence_weight, thresh.c_str()); } /* If there is an exact match, return its weights. Else if null structure exists, return its weights. Else return null pointer */ const Mabs_seg_weights* Mabs_seg_weights_list::find ( const std::string& structure) const { lprintf ("MSW searching for (%s)\n", structure.c_str()); const Mabs_seg_weights* msw = &default_weights; std::list::const_iterator msw_it; for (msw_it = weights_list.begin(); msw_it != weights_list.end(); msw_it++) { if (msw_it->structure == structure) { lprintf ("MSW search found exact match.\n"); msw_it->print(); return &(*msw_it); } else if (msw_it->structure == "") { lprintf ("MSW search found default.\n"); msw = &(*msw_it); } } lprintf ("MSW search complete.\n"); msw->print(); return msw; } mabs_seg_weights.h000066400000000000000000000026711321604176500316730ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _mabs_seg_weights_h_ #define _mabs_seg_weights_h_ #include "plmsegment_config.h" #include #include #include "logfile.h" class PLMSEGMENT_API Mabs_seg_weights { public: Mabs_seg_weights () { this->factory_reset (); } public: std::string structure; float rho; float sigma; float minsim; /* This is a string because the thresholding function can efficiently perform multiple thresholds during training */ std::string thresh; float confidence_weight; public: void factory_reset () { rho = 0.5; sigma = 1.5; minsim = 0.25; thresh = "0.4"; confidence_weight = 1e-8; } void print () const; }; class PLMSEGMENT_API Mabs_seg_weights_list { public: Mabs_seg_weights default_weights; std::list weights_list; public: void push_back (const Mabs_seg_weights& new_weights) { lprintf ("MSW: pushing new entry\n"); new_weights.print(); this->weights_list.push_back (new_weights); } Mabs_seg_weights& front () { return this->weights_list.front (); } const Mabs_seg_weights* find (const std::string& structure) const; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/mabs_staple.cxx000066400000000000000000000027501321604176500313030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- * See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information * ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include "itkImage.h" #include #include "mabs_staple.h" Mabs_staple::Mabs_staple() { this->foreground_val = 1; this->confidence_weight = 1.0; } Mabs_staple::~Mabs_staple() { this->structures.clear(); } void Mabs_staple::add_input_structure(Plm_image::Pointer& structure) { this->structures.push_back(structure); } void Mabs_staple::set_confidence_weight(float confidence_weight) { this->confidence_weight = confidence_weight; } void Mabs_staple::run() { typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::STAPLEImageFilter< InputImageType, OutputImageType > StapleType; StapleType::Pointer staple = StapleType::New(); std::list::iterator stru_it; int i; for (stru_it = this->structures.begin(), i=0; stru_it != this->structures.end(); stru_it++, i++) { staple->SetInput(i, (*stru_it)->itk_uchar()); } staple->SetForegroundValue(this->foreground_val); if (this->confidence_weight != 1.0) staple->SetConfidenceWeight((double) this->confidence_weight); staple->Update(); this->output_img = Plm_image::New(staple->GetOutput()); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/mabs_staple.h000066400000000000000000000014111321604176500307210ustar00rootroot00000000000000/* ----------------------------------------------------------------------- * See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information * ----------------------------------------------------------------------- */ #ifndef _mabs_staple_h_ #define _mabs_staple_h_ #include "plmsegment_config.h" #include #include #include "plm_image.h" class PLMSEGMENT_API Mabs_staple { public: Mabs_staple(); ~Mabs_staple(); void add_input_structure(Plm_image::Pointer&); void set_confidence_weight(float confidence_weight); void run(); public: std::list structures; int foreground_val; float confidence_weight; Plm_image::Pointer output_img; }; #endif /* #ifndef _mabs_staple_h_ */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/mabs_stats.cxx000066400000000000000000000075021321604176500311510ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include #include "dice_statistics.h" #include "hausdorff_distance.h" #include "logfile.h" #include "mabs_stats.h" #include "plm_timer.h" #include "string_util.h" class Mabs_stats_private { public: /* Keep track of score, for choosing best parameters */ std::map score_map; /* Which distance map algorithm to use */ std::string dmap_alg; /* Timing statistics */ double time_dice; double time_hausdorff; public: Mabs_stats_private () { this->dmap_alg = ""; this->time_dice = 0; this->time_hausdorff = 0; } }; Mabs_stats::Mabs_stats () { this->d_ptr = new Mabs_stats_private; } Mabs_stats::~Mabs_stats () { delete this->d_ptr; } void Mabs_stats::set_distance_map_algorithm ( const std::string& dmap_alg) { d_ptr->dmap_alg = dmap_alg; } std::string Mabs_stats::compute_statistics ( const std::string& score_id, const UCharImageType::Pointer& ref_img, const UCharImageType::Pointer& cmp_img) { Plm_timer timer; timer.start(); lprintf ("Computing Dice...\n"); Dice_statistics dice; dice.set_reference_image (ref_img); dice.set_compare_image (cmp_img); dice.run (); d_ptr->time_dice += timer.report(); timer.start(); lprintf ("Computing Hausdorff (alg=%s)\n", d_ptr->dmap_alg == "" ? "default" : d_ptr->dmap_alg.c_str()); Hausdorff_distance hd; hd.set_reference_image (ref_img); hd.set_compare_image (cmp_img); hd.set_distance_map_algorithm (d_ptr->dmap_alg); /* GCS FIX: This should not be hard-coded */ hd.set_maximum_distance (500); hd.run (); d_ptr->time_hausdorff += timer.report(); /* Update registration statistics -- these are used to keep track of which registration approach is the best */ std::map::const_iterator score_it = d_ptr->score_map.find (score_id); if (score_it == d_ptr->score_map.end()) { d_ptr->score_map[score_id] = dice.get_dice(); } else { d_ptr->score_map[score_id] += dice.get_dice(); } std::string stats_string = string_format ( "dice=%f,tp=%d,tn=%d,fp=%d,fn=%d," "hd=%f,95hd=%f,ahd=%f," "bhd=%f,95bhd=%f,abhd=%f", dice.get_dice(), (int) dice.get_true_positives(), (int) dice.get_true_negatives(), (int) dice.get_false_positives(), (int) dice.get_false_negatives(), hd.get_hausdorff(), hd.get_percent_hausdorff(), hd.get_avg_average_hausdorff(), hd.get_boundary_hausdorff(), hd.get_percent_boundary_hausdorff(), hd.get_avg_average_boundary_hausdorff() ); return stats_string; } std::string Mabs_stats::choose_best () { /* Select best pre-alignment result */ std::map::const_iterator score_it; score_it = d_ptr->score_map.begin(); double best_score = 0; std::string best_registration_name = ""; while (score_it != d_ptr->score_map.end()) { std::string registration_name = score_it->first; double this_score = d_ptr->score_map[registration_name]; printf ("Recovered score: %s, %f\n", registration_name.c_str(), (float) this_score); if (this_score > best_score) { best_score = this_score; best_registration_name = registration_name; } score_it ++; } return best_registration_name; } double Mabs_stats::get_time_dice () { return d_ptr->time_dice; } double Mabs_stats::get_time_hausdorff () { return d_ptr->time_hausdorff; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/mabs_stats.h000066400000000000000000000015311321604176500305720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _mabs_stats_h_ #define _mabs_stats_h_ #include "plmsegment_config.h" #include #include "itk_image.h" class Mabs_stats_private; class PLMSEGMENT_API Mabs_stats { public: Mabs_stats (); ~Mabs_stats (); public: Mabs_stats_private *d_ptr; public: void set_distance_map_algorithm ( const std::string& dmap_alg); std::string compute_statistics ( const std::string& score_id, const UCharImageType::Pointer& ref_img, const UCharImageType::Pointer& cmp_img); std::string choose_best (); double get_time_dice (); double get_time_hausdorff (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/mabs_vote.cxx000066400000000000000000000167771321604176500310060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include #include #include #include #include #include #if (OPENMP_FOUND) #include #endif #include "itkImageRegionIterator.h" #include "logfile.h" #include "mabs_vote.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_math.h" #include "volume.h" class Plm_image; class Mabs_vote_private { public: Mabs_vote_private () { rho = 1; sigma = 50; minimum_similarity = 0.0001; } ~Mabs_vote_private () { } public: FloatImageType::Pointer target; Plm_image::Pointer score_img; Plm_image::Pointer like0_img; Plm_image::Pointer like1_img; double rho; double sigma; double minimum_similarity; }; Mabs_vote::Mabs_vote () { d_ptr = new Mabs_vote_private; } Mabs_vote::~Mabs_vote () { delete d_ptr; } void Mabs_vote::set_fixed_image ( FloatImageType::Pointer target ) { /* Save a copy of target */ d_ptr->target = target; /* Create a like0 image */ d_ptr->like0_img = Plm_image::New ( new Plm_image ( PLM_IMG_TYPE_ITK_FLOAT, Plm_image_header (d_ptr->target))); /* Create a like1 image */ d_ptr->like1_img = Plm_image::New ( new Plm_image ( PLM_IMG_TYPE_ITK_FLOAT, Plm_image_header (d_ptr->target))); } void Mabs_vote::set_rho ( float rho ) { d_ptr->rho = (double) rho; } void Mabs_vote::set_sigma ( float sigma ) { d_ptr->sigma = (double) sigma; } void Mabs_vote::set_minimum_similarity ( float minimum_similarity ) { d_ptr->minimum_similarity = (double) minimum_similarity; } void Mabs_vote::vote ( FloatImageType::Pointer atlas_image, FloatImageType::Pointer dmap_image ) { /* GCS FIX: I shouldn't need to re-convert these every time I vote */ Plm_image atl_i (atlas_image); Plm_image dmp_i (dmap_image); Plm_image tgt_i (d_ptr->target); Volume::Pointer atl_vol = atl_i.get_volume_float (); Volume::Pointer dmp_vol = dmp_i.get_volume_float (); Volume::Pointer tgt_vol = tgt_i.get_volume_float (); float *atl_img = (float*) atl_vol->img; float *dmp_img = (float*) dmp_vol->img; float *tgt_img = (float*) tgt_vol->img; Volume::Pointer like0_vol = d_ptr->like0_img->get_volume_float (); Volume::Pointer like1_vol = d_ptr->like1_img->get_volume_float (); float *like0_img = (float*) like0_vol->img; float *like1_img = (float*) like1_vol->img; plm_long v; #pragma omp parallel for for (v = 0; v < tgt_vol->npix; v++) { /* Compute similarity between target and atlas images */ double intensity_diff = tgt_img[v] - atl_img[v]; /* GCS Note: Sometimes value is zero, when med_diff is very high. When this happens for all atlas examples, we get divide by zero. Furthermore, there is no sense dividing by M_SQRT2PI * d_ptr->sigma, because that is a constant. */ #if defined (commentout) similarity_value = exp (-(intensity_diff * intensity_diff) / (2.0*d_ptr->sigma*d_ptr->sigma)) / (M_SQRT2PI * d_ptr->sigma); #endif /* So instead, we do this */ double similarity_value = exp (-(intensity_diff * intensity_diff) / (2.0*d_ptr->sigma*d_ptr->sigma)); if (similarity_value < 0.0001) { similarity_value = 0.0001; } /* The above is too sensitive. We should truncate. Mixed Gaussian / Uniform model. */ if (similarity_value < d_ptr->minimum_similarity) { similarity_value = d_ptr->minimum_similarity; } /* Compute the chance of being in the structure. */ double dmap_value = dmp_img[v]; #if defined (commentout) /* GCS 2013-01-31: Distance map is squared. This should probably be corrected before saving */ if (dmap_value > 0) { dmap_value = sqrt(dmap_value); } else { dmap_value = -sqrt(-dmap_value); } #endif /* Nb. we need to check to make sure exp(dmap_value) doesn't overflow. The actual overflow is at about exp(700) for double, and about exp(85) for float. But we can be a little more conservative. */ double label_likelihood_0, label_likelihood_1; if (dmap_value > 50) { label_likelihood_0 = 1; label_likelihood_1 = 0; } else if (dmap_value > -50) { label_likelihood_0 = exp (+d_ptr->rho*dmap_value); label_likelihood_1 = exp (-d_ptr->rho*dmap_value); } else { label_likelihood_0 = 0; label_likelihood_1 = 1; } /* Compute total score, weighted by image similarity L0 is likelihood for being outside structure L1 is likelihood for being inside structure */ double sum = label_likelihood_0 + label_likelihood_1; double l0 = (label_likelihood_0 / sum) * similarity_value; double l1 = (label_likelihood_1 / sum) * similarity_value; /* Save the scores */ like0_img[v] += l0; like1_img[v] += l1; } } void Mabs_vote::normalize_votes () { /* Create weight image */ d_ptr->score_img = Plm_image::New ( new Plm_image( PLM_IMG_TYPE_ITK_FLOAT, Plm_image_header (d_ptr->target))); Volume::Pointer score_vol = d_ptr->score_img->get_volume_float (); Volume::Pointer like0_vol = d_ptr->like0_img->get_volume_float (); Volume::Pointer like1_vol = d_ptr->like1_img->get_volume_float (); float *score_img = (float*) score_vol->img; float *like0_img = (float*) like0_vol->img; float *like1_img = (float*) like1_vol->img; plm_long v; float l0_min = FLT_MAX; float l1_min = FLT_MAX; float l0_max = -FLT_MAX; float l1_max = -FLT_MAX; #pragma omp parallel { float priv_l0_min = FLT_MAX; float priv_l1_min = FLT_MAX; float priv_l0_max = -FLT_MAX; float priv_l1_max = -FLT_MAX; #pragma omp for for (v = 0; v < score_vol->npix; v++) { float l0 = like0_img[v]; float l1 = like1_img[v]; score_img[v] = l1 / (l0 + l1); if (l0 < priv_l0_min) priv_l0_min = l0; if (l1 < priv_l1_min) priv_l1_min = l1; if (l0 > priv_l0_max) priv_l0_max = l0; if (l1 > priv_l1_max) priv_l1_max = l1; } /* GCS Note: this could be done faster using pragma omp flush, and then testing whether or not it is needed to enter the critical section. Cf: http://pc51.plm.eecs.uni-kassel.de/plm/fileadmin/pm/courses/pvI07/SL06.pdf However, for readability I leave it as-is */ #pragma omp critical { l0_min = std::min (l0_min, priv_l0_min); } #pragma omp critical { l1_min = std::min (l1_min, priv_l1_min); } #pragma omp critical { l0_max = std::max (l0_max, priv_l0_max); } #pragma omp critical { l1_max = std::max (l1_max, priv_l1_max); } } lprintf ("\tLikelihood 0 \\in [ %g, %g ]\n", l0_min, l0_max); lprintf ("\tLikelihood 1 \\in [ %g, %g ]\n", l1_min, l1_max); } FloatImageType::Pointer Mabs_vote::get_weight_image () { FloatImageType::Pointer itk_score_img = d_ptr->score_img->itk_float(); return itk_score_img; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/mabs_vote.h000066400000000000000000000033151321604176500304130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _mabs_vote_h_ #define _mabs_vote_h_ #include "plmsegment_config.h" #include "itk_image_type.h" class Mabs_vote_private; class PLMSEGMENT_API Mabs_vote { public: Mabs_vote (); ~Mabs_vote (); public: Mabs_vote_private *d_ptr; public: /*! \name Inputs */ ///@{ /*! \brief Set the reference image. This is the image we want to segment. */ void set_fixed_image ( FloatImageType::Pointer target ); /*! \brief Set the tuning parameters. Rho is the penalty with respect to distance */ void set_rho ( float rho ); /*! \brief Set the tuning parameters. Sigma is the width of the gaussian with respect to image difference */ void set_sigma ( float sigma ); void set_minimum_similarity ( float minimum_similarity ); ///@} /*! \name Execution */ ///@{ /*! \brief Vote for labels using the contribution for a single registered atlas image */ void vote ( FloatImageType::Pointer atlas_image, FloatImageType::Pointer dmap_image); /*! \brief After you done adding contributions, normalize the votes. */ void normalize_votes (); ///@} /*! \name Outputs */ ///@{ /*! \brief Return the label likelihoods as an ITK image. */ FloatImageType::Pointer get_weight_image (); /*! \brief Return the weights as an ITK image. */ UCharImageType::Pointer get_label_image (); ///@} }; #endif /* #ifndef _mabs_vote_h_ */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/ml_convert.cxx000066400000000000000000000275101321604176500311620ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include #include #include "itkImageRegionIterator.h" #include "dir_list.h" #include "file_util.h" #include "itk_image_create.h" #include "itk_image_save.h" #include "logfile.h" #include "ml_convert.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_timer.h" #include "print_and_exit.h" #include "string_util.h" class Ml_convert_private { public: std::string append_filename; std::string input_ml_results_filename; std::string label_filename; std::string mask_filename; std::string output_filename; std::string output_format; std::list feature_dir; Plm_image_type plm_image_type; public: void image_from_ml (); void ml_from_image (); protected: template void image_from_ml_internal (); template T choose_value ( float value ); }; void Ml_convert_private::ml_from_image () { Plm_timer pli; pli.start (); /* Create files for ping-pong -- unfortunately we have to use FILE* due to lack of fstream support for temporary filenames */ FILE *fp[2], *current, *previous; fp[0] = make_tempfile (); fp[1] = make_tempfile (); current = fp[0]; previous = fp[0]; bool vw_format = true; if (this->output_format == "libsvm") { vw_format = false; } /* The index of the features */ int idx = 0; #define BUFSIZE 1024*1024 char buf[BUFSIZE]; size_t chars_in_buf = 0; char *buf_ptr; /* Load mask */ bool have_mask = false; UCharImageType::Pointer mask_itk; itk::ImageRegionIterator< UCharImageType > mask_it; if (this->mask_filename != "") { Plm_image::Pointer mask = Plm_image::New (this->mask_filename); mask_itk = mask->itk_uchar(); mask_it = itk::ImageRegionIterator< UCharImageType > ( mask_itk, mask_itk->GetLargestPossibleRegion()); have_mask = true; } /* Load labelmap */ if (this->label_filename != "") { lprintf ("Processing labelmap\n"); Plm_image::Pointer labelmap = Plm_image::New (this->label_filename); UCharImageType::Pointer labelmap_itk = labelmap->itk_uchar(); /* Dump labels to file */ UCharImageType::RegionType rg = labelmap_itk->GetLargestPossibleRegion (); itk::ImageRegionIterator< UCharImageType > labelmap_it (labelmap_itk, rg); if (have_mask) { mask_it.GoToBegin(); } for (labelmap_it.GoToBegin(); !labelmap_it.IsAtEnd(); ++labelmap_it) { if (have_mask) { unsigned char m = (unsigned char) mask_it.Get(); ++mask_it; if (!m) { continue; } } unsigned char v = (unsigned char) labelmap_it.Get(); fprintf (current, "%d %s\n", v == 0 ? -1 : 1, vw_format ? "|" : ""); } } else if (this->append_filename != "") { lprintf ("Processing append\n"); FILE *app_fp = fopen (this->append_filename.c_str(), "r"); rewind (current); /* Do the copy */ while ((chars_in_buf = fread (buf, 1, BUFSIZE, app_fp)) != 0) { fwrite (buf, 1, chars_in_buf, current); } fclose (app_fp); /* Re-open input, and get the highest index. Only needed for libsvm format. */ if (!vw_format) { std::string line; std::ifstream app_fs (this->append_filename.c_str()); std::getline (app_fs, line); app_fs.close (); std::vector tokens = string_split (line, ' '); if (!tokens.empty()) { float junk; int rc = sscanf (tokens.back().c_str(), "%d:%f", &idx, &junk); if (rc != 2) { idx = 0; } } } } /* Compile a complete list of feature input files */ std::list all_feature_files; std::list::iterator fpath_it; for (fpath_it = this->feature_dir.begin(); fpath_it != this->feature_dir.end(); fpath_it++) { if (is_directory(*fpath_it)) { Dir_list dir_list (*fpath_it); for (int i = 0; i < dir_list.num_entries; i++) { /* Skip directories */ std::string dir_entry = dir_list.entry (i); if (is_directory(dir_entry)) { continue; } all_feature_files.push_back (dir_entry); } } else { all_feature_files.push_back (*fpath_it); } } /* Loop through feature files */ for (fpath_it = all_feature_files.begin(); fpath_it != all_feature_files.end(); fpath_it++) { std::string dir_entry = *fpath_it; /* Load a feature image */ Plm_image::Pointer feature = Plm_image::New (dir_entry); if (!feature->have_image()) { continue; } FloatImageType::Pointer feature_itk = feature->itk_float(); /* Set up input and output file */ lprintf ("Processing %s\n", dir_entry.c_str()); if (current == fp[0]) { previous = fp[0]; current = fp[1]; } else { previous = fp[1]; current = fp[0]; } rewind (previous); rewind (current); /* Loop through pixels, appending them to each line of file */ buf_ptr = 0; itk::ImageRegionIterator< FloatImageType > feature_it ( feature_itk, feature_itk->GetLargestPossibleRegion ()); if (have_mask) { mask_it.GoToBegin(); } for (feature_it.GoToBegin(); !feature_it.IsAtEnd(); ++feature_it) { /* Check mask */ if (have_mask) { unsigned char m = (unsigned char) mask_it.Get(); ++mask_it; if (!m) { continue; } } /* Get pixel value */ float v = (float) feature_it.Get(); /* Copy existing line from previous file into current file */ bool eol_found = false; while (1) { if (chars_in_buf == 0) { chars_in_buf = fread (buf, 1, BUFSIZE, previous); if (chars_in_buf == 0) { break; } buf_ptr = buf; } size_t write_size = 0; for (write_size = 0; write_size < chars_in_buf; write_size++) { if (buf_ptr[write_size] == '\n') { eol_found = true; break; } } fwrite (buf_ptr, 1, write_size, current); buf_ptr += write_size; chars_in_buf -= write_size; if (eol_found) { buf_ptr += 1; chars_in_buf -= 1; break; } } /* Append new value */ if (vw_format) { fprintf (current, " %s:%f\n", dir_entry.c_str(), v); } else { fprintf (current, " %d:%f\n", idx+1, v); } } idx ++; } /* Finally, re-write temp file into final output file */ lprintf ("Processing final output\n"); rewind (current); FILE *final_output = plm_fopen (this->output_filename.c_str(), "wb"); while ((chars_in_buf = fread (buf, 1, BUFSIZE, current)) != 0) { fwrite (buf, 1, chars_in_buf, final_output); } fclose (final_output); fclose (fp[0]); fclose (fp[1]); printf ("Time = %f\n", (float) pli.report()); } template<> unsigned char Ml_convert_private::choose_value ( float value ) { if (value <= 0) { return 0; } else { return 1; } } template<> float Ml_convert_private::choose_value ( float value ) { return value; } template void Ml_convert_private::image_from_ml_internal () { Plm_image::Pointer mask; bool have_mask = false; if (this->mask_filename != "") { have_mask = true; mask = Plm_image::New (this->mask_filename); } else if (this->label_filename != "") { have_mask = false; mask = Plm_image::New (this->label_filename); } else { print_and_exit ("Sorry, could not convert ml text file to image " "without knowing the image size"); } typedef typename itk::Image ImageType; typename ImageType::Pointer output_image = itk_image_create ( Plm_image_header (mask) ); std::ifstream fp (this->input_ml_results_filename.c_str()); itk::ImageRegionIterator< ImageType > out_it (output_image, output_image->GetLargestPossibleRegion()); itk::ImageRegionIterator< UCharImageType > mask_it; if (have_mask) { mask_it = itk::ImageRegionIterator< UCharImageType > ( mask->itk_uchar(), mask->itk_uchar()->GetLargestPossibleRegion()); mask_it.GoToBegin(); } for (out_it.GoToBegin(); !out_it.IsAtEnd(); ++out_it) { if (have_mask) { unsigned char mask_value = mask_it.Get(); ++mask_it; if (mask_value == 0) { out_it.Set (0); continue; } } std::string line; if (!std::getline (fp, line)) { print_and_exit ("Error, getline unexpected returned false during ml text read.\n"); } float value; int rc = sscanf (line.c_str(), "%f", &value); if (rc != 1) { out_it.Set ((T) 0); } else { out_it.Set (this->choose_value (value)); } } itk_image_save (output_image, this->output_filename); } void Ml_convert_private::image_from_ml () { switch (this->plm_image_type) { case PLM_IMG_TYPE_ITK_UCHAR: case PLM_IMG_TYPE_GPUIT_UCHAR: this->image_from_ml_internal (); break; case PLM_IMG_TYPE_ITK_FLOAT: case PLM_IMG_TYPE_GPUIT_FLOAT: this->image_from_ml_internal (); break; default: print_and_exit ("Warning: unimplemented image type in image_from_ml()\n"); this->image_from_ml_internal (); break; } } Ml_convert::Ml_convert () { d_ptr = new Ml_convert_private; } Ml_convert::~Ml_convert () { delete d_ptr; } void Ml_convert::set_append_filename (const std::string& append_filename) { d_ptr->append_filename = append_filename; } void Ml_convert::set_input_ml_results_filename ( const std::string& input_ml_results_filename) { d_ptr->input_ml_results_filename = input_ml_results_filename; } void Ml_convert::set_label_filename (const std::string& label_filename) { d_ptr->label_filename = label_filename; } void Ml_convert::set_mask_filename (const std::string& mask_filename) { d_ptr->mask_filename = mask_filename; } void Ml_convert::set_output_filename (const std::string& output_filename) { d_ptr->output_filename = output_filename; } void Ml_convert::set_output_format (const std::string& output_format) { d_ptr->output_format = output_format; } void Ml_convert::set_output_type (const std::string& output_type) { d_ptr->plm_image_type = plm_image_type_parse (output_type.c_str()); } void Ml_convert::add_feature_path (const std::string& feature_path) { d_ptr->feature_dir.push_back (feature_path); } void Ml_convert::run () { if (d_ptr->input_ml_results_filename != "") { d_ptr->image_from_ml (); } else { d_ptr->ml_from_image (); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/ml_convert.h000066400000000000000000000020711321604176500306020ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _ml_convert_h_ #define _ml_convert_h_ #include "plmsegment_config.h" #include #include "plm_image_type.h" class Ml_convert_private; class PLMSEGMENT_API Ml_convert { public: Ml_convert_private *d_ptr; public: Ml_convert (); ~Ml_convert (); public: void set_append_filename (const std::string& append_filename); void set_input_ml_results_filename ( const std::string& input_ml_results_filename); void set_label_filename (const std::string& label_filename); void set_mask_filename (const std::string& mask_filename); void set_output_filename (const std::string& output_filename); void set_output_format (const std::string& output_format); void set_output_type (const std::string& output_format); void add_feature_path (const std::string& feature_path); void run (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/plmsegment.h000066400000000000000000000012051321604176500306030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifdef __PLM_MASTER_HEADER__ #error "plmsegment.h cannot be #included by another plastimatch header!" #else #define __PLM_MASTER_HEADER__ #ifndef _plmsegment_h_ #define _plmsegment_h_ #include "plmsegment_config.h" #include "mabs.h" #include "mabs_parms.h" #include "mabs_subject.h" #include "mabs_vote.h" #endif /* #ifndef _plmsegment_h_ */ #undef __PLM_MASTER_HEADER__ #endif /* #ifdef __PLM_MASTER_HEADER__ */ plmsegment_config.h.in000066400000000000000000000013341321604176500324610ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plmsegment_config_h__ #define __plmsegment_config_h__ #include "plm_config.h" #if ((defined(_WIN32) || defined(WIN32)) && (defined (PLM_BUILD_SHARED_LIBS))) # ifdef plmsegment_EXPORTS # define PLMSEGMENT_C_API EXTERNC __declspec(dllexport) # define PLMSEGMENT_API __declspec(dllexport) # else # define PLMSEGMENT_C_API EXTERNC __declspec(dllimport) # define PLMSEGMENT_API __declspec(dllimport) # endif #else # define PLMSEGMENT_C_API EXTERNC # define PLMSEGMENT_API #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/segment_body.cxx000066400000000000000000000367751321604176500315060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsegment_config.h" #include "itkImage.h" #include "itkImageFileWriter.h" #include "itkImageRegionIteratorWithIndex.h" #include "itkGetAverageSliceImageFilter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkConnectedComponentImageFilter.h" #include "itkRelabelComponentImageFilter.h" #include "itkBinaryBallStructuringElement.h" #include "itkBinaryDilateImageFilter.h" #include "itkBinaryErodeImageFilter.h" #include "itkVotingBinaryIterativeHoleFillingImageFilter.h" #include "itk_image_save.h" #include "itk_resample.h" #include "plm_image.h" #include "plm_image_header.h" #include "segment_body.h" /* Thresholds for finding patient & couch */ const short T1 = -300; const short T2 = -500; const short T3 = -1000; /* Reduce resolution to at most 5 mm voxels if "m_fast" option selected */ FloatImageType::Pointer Segment_body::reduce_image_dim (FloatImageType::Pointer i1) { if (m_fast) { Plm_image_header pih; bool need_resample = false; pih.set_from_plm_image (this->img_in); RegionType itk_region = pih.GetRegion(); SizeType itk_dim = itk_region.GetSize(); OriginType itk_origin = pih.GetOrigin(); SpacingType itk_spacing = pih.GetSpacing(); DirectionType itk_direction = pih.GetDirection(); for (int d = 0; d < 3; d++) { if (itk_spacing[d] < 5.0) { itk_dim[d] = (int) floor(itk_dim[d] * itk_spacing[d] / 5.0); itk_origin[d] += (5.0 - itk_spacing[d]) / 2; itk_spacing[d] = 5.0; need_resample = true; } } if (need_resample) { printf ("Resampling image\n"); itk_region.SetSize (itk_dim); pih.set (itk_region, itk_origin, itk_spacing, itk_direction); i1 = resample_image (i1, &pih, -1000, 1); if (m_debug) { itk_image_save (i1, "0_resample.nrrd"); } } } return i1; } /* Return bottom image row (indexed starting at 0) containing a patient pixel */ int Segment_body::find_patient_bottom (FloatImageType::Pointer i1) { FloatImageType::RegionType r1 = i1->GetLargestPossibleRegion(); const FloatImageType::SizeType& sz = r1.GetSize(); typedef itk::ImageRegionIteratorWithIndex< FloatImageType > FloatIteratorType; /* In the future, these two steps can use MeanProjectionImageFilter and MaximumProjectionImageFilter. But this is not implemented in 2.4.1 or 3.4.0 */ /* i3 = mean image along Z */ /* This step can't be done with short(), because itk overflows */ typedef itk::GetAverageSliceImageFilter < FloatImageType, FloatImageType > GASFilterType; GASFilterType::Pointer gas_filter = GASFilterType::New (); gas_filter->SetInput (i1); gas_filter->SetAveragedOutDimension (2); gas_filter->Update (); FloatImageType::Pointer i3 = gas_filter->GetOutput (); /* i3max = max value along each row of i3 */ /* pt_top = top of patient, couch_bot = bottom of couch */ float* i3max = (float*) malloc (sz[1]*sizeof(float)); for (unsigned long i = 0; i < sz[1]; i++) { i3max[i] = m_lower_threshold; } FloatImageType::RegionType r3 = i3->GetLargestPossibleRegion(); FloatIteratorType it3 (i3, r3); for (it3.GoToBegin(); !it3.IsAtEnd(); ++it3) { FloatImageType::IndexType idx = it3.GetIndex(); float pix_value = it3.Get(); if (i3max[idx[1]] > pix_value) continue; i3max[idx[1]] = pix_value; } int pt_top = -1, couch_bot = -1; for (unsigned long i = 0; i < sz[1]; i++) { if (i3max[i] > T1) { if (pt_top == -1) { pt_top = i; } couch_bot = i; } } /* pt_bot = bottom of patient */ int pt_bot = couch_bot; for (int i = pt_top+1; i < couch_bot; i++) { if (i3max[i] < T2) { pt_bot = i; break; } } free (i3max); printf ("pt_top = %d, pt_bot = %d, couch_bot = %d\n", pt_top, pt_bot, couch_bot); return pt_bot; } UCharImageType::Pointer Segment_body::threshold_patient (FloatImageType::Pointer i1) { typedef itk::BinaryThresholdImageFilter< FloatImageType, UCharImageType > ThresholdFilterType; ThresholdFilterType::Pointer thresh_filter = ThresholdFilterType::New (); thresh_filter->SetInput (i1); thresh_filter->SetLowerThreshold (m_lower_threshold); // Upper threshold is max value by default thresh_filter->SetOutsideValue (0); thresh_filter->SetInsideValue (1); try { thresh_filter->Update (); } catch (itk::ExceptionObject & excep) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } return thresh_filter->GetOutput (); } void remove_couch (UCharImageType::Pointer i2, int patient_bottom) { typedef itk::ImageRegionIteratorWithIndex< UCharImageType > UCharIteratorType; UCharImageType::RegionType r2 = i2->GetLargestPossibleRegion(); UCharIteratorType it2 (i2, r2); for (it2.GoToBegin(); !it2.IsAtEnd(); ++it2) { UCharImageType::IndexType idx = it2.GetIndex(); if (idx[1] > patient_bottom) it2.Set(0); } } UCharImageType::Pointer erode_and_dilate (UCharImageType::Pointer i2) { typedef itk::BinaryBallStructuringElement< unsigned char,3 > BallType; typedef itk::BinaryErodeImageFilter< UCharImageType, UCharImageType, itk::BinaryBallStructuringElement > ErodeFilterType; typedef itk::BinaryDilateImageFilter< UCharImageType, UCharImageType, itk::BinaryBallStructuringElement > DilateFilterType; BallType ball; ErodeFilterType::Pointer erode_filter = ErodeFilterType::New (); DilateFilterType::Pointer dilate_filter = DilateFilterType::New (); ball.SetRadius (2); ball.CreateStructuringElement (); erode_filter->SetInput (i2); erode_filter->SetKernel (ball); erode_filter->SetErodeValue (1); try { erode_filter->Update (); } catch (itk::ExceptionObject & excep) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } i2 = erode_filter->GetOutput (); dilate_filter->SetInput (i2); dilate_filter->SetKernel (ball); dilate_filter->SetDilateValue (1); try { dilate_filter->Update (); } catch (itk::ExceptionObject & excep) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } i2 = dilate_filter->GetOutput (); return i2; } UCharImageType::Pointer get_largest_connected_component (UCharImageType::Pointer i2) { ShortImageType::Pointer i4 = ShortImageType::New (); /* Identify components */ typedef itk::ConnectedComponentImageFilter< UCharImageType, ShortImageType, UCharImageType > ConnectedFilterType; ConnectedFilterType::Pointer cc_filter = ConnectedFilterType::New (); cc_filter->SetInput (i2); try { cc_filter->Update (); } catch (itk::ExceptionObject & excep) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } i4 = cc_filter->GetOutput (); /* Sort components by size */ typedef itk::RelabelComponentImageFilter< ShortImageType, ShortImageType > RelabelFilterType; RelabelFilterType::Pointer rel_filter = RelabelFilterType::New (); rel_filter->SetInput (i4); try { rel_filter->Update (); } catch (itk::ExceptionObject & excep) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } i4 = rel_filter->GetOutput (); int num_vox = i4->GetLargestPossibleRegion().GetSize()[0] * i4->GetLargestPossibleRegion().GetSize()[1] * i4->GetLargestPossibleRegion().GetSize()[2]; int label_upper_thresh = 1; float ccs_percent_thresh = 0.05; for (unsigned int ccs = 0; ccs < rel_filter->GetSizeOfObjectsInPixels().size(); ++ccs) { float cc_pct = (float) rel_filter->GetSizeOfObjectsInPixels()[ccs] / num_vox; if (cc_pct > ccs_percent_thresh) { label_upper_thresh = ccs + 1; printf ("CC %d has size %d (%f)\n", ccs, (int) rel_filter->GetSizeOfObjectsInPixels()[ccs], cc_pct ); } else { break; } } /* Select largest N components */ typedef itk::BinaryThresholdImageFilter< ShortImageType, UCharImageType > LabelSelectFilterType; LabelSelectFilterType::Pointer ls_filter = LabelSelectFilterType::New (); ls_filter->SetInput (i4); ls_filter->SetLowerThreshold (1); ls_filter->SetUpperThreshold (label_upper_thresh); ls_filter->SetOutsideValue (0); ls_filter->SetInsideValue (1); try { ls_filter->Update (); } catch (itk::ExceptionObject & excep) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } i2 = ls_filter->GetOutput (); return i2; } UCharImageType::Pointer Segment_body::fill_holes (UCharImageType::Pointer mask, int radius, int max_its) { /* PAOLO ZAFFINO 9-4-13 * Often the mask has some big holes inside (for example the structures that contain air). * Try to fill that holes. * This step can be very slow but anyway it seems to fix the issue. */ typedef itk::VotingBinaryIterativeHoleFillingImageFilter< UCharImageType > holeFillerFilter; holeFillerFilter::Pointer filler = holeFillerFilter::New(); filler->SetInput(mask); UCharImageType::SizeType indexRadius; indexRadius[0] = radius; indexRadius[1] = radius; indexRadius[2] = radius/2.0; filler->SetRadius(indexRadius); filler->SetMajorityThreshold(0); filler->SetBackgroundValue(1); filler->SetForegroundValue(0); filler->SetMaximumNumberOfIterations(max_its); filler->Update(); printf("Changed voxels = %d \n", (int) filler->GetNumberOfPixelsChanged()); return filler->GetOutput(); } void invert_image (UCharImageType::Pointer i2) { typedef itk::ImageRegionIteratorWithIndex< UCharImageType > UCharIteratorType; UCharImageType::RegionType r2 = i2->GetLargestPossibleRegion(); UCharIteratorType it2 (i2, r2); for (it2.GoToBegin(); !it2.IsAtEnd(); ++it2) { it2.Set(!it2.Get()); } } void Segment_body::do_segmentation () { /* Convert input to float */ FloatImageType::Pointer i1 = this->img_in->itk_float(); /* Reduce resolution to at most 5 mm voxels */ i1 = reduce_image_dim (i1); /* Allocate output image (i2) */ UCharImageType::Pointer i2 = UCharImageType::New (); /* Find patient */ int patient_bottom; if (this->m_bot_given) { patient_bottom = this->m_bot; } else { printf ("find_patient_bottom\n"); patient_bottom = find_patient_bottom (i1); } /* Threshold image */ printf ("threshold\n"); i2 = this->threshold_patient (i1); /* Zero out the couch */ printf ("remove_couch\n"); remove_couch (i2, patient_bottom); if (m_debug) { itk_image_save (i2, "1_remove_couch.nrrd"); } /* Erode and dilate */ printf ("erode_and_dilate\n"); i2 = erode_and_dilate (i2); /* Compute connected components */ printf ("get_largest_connected_component\n"); i2 = get_largest_connected_component (i2); /* Invert the image */ printf ("invert\n"); invert_image (i2); if (m_debug) { itk_image_save (i2, "2_largest_cc.nrrd"); } /* Fill holes: Redo connected components on the (formerly) black parts */ printf ("get_largest_connected_component\n"); i2 = get_largest_connected_component (i2); if (m_debug) { itk_image_save (i2, "3_re_invert.nrrd"); } /* Fill holes */ /* PAOLO ZAFFINO 9-4-13 * Often the mask has some big holes inside (for example the structures that contain air). * Try to fill that holes. * This step can be very slow but anyway it seems to fix the issue. */ if (m_fill_holes) { printf("fill holes \n"); printf("fill parameters: \n"); printf("radius1 = %d, radius2 = %d, radius3 = %d \n", m_fill_parms[0], m_fill_parms[1], m_fill_parms[2]); printf("iterations1 = %d, iterations2 = %d, iterations3 = %d \n", m_fill_parms[3], m_fill_parms[4], m_fill_parms[5]); i2 = fill_holes(i2, m_fill_parms[0], m_fill_parms[3]); i2 = fill_holes(i2, m_fill_parms[1], m_fill_parms[4]); i2 = fill_holes(i2, m_fill_parms[2], m_fill_parms[5]); if (m_debug) { itk_image_save (i2, "4_filled.nrrd"); } } /* Invert the image */ printf ("invert\n"); invert_image (i2); /* Return image to caller */ printf ("return\n"); this->img_out->set_itk (i2); } void Segment_body::do_segmentation_air_cavity()//for air cavity filling in CT/CBCT images { /* Convert input to float */ FloatImageType::Pointer i1 = this->img_in->itk_float(); /* Reduce resolution to at most 5 mm voxels */ i1 = reduce_image_dim (i1); /* Allocate output image (i2) */ UCharImageType::Pointer i2 = UCharImageType::New(); /* Find patient */ int patient_bottom; if (this->m_bot_given) { patient_bottom = this->m_bot; } else { printf("find_patient_bottom\n"); patient_bottom = find_patient_bottom(i1); } /* Threshold image */ printf("threshold\n"); i2 = this->threshold_patient(i1); /* Zero out the couch */ //YKTEMP /* printf ("remove_couch\n"); remove_couch (i2, patient_bottom); if (m_debug) { itk_image_save (i2, "1_remove_couch.nrrd"); }*/ /* Erode and dilate */ //YKTEMP printf("erode_and_dilate\n"); i2 = erode_and_dilate(i2); /* Compute connected components */ //YKTEMP //printf ("get_largest_connected_component\n"); //i2 = get_largest_connected_component (i2); /* Invert the image *///YKTEMP /*printf ("invert\n"); invert_image (i2);*/ if (m_debug) { itk_image_save(i2, "2_largest_cc.nrrd"); } /* Fill holes: Redo connected components on the (formerly) black parts *///YKTEMP //printf ("get_largest_connected_component\n"); //i2 = get_largest_connected_component (i2); if (m_debug) { itk_image_save(i2, "3_re_invert.nrrd"); } /* Fill holes */ /* PAOLO ZAFFINO 9-4-13 * Often the mask has some big holes inside (for example the structures that contain air). * Try to fill that holes. * This step can be very slow but anyway it seems to fix the issue. */ if (m_fill_holes) { printf("fill holes \n"); printf("fill parameters: \n"); printf("radius1 = %d, radius2 = %d, radius3 = %d \n", m_fill_parms[0], m_fill_parms[1], m_fill_parms[2]); printf("iterations1 = %d, iterations2 = %d, iterations3 = %d \n", m_fill_parms[3], m_fill_parms[4], m_fill_parms[5]); i2 = fill_holes(i2, m_fill_parms[0], m_fill_parms[3]); i2 = fill_holes(i2, m_fill_parms[1], m_fill_parms[4]); i2 = fill_holes(i2, m_fill_parms[2], m_fill_parms[5]); if (m_debug) { itk_image_save(i2, "4_filled.nrrd"); } } /* Invert the image */ printf("invert\n"); invert_image(i2); /* Return image to caller */ printf("return\n"); this->img_out->set_itk(i2); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/segment/segment_body.h000066400000000000000000000025441321604176500311160ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _segment_body_h_ #define _segment_body_h_ #include "plmsegment_config.h" #include "itk_image_type.h" class Plm_image; class PLMSEGMENT_API Segment_body { public: Plm_image *img_in; Plm_image *img_out; bool m_bot_given; float m_bot; bool m_debug; bool m_fast; bool m_fill_holes; float m_lower_threshold; float m_upper_threshold; int m_fill_parms [6]; public: Segment_body () { m_bot_given = false; m_debug = false; m_fast = false; m_fill_holes = false; m_lower_threshold = -300; m_fill_parms[0]= 7; m_fill_parms[1]= 5; m_fill_parms[2]= 2; m_fill_parms[3]= 2; m_fill_parms[4]= 10; m_fill_parms[5]= 50; } void do_segmentation (); void do_segmentation_air_cavity(); FloatImageType::Pointer reduce_image_dim (FloatImageType::Pointer i1); UCharImageType::Pointer threshold_patient (FloatImageType::Pointer i1); int find_patient_bottom (FloatImageType::Pointer i1); UCharImageType::Pointer fill_holes (UCharImageType::Pointer mask, int radius, int max_its); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/000077500000000000000000000000001321604176500267475ustar00rootroot00000000000000BeamDataRFA.cxx000066400000000000000000000034321321604176500314050ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "BeamDataRFA.h" CBeamDataRFA::CBeamDataRFA() { m_ScanType = ST_UNKNOWN; m_BeamType = BT_UNKNOWN; m_fBeamEnergy = 6.0; m_fFieldSizeX_cm = 10.0; m_fFieldSizeY_cm = 10.0; m_fSSD_cm = 100.0; m_iWedgeType = 0; //Open Field m_fFixedPosX_mm = 0.0; //DICOM X, mm for PDD m_fFixedPosY_mm = 0.0; //DICOM Z, mm for PDD m_fFixedPosDepth_mm = 0.0; //Depth for PDD, vertical down is + m_fSAD_cm = 100.0;//fixed } CBeamDataRFA::~CBeamDataRFA() { m_vDoseProfile.clear(); } QString CBeamDataRFA::GetBeamName() { //enScanType scanType; //file name with extention //enBeamType beamType; //float m_fBeamEnergy; //float m_fFieldSizeX_cm; //float m_fFieldSizeY_cm; //float m_fSSD_cm; QString strScan, strBeamType, strEnergy, strFS, strDepth; switch (m_ScanType) { case ST_PDD: strScan = "PDD"; break; case ST_PROFILE_CR: strScan = "ProfileCr"; break; case ST_PROFILE_IN: strScan = "ProfileIn"; break; default: strScan = "Unknown"; break; } switch (m_BeamType) { case BT_PHOTON: strBeamType = "PHO"; break; case BT_ELECTRON: strBeamType = "ELE"; break; case BT_PROTON: strBeamType = "PRO"; break; default: strBeamType = "Unknown"; break; } strEnergy = QString::number(m_fBeamEnergy, 'f', 1); strFS.sprintf("%3.1fx%3.1f_cm2", m_fFieldSizeX_cm, m_fFieldSizeY_cm); strDepth.sprintf("d%3.1fcm", m_fFixedPosDepth_mm/10.0); QString finalStr = strBeamType + strEnergy + "_" + strScan + "_" + strFS; if (m_ScanType == ST_PROFILE_CR || m_ScanType == ST_PROFILE_IN) finalStr = finalStr + "_" + strDepth; return finalStr; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/BeamDataRFA.h000066400000000000000000000015171321604176500311130ustar00rootroot00000000000000#pragma once //#include "yk_config.h" #include #include #include using namespace std; enum enScanType{ ST_UNKNOWN = 0, ST_PDD, ST_PROFILE_CR, ST_PROFILE_IN, }; enum enBeamType{ BT_UNKNOWN = 0, BT_PHOTON, BT_ELECTRON, BT_PROTON, }; class CBeamDataRFA { public: enScanType m_ScanType; //file name with extention enBeamType m_BeamType; float m_fBeamEnergy; float m_fFieldSizeX_cm; float m_fFieldSizeY_cm; float m_fSSD_cm; float m_fSAD_cm; vector m_vDoseProfile; int m_iWedgeType; float m_fFixedPosX_mm; //DICOM X, mm for PDD float m_fFixedPosY_mm; //DICOM Z, mm for PDD float m_fFixedPosDepth_mm; //Depth for PDD, vertical down is + public: CBeamDataRFA(); ~CBeamDataRFA(); QString GetBeamName(); };CMakeLists.txt000066400000000000000000000245231321604176500314360ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_standalone) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (BEFORE ${CMAKE_CURRENT_BINARY_DIR}) include_directories (AFTER ${INIH_INCLUDE_DIR}) set (XVI_ARCHIVE_LIBRARIES ${PLASTIMATCH_LIBS} inih ) ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (BRAGG_CURVE_SRC bragg_curve_main.cxx bragg_curve_opts.cxx ) set (SOBP_SRC sobp_main.cxx ) set (BSPLINE_SRC bspline_main.cxx bspline_opts.cxx ) set (CHECK_GRAD_SRC check_grad.cxx ) set (COMPUTE_DISTANCE_SRC compute_distance.cxx closest_point.cxx read_obj.cxx ) set (CUDA_PROBE_SRC cuda_probe_main.cxx ) set (DEMONS_SRC demons_main.cxx demons_opts.cxx ) set (DICOM_INFO_SRC dicom_info.cxx ) set (DICOM_UID_SRC dicom_uid_main.cxx ) set (DLIB_TRAIN_SRC dlib_train.cxx ) set (DRR_SRC drr_main.cxx drr_opts.cxx ) set (FDK_SRC fdk_main.cxx fdk_opts.cxx ) set (HND_TO_PFM_SRC hnd_to_pfm.cxx ) set (LANDMARK_DIFF_SRC landmark_diff_main.cxx ) set (MERGE_VFS_SRC merge_vector_fields.cxx ) set (MEX_DRR_SRC mex_drr.c ) set (MHA_TO_RAW_SRC mha_to_raw.c ) #set (MHA_TO_RTOG_DOSE_SRC # mha_to_rtog_dose.cxx # ) set (OPENCL_PROBE_SRC opencl_probe_main.c opencl_probe.cxx ) if (OPENCL_FOUND) plm_add_opencl_file (OPENCL_PROBE_SRC opencl_probe.cl) endif () set (RAW_TO_MHA_SRC raw_to_mha.c ) #set (RTOG_TO_MHA_SRC # rtog_to_mha.cxx # ) set (VISCOUS_SRC viscous.cxx ) set (WED_SRC wed_main.cxx ) set (XVI_ARCHIVE_SRC xvi_archive.cxx ) set (GROUP_ADD_SRC group_add.cxx ) set (FILTER_SRC filter.cxx ) set (GAMMA_THRESH_SRC Gamma_Thresh.cxx ) set (FLIP_IMAGE_SRC flip_image.cxx ) set (DECOMP_VECTOR_SRC decomp_vector.cxx ) set (TEMPLATE_SRC Template.cxx ) set (FIND_CENTER_SRC find_center.cxx ) set (SHUFFLE_MHA_SRC shuffle_mha_main.cxx ) set (VF_INVERT_SRC vf_invert_main.cxx ) set (XF_TO_EMPIREFMT_SRC xf_to_empirefmt.cxx ) set (CMD_PROMPT_LAUNCHER_SRC cmd_prompt_launcher.cxx ) if (QT4_FOUND) set(nki2mha_converter_SRC nki2mha_converter_main.cpp nki2mha_converter.cpp nki2mha_converter.h) QT4_WRAP_CPP(nki2mha_converter_SRC nki2mha_converter.h) QT4_WRAP_UI(nki2mha_converter_SRC nki2mha_converter.ui) QT4_ADD_RESOURCES (nki2mha_converter_SRC nki2mha_converter.qrc) set(GAMMA_GUI_BASE_SRC gamma_gui_main.cpp gamma_gui.cpp gamma_gui.h qyklabel.h qyklabel.cpp DlgGammaView.h DlgGammaView.cxx YK16GrayImage.cxx YK16GrayImage.h qt_util.h qt_util.cxx qcustomplot.h qcustomplot.cpp yk_config.h) QT4_WRAP_CPP(GAMMA_GUI_MOC DlgGammaView.h qyklabel.h qcustomplot.h gamma_gui.h) QT4_WRAP_UI(GAMMA_GUI_UI gamma_gui.ui DlgGammaView.ui) set(GAMMA_GUI_SRC ${GAMMA_GUI_BASE_SRC} ${GAMMA_GUI_MOC} ${GAMMA_GUI_UI} ) # Don't compile the files which include generated headers until # generated headers are built. set_source_files_properties (${GAMMA_GUI_BASE_SRC} PROPERTIES OBJECT_DEPENDS "${GAMMA_GUI_UI}") set(REGISTER_GUI_SRC register_gui_main.cpp register_gui.cpp register_gui.h qyklabel.h qyklabel.cpp YK16GrayImage.cxx YK16GrayImage.h qt_util.h qt_util.cxx qcustomplot.h qcustomplot.cpp yk_config.h YKThreadRegi.h YKThreadRegi.cpp ) QT4_WRAP_CPP(REGISTER_GUI_SRC qyklabel.h qcustomplot.h register_gui.h YKThreadRegi.h) QT4_WRAP_UI(REGISTER_GUI_SRC register_gui.ui ) set(BEAMDATA_GEN_GUI_SRC beamdata_gen_gui.h beamdata_gen_gui.cpp beamdata_gen_gui_main.cpp qyklabel.h qyklabel.cpp YK16GrayImage.cxx YK16GrayImage.h qt_util.h qt_util.cxx qcustomplot.h qcustomplot.cpp yk_config.h BeamDataRFA.cxx BeamDataRFA.h ) QT4_WRAP_CPP(BEAMDATA_GEN_GUI_SRC beamdata_gen_gui.h qyklabel.h qcustomplot.h beamdata_gen_gui.h ) QT4_WRAP_UI(BEAMDATA_GEN_GUI_SRC beamdata_gen_gui.ui ) endif() ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- if (ITK_FOUND) plm_add_executable (compute_distance "${COMPUTE_DISTANCE_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (dicom_info "${DICOM_INFO_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (landmark_diff "${LANDMARK_DIFF_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (merge_vfs "${MERGE_VFS_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (shuffle_mha "${SHUFFLE_MHA_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) if (PLM_BUILD_VISCOUS) plm_add_executable (viscous "${VISCOUS_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) endif () plm_add_executable (vf_invert "${VF_INVERT_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_IF_NOT_DEBIAN}) plm_add_executable (wed "${WED_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) if (PLM_DCM_USE_DCMTK) plm_add_executable (xvi_archive "${XVI_ARCHIVE_SRC}" "${XVI_ARCHIVE_LIBRARIES}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) endif () plm_add_executable (group_add "${GROUP_ADD_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) if (COMMENT_OUT) plm_add_executable (gamma_thresh "${GAMMA_THRESH_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) endif () plm_add_executable (filter "${FILTER_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) if (COMMENT_OUT) plm_add_executable (flip_image "${FLIP_IMAGE_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (decomp_vector "${DECOMP_VECTOR_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (template "${TEMPLATE_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (find_center "${FIND_CENTER_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) endif () # plm_add_executable (xf_to_EMPIREFMT "${XF_TO_EMPIREFMT_SRC}" # "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" # ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) endif () if (QT4_FOUND) set (QT4_INCLUDE_DIRS ${QT_QTGUI_INCLUDE_DIR} ${QT_INCLUDE_DIR} ${QT_QTCORE_INCLUDE_DIR}) set (QT4_LIBRARIES ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY}) plm_add_executable_v2 (nki2mha_converter "${nki2mha_converter_SRC}" "${QT4_INCLUDE_DIRS}" "${PLASTIMATCH_LIBS};${QT4_LIBRARIES}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_IF_NOT_DEBIAN}) if (DCMTK_FOUND) plm_add_executable (gamma_gui "${GAMMA_GUI_SRC}" "${QT4_INCLUDE_DIRS}" "${PLASTIMATCH_LIBS};${QT4_LIBRARIES}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_IF_NOT_DEBIAN}) plm_add_executable (beamdata_gen_gui "${BEAMDATA_GEN_GUI_SRC}" "${QT4_INCLUDE_DIRS}" "${PLASTIMATCH_LIBS};${QT4_LIBRARIES}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_IF_NOT_DEBIAN}) endif () plm_add_executable (register_gui "${REGISTER_GUI_SRC}" "${QT4_INCLUDE_DIRS}" "${PLASTIMATCH_LIBS};${QT4_LIBRARIES}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_IF_NOT_DEBIAN}) endif() plm_add_executable (cmd_prompt_launcher "${CMD_PROMPT_LAUNCHER_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (bspline "${BSPLINE_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (check_grad "${CHECK_GRAD_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (demons "${DEMONS_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (dlib_train "${DLIB_TRAIN_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (drr "${DRR_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_ALWAYS}) plm_add_executable (fdk "${FDK_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_ALWAYS}) plm_add_executable (hnd_to_pfm "${HND_TO_PFM_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_IF_NOT_DEBIAN}) plm_add_executable (mha_to_raw "${MHA_TO_RAW_SRC}" "" "" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (raw_to_mha "${RAW_TO_MHA_SRC}" "" "" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (bragg_curve "${BRAGG_CURVE_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (sobp "${SOBP_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) if (CUDA_FOUND) plm_add_executable (cuda_probe "${CUDA_PROBE_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_IF_NOT_DEBIAN}) endif () if (MATLAB_FOUND) mex_target (mex_drr "${MEX_DRR_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}") endif () if (OPENCL_FOUND) plm_add_executable (opencl_probe "${OPENCL_PROBE_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_IF_NOT_DEBIAN}) endif () # dicom_uid requires dcmtk plm_add_executable (dicom_uid "${DICOM_UID_SRC}" "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_IF_NOT_DEBIAN}) Dew_Example.cfg000066400000000000000000000014131321604176500315420ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone# James Shackleford # 2012.08.22 # Example water equiv. depth configuration file # Modified 2013.03.06 by Justin Phillips [INPUT SETTINGS] patient=(Patient CT Volume) dose_wed=(WED Dose Volume) [OUTPUT SETTINGS] dose=(Inverse Output - Dose Volume) # pos: beam position in real world coordinates # isocenter: defines beam direction # res: step length when computing wed [BEAM] pos=-2270.5 10 50 isocenter=0 10 50 res=1 # center: center of aperture (mm) # offset: distance from beam nozzle (mm) # resolution: size of aperture in mm (# of pencil beams) # so there is 1 pencil beam per mm [APERTURE] offset=2070 center=50 130 resolution=100 200 [DEW VOLUME] #Example settings - output dimensions dew_dim=82 82 101 dew_origin=-73 -72.4 -63.8 dew_spacing=2. 2. 2.5DlgGammaView.cxx000066400000000000000000000005671321604176500317300ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "DlgGammaView.h" #include "gamma_gui.h" #define FIXME_BACKGROUND_MAX (-1200) using namespace std; DlgGammaView::DlgGammaView(): QDialog () { /* Sets up the GUI */ ui.setupUi (this); } DlgGammaView::DlgGammaView(QWidget *parent): QDialog (parent) { ui.setupUi (this); m_pParent = (gamma_gui*)(parent); } DlgGammaView::~DlgGammaView() { }DlgGammaView.h000066400000000000000000000006121321604176500313440ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#pragma once #include #include "ui_DlgGammaView.h" class gamma_gui; class DlgGammaView : public QDialog, public Ui::DlgGammaViewClass { Q_OBJECT ; public slots: public: DlgGammaView(); DlgGammaView(QWidget *parent); ~DlgGammaView(); public: gamma_gui* m_pParent; //to pull 3D images private: Ui::DlgGammaViewClass ui; }; DlgGammaView.ui000066400000000000000000001332441321604176500315420ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone DlgGammaViewClass 0 0 1120 823 Dialog true 20 40 512 512 true false QFrame::Box true 550 40 256 256 true false QFrame::Box true 550 340 256 256 true false QFrame::Box 30 650 381 131 210 10 161 22 10 0 131 31 14 Fixed Image 10 40 221 21 10000 10 100 2000 Qt::Horizontal 250 40 51 21 10000 100 2000 10 60 231 21 65535 10 100 1024 Qt::Horizontal 250 60 51 21 65535 100 1024 130 90 211 20 10 90 111 16 Origin (DICOM, mm) 310 40 21 16 W 310 60 21 16 L 130 10 61 21 Pass 430 650 381 131 220 10 151 22 10 0 131 31 14 Moving Image 10 40 221 21 10000 10 100 2000 Qt::Horizontal 250 40 51 21 10000 100 2000 10 60 231 21 65535 10 100 1024 Qt::Horizontal 250 60 51 21 65535 100 1024 130 90 201 20 10 90 111 16 Origin (DICOM, mm) 310 40 21 16 W 310 60 21 16 L 150 10 61 21 Pass 160 10 361 21 65535 1 10 Qt::Horizontal 640 310 161 21 65535 1 10 Qt::Horizontal 640 10 161 21 65535 1 10 Qt::Horizontal 30 560 511 81 50 60 61 21 160 60 61 21 280 60 61 21 350 60 51 21 GO 10 60 41 16 X (mm) 120 60 41 16 Y (mm) 230 60 41 16 Z (mm) 20 0 181 31 10 Current Position (DICOM) 210 10 70 17 Crosshair true 210 30 70 17 SplitView true 350 30 51 17 Zoom false 350 10 51 17 Pan true 420 10 81 31 Restore single 420 50 81 31 Restore all 30 10 101 16 12 Axial 540 10 91 21 12 Frontal 550 310 81 21 12 Sagittal 810 130 261 121 Manual registration 10 40 71 20 Moving origin 20 60 131 20 10 90 121 20 Moving resolution (mm) 140 90 41 20 1.0 90 20 51 23 Restore 10 20 81 17 Keyboard false 160 60 91 20 0.7,0.7,0.7 810 390 221 91 Plastimatch- rigid body 120 20 91 31 Do registration 20 60 101 16 Crop skin bf. DIR 130 60 41 20 8.0 180 60 21 16 mm 810 490 221 261 Plastimatch-deformable 10 20 81 20 Optimization 100 20 91 22 -1 90 200 91 23 Do registration 10 50 101 20 Arguments Step1 10 70 171 20 2,2,1,30,0.00001,0.005,30 10 100 101 20 Arguments Step2 10 120 171 20 10 150 101 20 Arguments Step3 10 170 171 20 90 230 91 23 Macro 550 600 91 41 Chage View 810 10 221 111 Prepare CT 10 30 101 17 Crop bkground true 10 50 71 17 Fill bubble false 120 80 91 23 Process 110 50 41 20 -600 110 10 41 16 Detect 170 10 41 16 Fill 160 30 41 20 -1024 160 50 41 20 0 120 30 31 16 skin 810 260 221 111 Prepare CBCT 10 30 101 17 Crop bkground true 10 50 71 17 Fill bubble false 160 50 41 20 700 110 10 41 16 Detect 110 50 41 20 500 170 10 21 16 Fill 160 30 41 20 0 120 30 31 16 skin 10 80 101 16 Crop skin bf. regid 130 80 41 20 10.0 180 80 21 16 mm 980 150 61 23 Gradient qyklabel QLabel
qyklabel.h
SetDrawPointToggle(bool)
pushButtonCurPosGo released() DlgGammaViewClass SLT_CrntPosGo() 412 634 555 633 sliderPosDisp1 valueChanged(int) DlgGammaViewClass SLT_DrawImageWhenSliceChange() 165 22 118 17 sliderPosDisp2 valueChanged(int) DlgGammaViewClass SLT_DrawImageWhenSliceChange() 735 20 817 22 sliderPosDisp3 valueChanged(int) DlgGammaViewClass SLT_DrawImageWhenSliceChange() 695 317 808 305 sliderFixedW valueChanged(int) DlgGammaViewClass SLT_DrawImageInFixedSlice() 46 697 16 697 sliderFixedL valueChanged(int) DlgGammaViewClass SLT_DrawImageInFixedSlice() 43 723 14 731 sliderMovingW valueChanged(int) DlgGammaViewClass SLT_DrawImageInFixedSlice() 458 696 423 701 sliderMovingL valueChanged(int) DlgGammaViewClass SLT_DrawImageInFixedSlice() 456 721 420 733 sliderFixedW valueChanged(int) spinBoxFixedW setValue(int) 254 698 284 697 spinBoxFixedW valueChanged(int) sliderFixedW setValue(int) 300 693 240 694 sliderFixedL valueChanged(int) spinBoxFixedL setValue(int) 228 716 297 716 spinBoxFixedL valueChanged(int) sliderFixedL setValue(int) 296 727 256 728 sliderMovingW valueChanged(int) spinBoxMovingW setValue(int) 655 701 689 699 sliderMovingL valueChanged(int) spinBoxMovingL setValue(int) 667 722 683 722 spinBoxMovingL valueChanged(int) sliderMovingL setValue(int) 710 727 647 728 spinBoxMovingW valueChanged(int) sliderMovingW setValue(int) 686 697 659 697 pushButtonChangeView released() DlgGammaViewClass SLT_ChangeView() 597 608 638 612 checkBoxDrawCrosshair released() DlgGammaViewClass SLT_DrawImageWhenSliceChange() 281 584 256 563 pushButtonRestoreSingle released() DlgGammaViewClass SLT_RestoreImageSingle() 529 585 541 552 pushButtonRestoreAll released() DlgGammaViewClass SLT_RestoreImageAll() 508 632 537 648 pushButtonDoRigid released() DlgGammaViewClass SLT_DoRegistrationRigid() 935 268 828 303 checkBoxKeyMoving toggled(bool) DlgGammaViewClass SLT_BringFocusToEnableArrow(bool) 900 150 1012 20 checkBoxKeyMoving toggled(bool) DlgGammaViewClass SLT_KeyMoving(bool) 900 150 1019 69 comboBoxImgFixed currentIndexChanged(QString) DlgGammaViewClass SLT_FixedImageSelected(QString) 381 663 387 792 comboBoxImgMoving currentIndexChanged(QString) DlgGammaViewClass SLT_MovingImageSelected(QString) 780 674 822 721 pushButtonRestoreOriginal released() DlgGammaViewClass SLT_RestoreMovingImg() 1003 170 968 0 pushButtonDoDeformable released() DlgGammaViewClass SLT_DoRegistrationDeform() 948 690 951 584 pushButtonProcessCT released() DlgGammaViewClass SLT_PreProcessCT() 952 93 1008 119 pushButtonPassFixed released() DlgGammaViewClass SLT_PassFixedImgForAnalysis() 190 672 18 640 pushButtonPassMoving released() DlgGammaViewClass SLT_PassMovingImgForAnalysis() 613 670 667 625 pushButtonMacro released() DlgGammaViewClass SLT_Macro() 946 734 948 757 pushButtonGradSearch released() DlgGammaViewClass SLT_DoRegistrationGradient() 940 159 1039 171 SLT_CrntPosGo() SLT_DrawImageWhenSliceChange() SLT_DrawImageInFixedSlice() SLT_ChangeView() SLT_RestoreImageSingle() SLT_RestoreImageAll() SLT_DoRegistrationRigid() SLT_BringFocusToEnableArrow(bool) SLT_KeyMoving(bool) SLT_FixedImageSelected(QString) SLT_MovingImageSelected(QString) SLT_RestoreMovingImg() SLT_DoRegistrationDeform() SLT_PreProcessCT() SLT_PreProcessCBCT() SLT_PassFixedImgForAnalysis() SLT_PassMovingImgForAnalysis() SLT_Macro() SLT_ExchangeRawRef() SLT_DoRegistrationGradient()
Launch_cmd_prompt.bat000066400000000000000000000017731321604176500330260ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standaloneset target_file_a=C:\Windows\system32\cmd.exe @echo off set SCRIPT="%TEMP%\%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.vbs" echo Set oWS = WScript.CreateObject("WScript.Shell") >> %SCRIPT% echo sLinkFile = "%ALLUSERSPROFILE%\Desktop\plastimatch32_cmd.lnk" >> %SCRIPT% echo Set oLink = oWS.CreateShortcut(sLinkFile) >> %SCRIPT% echo oLink.TargetPath = "%target_file_a%" >> %SCRIPT% echo oLink.WorkingDirectory = "%~dp0" >> %SCRIPT% echo oLink.Save >> %SCRIPT% cscript /nologo %SCRIPT% del %SCRIPT% set SCRIPT2="%TEMP%\%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.vbs" echo Set oWS = WScript.CreateObject("WScript.Shell") >> %SCRIPT2% echo sLinkFile = "%~dp0\plastimatch32_cmd.lnk" >> %SCRIPT2% echo Set oLink = oWS.CreateShortcut(sLinkFile) >> %SCRIPT2% echo oLink.TargetPath = "%target_file_a%" >> %SCRIPT2% echo oLink.WorkingDirectory = "%~dp0" >> %SCRIPT2% echo oLink.Save >> %SCRIPT2% cscript /nologo %SCRIPT2% del %SCRIPT2% start "" http://plastimatch.org/contents.html %SystemRoot%\explorer.exe "%~dp0" Wed_Example.cfg000066400000000000000000000013171321604176500315450ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone# James Shackleford # 2012.08.22 # Example water equiv. depth configuration file # Modified 2013.03.06 by Justin Phillips [INPUT SETTINGS] patient=(Patient CT Volume) dose=(Input - Dose Volume) [OUTPUT SETTINGS] patient_wed=(Output - WED converted CT Volume) dose_wed=(Output - WED converted Dose Volume) # pos: beam position in real world coordinates # isocenter: defines beam direction # res: step length when computing wed [BEAM] pos=-2270.5 10 50 isocenter=0 10 50 res=1 # center: center of aperture (mm) # offset: distance from beam nozzle (mm) # resolution: size of aperture in mm (# of pencil beams) # so there is 1 pencil beam per mm [APERTURE] offset=2070 center=50 100 resolution=100 200 YK16GrayImage.cxx000066400000000000000000002025471321604176500317060ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "YK16GrayImage.h" #include #include #include #include #include #include "itkImageRegionIterator.h" #include "itkMedianImageFilter.h" #include "itkIdentityTransform.h" #include "itkResampleImageFilter.h" #include "itkAffineTransform.h" #include "itkNearestNeighborInterpolateImageFunction.h" #include "itkFlipImageFilter.h" #include #include "qt_util.h" using namespace std; YK16GrayImage::YK16GrayImage(void) { m_iWidth = 0; m_iHeight = 0; m_pData = NULL; m_pPixmap = NULL;// for display m_pElektaHisHeader = NULL; //m_pQImage = NULL; //m_pPainter = NULL; m_fPixelMean = 0.0; m_fPixelSD= 0.0; m_fPixelMin = 0.0; m_fPixelMax= 0.0; m_fPixelMean_ROI = 0.0; m_fPixelSD_ROI = 0.0; m_fPixelMin_ROI = 0.0; m_fPixelMax_ROI = 0.0; m_bDrawROI = false; m_bShowInvert = false; m_fSpacingX = 0.0; m_fSpacingY = 0.0; m_fOriginX = 0.0; m_fOriginY = 0.0; m_ptProfileProbe.setX(0); //Mouse Clicked Position --> Data m_ptProfileProbe.setY(0); m_bDrawProfileX = false; m_bDrawProfileY = false; m_ptFOVCenter.setX(0); m_ptFOVCenter.setY(0); m_iFOVRadius = 0;//data pixel m_bDrawFOVCircle = false; m_iTableTopPos = 0; m_bDrawTableLine = false; m_bDrawCrosshair = false; m_fZoom = 1.0; m_iOffsetX = 0; m_iOffsetY = 0; m_strTimeStamp = "00000000"; //9 digits HHMMSSFFF m_bDrawMarkers = false; m_bDrawMarkersRef = false; m_iNumOfDispMarker = -1; m_iNumOfTrackMarker = -1; m_track_priorErr = 0.0; m_track_motionErr = 0.0; //m_track_motionWtX = 0.0; //m_track_motionWtY = 0.0; m_fMVGantryAngle = 0.0; m_fPanelOffsetX = 0.0; //mm m_fPanelOffsetY = 0.0;//mm m_bKVOn = true;//default value: should be on otherwise doesn't work in simulation mode m_bMVOn = false; m_iXVI_ElapseMS = 0; m_iProcessingElapsed = 0; m_track_CC_penalty = 0.0; m_bDraw8Bit = false; m_fIntensityMag = 1.0;//intensity magnification factor default = 1.0; m_fIntensityOffset = 0.0;//intensity Offset factor default = 0.0; m_bDrawOverlayText = false; //m_bDrawContours = false; m_fNormValue = -1.0; } YK16GrayImage::YK16GrayImage(int width, int height) { m_pData = NULL; m_pPixmap = NULL;// for display m_pElektaHisHeader = NULL; m_fPixelMean = 0.0; m_fPixelSD = 0.0; m_fPixelMin = 0.0; m_fPixelMax = 0.0; m_fPixelMean_ROI = 0.0; m_fPixelSD_ROI = 0.0; m_fPixelMin_ROI = 0.0; m_fPixelMax_ROI = 0.0; m_bDrawROI = false; m_bShowInvert = false; m_fSpacingX = 0.0; m_fSpacingY = 0.0; m_fOriginX = 0.0; m_fOriginY = 0.0; m_ptProfileProbe.setX(0); //Mouse Clicked Position --> Data m_ptProfileProbe.setY(0); m_bDrawProfileX = false; m_bDrawProfileY = false; m_ptFOVCenter.setX(0); m_ptFOVCenter.setY(0); m_iFOVRadius = 0;//data pixel m_bDrawFOVCircle = false; m_iTableTopPos = 0; m_bDrawTableLine = false; m_bDrawCrosshair = false; m_fZoom = 1.0; m_iOffsetX = 0; m_iOffsetY = 0; m_strTimeStamp = "00000000"; //9 digits HHMMSSFFF m_iWidth = width; m_iHeight = height; CreateImage(width, height, 0); m_bDrawMarkers = false; m_bDrawMarkersRef = false; m_iNumOfDispMarker = -1; m_iNumOfTrackMarker = -1; m_track_priorErr = 0.0; m_track_motionErr = 0.0; //m_track_motionWtX = 0.0; //m_track_motionWtY = 0.0; m_track_CC_penalty = 0.0; m_fMVGantryAngle = 0.0; m_fPanelOffsetX = 0.0; //mm m_fPanelOffsetY = 0.0;//mm m_bKVOn = true; m_bMVOn = false; m_iXVI_ElapseMS = 0; m_iProcessingElapsed = 0; m_track_CC_penalty = 0.0; m_bDraw8Bit = false; //m_bDrawContours = false; m_fIntensityMag = 1.0;//intensity magnification factor default = 1.0; m_fIntensityOffset = 0.0;//intensity Offset factor default = 0.0; m_bDrawOverlayText = false; m_fNormValue = -1.0; } YK16GrayImage::~YK16GrayImage(void) { ReleaseBuffer(); } bool YK16GrayImage::ReleaseBuffer() { if (m_pData != NULL) { delete [] m_pData; m_pData = NULL; } if (m_pPixmap != NULL) { delete m_pPixmap; //delete m_pPixmap?? m_pPixmap = NULL; } m_iWidth = 0; m_iHeight = 0; if (m_pElektaHisHeader!= NULL) { delete [] m_pElektaHisHeader; m_pElektaHisHeader= NULL; } m_vMarker.clear(); m_vMarkerRef.clear(); //m_vContourROI.clear(); ClearContourROI(); m_strOverlayText = ""; m_fNormValue = -1.0; return true; } bool YK16GrayImage::IsEmpty() { if (m_pData == NULL) return true; else return false; } bool YK16GrayImage::CreateImage(int width, int height, unsigned short usVal) { if (width < 1 || height < 1) return false; if (usVal < 0 || usVal > 65535) usVal = 0; //if (m_pData != NULL) //delete [] m_pData; ReleaseBuffer(); m_iWidth = width; m_iHeight = height; int imgSize = width*height; m_pData = new unsigned short [imgSize]; for (int i = 0 ; i= uppVal) { //QRgb rgbVal = qRgb(255, 255, 255); //m_QImage.setPixel(j,i,qRgb(255, 255, 255)); tmpData[tmpIdx+0] = 255; tmpData[tmpIdx+1] = 255; tmpData[tmpIdx+2] = 255; } else if (m_pData[i*m_iWidth+j] <= lowVal) { tmpData[tmpIdx+0] = 0; tmpData[tmpIdx+1] = 0; tmpData[tmpIdx+2] = 0; //QRgb rgbVal = qRgb(0, 0, 0); //m_QImage.setPixel(j,i,qRgb(0, 0, 0)); } else { tmpData[tmpIdx+0] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal)/(double)winWidth * 255.0); //success tmpData[tmpIdx+1] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal)/(double)winWidth * 255.0); //success tmpData[tmpIdx+2] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal)/(double)winWidth * 255.0); //success } } else { if (m_pData[i*m_iWidth+j] >= uppVal) { //QRgb rgbVal = qRgb(255, 255, 255); //m_QImage.setPixel(j,i,qRgb(255, 255, 255)); tmpData[tmpIdx+0] = 0; tmpData[tmpIdx+1] = 0; tmpData[tmpIdx+2] = 0; } else if (m_pData[i*m_iWidth+j] <= lowVal) { tmpData[tmpIdx+0] = 255; tmpData[tmpIdx+1] = 255; tmpData[tmpIdx+2] = 255; //QRgb rgbVal = qRgb(0, 0, 0); //m_QImage.setPixel(j,i,qRgb(0, 0, 0)); } else { tmpData[tmpIdx+0] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal)/(double)winWidth * 255.0); //success tmpData[tmpIdx+1] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal)/(double)winWidth * 255.0); //success tmpData[tmpIdx+2] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal)/(double)winWidth * 255.0); //success } } } } ///m_QImage.save("C:\\FromFillPixmap.png");//it works well int iBytesPerLine = m_iWidth*3; QImage tmpQImage = QImage((unsigned char*)tmpData,m_iWidth, m_iHeight,iBytesPerLine, QImage::Format_RGB888); //not deep copy! //image ratio (width / height) should be kept constant. //PAN: center of image is moving //m_QImage = tmpQImage.copy(0,0,m_iWidth, m_iHeight); //memory allocated here!!! int newWidth = qRound(m_iWidth/m_fZoom); int newHeight = qRound(m_iHeight/m_fZoom); int centerX = m_iOffsetX + qRound(m_iWidth/2.0); int centerY = m_iOffsetY + qRound(m_iHeight/2.0); int newLeftTopX = centerX - qRound(newWidth/2.0); int newLeftTopY = centerY - qRound(newHeight/2.0); m_QImage = tmpQImage.copy(qRound(newLeftTopX), qRound(newLeftTopY), newWidth, newHeight); //memory allocated here!!! delete [] tmpData; return true; } void YK16GrayImage::SetNormValueOriginal(float normval) { m_fNormValue = normval; } //normval = Gy bool YK16GrayImage::FillPixMapDose() { if (m_pData == NULL) return false; if (m_fNormValue <= 0.0) return false; int size = m_iWidth*m_iHeight; uchar* tmpData = new uchar[size * 3];//RGB unsigned short curVal = 0; float originalVal = 0.0; float percVal = 0.0; for (int i = 0; i < m_iHeight; i++) //So long time.... { for (int j = 0; j < m_iWidth; j++) { curVal = m_pData[i*m_iWidth + j]; originalVal = GetOriginalIntensityVal(curVal); percVal = originalVal / m_fNormValue*100.0; //use lookup table QColor colorVal = GetColorFromDosePerc(percVal); int tmpIdx = 3 * (i*m_iWidth + j); tmpData[tmpIdx + 0] = colorVal.red(); tmpData[tmpIdx + 1] = colorVal.green(); tmpData[tmpIdx + 2] = colorVal.blue(); } } int iBytesPerLine = m_iWidth * 3; QImage tmpQImage = QImage((unsigned char*)tmpData, m_iWidth, m_iHeight, iBytesPerLine, QImage::Format_RGB888); //not deep copy! //image ratio (width / height) should be kept constant. //PAN: center of image is moving //m_QImage = tmpQImage.copy(0,0,m_iWidth, m_iHeight); //memory allocated here!!! int newWidth = qRound(m_iWidth / m_fZoom); int newHeight = qRound(m_iHeight / m_fZoom); int centerX = m_iOffsetX + qRound(m_iWidth / 2.0); int centerY = m_iOffsetY + qRound(m_iHeight / 2.0); int newLeftTopX = centerX - qRound(newWidth / 2.0); int newLeftTopY = centerY - qRound(newHeight / 2.0); m_QImage = tmpQImage.copy(qRound(newLeftTopX), qRound(newLeftTopY), newWidth, newHeight); //memory allocated here!!! delete[] tmpData; return true; } //normval = Gy bool YK16GrayImage::FillPixMapDose(float normval) { if (m_pData == NULL) return false; if (normval <= 0.0) return false; int size = m_iWidth*m_iHeight; uchar* tmpData = new uchar[size * 3];//RGB unsigned short curVal = 0; float originalVal = 0.0; float percVal = 0.0; for (int i = 0; i < m_iHeight; i++) //So long time.... { for (int j = 0; j < m_iWidth; j++) { curVal = m_pData[i*m_iWidth + j]; originalVal = GetOriginalIntensityVal(curVal); percVal = originalVal / normval*100.0; //use lookup table QColor colorVal = GetColorFromDosePerc(percVal); int tmpIdx = 3 * (i*m_iWidth + j); tmpData[tmpIdx + 0] = colorVal.red(); tmpData[tmpIdx + 1] = colorVal.green(); tmpData[tmpIdx + 2] = colorVal.blue(); } } int iBytesPerLine = m_iWidth * 3; QImage tmpQImage = QImage((unsigned char*)tmpData, m_iWidth, m_iHeight, iBytesPerLine, QImage::Format_RGB888); //not deep copy! //image ratio (width / height) should be kept constant. //PAN: center of image is moving //m_QImage = tmpQImage.copy(0,0,m_iWidth, m_iHeight); //memory allocated here!!! int newWidth = qRound(m_iWidth / m_fZoom); int newHeight = qRound(m_iHeight / m_fZoom); int centerX = m_iOffsetX + qRound(m_iWidth / 2.0); int centerY = m_iOffsetY + qRound(m_iHeight / 2.0); int newLeftTopX = centerX - qRound(newWidth / 2.0); int newLeftTopY = centerY - qRound(newHeight / 2.0); m_QImage = tmpQImage.copy(qRound(newLeftTopX), qRound(newLeftTopY), newWidth, newHeight); //memory allocated here!!! delete[] tmpData; return true; } bool YK16GrayImage::FillPixMapGamma() { if (m_pData == NULL) return false; int size = m_iWidth*m_iHeight; uchar* tmpData = new uchar[size * 3];//RGB unsigned short curVal = 0; float originalVal = 0.0; float percVal = 0.0; for (int i = 0; i < m_iHeight; i++) //So long time.... { for (int j = 0; j < m_iWidth; j++) { if (i == 10 && j == qRound(m_iWidth / 2.0)) int aa = 5; curVal = m_pData[i*m_iWidth + j]; originalVal = GetOriginalIntensityVal(curVal); //use lookup table QColor colorVal = GetColorFromGamma(originalVal); //originalVal is always 0 or 1 now /* if (originalVal > 0 && originalVal < 1) { cout << "number is = " << originalVal << " " << curVal << " " << m_fIntensityMag << endl; }*/ int tmpIdx = 3 * (i*m_iWidth + j); tmpData[tmpIdx + 0] = colorVal.red(); tmpData[tmpIdx + 1] = colorVal.green(); tmpData[tmpIdx + 2] = colorVal.blue(); } } int iBytesPerLine = m_iWidth * 3; QImage tmpQImage = QImage((unsigned char*)tmpData, m_iWidth, m_iHeight, iBytesPerLine, QImage::Format_RGB888); //not deep copy! //image ratio (width / height) should be kept constant. //PAN: center of image is moving //m_QImage = tmpQImage.copy(0,0,m_iWidth, m_iHeight); //memory allocated here!!! int newWidth = qRound(m_iWidth / m_fZoom); int newHeight = qRound(m_iHeight / m_fZoom); int centerX = m_iOffsetX + qRound(m_iWidth / 2.0); int centerY = m_iOffsetY + qRound(m_iHeight / 2.0); int newLeftTopX = centerX - qRound(newWidth / 2.0); int newLeftTopY = centerY - qRound(newHeight / 2.0); m_QImage = tmpQImage.copy(qRound(newLeftTopX), qRound(newLeftTopY), newWidth, newHeight); //memory allocated here!!! delete[] tmpData; return true; } bool YK16GrayImage::FillPixMapMinMax(int winMin, int winMax) //0-65535 Áß window level { if (winMin < 0 || winMax > 65535 || winMin > winMax) { winMin = 0; winMax = 65535; } int midVal = (int)((winMin + winMax)/2.0); int widthVal = winMax - winMin; return FillPixMap(midVal, widthVal); } bool YK16GrayImage::SaveDataAsRaw (const char *filePath) //save 16 bit gray raw file { if (m_pData == NULL) return false; int imgSize = m_iWidth*m_iHeight; FILE* fd = NULL; fd = fopen(filePath, "wb"); for (int i = 0 ; iwidth(); // int height = lbDisplay->height(); // // double ratio =m_pPixmap->width() / (double)width; // int newHeight = m_pPixmap->height() / ratio; // // //m_pPixmap->scaled(wid,showHeght,Qt::IgnoreAspectRatio) // //lbDisplay->setPixmap(m_pPixmap->scaled(width, height, Qt::IgnoreAspectRatio)); // lbDisplay->setPixmap(m_pPixmap->scaled(width, newHeight, Qt::IgnoreAspectRatio)); // // /*int w = m_QImage.width(); // int h = m_QImage.height();*/ // //bool result = m_QImage.save("C:\\abcdefg.png"); // // return true; //} // //bool YK16GrayImage::CalcImageInfo (double& meanVal, double& STDV, double& minVal, double& maxVal) //{ // if (m_pData == NULL) // return false; // // int nTotal; // long minPixel, maxPixel; // int i; // double pixel, sumPixel; // // int npixels = m_iWidth*m_iHeight; // nTotal = 0; // //minPixel = 4095; // minPixel = 65535; // maxPixel = 0; // sumPixel = 0.0; // // for (i = 0; i < npixels; i++) // { // pixel = (double) m_pData[i]; // sumPixel += pixel; // if (m_pData[i] > maxPixel) // maxPixel = m_pData[i]; // if (m_pData[i] < minPixel) // minPixel = m_pData[i]; // nTotal++; // } // // double meanPixelval = sumPixel / (double)nTotal; // // double sqrSum = 0.0; // for (i = 0; i < npixels; i++) // { // sqrSum = sqrSum + pow(((double)m_pData[i] - meanPixelval),2.0); // } // double SD = sqrt(sqrSum/(double)nTotal); // // meanVal = meanPixelval; // STDV = SD; // minVal = minPixel; // maxVal = maxPixel; // // return true; //} // bool YK16GrayImage::CalcImageInfo () { if (m_pData == NULL) return false; int nTotal; long minPixel, maxPixel; int i; double pixel, sumPixel; int npixels = m_iWidth*m_iHeight; if (npixels <= 0) return false; nTotal = 0; //minPixel = 4095; minPixel = 65535; maxPixel = 0; sumPixel = 0.0; for (i = 0; i < npixels; i++) { pixel = (double) m_pData[i]; sumPixel += pixel; if (m_pData[i] > maxPixel) maxPixel = m_pData[i]; if (m_pData[i] < minPixel) minPixel = m_pData[i]; nTotal++; } double meanPixelval = 0.0; if (nTotal <= 0) meanPixelval = 0.0; else meanPixelval = sumPixel / (double)nTotal; double sqrSum = 0.0; for (i = 0; i < npixels; i++) { sqrSum = sqrSum + pow(((double)m_pData[i] - meanPixelval),2.0); } double SD = sqrt(sqrSum/(double)nTotal); m_fPixelMean = meanPixelval; m_fPixelSD = SD; m_fPixelMin = minPixel; m_fPixelMax = maxPixel; return true; } double YK16GrayImage::CalcAveragePixelDiff(YK16GrayImage& other) { if (m_pData == NULL || other.m_pData == NULL) return 0.0; int totalPixCnt = m_iWidth * m_iHeight; double tmpSum = 0.0; for (int i = 0 ; i& vPixelMapping ) //{ // if (vPixelMapping.empty()) // return false; // // if (m_pData == NULL) // return false; // // // // int oriIdx, replIdx; // // vector::iterator it; // // for (it = vPixelMapping.begin() ; it != vPixelMapping.end() ; it++) // { // BADPIXELMAP tmpData= (*it); // oriIdx = tmpData.BadPixY * m_iWidth + tmpData.BadPixX; // replIdx = tmpData.ReplPixY * m_iWidth + tmpData.ReplPixX; // m_pData[oriIdx] = m_pData[replIdx]; // } // // // // return true; //} // //void YK16GrayImage::CopyYKImage2ItkImage(YK16GrayImage* pYKImage, UnsignedShortImageType::Pointer& spTarImage) //{ // if (pYKImage == NULL) // return; // //Raw File open // //UnsignedShortImageType::SizeType tmpSize = // UnsignedShortImageType::RegionType region = spTarImage->GetRequestedRegion(); // UnsignedShortImageType::SizeType tmpSize = region.GetSize(); // // int sizeX = tmpSize[0]; // int sizeY = tmpSize[1]; // // if (sizeX < 1 || sizeY <1) // return; // // itk::ImageRegionIterator it(spTarImage, region); // // int i = 0; // for (it.GoToBegin() ; !it.IsAtEnd(); it++) // { // it.Set(pYKImage->m_pData[i]); // i++; // } // //int totCnt = i; // //writerType::Pointer writer = writerType::New(); // //writer->SetInput(spTarImage); // //writer->SetFileName("C:\\ThisImageIs_spSrcImage.png"); //It works! // //writer->Update(); //} //void YK16GrayImage::CopyItkImage2YKImage(UnsignedShortImageType::Pointer& spSrcImage, YK16GrayImage* pYKImage) //{ // if (pYKImage == NULL) // return; // //Raw File open // //UnsignedShortImageType::SizeType tmpSize = // UnsignedShortImageType::RegionType region = spSrcImage->GetRequestedRegion(); // UnsignedShortImageType::SizeType tmpSize = region.GetSize(); // // int sizeX = tmpSize[0]; // int sizeY = tmpSize[1]; // // if (sizeX < 1 || sizeY <1) // return; // // //itk::ImageRegionConstIterator it(spSrcImage, region); // itk::ImageRegionIterator it(spSrcImage, region); // // int i = 0; // for (it.GoToBegin() ; !it.IsAtEnd() ; it++) // { // pYKImage->m_pData[i] = it.Get(); // i++; // } // //int totCnt = i; //Total Count is OK // // //int width = pYKImage->m_iWidth; // //int height = pYKImage->m_iHeight; // // // //writerType::Pointer writer = writerType::New(); // //writer->SetInput(spSrcImage); // //writer->SetFileName("C:\\ThisImageIs_spSrcImage2.png"); //It works! // //writer->Update(); //} void YK16GrayImage::Swap(YK16GrayImage* pImgA, YK16GrayImage* pImgB) { if (pImgA == NULL || pImgB == NULL ) return; if (pImgA->IsEmpty() || pImgB->IsEmpty() ) return; YK16GrayImage tmpImg(pImgA->m_iWidth, pImgB->m_iHeight); tmpImg.CopyFromBuffer(pImgA->m_pData,pImgA->m_iWidth, pImgA->m_iHeight); tmpImg.m_strFilePath = pImgA->m_strFilePath; pImgA->CopyFromBuffer(pImgB->m_pData,pImgB->m_iWidth, pImgB->m_iHeight); pImgA->m_strFilePath = pImgB->m_strFilePath; pImgB->CopyFromBuffer(tmpImg.m_pData,tmpImg.m_iWidth, tmpImg.m_iHeight); pImgB->m_strFilePath = tmpImg.m_strFilePath; } bool YK16GrayImage::SaveDataAsHis( const char *filePath, bool bInverse ) { if (m_pData == NULL) return false; if (m_pElektaHisHeader ==NULL) return false; FILE* fd = NULL; fd = fopen(filePath, "wb"); fwrite(m_pElektaHisHeader, 100, 1, fd); int imgSize = m_iWidth*m_iHeight; for (int i = 0 ; iIsEmpty() || pImgB->IsEmpty() ) // return; // // YK16GrayImage tmpImg(pImgA->m_iWidth, pImgB->m_iHeight); // tmpImg.CopyFromBuffer(pImgA->m_pData,pImgA->m_iWidth, pImgA->m_iHeight); // tmpImg.m_strFilePath = pImgA->m_strFilePath; // // pImgA->CopyFromBuffer(pImgB->m_pData,pImgB->m_iWidth, pImgB->m_iHeight); // pImgA->m_strFilePath = pImgB->m_strFilePath; // // // pImgB->CopyFromBuffer(tmpImg.m_pData,tmpImg.m_iWidth, tmpImg.m_iHeight); // pImgB->m_strFilePath = tmpImg.m_strFilePath; //} void YK16GrayImage::CopyYKImage2ItkImage(YK16GrayImage* pYKImage, UnsignedShortImageType::Pointer& spTarImage) { if (pYKImage == NULL) return; //Raw File open //UnsignedShortImageType::SizeType tmpSize = UnsignedShortImageType::RegionType region = spTarImage->GetRequestedRegion(); UnsignedShortImageType::SizeType tmpSize = region.GetSize(); int sizeX = tmpSize[0]; int sizeY = tmpSize[1]; if (sizeX < 1 || sizeY <1) return; if (sizeX != pYKImage->m_iWidth || sizeY != pYKImage->m_iHeight) { cout << "ERRROR! IN CopyYKImage2ItkImage. Image size should be matched" << endl; return; } itk::ImageRegionIterator it(spTarImage, region); int i = 0; for (it.GoToBegin() ; !it.IsAtEnd(); ++it) { it.Set(pYKImage->m_pData[i]); i++; } UnsignedShortImageType::SpacingType sp; sp[0] = pYKImage->m_fSpacingX; sp[1] = pYKImage->m_fSpacingY; spTarImage->SetSpacing(sp); //int totCnt = i; //writerType::Pointer writer = writerType::New(); //writer->SetInput(spTarImage); //writer->SetFileName("C:\\ThisImageIs_spSrcImage.png"); //It works! //writer->Update(); } void YK16GrayImage::CopyItkImage2YKImage(UnsignedShortImageType::Pointer& spSrcImage, YK16GrayImage* pYKImage) { if (pYKImage == NULL) return; //Raw File open //UnsignedShortImageType::SizeType tmpSize = UnsignedShortImageType::RegionType region = spSrcImage->GetRequestedRegion(); UnsignedShortImageType::SizeType tmpSize = region.GetSize(); int sizeX = tmpSize[0]; int sizeY = tmpSize[1]; if (sizeX < 1 || sizeY <1) return; if (sizeX != pYKImage->m_iWidth || sizeY != pYKImage->m_iHeight) { cout << "ERRROR! IN CopyItkImage2YKImage. Image size should be matched" << endl; return; } //itk::ImageRegionConstIterator it(spSrcImage, region); itk::ImageRegionIterator it(spSrcImage, region); int i = 0; for (it.GoToBegin() ; !it.IsAtEnd() ; ++it) { pYKImage->m_pData[i] = it.Get(); i++; } pYKImage->SetSpacing(spSrcImage->GetSpacing()[0], spSrcImage->GetSpacing()[1]); //int totCnt = i; //Total Count is OK //int width = pYKImage->m_iWidth; //int height = pYKImage->m_iHeight; //writerType::Pointer writer = writerType::New(); //writer->SetInput(spSrcImage); //writer->SetFileName("C:\\ThisImageIs_spSrcImage2.png"); //It works! //writer->Update(); } bool YK16GrayImage::CalcImageInfo_ROI() { if (m_pData == NULL) { m_fPixelMean_ROI =-1.0; m_fPixelSD_ROI=-1.0; m_fPixelMin_ROI=-1.0; m_fPixelMax_ROI=-1.0; return false; } if (m_rtROI.width() < 1 || m_rtROI.height() < 1) { m_fPixelMean_ROI =-1.0; m_fPixelSD_ROI=-1.0; m_fPixelMin_ROI=-1.0; m_fPixelMax_ROI=-1.0; return false; } int nTotal; long minPixel, maxPixel; double pixel, sumPixel; int npixels = m_iWidth*m_iWidth; nTotal = 0; //minPixel = 4095; minPixel = 65535; maxPixel = 0; sumPixel = 0.0; int i,j; for (i =m_rtROI.top() ; i maxPixel) maxPixel = m_pData[idx]; if (m_pData[idx] < minPixel) minPixel = m_pData[idx]; nTotal++; } } double meanPixelval = sumPixel / (double)nTotal; double sqrSum = 0.0; /*for (i = 0; i < nTotal; i++) { sqrSum = sqrSum + pow(((double)m_pData[i] - meanPixelval),2.0); }*/ for (i =m_rtROI.top() ; i= right || top >= bottom || left < 0 || right > m_iWidth-1 || top <0 || bottom > m_iHeight-1) { m_rtROI.setLeft(0); m_rtROI.setTop(0); m_rtROI.setRight(m_iWidth-1); m_rtROI.setBottom(m_iHeight-1); return false; } m_rtROI.setLeft(left); m_rtROI.setTop(top); m_rtROI.setRight(right); m_rtROI.setBottom(bottom); return true; } void YK16GrayImage::DrawROIOn( bool bROI_Draw ) { m_bDrawROI = bROI_Draw; } bool YK16GrayImage::CloneImage( YK16GrayImage& other ) { if (other.m_pData == NULL) return false; //first, delete existing things ReleaseBuffer(); //Redundancy. CreateImage will call this too. also Create is calling this func. int width = other.m_iWidth; int height = other.m_iHeight; CreateImage(width, height, 0); CopyFromBuffer(other.m_pData, width, height); if (other.m_pElektaHisHeader != NULL) { m_pElektaHisHeader = new char [DEFAULT_ELEKTA_HIS_HEADER_SIZE]; for (int i = 0 ; i= 0 && m_ptProfileProbe.y() < m_iHeight && m_ptProfileProbe.x() >= 0 && m_ptProfileProbe.x() < m_iWidth) { m_ptProfileProbe.setX(dataX); m_ptProfileProbe.setY(dataY); } else { m_ptProfileProbe.setX(0); m_ptProfileProbe.setY(0); } } unsigned short YK16GrayImage::GetProfileProbePixelVal() { unsigned short resultVal = 0; if (m_pData == NULL) return 0; if (m_ptProfileProbe.y() >= 0 && m_ptProfileProbe.y() < m_iHeight && m_ptProfileProbe.x() >= 0 && m_ptProfileProbe.x() < m_iWidth) resultVal = m_pData[m_iWidth*m_ptProfileProbe.y() + m_ptProfileProbe.x()]; else resultVal = 0; return resultVal; } void YK16GrayImage::GetProfileData( int dataX, int dataY, QVector& vTarget, enProfileDirection direction ) { if (m_pData == NULL) return; if (dataY < 0 || dataY >= m_iHeight || dataX < 0 || dataX >= m_iWidth) return; vTarget.clear(); if (direction == DIRECTION_HOR) { int fixedY = dataY; for (int j = 0 ; j< m_iWidth ; j++) { vTarget.push_back(m_pData[m_iWidth*fixedY + j]); } } else if (direction == DIRECTION_VER) { //Upper to Lower profile int fixedX = dataX; for (int i = 0 ; i< m_iHeight ; i++) { vTarget.push_back(m_pData[m_iWidth*i + fixedX]); } } return; } void YK16GrayImage::GetProfileData(QVector& vTarget, enProfileDirection direction ) { if (m_pData == NULL) return; int dataX = m_ptProfileProbe.x(); int dataY = m_ptProfileProbe.y(); if (dataY < 0 || dataY >= m_iHeight || dataX < 0 || dataX >= m_iWidth) return; vTarget.clear(); if (direction == DIRECTION_HOR) { int fixedY = dataY; for (int j = 0 ; j< m_iWidth ; j++) { vTarget.push_back((double)(m_pData[m_iWidth*fixedY + j])); } } else if (direction == DIRECTION_VER) { //Upper to Lower profile int fixedX = dataX; for (int i = 0 ; i< m_iHeight ; i++) { vTarget.push_back((double)(m_pData[m_iWidth*i + fixedX])); } } } bool YK16GrayImage::ConstituteFromTwo( YK16GrayImage& YKImg1,YK16GrayImage& YKImg2 ) { //Filtering if (YKImg1.IsEmpty() || YKImg2.IsEmpty() || YKImg1.m_iWidth != YKImg2.m_iWidth || YKImg1.m_iHeight != YKImg2.m_iHeight || YKImg1.m_iWidth * YKImg1.m_iHeight == 0) return false; if (m_enSplitOption < 0) { cout << "ConstituteFromTwo cannot be carried out due to the wrong split option" << endl; return false; } int width = YKImg1.m_iWidth; int height = YKImg1.m_iHeight; int centerX = m_ptSplitCenter.x(); //data index int centerY = m_ptSplitCenter.y(); //bool bPreserveInfo = true; //CreateImage(width, height, 0, bPreserveInfo);//tracking data should be reserved CloneImage(YKImg1); //copy all the tracking data as well //EXCEPT for Split center!!!! //restore split center after clone m_ptSplitCenter.setX(centerX); m_ptSplitCenter.setY(centerY); int i, j; switch (m_enSplitOption) { case PRI_LEFT_TOP: for (i = 0; i < centerY; i++) { for (j = 0; j < centerX; j++) { m_pData[width*i + j] = YKImg1.m_pData[width*i + j]; } } for (i = centerY; i < height; i++) { for (j = centerX; j < width; j++) { m_pData[width*i + j] = YKImg1.m_pData[width*i + j]; } } for (i = 0; i < centerY; i++) { for (j = centerX; j < width; j++) { m_pData[width*i + j] = YKImg2.m_pData[width*i + j]; } } for (i = centerY; i < height; i++) { for (j = 0; j < centerX; j++) { m_pData[width*i + j] = YKImg2.m_pData[width*i + j]; } } break; default: break; } return true; } void YK16GrayImage::EditImage_Flip() { if (m_pData == NULL) return; int imgSize = m_iWidth*m_iHeight; if (imgSize <=0) return; //º¹»çÇÒ Àӽà buffer »ý¼º unsigned short* pPrevImg = new unsigned short [imgSize]; int i,j; for (i = 0 ; i 65535) uppVal1 = 65535; if (uppVal2 > 65535) uppVal2 = 65535; if (lowVal1 <= 0) lowVal1 = 0; if (uppVal2 <= 0) uppVal2 = 0; //It takes 0.4 s in Release mode if (m_enSplitOption != PRI_LEFT_TOP) return false; int splitX = m_ptSplitCenter.x(); int splitY = m_ptSplitCenter.y(); //1/4 sector for (int i = 0 ; i= uppVal1) { //QRgb rgbVal = qRgb(255, 255, 255); //m_QImage.setPixel(j,i,qRgb(255, 255, 255)); tmpData[tmpIdx+0] = 255; tmpData[tmpIdx+1] = 255; tmpData[tmpIdx+2] = 255; } else if (m_pData[i*m_iWidth+j] <= lowVal1) { tmpData[tmpIdx+0] = 0; tmpData[tmpIdx+1] = 0; tmpData[tmpIdx+2] = 0; //QRgb rgbVal = qRgb(0, 0, 0); //m_QImage.setPixel(j,i,qRgb(0, 0, 0)); } else { tmpData[tmpIdx+0] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success tmpData[tmpIdx+1] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success tmpData[tmpIdx+2] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success } } else { if (m_pData[i*m_iWidth+j] >= uppVal1) { //QRgb rgbVal = qRgb(255, 255, 255); //m_QImage.setPixel(j,i,qRgb(255, 255, 255)); tmpData[tmpIdx+0] = 0; tmpData[tmpIdx+1] = 0; tmpData[tmpIdx+2] = 0; } else if (m_pData[i*m_iWidth+j] <= lowVal1) { tmpData[tmpIdx+0] = 255; tmpData[tmpIdx+1] = 255; tmpData[tmpIdx+2] = 255; //QRgb rgbVal = qRgb(0, 0, 0); //m_QImage.setPixel(j,i,qRgb(0, 0, 0)); } else { tmpData[tmpIdx+0] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success tmpData[tmpIdx+1] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success tmpData[tmpIdx+2] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success } } } } //2/4 sector for (int i = 0 ; i= uppVal2) { //QRgb rgbVal = qRgb(255, 255, 255); //m_QImage.setPixel(j,i,qRgb(255, 255, 255)); tmpData[tmpIdx+0] = 255; tmpData[tmpIdx+1] = 255; tmpData[tmpIdx+2] = 255; } else if (m_pData[i*m_iWidth+j] <= lowVal2) { tmpData[tmpIdx+0] = 0; tmpData[tmpIdx+1] = 0; tmpData[tmpIdx+2] = 0; //QRgb rgbVal = qRgb(0, 0, 0); //m_QImage.setPixel(j,i,qRgb(0, 0, 0)); } else { tmpData[tmpIdx+0] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success tmpData[tmpIdx+1] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success tmpData[tmpIdx+2] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success } } else { if (m_pData[i*m_iWidth+j] >= uppVal2) { //QRgb rgbVal = qRgb(255, 255, 255); //m_QImage.setPixel(j,i,qRgb(255, 255, 255)); tmpData[tmpIdx+0] = 0; tmpData[tmpIdx+1] = 0; tmpData[tmpIdx+2] = 0; } else if (m_pData[i*m_iWidth+j] <= lowVal2) { tmpData[tmpIdx+0] = 255; tmpData[tmpIdx+1] = 255; tmpData[tmpIdx+2] = 255; //QRgb rgbVal = qRgb(0, 0, 0); //m_QImage.setPixel(j,i,qRgb(0, 0, 0)); } else { tmpData[tmpIdx+0] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success tmpData[tmpIdx+1] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success tmpData[tmpIdx+2] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success } } } } //3/4 sector for (int i = splitY ; i= uppVal2) { //QRgb rgbVal = qRgb(255, 255, 255); //m_QImage.setPixel(j,i,qRgb(255, 255, 255)); tmpData[tmpIdx+0] = 255; tmpData[tmpIdx+1] = 255; tmpData[tmpIdx+2] = 255; } else if (m_pData[i*m_iWidth+j] <= lowVal2) { tmpData[tmpIdx+0] = 0; tmpData[tmpIdx+1] = 0; tmpData[tmpIdx+2] = 0; //QRgb rgbVal = qRgb(0, 0, 0); //m_QImage.setPixel(j,i,qRgb(0, 0, 0)); } else { tmpData[tmpIdx+0] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success tmpData[tmpIdx+1] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success tmpData[tmpIdx+2] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success } } else { if (m_pData[i*m_iWidth+j] >= uppVal2) { //QRgb rgbVal = qRgb(255, 255, 255); //m_QImage.setPixel(j,i,qRgb(255, 255, 255)); tmpData[tmpIdx+0] = 0; tmpData[tmpIdx+1] = 0; tmpData[tmpIdx+2] = 0; } else if (m_pData[i*m_iWidth+j] <= lowVal2) { tmpData[tmpIdx+0] = 255; tmpData[tmpIdx+1] = 255; tmpData[tmpIdx+2] = 255; //QRgb rgbVal = qRgb(0, 0, 0); //m_QImage.setPixel(j,i,qRgb(0, 0, 0)); } else { tmpData[tmpIdx+0] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success tmpData[tmpIdx+1] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success tmpData[tmpIdx+2] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal2)/(double)winWidth2 * 255.0); //success } } } } //4/4 sector for (int i = splitY ; i= uppVal1) { //QRgb rgbVal = qRgb(255, 255, 255); //m_QImage.setPixel(j,i,qRgb(255, 255, 255)); tmpData[tmpIdx+0] = 255; tmpData[tmpIdx+1] = 255; tmpData[tmpIdx+2] = 255; } else if (m_pData[i*m_iWidth+j] <= lowVal1) { tmpData[tmpIdx+0] = 0; tmpData[tmpIdx+1] = 0; tmpData[tmpIdx+2] = 0; //QRgb rgbVal = qRgb(0, 0, 0); //m_QImage.setPixel(j,i,qRgb(0, 0, 0)); } else { tmpData[tmpIdx+0] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success tmpData[tmpIdx+1] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success tmpData[tmpIdx+2] = (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success } } else { if (m_pData[i*m_iWidth+j] >= uppVal1) { //QRgb rgbVal = qRgb(255, 255, 255); //m_QImage.setPixel(j,i,qRgb(255, 255, 255)); tmpData[tmpIdx+0] = 0; tmpData[tmpIdx+1] = 0; tmpData[tmpIdx+2] = 0; } else if (m_pData[i*m_iWidth+j] <= lowVal1) { tmpData[tmpIdx+0] = 255; tmpData[tmpIdx+1] = 255; tmpData[tmpIdx+2] = 255; //QRgb rgbVal = qRgb(0, 0, 0); //m_QImage.setPixel(j,i,qRgb(0, 0, 0)); } else { tmpData[tmpIdx+0] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success tmpData[tmpIdx+1] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success tmpData[tmpIdx+2] = 255 - (uchar) ((m_pData[i*m_iWidth+j] - lowVal1)/(double)winWidth1 * 255.0); //success } } } } int iBytesPerLine = m_iWidth*3; QImage tmpQImage = QImage((unsigned char*)tmpData,m_iWidth, m_iHeight,iBytesPerLine, QImage::Format_RGB888); //not deep copy! //Copy only a ROI region. All below are data-point, rather than display points //Outside region wiill be filled with Black by QImage inherent function // int newWidth = qRound(m_iWidth/m_fZoom); int newHeight = qRound(m_iHeight/m_fZoom); int centerX = m_iOffsetX + qRound(m_iWidth/2.0); int centerY = m_iOffsetY + qRound(m_iHeight/2.0); int newLeftTopX = centerX - qRound(newWidth/2.0);//data position int newLeftTopY = centerY - qRound(newHeight/2.0); //data position m_QImage = tmpQImage.copy(qRound(newLeftTopX),qRound(newLeftTopY), newWidth, newHeight); //memory allocated here!!! //m_QImage = tmpQImage.copy(0,0,m_iWidth, m_iHeight); //memory allocated here!!! //YKTEMP: is it needed? no it worked without below: //*m_pPixmap = QPixmap::fromImage(m_QImage); //copy data to pre-allcated pixmap buffer delete [] tmpData; return true; } bool YK16GrayImage::FillPixMapMinMaxDual( int winMin1, int winMin2, int winMax1, int winMax2 ) { if (winMin1 < 0 || winMax1 > 65535 || winMin1 > winMax1) { winMin1 = 0; winMax1 = 65535; } if (winMin2 < 0 || winMax2 > 65535 || winMin2 > winMax2) { winMin2 = 0; winMax2 = 65535; } int midVal1 = (int)((winMin1 + winMax1)/2.0); int midVal2 = (int)((winMin2 + winMax2)/2.0); int widthVal1 = winMax1 - winMin1; int widthVal2 = winMax2 - winMin2; return FillPixMapDual(midVal1, midVal2, widthVal1, widthVal2); } bool YK16GrayImage::isPtInFirstImage(int dataX, int dataY) { if (dataX < 0 || dataX >= m_iWidth || dataY < 0 || dataY >= m_iHeight) { cout << "Fatal error in isPtInFirstImage! Given point is out of image point" << endl; return false; } if (m_enSplitOption == PRI_LEFT_TOP && !IsEmpty()) { if ((dataX >= 0 && dataX < m_ptSplitCenter.x() && dataY >=0 && dataY < m_ptSplitCenter.y()) || (dataX >= m_ptSplitCenter.x() && dataX < m_iWidth && dataY >= m_ptSplitCenter.y() && dataY < m_iHeight)) return true; else return false; } return false; } void YK16GrayImage::SetSplitCenter( QPoint& ptSplitCenter ) { if (IsEmpty()) return; if (ptSplitCenter.x() < 0 || ptSplitCenter.x() >= m_iWidth || ptSplitCenter.y() < 0 || ptSplitCenter.y() >= m_iHeight) { m_ptSplitCenter.setX(0); m_ptSplitCenter.setY(0); } else m_ptSplitCenter = ptSplitCenter; } void YK16GrayImage::SetZoom( double fZoom ) { if (fZoom <= 1) m_fZoom = 1.0; else m_fZoom = fZoom; } void YK16GrayImage::MedianFilter( int iMedianSizeX, int iMedianSizeY ) { if (m_pData == NULL) return; UnsignedShortImageType::Pointer spTmpItkImg = UnsignedShortImageType::New(); UnsignedShortImageType::SizeType size; size[0] = m_iWidth; size[1] = m_iHeight; UnsignedShortImageType::IndexType idxStart; idxStart[0] = 0; idxStart[1] = 0; UnsignedShortImageType::SpacingType spacing; if (m_fSpacingX*m_fSpacingY == 0) { spacing[0] = 1.0; spacing[1] = 1.0; } else { spacing[0] = m_fSpacingX; spacing[1] = m_fSpacingY; } UnsignedShortImageType::PointType origin; origin[0] = size[0]*spacing[0]/-2.0; origin[1] = size[1]*spacing[1]/-2.0; UnsignedShortImageType::RegionType region; region.SetSize(size); region.SetIndex(idxStart); spTmpItkImg->SetRegions(region); spTmpItkImg->SetSpacing(spacing); spTmpItkImg->SetOrigin(origin); spTmpItkImg->Allocate(); CopyYKImage2ItkImage(this, spTmpItkImg); typedef itk::MedianImageFilter MedianFilterType; MedianFilterType::Pointer medianFilter = MedianFilterType::New(); //medianFilter->SetInput(spTmpItkImg); MedianFilterType::InputSizeType radius; radius[0] = qRound(iMedianSizeX/2.0); radius[1] = qRound(iMedianSizeY/2.0); medianFilter->SetRadius(radius); medianFilter->SetInput(spTmpItkImg); medianFilter->Update(); spTmpItkImg = medianFilter->GetOutput(); CopyItkImage2YKImage(spTmpItkImg, this); } UnsignedShortImageType::Pointer YK16GrayImage::CloneItkImage() { if (m_pData == NULL) return NULL; UnsignedShortImageType::Pointer spTmpItkImg = UnsignedShortImageType::New(); UnsignedShortImageType::SizeType size; size[0] = m_iWidth; size[1] = m_iHeight; UnsignedShortImageType::IndexType idxStart; idxStart[0] = 0; idxStart[1] = 0; UnsignedShortImageType::SpacingType spacing; if (m_fSpacingX*m_fSpacingY == 0) { spacing[0] = 1.0; spacing[1] = 1.0; } else { spacing[0] = m_fSpacingX; spacing[1] = m_fSpacingY; } UnsignedShortImageType::PointType origin; origin[0] = size[0]*spacing[0]/-2.0; origin[1] = size[1]*spacing[1]/-2.0; UnsignedShortImageType::RegionType region; region.SetSize(size); region.SetIndex(idxStart); spTmpItkImg->SetRegions(region); spTmpItkImg->SetSpacing(spacing); spTmpItkImg->SetOrigin(origin); spTmpItkImg->Allocate(); //Raw File open //UnsignedShortImageType::SizeType tmpSize = //UnsignedShortImageType::RegionType region = spTmpItkImg->GetRequestedRegion(); //UnsignedShortImageType::SizeType tmpSize = region.GetSize(); //int sizeX = tmpSize[0]; //int sizeY = tmpSize[1]; //if (sizeX < 1 || sizeY <1) // return; itk::ImageRegionIterator it(spTmpItkImg, spTmpItkImg->GetRequestedRegion()); int i = 0; for (it.GoToBegin() ; !it.IsAtEnd(); ++it) { it.Set(m_pData[i]); i++; } return spTmpItkImg; } void YK16GrayImage::ResampleImage( double fResampleFactor ) { if (m_pData == NULL) return; if (fResampleFactor <= 0) return; m_fResampleFactor = fResampleFactor; UnsignedShortImageType::SizeType inputSize; inputSize[0] = m_iWidth; inputSize[1] = m_iHeight; UnsignedShortImageType::SizeType outputSize; outputSize[0] = qRound(m_iWidth*fResampleFactor); outputSize[1] = qRound(m_iHeight*fResampleFactor); //m_iWidth = outputSize[0]; //m_iHeight = outputSize[1]; UnsignedShortImageType::SpacingType outputSpacing; if (m_fSpacingX <=0 ||m_fSpacingY <=0) { m_fSpacingX = 1.0; m_fSpacingY = 1.0; } outputSpacing[0] = m_fSpacingX * (static_cast(inputSize[0]) / static_cast(outputSize[0])); outputSpacing[1] = m_fSpacingY * (static_cast(inputSize[1]) / static_cast(outputSize[1])); UnsignedShortImageType::Pointer input = CloneItkImage();//returns Ushort itk image from data buf UnsignedShortImageType::PointType outputOrigin = input->GetOrigin(); //-204.6 - 204.6 0 //// Resample the image //typedef itk::IdentityTransform TransformType; typedef itk::ResampleImageFilter ResampleImageFilterType; ResampleImageFilterType::Pointer resample = ResampleImageFilterType::New(); typedef itk::AffineTransform< float, 2 > TransformType; TransformType::Pointer transform = TransformType::New(); typedef itk::NearestNeighborInterpolateImageFunction InterpolatorType; InterpolatorType::Pointer interpolator = InterpolatorType::New(); transform->SetIdentity(); resample->SetInput(input); resample->SetOutputDirection( input->GetDirection() ); resample->SetInterpolator(interpolator); resample->SetDefaultPixelValue( 50 ); resample->SetSize(outputSize); resample->SetOutputSpacing(outputSpacing); resample->SetOutputOrigin(outputOrigin); resample->SetTransform(transform); resample->Update(); UnsignedShortImageType::Pointer outputImg = resample->GetOutput(); UpdateFromItkImage(outputImg); //itk --> YKImage } void YK16GrayImage::UpdateFromItkImage( UnsignedShortImageType::Pointer& spRefItkImg ) { if (!spRefItkImg) return; if (m_pData != NULL) { delete [] m_pData; m_pData = NULL; } if (m_pPixmap != NULL) { delete m_pPixmap; m_pPixmap = NULL; } UnsignedShortImageType::SizeType size = spRefItkImg->GetRequestedRegion().GetSize(); UnsignedShortImageType::SpacingType spacing = spRefItkImg->GetSpacing(); UnsignedShortImageType::PointType origin = spRefItkImg->GetOrigin(); m_iWidth = size[0]; m_iHeight = size[1]; SetSpacing(spacing[0], spacing[1]); SetOrigin(origin[0], origin[1]); m_pData = new unsigned short [m_iWidth*m_iHeight]; itk::ImageRegionIterator it(spRefItkImg, spRefItkImg->GetRequestedRegion()); int i = 0; for (it.GoToBegin() ; !it.IsAtEnd() ; ++it) { m_pData[i] = it.Get(); i++; } } void YK16GrayImage::UpdateFromItkImageFloat( FloatImageType2D::Pointer& spRefItkImg ) { if (!spRefItkImg) return; if (m_pData != NULL) { delete [] m_pData; m_pData = NULL; } if (m_pPixmap != NULL) { delete m_pPixmap; m_pPixmap = NULL; } FloatImageType2D::SizeType size = spRefItkImg->GetRequestedRegion().GetSize(); FloatImageType2D::SpacingType spacing = spRefItkImg->GetSpacing(); FloatImageType2D::PointType origin = spRefItkImg->GetOrigin(); m_iWidth = size[0]; m_iHeight = size[1]; SetSpacing(spacing[0], spacing[1]); SetOrigin(origin[0], origin[1]); m_pData = new unsigned short [m_iWidth*m_iHeight]; itk::ImageRegionIterator it(spRefItkImg, spRefItkImg->GetRequestedRegion()); int i = 0; for (it.GoToBegin() ; !it.IsAtEnd() ; ++it) { float curVal =it.Get(); unsigned short outVal; if (curVal < 0.0) outVal = 0; else if (curVal > 65535.0) outVal = 65535; else outVal = (unsigned short)qRound(curVal); m_pData[i] = outVal; i++; } } void YK16GrayImage::UpdateFromItkImageFloat(FloatImageType2D::Pointer& spRefItkImg, float fIntenistyMag, float fIntensityOffset, bool bYFlip) { if (!spRefItkImg) return; if (m_pData != NULL) { delete[] m_pData; m_pData = NULL; } if (m_pPixmap != NULL) { delete m_pPixmap; m_pPixmap = NULL; } FloatImageType2D::SizeType size = spRefItkImg->GetRequestedRegion().GetSize(); FloatImageType2D::SpacingType spacing = spRefItkImg->GetSpacing(); FloatImageType2D::PointType origin = spRefItkImg->GetOrigin(); m_iWidth = size[0]; m_iHeight = size[1]; SetSpacing(spacing[0], spacing[1]); SetOrigin(origin[0], origin[1]); m_pData = new unsigned short[m_iWidth*m_iHeight]; this->m_fIntensityMag = fIntenistyMag; this->m_fIntensityOffset = fIntensityOffset; FloatImageType2D::Pointer spTmpImg; if (bYFlip) { ////Let's flip image typedef itk::FlipImageFilter< FloatImageType2D > FilterType; FilterType::Pointer flipFilter = FilterType::New(); typedef FilterType::FlipAxesArrayType FlipAxesArrayType; FlipAxesArrayType arrFlipAxes; arrFlipAxes[0] = 0; arrFlipAxes[1] = 1; flipFilter->SetFlipAxes(arrFlipAxes); flipFilter->SetInput(spRefItkImg); flipFilter->Update(); spTmpImg = flipFilter->GetOutput(); //spTmpImg = spRefItkImg; } else { spTmpImg = spRefItkImg; } itk::ImageRegionIterator it(spTmpImg, spTmpImg->GetRequestedRegion()); //itk::ImageRegionIterator it(flipFilter->GetOutput(), flipFilter->GetOutput()->GetRequestedRegion()); int i = 0; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { float curVal = it.Get(); m_pData[i] = GetWrappingIntensityVal(curVal); i++; } } void YK16GrayImage::UpdateToItkImageFloat(FloatImageType2D::Pointer& spRefItkImg) { /*if (m_pData != NULL) { delete[] m_pData; m_pData = NULL; } if (m_pPixmap != NULL) { delete m_pPixmap; m_pPixmap = NULL; } FloatImageType2D::SizeType size = spRefItkImg->GetRequestedRegion().GetSize(); FloatImageType2D::SpacingType spacing = spRefItkImg->GetSpacing(); FloatImageType2D::PointType origin = spRefItkImg->GetOrigin(); m_iWidth = size[0]; m_iHeight = size[1]; SetSpacing(spacing[0], spacing[1]); SetOrigin(origin[0], origin[1]); m_pData = new unsigned short[m_iWidth*m_iHeight]; itk::ImageRegionIterator it(spRefItkImg, spRefItkImg->GetRequestedRegion()); int i = 0; for (it.GoToBegin(); !it.IsAtEnd(); it++) { float curVal = it.Get(); m_pData[i] = GetWrappingIntensityVal(curVal); i++; }*/ } void YK16GrayImage::InvertImage() { if (m_pData == NULL) return; int imgSize= m_iWidth * m_iHeight; //Data inversion: Default for Elekta XVI system for (int i = 0 ; i::iterator it; int maxNum = 0; if (m_iNumOfTrackMarker == 0) return QPoint(0, 0); if (m_iNumOfTrackMarker == -1) maxNum = 100000; else maxNum = m_iNumOfTrackMarker; int cnt = 0; for (it = m_vMarker.begin(); it != m_vMarker.end(); it++) { sumPosX += (*it).x(); sumPosY += (*it).y(); cnt++; if (cnt >= maxNum) break; } return QPoint(qRound(sumPosX / (double)cnt), qRound(sumPosY / (double)cnt)); } void YK16GrayImage::AddMarkerPosRef(int dataX, int dataY) { m_vMarkerRef.push_back(QPoint(dataX, dataY)); int margin = 10; if (dataX < margin || dataX > m_iWidth - margin || dataY < margin || dataY > m_iHeight - margin) m_bvRefOutOfRange.push_back(true); else m_bvRefOutOfRange.push_back(false); } void YK16GrayImage::ClearMarkerPosRef() { m_vMarkerRef.clear(); m_bvRefOutOfRange.clear(); } QPoint YK16GrayImage::GetMeanPosRef() { double sumPosX = 0.0; double sumPosY = 0.0; if (!existRefMarkers()) return QPoint(0, 0); vector::iterator it; int cnt = 0; for (it = m_vMarkerRef.begin(); it != m_vMarkerRef.end(); it++) { sumPosX += (*it).x(); sumPosY += (*it).y(); cnt++; } if (cnt == 0) return QPoint(0,0); return QPoint(qRound(sumPosX / (double)cnt), qRound(sumPosY / (double)cnt)); } bool YK16GrayImage::existRefMarkers() { if (m_vMarkerRef.empty()) return false; return true; } void YK16GrayImage::UpdateTrackingData(YK16GrayImage* pYKProcessedImage) { m_strTimeStamp = pYKProcessedImage->m_strTimeStamp; //HHMMSSFFF (9digits) m_iProcessingElapsed = pYKProcessedImage->m_iProcessingElapsed; //processing time in ms //m_bDrawMarkers; m_iNumOfDispMarker = pYKProcessedImage->m_iNumOfDispMarker; //for display e.g.) 0,1,2,3,4 m_iNumOfTrackMarker = pYKProcessedImage->m_iNumOfTrackMarker; //for tracking GetMeanPos e.g.) 0,1,2 only //Reference marker group m_vMarkerRef = pYKProcessedImage->m_vMarkerRef;//let's see it works m_bvRefOutOfRange = pYKProcessedImage->m_bvRefOutOfRange;//leave a tag when calculated 2D ref position is out of image m_vMarker = pYKProcessedImage->m_vMarker;//position in data dimension (not either physical nor display) //should be implemented later m_track_priorErr = pYKProcessedImage->m_track_priorErr; m_track_motionErr = pYKProcessedImage->m_track_motionErr; m_track_CC_penalty = pYKProcessedImage->m_track_CC_penalty; //already there! m_fMVGantryAngle = pYKProcessedImage->m_fMVGantryAngle; m_fPanelOffsetX = pYKProcessedImage->m_fPanelOffsetX; //mm m_fPanelOffsetY = pYKProcessedImage->m_fPanelOffsetY; //mm m_bKVOn = pYKProcessedImage->m_bKVOn; //mm m_bMVOn = pYKProcessedImage->m_bMVOn; //mm m_iXVI_ElapseMS = pYKProcessedImage->m_iXVI_ElapseMS; //mm m_rtROI = pYKProcessedImage->m_rtROI; m_bDraw8Bit = pYKProcessedImage->m_bDraw8Bit; } //void YK16GrayImage::AddContourROI(QString& strROIName, bool bDisplay, std::vector& vContourPts) //{ // CContourROI* pContourROI = new CContourROI(); // // pContourROI->_strNameROI = strROIName; // pContourROI->_bDrawROI = bDisplay; // // //dip copy of points // vector::iterator it; // for (it = vContourPts.begin(); it != vContourPts.end(); it++) // { // pContourROI->_vDataPt.push_back((*it)); // } // m_vvContourROI.push_back(pContourROI); //} void YK16GrayImage::AddContourROI(QString& strROIName, bool bDisplay, QRgb color, int thickness, std::vector& vContourPts) { CContourROI* pContourROI = new CContourROI(); pContourROI->_strNameROI = strROIName; pContourROI->_bDrawROI = bDisplay; pContourROI->_rgb = color; pContourROI->_thick = thickness; //dip copy of points vector::iterator it; for (it = vContourPts.begin(); it != vContourPts.end(); it++) { pContourROI->_vDataPt.push_back((*it)); } m_vvContourROI.push_back(pContourROI); } void YK16GrayImage::ClearContourROI() { vector::iterator it; for (it = m_vvContourROI.begin(); it != m_vvContourROI.end(); it++) { delete (*it); //release mem of each item (pt data) } m_vvContourROI.clear(); } bool YK16GrayImage::SetDisplayStatus(QString& strROIName, bool bDisplay) { vector::iterator it; CContourROI* pCurContour = NULL; for (it = m_vvContourROI.begin(); it != m_vvContourROI.end(); it++) { pCurContour = (*it); if (pCurContour->_strNameROI == strROIName) { pCurContour->_bDrawROI = bDisplay; return true; } } return false; } float YK16GrayImage::GetOriginalIntensityVal(unsigned short usPixVal) { if (m_fIntensityMag <= 0) return -1.0; return (float)(usPixVal - m_fIntensityOffset) / m_fIntensityMag; } unsigned short YK16GrayImage::GetWrappingIntensityVal(float fPixVal) { unsigned short outVal; float fVal = fPixVal*m_fIntensityMag + m_fIntensityOffset; if (fVal < 0.0) outVal = 0; else if (fVal > 65535.0) outVal = 65535; else outVal = (unsigned short)qRound(fVal); return outVal; } void YK16GrayImage::SetCrosshairPosPhys(float physX, float physY, enPLANE plane) { if (m_fSpacingX*m_fSpacingY == 0) return; int dataX, dataY; dataX = qRound((physX - m_fOriginX) / m_fSpacingX); dataY = qRound((physY - m_fOriginY) / m_fSpacingY); /* cout << "m_fOriginY: " << m_fOriginY << endl; cout << "physY: " << physY << endl;*/ if (dataX < 0) dataX = 0; if (dataX >= m_iWidth) dataX = m_iWidth - 1; if (dataY < 0) dataY = 0; if (dataY >= m_iHeight) dataY = m_iHeight - 1; if (plane != PLANE_AXIAL) { dataY = m_iHeight - dataY - 1; } m_ptCrosshair.setX(dataX); m_ptCrosshair.setY(dataY); } QColor YK16GrayImage::GetColorFromDosePerc(float percVal) //to be edited to use LUT { /* float blueRef = 40.0; float greenRef = 80.0; float redRef = 120.0;*/ /* if (percVal < blueRef) { blueVal = (int)((blueRef - percVal)*4.0+90.0); greenVal = 0; redVal = 0; } else if (percVal >= blueRef && percVal < greenRef) { blueVal = 0; greenVal = (int)((greenRef - percVal)*4.0 + 90.0); redVal = 0; } else if (percVal >= greenRef && percVal < redRef) { blueVal = 0; greenVal = 0;; redVal = (int)((redRef - percVal)*4.0 + 90.0); } else if (percVal > redRef) { blueVal = 255; greenVal = 255;; redVal = 255; } */ QColor color; int blueVal, greenVal, redVal; if (m_vColorTable.empty()) return color; float minDosePerc = 0.0; float maxDosePerc = 120.0; //120% VEC3D curVal = QUTIL::GetRGBValueFromTable(m_vColorTable, minDosePerc, maxDosePerc, percVal); redVal = qRound(curVal.x*255); greenVal = qRound(curVal.y*255); blueVal = qRound(curVal.z*255); if (redVal > 255) redVal = 255; if (greenVal > 255) greenVal = 255; if (blueVal > 255) blueVal = 255; color.setRed(redVal); color.setGreen(greenVal); color.setBlue(blueVal); return color; } QColor YK16GrayImage::GetColorFromGamma(float gammaVal) { QColor color; int blueVal, greenVal, redVal; if (m_vColorTable.empty()) return color; VEC3D curVal; curVal = QUTIL::GetRGBValueFromTable(m_vColorTable, 0.0, 2.0, gammaVal); redVal = qRound(curVal.x * 255); greenVal = qRound(curVal.y * 255); blueVal = qRound(curVal.z * 255); if (redVal > 255) redVal = 255; if (greenVal > 255) greenVal = 255; if (blueVal > 255) blueVal = 255; color.setRed(redVal); color.setGreen(greenVal); color.setBlue(blueVal); return color; } void YK16GrayImage::SetColorTable(vector& vInputColorTable) { if (vInputColorTable.empty()) return; m_vColorTable.clear(); m_vColorTable = vInputColorTable; //deep copy? } unsigned short YK16GrayImage::GetCrosshairPixelData() { return GetPixelData(m_ptCrosshair.x(), m_ptCrosshair.y()); } float YK16GrayImage::GetCrosshairOriginalData() { return GetOriginalIntensityVal(GetCrosshairPixelData()); } float YK16GrayImage::GetCrosshairPercData() { if (m_fNormValue > 0) { return (GetOriginalIntensityVal(GetCrosshairPixelData()) / m_fNormValue*100.0); } else return 0.0; }YK16GrayImage.h000066400000000000000000000231141321604176500313220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#pragma once //v20130830 : his header buffer, itk compatible class QPixmap; class QLabel; class QPainter; //class QImage; #define DEFAULT_WINLEVEL_MID 10000 #define DEFAULT_WINLEVEL_WIDTH 20000 #define DEFAULT_ELEKTA_HIS_HEADER_SIZE 100 #include "itkImage.h" #include #include #include #include #include #include "yk_config.h" struct BADPIXELMAP{ int BadPixX; int BadPixY; int ReplPixX; int ReplPixY; }; class CContourROI { public: CContourROI(void){ ; } ~CContourROI(void){ _vDataPt.clear(); } bool _bDrawROI; QString _strNameROI; QRgb _rgb; //QRgb(255,0,0) int _thick; std::vector _vDataPt; }; enum enProfileDirection{ DIRECTION_HOR = 0, DIRECTION_VER, }; enum enSplitOption{ PRI_LEFT_TOP = 0, //Primary Left Top PRI_RIGHT_TOP, //Primary Left Top PRI_LEFT, PRI_RIGHT, PRI_TOP, PRI_BOTTOM, }; typedef itk::Image UnsignedShortImageType; typedef itk::Image FloatImageType2D; using namespace std; class YK16GrayImage { public: YK16GrayImage(void); YK16GrayImage(int width, int height); ~YK16GrayImage(void); int m_iWidth; int m_iHeight; //added: 20140206 double m_fSpacingX; //[mm/px] double m_fSpacingY; double m_fOriginX; double m_fOriginY; float m_fIntensityMag;//intensity magnification factor default = 1.0; float m_fIntensityOffset;//intensity Offset factor default = 0.0; float m_fNormValue; void SetIntensityModification(float intensityMag, float intensityOffset){ m_fIntensityMag = intensityMag; m_fIntensityOffset = intensityOffset; } float GetOriginalIntensityVal(unsigned short usPixVal); //regarding m_fIntensityMag and m_fIntensityOffset unsigned short GetWrappingIntensityVal(float fPixVal); unsigned short* m_pData; // 0 - 65535 QPixmap* m_pPixmap; //Actually, no need! QImage m_QImage; //QPainter* m_pPainter; bool LoadRawImage(const char *filePath, int width, int height); bool LoadRawImage(const char *filePath, int width, int height, int headerOffset); bool LoadRawImage(const char *filePath, int width, int height, int headerOffset, bool bInvert); bool CopyFromBuffer(unsigned short* pImageBuf, int width, int height); bool CloneImage(YK16GrayImage& other); bool CreateImage(int width, int height, unsigned short usVal); bool FillPixMap(int winMid, int winWidth); bool FillPixMapMinMax(int winMin, int winMax); //0-65535 Áß window level bool FillPixMapDose(float normval); bool FillPixMapDose(); //m_fNormValue void SetNormValueOriginal(float normval); QColor GetColorFromDosePerc(float percVal); bool FillPixMapGamma(); QColor GetColorFromGamma(float gammaVal); bool FillPixMapDual(int winMid1, int winMid2,int winWidth1, int winWidth2); bool FillPixMapMinMaxDual(int winMin1, int winMin2, int winMax1, int winMax2); //0-65535 Áß window level bool SaveDataAsRaw (const char *filePath); //bool DrawToLabel(QLabel* lbDisplay); bool IsEmpty(); bool ReleaseBuffer(); //bool CalcImageInfo (double& meanVal, double& STDV, double& minVal, double& maxVal); bool CalcImageInfo (); double CalcAveragePixelDiff(YK16GrayImage& other); bool DoPixelReplacement(std::vector& vPixelMapping); //based on pixel mapping information, some bad pixels will be replaced with median pixel value near by static void CopyYKImage2ItkImage(YK16GrayImage* pYKImage, UnsignedShortImageType::Pointer& spTarImage); static void CopyItkImage2YKImage(UnsignedShortImageType::Pointer& spSrcImage, YK16GrayImage* pYKImage); QString m_strFilePath; double m_fPixelMean; double m_fPixelSD; double m_fPixelMin; double m_fPixelMax; static void Swap(YK16GrayImage* pImgA, YK16GrayImage* pImgB); QRect m_rtROI; bool setROI(int left, int top, int right, int bottom); //if there is error, go to default: entire image bool CalcImageInfo_ROI(); double m_fPixelMean_ROI; double m_fPixelSD_ROI; double m_fPixelMin_ROI; double m_fPixelMax_ROI; bool m_bDrawROI; void DrawROIOn(bool bROI_Draw); //only rectangle //Elekta CBCT recon char* m_pElektaHisHeader; void CopyHisHeader(const char *hisFilePath); //bool SaveDataAsHis (const char *filePath); bool SaveDataAsHis( const char *filePath, bool bInverse ); bool m_bShowInvert; void MultiplyConstant(double multiplyFactor); void SetSpacing(double spacingX, double spacingY) { m_fSpacingX = spacingX; m_fSpacingY = spacingY; }; void SetOrigin(double originX, double originY) { m_fOriginX = originX; m_fOriginY = originY; }; QPoint m_ptProfileProbe; //Mouse Clicked Position --> Data bool m_bDrawProfileX; bool m_bDrawProfileY; QPoint m_ptFOVCenter; // data pos int m_iFOVRadius;//data pos (pixel) bool m_bDrawFOVCircle; int m_iTableTopPos;//data pos bool m_bDrawTableLine; QPoint m_ptCrosshair; //data position bool m_bDrawCrosshair; ////ZOOM and PAN function. Using these information below, prepare the m_QImage for displaying //in qlabel in FillPixMap function int m_iOffsetX; //for Pan function.. this is data based offset int m_iOffsetY; void SetOffset(int offsetX, int offsetY){m_iOffsetX = offsetX; m_iOffsetY = offsetY;} double m_fZoom; void SetZoom(double fZoom); unsigned short GetPixelData(int x, int y); unsigned short GetCrosshairPixelData();//Get pixel data of crosshair float GetCrosshairOriginalData();//Get pixel data of crosshair float GetCrosshairPercData();//Get pixel data of crosshair //SPLIT VIEW QPoint m_ptSplitCenter; //Fixed image with Moving image. center is based on dataPt.//Fixed Image: Left Top + Right Bottom, Moving: Right Top + Left Bottom int m_enSplitOption; //This cetner is moved while Left Dragging //All split and crosshair are data point based! void SetSplitOption(enSplitOption option) {m_enSplitOption = option;} void SetSplitCenter(QPoint& ptSplitCenter); //From mouse event, data point //void SetSplitCenter(int centerX, int centerY) {m_ptSplitCenter.setX(centerX); m_ptSplitCenter.setY(centerY);}//From mouse event, data point bool ConstituteFromTwo(YK16GrayImage& YKImg1,YK16GrayImage& YKImg2); //YKImg1 and two should be in exactly same dimension and spacing bool isPtInFirstImage(int dataX, int dataY); void SetProfileProbePos(int dataX, int dataY); void SetCrosshairPosPhys(float physX, float physY, enPLANE plane); unsigned short GetProfileProbePixelVal(); void GetProfileData(int dataX, int dataY, QVector& vTarget, enProfileDirection direction); void GetProfileData(QVector& vTarget, enProfileDirection direction); void EditImage_Flip(); void EditImage_Mirror(); void MedianFilter(int iMedianSizeX, int iMedianSizeY); double m_fResampleFactor;//if it is not the 1.0, the data is already resampled. UnsignedShortImageType::Pointer CloneItkImage(); void ResampleImage(double fResampleFactor); void UpdateFromItkImage(UnsignedShortImageType::Pointer& spRefItkImg); void UpdateFromItkImageFloat(FloatImageType2D::Pointer& spRefItkImg); void UpdateFromItkImageFloat(FloatImageType2D::Pointer& spRefItkImg, float fIntenistyMag, float fIntensityOffset, bool bYFlip= false); void UpdateToItkImageFloat(FloatImageType2D::Pointer& spRefItkImg); //to be implemented void InvertImage(); QString m_strTimeStamp; //HHMMSSFFF (9digits) int m_iProcessingElapsed; //processing time in ms //will be added later /*void EditImage_CW90(); void EditImage_CCW90(); void EditImage_Rotation(double angle);*/ std::vector m_vMarker;//position in data dimension (not either physical nor display) void AddMarkerPos(int dataX, int dataY); void ClearMarkerPos(); bool m_bDrawMarkers; int m_iNumOfDispMarker; //for display e.g.) 0,1,2,3,4 int m_iNumOfTrackMarker; //for tracking GetMeanPos e.g.) 0,1,2 only QPoint GetMeanPos(); //m_iNumOfTrackMarker based //Reference marker group std::vector m_vMarkerRef;//position in data dimension (not either physical nor display) std::vector m_bvRefOutOfRange;//leave a tag when calculated 2D ref position is out of image void AddMarkerPosRef(int dataX, int dataY); void ClearMarkerPosRef(); bool m_bDrawMarkersRef; QPoint GetMeanPosRef(); //m_iNumOfDispMarker based bool existRefMarkers(); //should be implemented later double m_track_priorErr; double m_track_motionErr; double m_track_CC_penalty; //Below are the flexmap related stuffs float m_fMVGantryAngle; float m_fPanelOffsetX; //mm float m_fPanelOffsetY;//mm bool m_bKVOn; bool m_bMVOn; int m_iXVI_ElapseMS; void UpdateTrackingData(YK16GrayImage* pYKProcessedImage); bool m_bDraw8Bit; //if some processing is done by 8bit bool m_bDrawOverlayText; QString m_strOverlayText; //2D points in data map. only outer contour points are included here after trimming out. //std::vector m_vContourROI; //later it will be array or linked list to display mutliple ROIs //std::vector*> m_vvContourROI; //std::vector m_vbDrawContourROI; //bool m_bDrawContours; std::vector m_vvContourROI; void AddContourROI(QString& strROIName, bool bDisplay, QRgb color, int thickness, std::vector& vContourPts); void ClearContourROI();// delete all the data of contourROI bool SetDisplayStatus(QString& strROIName, bool bDisplay); //void GetColorSingleROI() vector m_vColorTable; //vector m_vColorTableGammaLow; //vector m_vColorTableGammaHigh; void SetColorTable(vector& vInputColorTable); };YKThreadRegi.cpp000066400000000000000000000047361321604176500316700ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "YKThreadRegi.h" #include "register_gui.h" #include "registration.h" #include "registration_data.h" #include "registration_parms.h" #include "plm_exception.h" #include using namespace std; YKThreadRegi::YKThreadRegi(register_gui* pParent, QString& strPathCommand, int iRowIndex) { m_strCommandFilePath = strPathCommand; m_iProcessingTime = 0; m_iIndex = iRowIndex; m_pParent = pParent; } YKThreadRegi::~YKThreadRegi() { } void YKThreadRegi::run()//called by thread.start() { if (m_pParent == NULL) { exec(); return; } m_pParent->m_mutex.lock(); //maybe not needed just for copying if (m_iIndex >= m_pParent->m_vRegiQue.size()) { m_pParent->m_mutex.unlock(); //maybe not needed just for copying exec(); return; } m_pParent->m_vRegiQue.at(m_iIndex).m_iStatus = ST_PENDING; m_pParent->UpdateTable_Que(); m_pParent->m_mutex.unlock(); //maybe not needed just for copying std::string strPath = m_strCommandFilePath.toLocal8Bit().constData(); Registration reg; if (reg.set_command_file(strPath) < 0) { printf("Error. could not load %s as command file.\n", strPath.c_str()); } QTime time; time.start(); try { reg.do_registration(); } catch (Plm_exception e) { printf("Your error was %s", e.what()); m_pParent->m_mutex.lock(); m_iProcessingTime = time.elapsed(); m_pParent->m_vRegiQue.at(m_iIndex).m_iStatus = ST_ERROR; m_pParent->m_vRegiQue.at(m_iIndex).m_fProcessingTime = m_iProcessingTime / 1000.0; m_pParent->m_mutex.unlock(); exec(); return; } m_iProcessingTime = time.elapsed(); /*QString strDisp = "Done: " + QString::number(m_iProcessingTime/1000, 'f', 1) + " s"; m_pParent->SetTableText(m_iIndex, DEFAULT_NUM_COLUMN_MAIN - 1, strDisp);*/ m_pParent->m_mutex.lock(); //maybe not needed just for copying m_pParent->m_vRegiQue.at(m_iIndex).m_iStatus = ST_DONE; m_pParent->m_vRegiQue.at(m_iIndex).m_fProcessingTime = m_iProcessingTime / 1000.0; m_pParent->UpdateTable_Que(); //m_pParent->m_vRegiQue.at(m_iIndex).m_fScore = 999.0;"not yet implemented" m_pParent->CopyCommandFileToOutput(this->m_strCommandFilePath); m_pParent->m_mutex.unlock(); //maybe not needed just for copying exec();//event roop Thread is still alive To quit thread, call exit() //quit thread } YKThreadRegi.h000066400000000000000000000010461321604176500313240ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#ifndef YKTHREADREGI_H #define YKTHREADREGI_H #include #include using namespace std; class register_gui; class YKThreadRegi : public QThread { public: //DPGMTracking* m_pParent; public: //YKThreadRegi(register_gui* pParent, QString& strPathCommand); YKThreadRegi(register_gui* pParent, QString& strPathCommand, int iRowIndex); ~YKThreadRegi(); void run(); int m_iProcessingTime; //ms QString m_strCommandFilePath; register_gui* m_pParent; int m_iIndex; }; #endif // YKTHREADREGI_H beamdata_gen_gui.cpp000066400000000000000000002345221321604176500326370ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "beamdata_gen_gui.h" #include #include #include #include #include #include "YK16GrayImage.h" #include "plm_image.h" #include "rt_study_metadata.h" #include "gamma_dose_comparison.h" #include #include "logfile.h" #include "pcmd_gamma.h" #include "print_and_exit.h" #include "plm_file_format.h" #include "rt_study.h" #include "qt_util.h" #include #include #include "dcmtk_rt_study.h" #include "dcmtk_rt_study_p.h" #include "dcmtk_series.h" #include "dcmtk_config.h" #include "dcmtk/dcmdata/dctagkey.h" #include "dcmtk/dcmdata/dcsequen.h" #include "dcmtk/dcmdata/dcitem.h" #include "dcmtk/dcmdata/dcdeftag.h" #include #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkImageSliceIteratorWithIndex.h" #include "itkFlipImageFilter.h" #include "itkMinimumMaximumImageCalculator.h" #include #include "dcmtk_rt_study.h" #include "rtplan.h" #include "rtplan_beam.h" #include "rtplan_control_pt.h" beamdata_gen_gui::beamdata_gen_gui(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { ui.setupUi(this); m_pCurImageAxial = new YK16GrayImage(); m_pCurImageSagittal = new YK16GrayImage(); m_pCurImageFrontal = new YK16GrayImage(); //QUTIL::LoadColorTableFromFile("colormap_jet.txt", m_vColormapDose); QUTIL::LoadColorTableInternal(m_vColormapDose, COL_TABLE_JET); if (m_vColormapDose.size() < 1) { cout << "Fatal error!: colormap is not ready. colormap_table should be checked in QtUtil." << endl; } else { cout << "Colormap_Jet is successfully loaded" << endl; } m_pCurImageAxial->SetColorTable(m_vColormapDose); m_pCurImageSagittal->SetColorTable(m_vColormapDose); m_pCurImageFrontal->SetColorTable(m_vColormapDose); connect(ui.labelDoseImgAxial, SIGNAL(Mouse_Pressed_Left()), this, SLOT(SLT_UpdateProbePosFromAxial())); //added connect(ui.labelDoseImgSagittal, SIGNAL(Mouse_Pressed_Left()), this, SLOT(SLT_UpdateProbePosFromSagittal())); //added connect(ui.labelDoseImgFrontal, SIGNAL(Mouse_Pressed_Left()), this, SLOT(SLT_UpdateProbePosFromFrontal())); //added connect(ui.labelDoseImgAxial, SIGNAL(Mouse_Left_DoubleClick()), this, SLOT(SLT_GoCenterPos())); //added connect(ui.labelDoseImgSagittal, SIGNAL(Mouse_Left_DoubleClick()), this, SLOT(SLT_GoCenterPos())); //added connect(ui.labelDoseImgFrontal, SIGNAL(Mouse_Left_DoubleClick()), this, SLOT(SLT_GoCenterPos())); //added connect(ui.labelDoseImgAxial, SIGNAL(Mouse_Wheel()), this, SLOT(SLT_MouseWheelUpdateAxial())); //added connect(ui.labelDoseImgSagittal, SIGNAL(Mouse_Wheel()), this, SLOT(SLT_MouseWheelUpdateSagittal())); //added connect(ui.labelDoseImgFrontal, SIGNAL(Mouse_Wheel()), this, SLOT(SLT_MouseWheelUpdateFrontal())); //added connect(ui.labelDoseImgAxial, SIGNAL(Mouse_Move()), this, SLOT(SLT_UpdatePanSettingAxial())); //added connect(ui.labelDoseImgSagittal, SIGNAL(Mouse_Move()), this, SLOT(SLT_UpdatePanSettingSagittal())); //added connect(ui.labelDoseImgFrontal, SIGNAL(Mouse_Move()), this, SLOT(SLT_UpdatePanSettingFrontal())); //added connect(ui.labelDoseImgAxial, SIGNAL(Mouse_Pressed_Right()), this, SLOT(SLT_MousePressedRightAxial())); //added connect(ui.labelDoseImgSagittal, SIGNAL(Mouse_Pressed_Right()), this, SLOT(SLT_MousePressedRightSagittal())); //added connect(ui.labelDoseImgFrontal, SIGNAL(Mouse_Pressed_Right()), this, SLOT(SLT_MousePressedRightFrontal())); //added connect(ui.labelDoseImgAxial, SIGNAL(Mouse_Released_Right()), this, SLOT(SLT_MouseReleasedRightAxial())); //added connect(ui.labelDoseImgSagittal, SIGNAL(Mouse_Released_Right()), this, SLOT(SLT_MouseReleasedRightSagittal())); //added connect(ui.labelDoseImgFrontal, SIGNAL(Mouse_Released_Right()), this, SLOT(SLT_MouseReleasedRightFrontal())); //added m_pTableModel = NULL; m_bMousePressedRightAxial = false; m_bMousePressedRightSagittal = false; m_bMousePressedRightFrontal = false; //Test code for dicom rt plan loading Dcmtk_rt_study* pRTstudyRP = new Dcmtk_rt_study(); QString strTest = "D:/dcmrt_plan.dcm"; Plm_file_format file_type_dcm_plan = plm_file_format_deduce(strTest.toLocal8Bit().constData()); if (file_type_dcm_plan == PLM_FILE_FMT_DICOM_RTPLAN) { pRTstudyRP->load(strTest.toLocal8Bit().constData()); } Rtplan::Pointer rtplan = pRTstudyRP->get_rtplan(); if (!rtplan) { cout << "Error! no dcm plan is loaded" << endl; return; } int iCntBeam = rtplan->beamlist.size(); if (iCntBeam < 1) { cout << "Error! no beam is found" << endl; return; } float* final_iso_pos = NULL; for (int i = 0; i < iCntBeam; i++) { Rtplan_beam *curBeam = rtplan->beamlist[i]; int iCntCP = curBeam->cplist.size(); for (int j = 0; j < iCntCP; j++) { float* cur_iso_pos = curBeam->cplist[j]->get_isocenter(); cout << "Beam ID: " << j << ", Control point ID: " << j << ", Isocenter pos : " << cur_iso_pos[0] << "/" << cur_iso_pos[1] << "/" << cur_iso_pos[2] << endl; if (i == 0 && j == 0) //choose first beam's isocenter final_iso_pos = curBeam->cplist[j]->get_isocenter(); } } if (final_iso_pos == NULL) { cout << "Error! No isocenter position was found. " << endl; return; } cout << final_iso_pos[0] << " " << final_iso_pos[1] << " " << final_iso_pos[1] << endl; delete pRTstudyRP; } beamdata_gen_gui::~beamdata_gen_gui() { //delete m_pImgOffset; //delete m_pImgGain; //m_vPixelReplMap.clear(); //not necessary //delete m_pView; m_vDoseImages.clear(); delete m_pCurImageAxial; delete m_pCurImageSagittal; delete m_pCurImageFrontal; if (m_pTableModel != NULL) { delete m_pTableModel; m_pTableModel = NULL; } if (m_vBeamDataRFA.size() > 0) { cout << m_vBeamDataRFA.size() << " beam data were successfully deleted." << endl; m_vBeamDataRFA.clear(); //cascade deleting, otherwise pointer vector is needed. } } void beamdata_gen_gui::SLTM_ImportRDFiles() { QStringList tmpList = QFileDialog::getOpenFileNames(this, "Select one or more files to open", m_strPathInputDir, "3D dose file (*.dcm *.mha)"); int iFileCnt = tmpList.size(); if (iFileCnt < 1) return; m_strlistPath.clear(); m_strlistFileBaseName.clear(); m_vDoseImages.clear(); m_vRefDose.clear(); m_strlistPath = tmpList; for (int i = 0; i < iFileCnt; i++) { QFileInfo tmpInfo = QFileInfo(m_strlistPath.at(i)); m_strlistFileBaseName.push_back(tmpInfo.completeBaseName()); } QFileInfo finfo(m_strlistPath.at(0)); QDir crntDir = finfo.absoluteDir(); m_strPathInputDir = crntDir.absolutePath(); //path to m_spImage int iCnt = m_strlistPath.count(); QString crntPath; typedef itk::ImageFileReader ReaderType; ReaderType::Pointer reader = ReaderType::New(); for (int i = 0; i < iCnt; i++) { crntPath = m_strlistPath.at(i); QFileInfo fInfo(crntPath); Plm_file_format cur_file_type; Rt_study cur_rt_study; cur_file_type = plm_file_format_deduce(crntPath.toLocal8Bit().constData()); FloatImageType::Pointer spCurFloat; if (cur_file_type == PLM_FILE_FMT_DICOM_DOSE) { cur_rt_study.load(crntPath.toLocal8Bit().constData(), cur_file_type); if (cur_rt_study.has_dose()) { //Plm_image::Pointer plm_img = cur_rt_study.get_dose(); Plm_image::Pointer plm_img = cur_rt_study.get_dose()->clone(); spCurFloat = plm_img->itk_float(); } else { cout << "Error! File= " << crntPath.toLocal8Bit().constData() << " DICOM DOSE but no dose info contained" << endl; } } else if (fInfo.suffix() == "mha" || fInfo.suffix() == "MHA") { reader->SetFileName(crntPath.toLocal8Bit().constData()); reader->Update(); spCurFloat = reader->GetOutput(); } if (spCurFloat) { m_vDoseImages.push_back(spCurFloat); //Calculate dose max typedef itk::MinimumMaximumImageCalculator MinimumMaximumImageCalculatorType; MinimumMaximumImageCalculatorType::Pointer minimumMaximumImageCalculatorFilter = MinimumMaximumImageCalculatorType::New(); minimumMaximumImageCalculatorFilter->SetImage(spCurFloat); minimumMaximumImageCalculatorFilter->Compute(); float maxVal = minimumMaximumImageCalculatorFilter->GetMaximum(); m_vRefDose.push_back(maxVal); } } cout << m_vDoseImages.size() << " files were successfully loaded." << endl; disconnect(ui.comboBoxFileName, SIGNAL(currentIndexChanged(int)), this, SLOT(SLT_WhenSelectCombo())); SLT_UpdateComboContents(); connect(ui.comboBoxFileName, SIGNAL(currentIndexChanged(int)), this, SLOT(SLT_WhenSelectCombo())); SLT_WhenSelectCombo(); //Draw all included SLT_GoCenterPos(); //Draw all included } void beamdata_gen_gui::SLT_UpdateComboContents() //compare image based.. { QComboBox* crntCombo = ui.comboBoxFileName; crntCombo->clear(); int cntComp = m_strlistFileBaseName.count(); for (int i = 0; i < cntComp; i++) { //SLT_WHenComboSelect should be disconnected here crntCombo->addItem(m_strlistFileBaseName.at(i)); } } void beamdata_gen_gui::SLT_DrawAll() { //Get combo box selection QComboBox* crntCombo = ui.comboBoxFileName; //QString curStr = crntCombo->currentText(); //this should be basename int curIdx = crntCombo->currentIndex(); //this should be basename int iCnt = crntCombo->count(); if (iCnt < 1) return; if ((int)(m_vDoseImages.size()) != iCnt) { cout << "Error! iCnt not matching in DrawAll" << endl; return; } FloatImageType::Pointer spCurImg3D = m_vDoseImages.at(curIdx); //DICOM float probePosX = ui.lineEdit_ProbePosX->text().toFloat(); float probePosY = ui.lineEdit_ProbePosY->text().toFloat(); float probePosZ = ui.lineEdit_ProbePosZ->text().toFloat(); /*FloatImage2DType::Pointer spCurGamma2DFrom3D; */ double finalPos1, finalPos2, finalPos3; //enPLANE curPlane = PLANE_AXIAL; float fixedPos = 0.0; float probePos2D_X =0.0; float probePos2D_Y = 0.0; bool bYFlip = false; vector vProfileAxial, vProfileSagittal, vProfileFrontal; enPROFILE_DIRECTON enDirection = PRIFLE_HOR; float fixedPosProfileAxial, fixedPosProfileSagittal, fixedPosProfileFrontal; if (ui.radioButtonHor->isChecked()) enDirection = PRIFLE_HOR; else if (ui.radioButtonVert->isChecked()) enDirection = PRIFLE_VER; enPLANE curPlane = PLANE_AXIAL; if (curPlane == PLANE_AXIAL) { fixedPos = probePosZ; probePos2D_X = probePosX; probePos2D_Y = probePosY; bYFlip = false; QUTIL::Get2DFrom3DByPosition(spCurImg3D, m_spCur2DAxial, PLANE_AXIAL, fixedPos, finalPos1); //YKImage receives 2D float m_pCurImageAxial->UpdateFromItkImageFloat(m_spCur2DAxial, GY2YKIMG_MAG, NON_NEG_SHIFT, bYFlip); //flip Y for display only m_pCurImageAxial->SetCrosshairPosPhys(probePos2D_X, probePos2D_Y, curPlane); if (enDirection == PRIFLE_HOR) fixedPosProfileAxial = probePosY; else fixedPosProfileAxial = probePosX; ui.lineEdit_ProbePosZ->setText(QString::number(finalPos1, 'f', 1)); } curPlane = PLANE_SAGITTAL; //Actually, frontal and sagittal image should be flipped for display purpose (in axial, Y is small to large, SAG and FRONTAL, Large to Small (head to toe direction) //Let's not change original data itself due to massing up the origin. Only change the display image //Point probe and profiles, other things works fine. if (curPlane == PLANE_SAGITTAL) { fixedPos = probePosX; probePos2D_X = probePosY; probePos2D_Y = probePosZ; //YKDebug: may be reversed bYFlip = true; QUTIL::Get2DFrom3DByPosition(spCurImg3D, m_spCur2DSagittal, PLANE_SAGITTAL, fixedPos, finalPos2); //YKImage receives 2D float m_pCurImageSagittal->UpdateFromItkImageFloat(m_spCur2DSagittal, GY2YKIMG_MAG, NON_NEG_SHIFT, bYFlip); //flip Y for display only m_pCurImageSagittal->SetCrosshairPosPhys(probePos2D_X, probePos2D_Y, curPlane); if (enDirection == PRIFLE_HOR) fixedPosProfileSagittal = probePosZ; else fixedPosProfileSagittal = probePosY; ui.lineEdit_ProbePosX->setText(QString::number(finalPos2, 'f', 1)); } curPlane = PLANE_FRONTAL; if (curPlane == PLANE_FRONTAL) { fixedPos = probePosY; probePos2D_X = probePosX; probePos2D_Y = probePosZ;//YKDebug: may be reversed bYFlip = true; QUTIL::Get2DFrom3DByPosition(spCurImg3D, m_spCur2DFrontal, PLANE_FRONTAL, fixedPos, finalPos3); m_pCurImageFrontal->UpdateFromItkImageFloat(m_spCur2DFrontal, GY2YKIMG_MAG, NON_NEG_SHIFT, bYFlip); //flip Y for display only m_pCurImageFrontal->SetCrosshairPosPhys(probePos2D_X, probePos2D_Y, curPlane); if (enDirection == PRIFLE_HOR) fixedPosProfileFrontal = probePosZ; else fixedPosProfileFrontal = probePosX; ui.lineEdit_ProbePosY->setText(QString::number(finalPos3, 'f', 1)); } float doseGyNorm = 0.01 * (ui.sliderNormDose->value()); //cGy --> Gy m_pCurImageAxial->SetNormValueOriginal(doseGyNorm); m_pCurImageSagittal->SetNormValueOriginal(doseGyNorm); m_pCurImageFrontal->SetNormValueOriginal(doseGyNorm); m_pCurImageAxial->FillPixMapDose(); m_pCurImageSagittal->FillPixMapDose(); m_pCurImageFrontal->FillPixMapDose(); m_pCurImageAxial->m_bDrawCrosshair = true; m_pCurImageSagittal->m_bDrawCrosshair = true; m_pCurImageFrontal->m_bDrawCrosshair = true; m_pCurImageAxial->m_bDrawOverlayText = true; m_pCurImageSagittal->m_bDrawOverlayText = true; m_pCurImageFrontal->m_bDrawOverlayText = true; QString strValAxial = QString::number(m_pCurImageAxial->GetCrosshairOriginalData() * 100, 'f', 1) + " cGy"; QString strValSagittal = QString::number(m_pCurImageSagittal->GetCrosshairOriginalData() * 100, 'f', 1) + " cGy"; QString strValFrontal = QString::number(m_pCurImageFrontal->GetCrosshairOriginalData() * 100, 'f', 1) + " cGy"; float fPercAxial = m_pCurImageAxial->GetCrosshairPercData(); float fPercSagittal = m_pCurImageSagittal->GetCrosshairPercData(); float fPercFrontal = m_pCurImageFrontal->GetCrosshairPercData(); QString strPercAxial = QString::number(fPercAxial, 'f', 1) + "%"; QString strPercSagittal = QString::number(fPercSagittal, 'f', 1) + "%"; QString strPercFrontal = QString::number(fPercFrontal, 'f', 1) + "%"; m_pCurImageAxial->m_strOverlayText = strValAxial + " [" + strPercAxial + "]"; m_pCurImageSagittal->m_strOverlayText = strValSagittal + " [" + strPercSagittal + "]"; m_pCurImageFrontal->m_strOverlayText = strValFrontal + " [" + strPercFrontal + "]"; ui.labelDoseImgAxial->SetBaseImage(m_pCurImageAxial); ui.labelDoseImgSagittal->SetBaseImage(m_pCurImageSagittal); ui.labelDoseImgFrontal->SetBaseImage(m_pCurImageFrontal); ui.labelDoseImgAxial->update(); ui.labelDoseImgSagittal->update(); ui.labelDoseImgFrontal->update(); //Update Table and Chart //1) prepare vector float QUTIL::GetProfile1DByPosition(m_spCur2DAxial, vProfileAxial, fixedPosProfileAxial, enDirection); QUTIL::GetProfile1DByPosition(m_spCur2DSagittal, vProfileSagittal, fixedPosProfileSagittal, enDirection); QUTIL::GetProfile1DByPosition(m_spCur2DFrontal, vProfileFrontal, fixedPosProfileFrontal, enDirection); //fNorm: Gy //float doseGyNormRef = 0.01 * (ui.sliderNormRef->value()); //float doseGyNormComp = 0.01 *(ui.sliderNormComp->value()); if (ui.radioButtonAxial->isChecked()) UpdateTable(vProfileAxial, doseGyNorm, 100.0); else if (ui.radioButtonSagittal->isChecked()) UpdateTable(vProfileSagittal, doseGyNorm, 100.0); else if (ui.radioButtonFrontal->isChecked()) UpdateTable(vProfileFrontal, doseGyNorm, 100.0); SLT_DrawGraph(ui.checkBoxAutoAdjust->isChecked()); if (ui.checkBox_FixedAuto->isChecked()) { if (ui.radioButtonAxial->isChecked()) curPlane = PLANE_AXIAL; else if (ui.radioButtonSagittal->isChecked()) curPlane = PLANE_SAGITTAL; else if (ui.radioButtonFrontal->isChecked()) curPlane = PLANE_FRONTAL; //Set RFA value according to the plane selected. //can be later changed by user if (curPlane == PLANE_AXIAL && enDirection == PRIFLE_HOR) { ui.radio_RFA300_Profile_Cr->setChecked(true); } else if (curPlane == PLANE_SAGITTAL && enDirection == PRIFLE_HOR) { ui.radio_RFA300_PDD->setChecked(true); } else if (curPlane == PLANE_FRONTAL && enDirection == PRIFLE_HOR) { ui.radio_RFA300_Profile_Cr->setChecked(true); } else if (curPlane == PLANE_AXIAL && enDirection == PRIFLE_VER) { ui.radio_RFA300_PDD->setChecked(true); } else if (curPlane == PLANE_SAGITTAL && enDirection == PRIFLE_VER) { ui.radio_RFA300_Profile_In->setChecked(true); } else if (curPlane == PLANE_FRONTAL &&enDirection == PRIFLE_VER) { ui.radio_RFA300_Profile_In->setChecked(true); } //Device Rot is not accounted yet. just follow DICOM convention ui.lineEdit_RFA300_FixedCR->setText(ui.lineEdit_ProbePosX->text()); ui.lineEdit_RFA300_FixedIN->setText(ui.lineEdit_ProbePosZ->text()); //assume Sup: + //ui.lineEdit_RFA300_FixedDepth->setText(ui.lineEdit_ProbePosY->text()); //Get new origin value float curDCM_Y = ui.lineEdit_ProbePosY->text().toFloat(); //-129.5 float curNewOrigin = ui.lineEditTableOrigin->text().toFloat(); //-149.5 float depth_mm = curDCM_Y - curNewOrigin; ui.lineEdit_RFA300_FixedDepth->setText(QString::number(depth_mm, 'f', 1)); } } void beamdata_gen_gui::SLT_UpdateProbePosFromAxial()//by Mouse Left click { ui.radioButtonAxial->setChecked(true); UpdateProbePos(ui.labelDoseImgAxial, PLANE_AXIAL); } void beamdata_gen_gui::SLT_UpdateProbePosFromSagittal() { ui.radioButtonSagittal->setChecked(true); UpdateProbePos(ui.labelDoseImgSagittal, PLANE_SAGITTAL); } void beamdata_gen_gui::SLT_UpdateProbePosFromFrontal() { ui.radioButtonFrontal->setChecked(true); UpdateProbePos(ui.labelDoseImgFrontal, PLANE_FRONTAL); } void beamdata_gen_gui::UpdateProbePos(qyklabel* qlabel, enPLANE enPlane) { YK16GrayImage* pYKImg = qlabel->m_pYK16Image; if (pYKImg == NULL) return; QPoint viewPt = QPoint(qlabel->x, qlabel->y); QPoint crntDataPt = qlabel->GetDataPtFromViewPt(viewPt.x(), viewPt.y()); float originX = pYKImg->m_fOriginX; float originY = pYKImg->m_fOriginY; float spacingX = pYKImg->m_fSpacingX; float spacingY = pYKImg->m_fSpacingY; //float iWidth = pYKImg->m_iWidth; float iHeight = pYKImg->m_iHeight; float physPosX = 0.0; float physPosY = 0.0; if (enPlane == PLANE_AXIAL) { physPosX = crntDataPt.x()*spacingX + originX; physPosY = crntDataPt.y()*spacingY + originY; ui.lineEdit_ProbePosX->setText(QString::number(physPosX, 'f', 1)); ui.lineEdit_ProbePosY->setText(QString::number(physPosY, 'f', 1)); } else if (enPlane == PLANE_SAGITTAL) { physPosX = crntDataPt.x()*spacingX + originX; physPosY = (iHeight - crntDataPt.y() - 1)*spacingY + originY; ui.lineEdit_ProbePosY->setText(QString::number(physPosX, 'f', 1)); ui.lineEdit_ProbePosZ->setText(QString::number(physPosY, 'f', 1)); } else if (enPlane == PLANE_FRONTAL) { physPosX = crntDataPt.x()*spacingX + originX; physPosY = (iHeight - crntDataPt.y() - 1)*spacingY + originY; ui.lineEdit_ProbePosX->setText(QString::number(physPosX, 'f', 1)); ui.lineEdit_ProbePosZ->setText(QString::number(physPosY, 'f', 1)); } SLT_DrawAll(); } void beamdata_gen_gui::UpdateTable(vector& vData, float fNorm, float fMag) { if (m_pTableModel != NULL) { delete m_pTableModel; m_pTableModel = NULL; } int columnSize = 3; int rowSize = vData.size(); if (fNorm <= 0) return; m_pTableModel = new QStandardItemModel(rowSize, columnSize, this); //2 Rows and 3 Columns m_pTableModel->setHorizontalHeaderItem(0, new QStandardItem(QString("mm"))); m_pTableModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Dose[cGy]"))); m_pTableModel->setHorizontalHeaderItem(2, new QStandardItem(QString("Dose[%]"))); for (int i = 0; i < rowSize; i++) { qreal tmpValX1 = vData.at(i).x(); qreal tmpValY1 = vData.at(i).y()*fMag; //Gy --> cGy qreal tmpValY1_Perc = vData.at(i).y() / fNorm * 100.0; QString strValX, strValY,strValY_Perc; strValX = QString::number(tmpValX1, 'f', 1); //cGy strValY = QString::number(tmpValY1, 'f', 1); //cGy strValY_Perc = QString::number(tmpValY1_Perc, 'f', 1); //% m_pTableModel->setItem(i, 0, new QStandardItem(strValX)); m_pTableModel->setItem(i, 1, new QStandardItem(strValY)); m_pTableModel->setItem(i, 2, new QStandardItem(strValY_Perc)); } ui.tableViewProfile->setModel(m_pTableModel); ui.tableViewProfile->resizeColumnsToContents(); ui.tableViewProfile->update(); } void beamdata_gen_gui::SLT_CopyTableToClipboard() { qApp->clipboard()->clear(); QStringList list; int rowCnt = m_pTableModel->rowCount(); int columnCnt = m_pTableModel->columnCount(); //list << "\n"; //for (int i = 0 ; i < columnCnt ; i++) //{ //QFileInfo tmpInfo = QFileInfo(ui.lineEdit_Cur3DFileName->text()); //list << "Index"; //list << tmpInfo.baseName(); list << "\n"; /* m_pTableModel->setHorizontalHeaderItem(0, new QStandardItem(QString("mm"))); m_pTableModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Ref_cGy"))); m_pTableModel->setHorizontalHeaderItem(2, new QStandardItem(QString("Com_cGy"))); m_pTableModel->setHorizontalHeaderItem(3, new QStandardItem(QString("Ref_%"))); m_pTableModel->setHorizontalHeaderItem(4, new QStandardItem(QString("Com_%"))); m_pTableModel->setHorizontalHeaderItem(5, new QStandardItem(QString("Gmma100"))); */ list << "mm"; list << "Dose[cGy]"; list << "Ref[%]"; list << "\n"; for (int j = 0; j < rowCnt; j++) { for (int i = 0; i < columnCnt; i++) { QStandardItem* item = m_pTableModel->item(j, i); list << item->text(); } list << "\n"; } qApp->clipboard()->setText(list.join("\t")); } void beamdata_gen_gui::SLT_DrawGraph(bool bInitMinMax) { if (m_pTableModel == NULL) return; bool bNorm = ui.checkBoxNormalized->isChecked();// show percentage chart //Draw only horizontal, center QVector vAxisX1; //can be rows or columns QVector vAxisY1; //QVector vAxisX2; //can be rows or columns //QVector vAxisY2; //QVector vAxisX3; //can be rows or columns //QVector vAxisY3; //QStandardItemModel m_pTableModel.item() int dataLen = m_pTableModel->rowCount(); // int columnLen = m_pTableModel->columnCount(); if (dataLen < 1) return; ui.customPlotProfile->clearGraphs(); double minX = 9999.0; double maxX = -1.0; double minY = 9999.0; double maxY = -1.0; for (int i = 0; i< dataLen; i++) { QStandardItem* tableItem_0 = m_pTableModel->item(i, 0); QStandardItem* tableItem_1 = m_pTableModel->item(i, 1); QStandardItem* tableItem_2 = m_pTableModel->item(i, 2); double tableVal_0 = tableItem_0->text().toDouble(); double tableVal_1 = tableItem_1->text().toDouble(); double tableVal_2 = tableItem_2->text().toDouble(); if (minX > tableVal_0) minX = tableVal_0; if (maxX < tableVal_0) maxX = tableVal_0; if (minY > tableVal_1) minY = tableVal_1; if (maxY < tableVal_1) maxY = tableVal_1; if (bNorm) //% { vAxisX1.push_back(tableVal_0); vAxisY1.push_back(tableVal_2); } else { vAxisX1.push_back(tableVal_0); vAxisY1.push_back(tableVal_1); } } ui.customPlotProfile->addGraph(); ui.customPlotProfile->graph(0)->setData(vAxisX1, vAxisY1); ui.customPlotProfile->graph(0)->setPen(QPen(Qt::red)); ui.customPlotProfile->graph(0)->setName("Dose"); if (bInitMinMax) { ui.lineEditXMin->setText(QString("%1").arg(minX)); ui.lineEditXMax->setText(QString("%1").arg(maxX)); } double tmpXMin = ui.lineEditXMin->text().toDouble(); double tmpXMax = ui.lineEditXMax->text().toDouble(); double tmpYMin = ui.lineEditYMin->text().toDouble(); double tmpYMax = ui.lineEditYMax->text().toDouble(); ui.customPlotProfile->xAxis->setRange(tmpXMin, tmpXMax); ui.customPlotProfile->yAxis->setRange(tmpYMin, tmpYMax); ui.customPlotProfile->xAxis->setLabel("mm"); if (bNorm) ui.customPlotProfile->yAxis->setLabel("%"); else ui.customPlotProfile->yAxis->setLabel("cGy"); ui.customPlotProfile->setTitle("Dose profile"); QFont titleFont = font(); titleFont.setPointSize(10); ui.customPlotProfile->setTitleFont(titleFont); ui.customPlotProfile->legend->setVisible(true); QFont legendFont = font(); // start out with MainWindow's font.. legendFont.setPointSize(8); // and make a bit smaller for legend ui.customPlotProfile->legend->setFont(legendFont); ui.customPlotProfile->legend->setPositionStyle(QCPLegend::psTopRight); ui.customPlotProfile->legend->setBrush(QBrush(QColor(255, 255, 255, 200))); ui.customPlotProfile->replot(); } void beamdata_gen_gui::SLT_GoCenterPos() //double click { QComboBox* crntCombo = ui.comboBoxFileName; int curIdx = crntCombo->currentIndex(); //this should be basename if (curIdx < 0) return; if (m_vDoseImages.empty()) return; FloatImageType::Pointer spCurFloat3D = m_vDoseImages.at(curIdx); FloatImageType::PointType ptOrigin = spCurFloat3D->GetOrigin(); FloatImageType::SizeType imgSize = spCurFloat3D->GetBufferedRegion().GetSize(); //dimension FloatImageType::SpacingType imgSpacing = spCurFloat3D->GetSpacing(); //dimension VEC3D middlePtPos; middlePtPos.x = ptOrigin[0] + imgSize[0] * imgSpacing[0] / 2.0; middlePtPos.y = ptOrigin[1] + imgSize[1] * imgSpacing[1] / 2.0; middlePtPos.z = ptOrigin[2] + imgSize[2] * imgSpacing[2] / 2.0; ui.lineEdit_ProbePosX->setText(QString::number(middlePtPos.x, 'f', 1)); ui.lineEdit_ProbePosY->setText(QString::number(middlePtPos.y, 'f', 1)); ui.lineEdit_ProbePosZ->setText(QString::number(middlePtPos.z, 'f', 1)); SLT_RestoreZoomPan(); SLT_DrawAll(); //triggered when Go Position button } void beamdata_gen_gui::SaveDoseIBAGenericTXTFromItk(QString strFilePath, FloatImage2DType::Pointer& spFloatDose) { if (!spFloatDose) return; //Set center point first (from MainDLg --> TIF) //this will update m_rXPos.a, b //SetRationalCenterPosFromDataCenter(dataCenterPoint); //POINT ptCenter = GetDataCenter(); //will get dataPt from m_rXPos FloatImage2DType::PointType ptOrigin = spFloatDose->GetOrigin(); FloatImage2DType::SizeType imgSize = spFloatDose->GetBufferedRegion().GetSize(); //dimension FloatImage2DType::SpacingType imgSpacing = spFloatDose->GetSpacing(); //dimension int imgWidth = imgSize[0]; int imgHeight = imgSize[1]; float spacingX = imgSpacing[0]; float spacingY = imgSpacing[1]; float originX = ptOrigin[0]; float originY = ptOrigin[1]; ofstream fout; fout.open(strFilePath.toLocal8Bit().constData()); fout << "" << endl; fout << endl; fout << "" << endl; fout << "Separator: [TAB]" << endl; fout << "Workspace Name: n/a" << endl; fout << "File Name: n/a" << endl; fout << "Image Name: n/a" << endl; fout << "Radiation Type: Photons" << endl; fout << "Energy: 0.0 MV" << endl; fout << "SSD: 10.0 cm" << endl; fout << "SID: 100.0 cm" << endl; fout << "Field Size Cr: 10.0 cm" << endl; fout << "Field Size In: 10.0 cm" << endl; fout << "Data Type: Abs. Dose" << endl; fout << "Data Factor: 1.000" << endl; fout << "Data Unit: mGy" << endl; fout << "Length Unit: cm" << endl; fout << "Plane: " << "XY" << endl; fout << "No. of Columns: " << imgWidth << endl; fout << "No. of Rows: " << imgHeight << endl; fout << "Number of Bodies: " << 1 << endl; fout << "Operators Note: made by ykp" << endl; fout << "" << endl; fout << endl; fout << "" << endl; fout << "Plane Position: 0.00 cm" << endl; fout << endl; fout << "X[cm]" << "\t"; QString strTempX; double fPosX = 0.0; for (int i = 0; i < imgWidth; i++) { fPosX = (originX + i*spacingX) * 0.1;//mm --> cm fout << QString::number(fPosX, 'f', 3).toLocal8Bit().constData() << "\t"; } fout << endl; fout << "Y[cm]" << endl; QString strTempY; double fPosY = 0.0; //cm int imgVal = 0; // mGy, integer itk::ImageRegionConstIterator it(spFloatDose, spFloatDose->GetRequestedRegion()); it.GoToBegin(); float* pImg; pImg = new float [imgWidth*imgHeight]; int idx = 0; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { pImg[idx] = it.Get(); idx++; } for (int i = imgHeight - 1; i >= 0; i--) { //spacing: mm/px --> to make a cm, * 0.1 fPosY = (originY + i*spacingY) * 0.1; //--> Image writing From bottom to Top // Y value < 0 means Inferior in XY plane --> more make sense QString strYVal = QString::number(fPosY, 'f', 3); fout << strYVal.toLocal8Bit().constData() << "\t"; for (int j = 0; j < imgWidth; j++) { imgVal = qRound(pImg[imgWidth*i + j] * 1000); // Gy --> mGy fout << imgVal << "\t"; } fout << endl; } delete [] pImg; fout << "" << endl; fout << "" << endl; // POINT GetDataCenter();//data center index, 0 based // double m_spacingX; // mm/pixel //double m_spacingY;// mm/pixel fout.close(); return; } void beamdata_gen_gui::SLT_WhenSelectCombo() { QComboBox* crntCombo = ui.comboBoxFileName; int curIdx = crntCombo->currentIndex(); //this should be basename int iCnt = crntCombo->count(); if (iCnt < 1) return; if ((int)m_vRefDose.size() != iCnt || (int)m_strlistPath.size() != iCnt) { cout << "Error! SLT_WhenSelectCombo file count doesn't match!" << endl; cout << "crntComboCnt " << iCnt << endl; cout << "m_vRefDose " << m_vRefDose.size() << endl; cout << "m_strlistPath " << m_strlistPath.size() << endl; return; } if ((int)(m_vDoseImages.size()) != iCnt) { cout << "Error! ItkImage Pointer count doesn't match!" << endl; return; } disconnect(ui.sliderNormDose, SIGNAL(valueChanged(int)), this, SLOT(SLT_DrawAll())); ui.sliderNormDose->setValue(qRound(m_vRefDose.at(curIdx) * 100)); //Gy to cGy connect(ui.sliderNormDose, SIGNAL(valueChanged(int)), this, SLOT(SLT_DrawAll())); //QString strPath_Cur = m_strlistPath.at(curIdx); //always readable mha format //QFileInfo info_ref = QFileInfo(strPath_Cur); //SLT_WhenChangePlane(); //RestorePanZoom + DrawAll SLT_RestoreZoomPan(); SLT_DrawAll(); } void beamdata_gen_gui::SLT_MouseWheelUpdateAxial() { MouseWheelUpdateCommon(PLANE_AXIAL); } void beamdata_gen_gui::SLT_MouseWheelUpdateSagittal() { MouseWheelUpdateCommon(PLANE_SAGITTAL); } void beamdata_gen_gui::SLT_MouseWheelUpdateFrontal() { MouseWheelUpdateCommon(PLANE_FRONTAL); } void beamdata_gen_gui::MouseWheelUpdateCommon(enPLANE curPlane) { if (ui.labelDoseImgAxial->m_pYK16Image == NULL || ui.labelDoseImgSagittal->m_pYK16Image == NULL || ui.labelDoseImgFrontal->m_pYK16Image == NULL) { return; } QComboBox* crntCombo = ui.comboBoxFileName; int curIdx = crntCombo->currentIndex(); //this should be basename if (curIdx < 0) return; if (curIdx >= (int)(m_vDoseImages.size())) return; if (ui.checkBox_ScrollZoom->isChecked()) { double oldZoom =1.0; double fWeighting = 0.2; float vZoomVal = 1.0; if (curPlane == PLANE_AXIAL) { oldZoom = ui.labelDoseImgAxial->m_pYK16Image->m_fZoom; vZoomVal = oldZoom + ui.labelDoseImgAxial->m_iMouseWheelDelta * fWeighting; } else if (curPlane == PLANE_SAGITTAL) { oldZoom = ui.labelDoseImgSagittal->m_pYK16Image->m_fZoom; vZoomVal = oldZoom + ui.labelDoseImgSagittal->m_iMouseWheelDelta * fWeighting; } else if (curPlane == PLANE_FRONTAL) { oldZoom = ui.labelDoseImgFrontal->m_pYK16Image->m_fZoom; vZoomVal = oldZoom + ui.labelDoseImgFrontal->m_iMouseWheelDelta * fWeighting; } ui.labelDoseImgAxial->m_pYK16Image->SetZoom(vZoomVal); ui.labelDoseImgSagittal->m_pYK16Image->SetZoom(vZoomVal); ui.labelDoseImgFrontal->m_pYK16Image->SetZoom(vZoomVal); } else { FloatImageType::Pointer spCurImg = m_vDoseImages.at(curIdx); VEC3D ptLimitStart = { 0.0, 0.0, 0.0 }; VEC3D ptLimitEnd = { 0.0, 0.0, 0.0 }; QUTIL::GetGeometricLimitFloatImg(spCurImg, ptLimitStart, ptLimitEnd); double fWeighting = 1.0; float probePosX = ui.lineEdit_ProbePosX->text().toFloat(); float probePosY = ui.lineEdit_ProbePosY->text().toFloat(); float probePosZ = ui.lineEdit_ProbePosZ->text().toFloat(); if (curPlane == PLANE_AXIAL) { probePosZ = probePosZ + ui.labelDoseImgAxial->m_iMouseWheelDelta*fWeighting; if (probePosZ <= ptLimitStart.z) probePosZ = ptLimitStart.z; if (probePosZ >= ptLimitEnd.z) probePosZ = ptLimitEnd.z; ui.lineEdit_ProbePosZ->setText(QString::number(probePosZ, 'f', 1)); } else if (curPlane == PLANE_SAGITTAL) { probePosX = probePosX + ui.labelDoseImgSagittal->m_iMouseWheelDelta*fWeighting; if (probePosX <= ptLimitStart.x) probePosX = ptLimitStart.x; if (probePosX >= ptLimitEnd.x) probePosX = ptLimitEnd.x; ui.lineEdit_ProbePosX->setText(QString::number(probePosX, 'f', 1)); } else if (curPlane == PLANE_FRONTAL) { probePosY = probePosY + ui.labelDoseImgFrontal->m_iMouseWheelDelta*fWeighting; if (probePosY <= ptLimitStart.y) probePosY = ptLimitStart.y; if (probePosY >= ptLimitEnd.y) probePosY = ptLimitEnd.y; ui.lineEdit_ProbePosY->setText(QString::number(probePosY, 'f', 1)); } } SLT_DrawAll(); } void beamdata_gen_gui::SLT_RestoreZoomPan() { if (ui.labelDoseImgAxial->m_pYK16Image == NULL || ui.labelDoseImgSagittal->m_pYK16Image == NULL || ui.labelDoseImgFrontal->m_pYK16Image == NULL) { return; } ui.labelDoseImgAxial->setFixedWidth(DEFAULT_LABEL_WIDTH); ui.labelDoseImgAxial->setFixedHeight(DEFAULT_LABEL_HEIGHT); ui.labelDoseImgSagittal->setFixedWidth(DEFAULT_LABEL_WIDTH); ui.labelDoseImgSagittal->setFixedHeight(DEFAULT_LABEL_HEIGHT); ui.labelDoseImgFrontal->setFixedWidth(DEFAULT_LABEL_WIDTH); ui.labelDoseImgFrontal->setFixedHeight(DEFAULT_LABEL_HEIGHT); ui.labelDoseImgAxial->m_pYK16Image->SetZoom(1.0); ui.labelDoseImgSagittal->m_pYK16Image->SetZoom(1.0); ui.labelDoseImgFrontal->m_pYK16Image->SetZoom(1.0); ui.labelDoseImgAxial->m_pYK16Image->SetOffset(0,0); ui.labelDoseImgSagittal->m_pYK16Image->SetOffset(0, 0); ui.labelDoseImgFrontal->m_pYK16Image->SetOffset(0, 0); } void beamdata_gen_gui::SLT_MousePressedRightAxial() { m_bMousePressedRightAxial = true; WhenMousePressedRight(ui.labelDoseImgAxial); } void beamdata_gen_gui::SLT_MousePressedRightSagittal() { m_bMousePressedRightSagittal = true; WhenMousePressedRight(ui.labelDoseImgSagittal); } void beamdata_gen_gui::SLT_MousePressedRightFrontal() { m_bMousePressedRightFrontal = true; WhenMousePressedRight(ui.labelDoseImgFrontal); } void beamdata_gen_gui::WhenMousePressedRight(qyklabel* pWnd) { if (pWnd->m_pYK16Image == NULL) return; m_ptPanStart.setX(pWnd->x); m_ptPanStart.setY(pWnd->y); m_ptOriginalDataOffset.setX(pWnd->m_pYK16Image->m_iOffsetX); m_ptOriginalDataOffset.setY(pWnd->m_pYK16Image->m_iOffsetY); } void beamdata_gen_gui::SLT_MouseReleasedRightAxial() { m_bMousePressedRightAxial = false; } void beamdata_gen_gui::SLT_MouseReleasedRightSagittal() { m_bMousePressedRightSagittal = false; } void beamdata_gen_gui::SLT_MouseReleasedRightFrontal() { m_bMousePressedRightFrontal = false; } void beamdata_gen_gui::UpdatePanCommon(qyklabel* qWnd) { if (qWnd->m_pYK16Image == NULL) return; double dspWidth = qWnd->width(); double dspHeight = qWnd->height(); int dataWidth = qWnd->m_pYK16Image->m_iWidth; int dataHeight = qWnd->m_pYK16Image->m_iHeight; if (dataWidth*dataHeight == 0) return; // int dataX = qWnd->GetDataPtFromMousePos().x(); // int dataY = qWnd->GetDataPtFromMousePos().y(); ////Update offset information of dispImage //GetOriginalDataPos (PanStart) //offset should be 0.. only relative distance matters. offset is in realtime changing QPoint ptDataPanStartRel = qWnd->View2DataExt(m_ptPanStart, dspWidth, dspHeight, dataWidth, dataHeight, QPoint(0, 0), qWnd->m_pYK16Image->m_fZoom); QPoint ptDataPanEndRel = qWnd->View2DataExt(QPoint(qWnd->x, qWnd->y), dspWidth, dspHeight, dataWidth, dataHeight, QPoint(0, 0), qWnd->m_pYK16Image->m_fZoom); //int dspOffsetX = pOverlapWnd->x - m_ptPanStart.x(); //int dspOffsetY = m_ptPanStart.y() - pOverlapWnd->y; /*QPoint ptDataStart= pOverlapWnd->GetDataPtFromViewPt(m_ptPanStart.x(), m_ptPanStart.y()); QPoint ptDataEnd= pOverlapWnd->GetDataPtFromViewPt(pOverlapWnd->x, pOverlapWnd->y);*/ int curOffsetX = ptDataPanEndRel.x() - ptDataPanStartRel.x(); int curOffsetY = ptDataPanEndRel.y() - ptDataPanStartRel.y(); int prevOffsetX = m_ptOriginalDataOffset.x(); int prevOffsetY = m_ptOriginalDataOffset.y(); //double fZoom = qWnd->m_pYK16Image->m_fZoom; qWnd->m_pYK16Image->SetOffset(prevOffsetX - curOffsetX, prevOffsetY - curOffsetY); //SLT_DrawAll(); } void beamdata_gen_gui::SLT_UpdatePanSettingAxial() //Mouse Move { if (!m_bMousePressedRightAxial) return; if (ui.labelDoseImgAxial->m_pYK16Image == NULL || ui.labelDoseImgSagittal->m_pYK16Image == NULL || ui.labelDoseImgFrontal->m_pYK16Image == NULL) return; UpdatePanCommon(ui.labelDoseImgAxial); //Sync offset int offsetX = ui.labelDoseImgAxial->m_pYK16Image->m_iOffsetX; int offsetY = ui.labelDoseImgAxial->m_pYK16Image->m_iOffsetY; ui.labelDoseImgAxial->m_pYK16Image->SetOffset(offsetX, offsetY); //check the other plane /* int offsetX = ui.labelDoseImgAxial->m_pYK16Image->m_iOffsetX; int offsetY = ui.labelDoseImgAxial->m_pYK16Image->m_iOffsetY; ui.labelDoseImgFrontal->m_pYK16Image->SetOffset(offsetX, offsetY); */ SLT_DrawAll(); } void beamdata_gen_gui::SLT_UpdatePanSettingSagittal() { if (!m_bMousePressedRightSagittal) return; if (ui.labelDoseImgAxial->m_pYK16Image == NULL || ui.labelDoseImgSagittal->m_pYK16Image == NULL || ui.labelDoseImgFrontal->m_pYK16Image == NULL) return; UpdatePanCommon(ui.labelDoseImgSagittal); //Sync offset int offsetX = ui.labelDoseImgSagittal->m_pYK16Image->m_iOffsetX; int offsetY = ui.labelDoseImgSagittal->m_pYK16Image->m_iOffsetY; ui.labelDoseImgSagittal->m_pYK16Image->SetOffset(offsetX, offsetY); //check the other plane SLT_DrawAll(); } void beamdata_gen_gui::SLT_UpdatePanSettingFrontal() { if (!m_bMousePressedRightFrontal) return; if (ui.labelDoseImgAxial->m_pYK16Image == NULL || ui.labelDoseImgSagittal->m_pYK16Image == NULL || ui.labelDoseImgFrontal->m_pYK16Image == NULL) return; UpdatePanCommon(ui.labelDoseImgFrontal); //Sync offset int offsetX = ui.labelDoseImgFrontal->m_pYK16Image->m_iOffsetX; int offsetY = ui.labelDoseImgFrontal->m_pYK16Image->m_iOffsetY; ui.labelDoseImgFrontal->m_pYK16Image->SetOffset(offsetX, offsetY); //check the other plane SLT_DrawAll(); } void beamdata_gen_gui::SLTM_RenameRDFilesByDICOMInfo() { QStringList files = QFileDialog::getOpenFileNames(this, "Select one or more files to open", m_strPathInputDir, "DICOM-RD files (*.dcm)"); int cnt = files.size(); if (cnt <= 0) return; QString strMsg = "Original file names will be gone. Backup is strongly recommended. Continue?"; QMessageBox msgBox; msgBox.setText(strMsg); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); int res = msgBox.exec(); if (res == QMessageBox::Yes) { } RenameFileByDCMInfo(files); } void beamdata_gen_gui::RenameFileByDCMInfo(QStringList& filenameList) { int size = filenameList.size(); QString crntFilePath; //Rt_study rt_study; for (int a = 0; a < size; a++) { crntFilePath = filenameList.at(a); //1) contructor Dcmtk_rt_study dss(crntFilePath.toLocal8Bit().constData()); //2) parse directory: this will link dicome seriese to proper one (e.g. ds_dose) dss.parse_directory(); Dcmtk_series *pDcmSeries = dss.d_ptr->ds_rtdose; if (pDcmSeries == NULL) continue; //Pt name: 0010, 0010 QString strPtId = QString(pDcmSeries->get_cstr(DcmTagKey(0x0010, 0x0020))); QString strRDType = QString(pDcmSeries->get_cstr(DcmTagKey(0x3004, 0x000A))); //QString strFractionGroup = QString(pDcmSeries->get_cstr(DcmTagKey(0x300C, 0x0022))); //QString strBeamNumberTmp = QString(pDcmSeries->get_cstr(DcmTagKey(0x300C, 0x0006))); //long int iFractionGroup = 0; //long int iBeamNumber = 0; DcmSequenceOfItems *seqRefPlan = 0; bool rc = pDcmSeries->get_sequence(DcmTagKey(0x300c, 0x0002), seqRefPlan); //rc = pDcmSeries->get_sequence(DcmTagKey(0x300C, 0x0020), seqFractionGroup); long int iValBeamNumber = 0; long int iValFractionGroupNumber = 0; if (rc) { //DcmSequenceOfItems *seqFractionGroup = 0; int iNumOfRefPlanSeq = (int)(seqRefPlan->card()); for (int i = 0; i < iNumOfRefPlanSeq; i++) { OFCondition orc; // const char *strVal = 0; DcmItem *itemRefPlan = seqRefPlan->getItem(i); //orc = item->findAndGetString(DcmTagKey(0x0008, 0x1150), strVal);//it works! /*orc = item->findAndGetLongInt(DcmTagKey(0x300C, 0x0022), iVal);*/ /*if (!orc.good()){ continue; }*/ DcmSequenceOfItems *seqFractionGroup = 0; //rc = pDcmSeries->get_sequence(DcmTagKey(0x300c, 0x0020), seqFractionGroup);//ReferencedFractionGroupSequence orc = itemRefPlan->findAndGetSequence(DCM_ReferencedFractionGroupSequence, seqFractionGroup);//ReferencedFractionGroupSequence if (orc.good()) { int iNumOfFractionGroup = seqFractionGroup->card(); DcmItem *itemFractionGroup = 0; for (int j = 0; j < iNumOfFractionGroup; j++) { itemFractionGroup = seqFractionGroup->getItem(j); DcmSequenceOfItems *seqRefBeam = 0; orc = itemFractionGroup->findAndGetLongInt(DCM_ReferencedFractionGroupNumber, iValFractionGroupNumber); //cout << "Group Number changed = " << iValFractionGroupNumber << endl; if (!orc.good()) cout << "error! refFraction group number is not found" << endl; orc = itemFractionGroup->findAndGetSequence(DCM_ReferencedBeamSequence, seqRefBeam);//ReferencedFractionGroupSequence if (!orc.good()) continue; int iNumOfRefBeam = seqRefBeam->card(); for (int k = 0; k < iNumOfRefBeam; k++) { DcmItem *itemBeam = 0; itemBeam = seqRefBeam->getItem(k); //orc = itemBeam->findAndGetLongInt(DcmTagKey(0x300C, 0x0006), iValBeamNumber); orc = itemBeam->findAndGetLongInt(DCM_ReferencedBeamNumber, iValBeamNumber); //cout << "iValBeamNumber changed = " << iValBeamNumber << endl; } } } } //iVal } //long int iFractionGroup = 0; //long int iBeamNumber = 0; //cout << "iFractionGroup " << iValFractionGroupNumber << endl; //cout << "iBeamNumber " << iValBeamNumber << endl; QString strFractionGroupNumber; strFractionGroupNumber = strFractionGroupNumber.sprintf("%02d", (int)iValFractionGroupNumber); QString strBeamNumber; strBeamNumber = strBeamNumber.sprintf("%03d", (int)iValBeamNumber); QFileInfo fileInfo = QFileInfo(crntFilePath); QDir dir = fileInfo.absoluteDir(); QString newBaseName = strPtId + "_" + strRDType + "_" + strFractionGroupNumber + "_" + strBeamNumber; //QString extStr = fileInfo.completeSuffix(); QString newFileName = newBaseName.append(".").append("dcm"); QString newPath = dir.absolutePath() + "/" + newFileName; //cout << newPath.toLocal8Bit().constData() << endl; //extract former part QFile::rename(crntFilePath, newPath); }// end of for, cout << "In total "<< size << " files were successfully renamed" << endl; } void beamdata_gen_gui::SLT_WhenChangePlane() { //Change the Graph SLT_DrawAll(); //is this enough to update the graph? } void beamdata_gen_gui::SLT_TableEdit_Invert() { /* cout << "RFA " << m_vBeamDataRFA.size() << endl; if (m_vBeamDataRFA.size() > 0) cout << "num of profile data " << m_vBeamDataRFA.at(0).m_vDoseProfile.size() << endl; return;*/ vector vProfile1D; QUTIL::Get1DProfileFromTable(m_pTableModel, 0, 2, vProfile1D); //x: mm , y: % //Edit profile vector vProfile1D_new; vector::iterator it; QPointF fPt_old; QPointF fPt_new; for (it = vProfile1D.begin(); it != vProfile1D.end(); ++it) { fPt_old = (*it); fPt_new.setX(-fPt_old.x()); fPt_new.setY(fPt_old.y()); vProfile1D_new.push_back(fPt_new); } //sort std::sort(vProfile1D_new.begin(), vProfile1D_new.end(), QUTIL::QPointF_Compare); ////Update Table //vProfile1D_new// CURRENTLY THIS IS DOSE //CURRENTLY DOSE VALUE = percent --> Norm=100, Mag=1.0 UpdateTable(vProfile1D_new, 100.0, 1.0); //from now, dose cGy = % SLT_DrawGraph(ui.checkBoxAutoAdjust->isChecked()); } void beamdata_gen_gui::SLT_TableEdit_SetOrigin() { vector vProfile1D; QUTIL::Get1DProfileFromTable(m_pTableModel, 0, 2, vProfile1D); //x: mm , y: % //Get new origin value float newOriginX = ui.lineEditTableOrigin->text().toFloat(); //Edit profile vector vProfile1D_new; vector::iterator it; QPointF fPt_old; QPointF fPt_new; for (it = vProfile1D.begin(); it != vProfile1D.end(); ++it) { fPt_old = (*it); fPt_new.setX(fPt_old.x() - newOriginX); fPt_new.setY(fPt_old.y()); vProfile1D_new.push_back(fPt_new); } //sort std::sort(vProfile1D_new.begin(), vProfile1D_new.end(), QUTIL::QPointF_Compare); ////Update Table //vProfile1D_new// CURRENTLY THIS IS DOSE //CURRENTLY DOSE VALUE = percent --> Norm=100, Mag=1.0 UpdateTable(vProfile1D_new, 100.0, 1.0); //from now, dose cGy = % SLT_DrawGraph(ui.checkBoxAutoAdjust->isChecked()); //applies only depth mode if (ui.radio_RFA300_PDD->isChecked()) { float curDCM_Y = ui.lineEdit_ProbePosY->text().toFloat(); //-129.5 float curNewOrigin = ui.lineEditTableOrigin->text().toFloat(); //-149.5 float depth_mm = curDCM_Y - curNewOrigin; ui.lineEdit_RFA300_FixedDepth->setText(QString::number(depth_mm, 'f', 1)); } } void beamdata_gen_gui::SLT_TableEdit_TrimXMin() { vector vProfile1D; QUTIL::Get1DProfileFromTable(m_pTableModel, 0, 2, vProfile1D); //x: mm , y: % //Get new origin value float newTrimX_Min = ui.lineEditTableMin->text().toFloat(); float newTrimX_Max = ui.lineEditTableMax->text().toFloat(); //Edit profile vector vProfile1D_new; vector::iterator it; QPointF fPt_old; QPointF fPt_new; for (it = vProfile1D.begin(); it != vProfile1D.end(); ++it) { fPt_old = (*it); if (fPt_old.x() >= newTrimX_Min) { fPt_new.setX(fPt_old.x()); fPt_new.setY(fPt_old.y()); vProfile1D_new.push_back(fPt_new); } } //sort std::sort(vProfile1D_new.begin(), vProfile1D_new.end(), QUTIL::QPointF_Compare); ////Update Table //vProfile1D_new// CURRENTLY THIS IS DOSE //CURRENTLY DOSE VALUE = percent --> Norm=100, Mag=1.0 UpdateTable(vProfile1D_new, 100.0, 1.0); //from now, dose cGy = % SLT_DrawGraph(ui.checkBoxAutoAdjust->isChecked()); } void beamdata_gen_gui::SLT_TableEdit_TrimXMax() { vector vProfile1D; QUTIL::Get1DProfileFromTable(m_pTableModel, 0, 2, vProfile1D); //x: mm , y: % //Get new origin value float newTrimX_Min = ui.lineEditTableMin->text().toFloat(); float newTrimX_Max = ui.lineEditTableMax->text().toFloat(); //Edit profile vector vProfile1D_new; vector::iterator it; QPointF fPt_old; QPointF fPt_new; for (it = vProfile1D.begin(); it != vProfile1D.end(); ++it) { fPt_old = (*it); if (fPt_old.x() <= newTrimX_Max) { fPt_new.setX(fPt_old.x()); fPt_new.setY(fPt_old.y()); vProfile1D_new.push_back(fPt_new); } } //sort std::sort(vProfile1D_new.begin(), vProfile1D_new.end(), QUTIL::QPointF_Compare); ////Update Table //vProfile1D_new// CURRENTLY THIS IS DOSE //CURRENTLY DOSE VALUE = percent --> Norm=100, Mag=1.0 UpdateTable(vProfile1D_new, 100.0, 1.0); //from now, dose cGy = % SLT_DrawGraph(ui.checkBoxAutoAdjust->isChecked()); } void beamdata_gen_gui::SLT_TableEdit_Restore() { //DrawAll or goto button SLT_DrawAll(); } void beamdata_gen_gui::SLT_AddBeamDataToRFA300List() { if (m_pTableModel == NULL) return; vector vProfile1D; QUTIL::Get1DProfileFromTable(m_pTableModel, 0, 2, vProfile1D); //x: mm , y: % CBeamDataRFA beamDataRFA; beamDataRFA.m_vDoseProfile = vProfile1D; //deep copy? if (ui.radio_RFA300_PDD->isChecked()) { beamDataRFA.m_ScanType = ST_PDD; } else if (ui.radio_RFA300_Profile_Cr->isChecked()) { beamDataRFA.m_ScanType = ST_PROFILE_CR; } else if (ui.radio_RFA300_Profile_In->isChecked()) { beamDataRFA.m_ScanType = ST_PROFILE_IN; } if (ui.radio_RFA300_BT_photon->isChecked()) { beamDataRFA.m_BeamType = BT_PHOTON; } else if (ui.radio_RFA300_BT_electron->isChecked()) { beamDataRFA.m_BeamType = BT_ELECTRON; } else if (ui.radio_RFA300_BT_proton->isChecked()) { beamDataRFA.m_BeamType = BT_PROTON; } beamDataRFA.m_fBeamEnergy = ui.lineEdit_RFA300_Energy->text().toFloat(); beamDataRFA.m_fFieldSizeX_cm = ui.lineEdit_RFA300_FS_Xcm->text().toFloat(); beamDataRFA.m_fFieldSizeY_cm = ui.lineEdit_RFA300_FS_Ycm->text().toFloat(); beamDataRFA.m_fSSD_cm = ui.lineEdit_RFA300_SSDcm->text().toFloat(); beamDataRFA.m_fFixedPosX_mm = ui.lineEdit_RFA300_FixedCR->text().toFloat(); //no device rot applied yet. just dicom beamDataRFA.m_fFixedPosY_mm = ui.lineEdit_RFA300_FixedIN->text().toFloat(); beamDataRFA.m_fFixedPosDepth_mm = ui.lineEdit_RFA300_FixedDepth->text().toFloat(); m_vBeamDataRFA.push_back(beamDataRFA); //deep copy? UpdateBeamDataList(); SLT_DrawGraphRFA300(ui.checkBoxAutoAdjust_RFA300->isChecked()); } void beamdata_gen_gui::UpdateBeamDataList() //Update List UI: listWidgetRFA300 { ui.listWidgetRFA300->clear(); /*if (m_vBeamDataRFA.empty()) { return; } */ // int iBeamDataCnt = m_vBeamDataRFA.size(); vector::iterator it; QString strBeamName; for (it = m_vBeamDataRFA.begin(); it != m_vBeamDataRFA.end(); ++it) { strBeamName = (*it).GetBeamName(); ui.listWidgetRFA300->addItem(strBeamName); } } void beamdata_gen_gui::SLT_ClearBeamDataRFA300() { m_vBeamDataRFA.clear(); UpdateBeamDataList(); SLT_DrawGraphRFA300(ui.checkBoxAutoAdjust_RFA300->isChecked()); } void beamdata_gen_gui::SLT_ExportBeamDataRFA300() { if (m_vBeamDataRFA.size() < 1) { QUTIL::ShowErrorMessage("Error! no beam data to export"); return; } QString strFilePath = QFileDialog::getSaveFileName(this, "Export Beam data as RFA300 format",m_strPathInputDir, "RFA300 (*.asc)", 0, 0); if (strFilePath.length() < 1) return; if (!ExportBeamDataRFA300(strFilePath, m_vBeamDataRFA)) { QUTIL::ShowErrorMessage("Error! RFA300 export failed"); } else { cout << "RFA300 file was successfully exported" << endl; } } bool beamdata_gen_gui::ExportBeamDataRFA300(QString& strPathOut, vector& vBeamDataRFA) { ofstream fout; fout.open(strPathOut.toLocal8Bit().constData()); int iBeamCnt = vBeamDataRFA.size(); if (iBeamCnt < 1) return false; //global header QString gStrHeader1, gStrHeader2; gStrHeader1.sprintf(":MSR \t%d\t # No. of measurement in file", iBeamCnt); gStrHeader2.sprintf(":SYS BDS 0 # Beam Data Scanner System"); fout << gStrHeader1.toLocal8Bit().constData() << endl; fout << gStrHeader2.toLocal8Bit().constData() << endl; vector::iterator it; QDateTime curDateTime = QDateTime::currentDateTime(); QString strDate = curDateTime.toString("MM-dd-yyyy"); QString strTime = curDateTime.toString("hh:mm:ss"); int iBeamIdx = 0; VEC3D ptStart, ptEnd; ptStart.x = 0.0; ptStart.y = 0.0; ptStart.z = 0.0; ptEnd.x = 0.0; ptEnd.y = 0.0; ptEnd.z = 0.0; QString strSTS, strEDS; QString strBeamType; QString strEnergy; QString strSSD; QString strBRD; QString strWEG; QString strFS; QString strSCN; QString strProfileDepth; //mm, seems to be no need for (it = vBeamDataRFA.begin(); it != vBeamDataRFA.end(); ++it) { CBeamDataRFA* pCurBeam = &(*it); int iCntDataPt = pCurBeam->m_vDoseProfile.size(); if (iCntDataPt < 1) { // iBeamIdx++; continue; //skip, if there is no data } float valX, valY; float valFixedX = 0.0; //mm float valFixedY = 0.0; float valFixedDepth = 0.0; //mm int iMeasType = -1; int iNumOfDataPt = pCurBeam->m_vDoseProfile.size(); strSSD.sprintf("%4d", qRound(pCurBeam->m_fSSD_cm*10.0)); strBRD.sprintf("%4d", qRound(pCurBeam->m_fSAD_cm*10.0)); //BeamReferenceDist strWEG.sprintf("%d", pCurBeam->m_iWedgeType); //0 //Inplane comes first! //strFS.sprintf("%d\t%d", qRound(pCurBeam->m_fFieldSizeX_cm*10.0), qRound(pCurBeam->m_fFieldSizeY_cm*10.0)); strFS.sprintf("%d\t%d", qRound(pCurBeam->m_fFieldSizeY_cm*10.0), qRound(pCurBeam->m_fFieldSizeX_cm*10.0)); switch (pCurBeam->m_BeamType) { case BT_PHOTON: strBeamType = "PHO\t"; break; case BT_ELECTRON: strBeamType = "ELE\t"; break; case BT_PROTON: strBeamType = "UDF\t"; break; default: strBeamType = "UDF\t"; // unknown break; } strEnergy.sprintf("% 7.1f", pCurBeam->m_fBeamEnergy); strBeamType = strBeamType + strEnergy; switch (pCurBeam->m_ScanType) // DPT, PRO, MTX, DIA, UDF { case ST_PDD: strSCN = "DPT"; iMeasType = 1; break; case ST_PROFILE_CR: strSCN = "PRO"; iMeasType = 2; break; case ST_PROFILE_IN: strSCN = "PRO"; iMeasType = 2; break; default: strSCN = "UDF"; // unknown break; } //Header fout << "#" << endl; fout << "# RFA300 ASCII Measurement Dump ( BDS format )" << endl; fout << "#" << endl; fout << "# Measurement number " << "\t" << iBeamIdx+1 << endl; fout << "#" << endl; //Beam data header fout << "%VNR " << "1.0" << endl; fout << "%MOD \t" << "RAT" << endl;//ratio fout << "%TYP \t" << "SCN" << endl; fout << "%SCN \t" << strSCN.toLocal8Bit().constData() << endl; fout << "%FLD \t" << "ION" << endl; fout << "%DAT \t" << strDate.toLocal8Bit().constData() << endl; fout << "%TIM \t" << strTime.toLocal8Bit().constData() << endl; fout << "%FSZ \t" << strFS.toLocal8Bit().constData() << endl; fout << "%BMT \t" << strBeamType.toLocal8Bit().constData() << endl; fout << "%SSD \t" << strSSD.toLocal8Bit().constData() << endl; fout << "%BUP \t" << "0" << endl; fout << "%BRD \t" << strBRD.toLocal8Bit().constData() << endl; fout << "%FSH \t" << "-1" << endl; fout << "%ASC \t" << "0" << endl; fout << "%WEG \t" << strWEG.toLocal8Bit().constData() << endl; //open field fout << "%GPO \t" << "0" << endl; fout << "%CPO \t" << "0" << endl; //This MEA was originally 1 even in Profile. it seems to have caused the crash fout << "%MEA \t" << iMeasType << endl; //-1 undefined, 0: abs dose, 1: open depth, 2: open profile, 4:wedge, 5: wedge depth, 6: wedge profile fout << "%PRD \t" << "0.0" << endl; //ProfileDepth in 0.1 mm // Omnipro doesn't seem to care fout << "%PTS \t" << iNumOfDataPt << endl; if (pCurBeam->m_ScanType == ST_PDD) { valFixedX = pCurBeam->m_fFixedPosX_mm; valFixedY = pCurBeam->m_fFixedPosY_mm; ptStart.x = valFixedX; ptStart.y = valFixedY; ptStart.z = pCurBeam->m_vDoseProfile.at(0).x(); ptEnd.x = valFixedX; ptEnd.y = valFixedY; ptEnd.z = pCurBeam->m_vDoseProfile.at(iCntDataPt-1).x(); } else if (pCurBeam->m_ScanType == ST_PROFILE_CR) { //This is for Device Rot 0 valFixedY = pCurBeam->m_fFixedPosY_mm; valFixedDepth = pCurBeam->m_fFixedPosDepth_mm; ptStart.x = pCurBeam->m_vDoseProfile.at(0).x(); ptStart.y = valFixedY; ptStart.z = valFixedDepth; ptEnd.x = pCurBeam->m_vDoseProfile.at(iCntDataPt-1).x(); ptEnd.y = valFixedY; ptEnd.z = valFixedDepth; } else if (pCurBeam->m_ScanType == ST_PROFILE_IN) { valFixedX = pCurBeam->m_fFixedPosX_mm; valFixedDepth = pCurBeam->m_fFixedPosDepth_mm; ptStart.x = valFixedX; ptStart.y = pCurBeam->m_vDoseProfile.at(0).x(); ptStart.z = valFixedDepth; ptEnd.x = valFixedX; ptEnd.y = pCurBeam->m_vDoseProfile.at(iCntDataPt-1).x(); ptEnd.z = valFixedDepth; } //Device Rotation should be considered! //MGH: Device 90 //CR : Put X value on Y column. //IN: Put Y value on X column. Inf: + (opposite direction) //Depth: same //Device0 //strSTS.sprintf("% 7.1f\t% 7.1f\t% 7.1f ", ptStart.x, ptStart.y, ptStart.z); //allocated space: 7, precision: 1 //strEDS.sprintf("% 7.1f\t% 7.1f\t% 7.1f ", ptEnd.x, ptEnd.y, ptEnd.z); //Device 90 strSTS.sprintf("% 7.1f\t% 7.1f\t% 7.1f ", -ptStart.y, ptStart.x, ptStart.z); //allocated space: 7, precision: 1 strEDS.sprintf("% 7.1f\t% 7.1f\t% 7.1f ", -ptEnd.y, ptEnd.x, ptEnd.z); fout << "%STS \t" << strSTS.toLocal8Bit().constData() << "# Start Scan values in mm ( X , Y , Z )" << endl; fout << "%EDS \t" << strEDS.toLocal8Bit().constData() << "# End Scan values in mm ( X , Y , Z )" << endl; fout << "#" << endl; fout << "#\t X Y Z Dose" << endl; fout << "#" << endl; vector::iterator itData; QString strDataPt; if (pCurBeam->m_ScanType == ST_PDD) { for (itData = pCurBeam->m_vDoseProfile.begin(); itData != pCurBeam->m_vDoseProfile.end(); ++itData) { valX = (*itData).x();//mm valY = (*itData).y();//dose /* valFixedX = pCurBeam->m_fFixedPosX_mm; valFixedY = pCurBeam->m_fFixedPosY_mm;*/ //Device 0 //strDataPt.sprintf("= \t% 7.1f\t% 7.1f\t% 7.1f\t% 7.1f", valFixedX, valFixedY, valX, valY); //Device 90 strDataPt.sprintf("= \t% 7.1f\t% 7.1f\t% 7.1f\t% 7.1f", -valFixedY, valFixedX, valX, valY); fout << strDataPt.toLocal8Bit().constData() << endl; } } else if (pCurBeam->m_ScanType == ST_PROFILE_CR) { for (itData = pCurBeam->m_vDoseProfile.begin(); itData != pCurBeam->m_vDoseProfile.end(); ++itData) { valX = (*itData).x();//mm valY = (*itData).y();//dose /*valFixedY = pCurBeam->m_fFixedPosY_mm; valFixedDepth = pCurBeam->m_fFixedPosDepth_mm;*/ //strDataPt.sprintf("= \t% 7.1f\t% 7.1f\t% 7.1f\t% 7.1f", valX, valFixedY, valFixedDepth, valY); //DEVICE90 for MGH strDataPt.sprintf("= \t% 7.1f\t% 7.1f\t% 7.1f\t% 7.1f", -valFixedY, valX, valFixedDepth, valY); fout << strDataPt.toLocal8Bit().constData() << endl; } } else if (pCurBeam->m_ScanType == ST_PROFILE_IN) { for (itData = pCurBeam->m_vDoseProfile.begin(); itData != pCurBeam->m_vDoseProfile.end(); ++itData) { valX = (*itData).x();//mm, Sup:+, Inf:- valY = (*itData).y();//dose /*valFixedX = pCurBeam->m_fFixedPosX_mm; valFixedDepth = pCurBeam->m_fFixedPosDepth_mm;*/ //strDataPt.sprintf("= \t% 7.1f\t% 7.1f\t% 7.1f\t% 7.1f", valFixedX, valX, valFixedDepth, valY); //DEVICE90 for MGH strDataPt.sprintf("= \t% 7.1f\t% 7.1f\t% 7.1f\t% 7.1f", -valX, valFixedX, valFixedDepth, valY); fout << strDataPt.toLocal8Bit().constData() << endl; } } fout << ":EOM # End of Measurement" << endl; /* %VNR 1.0 %MOD RAT %TYP SCN %SCN DPT %FLD ION %DAT 04 - 09 - 2015 %TIM 19:09 : 40 %FSZ 40 40 %BMT ELE 6.0 %SSD 1000 %BUP 0 % BRD 1000 % FSH - 1 % ASC 0 % WEG 0 % GPO 0 % CPO 0 % MEA 1 % PRD 0 % PTS 259*/ iBeamIdx++; } fout << ":EOF # End of File" << endl; fout.close(); return true; } void beamdata_gen_gui::SLT_DrawGraphRFA300(bool bInitMinMax) { //source: m_vBeamDataRFA ui.customPlotProfile_RFA300->clearGraphs(); /* if (m_vBeamDataRFA.empty()) return;*/ vector::iterator it; double minX = 9999.0; double maxX = -1.0; double minY = 9999.0; double maxY = -1.0; QVector vAxisX; //can be rows or columns QVector vAxisY; float ValX, ValY; int iIndex = 0; for (it = m_vBeamDataRFA.begin(); it != m_vBeamDataRFA.end(); ++it) { vector::iterator itSub; vAxisX.clear(); vAxisY.clear(); for (itSub = (*it).m_vDoseProfile.begin(); itSub != (*it).m_vDoseProfile.end(); ++itSub) { ValX = (*itSub).x(); ValY = (*itSub).y(); if (minX > ValX) minX = ValX; if (maxX < ValX) maxX = ValX; if (minY > ValY) minY = ValY; if (maxY < ValY) maxY = ValY; vAxisX.push_back(ValX); vAxisY.push_back(ValY); } ui.customPlotProfile_RFA300->addGraph(); ui.customPlotProfile_RFA300->graph(iIndex)->setData(vAxisX, vAxisY); //Get Color Qt::GlobalColor color; QString strScanName; if ((*it).m_ScanType == ST_PDD) { color = Qt::red; strScanName = "PDD"; } else if ((*it).m_ScanType == ST_PROFILE_CR) { color = Qt::blue; strScanName = "PROFILE_CR"; } else if ((*it).m_ScanType == ST_PROFILE_IN) { color = Qt::green; strScanName = "PROFILE_IN"; } ui.customPlotProfile_RFA300->graph(iIndex)->setPen(QPen(color)); ui.customPlotProfile_RFA300->graph(iIndex)->setName(strScanName); iIndex++; } if (bInitMinMax) { ui.lineEditXMin_RFA300->setText(QString("%1").arg(minX)); ui.lineEditXMax_RFA300->setText(QString("%1").arg(maxX)); } double tmpXMin = ui.lineEditXMin_RFA300->text().toDouble(); double tmpXMax = ui.lineEditXMax_RFA300->text().toDouble(); double tmpYMin = ui.lineEditYMin_RFA300->text().toDouble(); double tmpYMax = ui.lineEditYMax_RFA300->text().toDouble(); ui.customPlotProfile_RFA300->xAxis->setRange(tmpXMin, tmpXMax); ui.customPlotProfile_RFA300->yAxis->setRange(tmpYMin, tmpYMax); ui.customPlotProfile_RFA300->xAxis->setLabel("mm"); ui.customPlotProfile_RFA300->yAxis->setLabel("%"); ui.customPlotProfile_RFA300->setTitle("Dose profiles"); QFont titleFont = font(); titleFont.setPointSize(10); ui.customPlotProfile_RFA300->setTitleFont(titleFont); //ui.customPlotProfile_RFA300->legend->setVisible(true); ui.customPlotProfile_RFA300->legend->setVisible(false); QFont legendFont = font(); // start out with MainWindow's font.. legendFont.setPointSize(8); // and make a bit smaller for legend ui.customPlotProfile_RFA300->legend->setFont(legendFont); ui.customPlotProfile_RFA300->legend->setPositionStyle(QCPLegend::psTopRight); ui.customPlotProfile_RFA300->legend->setBrush(QBrush(QColor(255, 255, 255, 200))); ui.customPlotProfile_RFA300->replot(); } void beamdata_gen_gui::SLT_ResampleAll() { if (m_vDoseImages.empty()) return; //Resample vector::iterator it; vector vDoseImagesResampled; for (it = m_vDoseImages.begin(); it != m_vDoseImages.end(); ++it) { FloatImageType::Pointer spCurImg = (*it); FloatImageType::Pointer spNewImg; VEC3D new_spacing; new_spacing.x = ui.lineEdit_NewSpacingDCM_X->text().toFloat(); new_spacing.y = ui.lineEdit_NewSpacingDCM_Y->text().toFloat(); new_spacing.z = ui.lineEdit_NewSpacingDCM_Z->text().toFloat(); QUTIL::ResampleFloatImg(spCurImg, spNewImg, new_spacing); vDoseImagesResampled.push_back(spNewImg); } m_vDoseImages.clear();//delete old m_vRefDose.clear(); for (it = vDoseImagesResampled.begin(); it != vDoseImagesResampled.end(); ++it) { FloatImageType::Pointer spCurImg = (*it); m_vDoseImages.push_back(spCurImg); typedef itk::MinimumMaximumImageCalculator MinimumMaximumImageCalculatorType; MinimumMaximumImageCalculatorType::Pointer minimumMaximumImageCalculatorFilter = MinimumMaximumImageCalculatorType::New(); minimumMaximumImageCalculatorFilter->SetImage(spCurImg); minimumMaximumImageCalculatorFilter->Compute(); float maxVal = minimumMaximumImageCalculatorFilter->GetMaximum(); m_vRefDose.push_back(maxVal); } vDoseImagesResampled.clear();//may not be needed. cout << m_vDoseImages.size() << " files were successfully replaced." << endl; disconnect(ui.comboBoxFileName, SIGNAL(currentIndexChanged(int)), this, SLOT(SLT_WhenSelectCombo())); SLT_UpdateComboContents(); connect(ui.comboBoxFileName, SIGNAL(currentIndexChanged(int)), this, SLOT(SLT_WhenSelectCombo())); SLT_WhenSelectCombo(); //Draw all included SLT_GoCenterPos(); //Draw all included } //void beamdata_gen_gui::SLT_RunBatchGamma() //{ // //number of batch should be matched // int cntRef = m_strlistPath_RD_Original_Ref.count(); // int cntComp = m_strlistPath_RD_Original_Comp.count(); // // QDir tmpCheckDir(m_strPathDirWorkDir); // // // if (m_strPathDirWorkDir.isEmpty()) // { // QUTIL::ShowErrorMessage("Error! No work space is specified. Set it first."); // return; // } // // if (!tmpCheckDir.exists()) // { // QUTIL::ShowErrorMessage("Error! Current work space doesn't exist. Set it again"); // return; // } // // if (cntRef*cntComp == 0 || cntRef != cntComp) // { // cout << "ERROR! Invalid input file counts" << endl; // return; // } // // //Check the working directory. Subfolders..This should have no relavant subdirectories // // QString strParamSet; // strParamSet.sprintf("_%dmm_%dp", ui.lineEdit_dta_tol->text().toInt(), ui.lineEdit_dose_tol->text().toInt()); // // float fResmp = ui.lineEdit_inhereResample->text().toFloat(); // // if (fResmp > 0 && ui.checkBox_inhereResample->isChecked()) // strParamSet = strParamSet + "_rsmp" + QString::number(fResmp, 'd', 0); // // if (ui.checkBox_Interp_search->isChecked()) // strParamSet = strParamSet + "_interp"; // // // QString timeStamp = QUTIL::GetTimeStampDirName(); // // QString strSubRef = "DoseRef_" + timeStamp; // QString strSubComp = "DoseComp_"+ timeStamp; // QString strSubAnalysis = "Analysis_" + timeStamp + strParamSet; // // //Create Folders // // QDir crntWorkDir(m_strPathDirWorkDir); // crntWorkDir.mkdir(strSubRef); // crntWorkDir.mkdir(strSubComp); // crntWorkDir.mkdir(strSubAnalysis); // // QString strPathDirReadRef = m_strPathDirWorkDir + "/" + strSubRef; // QString strPathDirReadComp = m_strPathDirWorkDir + "/" + strSubComp; // QString strPathDirAnalysis = m_strPathDirWorkDir + "/" + strSubAnalysis; // // m_strlistPath_RD_Read_Ref.clear(); // m_strlistPath_RD_Read_Comp.clear(); // // m_strlistBatchReport.clear(); // m_strlistPath_Output_Gammamap.clear(); // m_strlistPath_Output_Failure.clear(); // m_strlistPath_Output_Report.clear(); // m_vRefDose.clear(); // // QString dirPathFirstFileDir; //for saving workspace // QString dirPathFirstFileBase; //for saving workspace // // for (int i = 0; i < cntRef; i++) // { // QString strPathRef = m_strlistPath_RD_Original_Ref.at(i); // QString strPathComp = m_strlistPath_RD_Original_Comp.at(i); // // QFileInfo fInfoRef = QFileInfo(strPathRef); // QFileInfo fInfoComp = QFileInfo(strPathComp); // // QString baseNameRef = fInfoRef.completeBaseName(); // QString baseNameComp = fInfoComp.completeBaseName(); // // if (i == 0) //first image location // { // //dirPathFirstFileDir = dirPath; // dirPathFirstFileBase = baseNameComp; // } // QString strPathBkupRef = strPathDirReadRef + "/" + baseNameRef + ".mha"; // QString strPathBkupComp = strPathDirReadComp + "/" + baseNameComp + ".mha"; // // // if (strPathRef.length() < 2 || strPathComp.length() < 2) // continue;//skip this pair // // Gamma_parms parms; // //Gamma param: should come from the UI // parms.b_ref_only_threshold = false; // parms.mask_image_fn = ""; // //parms->reference_dose; // parms.gamma_max = 2.0; // parms.b_compute_full_region = false; // parms.b_resample_nn = false; //default: false // // //From File List // parms.ref_image_fn = strPathRef.toLocal8Bit().constData(); // parms.cmp_image_fn = strPathComp.toLocal8Bit().constData(); // // //From GUI // if (ui.checkBox_inhereResample->isChecked()) // parms.f_inherent_resample_mm = ui.lineEdit_inhereResample->text().toDouble(); // else // parms.f_inherent_resample_mm = -1.0; // // parms.b_interp_search = ui.checkBox_Interp_search->isChecked(); // // if (ui.radioButton_localGamma->isChecked()) // { // parms.b_local_gamma = true; // } // else // { // parms.b_local_gamma = false; // // } // // float inputRefDose = ui.lineEdit_refDoseInGy->text().toFloat(); // // if (inputRefDose <= 0) //blank // { // parms.have_reference_dose = false; // parms.reference_dose = 0.0; // } // else // { // parms.have_reference_dose = true; // parms.reference_dose = inputRefDose; // } // // parms.dta_tolerance = ui.lineEdit_dta_tol->text().toDouble(); // parms.dose_tolerance = ui.lineEdit_dose_tol->text().toDouble() / 100.0;//gui input: 3% --> param: 0.03 // parms.f_analysis_threshold = ui.lineEdit_cutoff_dose->text().toDouble() / 100.0; // // //Saving folder: comp folder. FileName Should Include dta, dose, local/global // // QString strLocGlob; // // if (parms.b_local_gamma) // strLocGlob = "loc"; // else // strLocGlob = "glb"; // // QString strSettingAbs = QString::number(parms.dta_tolerance, 'f', 0) + "mm_" + "" // + QString::number(parms.dose_tolerance*100.0, 'f', 0) + "%_" + strLocGlob; // // // QString outputPath = strPathDirAnalysis + "/" + baseNameComp + "_gammamap" + ".mha"; // parms.out_image_fn = outputPath.toLocal8Bit().constData(); // m_strlistPath_Output_Gammamap.push_back(outputPath); // // // //if (ui.checkBox_failuremap_output->isChecked()) // //{ // //QString outputPath = dirPath + "/" + baseName + "_failmap_" + strSettingAbs + ".mha"; // outputPath = strPathDirAnalysis + "/" + baseNameComp + "_failmap" + ".mha"; // parms.out_failmap_fn = outputPath.toLocal8Bit().constData(); // m_strlistPath_Output_Failure.push_back(outputPath); // //} // // //QString outputPath = dirPath + "/" + baseName + "_report_" + strSettingAbs + ".txt"; // outputPath = strPathDirAnalysis + "/" + baseNameComp + "_report" + ".txt"; // parms.out_report_fn = outputPath.toLocal8Bit().constData(); // m_strlistPath_Output_Report.push_back(outputPath); // // float refDoseGy; // QString overallReport = GammaMain(&parms, refDoseGy, strPathBkupRef, strPathBkupComp); // m_strlistBatchReport.push_back(overallReport); // // m_strlistPath_RD_Read_Ref.push_back(strPathBkupRef); // m_strlistPath_RD_Read_Comp.push_back(strPathBkupComp); // // m_vRefDose.push_back(refDoseGy); // } // //Save WorkSpace File for future loading // // // //QString strPathGammaWorkSpace = m_strPathDirWorkDir + "/" + dirPathFirstFileBase + "_" + strParamSet + "_" + QString("%1").arg(cntRef) + "cases.gws"; //gamma work space // // QString strPathGammaWorkSpace = m_strPathDirWorkDir + "/" + strSubAnalysis + ".gws"; //gamma work space // QString strFilePathReport = m_strPathDirWorkDir + "/" + strSubAnalysis + "BatchReport.txt"; //gamma work space // // SaveCurrentGammaWorkSpace(strPathGammaWorkSpace); // // cout << cntRef << " analysis were successfully done!" << endl; // // SLT_LoadResults(); // // //After the batch mode analysis, export the simpe report. // //Only when the number of files is > 1 //// if (cntRef == 1) // // return; // // SaveBatchGamma3DSimpleReport(strFilePathReport); // // /*QString fileName = QFileDialog::getSaveFileName(this, "Save batch report file", "", "report (*.txt)", 0, 0); // // if (fileName.length() < 1) // return; // // ofstream fout; // fout.open(fileName.toLocal8Bit().constData()); // fout << "Reference_File\t" // << "Compare_File\t" // << "dta_tolerance[mm]\t" // << "dose_tolerance[%]\t" // << "doseCutoff[%]\t" // << "Local/Global\t" // << "Ref_dose[Gy]\t" // << "VoxNumAnalyzed\t" // << "VoxNumPassed\t" // << "GammaPassRate[%]" << endl; // // for (int i = 0; i < cntRef; i++) // { // fout << m_strlistBatchReport.at(i).toLocal8Bit().constData() << endl; // } // // fout.close();*/ //} beamdata_gen_gui.h000066400000000000000000000077211321604176500323030ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#ifndef BEAMDATA_GEN_GUI_H #define BEAMDATA_GEN_GUI_H #include #include "ui_beamdata_gen_gui.h" #include #include #include "yk_config.h" #include "itk_image_type.h" #include "BeamDataRFA.h" using namespace std; class DlgGammaView; class YK16GrayImage; class qyklabel; class QStandardItemModel; class beamdata_gen_gui : public QMainWindow { Q_OBJECT public: beamdata_gen_gui(QWidget *parent = 0, Qt::WFlags flags = 0); ~beamdata_gen_gui(); void UpdateProbePos(qyklabel* qlabel, enPLANE enPlane); void UpdateTable(vector& vData1, float fNorm, float fMag); void MouseWheelUpdateCommon(enPLANE curPlane); void WhenMousePressedRight(qyklabel* pWnd); void UpdatePanCommon(qyklabel* qWnd); void RenameFileByDCMInfo(QStringList& filenameList); //QString ReplaceUpperDirOnly(QString& strOriginalPath, QString& strCurrDirPath, QString& strDelim); void SaveDoseIBAGenericTXTFromItk(QString strFilePath, FloatImage2DType::Pointer& spFloatDose); void UpdateBeamDataList(); bool ExportBeamDataRFA300(QString& strPathOut, vector& vBeamDataRFA); public slots: void SLTM_ImportRDFiles(); void SLTM_RenameRDFilesByDICOMInfo(); void SLT_UpdateProbePosFromAxial(); void SLT_UpdateProbePosFromSagittal(); void SLT_UpdateProbePosFromFrontal(); void SLT_MouseWheelUpdateAxial(); void SLT_MouseWheelUpdateSagittal(); void SLT_MouseWheelUpdateFrontal(); void SLT_RestoreZoomPan(); void SLT_UpdateComboContents(); void SLT_WhenSelectCombo(); void SLT_WhenChangePlane();//Radio Button, to be implemented void SLT_DrawAll(); void SLT_DrawGraph(bool bInitMinMax = false); void SLT_DrawGraphRFA300(bool bInitMinMax = false); void SLT_CopyTableToClipboard(); //void SLT_DrawGraph(); void SLT_GoCenterPos(); void SLT_MousePressedRightAxial(); void SLT_MousePressedRightSagittal(); void SLT_MousePressedRightFrontal(); void SLT_MouseReleasedRightAxial(); void SLT_MouseReleasedRightSagittal(); void SLT_MouseReleasedRightFrontal(); void SLT_UpdatePanSettingAxial(); void SLT_UpdatePanSettingSagittal(); void SLT_UpdatePanSettingFrontal(); void SLT_TableEdit_Invert(); void SLT_TableEdit_SetOrigin(); void SLT_TableEdit_TrimXMin(); void SLT_TableEdit_TrimXMax(); void SLT_TableEdit_Restore(); void SLT_AddBeamDataToRFA300List(); void SLT_ClearBeamDataRFA300(); void SLT_ExportBeamDataRFA300(); void SLT_ResampleAll(); public: QString m_strPathInputDir;//this is for input DCM. initialized when Load Ref files or Load Comp files QStringList m_strlistPath; //RD files, before the conversio QStringList m_strlistFileBaseName; vector m_vDoseImages; vector m_vRefDose; // for normalization FloatImage2DType::Pointer m_spCur2DAxial; //extracted 2D from 3D FloatImage2DType::Pointer m_spCur2DSagittal; //extracted 2D from 3D FloatImage2DType::Pointer m_spCur2DFrontal; //extracted 2D from 3D YK16GrayImage* m_pCurImageAxial; //for display YK image YK16GrayImage* m_pCurImageSagittal; //for display YK image YK16GrayImage* m_pCurImageFrontal; //for display YK image QStandardItemModel *m_pTableModel; //for dose profile, col: 2 vector m_vColormapDose; bool m_bMousePressedRightAxial; bool m_bMousePressedRightSagittal; bool m_bMousePressedRightFrontal; QPoint m_ptPanStart; QPoint m_ptOriginalDataOffset; int m_iLastLoadedIndex; vector m_vBeamDataRFA; private: Ui::beamdata_gen_guiClass ui; }; #endif // beamdata_gen_gui_H beamdata_gen_gui.ui000066400000000000000000001356231321604176500324740ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone beamdata_gen_guiClass 0 0 1269 822 DICOM RD to ScanData Converter 30 410 121 16 Profile Table 20 10 121 16 Axial 10 440 181 281 10 730 181 31 CopyToClipboard 770 300 101 17 scroll_zoom false 810 30 91 261 Norm dose (cGy) 10 30 51 22 10000 200 30 60 31 171 10000 10 100 200 Qt::Vertical 610 400 441 131 Make RFA300 Format 10 20 211 41 Scan Type 10 20 51 17 PDD true 60 20 61 17 ProfileCr false 140 20 61 17 ProfileIn false 10 60 211 41 Beam Type 10 20 61 17 Photon false 70 20 61 17 Electron true 140 20 61 17 Proton false 230 10 31 21 6 270 10 31 20 MeV 230 40 51 20 FS_X(cm) 330 40 51 20 FS_Y(cm) 280 40 41 21 10 390 40 41 21 10 330 10 51 20 SSD (cm) 380 10 41 21 100 230 70 51 20 FixedCr 230 90 31 21 0 330 90 31 21 0 320 70 61 20 Depth_mm 280 70 51 20 FixedIn 280 90 31 21 0 380 100 51 17 Auto false 210 420 391 91 Edit current profile 10 20 61 21 Invert 10 50 61 21 Set origin 80 50 41 21 0 320 20 61 21 Restore 160 20 61 21 Trim X min 230 20 41 21 0 160 50 61 21 Trim X max 230 50 41 21 0 130 50 21 20 mm 280 20 21 20 mm 280 50 21 20 mm 10 40 256 256 QFrame::Box 280 40 256 256 QFrame::Box 550 40 256 256 QFrame::Box 290 10 121 16 Sagittal 560 10 121 16 Frontal 10 300 741 91 Go position 20 20 41 16 File 60 20 181 22 270 20 51 20 DCM_X 270 50 41 21 0 330 20 51 20 DCM_Y 330 50 41 21 0 390 20 51 20 DCM_Z 390 50 41 21 0 450 40 71 31 Go position 540 30 181 51 Profile direction 20 20 81 17 Horizontal true 110 20 71 17 Vertical 10 50 231 31 10 10 61 17 8 Axial true 70 10 71 17 8 Sagittal 150 10 71 17 Frontal 200 530 391 231 Current Profile 20 20 41 20 130 20 160 41 20 0 70 20 311 171 70 200 51 20 330 200 51 20 true 130 200 91 17 Auto Adjust X true 230 200 81 17 Normalize Y true 1070 410 191 351 Export RFA300 10 61 171 271 70 20 51 31 Clear all 130 20 51 31 Export 10 20 51 31 Add 610 530 441 231 All profiles 20 20 41 20 130 20 160 41 20 0 70 20 351 171 70 200 51 20 360 200 51 20 true 130 200 101 17 Auto Adjust X true 760 320 341 71 Resample 270 20 61 31 Resample 60 40 41 21 1 60 20 41 20 DCM_X 10 20 41 20 Spacing 10 40 41 20 mm 120 20 41 20 DCM_Y 180 20 41 20 DCM_Z 120 40 41 21 1 180 40 41 21 1 0 0 1269 21 File View Tool TopToolBarArea false false Profile View Rename RD files Import DICOM-RD file(s) Export simple batch report Import proton dose file (*.set) QCustomPlot QWidget
qcustomplot.h
1
qyklabel QLabel
qyklabel.h
lineEdit_ProbePosX lineEdit_ProbePosY lineEdit_ProbePosZ pushButtonGoForcedProbe lineEdit_RFA300_Energy lineEdit_RFA300_SSDcm lineEdit_RFA300_FS_Xcm lineEdit_RFA300_FS_Ycm lineEdit_RFA300_FixedCR lineEdit_RFA300_FixedIN lineEdit_RFA300_FixedDepth pushButtonRFA300_Add radio_RFA300_BT_photon radio_RFA300_PDD radio_RFA300_BT_proton tableViewProfile radio_RFA300_Profile_In checkBox_FixedAuto pushButtonTableInvert pushButtonTableOrigin lineEditTableOrigin pushButtonRestore pushButtonTableTrimMin lineEditTableMin pushButtonTableTrimMax lineEditTableMax comboBoxFileName pushButtonCopyTableToClipboard checkBox_ScrollZoom spinBoxNormDose radio_RFA300_BT_electron radioButtonHor radioButtonVert radioButtonAxial radioButtonSagittal radioButtonFrontal lineEditYMax lineEditYMin lineEditXMin lineEditXMax checkBoxAutoAdjust checkBoxNormalized listWidgetRFA300 pushButtonClearAll_RFA300 pushButtonExportAll_RFA300 radio_RFA300_Profile_Cr lineEditYMax_RFA300 lineEditYMin_RFA300 lineEditXMin_RFA300 lineEditXMax_RFA300 checkBoxAutoAdjust_RFA300 pushButtonResampleAll lineEdit_NewSpacingDCM_X lineEdit_NewSpacingDCM_Y lineEdit_NewSpacingDCM_Z sliderNormDose sliderNormDose valueChanged(int) spinBoxNormDose setValue(int) 840 255 820 114 spinBoxNormDose valueChanged(int) sliderNormDose setValue(int) 820 114 840 272 sliderNormDose valueChanged(int) beamdata_gen_guiClass SLT_DrawAll() 840 293 563 553 pushButtonCopyTableToClipboard released() beamdata_gen_guiClass SLT_CopyTableToClipboard() 190 763 960 563 checkBoxAutoAdjust clicked(bool) beamdata_gen_guiClass SLT_DrawGraph(bool) 330 779 875 821 lineEditYMax textEdited(QString) beamdata_gen_guiClass SLT_DrawGraph() 220 602 601 618 lineEditYMin textEdited(QString) beamdata_gen_guiClass SLT_DrawGraph() 220 742 618 766 lineEditXMin textEdited(QString) beamdata_gen_guiClass SLT_DrawGraph() 270 782 725 821 lineEditXMax textEdited(QString) beamdata_gen_guiClass SLT_DrawGraph() 530 782 977 812 radioButtonHor released() beamdata_gen_guiClass SLT_DrawAll() 570 399 934 520 radioButtonVert released() beamdata_gen_guiClass SLT_DrawAll() 660 399 946 536 checkBoxNormalized released() beamdata_gen_guiClass SLT_DrawAll() 440 779 906 821 actionRename_RD_files triggered() beamdata_gen_guiClass SLTM_RenameRDFilesByDICOMInfo() -1 -1 612 428 pushButtonGoForcedProbe released() beamdata_gen_guiClass SLT_DrawAll() 460 403 690 408 radioButtonAxial toggled(bool) beamdata_gen_guiClass SLT_WhenChangePlane() 90 409 913 567 radioButtonSagittal toggled(bool) beamdata_gen_guiClass SLT_WhenChangePlane() 160 409 1075 508 radioButtonFrontal toggled(bool) beamdata_gen_guiClass SLT_WhenChangePlane() 240 409 1075 404 actionImportRDFiles triggered() beamdata_gen_guiClass SLTM_ImportRDFiles() -1 -1 609 410 comboBoxFileName currentIndexChanged(int) beamdata_gen_guiClass SLT_WhenSelectCombo() 243 374 306 429 pushButtonTableInvert released() beamdata_gen_guiClass SLT_TableEdit_Invert() 262 482 233 445 pushButtonTableOrigin released() beamdata_gen_guiClass SLT_TableEdit_SetOrigin() 260 515 260 545 pushButtonTableTrimMin released() beamdata_gen_guiClass SLT_TableEdit_TrimXMin() 416 485 449 452 pushButtonTableTrimMax released() beamdata_gen_guiClass SLT_TableEdit_TrimXMax() 403 512 403 547 pushButtonRestore released() beamdata_gen_guiClass SLT_TableEdit_Restore() 565 480 591 435 pushButtonRFA300_Add released() beamdata_gen_guiClass SLT_AddBeamDataToRFA300List() 1105 493 963 430 pushButtonExportAll_RFA300 released() beamdata_gen_guiClass SLT_ExportBeamDataRFA300() 1235 493 1210 480 pushButtonClearAll_RFA300 released() beamdata_gen_guiClass SLT_ClearBeamDataRFA300() 1178 493 1099 434 lineEditYMax_RFA300 textEdited(QString) beamdata_gen_guiClass SLT_DrawGraphRFA300() 635 594 598 657 lineEditYMin_RFA300 textEdited(QString) beamdata_gen_guiClass SLT_DrawGraphRFA300() 645 729 605 731 lineEditXMin_RFA300 textEdited(QString) beamdata_gen_guiClass SLT_DrawGraphRFA300() 718 775 661 797 lineEditXMax_RFA300 textEdited(QString) beamdata_gen_guiClass SLT_DrawGraphRFA300() 978 779 967 799 pushButtonResampleAll released() beamdata_gen_guiClass SLT_ResampleAll() 994 399 1014 352 SLT_DrawAll() SLT_CopyTableToClipboard() SLT_DrawGraph(bool) SLT_WhenSelectCombo() SLTM_RenameRDFilesByDICOMInfo() SLTM_ImportRDFiles() SLT_DrawGraph() SLT_WhenChangePlane() SLT_TableEdit_Invert() SLT_TableEdit_SetOrigin() SLT_TableEdit_TrimXMin() SLT_TableEdit_TrimXMax() SLT_TableEdit_Restore() SLT_AddBeamDataToRFA300List() SLT_ExportBeamDataRFA300() SLT_ClearBeamDataRFA300() SLT_DrawGraphRFA300() SLT_ResampleAll()
beamdata_gen_gui_main.cpp000066400000000000000000000002701321604176500336320ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "beamdata_gen_gui.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); beamdata_gen_gui w; w.show(); return a.exec(); } bragg_curve_main.cxx000066400000000000000000000024041321604176500327060ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #if (OPENMP_FOUND) #include #endif #include "bragg_curve.h" #include "bragg_curve_opts.h" int main (int argc, char* argv[]) { Bragg_curve_options options; FILE *fp = 0; double z; parse_args (&options, argc, argv); //printf ("sigma = %f\n", sigma); /* Set z max */ if (!options.have_z_max) { double p = 1.77; double alpha = 0.0022; double R_0 = alpha * pow (options.E_0, p); options.z_max = 10 * 1.1 * R_0; } /* Set sigma E0 */ if (!options.have_e_sigma) { options.e_sigma = 0.01 * options.E_0; } if (options.output_file) { fp = fopen (options.output_file, "w"); } else { fp = stdout; } for (z = 0.0; z < options.z_max; z += options.z_spacing) { fprintf (fp, "%f %f\n", z, bragg_curve (options.E_0, options.e_sigma, z)); } if (options.output_file) { fclose (fp); } printf ("Done.\n"); return 0; } bragg_curve_opts.cxx000066400000000000000000000051451321604176500327540ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "bragg_curve_opts.h" #include "plm_math.h" #ifndef NULL #define NULL ((void*)0) #endif void print_usage (void) { printf ( "Usage: bragg_curve [options]\n" "Options:\n" " -z z_max Maximum range (in mm)\n" " -s z_spacing Spacing of points of depth dose curve (in mm)\n" " -E energy Energy of beam (in MeV)\n" " -e energy_spread Sigma of beam energy (in MeV)\n" " -O output_file Write output to a file\n" ); exit (1); } void bragg_curve_opts_init (Bragg_curve_options* options) { options->have_z_max = 0; options->z_max = 0.0; options->z_spacing = 1.0; options->E_0 = 200.0; options->have_e_sigma = 0; options->e_sigma = 0.0; options->output_file = 0; } void parse_args (Bragg_curve_options* options, int argc, char* argv[]) { int i, rc; bragg_curve_opts_init (options); for (i = 1; i < argc; i++) { //printf ("ARG[%d] = %s\n", i, argv[i]); if (argv[i][0] != '-') break; if (!strcmp (argv[i], "-e")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%f", &options->e_sigma); if (rc != 1) { print_usage (); } options->have_e_sigma = 1; } else if (!strcmp (argv[i], "-E")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%lf", &options->E_0); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-O")) { i++; options->output_file = strdup (argv[i]); } else if (!strcmp (argv[i], "-s")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%f", &options->z_spacing); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-z")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%f", &options->z_max); if (rc != 1) { print_usage (); } options->have_z_max = 1; } else { print_usage (); break; } } if (i < argc) { print_usage (); } } bragg_curve_opts.h000066400000000000000000000012761321604176500324020ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bragg_curve_opts_h_ #define _bragg_curve_opts_h_ typedef struct bragg_curve_options Bragg_curve_options; struct bragg_curve_options { float z_max; /* in mm */ int have_z_max; float z_spacing; /* in mm */ double E_0; /* in MeV */ float e_sigma; /* in MeV */ float have_e_sigma; char* output_file; }; void parse_args (Bragg_curve_options* options, int argc, char* argv[]); #endif bspline_main.cxx000066400000000000000000000125451321604176500320630ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- REFS: http://en.wikipedia.org/wiki/B-spline http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/surface/bspline-construct.html http://graphics.idav.ucdavis.edu/education/CAGDNotes/Quadratic-B-Spline-Surface-Refinement/Quadratic-B-Spline-Surface-Refinement.html ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "bspline_cuda.h" #include "bspline_interpolate.h" #include "bspline_optimize.h" #include "bspline_opts.h" #include "bspline_xform.h" #if (CUDA_FOUND) #include "cuda_util.h" #include "delayload.h" #endif #include "mha_io.h" #include "vf.h" #include "volume.h" #include "volume_grad.h" int main (int argc, char* argv[]) { Bspline_options options; Bspline_parms *parms = &options.parms; Bspline_xform *bxf; Volume *moving, *fixed, *moving_grad; Volume *vector_field = 0; Volume *moving_warped = 0; plm_long roi_offset[3]; bspline_opts_parse_args (&options, argc, argv); #if (CUDA_FOUND) if (parms->threading == BTHR_CUDA) { LOAD_LIBRARY_SAFE (libplmcuda); LOAD_SYMBOL (CUDA_selectgpu, libplmcuda); CUDA_selectgpu (parms->gpuid); UNLOAD_LIBRARY (libplmcuda); } #endif #if defined (commentout) /* Load and adjust landmarks */ if (options.fixed_landmarks && options.moving_landmarks) { parms->landmarks = bspline_landmarks_load ( options.fixed_landmarks, options.moving_landmarks); bspline_landmarks_adjust (parms->landmarks, fixed, moving); } #endif /* Debug */ //write_mha ("moving_grad.mha", moving_grad); /* Load images */ fixed = read_mha (options.fixed_fn); if (!fixed) exit (-1); moving = read_mha (options.moving_fn); if (!moving) exit (-1); /* Allocate memory and build lookup tables */ printf ("Allocating lookup tables\n"); memset (roi_offset, 0, 3*sizeof(plm_long)); if (options.input_xf_fn) { bxf = bspline_xform_load (options.input_xf_fn); if (!bxf) { fprintf (stderr, "Failed to load %s\n", options.input_xf_fn); exit (-1); } } else { bxf = new Bspline_xform; bxf->initialize ( fixed->origin, fixed->spacing, fixed->dim, roi_offset, fixed->dim, options.vox_per_rgn, fixed->get_direction_matrix() ); } /* Initialize Bspline_optimize data structure */ Bspline_optimize bod; Bspline_state *bst = bod.get_bspline_state(); /* Set up Metric_state */ Metric_state::Pointer ms = Metric_state::New (); ms->metric_type = options.metric_type; printf ("Metric type %d\n", ms->metric_type); ms->metric_lambda = 1.f; ms->fixed_ss.reset (fixed); ms->moving_ss.reset (moving); bst->similarity_data.push_back (ms); volume_convert_to_float (moving); volume_convert_to_float (fixed); printf ("Making gradient\n"); moving_grad = volume_make_gradient (ms->moving_ss.get()); ms->moving_grad.reset (moving_grad); /* Run the optimization */ printf ("Running optimization.\n"); bod.set_bspline_parms (parms); bod.set_bspline_xform (bxf); bod.optimize (); printf ("Done running optimization.\n"); /* Save output transform */ if (options.output_xf_fn) { bxf->save (options.output_xf_fn); } /* Create vector field from bspline coefficients and save */ if (options.output_vf_fn || options.output_warped_fn #if defined (commentout) || (options.warped_landmarks && options.fixed_landmarks && options.moving_landmarks) #endif ) { printf ("Creating vector field.\n"); vector_field = new Volume (fixed->dim, fixed->origin, fixed->spacing, fixed->direction_cosines, PT_VF_FLOAT_INTERLEAVED, 3); if (parms->threading == BTHR_CUDA) { #if (CUDA_FOUND) LOAD_LIBRARY_SAFE (libplmcuda); LOAD_SYMBOL (CUDA_bspline_interpolate_vf, libplmcuda); CUDA_bspline_interpolate_vf (vector_field, bxf); UNLOAD_LIBRARY (libplmcuda); #else bspline_interpolate_vf (vector_field, bxf); #endif } else { bspline_interpolate_vf (vector_field, bxf); } } /* Create warped output image and save */ if (options.output_warped_fn) { printf ("Warping image.\n"); moving_warped = vf_warp (0, moving, vector_field); if (moving_warped) { printf ("Writing warped image.\n"); write_mha (options.output_warped_fn, moving_warped); } else { printf ("Sorry, couldn't create warped image.\n"); } } /* Write the vector field */ if (options.output_vf_fn) { printf ("Writing vector field.\n"); write_mha (options.output_vf_fn, vector_field); } /* Free memory */ printf ("Done warping images.\n"); delete bxf; delete moving_warped; delete vector_field; printf ("Done freeing memory\n"); return 0; } bspline_opts.cxx000066400000000000000000000266051321604176500321260ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "bspline_landmarks.h" #include "bspline_opts.h" #include "bspline_regularize.h" #include "delayload.h" #if (CUDA_FOUND) #include "cuda_util.h" #endif void print_usage (void) { printf ( "Usage: bspline [options] fixed moving\n" "Options:\n" " -A hardware Either \"cpu\" or \"cuda\" (default=cpu)\n" " -G gpuid Select GPU to use (default=0)\n" " -a { steepest | lbfgsb } Choose optimization algorithm\n" " -M { mse | mi } Registration metric (default is mse)\n" " -f implementation Choose implementation (a single letter: a, b, etc.)\n" " -m iterations Maximum iterations (default is 10)\n" " -R implementation Choose regularization implementation (a, b, etc.)\n" " -S smoothness Weight of regularization (floating point number)\n" " -B \"F M\" # of [F]ixed & [M]oving histogram bins (default=20)\n" " --factr value L-BFGS-B cost converg tol (default is 1e+7)\n" " --pgtol value L-BFGS-B projected grad tol (default is 1e-5)\n" " -s \"i j k\" Integer knot spacing (voxels)\n" " -h prefix Generate histograms for each MI iteration\n" " -V outfile Output vector field\n" " -X infile Input bspline coefficients\n" " -x outfile Output bspline coefficients\n" " -O outfile Output warped image\n" " --fixed-landmarks file Input fixed landmarks file\n" " --moving-landmarks file Input moving landmarks file\n" " --warped-landmarks file Output warped landmarks file\n" " --landmark-stiffness float Relative weight of landmarks\n" " -F landm_implementation Landmark implementation: a or b (default is a)\n" " --young-modulus float Young modulus (cost of vector field gradient)\n" " --rbf-radius float Apply radial basis functions with a given radius\n" " --rbf-young-modulus float RBF Young modulus (cost of RBF vf second derivative)\n" " --vopt Use v-optimal histograms (experimental/cpu only)\n" " --list-gpu Enumerates available GPU IDs and displays details\n" " --debug Create various debug files\n" ); exit (1); } void bspline_opts_parse_args (Bspline_options* options, int argc, char* argv[]) { int i, rc; Bspline_parms* parms = &options->parms; Regularization_parms* reg_parms = parms->reg_parms; Bspline_landmarks* blm = parms->blm; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') break; if (!strcmp (argv[i], "-A")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; if (!strcmp(argv[i], "cuda") || !strcmp(argv[i], "CUDA") || !strcmp(argv[i], "gpu") || !strcmp(argv[i], "GPU")) { parms->threading = BTHR_CUDA; } else { parms->threading = BTHR_CPU; } } else if (!strcmp (argv[i], "-a")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; if (!strcmp(argv[i], "steepest")) { parms->optimization = BOPT_STEEPEST; } else if (!strcmp(argv[i], "liblbfgs")) { parms->optimization = BOPT_LIBLBFGS; } else if (!strcmp(argv[i], "nlopt-lbfgs")) { parms->optimization = BOPT_NLOPT_LBFGS; } else if (!strcmp(argv[i], "nlopt-ld-mma")) { parms->optimization = BOPT_NLOPT_LD_MMA; } else if (!strcmp(argv[i], "nlopt-ptn")) { parms->optimization = BOPT_NLOPT_PTN_1; } else if (!strcmp(argv[i], "lbfgsb")) { parms->optimization = BOPT_LBFGSB; } else { fprintf (stderr, "Unknown optimization type: %s\n", argv[i]); print_usage (); } } else if (!strcmp (argv[i], "-G")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%d" , &parms->gpuid); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-f")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; parms->implementation = argv[i][0]; } else if (!strcmp (argv[i], "-m")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%d" , &parms->max_its); if (rc != 1) { print_usage (); } parms->max_feval = parms->max_its; } else if (!strcmp (argv[i], "-R")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; reg_parms->implementation = argv[i][0]; } else if (!strcmp (argv[i], "-S")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g", ®_parms->lambda); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-B")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; unsigned int a, b; rc = sscanf (argv[i], "%u %u", &a, &b); if (rc == 1) { parms->mi_hist_fixed_bins = a; parms->mi_hist_moving_bins = a; } else if (rc == 2) { parms->mi_hist_fixed_bins = a; parms->mi_hist_moving_bins = b; } else { print_usage (); } } else if (!strcmp (argv[i], "-M")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; if (!strcmp(argv[i], "mse")) { options->metric_type = SIMILARITY_METRIC_MSE; } else if (!strcmp(argv[i], "mi")) { options->metric_type = SIMILARITY_METRIC_MI_MATTES; } else { print_usage (); } } else if (!strcmp (argv[i], "-s")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; unsigned int a, b, c; rc = sscanf (argv[i], "%d %d %d", &a, &b, &c); if (rc == 1) { options->vox_per_rgn[0] = a; options->vox_per_rgn[1] = a; options->vox_per_rgn[2] = a; } else if (rc == 3) { options->vox_per_rgn[0] = a; options->vox_per_rgn[1] = b; options->vox_per_rgn[2] = c; } else { print_usage (); } } else if (!strcmp (argv[i], "-h")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; parms->xpm_hist_dump = strdup (argv[i]); } else if (!strcmp (argv[i], "-O")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; options->output_warped_fn = strdup (argv[i]); } else if (!strcmp (argv[i], "-V")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; options->output_vf_fn = strdup (argv[i]); } else if (!strcmp (argv[i], "-x")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; options->output_xf_fn = strdup (argv[i]); } else if (!strcmp (argv[i], "-X")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; options->input_xf_fn = strdup (argv[i]); } else if (!strcmp (argv[i], "--debug")) { parms->debug = 1; } else if (!strcmp (argv[i], "--factr")) { float f; if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g", &f); if (rc != 1) { print_usage (); } parms->lbfgsb_factr = (double) f; } else if (!strcmp (argv[i], "--pgtol")) { float f; if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g", &f); if (rc != 1) { print_usage (); } parms->lbfgsb_pgtol = (double) f; } else if (!strcmp (argv[i], "--fixed-landmarks")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; options->fixed_landmarks = strdup (argv[i]); } else if (!strcmp (argv[i], "--moving-landmarks")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; options->moving_landmarks = strdup (argv[i]); } else if (!strcmp (argv[i], "--warped-landmarks")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; options->warped_landmarks = strdup (argv[i]); } else if (!strcmp (argv[i], "--landmark-stiffness")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g", &blm->landmark_stiffness); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-F")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; blm->landmark_implementation = argv[i][0]; } else if (!strcmp (argv[i], "--young-modulus")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g", ®_parms->lambda); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "--rbf-radius")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g", &parms->rbf_radius); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "--rbf-young-modulus")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g", &parms->rbf_young_modulus); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "--vopt")) { parms->mi_hist_type = HIST_VOPT; } else if (!strcmp (argv[i], "--list-gpu")) { #if (CUDA_FOUND) printf ("Enumerating available GPUs:\n\n"); LOAD_LIBRARY_SAFE (libplmcuda); LOAD_SYMBOL(CUDA_listgpu, libplmcuda); CUDA_listgpu (); UNLOAD_LIBRARY (libplmcuda); #else printf ("\nPlastimatch was not compiled with CUDA support!\n\n"); #endif exit (0); } else { print_usage (); break; } } if (i+1 >= argc) { print_usage (); } options->fixed_fn = argv[i]; options->moving_fn = argv[i+1]; printf ("Fixed = %s\n", options->fixed_fn); printf ("Moving = %s\n", options->moving_fn); } bspline_opts.h000066400000000000000000000023651321604176500315500ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_opts_h_ #define _bspline_opts_h_ #include "bspline.h" #include "bspline_parms.h" #include "similarity_metric_type.h" class Bspline_options { public: char* fixed_fn; char* moving_fn; char* input_xf_fn; char* output_warped_fn; char* output_xf_fn; char* output_vf_fn; char* fixed_landmarks; char* moving_landmarks; char* warped_landmarks; char* method; Similarity_metric_type metric_type; float landmark_stiffness; float young_modulus; plm_long vox_per_rgn[3]; Bspline_parms parms; public: Bspline_options () { fixed_fn = 0; moving_fn = 0; input_xf_fn = 0; output_warped_fn = 0; output_xf_fn = 0; output_vf_fn = 0; fixed_landmarks = 0; moving_landmarks = 0; warped_landmarks = 0; method = 0; metric_type = SIMILARITY_METRIC_MSE; landmark_stiffness = 0; young_modulus = 0; for (int d = 0; d < 3; d++) { vox_per_rgn[d] = 15; } } }; void bspline_opts_parse_args ( Bspline_options* options, int argc,char* argv[] ); #endif check_grad.cxx000066400000000000000000000334151321604176500314740ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include #include #include "bspline.h" #include "bspline_mi.h" #include "bspline_optimize.h" #include "bspline_parms.h" #include "bspline_state.h" #include "bspline_xform.h" #include "mha_io.h" #include "plm_clp.h" #include "plm_image.h" #include "print_and_exit.h" #include "similarity_metric_type.h" #include "volume.h" #include "volume_grad.h" enum Check_grad_process { CHECK_GRAD_PROCESS_FWD, CHECK_GRAD_PROCESS_BKD, CHECK_GRAD_PROCESS_CTR, CHECK_GRAD_PROCESS_LINE }; class Check_grad_opts { public: std::string fixed_fn; std::string fixed_roi_fn; std::string moving_fn; std::string input_xf_fn; std::string input_search_dir_fn; std::string output_fn; const char* xpm_hist_prefix; float factr; float pgtol; float step_size; int line_range[2]; plm_long vox_per_rgn[3]; Check_grad_process process; int random; float random_range[2]; int control_point_index; std::string debug_dir; char bsp_implementation; BsplineThreading bsp_threading; Similarity_metric_type bsp_metric; public: Check_grad_opts () { xpm_hist_prefix = 0; factr = 0; pgtol = 0; step_size = 1e-4; line_range[0] = 0; line_range[1] = 30; for (int d = 0; d < 3; d++) { vox_per_rgn[d] = 15; } process = CHECK_GRAD_PROCESS_FWD; random = 0; random_range[0] = 0; random_range[1] = 0; control_point_index = 514; // -1; debug_dir = ""; bsp_implementation = '\0'; bsp_threading = BTHR_CPU; bsp_metric = SIMILARITY_METRIC_MSE; } }; void check_gradient ( Check_grad_opts *options, Volume *fixed, Volume *moving, Volume *moving_grad) { int i, j; float *x, *grad, *grad_fd; float score; FILE *fp; plm_long roi_offset[3]; Bspline_optimize bod; Bspline_xform *bxf; Bspline_parms *parms = new Bspline_parms; Bspline_state *bst = bod.get_bspline_state (); /* Fixate images into bspline parms */ Metric_state::Pointer sim = Metric_state::New(); bst->similarity_data.push_back (sim); parms->implementation = options->bsp_implementation; sim->fixed_ss.reset (fixed); sim->moving_ss.reset (moving); sim->moving_grad.reset (moving_grad); sim->metric_type = options->bsp_metric; /* Maybe we got a roi too */ Plm_image::Pointer pli_fixed_roi; if (options->fixed_roi_fn != "") { pli_fixed_roi = Plm_image::New (options->fixed_roi_fn); sim->fixed_roi = pli_fixed_roi->get_volume_uchar(); } /* Set extra debug stuff, if desired */ if (options->debug_dir != "") { parms->debug = 1; parms->debug_dir = options->debug_dir; parms->debug_stage = 0; } /* Allocate memory and build lookup tables */ printf ("Allocating lookup tables\n"); memset (roi_offset, 0, 3*sizeof(plm_long)); if (!options->input_xf_fn.empty()) { bxf = bspline_xform_load (options->input_xf_fn.c_str()); } else { bxf = new Bspline_xform; bxf->initialize ( fixed->origin, fixed->spacing, fixed->dim, roi_offset, fixed->dim, options->vox_per_rgn, fixed->get_direction_matrix() ); if (options->random) { srand (time (0)); for (i = 0; i < bxf->num_coeff; i++) { bxf->coeff[i] = options->random_range[0] + (options->random_range[1] - options->random_range[0]) * rand () / (double) RAND_MAX; } } } bod.set_bspline_xform (bxf); bod.set_bspline_parms (parms); /* Create scratch variables */ x = (float*) malloc (sizeof(float) * bxf->num_coeff); grad = (float*) malloc (sizeof(float) * bxf->num_coeff); grad_fd = (float*) malloc (sizeof(float) * bxf->num_coeff); /* Save a copy of x */ for (i = 0; i < bxf->num_coeff; i++) { x[i] = bxf->coeff[i]; } bst->initialize_mi_histograms (); /* Get score and gradient */ bspline_score (&bod); if (parms->debug) { bspline_save_debug_state (parms, bst, bxf); } /* Save a copy of score and gradient */ for (i = 0; i < bxf->num_coeff; i++) { grad[i] = bst->ssd.total_grad[i]; } score = bst->ssd.total_score; /* If a search dir was specified, use that instead of the gradient */ if (options->input_search_dir_fn != "") { std::ifstream ifs (options->input_search_dir_fn.c_str()); if (!ifs) { print_and_exit ("Failure opening %s for read\n", options->input_search_dir_fn.c_str()); } for (i = 0; i < bxf->num_coeff; i++) { ifs >> grad[i]; if (!ifs) { print_and_exit ("Incomplete search_dir in %s\n", options->input_search_dir_fn.c_str()); } } } if (options->output_fn.empty()) { fp = stdout; } else { fp = fopen (options->output_fn.c_str(), "w"); } if (options->process == CHECK_GRAD_PROCESS_LINE) { /* For each step along line */ for (i = options->line_range[0]; i <= options->line_range[1]; i++) { bst->it = i; /* Already computed for i = 0 */ if (i == 0) { fprintf (fp, "%4d,%12.12f\n", i, score); continue; } /* Create new location for x */ for (j = 0; j < bxf->num_coeff; j++) { bxf->coeff[j] = x[j] - i * options->step_size * grad[j]; } /* Get score */ bspline_score (&bod); if (parms->debug) { bspline_save_debug_state (parms, bst, bxf); } /* Compute difference between grad and grad_fd */ fprintf (fp, "%4d,%12.12f\n", i, bst->ssd.total_score); // JAS 04.19.2010 // This loop could take a while to exit. This will // flush the buffer so that we will at least get the data // that we worked for if we get sick of waiting and opt // for early program termination. fflush(fp); } } else { /* Loop through directions */ for (i = 0; i < bxf->num_coeff; i++) { bst->it = i; if (options->control_point_index >= 0) { if (i != options->control_point_index) { continue; } } /* Take a step in this direction */ for (j = 0; j < bxf->num_coeff; j++) { bxf->coeff[j] = x[j]; } bxf->coeff[i] = bxf->coeff[i] + options->step_size; /* Get score */ bspline_score (&bod); if (parms->debug) { bspline_save_debug_state (parms, bst, bxf); } /* Stash score difference in grad_fd */ grad_fd[i] = (bst->ssd.total_score - score) / options->step_size; /* Compute difference between grad and grad_fd */ fprintf (fp, "%12.12f,%12.12f\n", grad[i], grad_fd[i]); } } if (!options->output_fn.empty()) { fclose (fp); } free (x); free (grad); free (grad_fd); delete parms; delete bxf; } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: check_grad [options] fixed-image moving-image\n"; parser->print_options (std::cout); std::cout << std::endl; } /* -A hardware Either "cpu" or "cuda" (default=cpu) -M { mse | mi } Registration metric (default is mse) -f implementation Choose implementation (a single letter: a, b, etc.) -s "i j k" Integer knot spacing (voxels) -h prefix Generate histograms for each MI iteration --debug Create various debug files -p process Choices: "fwd", "bkd", "ctr" (for forward, backward, or central difference, or "line" for line profile. (default=fwd) -e step Step size (default is 1e-4) -l "min max" Min, max range for line profile (default "0 30") -R "min max" Random starting point (coeff between min, max) -X infile Input bspline coefficients -O file Output file */ static void parse_fn ( Check_grad_opts *parms, dlib::Plm_clp *parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Algorithm options */ parser->add_long_option ("A", "hardware", "algorithm hardware, either \"cpu\" or \"cuda\", " "default is cpu", 1, "cpu"); parser->add_long_option ("f", "flavor", "algroithm flavor, a single letter such as 'c' or 'f'", 1, ""); parser->add_long_option ("M", "metric", "registration metric, either \"mse\" or \"mi\", " "default is mse", 1, "mse"); parser->add_long_option ("p", "process", "analysis process, either \"fwd\", \"bkd\", or \"ctr\" " "for forward, backward, or central differencing, " "or \"line\" for line profile; default is \"fwd\"", 1, "fwd"); parser->add_long_option ("e", "step", "step size; default is 1e-4", 1, "1e-4"); parser->add_long_option ("l", "line-range", "range of line profile as number of steps between \"min max\"; " "default is \"0 30\"", 1, "0 30"); parser->add_long_option ("R", "random-start", "use random coefficient values in range between \"min max\"", 1, ""); /* Input/output files */ parser->add_long_option ("X", "input-xform", "input bspline transform", 1, ""); parser->add_long_option ("O", "output", "output file", 1, ""); parser->add_long_option ("", "debug-dir", "create various debug files", 1, ""); parser->add_long_option ("H", "histogram-prefix", "create MI histograms files with the specified prefix", 1, ""); parser->add_long_option ("", "input-search-dir", "input file containing search direction", 1, ""); parser->add_long_option ("", "fixed-roi", "input file for fixed image roi", 1, ""); /* Parse the command line arguments */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that two, and only two, input files were given */ if (parser->number_of_arguments() < 2) { throw (dlib::error ("Error. You must specify two input files")); } else if (parser->number_of_arguments() > 2) { std::string extra_arg = (*parser)[2]; throw (dlib::error ("Error. Unknown option " + extra_arg)); } /* Copy algorithm values into parms struct */ std::string val; val = parser->get_string("hardware").c_str(); if (val == "cpu") { parms->bsp_threading = BTHR_CPU; } else if (val == "cuda") { parms->bsp_threading = BTHR_CUDA; } else { throw (dlib::error ("Error parsing --hardware, unknown option.")); } val = parser->get_string("metric").c_str(); if (val == "mse") { parms->bsp_metric = SIMILARITY_METRIC_MSE; } else if (val == "mi") { parms->bsp_metric = SIMILARITY_METRIC_MI_MATTES; } else { throw (dlib::error ("Error parsing --metric, unknown option.")); } val = parser->get_string("flavor").c_str(); parms->bsp_implementation = val[0]; val = parser->get_string("process").c_str(); if (val == "fwd") { parms->process = CHECK_GRAD_PROCESS_FWD; } else if (val == "bkd") { parms->process = CHECK_GRAD_PROCESS_BKD; } else if (val == "ctr") { parms->process = CHECK_GRAD_PROCESS_CTR; } else if (val == "line") { parms->process = CHECK_GRAD_PROCESS_LINE; } else { throw (dlib::error ("Error parsing --metric, unknown option.")); } parms->step_size = parser->get_float ("step"); parser->assign_int_2 (parms->line_range, "line-range"); if (parser->have_option ("random-start")) { parser->assign_float_2 (parms->random_range, "random-start"); } /* Copy input filenames to parms struct */ parms->fixed_fn = (*parser)[0]; parms->moving_fn = (*parser)[1]; if (parser->have_option ("input-xform")) { parms->input_xf_fn = parser->get_string("input-xform"); } if (parser->have_option ("input-search-dir")) { parms->input_search_dir_fn = parser->get_string("input-search-dir"); } if (parser->have_option ("output")) { parms->output_fn = parser->get_string("output"); } if (parser->have_option ("debug-dir")) { parms->debug_dir = parser->get_string ("debug-dir"); } if (parser->have_option ("fixed-roi")) { parms->fixed_roi_fn = parser->get_string ("fixed-roi"); } if (parser->have_option ("histogram-prefix")) { parms->xpm_hist_prefix = parser->get_string("histogram-prefix").c_str(); } } int main (int argc, char* argv[]) { Check_grad_opts parms; Volume::Pointer moving, fixed; Volume *moving_grad; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv); /* Load images */ Plm_image::Pointer pli_fixed = Plm_image::New (new Plm_image (parms.fixed_fn)); Plm_image::Pointer pli_moving = Plm_image::New (new Plm_image (parms.moving_fn)); fixed = pli_fixed->get_volume_float (); moving = pli_moving->get_volume_float (); /* Compute spatial gradient */ moving_grad = volume_make_gradient (moving.get()); /* Check the gradient */ check_gradient (&parms, fixed.get(), moving.get(), moving_grad); /* Free memory */ delete moving_grad; return 0; } closest_point.cxx000066400000000000000000000237551321604176500323150ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "compute_distance.h" #define BUFLEN 2048 void calculate_mass (SURFACE* surface) { //computes center of mass for each triangle float x_sum = 0; float y_sum = 0; float z_sum = 0; VERTICES_LIST* vertices; TRIANGLE_LIST* triangles; MASS* center_mass; vertices = &surface->vertices; triangles = &surface->triangles; center_mass = &surface->centres; center_mass->num_triangles = triangles->num_triangles; for (int i = 0; i < triangles->num_triangles; i++) { center_mass->x = (float*) realloc (center_mass->x, (i + 1) * sizeof(float)); center_mass->y = (float*) realloc (center_mass->y, (i + 1) * sizeof(float)); center_mass->z = (float*) realloc (center_mass->z, (i + 1) * sizeof(float)); x_sum = vertices->x[triangles->first[i] - 1] + vertices->x[triangles->second[i] - 1] + vertices->x[triangles->third[i] - 1]; y_sum = vertices->y[triangles->first[i] - 1] + vertices->y[triangles->second[i] - 1] + vertices->y[triangles->third[i] - 1]; z_sum = vertices->z[triangles->first[i] - 1] + vertices->z[triangles->second[i] - 1] + vertices->z[triangles->third[i] - 1]; center_mass->x[i] = x_sum / 3; center_mass->y[i] = y_sum / 3; center_mass->z[i] = z_sum / 3; //printf("INDEX: %d %d %d\n",triangles->first[i],triangles->second[i],triangles->third[i]); //printf("CENTER OF MASS: %f %f %f\n",center_mass->x[i],center_mass->y[i],center_mass->z[i]); } } void cp (SURFACE* surface) { float x_min = 0; float y_min = 0; float z_min = 0; float d = 0; float d_prev = 0; //FILE* test; VERTICES_LIST* MDpoints; MASS* center_mass; CORR* corresp; corresp = &surface->correspondance; MDpoints = &surface->MDpoints; center_mass = &surface->centres; corresp->num_points = MDpoints->num_vertices; //printf("NUM CORR: %d \t NUM MDpoints:%d",corresp->num_points,MDpoints->num_vertices); corresp->corrpoint_index = (int*) realloc (corresp->corrpoint_index, corresp->num_points * sizeof(int)); //test=fopen("testing_bari.txt","w"); for (int k = 0; k < MDpoints->num_vertices; k++) { d = 999999999; d_prev = 999999999; for (int i = 0; i < center_mass->num_triangles; i++) { x_min = center_mass->x[i] - MDpoints->x[k]; y_min = center_mass->y[i] - MDpoints->y[k]; z_min = center_mass->z[i] - MDpoints->z[k]; d = (x_min * x_min) + (y_min * y_min) + (z_min * z_min); if (d < d_prev) { corresp->corrpoint_index[k] = i; d_prev = d; } x_min = 0; y_min = 0; z_min = 0; } //fprintf(test,"%f %f %f\n",center_mass->x[ center_mass->corrpoint_index[k]], center_mass->y[ center_mass->corrpoint_index[k]],center_mass->z[ center_mass->corrpoint_index[k]]); } //printf("NUM CORR: %d \t NUM MDpoints:%d\n",corresp->num_points,MDpoints->num_vertices); //for(int r=0; rnum_triangles/100; r++) // printf("CORR: %d\n",center_mass->corrpoint_index[r]); //fclose(test); } void compute_plane (SURFACE* surface) { float matrix[3][3]; int i = 0; VERTICES_LIST* vertices; PLANE* plane; TRIANGLE_LIST* triangles; CORR* corresp; vertices = &surface->vertices; triangles = &surface->triangles; corresp = &surface->correspondance; plane = &surface->planes; plane->num_planes = corresp->num_points; //printf("corresp->num_points: %d NUMPLANES: %d\n", corresp->num_points, plane->num_planes); plane->a0 = (float*) realloc (plane->a0, corresp->num_points * sizeof(float)); plane->a1 = (float*) realloc (plane->a1, corresp->num_points * sizeof(float)); plane->a2 = (float*) realloc (plane->a2, corresp->num_points * sizeof(float)); plane->a3 = (float*) realloc (plane->a3, corresp->num_points * sizeof(float)); for (i = 0; i < corresp->num_points; i++) { //printf("corresp->num_points: %d", corresp->num_points); //exit(-1); //a0 matrix[0][0] = vertices->x[triangles->first[corresp->corrpoint_index[i]] - 1]; matrix[1][0] = vertices->x[triangles->second[corresp->corrpoint_index[i]] - 1]; matrix[2][0] = vertices->x[triangles->third[corresp->corrpoint_index[i]] - 1]; matrix[0][1] = vertices->y[triangles->first[corresp->corrpoint_index[i]] - 1]; matrix[1][1] = vertices->y[triangles->second[corresp->corrpoint_index[i]] - 1]; matrix[2][1] = vertices->y[triangles->third[corresp->corrpoint_index[i]] - 1]; matrix[0][2] = vertices->z[triangles->first[corresp->corrpoint_index[i]] - 1]; matrix[1][2] = vertices->z[triangles->second[corresp->corrpoint_index[i]] - 1]; matrix[2][2] = vertices->z[triangles->third[corresp->corrpoint_index[i]] - 1]; //printf("TRIANGOLO: %d\n", corresp->corrpoint_index[i]); //printf("INDEX POINT: %d %d %d\n", triangles->first[corresp->corrpoint_index[i]]-1,triangles->second[corresp->corrpoint_index[i]]-1, triangles->third[corresp->corrpoint_index[i]]-1); //printf("MATRIX:\n"); //printf("%f %f %f\n",matrix[0][0],matrix[0][1],matrix[0][2]); //printf("%f %f %f\n",matrix[1][0],matrix[1][1],matrix[1][2]); //printf("%f %f %f\n",matrix[2][0],matrix[2][1],matrix[2][2]); plane->a0[i] = matrix[0][0] * (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1]) - matrix[1][0] * (matrix[0][1] * matrix[2][2] - matrix[2][1] * matrix[0][2]) + matrix[2][0] * (matrix[0][1] * matrix[1][2] - matrix[1][1] * matrix[0][2]); //printf("a0= %f\n", plane->a0[i]); //exit(-1); //a1 matrix[0][0] = 1; matrix[1][0] = 1; matrix[2][0] = 1; matrix[0][1] = vertices->y[triangles->first[corresp->corrpoint_index[i]] - 1]; matrix[1][1] = vertices->y[triangles->second[corresp->corrpoint_index[i]] - 1]; matrix[2][1] = vertices->y[triangles->third[corresp->corrpoint_index[i]] - 1]; matrix[0][2] = vertices->z[triangles->first[corresp->corrpoint_index[i]] - 1]; matrix[1][2] = vertices->z[triangles->second[corresp->corrpoint_index[i]] - 1]; matrix[2][2] = vertices->z[triangles->third[corresp->corrpoint_index[i]] - 1]; plane->a1[i] = matrix[0][0] * (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1]) - matrix[1][0] * (matrix[0][1] * matrix[2][2] - matrix[2][1] * matrix[0][2]) + matrix[2][0] * (matrix[0][1] * matrix[1][2] - matrix[1][1] * matrix[0][2]); //printf("a1= %f\n", plane->a1[i]); //a2 matrix[0][0] = vertices->x[triangles->first[corresp->corrpoint_index[i]] - 1]; matrix[1][0] = vertices->x[triangles->second[corresp->corrpoint_index[i]] - 1]; matrix[2][0] = vertices->x[triangles->third[corresp->corrpoint_index[i]] - 1]; matrix[0][1] = 1; matrix[1][1] = 1; matrix[2][1] = 1; matrix[0][2] = vertices->z[triangles->first[corresp->corrpoint_index[i]] - 1]; matrix[1][2] = vertices->z[triangles->second[corresp->corrpoint_index[i]] - 1]; matrix[2][2] = vertices->z[triangles->third[corresp->corrpoint_index[i]] - 1]; plane->a2[i] = matrix[0][0] * (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1]) - matrix[1][0] * (matrix[0][1] * matrix[2][2] - matrix[2][1] * matrix[0][2]) + matrix[2][0] * (matrix[0][1] * matrix[1][2] - matrix[1][1] * matrix[0][2]); //printf("a2= %f\n", plane->a2[i]); //a3 matrix[0][0] = vertices->x[triangles->first[corresp->corrpoint_index[i]] - 1]; matrix[1][0] = vertices->x[triangles->second[corresp->corrpoint_index[i]] - 1]; matrix[2][0] = vertices->x[triangles->third[corresp->corrpoint_index[i]] - 1]; matrix[0][1] = vertices->y[triangles->first[corresp->corrpoint_index[i]] - 1]; matrix[1][1] = vertices->y[triangles->second[corresp->corrpoint_index[i]] - 1]; matrix[2][1] = vertices->y[triangles->third[corresp->corrpoint_index[i]] - 1]; matrix[0][2] = 1; matrix[1][2] = 1; matrix[2][2] = 1; plane->a3[i] = matrix[0][0] * (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1]) - matrix[1][0] * (matrix[0][1] * matrix[2][2] - matrix[2][1] * matrix[0][2]) + matrix[2][0] * (matrix[0][1] * matrix[1][2] - matrix[1][1] * matrix[0][2]); //printf("a3= %f\n", plane->a3[i]); //exit(-1); } //printf("FIRST PLANE: %f %f %f %f",plane->a0[0],plane->a1[0], plane->a2[0], plane->a3[0]); //exit(-1); } void do_cp (FILE* mesh, FILE* MDpoints, SURFACE* surface, FILE* output) { float d = 0; float pt[3]; float coeff[4]; VERTICES_LIST* points; PLANE* plane; read_obj (mesh, surface); calculate_mass (surface); read_MDcontours (MDpoints, surface); cp (surface); compute_plane (surface); //printf("FIRST PLANE: %f %f %f %f",plane->a0[0],plane->a1[0], plane->a2[0], plane->a3[0]); //exit(-1); points = &surface->MDpoints; plane = &surface->planes; plane->num_planes = points->num_vertices; //printf("NUMPLANES: %d",plane->num_planes); //printf("FIRST PLANE: %f %f %f %f",plane->a0[0],plane->a1[0], plane->a2[0], plane->a3[0]); //exit(-1); for (int i = 0; i < plane->num_planes; i++) { pt[0] = points->x[i]; pt[1] = points->y[i]; pt[2] = points->z[i]; coeff[0] = plane->a0[i]; coeff[1] = plane->a1[i]; coeff[2] = plane->a2[i]; coeff[3] = plane->a3[i]; d = fabs ((coeff[1] * pt[0] + coeff[2] * pt[1] + coeff[3] * pt[2] - coeff[0]) / sqrt (coeff[1] * coeff[1] + coeff[2] * coeff[2] + coeff[3] * coeff[3])); //fprintf(output,"%f %f %f %f %f\n",plane->a0[i],plane->a1[i],plane->a2[i],plane->a3[i],d); fprintf (output, "%f\n", d); //exit(-1); } fclose (output); } cmd_prompt_launcher.cxx000066400000000000000000000014721321604176500334450ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include #if defined (_WIN32) #include #include #define GetCurrentDir _getcwd #endif #include /* defines FILENAME_MAX */ int main (int argc, char* argv[]) { #if defined (_WIN32) char cCurrentPath[FILENAME_MAX]; if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath))) { return errno; } printf(cCurrentPath); printf("\n"); ShellExecute(0, "open", "cmd", 0, (LPCSTR)cCurrentPath, SW_SHOW); #else printf ("Sorry, CMD prompt launcher is only for windows system.\n"); #endif return 0; } compute_distance.cxx000066400000000000000000000073531321604176500327520ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "compute_distance.h" void print_usage (void) { printf ("Usage: contour_statistics \n"); printf (" mode (options: cp, cm) "); printf (" file1 "); printf (" file2 "); printf (" [filename]\n"); printf (" OPTIONS EXPLANATION: \n"); printf (" cp= Closest Point computation between mesh file and reference points: file1 *.obj file, file2 *.txt file with the reference points, filename output *.txt file\n\n\n"); printf (" cm= Closest Mesh computation: file1 *.obj file with reference mesh, file2 *.obj file with the other mesh, filename output *.txt file\n"); exit (-1); } int main(int argc, char* argv[]) { ImgType::Pointer reference=ImgType::New(); ImgType::Pointer warped=ImgType::New(); ImgType::Pointer ex_1=ImgType::New(); ImgType::Pointer ex_2=ImgType::New(); ImgType::Pointer ex_3=ImgType::New(); FILE* mesh; //FILE* refMesh; FILE* MDpoints; FILE* output = 0; if (argc<3) print_usage(); if(strcmp("cp",argv[1])==0){ mesh=fopen(argv[2],"r"); MDpoints=fopen(argv[3],"r"); if(!mesh || !MDpoints){ fprintf(stderr,"Error: could not open the files for the cp calculation for reading!\n"); if(!mesh) fprintf(stderr,"This file could not be opened: %s\n",argv[2]); else fprintf(stderr,"This file could not be opened: %s\n",argv[3]); exit(-1); } }else if (strcmp("cm",argv[1])==0){ printf("Sorry! there is some work going on here!"); exit(-1); //refMesh=fopen(argv[2],"r"); //mesh=fopen(argv[3],"r"); //if(!refMesh || !mesh){ // fprintf(stderr,"Error: could not open the files for the cp calculation for reading!\n"); // if(!refMesh) // fprintf(stderr,"This file could not be opened: %s\n",argv[2]); // else // fprintf(stderr,"This file could not be opened: %s\n",argv[3]); // exit(-1); //} }else{ fprintf(stderr,"Sorry! you typed in the wrong mode"); exit(-1); } if (argc<5){ if(strcmp("cp",argv[1])==0){ output=fopen("cp_dist.txt","w"); }else{ output=fopen("mesh_dist.txt","w"); fclose(output); //to be canceled when mesh mesh distnace is implemented } }else if (argc==5){ output=fopen(argv[4],"w"); } if(!output){ fprintf(stderr, "An error occurred while opening the file for writing the outputs!"); exit(-1); } if(strcmp("cp",argv[1])==0){ SURFACE* surface=(SURFACE*)malloc(sizeof(SURFACE)); memset(surface,0,sizeof(SURFACE)); printf("Allocated Surface\n"); do_cp(mesh,MDpoints,surface,output); }else if(strcmp("cm",argv[1])==0){ printf("function in development\n"); exit(-1); } return 0; } //TRIANGLE_LIST* triangles=(TRIANGLE_LIST*)malloc(sizeof(TRIANGLE_LIST)); //memset(triangles,0,sizeof(TRIANGLE_LIST)); //triangles->num_triangles=0; //triangles=&surface->triangles; //printf("LAST: %d %d %d\n",triangles->first[triangles->num_triangles-1], // triangles->second[triangles->num_triangles-1], triangles->third[triangles->num_triangles-1]); //MASS* center_mass=(MASS*)malloc(sizeof(MASS)); //memset(center_mass,0,sizeof(MASS)); //center_mass->num_triangles=0; //center_mass->x=(float*)malloc(sizeof(float)); //memset(center_mass->x,0,sizeof(float)); //center_mass->y=(float*)malloc(sizeof(float)); //memset(center_mass->y,0,sizeof(float)); //center_mass->z=(float*)malloc(sizeof(float)); //memset(center_mass->z,0,sizeof(float)); //center_mass->corrpoint_index=(int*)malloc(sizeof(int)); //memset(center_mass->corrpoint_index,0,sizeof(int)); //for(int r=0; rnum_triangles; r++) // printf("CORR: %d\n",center_mass->corrpoint_index[r]); //fclose(mesh); compute_distance.h000066400000000000000000000033751321604176500323770ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/*=========================================================== See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ===========================================================*/ #ifndef _contour_statistics_h #define _contour_statistics_h #include #include #include #include #include "plm_config.h" #include "itkImageFileReader.h" #include "itkImage.h" #include "itk_image_type.h" #include "itkImageRegionIteratorWithIndex.h" #include "itkImageSliceConstIteratorWithIndex.h" /* =======================================================================* Definitions * =======================================================================*/ typedef UCharImageType ImgType; typedef itk::Image intImgType; typedef struct vertices VERTICES_LIST; struct vertices { int num_vertices; float* x; float* y; float* z; }; typedef struct triangle TRIANGLE_LIST; struct triangle { int num_triangles; int* first; int* second; int* third; }; typedef struct mass MASS; struct mass { float* x; float* y; float* z; int num_triangles; }; typedef struct corr CORR; struct corr{ int* corrpoint_index; int num_points; }; typedef struct plane PLANE; struct plane { int num_planes; float* a0; float* a1; float* a2; float* a3; }; typedef struct surface SURFACE; struct surface{ VERTICES_LIST vertices; TRIANGLE_LIST triangles; MASS centres; VERTICES_LIST MDpoints; CORR correspondance; PLANE planes; }; void do_cp(FILE* mesh,FILE* MDpoints, SURFACE* surface, FILE* output); void read_obj(FILE* mesh, SURFACE* surface); void read_MDcontours(FILE* MDpoints, SURFACE* surface); void calculate_mass(SURFACE* surface); void cp(SURFACE* surface); void compute_plane(SURFACE* surface); #endif cuda_probe_main.cxx000066400000000000000000000005041321604176500325220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "cuda_probe.h" int main (int argc, char* argv[]) { cuda_probe (); return 0; } cuda_probe_wrap.cpp000066400000000000000000000000351321604176500325260ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "cuda_probe.cu.cpp" demons_main.cxx000066400000000000000000000034141321604176500317070ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "delayload.h" #include "demons_opts.h" #include "mha_io.h" #include "vf.h" #include "vf_stats.h" #include "volume.h" #include "volume_grad.h" int main (int argc, char* argv[]) { Demons_options options; Volume* fixed; Volume* moving; Volume* warped; Volume* moving_grad = 0; Volume* vector_field; /* Read in command line options */ parse_args (&options, argc, argv); printf("\nReading the static/reference image\n"); fixed = read_mha (options.fixed_fn); if (!fixed) return -1; printf("\nReading the moving image \n"); moving = read_mha (options.moving_fn); if (!moving) return -1; if (fixed->npix != moving->npix) { printf("\nVolumes have different dimensions.....Exiting\n"); exit(-1); } volume_convert_to_float (moving); volume_convert_to_float (fixed); if (options.parms.threading != THREADING_OPENCL) { moving_grad = volume_make_gradient (moving); //write_mha ("moving_grad.mha", moving_grad); } vector_field = demons (fixed, moving, moving_grad, 0, &options.parms); vf_analyze (vector_field, 0); if (options.output_vf_fn) { write_mha (options.output_vf_fn, vector_field); } warped = vf_warp (0, moving, vector_field); if (options.output_img_fn) { write_mha (options.output_img_fn, warped); } delete fixed; delete moving; if (options.parms.threading != THREADING_OPENCL) { delete moving_grad; } delete vector_field; return 0; } demons_opts.cxx000066400000000000000000000104441321604176500317510ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include #include "demons_opts.h" void print_usage (void) { printf ( "Usage: demons [options] fixed moving\n" "Options:\n" " -A algorithm Either \"cpu\" or \"cuda\" (default=cpu)\n" " -a accel Acceleration factor (default=1)\n" " -e denom_eps Minimum allowed denominator magnitude (default=1)\n" " -f \"i j k\" Width of smoothing kernel (voxels)\n" " -h homogenization Cachier's alpha^2 homogenization (default=1)\n" " -m iterations Maximum iterations (default=10)\n" " -s std Std dev (mm) of smoothing kernel (default=5)\n" " -O outfile Output warped image file\n" " -V outfile Output vector field\n" ); exit (1); } void parse_args (Demons_options* options, int argc, char* argv[]) { int i, rc; Demons_parms* parms = &options->parms; options->output_img_fn = 0; options->output_vf_fn = 0; demons_default_parms (parms); for (i = 1; i < argc; i++) { if (argv[i][0] != '-') break; if (!strcmp (argv[i], "-A")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; #if CUDA_FOUND if (!strcmp(argv[i], "cuda") || !strcmp(argv[i], "CUDA")) { parms->threading = THREADING_CUDA; continue; } #endif #if OPENCL_FOUND if (!strcmp(argv[i], "opencl") || !strcmp(argv[i], "OPENCL")) { parms->threading = THREADING_OPENCL; continue; } #endif /* Default */ parms->threading = THREADING_CPU_OPENMP; } else if (!strcmp (argv[i], "-a")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g" , &parms->accel); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-e")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g" , &parms->denominator_eps); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-f")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%d %d %d", &parms->filter_width[0], &parms->filter_width[1], &parms->filter_width[2]); if (rc != 3) { print_usage (); } } else if (!strcmp (argv[i], "-h")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g" , &parms->homog); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-m")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%d" , &parms->max_its); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-s")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g" , &parms->filter_std); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-O")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; options->output_img_fn = strdup (argv[i]); } else if (!strcmp (argv[i], "-V")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; options->output_vf_fn = strdup (argv[i]); } else { print_usage (); break; } } if (i+1 >= argc) { print_usage (); } options->fixed_fn = argv[i]; options->moving_fn = argv[i+1]; printf ("Fixed = %s\n", options->fixed_fn); printf ("Moving = %s\n", options->moving_fn); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/demons_opts.h000066400000000000000000000010101321604176500314420ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _demon_opts_h_ #define _demon_opts_h_ #include "demons.h" class Demons_options { public: char* fixed_fn; char* moving_fn; char* output_vf_fn; char* output_img_fn; Demons_parms parms; }; void parse_args (Demons_options* options, int argc, char* argv[]); #endif dice_stats_main.cxx000066400000000000000000000027141321604176500325460ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "dice_statistics.h" #include "pcmd_resample.h" void print_usage (void) { printf ("Usage: dice_stats file1 file2\n"); } /* For differing resolutions, resamples image_2 to image_1 */ void check_resolution ( UCharImageType::Pointer *image_1, UCharImageType::Pointer *image_2 ) { if ( (*image_1)->GetLargestPossibleRegion().GetSize() != (*image_2)->GetLargestPossibleRegion().GetSize() ) { Plm_image_header pih; Resample_parms parms; parms.interp_lin = false; pih.set_from_itk_image (*image_1); *image_2 = resample_image ( *image_2, &pih, parms.default_val, parms.interp_lin ); } } int main (int argc, char* argv[]) { if (argc != 3) { print_usage(); exit (-1); } UCharImageType::Pointer image_1 = itk_image_load_uchar(argv[1], 0); UCharImageType::Pointer image_2 = itk_image_load_uchar(argv[2], 0); check_resolution (&image_1, &image_2); do_dice (image_1, image_2, stdout); do_hausdorff (image_1, image_2); do_contour_mean_dist (image_1, image_2); return 0; } dicom_info.cxx000066400000000000000000000077131321604176500315320ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include "itkImageFileReader.h" #include "itkGDCMImageIO.h" #include "itkImageIOBase.h" #include "itkMetaDataDictionary.h" #include "itkMetaDataObject.h" #include "gdcmGlobal.h" #include "plm_clp.h" class Dicom_info_parms { public: std::string input_dir; bool short_parms; public: Dicom_info_parms () { input_dir = ""; short_parms = false; } }; static void do_dicom_info (Dicom_info_parms *parms) { typedef signed short PixelType; const unsigned int Dimension = 2; typedef itk::Image ImageType; typedef itk::ImageFileReader ReaderType; ReaderType::Pointer reader = ReaderType::New(); typedef itk::GDCMImageIO ImageIOType; ImageIOType::Pointer dicomIO = ImageIOType::New(); dicomIO->SetMaxSizeLoadEntry(0xffff); printf ("Reading input file: %s\n", parms->input_dir.c_str()); reader->SetFileName(parms->input_dir); reader->SetImageIO(dicomIO); try { reader->Update(); } catch (itk::ExceptionObject &ex) { std::cout << ex << std::endl; return; } typedef itk::MetaDataDictionary DictionaryType; const DictionaryType & dictionary = dicomIO->GetMetaDataDictionary(); typedef itk::MetaDataObject< std::string > MetaDataStringType; DictionaryType::ConstIterator itr = dictionary.Begin(); DictionaryType::ConstIterator end = dictionary.End(); while (itr != end) { itk::MetaDataObjectBase::Pointer entry = itr->second; MetaDataStringType::Pointer entryvalue = dynamic_cast < MetaDataStringType *> (entry.GetPointer()); if (entryvalue) { std::string tagkey = itr->first; std::string labelId; bool found = itk::GDCMImageIO::GetLabelFromTag (tagkey, labelId); std::string tagvalue = entryvalue->GetMetaDataObjectValue(); if (found) { if (parms->short_parms) { if (tagkey == "0010|0010" || // Patient's Name tagkey == "0010|0040" || // Patient's Sex tagkey == "0010|0030" || // Patient's Birth Date tagkey == "0010|1010" || // Patient's Age tagkey == "0008|0020" || // Study Date tagkey == "0008|0080" || // Institution Name tagkey == "0008|0090" || // Referring Physician's Name tagkey == "0008|0060" || // Modality tagkey == "0028|0010" || // Rows tagkey == "0028|0011" || // Columns tagkey == "0028|0030" || // Pixel Spacing tagkey == "0018|0050") // Slice Thickness std::cout << labelId << " = " << tagvalue.c_str() << std::endl; } else { std::cout << labelId << " = " << tagvalue.c_str() << std::endl; } } } ++itr; } return; } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: dicom_info [options]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Dicom_info_parms *parms, dlib::Plm_clp *parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Basic options */ parser->add_long_option ("i", "input", "Input dicom file", 1, ""); parser->add_long_option ("s", "short", "Display only default set of common header values",0); /* Parse the command line arguments */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Copy values into output struct */ parms->input_dir = parser->get_string("input").c_str(); if (parser->option("short")) { parms->short_parms = true; } } int main (int argc, char *argv[]) { Dicom_info_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv); do_dicom_info (&parms); return 0; } dicom_uid_main.cxx000066400000000000000000000015351321604176500323600ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "dicom_util.h" #include "plm_uid_prefix.h" void print_usage (void) { fprintf (stderr, "Usage: dicom_uid [prefix]\n"); exit (-1); } int main (int argc, char* argv[]) { char uid[100]; const char* uid_root = PLM_UID_PREFIX; if (argc == 2) { uid_root = argv[1]; } else if (argc != 1) { print_usage (); } if (strlen (uid_root) >= 32) { fprintf (stderr, "Sorry, uid prefix should be less than 32 characters\n"); exit (-1); } dicom_uid (uid, uid_root); printf ("%s\n", uid); return (0); } dlib_train.cxx000066400000000000000000000660641321604176500315370ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone// The contents of this file are in the public domain. // See LICENSE_FOR_EXAMPLE_PROGRAMS.txt (in dlib) /* This is a command line program that can try different regression algorithms on a libsvm-formatted data set. */ #include "plm_config.h" #include #include #include #include #include #include "dlib/cmd_line_parser.h" #include "dlib/data_io.h" #include "dlib/mlp.h" #include "dlib/revision.h" #include "dlib/svm.h" //#include "dlib/svm_threaded.h" #include "option_range.h" #include "plm_clp.h" #include "plm_math.h" typedef std::map sparse_sample_type; typedef dlib::matrix< sparse_sample_type::value_type::second_type,0,1 > dense_sample_type; typedef double label_type; class Dlib_test_parms { public: int a; }; /* This particular is modified from libsvm_io.h, therefore part of dlib and distributed according to Boost license. */ namespace dlib { template void load_libsvm_or_vw_data ( const std::string& file_name, std::vector& samples, std::vector& labels ) { using namespace std; typedef typename sample_type::value_type pair_type; typedef typename basic_type::type key_type; typedef typename pair_type::second_type value_type; // You must use unsigned integral key types in your sparse vectors COMPILE_TIME_ASSERT(is_unsigned_type::value); samples.clear(); labels.clear(); ifstream fin(file_name.c_str()); if (!fin) throw sample_data_io_error("Unable to open file " + file_name); string line; istringstream sin; key_type key; value_type value; label_type label; sample_type sample; long line_num = 0; while (fin.peek() != EOF) { ++line_num; getline(fin, line); string::size_type pos = line.find_first_not_of(" \t\r\n"); // ignore empty lines or comment lines if (pos == string::npos || line[pos] == '#') continue; sin.clear(); sin.str(line); sample.clear(); sin >> label; if (!sin) throw sample_data_io_error("On line: " + cast_to_string(line_num) + ", error while reading file " + file_name ); // eat whitespace sin >> ws; /* Ignore pipe in vw format */ if (sin.peek() == '|') { sin.get(); sin >> ws; } while (sin.peek() != EOF && sin.peek() != '#') { sin >> key >> ws; // ignore what should be a : character if (sin.get() != ':') throw sample_data_io_error("On line: " + cast_to_string(line_num) + ", error while reading file " + file_name); sin >> value >> ws; if (sin && value != 0) { sample.insert(sample.end(), make_pair(key, value)); } } samples.push_back(sample); labels.push_back(label); } } } static void set_range ( Option_range& range, dlib::Plm_clp* parser, const std::string& option_name, float default_value ) { if (parser->option (option_name)) { range.set_range (parser->get_string (option_name)); } else { range.set_range (default_value); } } static float get_positive_rate ( std::vector& labels ) { std::vector::const_iterator label_it; int np = 0; int tot = 0; for (label_it = labels.begin(); label_it != labels.end(); label_it++) { if (*label_it > 0) { np++; } tot ++; } return (float) np / (float) tot; } static std::string get_kernel ( dlib::Plm_clp* parser ) { std::string kernel = "rbk"; if (parser->option ("learning-kernel")) { kernel = parser->get_string ("learning-kernel"); } return kernel; } static void get_rbk_gamma ( dlib::Plm_clp* parser, std::vector& dense_samples, Option_range& range ) { float default_gamma = 3.0 / compute_mean_squared_distance ( randomly_subsample (dense_samples, 2000)); set_range (range, parser, "rbk-gamma", default_gamma); } static void get_krls_tolerance ( dlib::Plm_clp* parser, std::vector& dense_samples, Option_range& range ) { float default_krls_tolerance = 0.001; set_range (range, parser, "krls-tolerance", default_krls_tolerance); } static double get_mlp_hidden_units ( dlib::Plm_clp* parser, std::vector& dense_samples ) { int num_hidden = 5; if (parser->option ("mlp-hidden-units")) { num_hidden = parser->get_int ("mlp-hidden-units"); } return num_hidden; } static double get_mlp_num_iterations ( dlib::Plm_clp* parser, std::vector& dense_samples ) { int num_iterations = 5000; if (parser->option ("mlp-num-iterations")) { num_iterations = parser->get_int ("mlp-num-iterations"); } return num_iterations; } static void get_svc ( dlib::Plm_clp* parser, std::vector& dense_samples, Option_range& range ) { float default_svc = 1000.; set_range (range, parser, "sv-c", default_svc); } #if defined (commentout) static double get_svr_epsilon_insensitivity ( dlib::Plm_clp* parser, std::vector& dense_samples ) { // Epsilon-insensitive regression means we do regression but stop // trying to fit a data point once it is "close enough" to its // target value. This parameter is the value that controls what // we mean by "close enough". In this case, I'm saying I'm happy // if the resulting regression function gets within 0.001 of the // target value. double epsilon_insensitivity = 0.001; if (parser->option ("svr-epsilon-insensitivity")) { epsilon_insensitivity = sa = parser->option("svr-epsilon-insensitivity").argument(); } return epsilon_insensitivity; } #endif static void krls_test ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { typedef dlib::radial_basis_kernel kernel_type; Option_range gamma_range, krls_tol_range; get_rbk_gamma (parser, dense_samples, gamma_range); get_krls_tolerance (parser, dense_samples, krls_tol_range); // Split into training set and testing set float training_pct = 0.8; unsigned int training_samples = (unsigned int) floor ( training_pct * dense_samples.size()); const std::list& krls_tol_list = krls_tol_range.get_range (); std::list::const_iterator krls_tol_it; for (krls_tol_it = krls_tol_list.begin (); krls_tol_it != krls_tol_list.end (); krls_tol_it++) { float krls_tol = *krls_tol_it; const std::list& gamma_list = gamma_range.get_range (); std::list::const_iterator gamma_it; for (gamma_it = gamma_list.begin (); gamma_it != gamma_list.end (); gamma_it ++) { float gamma = *gamma_it; dlib::krls net (kernel_type(gamma), krls_tol); // Krls doesn't seem to come with any batch training function for (unsigned int j = 0; j < training_samples; j++) { net.train (dense_samples[j], labels[j]); } // Test the performance (sorry, no cross-validation) double total_err = 0.0; for (unsigned int j = training_samples + 1; j < dense_samples.size(); j++) { double diff = net(dense_samples[j]) - labels[j]; total_err += diff * diff; } double testset_error = total_err / (dense_samples.size() - training_samples); printf ("%3.6f %3.6f %3.9f\n", krls_tol, gamma, testset_error); } } } static void krr_rbk_test ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { typedef dlib::radial_basis_kernel kernel_type; dlib::krr_trainer trainer; Option_range gamma_range; double best_gamma = DBL_MAX; float best_loo = FLT_MAX; get_rbk_gamma (parser, dense_samples, gamma_range); const std::list& gamma_list = gamma_range.get_range (); std::list::const_iterator gamma_it; for (gamma_it = gamma_list.begin (); gamma_it != gamma_list.end (); gamma_it ++) { float gamma = *gamma_it; // LOO cross validation double loo_error = 0.; if (parser->option("verbose")) { trainer.set_search_lambdas(dlib::logspace(-9, 4, 100)); trainer.be_verbose(); } trainer.set_kernel (kernel_type (gamma)); #if DLIB_REVISION == 4093 /* dlib 17.34 */ trainer.train (dense_samples, labels, loo_error); #elif DLIB_MAJOR_VERSION > 17 || (DLIB_MAJOR_VERSION == 17 && DLIB_MINOR_VERSION >= 44) /* dlib 17.44, dlib 18.7 */ std::vector loo_values; double lambda_used; trainer.train (dense_samples, labels, loo_values, lambda_used); loo_error = dlib::mean_squared_error (labels, loo_values); #else error, unknown DLIB version!; #endif if (loo_error < best_loo) { best_loo = loo_error; best_gamma = gamma; } printf ("10^%f %9.6f\n", log10(gamma), loo_error); } printf ("Best result: gamma=10^%f (%g), loo_error=%9.6f\n", log10(best_gamma), best_gamma, best_loo); if (parser->option("train-best")) { printf ("Training network with best parameters\n"); trainer.set_kernel (kernel_type (best_gamma)); dlib::decision_function best_network = trainer.train (dense_samples, labels); std::ofstream fout (parser->option("train-best").argument().c_str(), std::ios::binary); serialize (best_network, fout); fout.close(); #if defined (commentout) for (unsigned int j = 0; j < dense_samples.size(); j++) { printf ("%g %g\n", labels[j], best_network(dense_samples[j])); } #endif } } static void krr_lin_test ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { typedef dlib::linear_kernel kernel_type; dlib::krr_trainer trainer; // LOO cross validation double loo_error; #if DLIB_REVISION == 4093 /* dlib 17.34 */ trainer.train (dense_samples, labels, loo_error); #elif DLIB_MAJOR_VERSION > 17 || (DLIB_MAJOR_VERSION == 17 && DLIB_MINOR_VERSION >= 44) /* dlib 17.44, dlib 18.7 */ std::vector loo_values; double lambda_used; trainer.train (dense_samples, labels, loo_values, lambda_used); loo_error = dlib::mean_squared_error (labels, loo_values); #else error, unknown DLIB version!; #endif std::cout << "mean squared LOO error: " << loo_error << std::endl; } static void krr_test ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { const std::string& kernel = get_kernel (parser); if (kernel == "lin") { krr_lin_test (parser, dense_samples, labels); } else if (kernel == "rbk") { krr_rbk_test (parser, dense_samples, labels); } else { fprintf (stderr, "Unknown kernel type: %s\n", kernel.c_str()); exit (-1); } } static void mlp_test ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { // Create a multi-layer perceptron network. const int num_input = dense_samples[0].size(); int num_hidden = get_mlp_hidden_units (parser, dense_samples); printf ("Creating ANN with size (%d, %d)\n", num_input, num_hidden); dlib::mlp::kernel_1a_c net (num_input, num_hidden); // Dlib barfs if output values are not normalized to [0,1] double label_min = *(std::min_element (labels.begin(), labels.end())); double label_max = *(std::max_element (labels.begin(), labels.end())); std::vector::iterator it; for (it = labels.begin(); it != labels.end(); it++) { (*it) = ((*it) - label_min) / (label_max - label_min); } // Split into training set and testing set float training_pct = 0.8; unsigned int training_samples = (unsigned int) floor ( training_pct * dense_samples.size()); // Dlib doesn't seem to come with any batch training functions for mlp. // Also, note that only backprop is supported. int num_iterations = get_mlp_num_iterations (parser, dense_samples); for (int i = 0; i < num_iterations; i++) { for (unsigned int j = 0; j < training_samples; j++) { net.train (dense_samples[j], labels[j]); } } // Test the performance (sorry, no cross-validation) */ double total_err = 0.0; for (unsigned int j = training_samples + 1; j < dense_samples.size(); j++) { double diff = net(dense_samples[j]) - labels[j]; diff = diff * (label_max - label_min); total_err += diff * diff; } std::cout << "MSE (no cross-validation): " << total_err / (dense_samples.size() - training_samples) << std::endl; } static void svr_lin_test ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { Option_range svc_range; #if DLIB_REVISION == 4093 /* dlib 17.34 */ double best_svc = DBL_MAX; float best_cv_error = FLT_MAX; typedef linear_kernel kernel_type; svr_trainer trainer; double epsilon_insensitivity = get_svr_epsilon_insensitivity ( parser, dense_samples); trainer.set_epsilon_insensitivity (epsilon_insensitivity); double cv_error; for (float svc = svc_range.get_min_value(); svc <= svc_range.get_max_value(); svc = svc_range.get_next_value(svc)) { trainer.set_c (svc); cv_error = cross_validate_regression_trainer (trainer, dense_samples, labels, 10); if (cv_error < best_cv_error) { best_cv_error = cv_error; best_svc = svc; } printf ("%3.6f %3.9f\n", svc, cv_error); } printf ("Best result: svc=%3.6f, cv_error=%9.6f\n", best_svc, best_cv_error); if (parser->option("train-best")) { printf ("Training network with best parameters\n"); trainer.set_c (best_svc); decision_function best_network = trainer.train (dense_samples, labels); std::ofstream fout (parser->option("train-best").argument().c_str(), std::ios::binary); serialize (best_network, fout); fout.close(); for (unsigned int j = 0; j < dense_samples.size(); j++) { printf ("%g %g\n", labels[j], best_network(dense_samples[j])); } } #elif DLIB_MAJOR_VERSION > 17 || (DLIB_MAJOR_VERSION == 17 && DLIB_MINOR_VERSION >= 44) /* dlib 17.44, dlib 18.7 */ /* GCS FIX: The above doesn't compile. */ #else error, unknown DLIB version!; #endif } static void svr_rbk_test ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { typedef dlib::radial_basis_kernel kernel_type; dlib::svr_trainer trainer; Option_range gamma_range, svc_range; #if DLIB_REVISION == 4093 /* dlib 17.34 */ double best_gamma = DBL_MAX; double best_svc = DBL_MAX; float best_cv_error = FLT_MAX; get_rbk_gamma (parser, dense_samples, gamma_range); get_svc (parser, dense_samples, svc_range); double epsilon_insensitivity = get_svr_epsilon_insensitivity ( parser, dense_samples); trainer.set_epsilon_insensitivity (epsilon_insensitivity); for (float svc = svc_range.get_min_value(); svc <= svc_range.get_max_value(); svc = svc_range.get_next_value (svc)) { trainer.set_c (svc); for (float gamma = gamma_range.get_min_value(); gamma <= gamma_range.get_max_value(); gamma = gamma_range.get_next_value (gamma)) { double cv_error; trainer.set_kernel (kernel_type (gamma)); cv_error = cross_validate_regression_trainer (trainer, dense_samples, labels, 10); if (cv_error < best_cv_error) { best_cv_error = cv_error; best_gamma = gamma; best_svc = svc; } printf ("%3.6f %3.6f %3.9f\n", svc, gamma, cv_error); } } printf ("Best result: svc=%3.6f gamma=10^%f (%g), cv_error=%9.6f\n", best_svc, log10(best_gamma), best_gamma, best_cv_error); if (parser->option("train-best")) { printf ("Training network with best parameters\n"); trainer.set_c (best_svc); trainer.set_kernel (kernel_type (best_gamma)); decision_function best_network = trainer.train (dense_samples, labels); std::ofstream fout (parser->option("train-best").argument().c_str(), std::ios::binary); serialize (best_network, fout); fout.close(); for (unsigned int j = 0; j < dense_samples.size(); j++) { printf ("%g %g\n", labels[j], best_network(dense_samples[j])); } } #elif DLIB_MAJOR_VERSION > 17 || (DLIB_MAJOR_VERSION == 17 && DLIB_MINOR_VERSION >= 44) /* dlib 17.44, dlib 18.7 */ /* GCS FIX: The above doesn't compile. */ #else error, unknown DLIB version!; #endif } static void svr_test ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { const std::string& kernel = get_kernel (parser); if (kernel == "lin") { svr_lin_test (parser, dense_samples, labels); } else if (kernel == "rbk") { svr_rbk_test (parser, dense_samples, labels); } else { fprintf (stderr, "Unknown kernel type: %s\n", kernel.c_str()); exit (-1); } } static void svm_lin_test ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { typedef dlib::radial_basis_kernel kernel_type; dlib::svm_c_trainer trainer; double best_gamma = DBL_MAX; double best_svc = DBL_MAX; float best_loss = FLT_MAX; Option_range gamma_range; Option_range svc_range; get_rbk_gamma (parser, dense_samples, gamma_range); get_svc (parser, dense_samples, svc_range); float positive_rate = get_positive_rate (labels); printf ("Positive rate = %3.6f\n", positive_rate); const std::list& svc_list = svc_range.get_range (); std::list::const_iterator svc_it; for (svc_it = svc_list.begin (); svc_it != svc_list.end (); svc_it ++) { const std::list& gamma_list = gamma_range.get_range (); std::list::const_iterator gamma_it; for (gamma_it = gamma_list.begin (); gamma_it != gamma_list.end (); gamma_it ++) { float svc = *svc_it; float gamma = *gamma_it; trainer.set_kernel (kernel_type (gamma)); trainer.set_c (svc); dlib::matrix cv_error; cv_error = dlib::cross_validate_trainer ( trainer, dense_samples, labels, 3); /* cv_error(0) = percent correct positive = TP / (TP + FN) cv_error(1) = percent correct negative = TN / (TN + FP) */ float loss = cv_error(0) * positive_rate + cv_error(1) * (1 - positive_rate); float tp = cv_error(0) * positive_rate; // float tn = cv_error(1) * (1 - positive_rate); float fn = (1 - cv_error(0)) * positive_rate; float fp = (1 - cv_error(1)) * (1 - positive_rate); float dice = 2 * tp / (2 * tp + fn + fp); if (loss < best_loss) { best_loss = loss; best_gamma = gamma; best_svc = svc; } printf ("%3.6f %.3e %3.6f %3.6f %3.6f %3.6f\n", svc, gamma, cv_error(0), cv_error(1), loss, dice); } } if (parser->option("train-best")) { printf ("Training network with best parameters\n"); trainer.set_kernel (kernel_type (best_svc)); trainer.set_kernel (kernel_type (best_gamma)); dlib::decision_function best_network = trainer.train (dense_samples, labels); std::ofstream fout (parser->option("train-best").argument().c_str(), std::ios::binary); serialize (best_network, fout); fout.close(); } } static void svm_train ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { const std::string& kernel = get_kernel (parser); if (kernel == "lin") { svm_lin_test (parser, dense_samples, labels); } else if (kernel == "rbk") { svm_lin_test (parser, dense_samples, labels); } else { fprintf (stderr, "Unknown kernel type: %s\n", kernel.c_str()); exit (-1); } } static void svm_test ( dlib::Plm_clp* parser, std::vector& dense_samples, std::vector& labels ) { /* Load the network */ typedef dlib::radial_basis_kernel kernel_type; dlib::svm_c_trainer trainer; dlib::decision_function best_network; std::ifstream fin (parser->option("input-net").argument().c_str(), std::ios::binary); deserialize (best_network, fin); size_t tp = 0, fp = 0, fn = 0, tn = 0; for (size_t j = 0; j < dense_samples.size(); j++) { if (best_network(dense_samples[j]) > 0) { if (labels[j] > 0) { tp ++; } else { fp ++; } } else { if (labels[j] > 0) { fn ++; } else { tn ++; } } } printf ("Testing result: TP=%d TN=%d FP=%d FN=%d Loss=%f Dice=%f\n", (int) tp, (int) tn, (int) fp, (int) fn, (fp + fn) / (float) (fp + fn + tp + tn), (2 * tp) / (float) (2 * tp + fp + fn)); } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: dlib_test [options]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Dlib_test_parms *parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); // Algorithm-independent options parser->add_long_option ("", "learning-algorithm", "choose the learning algorithm: {krls,krr,mlp,svr}", 1, ""); parser->add_long_option ("", "learning-kernel", "Learning kernel (for krls,krr,svr methods): {lin,rbk}", 1, ""); parser->add_long_option ("", "input", "A libsvm-formatted file to test", 1, ""); parser->add_long_option ("", "input-net", "Test a pre-existing network", 1, ""); parser->add_long_option ("", "normalize", "Normalize the sample inputs to zero-mean unit variance?", 0); parser->add_long_option ("", "subsample", "limit size of training set to this number: {int}", 1, ""); parser->add_long_option ("", "train-best", "Train and save a network using best parameters", 1, ""); // Algorithm-specific options parser->add_long_option ("", "rbk-gamma", "Width of radial basis kernels: {float}.", 1, ""); parser->add_long_option ("", "krls-tolerance", "Numerical tolerance of krls linear dependency test: {float}.", 1, ""); parser->add_long_option ("", "mlp-hidden-units", "Number of hidden units in mlp: {integer}.", 1, ""); parser->add_long_option ("", "mlp-num-iterations", "Number of epochs to train the mlp: {integer}.", 1, ""); parser->add_long_option ("", "sv-c", "SV regularization parameter \"C\": {float}.", 1, ""); parser->add_long_option ("", "svr-epsilon-insensitivity", "SVR fitting tolerance parameter: {float}.", 1, ""); parser->add_long_option ("", "verbose", "Use verbose trainers", 0); // Parse the command line arguments parser->parse(argc,argv); /* Handle --help, --version */ parser->check_default_options (); // Check that an input file was given if (!parser->option("input")) { throw (dlib::error ( "Error. You must specify an input " "file with the --in option.")); } /* DO THE TEST */ std::string learning_algorithm = parser->get_string ("learning-algorithm"); std::string input_data = parser->get_string ("input"); std::string input_net = parser->get_string ("input-net"); std::vector sparse_samples; std::vector labels; /* Load the data */ dlib::load_libsvm_or_vw_data ( input_data, sparse_samples, labels ); std::cout << "Loaded " << sparse_samples.size() << " samples" << std::endl << "First sample " << labels[0] << " | " << sparse_samples[0][1] << " " << sparse_samples[0][2] << " ...\n"; /* Randomize the order of the samples, labels */ dlib::randomize_samples (sparse_samples, labels); /* Take a subset */ if (parser->option ("subsample")) { int num_subsamples = parser->get_int ("subsample"); int original_size = sparse_samples.size(); if (num_subsamples < original_size) { sparse_samples.resize (num_subsamples); labels.resize (num_subsamples); } } /* Remove empty feature */ dlib::fix_nonzero_indexing (sparse_samples); if (sparse_samples.size() < 1) { std::cout << "Sorry, I couldn't find any samples in your data set.\n" << "Aborting the operation.\n"; exit (0); } /* Convert sparse to dense */ std::vector dense_samples; dense_samples = dlib::sparse_to_dense (sparse_samples); std::cout << "Each sample has size " << dense_samples[0].nr() << std::endl; /* Normalize inputs to N(0,1) */ if (parser->option ("normalize")) { dlib::vector_normalizer normalizer; normalizer.train (dense_samples); for (unsigned long i = 0; i < dense_samples.size(); ++i) { dense_samples[i] = normalizer (dense_samples[i]); } } /* Handle the case where we are testing, and not training */ if (input_net != "") { if (learning_algorithm == "svm") { svm_test (parser, dense_samples, labels); } } else { if (learning_algorithm == "") { // Do KRR if user didn't specify an algorithm std::cout << "No algorithm specified, default to KRR\n"; krr_test (parser, dense_samples, labels); } else if (learning_algorithm == "krls") { krls_test (parser, dense_samples, labels); } else if (learning_algorithm == "krr") { krr_test (parser, dense_samples, labels); } else if (learning_algorithm == "mlp") { mlp_test (parser, dense_samples, labels); } else if (learning_algorithm == "svr") { svr_test (parser, dense_samples, labels); } else if (learning_algorithm == "svm") { svm_train (parser, dense_samples, labels); } else { fprintf (stderr, "Error, algorithm \"%s\" is unknown.\n" "Please use -h to see the command line options\n", learning_algorithm.c_str()); exit (-1); } } } int main (int argc, char* argv[]) { Dlib_test_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 0); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/drr_main.cxx000077500000000000000000000150131321604176500312710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #if (OPENMP_FOUND) #include #endif #include "delayload.h" #include "drr.h" #include "drr_cuda.h" #include "drr_opencl.h" #include "drr_opts.h" #include "mha_io.h" #include "plm_math.h" #include "plm_timer.h" #include "proj_image.h" #include "proj_matrix.h" #include "ray_trace.h" #include "string_util.h" #include "threading.h" #include "volume.h" static void* allocate_gpu_memory ( Proj_image *proj, Volume *vol, Drr_options *options ) { #if CUDA_FOUND || OPENCL_FOUND void* tmp; #endif switch (options->threading) { #if CUDA_FOUND case THREADING_CUDA: { LOAD_LIBRARY_SAFE (libplmreconstructcuda); LOAD_SYMBOL (drr_cuda_state_create, libplmreconstructcuda); tmp = drr_cuda_state_create (proj, vol, options); UNLOAD_LIBRARY (libplmreconstructcuda); return tmp; } #endif #if OPENCL_FOUND case THREADING_OPENCL: tmp = drr_opencl_state_create (proj, vol, options); return tmp; #endif case THREADING_CPU_SINGLE: case THREADING_CPU_OPENMP: default: return 0; } } static void free_gpu_memory ( void *dev_state, Drr_options *options ) { switch (options->threading) { #if CUDA_FOUND case THREADING_CUDA: { LOAD_LIBRARY_SAFE (libplmreconstructcuda); LOAD_SYMBOL (drr_cuda_state_destroy, libplmreconstructcuda); if (dev_state) { drr_cuda_state_destroy (dev_state); } UNLOAD_LIBRARY (libplmreconstructcuda); return; } #endif #if OPENCL_FOUND case THREADING_OPENCL: if (dev_state) { drr_opencl_state_destroy (dev_state); } return; #endif case THREADING_CPU_SINGLE: case THREADING_CPU_OPENMP: default: return; } } static void create_matrix_and_drr ( Volume* vol, Proj_image *proj, double cam[3], double tgt[3], double nrm[3], int a, void *dev_state, Drr_options* options ) { char mat_fn[256]; char img_fn[256]; std::string details_fn; Proj_matrix *pmat = proj->pmat; double vup[3] = { options->vup[0], options->vup[1], options->vup[2] }; double sid = options->sid; Plm_timer* timer = new Plm_timer; /* Set ic = image center (in pixels), and ps = pixel size (in mm) Note: pixels are numbered from 0 to ires-1 */ double ic[2] = { options->image_center[0], options->image_center[1] }; /* Set image resolution */ plm_long ires[2] = { options->image_resolution[0], options->image_resolution[1] }; /* Set physical size of imager in mm */ float isize[2]; isize[0] = options->image_size[0]; isize[1] = options->image_size[1]; /* Set pixel size in mm */ double ps[2] = { (double)isize[0]/(double)ires[0], (double)isize[1]/(double)ires[1] }; /* Create projection matrix */ sprintf (mat_fn, "%s%04d.txt", options->output_prefix, a); pmat->set (cam, tgt, vup, sid, ic, ps); if (options->output_format == OUTPUT_FORMAT_PFM) { sprintf (img_fn, "%s%04d.pfm", options->output_prefix, a); } else if (options->output_format == OUTPUT_FORMAT_PGM) { sprintf (img_fn, "%s%04d.pgm", options->output_prefix, a); } else { sprintf (img_fn, "%s%04d.raw", options->output_prefix, a); } if (options->output_details_prefix != "") { options->output_details_fn = string_format ("%s%04d.txt", options->output_details_prefix.c_str(), a); } if (options->geometry_only) { proj->save (0, mat_fn); } else { drr_render_volume_perspective (proj, vol, ps, dev_state, options); timer->start (); proj->save (img_fn, mat_fn); printf ("I/O time: %f sec\n", timer->report ()); } delete timer; } /* All distances in mm */ void drr_render_volume (Volume* vol, Drr_options* options) { Proj_image *proj; int a; void *dev_state = 0; /* tgt is isocenter */ double tgt[3] = { options->isocenter[0], options->isocenter[1], options->isocenter[2] }; Plm_timer* timer = new Plm_timer; timer->start (); /* Allocate data for image and matrix */ proj = new Proj_image; proj_image_create_pmat (proj); proj_image_create_img (proj, options->image_resolution); /* Allocate memory on the gpu device */ dev_state = allocate_gpu_memory (proj, vol, options); /* If nrm was specified, only create a single image */ if (options->have_nrm) { double cam[3]; double nrm[3] = { options->nrm[0], options->nrm[1], options->nrm[2] }; /* Make sure nrm is normal */ vec3_normalize1 (nrm); /* Place camera at distance "sad" from the volume isocenter */ cam[0] = tgt[0] + options->sad * nrm[0]; cam[1] = tgt[1] + options->sad * nrm[1]; cam[2] = tgt[2] + options->sad * nrm[2]; create_matrix_and_drr (vol, proj, cam, tgt, nrm, 0, dev_state, options); } /* Otherwise, loop through camera angles */ else { for (a = 0; a < options->num_angles; a++) { double angle = options->start_angle + a * options->angle_diff; double cam[3]; double nrm[3]; printf ("Rendering DRR %d\n", a); /* Place camera at distance "sad" from the volume isocenter */ cam[0] = tgt[0] + options->sad * cos(angle); cam[1] = tgt[1] - options->sad * sin(angle); cam[2] = tgt[2]; /* Compute normal vector */ vec3_sub3 (nrm, tgt, cam); vec3_normalize1 (nrm); create_matrix_and_drr (vol, proj, cam, tgt, nrm, a, dev_state, options); } } delete proj; free_gpu_memory (dev_state, options); printf ("Total time: %g secs\n", timer->report ()); delete timer; } void set_isocenter (Volume* vol, Drr_options* options) { vol->origin[0] -= options->isocenter[0]; vol->origin[1] -= options->isocenter[1]; vol->origin[2] -= options->isocenter[2]; } int main (int argc, char* argv[]) { Volume* vol = 0; Drr_options options; parse_args (&options, argc, argv); if (options.geometry_only) { options.threading = THREADING_CPU_SINGLE; } else { vol = read_mha (options.input_file); if (!vol) return -1; volume_convert_to_float (vol); } if (options.hu_conversion == PREPROCESS_CONVERSION && !options.geometry_only) { drr_preprocess_attenuation (vol); } drr_render_volume (vol, &options); if (!options.geometry_only) { delete vol; } printf ("Done.\n"); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/drr_opts.cxx000066400000000000000000000243371321604176500313400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "drr.h" #include "drr_opts.h" #include "plm_math.h" #include "threading.h" void print_usage (void) { printf ( "Usage: drr [options] [infile]\n" "Options:\n" " -A hardware Either \"cpu\" or \"cuda\" (default=cpu)\n" " -y angle Gantry angle for source\n" " -a num Generate num equally spaced angles\n" " -N angle Difference between neighboring angles (in degrees)\n" " -nrm \"x y z\" Set the normal vector for the panel\n" " -vup \"x y z\" Set the vup vector (toward top row) for the panel\n" " -g \"sad sid\" Set the sad, sid (in mm)\n" " -r \"r c\" Set output resolution (in pixels)\n" " -s scale Scale the intensity of the output file\n" " -e Do exponential mapping of output values\n" " -c \"r c\" Set the image center (in pixels)\n" " -z \"s1 s2\" Set the physical size of imager (in mm)\n" " -w \"r1 r2 c1 c2\" Only produce image for pixes in window (in pix)\n" " -t outformat Select output format: pgm, pfm or raw\n" " -S outprefix Output ray tracing details\n" //" -S Output multispectral output files\n" //" -i algorithm Choose algorithm {exact,uniform,tri_exact,tri_approx}\n" " -i algorithm Choose algorithm {exact,uniform}\n" " -o \"o1 o2 o3\" Set isocenter position\n" " -G Create geometry files only, not drr images.\n" " -P conversion Choose HU conversion type {preprocess,inline,none}\n" " -I infile Set the input file in mha format\n" " -O outprefix Generate output files using the specified prefix\n" ); exit (1); } void drr_opts_init (Drr_options* options) { options->threading = THREADING_CPU_OPENMP; options->image_resolution[0] = 128; options->image_resolution[1] = 128; options->image_size[0] = 600; options->image_size[1] = 600; options->have_image_center = 0; options->have_image_window = 0; options->isocenter[0] = 0.0f; options->isocenter[1] = 0.0f; options->isocenter[2] = 0.0f; options->start_angle = 0.f; options->num_angles = 1; options->have_angle_diff = 0; options->angle_diff = 1.0f; options->have_nrm = 0; options->nrm[0] = 1.0f; options->nrm[1] = 0.0f; options->nrm[2] = 0.0f; options->vup[0] = 0.0f; options->vup[1] = 0.0f; options->vup[2] = 1.0f; options->sad = 1000.0f; options->sid = 1630.0f; options->scale = 1.0f; options->exponential_mapping = 0; options->output_format= OUTPUT_FORMAT_PFM; options->hu_conversion = PREPROCESS_CONVERSION; options->output_details_prefix = ""; options->output_details_fn = ""; options->algorithm = DRR_ALGORITHM_EXACT; options->input_file = 0; options->geometry_only = 0; options->output_prefix = "out_"; } void set_image_parms (Drr_options* options) { if (!options->have_image_center) { options->image_center[0] = (options->image_resolution[0]-1)/2.0; options->image_center[1] = (options->image_resolution[1]-1)/2.0; } if (!options->have_image_window) { options->image_window[0] = 0; options->image_window[1] = options->image_resolution[1] - 1; options->image_window[2] = 0; options->image_window[3] = options->image_resolution[0] - 1; } if (options->have_angle_diff) { options->angle_diff *= (float) (M_TWOPI / 360.0); } else { options->angle_diff = M_TWOPI / options->num_angles; } } void parse_args (Drr_options* options, int argc, char* argv[]) { int i, rc; drr_opts_init (options); for (i = 1; i < argc; i++) { //printf ("ARG[%d] = %s\n", i, argv[i]); if (argv[i][0] != '-') break; if (!strcmp (argv[i], "-A")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } if (++i >= argc) { print_usage(); } #if CUDA_FOUND if (!strcmp(argv[i], "cuda") || !strcmp(argv[i], "CUDA") || !strcmp(argv[i], "gpu") || !strcmp(argv[i], "GPU")) { options->threading = THREADING_CUDA; continue; } #endif #if OPENCL_FOUND if (!strcmp(argv[i], "opencl") || !strcmp(argv[i], "OPENCL") || !strcmp(argv[i], "gpu") || !strcmp(argv[i], "GPU")) { options->threading = THREADING_OPENCL; continue; } #endif /* Default */ options->threading = THREADING_CPU_OPENMP; } else if (!strcmp (argv[i], "-r")) { /* Note: user inputs row, then column. But internally they are stored as column, then row. */ if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%d %d", &options->image_resolution[1], &options->image_resolution[0]); if (rc == 1) { options->image_resolution[0] = options->image_resolution[1]; } else if (rc != 2) { print_usage (); } } else if (!strcmp (argv[i], "-I")) { if (++i >= argc) { print_usage(); } options->input_file = strdup (argv[i]); } else if (!strcmp (argv[i], "-O")) { if (++i >= argc) { print_usage(); } options->output_prefix = strdup (argv[i]); } else if (!strcmp (argv[i], "-y")) { if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%g" , &options->start_angle); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-a")) { if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%d" , &options->num_angles); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-N")) { if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%g" , &options->angle_diff); if (rc != 1) { print_usage (); } options->have_angle_diff = 1; } else if (!strcmp (argv[i], "-nrm")) { if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%f %f %f", &options->nrm[0], &options->nrm[1], &options->nrm[2]); if (rc != 3) { print_usage (); } options->have_nrm = 1; } else if (!strcmp (argv[i], "-vup")) { if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%f %f %f", &options->vup[0], &options->vup[1], &options->vup[2]); if (rc != 3) { print_usage (); } } else if (!strcmp (argv[i], "-s")) { if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%g" , &options->scale); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-t")) { if (++i >= argc) { print_usage(); } if (!strcmp (argv[i], "pfm")) { options->output_format = OUTPUT_FORMAT_PFM; } else if (!strcmp (argv[i], "pgm")) { options->output_format = OUTPUT_FORMAT_PGM; } else if (!strcmp (argv[i], "raw")) { options->output_format = OUTPUT_FORMAT_RAW; } else { print_usage (); } } else if (!strcmp (argv[i], "-c")) { /* Note: user inputs row, then column. But internally they are stored as column, then row. */ if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%g %g", &options->image_center[1], &options->image_center[0]); if (rc == 1) { options->image_center[0] = options->image_center[1]; } else if (rc != 2) { print_usage (); } options->have_image_center = 1; } else if (!strcmp (argv[i], "-z")) { /* Note: user inputs row, then column. But internally they are stored as column, then row. */ if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%g %g", &options->image_size[1], &options->image_size[0]); if (rc == 1) { options->image_size[0] = options->image_size[1]; } else if (rc != 2) { print_usage (); } } else if (!strcmp (argv[i], "-g")) { if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%g %g", &options->sad, &options->sid); if (rc != 2) { print_usage (); } } else if (!strcmp (argv[i], "-w")) { /* Note: user inputs row start, row end, column start, column end */ if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%d %d %d %d", &options->image_window[0], &options->image_window[1], &options->image_window[2], &options->image_window[3]); if (rc == 2) { options->image_window[2] = options->image_window[0]; options->image_window[3] = options->image_window[1]; } else if (rc != 4) { print_usage (); } options->have_image_window = 1; } else if (!strcmp (argv[i], "-i")) { if (++i >= argc) { print_usage(); } if (!strcmp(argv[i], "exact")) { options->algorithm = DRR_ALGORITHM_EXACT; } else if (!strcmp(argv[i], "tri_exact")) { options->algorithm = DRR_ALGORITHM_TRILINEAR_EXACT; } else if (!strcmp(argv[i], "tri_approx")) { options->algorithm = DRR_ALGORITHM_TRILINEAR_APPROX; } else if (!strcmp(argv[i], "uniform")) { options->algorithm = DRR_ALGORITHM_UNIFORM; } else { print_usage (); } } else if (!strcmp (argv[i], "-o")) { if (++i >= argc) { print_usage(); } rc = sscanf (argv[i], "%g %g %g" , &options->isocenter[0], &options->isocenter[1], &options->isocenter[2]); if (rc != 3) { print_usage (); } } else if (!strcmp (argv[i], "-S")) { if (++i >= argc) { print_usage(); } options->output_details_prefix = argv[i]; } else if (!strcmp (argv[i], "-e")) { options->exponential_mapping = 1; } else if (!strcmp (argv[i], "-G")) { options->geometry_only = 1; } else if (!strcmp (argv[i], "-P")) { if (++i >= argc) { print_usage(); } if (!strcmp(argv[i], "preprocess")) { options->hu_conversion = PREPROCESS_CONVERSION; } else if (!strcmp(argv[i], "inline")) { options->hu_conversion = INLINE_CONVERSION; } else if (!strcmp(argv[i], "none")) { options->hu_conversion = NO_CONVERSION; } else { printf ("Error, unknown option -P %s\n", argv[i]); print_usage (); } } else { printf ("Error, unknown option %s\n", argv[i]); print_usage (); break; } } if (!options->input_file) { if (i < argc) { options->input_file = strdup (argv[i++]); } } if (i < argc) { print_usage (); } if (!options->input_file && !options->geometry_only) { print_usage (); } set_image_parms (options); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/drr_opts.h000066400000000000000000000005531321604176500307570ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _drr_opts_h_ #define _drr_opts_h_ class Drr_options; void parse_args (Drr_options* options, int argc, char* argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/fdk_main.cxx000066400000000000000000000046471321604176500312560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #if OPENMP_FOUND #include #endif #include "delayload.h" #include "fdk.h" #include "fdk_opts.h" #include "fdk_cuda.h" #include "fdk_opencl.h" #include "fdk_util.h" #include "mha_io.h" #include "plm_math.h" #include "print_and_exit.h" #include "proj_image_dir.h" #include "threading.h" #include "volume.h" int main (int argc, char* argv[]) { Fdk_parms parms; Volume* vol; Proj_image_dir *proj_dir; // LOAD_LIBRARY (libplmopencl); // LOAD_SYMBOL (opencl_reconstruct_conebeam, libplmopencl); /* Parse command line arguments */ fdk_parse_args (&parms, argc, argv); /* Look for input files */ proj_dir = new Proj_image_dir (parms.input_dir); if (proj_dir->num_proj_images < 1) { print_and_exit ("Error: couldn't find input files in directory %s\n", parms.input_dir); } /* Set the panel offset */ double xy_offset[2] = { parms.xy_offset[0], parms.xy_offset[1] }; proj_dir->set_xy_offset (xy_offset); /* Choose subset of input files if requested */ if (parms.image_range_requested) { proj_dir->select (parms.first_img, parms.skip_img, parms.last_img); } /* Allocate memory */ vol = my_create_volume (&parms); printf ("Reconstructing...\n"); switch (parms.threading) { #if (CUDA_FOUND) case THREADING_CUDA: CUDA_reconstruct_conebeam (vol, proj_dir, &parms); break; #endif #if (OPENCL_FOUND) case THREADING_OPENCL: opencl_reconstruct_conebeam (vol, proj_dir, &parms); //OPENCL_reconstruct_conebeam_and_convert_to_hu (vol, proj_dir, &parms); break; #endif case THREADING_CPU_SINGLE: case THREADING_CPU_OPENMP: default: reconstruct_conebeam (vol, proj_dir, &parms); } /* Free memory */ delete proj_dir; /* Prepare HU values in output volume */ convert_to_hu (vol, &parms); /* Do bowtie filter corrections */ //fdk_do_bowtie (vol, &parms); /* Write output */ printf ("Writing output volume(s)...\n"); write_mha (parms.output_file, vol); /* Free memory */ delete vol; // UNLOAD_LIBRARY (libplmopencl); printf(" done.\n\n"); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/fdk_opts.cxx000066400000000000000000000140221321604176500313030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "fdk.h" #include "fdk_opts.h" #include "threading.h" void print_usage (void) { printf ( "Usage: fdk [options]\n" "Options:\n" " -A hardware One of \"cpu\", \"cuda\" or \"opencl\" (default=cpu)\n" " -a \"num ((num) num)\" Use this range of images\n" " -r \"r1 r2 r3\" Set output resolution (in voxels)\n" " -f filter Either \"none\" or \"ramp\" (default=ramp)\n" " -s scale Scale the intensity of the output file\n" " -z \"s1 s2 s3\" Physical size of the reconstruction (in mm)\n" " -I indir The input directory\n" " -O outfile The output file\n" " -x \"x0 y0\" Panel offset (in pixels)\n" " -X flavor Implementation flavor (0,a,b,c,d) (default=c)\n" ); exit (1); } void set_default_parms (Fdk_parms* parms) { parms->threading = THREADING_CPU_OPENMP; parms->image_range_requested = 0; parms->first_img = 0; parms->last_img = 119; parms->skip_img = 1; parms->dim[0] = 256; parms->dim[1] = 256; parms->dim[2] = 100; parms->vol_size[0] = 300.0f; parms->vol_size[1] = 300.0f; parms->vol_size[2] = 150.0f; parms->xy_offset[0] = 0.f; parms->xy_offset[1] = 0.f; parms->scale = 1.0f; parms->filter = FDK_FILTER_TYPE_RAMP; parms->input_dir = "."; parms->output_file = "output.mha"; parms->flavor = 'c'; parms->full_fan=1; parms->Full_normCBCT_name="Full_norm.mh5"; parms->Full_radius=120; parms->Half_normCBCT_name="Half_norm.mh5"; parms->Half_radius=220; } void fdk_parse_args (Fdk_parms* parms, int argc, char* argv[]) { int i, rc; if (argc < 2) { print_usage(); exit(1); } set_default_parms (parms); for (i = 1; i < argc; i++) { if (argv[i][0] != '-') break; if (!strcmp (argv[i], "-A")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; #if CUDA_FOUND if (!strcmp(argv[i], "cuda") || !strcmp(argv[i], "CUDA")) { parms->threading = THREADING_CUDA; continue; } #endif #if OPENCL_FOUND if (!strcmp(argv[i], "opencl") || !strcmp(argv[i], "OPENCL")) { parms->threading = THREADING_OPENCL; continue; } #endif /* Default */ parms->threading = THREADING_CPU_OPENMP; } else if (!strcmp (argv[i], "-a")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; parms->image_range_requested = 1; rc = sscanf (argv[i], "%d %d %d" , &parms->first_img, &parms->skip_img, &parms->last_img); if (rc == 1) { parms->last_img = parms->first_img; parms->skip_img = 1; } else if (rc == 2) { parms->last_img = parms->skip_img; parms->skip_img = 1; } else if (rc != 3) { print_usage (); } } else if (!strcmp (argv[i], "-f")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; if (!strcmp(argv[i], "none") || !strcmp(argv[i], "NONE")) { parms->filter = FDK_FILTER_TYPE_NONE; } else if (!strcmp(argv[i], "ramp") || !strcmp(argv[i], "RAMP")) { parms->filter = FDK_FILTER_TYPE_RAMP; } else { print_usage (); } } else if (!strcmp (argv[i], "-X")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; parms->flavor = argv[i][0]; if (parms->flavor != '0' && parms->flavor != 'a' && parms->flavor != 'b' && parms->flavor != 'c' && parms->flavor != 'd') { print_usage (); } } else if (!strcmp (argv[i], "-I")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; parms->input_dir = strdup (argv[i]); } else if (!strcmp (argv[i], "-O")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; parms->output_file = strdup (argv[i]); } else if (!strcmp (argv[i], "-r")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; unsigned int a, b, c; rc = sscanf (argv[i], "%d %d %d", &a, &b, &c); if (rc == 1) { parms->dim[0] = a; parms->dim[1] = a; parms->dim[2] = a; } else if (rc == 3) { parms->dim[0] = a; parms->dim[1] = b; parms->dim[2] = c; } else { print_usage (); } } else if (!strcmp (argv[i], "-s")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g" , &parms->scale); if (rc != 1) { print_usage (); } } else if (!strcmp (argv[i], "-x")) { i++; rc = sscanf (argv[i], "%f %f", &parms->xy_offset[0], &parms->xy_offset[1]); if (rc != 2) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } else { print_usage (); } } } else if (!strcmp (argv[i], "-z")) { if (i == (argc-1) || argv[i+1][0] == '-') { fprintf(stderr, "option %s requires an argument\n", argv[i]); exit(1); } i++; rc = sscanf (argv[i], "%g %g %g", &parms->vol_size[0], &parms->vol_size[1], &parms->vol_size[2]); if (rc == 1) { parms->vol_size[1] = parms->vol_size[0]; parms->vol_size[2] = parms->vol_size[0]; } else if (rc != 3) { print_usage (); } } else { print_usage (); } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/fdk_opts.h000066400000000000000000000014761321604176500307410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _fdk_opts_h_ #define _fdk_opts_h_ #include "plm_config.h" class Fdk_parms; #define OPTION_RESOLUTION_STRING "resolution" #define OPTION_RESOLUTION 'r' #define OPTION_INPUT_DIR_STRING "input-dir" #define OPTION_INPUT_DIR 'I' #define OPTION_OUTPUT_FILE_STRING "output-file" #define OPTION_OUTPUT_FILE 'O' #define OPTION_IMAGE_RANGE_STRING "image-range" #define OPTION_IMAGE_RANGE 'a' #define OPTION_SCALE_STRING "scale" #define OPTION_SCALE 's' #define OPTION_VOL_SIZE_STRING "volume-size" #define OPTION_VOL_SIZE 'z' void fdk_parse_args (Fdk_parms* parms, int argc, char* argv[]); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/filter.cxx000066400000000000000000000234131321604176500307630ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "aperture.h" #include "file_util.h" #include "plm_math.h" #include "print_and_exit.h" #include "proj_volume.h" #include "ray_trace_probe.h" #include "rpl_volume.h" #include "volume.h" #include "volume_limit.h" #include "wed_parms.h" //For sure #include "print_and_exit.h" #include #include "plm_image.h" #include "plm_image_header.h" #include "itkImageRegionIterator.h" #include "pcmd_synth.h" #include "pcmd_synth.cxx" #include "synthetic_mha.h" void resize_3d_vect(std::vector< std::vector< std::vector > > &input_vector, plm_long size[]) { input_vector.resize( size[0] ); for (int i=0;i!=size[0];++i) { input_vector[i].resize( size[1] ); for (int j=0;j!= size[1];++j) { input_vector[i][j].resize( size[2] ); for (int k=0;k!= size[2];++k) { input_vector[i][j][k]=0.; } } } } int main (int argc, char* argv[]) { if (argc != 4) { printf ("Usage: filter input_fn reference_fn output_fn\n"); exit (1); } #if defined (commentout) std::string Reference_FN = "s4mid.mha"; std::string Input_FN = "Drift_added_fromraw.mha"; std::string Output_FN = "Filtered_output.mha"; #endif std::string Reference_FN = argv[2]; std::string Input_FN = argv[1]; std::string Output_FN = argv[3]; if (!file_exists (Reference_FN)) { print_and_exit ("Cannot open %s for read\n", Reference_FN.c_str()); } if (!file_exists (Input_FN)) { print_and_exit ("Cannot open %s for read\n", Input_FN.c_str()); } typedef itk::ImageRegionIterator< FloatImageType > FloatIteratorType; Plm_image_header image_header; plm_long image_dim[3]; float spacing[3]; float origin[3]; Plm_image *input_image = new Plm_image(); std::vector< std::vector< std::vector > > input_vect, base_input_vect, ct_input_vect; input_image->load_native(Input_FN); image_header.set_from_plm_image(input_image); image_header.get_dim(image_dim); image_header.get_spacing(spacing); image_header.get_origin(origin); Synthetic_mha_main_parms output_parms; for (int i=0;i!=3;++i) { output_parms.sm_parms.dim[i] = image_dim[i]; output_parms.sm_parms.spacing[i] = spacing[i]; output_parms.sm_parms.origin[i] = origin[i]; output_parms.sm_parms.background = 0.; //set background to 0 for wed doses } output_parms.output_fn = Output_FN; do_synthetic_mha(&output_parms); std::cout<<"Empty file \""<m_itk_float; FloatImageType::RegionType rg = img->GetLargestPossibleRegion (); FloatIteratorType image_it (img, rg); resize_3d_vect(input_vect,image_dim); resize_3d_vect(base_input_vect,image_dim); int zz = 0; plm_long ijk[3]; for (image_it.GoToBegin(); !image_it.IsAtEnd(); ++image_it) { COORDS_FROM_INDEX(ijk,zz,image_dim); input_vect[ ijk[0] ][ ijk[1] ][ ijk[2] ] = image_it.Get(); base_input_vect[ ijk[0] ][ ijk[1] ][ ijk[2] ] = image_it.Get(); zz++; } /////////////////////////////////////////////////////// //CT Image//////////////////////////// Plm_image *ct_image = new Plm_image(); Plm_image_header ct_image_header; plm_long ct_image_dim[3]; float ct_spacing[3]; float ct_origin[3]; ct_image->load_native(Reference_FN); ct_image_header.set_from_plm_image(ct_image); ct_image_header.get_dim(ct_image_dim); ct_image_header.get_spacing(ct_spacing); ct_image_header.get_origin(ct_origin); Volume::Pointer ct_vol = ct_image->get_volume_float(); float* ct_img = (float*) ct_vol->img; // std::cout<<"origin "<m_itk_float; FloatImageType::RegionType ct_rg = ct_img->GetLargestPossibleRegion (); FloatIteratorType ct_image_it (ct_img, ct_rg); */ resize_3d_vect(ct_input_vect,ct_image_dim); int ct_vol_max = ct_image_dim[0]*ct_image_dim[1]*ct_image_dim[2]; for (int i=0; i!=ct_vol_max;++i) { COORDS_FROM_INDEX(ijk,i,ct_image_dim); ct_input_vect[ ijk[0] ][ ijk[1] ][ ijk[2] ] = ct_img[i]; } float x_low,x_high,y_low,y_high,z_low,z_high; int x_low2,x_high2,y_low2,y_high2,z_low2,z_high2; for (int i=0; i!=ct_image_dim[0]; ++i) { for (int j=0; j!=ct_image_dim[1]; ++j) { for (int k=0; k!=ct_image_dim[2]; ++k) { x_low = ct_origin[0] + (i-.5)*ct_spacing[0]; x_high = x_low+ct_spacing[0]; y_low = ct_origin[1] + (j-.5)*ct_spacing[1]; y_high = y_low+ct_spacing[1]; z_low = ct_origin[2] + (k-.5)*ct_spacing[2]; z_high = z_low+ct_spacing[2]; x_low2 = (int) floor((x_low-origin[0])/spacing[0]+.5); x_high2 = (int) floor((x_high-origin[0])/spacing[0]+.5); y_low2 = (int) floor((y_low-origin[1])/spacing[1]+.5); y_high2 = (int) floor((y_high-origin[1])/spacing[1]+.5); z_low2 = (int) floor((z_low-origin[2])/spacing[2]+.5); z_high2 = (int) floor((z_high-origin[2])/spacing[2]+.5); for (int ii=x_low2; ii<=x_high2; ++ii) { for (int jj=y_low2; jj<=y_high2; ++jj) { for (int kk=z_low2; kk<=z_high2; ++kk) { float unit = 1.; //fraction of the input voxel in each added cell: //additions from group_add - now we have to allow for the possibility of the //input have smaller voxels. In group add, the inputs were guaranteed to //have the same same size or larger. if (x_low2==x_high2) { unit *= ( (1 - ((x_low-origin[0])/spacing[0]+.5 - x_low2)) - (x_high2 - (x_high-origin[0])/spacing[0]+.5) ); } else { if (ii==x_low2) {unit *= (1 - ((x_low-origin[0])/spacing[0]+.5 - x_low2));} if (ii==x_high2) {unit *= ((x_high-origin[0])/spacing[0]+.5 - x_high2);} } if (y_low2==y_high2) { unit *= ( (1 - ((y_low-origin[1])/spacing[1]+.5 - y_low2)) - (y_high2 - (y_high-origin[1])/spacing[1]+.5) ); } else { if (jj==y_low2) {unit *= (1 - ((y_low-origin[1])/spacing[1]+.5 - y_low2));} if (jj==y_high2) {unit *= ((y_high-origin[1])/spacing[1]+.5 - y_high2);} } if (z_low2==z_high2) { unit *= ( (1 - ((z_low-origin[2])/spacing[2]+.5 - z_low2)) - (z_high2 - (z_high-origin[2])/spacing[2]+.5) ); } else { if (kk==z_low2) {unit *= (1 - ((z_low-origin[2])/spacing[2]+.5 - z_low2));} if (kk==z_high2) {unit *= ((z_high-origin[2])/spacing[2]+.5 - z_high2);} } // if ((x_low2<0)||(y_low2<0)||(z_low2<0)||(x_high2>=image_dim[0])||(y_high2>=image_dim[1])||(z_high2>=image_dim[2])) {continue;} if ((ii<0)||(jj<0)||(kk<0)||(ii>=image_dim[0])||(jj>=image_dim[1])||(kk>=image_dim[2])) {continue;} if (ct_input_vect[i][j][k]==-1000) {input_vect[ii][jj][kk]-=base_input_vect[ii][jj][kk]*unit;} } } } } } } //Option to include full dose on any voxel that is partially in air (no interpolation): for (unsigned i=0; i!=base_input_vect.size(); ++i) { for (unsigned j=0; j!=base_input_vect[0].size(); ++j) { for (unsigned k=0; k!=base_input_vect[0][0].size(); ++k) { //If the "filtered" value is less than the original, but still greater than 0, keep the original value. if ((input_vect[i][j][k] < base_input_vect[i][j][k])&&(input_vect[i][j][k] > .001*base_input_vect[i][j][k])) { // std::cout<load_native(Output_FN); FloatImageType::Pointer img_out = output_image->m_itk_float; FloatImageType::RegionType rg_out = img_out->GetLargestPossibleRegion (); FloatIteratorType image_out_it (img_out, rg_out); zz = 0; for (image_out_it.GoToBegin(); !image_out_it.IsAtEnd(); ++image_out_it) { COORDS_FROM_INDEX(ijk,zz,image_dim); image_out_it.Set( input_vect[ ijk[0] ][ ijk[1] ][ ijk[2] ] ); zz++; } itk_image_save_float (img_out, Output_FN.c_str()); delete output_image; delete input_image; return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/gamma_gui.cpp000066400000000000000000003462761321604176500314230ustar00rootroot00000000000000#include "gamma_gui.h" #include #include #include #include #include #include "YK16GrayImage.h" #include "plm_image.h" #include "rt_study_metadata.h" #include "gamma_dose_comparison.h" #include #include "logfile.h" #include "pcmd_gamma.h" #include "print_and_exit.h" #include "plm_file_format.h" #include "rt_study.h" #include "qt_util.h" #include #include #include "dcmtk_rt_study.h" #include "dcmtk_rt_study_p.h" #include "dcmtk_series.h" #include "dcmtk_config.h" #include "dcmtk/dcmdata/dctagkey.h" #include "dcmtk/dcmdata/dcsequen.h" #include "dcmtk/dcmdata/dcitem.h" #include "dcmtk/dcmdata/dcdeftag.h" #include #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkImageSliceIteratorWithIndex.h" #include "itkFlipImageFilter.h" gamma_gui::gamma_gui(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { ui.setupUi(this); m_pCurImageRef = new YK16GrayImage(); m_pCurImageComp = new YK16GrayImage(); m_pCurImageGamma3D = new YK16GrayImage(); m_pCurImageGamma2D = new YK16GrayImage(); //QUTIL::LoadColorTableFromFile("colormap_jet.txt", m_vColormapDose); //QUTIL::LoadColorTableFromFile("colormap_customgamma.txt", m_vColormapGamma); QUTIL::LoadColorTableInternal(m_vColormapDose, COL_TABLE_JET); QUTIL::LoadColorTableInternal(m_vColormapGamma, COL_TABLE_GAMMA); m_pCurImageRef->SetColorTable(m_vColormapDose); m_pCurImageComp->SetColorTable(m_vColormapDose); m_pCurImageGamma3D->SetColorTable(m_vColormapGamma); //m_pCurImageGamma3D->SetColorTable(m_vColormapGammaLow); m_pCurImageGamma2D->SetColorTable(m_vColormapGamma); //m_pCurImageGamma2D->SetColorTableGammaHigh(m_vColormapGammaLow); connect(ui.labelReferDose, SIGNAL(Mouse_Pressed_Left()), this, SLOT(SLT_UpdateProbePosRef())); //added connect(ui.labelCompDose, SIGNAL(Mouse_Pressed_Left()), this, SLOT(SLT_UpdateProbePosComp())); //added connect(ui.labelGammaMap2D, SIGNAL(Mouse_Pressed_Left()), this, SLOT(SLT_UpdateProbePosGamma2D())); //added connect(ui.labelGammaMap3D, SIGNAL(Mouse_Pressed_Left()), this, SLOT(SLT_UpdateProbePosGamma3D())); //added connect(ui.labelReferDose, SIGNAL(Mouse_Left_DoubleClick()), this, SLOT(SLT_GoCenterPosRef())); //added connect(ui.labelCompDose, SIGNAL(Mouse_Left_DoubleClick()), this, SLOT(SLT_GoCenterPosComp())); //added connect(ui.labelReferDose, SIGNAL(Mouse_Wheel()), this, SLOT(SLT_MouseWheelUpdateRef())); //added connect(ui.labelCompDose, SIGNAL(Mouse_Wheel()), this, SLOT(SLT_MouseWheelUpdateComp())); //added connect(ui.labelGammaMap2D, SIGNAL(Mouse_Wheel()), this, SLOT(SLT_MouseWheelUpdateGamma2D())); //added connect(ui.labelGammaMap3D, SIGNAL(Mouse_Wheel()), this, SLOT(SLT_MouseWheelUpdateGamma3D())); //added connect(ui.labelReferDose, SIGNAL(Mouse_Move()), this, SLOT(SLT_UpdatePanSettingRef())); //added connect(ui.labelCompDose, SIGNAL(Mouse_Move()), this, SLOT(SLT_UpdatePanSettingComp())); //added connect(ui.labelGammaMap3D, SIGNAL(Mouse_Move()), this, SLOT(SLT_UpdatePanSettingGamma3D())); //added connect(ui.labelGammaMap2D, SIGNAL(Mouse_Move()), this, SLOT(SLT_UpdatePanSettingGamma2D())); //added connect(ui.labelReferDose, SIGNAL(Mouse_Pressed_Right()), this, SLOT(SLT_MousePressedRightRef())); //added connect(ui.labelCompDose, SIGNAL(Mouse_Pressed_Right()), this, SLOT(SLT_MousePressedRightComp())); //added connect(ui.labelGammaMap3D, SIGNAL(Mouse_Pressed_Right()), this, SLOT(SLT_MousePressedRightGamma3D())); //added connect(ui.labelGammaMap2D, SIGNAL(Mouse_Pressed_Right()), this, SLOT(SLT_MousePressedRightGamma2D())); //added connect(ui.labelReferDose, SIGNAL(Mouse_Released_Right()), this, SLOT(SLT_MouseReleasedRightRef())); //added connect(ui.labelCompDose, SIGNAL(Mouse_Released_Right()), this, SLOT(SLT_MouseReleasedRightComp())); //added connect(ui.labelGammaMap3D, SIGNAL(Mouse_Released_Right()), this, SLOT(SLT_MouseReleasedRightGamma3D())); //added connect(ui.labelGammaMap2D, SIGNAL(Mouse_Released_Right()), this, SLOT(SLT_MouseReleasedRightGamma2D())); //added if (m_vColormapDose.size() < 1 || m_vColormapGamma.size() < 1) { cout << "Fatal error!: colormap is not ready. Colormap table should be checked." << endl; } m_pTableModel = NULL; m_bGamma2DIsDone = false; m_bMousePressedRightRef = false; m_bMousePressedRightComp = false; m_bMousePressedRightGamma3D = false; m_bMousePressedRightGamma2D = false; QUTIL::CreateItkDummyImg(m_spDummyLowMemImg, 10, 10, 10, 1.0); m_iLastLoadedIndex = -1; } gamma_gui::~gamma_gui() { //delete m_pImgOffset; //delete m_pImgGain; //m_vPixelReplMap.clear(); //not necessary //delete m_pView; m_vRefDoseImages.clear(); m_vCompDoseImages.clear(); m_vGammaMapImages.clear(); delete m_pCurImageRef; delete m_pCurImageComp; delete m_pCurImageGamma3D; delete m_pCurImageGamma2D; if (m_pTableModel != NULL) { delete m_pTableModel; m_pTableModel = NULL; } } void gamma_gui::SLT_Load_RD_Ref() { QStringList tmpList = QFileDialog::getOpenFileNames(this, "Select one or more files to open", m_strPathInputDir, "3D dose file (*.dcm *.mha)"); int iFileCnt = tmpList.size(); if (iFileCnt < 1) return; ui.plainTextEdit_RD_Ref->clear(); m_strlistPath_RD_Original_Ref.clear(); m_strlistFileBaseName_Ref.clear(); m_strlistPath_RD_Original_Ref = tmpList; for (int i = 0; i < iFileCnt; i++) { ui.plainTextEdit_RD_Ref->appendPlainText(m_strlistPath_RD_Original_Ref.at(i)); //just for display QFileInfo tmpInfo = QFileInfo(m_strlistPath_RD_Original_Ref.at(i)); m_strlistFileBaseName_Ref.push_back(tmpInfo.completeBaseName()); } QFileInfo finfo(m_strlistPath_RD_Original_Ref.at(0)); QDir crntDir = finfo.absoluteDir(); m_strPathInputDir = crntDir.absolutePath(); } void gamma_gui::SLT_Load_RD_Comp() { QStringList tmpList = QFileDialog::getOpenFileNames(this, "Select one or more files to open", m_strPathInputDir, "3D dose file (*.dcm *.mha)"); int iFileCnt = tmpList.size(); if (iFileCnt < 1) return; ui.plainTextEdit_RD_Comp->clear(); m_strlistPath_RD_Original_Comp.clear(); m_strlistFileBaseName_Comp.clear(); m_strlistPath_RD_Original_Comp = tmpList; for (int i = 0; i < iFileCnt; i++) { ui.plainTextEdit_RD_Comp->appendPlainText(m_strlistPath_RD_Original_Comp.at(i)); //just for display QFileInfo tmpInfo = QFileInfo(m_strlistPath_RD_Original_Comp.at(i)); m_strlistFileBaseName_Comp.push_back(tmpInfo.completeBaseName()); } QFileInfo finfo(m_strlistPath_RD_Original_Comp.at(0)); QDir crntDir = finfo.absoluteDir(); m_strPathInputDir = crntDir.absolutePath(); } void gamma_gui::SLT_RunBatchGamma() { //number of batch should be matched int cntRef = m_strlistPath_RD_Original_Ref.count(); int cntComp = m_strlistPath_RD_Original_Comp.count(); QDir tmpCheckDir(m_strPathDirWorkDir); if (m_strPathDirWorkDir.isEmpty()) { QUTIL::ShowErrorMessage("Error! No work space is specified. Set it first."); return; } if (!tmpCheckDir.exists()) { QUTIL::ShowErrorMessage("Error! Current work space doesn't exist. Set it again"); return; } if (cntRef*cntComp == 0 || cntRef != cntComp) { cout << "ERROR! Invalid input file counts" << endl; return; } //Check the working directory. Subfolders..This should have no relavant subdirectories QString strParamSet; strParamSet.sprintf("_%dmm_%dp", ui.lineEdit_dta_tol->text().toInt(), ui.lineEdit_dose_tol->text().toInt()); float fResmp = ui.lineEdit_inhereResample->text().toFloat(); if (fResmp > 0 && ui.checkBox_inhereResample->isChecked()) strParamSet = strParamSet + "_rsmp" + QString::number(fResmp, 'd', 0); if (ui.checkBox_Interp_search->isChecked()) strParamSet = strParamSet + "_interp"; QString timeStamp = QUTIL::GetTimeStampDirName(); QString strSubRef = "DoseRef_" + timeStamp; QString strSubComp = "DoseComp_"+ timeStamp; QString strSubAnalysis = "Analysis_" + timeStamp + strParamSet; //Create Folders QDir crntWorkDir(m_strPathDirWorkDir); crntWorkDir.mkdir(strSubRef); crntWorkDir.mkdir(strSubComp); crntWorkDir.mkdir(strSubAnalysis); QString strPathDirReadRef = m_strPathDirWorkDir + "/" + strSubRef; QString strPathDirReadComp = m_strPathDirWorkDir + "/" + strSubComp; QString strPathDirAnalysis = m_strPathDirWorkDir + "/" + strSubAnalysis; m_strlistPath_RD_Read_Ref.clear(); m_strlistPath_RD_Read_Comp.clear(); m_strlistBatchReport.clear(); m_strlistPath_Output_Gammamap.clear(); m_strlistPath_Output_Failure.clear(); m_strlistPath_Output_Report.clear(); m_vRefDose.clear(); QString dirPathFirstFileDir; //for saving workspace QString dirPathFirstFileBase; //for saving workspace for (int i = 0; i < cntRef; i++) { QString strPathRef = m_strlistPath_RD_Original_Ref.at(i); QString strPathComp = m_strlistPath_RD_Original_Comp.at(i); QFileInfo fInfoRef = QFileInfo(strPathRef); QFileInfo fInfoComp = QFileInfo(strPathComp); QString baseNameRef = fInfoRef.completeBaseName(); QString baseNameComp = fInfoComp.completeBaseName(); if (i == 0) //first image location { //dirPathFirstFileDir = dirPath; dirPathFirstFileBase = baseNameComp; } QString strPathBkupRef = strPathDirReadRef + "/" + baseNameRef + ".mha"; QString strPathBkupComp = strPathDirReadComp + "/" + baseNameComp + ".mha"; if (strPathRef.length() < 2 || strPathComp.length() < 2) continue;//skip this pair Gamma_parms parms; //Gamma param: should come from the UI parms.b_ref_only_threshold = false; parms.mask_image_fn = ""; //parms->reference_dose; parms.gamma_max = 2.0; parms.b_compute_full_region = false; parms.b_resample_nn = false; //default: false //From File List parms.ref_image_fn = strPathRef.toLocal8Bit().constData(); parms.cmp_image_fn = strPathComp.toLocal8Bit().constData(); //From GUI if (ui.checkBox_inhereResample->isChecked()) parms.f_inherent_resample_mm = ui.lineEdit_inhereResample->text().toDouble(); else parms.f_inherent_resample_mm = -1.0; parms.b_interp_search = ui.checkBox_Interp_search->isChecked(); if (ui.radioButton_localGamma->isChecked()) { parms.b_local_gamma = true; } else { parms.b_local_gamma = false; } float inputRefDose = ui.lineEdit_refDoseInGy->text().toFloat(); if (inputRefDose <= 0) //blank { parms.have_reference_dose = false; parms.reference_dose = 0.0; } else { parms.have_reference_dose = true; parms.reference_dose = inputRefDose; } parms.dta_tolerance = ui.lineEdit_dta_tol->text().toDouble(); parms.dose_tolerance = ui.lineEdit_dose_tol->text().toDouble() / 100.0;//gui input: 3% --> param: 0.03 parms.f_analysis_threshold = ui.lineEdit_cutoff_dose->text().toDouble() / 100.0; //Saving folder: comp folder. FileName Should Include dta, dose, local/global QString strLocGlob; if (parms.b_local_gamma) strLocGlob = "loc"; else strLocGlob = "glb"; QString strSettingAbs = QString::number(parms.dta_tolerance, 'f', 0) + "mm_" + "" + QString::number(parms.dose_tolerance*100.0, 'f', 0) + "%_" + strLocGlob; QString outputPath = strPathDirAnalysis + "/" + baseNameComp + "_gammamap" + ".mha"; parms.out_image_fn = outputPath.toLocal8Bit().constData(); m_strlistPath_Output_Gammamap.push_back(outputPath); //if (ui.checkBox_failuremap_output->isChecked()) //{ //QString outputPath = dirPath + "/" + baseName + "_failmap_" + strSettingAbs + ".mha"; outputPath = strPathDirAnalysis + "/" + baseNameComp + "_failmap" + ".mha"; parms.out_failmap_fn = outputPath.toLocal8Bit().constData(); m_strlistPath_Output_Failure.push_back(outputPath); //} //QString outputPath = dirPath + "/" + baseName + "_report_" + strSettingAbs + ".txt"; outputPath = strPathDirAnalysis + "/" + baseNameComp + "_report" + ".txt"; parms.out_report_fn = outputPath.toLocal8Bit().constData(); m_strlistPath_Output_Report.push_back(outputPath); float refDoseGy; QString overallReport = GammaMain(&parms, refDoseGy, strPathBkupRef, strPathBkupComp); m_strlistBatchReport.push_back(overallReport); m_strlistPath_RD_Read_Ref.push_back(strPathBkupRef); m_strlistPath_RD_Read_Comp.push_back(strPathBkupComp); m_vRefDose.push_back(refDoseGy); } //Save WorkSpace File for future loading //QString strPathGammaWorkSpace = m_strPathDirWorkDir + "/" + dirPathFirstFileBase + "_" + strParamSet + "_" + QString("%1").arg(cntRef) + "cases.gws"; //gamma work space QString strPathGammaWorkSpace = m_strPathDirWorkDir + "/" + strSubAnalysis + ".gws"; //gamma work space QString strFilePathReport = m_strPathDirWorkDir + "/" + strSubAnalysis + "BatchReport.txt"; //gamma work space SaveCurrentGammaWorkSpace(strPathGammaWorkSpace); cout << cntRef << " analysis were successfully done!" << endl; SLT_LoadResults(); //After the batch mode analysis, export the simpe report. //Only when the number of files is > 1 // if (cntRef == 1) // return; SaveBatchGamma3DSimpleReport(strFilePathReport); /*QString fileName = QFileDialog::getSaveFileName(this, "Save batch report file", "", "report (*.txt)", 0, 0); if (fileName.length() < 1) return; ofstream fout; fout.open(fileName.toLocal8Bit().constData()); fout << "Reference_File\t" << "Compare_File\t" << "dta_tolerance[mm]\t" << "dose_tolerance[%]\t" << "doseCutoff[%]\t" << "Local/Global\t" << "Ref_dose[Gy]\t" << "VoxNumAnalyzed\t" << "VoxNumPassed\t" << "GammaPassRate[%]" << endl; for (int i = 0; i < cntRef; i++) { fout << m_strlistBatchReport.at(i).toLocal8Bit().constData() << endl; } fout.close();*/ } void gamma_gui::SaveBatchGamma3DSimpleReport(QString& strFilePath) { //QString fileName = QFileDialog::getSaveFileName(this, "Save batch report file", "", "report (*.txt)", 0, 0); /*if (fileName.length() < 1) return;*/ if (m_strlistBatchReport.count() < 1) { cout << "Error! No report is available" << endl; return; } ofstream fout; fout.open(strFilePath.toLocal8Bit().constData()); fout << "Reference_File\t" << "Compare_File\t" << "dta_tolerance[mm]\t" << "dose_tolerance[%]\t" << "doseCutoff[%]\t" << "Local/Global\t" << "Ref_dose[Gy]\t" << "VoxNumAnalyzed\t" << "VoxNumPassed\t" << "GammaPassRate[%]" << endl; int cnt = m_strlistBatchReport.count(); for (int i = 0; i < cnt; i++) { fout << m_strlistBatchReport.at(i).toLocal8Bit().constData() << endl; } fout.close(); } void gamma_gui::SLTM_SaveBatchModeSimpleReport() { QString filePath = QFileDialog::getSaveFileName(this, "Save batch report file", m_strPathDirWorkDir, "report (*.txt)", 0, 0); if (filePath.length() < 1) return; QFileInfo fInfo(filePath); if (fInfo.suffix() != "txt" && fInfo.suffix() != "TXT") { cout << "Saving filter didn't work. Saving this file as txt." << endl; filePath = filePath + ".txt"; } SaveBatchGamma3DSimpleReport(filePath); } QString gamma_gui::GammaMain(Gamma_parms* parms, float& refDoseGy, const QString& strPathBkupRef, const QString& strPathBkupComp) { QString reportResult; Gamma_dose_comparison gdc; //DICOM_RD compatible (added by YK, Feb 2015) //In the prev version, RD couldn't be read directly due to the scale factor inside of the DICOM file. //work-around was to use (plastimatch convert ...) //here, that feature has been integrated into plastimatch gamma Plm_file_format file_type_ref, file_type_comp; Rt_study rt_study_ref, rt_study_comp; file_type_ref = plm_file_format_deduce(parms->ref_image_fn.c_str()); file_type_comp = plm_file_format_deduce(parms->cmp_image_fn.c_str()); if (file_type_ref == PLM_FILE_FMT_DICOM_DOSE) { rt_study_ref.load(parms->ref_image_fn.c_str(), file_type_ref); if (rt_study_ref.has_dose()){ gdc.set_reference_image(rt_study_ref.get_dose()->clone()); } else{ gdc.set_reference_image(parms->ref_image_fn.c_str()); } } else { gdc.set_reference_image(parms->ref_image_fn.c_str()); } if (file_type_comp == PLM_FILE_FMT_DICOM_DOSE) { rt_study_comp.load(parms->cmp_image_fn.c_str(), file_type_comp); if (rt_study_comp.has_dose()) { gdc.set_compare_image(rt_study_comp.get_dose()->clone()); } else { gdc.set_compare_image(parms->cmp_image_fn.c_str()); } } else { gdc.set_compare_image(parms->cmp_image_fn.c_str()); } //End DICOM-RD if (parms->mask_image_fn != "") { gdc.set_mask_image(parms->mask_image_fn); } gdc.set_spatial_tolerance(parms->dta_tolerance); gdc.set_dose_difference_tolerance(parms->dose_tolerance); if (parms->have_reference_dose) { gdc.set_reference_dose(parms->reference_dose); } gdc.set_gamma_max(parms->gamma_max); /*Extended by YK*/ gdc.set_interp_search(parms->b_interp_search);//default: false gdc.set_local_gamma(parms->b_local_gamma);//default: false gdc.set_compute_full_region(parms->b_compute_full_region);//default: false gdc.set_resample_nn(parms->b_resample_nn); //default: false gdc.set_ref_only_threshold(parms->b_ref_only_threshold); if (parms->f_inherent_resample_mm > 0.0) { gdc.set_inherent_resample_mm(parms->f_inherent_resample_mm); } if (parms->f_analysis_threshold > 0) { gdc.set_analysis_threshold(parms->f_analysis_threshold);//0.1 = 10% } gdc.run(); if (parms->out_image_fn != "") { Plm_image::Pointer gamma_image = gdc.get_gamma_image(); gamma_image->save_image(parms->out_image_fn); } if (parms->out_failmap_fn != "") { gdc.get_fail_image()->save_image(parms->out_failmap_fn); } if (parms->out_report_fn != "") { //Export utput text using gdc.get_report_string(); std::ofstream fout; fout.open(parms->out_report_fn.c_str()); if (!fout.fail()){ fout << gdc.get_report_string(); fout << "Reference_file_name\t" << parms->ref_image_fn.c_str() << std::endl; fout << "Compare_file_name\t" << parms->cmp_image_fn.c_str() << std::endl; fout.close(); } } printf ("Pass rate = %2.6f %%\n", gdc.get_pass_fraction() * 100.0); //Composite a result string //FileName QFileInfo info_ref = QFileInfo(parms->ref_image_fn.c_str()); QFileInfo info_comp = QFileInfo(parms->cmp_image_fn.c_str()); QString fileName_ref = info_ref.fileName(); QString fileName_comp = info_comp.fileName(); QString strTol_dta = QString::number(parms->dta_tolerance,'f',2); QString strTol_dose = QString::number(parms->dose_tolerance*100.0, 'f', 0); QString strDoseCutoff = QString::number(parms->f_analysis_threshold*100, 'f', 0); QString strLocalOrGlobal; if (parms->b_local_gamma) strLocalOrGlobal = "local"; else strLocalOrGlobal = "global"; //if this is dcm, save the mha files //if (info_ref.suffix() == "dcm" || info_ref.suffix() == "DCM") //{ //QString newPath = info_ref.absolutePath() + "/" + info_ref.completeBaseName() + ".mha"; if (!strPathBkupRef.isEmpty()) { Plm_image* pImg = gdc.get_ref_image(); pImg->save_image(strPathBkupRef.toLocal8Bit().constData()); } //} //if (info_comp.suffix() == "dcm" || info_comp.suffix() == "DCM") //{ //QString newPath = info_comp.absolutePath() + "/" + info_comp.completeBaseName() + ".mha"; //QString newPath = info_comp.absolutePath() + "/" + info_comp.completeBaseName() + ".mha"; if (!strPathBkupComp.isEmpty()) { Plm_image* pImg = gdc.get_comp_image(); pImg->save_image(strPathBkupComp.toLocal8Bit().constData()); } QString strRef_dose = QString::number(gdc.get_reference_dose(), 'f', 2);//Gy QString strVoxNumAnalyzed = QString::number(gdc.get_analysis_num_vox(), 'f', 2); QString strVoxNumPassed = QString::number(gdc.get_passed_num_vox(), 'f', 2); QString strPassRate = QString::number(gdc.get_pass_fraction()*100.0, 'f', 2); reportResult = fileName_ref + "\t" + fileName_comp + "\t" + strTol_dta + "\t" + strTol_dose + "\t" + strDoseCutoff + "\t" + strLocalOrGlobal + "\t" + strRef_dose + "\t" + strVoxNumAnalyzed + "\t" + strVoxNumPassed + "\t" + strPassRate; refDoseGy = gdc.get_reference_dose(); return reportResult; } void gamma_gui::SLT_ProfileView() { //m_pView->show(); } void gamma_gui::SLT_DrawDoseImages() { // refer to probe positions, selected 3D file (spPointer), plane direction } void gamma_gui::SLT_DrawGammaMap3D() { } void gamma_gui::SLT_DrawGammaMap2D() { } void gamma_gui::Load_FilesToMem() { /*int cntRef = m_strlistPath_RD_Original_Ref.count(); int cntComp = m_strlistPath_RD_Original_Comp.count();*/ int cntRef = m_strlistPath_RD_Read_Ref.count(); int cntComp = m_strlistPath_RD_Read_Comp.count(); int cntGamma = m_strlistPath_Output_Gammamap.count(); if (cntRef*cntComp == 0 || cntRef != cntComp || cntRef != cntGamma) { cout << "Error: number should be matched" << endl; return; } m_vRefDoseImages.clear(); m_vCompDoseImages.clear(); m_vGammaMapImages.clear(); m_iLastLoadedIndex = -1; QString strPath_ref, strPath_comp, strPath_gamma; for (int i = 0; i < cntRef; i++) { strPath_ref = m_strlistPath_RD_Read_Ref.at(i); //always readable mha format strPath_comp = m_strlistPath_RD_Read_Comp.at(i); strPath_gamma = m_strlistPath_Output_Gammamap.at(i); QFileInfo info_ref = QFileInfo(strPath_ref); QFileInfo info_comp = QFileInfo(strPath_comp); //if (info_ref.suffix() == "dcm" || info_ref.suffix() == "DCM") //{ // //strPath_ref = info_ref.absolutePath() + "/" + info_ref.completeBaseName() + ".mha"; // strPath_ref = info_ref.absolutePath() + "/" + info_ref.completeBaseName() + ".mha"; //} //if (info_comp.suffix() == "dcm" || info_comp.suffix() == "DCM") //{ // //strPath_comp = info_comp.absolutePath() + "/" + info_comp.completeBaseName() + ".mha"; // strPath_comp = info_comp.absolutePath() + "/" + info_comp.completeBaseName() + ".mha"; //} bool bLowMem = ui.checkBox_low_mem->isChecked(); FloatImageType::Pointer spImgRef = FloatImageType::New(); FloatImageType::Pointer spImgComp = FloatImageType::New(); FloatImageType::Pointer spImgGamma = FloatImageType::New(); if (bLowMem) { spImgRef = m_spDummyLowMemImg; spImgComp = m_spDummyLowMemImg; spImgGamma = m_spDummyLowMemImg; } else { QUTIL::LoadFloatImage3D(strPath_ref.toLocal8Bit().constData(), spImgRef); QUTIL::LoadFloatImage3D(strPath_comp.toLocal8Bit().constData(), spImgComp); QUTIL::LoadFloatImage3D(strPath_gamma.toLocal8Bit().constData(), spImgGamma); } m_vRefDoseImages.push_back(spImgRef); m_vCompDoseImages.push_back(spImgComp); m_vGammaMapImages.push_back(spImgGamma); } } void gamma_gui::SLT_LoadResults() { cout << "Loading image data... please wait" << endl; Load_FilesToMem(); cout << "Dose and Gamma data are successfully loaded" << endl; disconnect(ui.comboBoxCompareFile, SIGNAL(currentIndexChanged(int)), this, SLOT(SLT_WhenSelectCombo())); SLT_UpdateComboContents(); connect(ui.comboBoxCompareFile, SIGNAL(currentIndexChanged(int)), this, SLOT(SLT_WhenSelectCombo())); SLT_WhenSelectCombo(); //initialization SLT_GoCenterPosRef(); SLT_GoCenterPosComp(); //SLT_DrawAll(); } void gamma_gui::SLT_UpdateComboContents() //compare image based.. { QComboBox* crntCombo = ui.comboBoxCompareFile; crntCombo->clear(); int cntComp = m_strlistFileBaseName_Comp.count(); for (int i = 0; i < cntComp; i++) { //SLT_WHenComboSelect should be disconnected here crntCombo->addItem(m_strlistFileBaseName_Comp.at(i)); } } void gamma_gui::SLT_DrawAll() { //Get combo box selection QComboBox* crntCombo = ui.comboBoxCompareFile; //QString curStr = crntCombo->currentText(); //this should be basename int curIdx = crntCombo->currentIndex(); //this should be basename int iCnt = crntCombo->count(); if (iCnt < 1) return; if ((int)(m_vRefDoseImages.size()) != iCnt || (int)(m_vCompDoseImages.size()) != iCnt) { cout << "Error! iCnt not matching in DrawAll" << endl; return; } //ui.labelReferDose->setFixedWidth(DEFAULT_LABEL_WIDTH); //ui.labelReferDose->setFixedHeight(DEFAULT_LABEL_HEIGHT); //ui.labelCompDose->setFixedWidth(DEFAULT_LABEL_WIDTH); //ui.labelCompDose->setFixedHeight(DEFAULT_LABEL_HEIGHT); //ui.labelGammaMap3D->setFixedWidth(DEFAULT_LABEL_WIDTH); //ui.labelGammaMap3D->setFixedHeight(DEFAULT_LABEL_HEIGHT); //ui.labelGammaMap2D->setFixedWidth(DEFAULT_LABEL_WIDTH); //ui.labelGammaMap2D->setFixedHeight(DEFAULT_LABEL_HEIGHT); //Convert3DTo2D (float2D, get radio, probe pos from GUI) //Get3DData (ref, comp, gamma) FloatImageType::Pointer spCurRef = m_vRefDoseImages.at(curIdx); FloatImageType::Pointer spCurComp = m_vCompDoseImages.at(curIdx); //FloatImageType::Pointer spCurRef = m_spRefDoseImages; //FloatImageType::Pointer spCurComp = m_spCompDoseImages; FloatImageType::Pointer spCurGamma; if ((int)(m_vGammaMapImages.size()) == iCnt) spCurGamma = m_vGammaMapImages.at(curIdx); /*if (m_pCurImageGamma3D) spCurGamma = m_spGammaMapImages;*/ //DICOM float probePosX = ui.lineEdit_ProbePosX->text().toFloat(); float probePosY = ui.lineEdit_ProbePosY->text().toFloat(); float probePosZ = ui.lineEdit_ProbePosZ->text().toFloat(); //Move them to Global due to 2D gamma export /*FloatImage2DType::Pointer m_spCurRef2D; FloatImage2DType::Pointer m_spCurComp2D;*/ //Move them to Global due to 2D gamma export FloatImage2DType::Pointer spCurGamma2DFrom3D; double finalPos1, finalPos2, finalPos3; enPLANE curPlane = PLANE_AXIAL; float fixedPos = 0.0; float probePos2D_X =0.0; float probePos2D_Y = 0.0; bool bYFlip = false; if (ui.radioButtonAxial->isChecked()) { curPlane = PLANE_AXIAL; fixedPos = probePosZ; probePos2D_X = probePosX; probePos2D_Y = probePosY; } else if (ui.radioButtonSagittal->isChecked()) { curPlane = PLANE_SAGITTAL; fixedPos = probePosX; probePos2D_X = probePosY; probePos2D_Y = probePosZ; //YKDebug: may be reversed bYFlip = true; } else if (ui.radioButtonFrontal->isChecked()) { curPlane = PLANE_FRONTAL; fixedPos = probePosY; probePos2D_X = probePosX; probePos2D_Y = probePosZ;//YKDebug: may be reversed bYFlip = true; } QUTIL::Get2DFrom3DByPosition(spCurRef, m_spCurRef2D, curPlane, fixedPos, finalPos1); QUTIL::Get2DFrom3DByPosition(spCurComp, m_spCurComp2D, curPlane, fixedPos, finalPos2); // if (curPlane == PLANE_FRONTAL) // QUTIL::SaveFloatImage2D("D:\\testFrontal.mha", m_spCurRef2D);//it is flipped! if (spCurGamma) { QUTIL::Get2DFrom3DByPosition(spCurGamma, spCurGamma2DFrom3D, curPlane, fixedPos, finalPos3); } //Actually, frontal and sagittal image should be flipped for display purpose (in axial, Y is small to large, SAG and FRONTAL, Large to Small (head to toe direction) //Let's not change original data itself due to massing up the origin. Only change the display image //Point probe and profiles, other things works fine. //YKImage receives 2D float m_pCurImageRef->UpdateFromItkImageFloat(m_spCurRef2D, GY2YKIMG_MAG, NON_NEG_SHIFT, bYFlip); //flip Y for display only m_pCurImageComp->UpdateFromItkImageFloat(m_spCurComp2D, GY2YKIMG_MAG, NON_NEG_SHIFT, bYFlip); //cout << "GAMMA2YKIMG_MAG= " << GAMMA2YKIMG_MAG << endl; if (spCurGamma2DFrom3D) { m_pCurImageGamma3D->UpdateFromItkImageFloat(spCurGamma2DFrom3D, GAMMA2YKIMG_MAG, NON_NEG_SHIFT, bYFlip); } if (m_spGamma2DResult) { m_pCurImageGamma2D->UpdateFromItkImageFloat(m_spGamma2DResult, GAMMA2YKIMG_MAG, NON_NEG_SHIFT, bYFlip); } float doseGyNormRef = 0.01 * (ui.sliderNormRef->value()); float doseGyNormComp = 0.01 *(ui.sliderNormComp->value()); //cout << "doseGyNormComp= " << doseGyNormRef << endl; //PixMap m_pCurImageRef->SetNormValueOriginal(doseGyNormRef); m_pCurImageComp->SetNormValueOriginal(doseGyNormComp); m_pCurImageRef->FillPixMapDose(); m_pCurImageComp->FillPixMapDose(); //m_pCurImageRef->FillPixMapDose(doseGyNormRef); //m_pCurImageComp->FillPixMapDose(doseGyNormComp); m_pCurImageGamma3D->FillPixMapGamma(); m_pCurImageGamma2D->FillPixMapGamma(); m_pCurImageRef->SetCrosshairPosPhys(probePos2D_X, probePos2D_Y, curPlane); m_pCurImageComp->SetCrosshairPosPhys(probePos2D_X, probePos2D_Y, curPlane); m_pCurImageGamma3D->SetCrosshairPosPhys(probePos2D_X, probePos2D_Y, curPlane); m_pCurImageGamma2D->SetCrosshairPosPhys(probePos2D_X, probePos2D_Y, curPlane); m_pCurImageRef->m_bDrawCrosshair = true; m_pCurImageComp->m_bDrawCrosshair = true; m_pCurImageGamma3D->m_bDrawCrosshair = true; m_pCurImageGamma2D->m_bDrawCrosshair = true; m_pCurImageRef->m_bDrawOverlayText = true; m_pCurImageComp->m_bDrawOverlayText = true; m_pCurImageGamma3D->m_bDrawOverlayText = true; m_pCurImageGamma2D->m_bDrawOverlayText = true; QString strValRef = QString::number(m_pCurImageRef->GetCrosshairOriginalData() * 100, 'f', 1) + " cGy"; QString strValComp = QString::number(m_pCurImageComp->GetCrosshairOriginalData() * 100, 'f', 1) + " cGy"; QString strValGamma3D = QString::number(m_pCurImageGamma3D->GetCrosshairOriginalData(), 'f', 2); QString strValGamma2D = QString::number(m_pCurImageGamma2D->GetCrosshairOriginalData(), 'f', 2); float fPercRef = m_pCurImageRef->GetCrosshairPercData(); float fPercComp = m_pCurImageComp->GetCrosshairPercData(); QString strPercRef = QString::number(fPercRef, 'f', 1) + "%"; QString strPercComp = QString::number(fPercComp, 'f', 1) + "%"; QString strDelta = QString::number(fPercComp - fPercRef, 'f', 1) + "%"; m_pCurImageRef->m_strOverlayText = strValRef + " [" + strPercRef + "]"; m_pCurImageComp->m_strOverlayText = strValComp + " [" + strPercComp + "]" + ", Delta= " + strDelta; m_pCurImageGamma3D->m_strOverlayText = strValGamma3D; m_pCurImageGamma2D->m_strOverlayText = strValGamma2D; ui.labelReferDose->SetBaseImage(m_pCurImageRef); ui.labelCompDose->SetBaseImage(m_pCurImageComp); ui.labelGammaMap3D->SetBaseImage(m_pCurImageGamma3D); ui.labelGammaMap2D->SetBaseImage(m_pCurImageGamma2D); //ui.labelRefDose //Set probe point in YKImage and crosshair display on //Update Table and Plot //Display //label.update() ui.labelReferDose->update(); ui.labelCompDose->update(); ui.labelGammaMap3D->update(); ui.labelGammaMap2D->update(); //Update Table and Chart //1) prepare vector float vector vProfileRef, vProfileComp, vProfileGamma3D, vProfileGamma2D; enPROFILE_DIRECTON enDirection = PRIFLE_HOR; float fixedPosProfile; if (ui.radioButtonHor->isChecked()) { enDirection = PRIFLE_HOR; } else if (ui.radioButtonVert->isChecked()) { enDirection = PRIFLE_VER; } if (curPlane == PLANE_AXIAL) { if (enDirection == PRIFLE_HOR) fixedPosProfile = probePosY; else fixedPosProfile = probePosX; } else if (curPlane == PLANE_SAGITTAL) { if (enDirection == PRIFLE_HOR) fixedPosProfile = probePosZ; else fixedPosProfile = probePosY; } else if (curPlane == PLANE_FRONTAL) { if (enDirection == PRIFLE_HOR) fixedPosProfile = probePosZ; else fixedPosProfile = probePosX; } QUTIL::GetProfile1DByPosition(m_spCurRef2D, vProfileRef, fixedPosProfile, enDirection); QUTIL::GetProfile1DByPosition(m_spCurComp2D, vProfileComp, fixedPosProfile, enDirection); QUTIL::GetProfile1DByPosition(spCurGamma2DFrom3D, vProfileGamma3D, fixedPosProfile, enDirection); //QUTIL::GetProfile1DByPosition(spCurRef2D, vProfileGamma2D, fixedPosProfile, enDirection); //cout << "vectorSize= " << vProfileRef.size() << endl; //fNorm: Gy //float doseGyNormRef = 0.01 * (ui.sliderNormRef->value()); //float doseGyNormComp = 0.01 *(ui.sliderNormComp->value()); UpdateTable(vProfileRef, vProfileComp, vProfileGamma3D, doseGyNormRef, doseGyNormComp, 1.0, 100.0, 100.0, 1.0); SLT_DrawGraph(ui.checkBoxAutoAdjust->isChecked()); if (m_pTableModel == NULL) { //cout << "TableModel is NULL" << endl; } if (m_pTableModel != NULL) { //cout << "table column " << m_pTableModel->columnCount() << endl; //cout << "table row " << m_pTableModel->rowCount() << endl; ui.tableViewProfile->setModel(m_pTableModel); ui.tableViewProfile->resizeColumnsToContents(); } //Update LineEdit using rounded fixed value if (curPlane == PLANE_AXIAL) { //ui.lineEdit_ProbePosZ->setText(QString("%1").arg(finalPos1));//finalPos1 is for all images ui.lineEdit_ProbePosZ->setText(QString::number(finalPos1,'f', 1)); } else if (curPlane == PLANE_SAGITTAL) { ui.lineEdit_ProbePosX->setText(QString::number(finalPos1, 'f', 1)); } else if (curPlane == PLANE_FRONTAL) { ui.lineEdit_ProbePosY->setText(QString::number(finalPos1, 'f', 1)); } ui.tableViewProfile->update(); SLT_UpdateReportTxt(); } void gamma_gui::SLT_UpdateReportTxt() { QComboBox* crntCombo = ui.comboBoxCompareFile; int curIdx = crntCombo->currentIndex(); //this should be basename int iCnt = crntCombo->count(); if (iCnt < 1) return; //Update plainTextEditGammaResult ui.plainTextEditGammaResult->clear(); if (m_strlistPath_Output_Report.count() == iCnt) { QString curPath = m_strlistPath_Output_Report.at(curIdx); QStringList strList = QUTIL::LoadTextFile(curPath.toLocal8Bit().constData()); for (int i = 0; i < strList.count(); i++) ui.plainTextEditGammaResult->appendPlainText(strList.at(i)); } QTextCursor txtCursor = ui.plainTextEditGammaResult->textCursor(); //position where you want it txtCursor.setPosition(0); ui.plainTextEditGammaResult->setTextCursor(txtCursor); } void gamma_gui::SLT_UpdateProbePosRef() { UpdateProbePos(ui.labelReferDose); } void gamma_gui::SLT_UpdateProbePosComp() { UpdateProbePos(ui.labelCompDose); } void gamma_gui::SLT_UpdateProbePosGamma2D() { UpdateProbePos(ui.labelGammaMap2D); } void gamma_gui::SLT_UpdateProbePosGamma3D() { UpdateProbePos(ui.labelGammaMap3D); } void gamma_gui::UpdateProbePos(qyklabel* qlabel) { YK16GrayImage* pYKImg = qlabel->m_pYK16Image; if (pYKImg == NULL) return; QPoint viewPt = QPoint(qlabel->x, qlabel->y); QPoint crntDataPt = qlabel->GetDataPtFromViewPt(viewPt.x(), viewPt.y()); float originX = pYKImg->m_fOriginX; float originY = pYKImg->m_fOriginY; float spacingX = pYKImg->m_fSpacingX; float spacingY = pYKImg->m_fSpacingY; //float iWidth = pYKImg->m_iWidth; float iHeight = pYKImg->m_iHeight; float physPosX = 0.0; float physPosY = 0.0; //connect(ui.labelReferDose, SIGNAL(Mouse_Pressed_Left()), this, SLOT(SLT_UpdateProbePosRef())); //added //connect(ui.labelCompDose, SIGNAL(Mouse_Pressed_Left()), this, SLOT(SLT_UpdateProbePosComp())); //added //connect(ui.labelGammaMap2D, SIGNAL(Mouse_Pressed_Left()), this, SLOT(SLT_UpdateProbePosGamma2D())); //added //connect(ui.labelGammaMap3D, SIGNAL //Update Probe position // ui.lineEdit_ProbePosX enPLANE curPlane = PLANE_AXIAL; if (ui.radioButtonAxial->isChecked()) { curPlane = PLANE_AXIAL; physPosX = crntDataPt.x()*spacingX + originX; physPosY = crntDataPt.y()*spacingY + originY; ui.lineEdit_ProbePosX->setText(QString::number(physPosX, 'f', 1)); ui.lineEdit_ProbePosY->setText(QString::number(physPosY, 'f', 1)); //ui.lineEdit_ProbePosZ } else if (ui.radioButtonSagittal->isChecked()) { curPlane = PLANE_SAGITTAL; physPosX = crntDataPt.x()*spacingX + originX; physPosY = (iHeight - crntDataPt.y() - 1)*spacingY + originY; ui.lineEdit_ProbePosY->setText(QString::number(physPosX, 'f', 1)); ui.lineEdit_ProbePosZ->setText(QString::number(physPosY, 'f', 1)); } else if (ui.radioButtonFrontal->isChecked()) { curPlane = PLANE_FRONTAL; physPosX = crntDataPt.x()*spacingX + originX; physPosY = (iHeight - crntDataPt.y() - 1)*spacingY + originY; //ui.lineEdit_ProbePosX->setText(QString("%1").arg(physPosX)); //ui.lineEdit_ProbePosZ->setText(QString("%1").arg(physPosY)); ui.lineEdit_ProbePosX->setText(QString::number(physPosX, 'f', 1)); ui.lineEdit_ProbePosZ->setText(QString::number(physPosY, 'f', 1)); } SLT_DrawAll(); } void gamma_gui::SLT_DrawTable() { } void gamma_gui::SLT_DrawChart() { } void gamma_gui::UpdateTable(vector& vData1, vector& vData2, vector& vData3, float fNorm1, float fNorm2, float fNorm3, float fMag1, float fMag2, float fMag3) { int numOfData = 3; if (m_pTableModel != NULL) { delete m_pTableModel; m_pTableModel = NULL; } int columnSize = 1; int rowSize1, rowSize2, rowSize3 = 0; columnSize = numOfData * 2; rowSize1 = vData1.size(); rowSize2 = vData2.size(); rowSize3 = vData3.size(); int maxRowSize = 0; if (rowSize1 > rowSize2) { if (rowSize1 < rowSize3) maxRowSize = rowSize3; else maxRowSize = rowSize1; } else { if (rowSize2 < rowSize3) maxRowSize = rowSize3; else maxRowSize = rowSize2; } if (maxRowSize == 0) { //cout << "MaxRowSize is 0" << endl; return; } if (fNorm1 <= 0 || fNorm2 <= 0 || fNorm3 <= 0) return; m_pTableModel = new QStandardItemModel(maxRowSize, columnSize, this); //2 Rows and 3 Columns m_pTableModel->setHorizontalHeaderItem(0, new QStandardItem(QString("mm"))); m_pTableModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Ref_cGy"))); m_pTableModel->setHorizontalHeaderItem(2, new QStandardItem(QString("Com_cGy"))); m_pTableModel->setHorizontalHeaderItem(3, new QStandardItem(QString("Ref_%"))); m_pTableModel->setHorizontalHeaderItem(4, new QStandardItem(QString("Com_%"))); m_pTableModel->setHorizontalHeaderItem(5, new QStandardItem(QString("Gamma"))); bool bData2Exists = false; bool bData3Exists = false; for (int i = 0; i < maxRowSize; i++) { if (i < rowSize2) bData2Exists = true; if (i < rowSize3) bData3Exists = true; qreal tmpValX1 = vData1.at(i).x(); qreal tmpValY1 = vData1.at(i).y()*fMag1; //Gy --> cGy qreal tmpValY1_Perc = vData1.at(i).y() / fNorm1 * 100.0; QString strValX, strValY1, strValY2, strValY1_Perc, strValY2_Perc, strValY3; strValX = QString::number(tmpValX1, 'f', 1); //cGy strValY1 = QString::number(tmpValY1, 'f', 1); //cGy strValY1_Perc = QString::number(tmpValY1_Perc, 'f', 1); //% if (bData2Exists) { //qreal tmpValX2 = vData2.at(i).x(); qreal tmpValY2 = vData2.at(i).y()*fMag2; qreal tmpValY2_Perc = vData2.at(i).y() / fNorm2 * 100.0; //fNorm : Gy not cGy strValY2 = QString::number(tmpValY2, 'f', 1); //cGy strValY2_Perc = QString::number(tmpValY2_Perc, 'f', 1); //% } if (bData3Exists) { //qreal tmpValX3 = vData3.at(i).x(); qreal tmpValY3 = vData3.at(i).y()*fMag3; //qreal tmpValY3_Perc = vData3.at(i).y() / fNorm3 * 100.0; //fNorm : Gy not cGy strValY3 = QString::number(tmpValY3, 'f', 2); //gamma } m_pTableModel->setItem(i, 0, new QStandardItem(strValX)); m_pTableModel->setItem(i, 1, new QStandardItem(strValY1)); m_pTableModel->setItem(i, 2, new QStandardItem(strValY2)); m_pTableModel->setItem(i, 3, new QStandardItem(strValY1_Perc)); m_pTableModel->setItem(i, 4, new QStandardItem(strValY2_Perc)); m_pTableModel->setItem(i, 5, new QStandardItem(strValY3)); } ui.tableViewProfile->setModel(m_pTableModel); ui.tableViewProfile->resizeColumnsToContents(); } void gamma_gui::SLT_CopyTableToClipboard() { qApp->clipboard()->clear(); QStringList list; int rowCnt = m_pTableModel->rowCount(); int columnCnt = m_pTableModel->columnCount(); //list << "\n"; //for (int i = 0 ; i < columnCnt ; i++) //{ //QFileInfo tmpInfo = QFileInfo(ui.lineEdit_Cur3DFileName->text()); //list << "Index"; //list << tmpInfo.baseName(); list << "\n"; /* m_pTableModel->setHorizontalHeaderItem(0, new QStandardItem(QString("mm"))); m_pTableModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Ref_cGy"))); m_pTableModel->setHorizontalHeaderItem(2, new QStandardItem(QString("Com_cGy"))); m_pTableModel->setHorizontalHeaderItem(3, new QStandardItem(QString("Ref_%"))); m_pTableModel->setHorizontalHeaderItem(4, new QStandardItem(QString("Com_%"))); m_pTableModel->setHorizontalHeaderItem(5, new QStandardItem(QString("Gmma100"))); */ list << "mm"; list << "Ref_cGy"; list << "Com_cGy"; list << "Ref_%"; list << "Com_%"; list << "Gamma"; list << "\n"; for (int j = 0; j < rowCnt; j++) { for (int i = 0; i < columnCnt; i++) { QStandardItem* item = m_pTableModel->item(j, i); list << item->text(); } list << "\n"; } qApp->clipboard()->setText(list.join("\t")); } void gamma_gui::SLT_DrawGraph(bool bInitMinMax) { if (m_pTableModel == NULL) return; bool bNorm = ui.checkBoxNormalized->isChecked();// show percentage chart //Draw only horizontal, center QVector vAxisX1; //can be rows or columns QVector vAxisY1; QVector vAxisX2; //can be rows or columns QVector vAxisY2; QVector vAxisX3; //can be rows or columns QVector vAxisY3; //QStandardItemModel m_pTableModel.item() int dataLen = m_pTableModel->rowCount(); // int columnLen = m_pTableModel->columnCount(); if (dataLen < 1) return; ui.customPlotProfile->clearGraphs(); double minX = 9999.0; double maxX = -1.0; double minY = 9999.0; double maxY = -1.0; for (int i = 0; i< dataLen; i++) { QStandardItem* tableItem1 = m_pTableModel->item(i, 0); QStandardItem* tableItem2 = m_pTableModel->item(i, 1); QStandardItem* tableItem3 = m_pTableModel->item(i, 2); QStandardItem* tableItem4 = m_pTableModel->item(i, 3); QStandardItem* tableItem5 = m_pTableModel->item(i, 4); QStandardItem* tableItem6 = m_pTableModel->item(i, 5); double tableVal1 = tableItem1->text().toDouble(); double tableVal2 = tableItem2->text().toDouble(); double tableVal3 = tableItem3->text().toDouble(); double tableVal4 = tableItem4->text().toDouble(); double tableVal5 = tableItem5->text().toDouble(); double tableVal6 = tableItem6->text().toDouble(); if (minX > tableVal1) minX = tableVal1; if (maxX < tableVal1) maxX = tableVal1; if (minY > tableVal2) minY = tableVal2; if (maxY < tableVal2) maxY = tableVal2; if (bNorm) //% { vAxisX1.push_back(tableVal1); vAxisY1.push_back(tableVal4); vAxisX2.push_back(tableVal1); vAxisY2.push_back(tableVal5); vAxisX3.push_back(tableVal1); vAxisY3.push_back(tableVal6); } else { vAxisX1.push_back(tableVal1); vAxisY1.push_back(tableVal2); vAxisX2.push_back(tableVal1); vAxisY2.push_back(tableVal3); vAxisX3.push_back(tableVal1); vAxisY3.push_back(tableVal6); } } ui.customPlotProfile->addGraph(); ui.customPlotProfile->graph(0)->setData(vAxisX1, vAxisY1); ui.customPlotProfile->graph(0)->setPen(QPen(Qt::blue)); ui.customPlotProfile->graph(0)->setName("Ref. dose"); ui.customPlotProfile->addGraph(); ui.customPlotProfile->graph(1)->setData(vAxisX2, vAxisY2); ui.customPlotProfile->graph(1)->setPen(QPen(Qt::red)); ui.customPlotProfile->graph(1)->setName("Compared dose"); /* ui.customPlotProfile->addGraph(); ui.customPlotProfile->graph(2)->setData(vAxisX3, vAxisY3); ui.customPlotProfile->graph(2)->setPen(QPen(Qt::green)); ui.customPlotProfile->graph(2)->setName("Gamma");*/ if (bInitMinMax) { //float marginX = 10; //float marginY = 100; ui.lineEditXMin->setText(QString("%1").arg(minX)); ui.lineEditXMax->setText(QString("%1").arg(maxX)); //ui.lineEditYMin->setText(QString("%1").arg(minY)); //ui.lineEditYMax->setText(QString("%1").arg(maxY + marginY)); } double tmpXMin = ui.lineEditXMin->text().toDouble(); double tmpXMax = ui.lineEditXMax->text().toDouble(); double tmpYMin = ui.lineEditYMin->text().toDouble(); double tmpYMax = ui.lineEditYMax->text().toDouble(); ui.customPlotProfile->xAxis->setRange(tmpXMin, tmpXMax); ui.customPlotProfile->yAxis->setRange(tmpYMin, tmpYMax); ui.customPlotProfile->xAxis->setLabel("mm"); if (bNorm) ui.customPlotProfile->yAxis->setLabel("%"); else ui.customPlotProfile->yAxis->setLabel("cGy"); ui.customPlotProfile->setTitle("Dose profile"); QFont titleFont = font(); titleFont.setPointSize(10); ui.customPlotProfile->setTitleFont(titleFont); ui.customPlotProfile->legend->setVisible(true); QFont legendFont = font(); // start out with MainWindow's font.. legendFont.setPointSize(8); // and make a bit smaller for legend ui.customPlotProfile->legend->setFont(legendFont); ui.customPlotProfile->legend->setPositionStyle(QCPLegend::psTopRight); ui.customPlotProfile->legend->setBrush(QBrush(QColor(255, 255, 255, 200))); ui.customPlotProfile->replot(); } void gamma_gui::SLT_RunGamma2D() { if (!m_spCurRef2D) return; if (!m_spCurComp2D) return; //Find export folder. if (m_strlistPath_RD_Read_Comp.empty()) return; if (m_strlistFileBaseName_Comp.empty()) return; QComboBox* crntCombo = ui.comboBoxCompareFile; int iCnt = crntCombo->count(); if (iCnt < 1 || m_strlistFileBaseName_Comp.count() != iCnt) return; int curIdx = crntCombo->currentIndex(); //this should be basename if (curIdx < 0) return; //QString strPathOutputRoot = m_strlistPath_RD_Comp.at(curIdx); ////QString strPathOutputRoot = m_strPathDirWorkDir; //QFileInfo fInfo(strPathOutputRoot); //QDir crntDir = fInfo.absolutePath(); QDir crntDir = QDir(m_strPathDirWorkDir); if (!crntDir.exists()) { QUTIL::ShowErrorMessage("Error! working space is not ready"); } //Get Current plane float probePosX = ui.lineEdit_ProbePosX->text().toFloat(); float probePosY = ui.lineEdit_ProbePosY->text().toFloat(); float probePosZ = ui.lineEdit_ProbePosZ->text().toFloat(); QString curBaseNameRef = m_strlistFileBaseName_Ref.at(curIdx); QString curBaseNameComp = m_strlistFileBaseName_Comp.at(curIdx); QString strPlane; if (ui.radioButtonAxial->isChecked()) { strPlane = "AXL_Z" + QString::number(probePosZ, 'f', 1) + "mm"; //fixedPos = probePosZ; } else if (ui.radioButtonSagittal->isChecked()) { strPlane = "SAG_X" + QString::number(probePosX, 'f', 1) + "mm"; //fixedPos = probePosX; } else if (ui.radioButtonFrontal->isChecked()) { strPlane = "FRN_Y" + QString::number(probePosY, 'f', 1) + "mm"; //fixedPos = probePosY; } QString subDirName = curBaseNameComp + "_" + strPlane; bool tmpResult = crntDir.mkdir(subDirName); //what if the directory exists? if (!tmpResult) cout << "Warning! Directory for 2D gamma already exists. files will be overwritten." << endl; //QString strSavingFolder = crntDir.absolutePath() + "/" + subDirName; QString strSavingFolder = crntDir.absolutePath() + "/" + subDirName; QDir dirSaving(strSavingFolder); if (!dirSaving.exists()) { cout << "Dir is not found:" << strSavingFolder.toLocal8Bit().constData() << endl; return; } /* From now on, the target folder is ready */ QString tmpFilePathRef = strSavingFolder + "/" + "Gamma2DRef.mha"; QString tmpFilePathComp = strSavingFolder + "/" + "Gamma2DComp.mha"; //Save current 2D m_spCurRef2D; m_spCurComp2D; QUTIL::SaveFloatImage2D(tmpFilePathRef.toLocal8Bit().constData(), m_spCurRef2D); QUTIL::SaveFloatImage2D(tmpFilePathComp.toLocal8Bit().constData(), m_spCurComp2D); Gamma_parms parms; //Gamma param: should come from the UI parms.mask_image_fn = ""; //parms->reference_dose; parms.gamma_max = 2.0; parms.b_compute_full_region = false; parms.b_resample_nn = false; //default: false parms.b_ref_only_threshold = false; //From File List parms.ref_image_fn = tmpFilePathRef.toLocal8Bit().constData(); parms.cmp_image_fn = tmpFilePathComp.toLocal8Bit().constData(); //From GUI if (ui.checkBox_inhereResample->isChecked()) parms.f_inherent_resample_mm = ui.lineEdit_inhereResample->text().toDouble(); else parms.f_inherent_resample_mm = -1.0; parms.b_interp_search = ui.checkBox_Interp_search->isChecked(); if (ui.radioButton_localGamma->isChecked()) { parms.b_local_gamma = true; } else { parms.b_local_gamma = false; } float inputRefDose = ui.lineEdit_refDoseInGy->text().toFloat(); if (inputRefDose <= 0) //blank { parms.have_reference_dose = false; } else { parms.have_reference_dose = true; parms.reference_dose = inputRefDose; } parms.dta_tolerance = ui.lineEdit_dta_tol->text().toDouble(); parms.dose_tolerance = ui.lineEdit_dose_tol->text().toDouble() / 100.0;//gui input: 3% --> param: 0.03 parms.f_analysis_threshold = ui.lineEdit_cutoff_dose->text().toDouble() / 100.0; //Saving folder: comp folder. FileName Should Include dta, dose, local/global //QFileInfo fInfo = QFileInfo(tmpFilePathComp); //QString dirPath = fInfo.absolutePath(); //QString baseName = fInfo.completeBaseName(); QString strLocGlob; if (parms.b_local_gamma) strLocGlob = "loc"; else strLocGlob = "glb"; QString strSettingAbs = QString::number(parms.dta_tolerance, 'f', 0) + "mm_" + "" + QString::number(parms.dose_tolerance*100.0, 'f', 0) + "%_" + strLocGlob; //QString tmpFilePathComp = strSavingFolder + "/" + "Gamma2DComp.mha"; QString strPathGamma2D = strSavingFolder + "/" + "gamma2D" + ".mha"; // if (ui.checkBox_gammamap_output->isChecked()) // { parms.out_image_fn = strPathGamma2D.toLocal8Bit().constData(); // } QString strPathFailmap2D = strSavingFolder + "/" + "fail2D" + ".mha"; //if (ui.checkBox_failuremap_output->isChecked()) // { parms.out_failmap_fn = strPathFailmap2D.toLocal8Bit().constData(); // } QString strPathReport = strSavingFolder + "/" + "text_report" + ".txt"; cout << "strPathReport= " << strPathReport.toLocal8Bit().constData() << endl; parms.out_report_fn = strPathReport.toLocal8Bit().constData(); float refDoseGy; QString overallReport = GammaMain(&parms, refDoseGy); //report for a single case //Update GUI //Read gammap2D //m_spGamma2DResult; QUTIL::LoadFloatImage2D(strPathGamma2D.toLocal8Bit().constData(), m_spGamma2DResult); //Update plainTextEditGammaResult QFileInfo reportInfo = QFileInfo(strPathReport); if (!reportInfo.exists()) { cout << "Error! output text doesn't exist." << endl; return; } //Update Report txt here ui.plainTextEditGammaResult2D->clear(); QStringList strList = QUTIL::LoadTextFile(strPathReport.toLocal8Bit().constData()); for (int i = 0; i < strList.count(); i++) ui.plainTextEditGammaResult2D->appendPlainText(strList.at(i)); QTextCursor txtCursor = ui.plainTextEditGammaResult2D->textCursor(); //position where you want it txtCursor.setPosition(0); ui.plainTextEditGammaResult2D->setTextCursor(txtCursor); //SaveIBA Image format QString IBAFilePathRef = strSavingFolder + "/" + strPlane + "_" + curBaseNameRef + ".OPG"; QString IBAFilePathComp = strSavingFolder + "/" + strPlane + "_" + curBaseNameComp + ".OPG"; SaveDoseIBAGenericTXTFromItk(IBAFilePathRef.toLocal8Bit().constData(), m_spCurRef2D); SaveDoseIBAGenericTXTFromItk(IBAFilePathComp.toLocal8Bit().constData(), m_spCurComp2D); SLT_RestoreZoomPan(); SLT_DrawAll(); } void gamma_gui::SLT_GoCenterPosRef() { QComboBox* crntCombo = ui.comboBoxCompareFile; int curIdx = crntCombo->currentIndex(); //this should be basename if (curIdx < 0) return; if (m_vRefDoseImages.empty()) return; FloatImageType::Pointer spCurFloat3D = m_vRefDoseImages.at(curIdx); FloatImageType::PointType ptOrigin = spCurFloat3D->GetOrigin(); FloatImageType::SizeType imgSize = spCurFloat3D->GetBufferedRegion().GetSize(); //dimension FloatImageType::SpacingType imgSpacing = spCurFloat3D->GetSpacing(); //dimension VEC3D middlePtPos; middlePtPos.x = ptOrigin[0] + imgSize[0] * imgSpacing[0] / 2.0; middlePtPos.y = ptOrigin[1] + imgSize[1] * imgSpacing[1] / 2.0; middlePtPos.z = ptOrigin[2] + imgSize[2] * imgSpacing[2] / 2.0; ui.lineEdit_ProbePosX->setText(QString::number(middlePtPos.x, 'f', 1)); ui.lineEdit_ProbePosY->setText(QString::number(middlePtPos.y, 'f', 1)); ui.lineEdit_ProbePosZ->setText(QString::number(middlePtPos.z, 'f', 1)); SLT_DrawAll(); //triggered when Go Position button } void gamma_gui::SLT_GoCenterPosComp() { QComboBox* crntCombo = ui.comboBoxCompareFile; int curIdx = crntCombo->currentIndex(); //this should be basename if (curIdx < 0) return; if (m_vCompDoseImages.empty()) return; FloatImageType::Pointer spCurFloat3D = m_vCompDoseImages.at(curIdx); FloatImageType::PointType ptOrigin = spCurFloat3D->GetOrigin(); FloatImageType::SizeType imgSize = spCurFloat3D->GetBufferedRegion().GetSize(); //dimension FloatImageType::SpacingType imgSpacing = spCurFloat3D->GetSpacing(); //dimension VEC3D middlePtPos; middlePtPos.x = ptOrigin[0] + imgSize[0] * imgSpacing[0] / 2.0; middlePtPos.y = ptOrigin[1] + imgSize[1] * imgSpacing[1] / 2.0; middlePtPos.z = ptOrigin[2] + imgSize[2] * imgSpacing[2] / 2.0; ui.lineEdit_ProbePosX->setText(QString::number(middlePtPos.x, 'f', 1)); ui.lineEdit_ProbePosY->setText(QString::number(middlePtPos.y, 'f', 1)); ui.lineEdit_ProbePosZ->setText(QString::number(middlePtPos.z, 'f', 1)); SLT_DrawAll(); //triggered when Go Position button } void gamma_gui::SLT_NormCompFromRefNorm() //button { QString crntNormComp = ui.lineEditNormComp->text(); float crntNormF = crntNormComp.toFloat(); if (crntNormF <= 0) return; //Get RefValue int iCurrRefNormVal = ui.sliderNormRef->value(); //cGy int iCurrCompNormVal = qRound(iCurrRefNormVal*crntNormF); ui.sliderNormComp->setValue(iCurrCompNormVal); } void gamma_gui::SaveDoseIBAGenericTXTFromItk(QString strFilePath, FloatImage2DType::Pointer& spFloatDose) { if (!spFloatDose) return; //Set center point first (from MainDLg --> TIF) //this will update m_rXPos.a, b //SetRationalCenterPosFromDataCenter(dataCenterPoint); //POINT ptCenter = GetDataCenter(); //will get dataPt from m_rXPos FloatImage2DType::PointType ptOrigin = spFloatDose->GetOrigin(); FloatImage2DType::SizeType imgSize = spFloatDose->GetBufferedRegion().GetSize(); //dimension FloatImage2DType::SpacingType imgSpacing = spFloatDose->GetSpacing(); //dimension int imgWidth = imgSize[0]; int imgHeight = imgSize[1]; float spacingX = imgSpacing[0]; float spacingY = imgSpacing[1]; float originX = ptOrigin[0]; float originY = ptOrigin[1]; ofstream fout; fout.open(strFilePath.toLocal8Bit().constData()); fout << "" << endl; fout << endl; fout << "" << endl; fout << "Separator: [TAB]" << endl; fout << "Workspace Name: n/a" << endl; fout << "File Name: n/a" << endl; fout << "Image Name: n/a" << endl; fout << "Radiation Type: Photons" << endl; fout << "Energy: 0.0 MV" << endl; fout << "SSD: 10.0 cm" << endl; fout << "SID: 100.0 cm" << endl; fout << "Field Size Cr: 10.0 cm" << endl; fout << "Field Size In: 10.0 cm" << endl; fout << "Data Type: Abs. Dose" << endl; fout << "Data Factor: 1.000" << endl; fout << "Data Unit: mGy" << endl; fout << "Length Unit: cm" << endl; fout << "Plane: " << "XY" << endl; fout << "No. of Columns: " << imgWidth << endl; fout << "No. of Rows: " << imgHeight << endl; fout << "Number of Bodies: " << 1 << endl; fout << "Operators Note: made by ykp" << endl; fout << "" << endl; fout << endl; fout << "" << endl; fout << "Plane Position: 0.00 cm" << endl; fout << endl; fout << "X[cm]" << "\t"; QString strTempX; double fPosX = 0.0; for (int i = 0; i < imgWidth; i++) { fPosX = (originX + i*spacingX) * 0.1;//mm --> cm fout << QString::number(fPosX, 'f', 3).toLocal8Bit().constData() << "\t"; } fout << endl; fout << "Y[cm]" << endl; QString strTempY; double fPosY = 0.0; //cm int imgVal = 0; // mGy, integer itk::ImageRegionConstIterator it(spFloatDose, spFloatDose->GetRequestedRegion()); it.GoToBegin(); float* pImg; pImg = new float [imgWidth*imgHeight]; int idx = 0; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { pImg[idx] = it.Get(); idx++; } for (int i = imgHeight - 1; i >= 0; i--) { //spacing: mm/px --> to make a cm, * 0.1 fPosY = (originY + i*spacingY) * 0.1; //--> Image writing From bottom to Top // Y value < 0 means Inferior in XY plane --> more make sense QString strYVal = QString::number(fPosY, 'f', 3); fout << strYVal.toLocal8Bit().constData() << "\t"; for (int j = 0; j < imgWidth; j++) { imgVal = qRound(pImg[imgWidth*i + j] * 1000); // Gy --> mGy fout << imgVal << "\t"; } fout << endl; } delete [] pImg; fout << "" << endl; fout << "" << endl; // POINT GetDataCenter();//data center index, 0 based // double m_spacingX; // mm/pixel //double m_spacingY;// mm/pixel fout.close(); return; } void gamma_gui::SLT_WhenSelectCombo() { QComboBox* crntCombo = ui.comboBoxCompareFile; int curIdx = crntCombo->currentIndex(); //this should be basename int iCnt = crntCombo->count(); if (iCnt < 1) return; if ((int)m_vRefDose.size() != iCnt || (int)m_strlistPath_RD_Read_Ref.size() != iCnt || (int)m_strlistPath_RD_Read_Comp.size() != iCnt || (int)m_strlistPath_Output_Gammamap.size() != iCnt) { cout << "Error! SLT_WhenSelectCombo file count doesn't match!" << endl; cout << "crntComboCnt " << iCnt << endl; cout << "m_vRefDose " << m_vRefDose.size() << endl; cout << "m_strlistPath_RD_Read_Ref " << m_strlistPath_RD_Read_Ref.size() << endl; cout << "m_strlistPath_RD_Read_Comp " << m_strlistPath_RD_Read_Comp.size() << endl; cout << "m_strlistPath_Output_Gammamap " << m_strlistPath_Output_Gammamap.size() << endl; return; } if ((int)(m_vRefDoseImages.size()) != iCnt || (int)(m_vCompDoseImages.size()) != iCnt || (int)(m_vGammaMapImages.size()) != iCnt) { cout << "Error! ItkImage Pointer count doesn't match!" << endl; return; } disconnect(ui.sliderNormRef, SIGNAL(valueChanged(int)), this, SLOT(SLT_DrawAll())); disconnect(ui.sliderNormComp, SIGNAL(valueChanged(int)), this, SLOT(SLT_DrawAll())); ui.sliderNormRef->setValue(qRound(m_vRefDose.at(curIdx) * 100)); //Gy to cGy ui.sliderNormComp->setValue(qRound(m_vRefDose.at(curIdx) * 100)); //Gy to cGy connect(ui.sliderNormRef, SIGNAL(valueChanged(int)), this, SLOT(SLT_DrawAll())); connect(ui.sliderNormComp, SIGNAL(valueChanged(int)), this, SLOT(SLT_DrawAll())); QString strPath_ref = m_strlistPath_RD_Read_Ref.at(curIdx); //always readable mha format QString strPath_comp = m_strlistPath_RD_Read_Comp.at(curIdx); QString strPath_gamma = m_strlistPath_Output_Gammamap.at(curIdx); QFileInfo info_ref = QFileInfo(strPath_ref); QFileInfo info_comp = QFileInfo(strPath_comp); bool bLowMem = ui.checkBox_low_mem->isChecked(); if (bLowMem) { /*FloatImageType::Pointer spImgRef = m_vRefDoseImages.at(curIdx); FloatImageType::Pointer spImgComp = m_vCompDoseImages.at(curIdx); FloatImageType::Pointer spImgGamma = m_vGammaMapImages.at(curIdx); */ cout << "Loading image from file. Index= " << curIdx << endl; QUTIL::LoadFloatImage3D(strPath_ref.toLocal8Bit().constData(), m_vRefDoseImages.at(curIdx)); QUTIL::LoadFloatImage3D(strPath_comp.toLocal8Bit().constData(), m_vCompDoseImages.at(curIdx)); QUTIL::LoadFloatImage3D(strPath_gamma.toLocal8Bit().constData(), m_vGammaMapImages.at(curIdx)); if (m_iLastLoadedIndex >= 0) { m_vRefDoseImages.at(m_iLastLoadedIndex) = m_spDummyLowMemImg; m_vCompDoseImages.at(m_iLastLoadedIndex) = m_spDummyLowMemImg; m_vGammaMapImages.at(m_iLastLoadedIndex) = m_spDummyLowMemImg; } m_iLastLoadedIndex = curIdx; } else { //do nothing } SLT_WhenChangePlane(); //RestorePanZoom + DrawAll //SLT_DrawAll(); } void gamma_gui::SLT_MouseWheelUpdateRef() { if (ui.labelReferDose->m_pYK16Image == NULL|| ui.labelCompDose->m_pYK16Image == NULL || ui.labelGammaMap3D->m_pYK16Image == NULL) { return; } QComboBox* crntCombo = ui.comboBoxCompareFile; int curIdx = crntCombo->currentIndex(); //this should be basename if (curIdx < 0) return; if (curIdx >= (int)(m_vRefDoseImages.size())) return; FloatImageType::Pointer spCurImg = m_vRefDoseImages.at(curIdx); VEC3D ptLimitStart = { 0.0, 0.0, 0.0 }; VEC3D ptLimitEnd = { 0.0, 0.0, 0.0 }; QUTIL::GetGeometricLimitFloatImg(spCurImg, ptLimitStart, ptLimitEnd); if (ui.checkBox_ScrollZoom->isChecked()) { double oldZoom = ui.labelReferDose->m_pYK16Image->m_fZoom; double fWeighting = 0.2; float vZoomVal = oldZoom + ui.labelReferDose->m_iMouseWheelDelta * fWeighting; ui.labelReferDose->m_pYK16Image->SetZoom(vZoomVal); ui.labelCompDose->m_pYK16Image->SetZoom(vZoomVal); ui.labelGammaMap3D->m_pYK16Image->SetZoom(vZoomVal); if (ui.labelGammaMap2D->m_pYK16Image != NULL) ui.labelGammaMap2D->m_pYK16Image->SetZoom(vZoomVal); } else //change slice { double fWeighting = 1.0; enPLANE curPlane = PLANE_AXIAL; float probePosX = ui.lineEdit_ProbePosX->text().toFloat(); float probePosY = ui.lineEdit_ProbePosY->text().toFloat(); float probePosZ = ui.lineEdit_ProbePosZ->text().toFloat(); if (ui.radioButtonAxial->isChecked()) { curPlane = PLANE_AXIAL; probePosZ = probePosZ + ui.labelReferDose->m_iMouseWheelDelta*fWeighting; if (probePosZ <= ptLimitStart.z) probePosZ = ptLimitStart.z; if (probePosZ >= ptLimitEnd.z) probePosZ = ptLimitEnd.z; ui.lineEdit_ProbePosZ->setText(QString::number(probePosZ, 'f', 1)); } else if (ui.radioButtonSagittal->isChecked()) { curPlane = PLANE_SAGITTAL; probePosX = probePosX + ui.labelReferDose->m_iMouseWheelDelta*fWeighting; if (probePosX <= ptLimitStart.x) probePosX = ptLimitStart.x; if (probePosX >= ptLimitEnd.x) probePosX = ptLimitEnd.x; ui.lineEdit_ProbePosX->setText(QString::number(probePosX, 'f', 1)); } else if (ui.radioButtonFrontal->isChecked()) { curPlane = PLANE_FRONTAL; probePosY = probePosY + ui.labelReferDose->m_iMouseWheelDelta*fWeighting; if (probePosY <= ptLimitStart.y) probePosY = ptLimitStart.y; if (probePosY >= ptLimitEnd.y) probePosY = ptLimitEnd.y; ui.lineEdit_ProbePosY->setText(QString::number(probePosY, 'f', 1)); } } SLT_DrawAll(); } void gamma_gui::SLT_MouseWheelUpdateComp() { if (ui.labelReferDose->m_pYK16Image == NULL || ui.labelCompDose->m_pYK16Image == NULL || ui.labelGammaMap3D->m_pYK16Image == NULL) { return; } QComboBox* crntCombo = ui.comboBoxCompareFile; int curIdx = crntCombo->currentIndex(); //this should be basename if (curIdx < 0) return; if (curIdx >= (int)(m_vRefDoseImages.size())) return; FloatImageType::Pointer spCurImg = m_vCompDoseImages.at(curIdx); VEC3D ptLimitStart = { 0.0, 0.0, 0.0 }; VEC3D ptLimitEnd = { 0.0, 0.0, 0.0 }; QUTIL::GetGeometricLimitFloatImg(spCurImg, ptLimitStart, ptLimitEnd); if (ui.checkBox_ScrollZoom->isChecked()) { double oldZoom = ui.labelCompDose->m_pYK16Image->m_fZoom; double fWeighting = 0.2; float vZoomVal = oldZoom + ui.labelCompDose->m_iMouseWheelDelta * fWeighting; ui.labelReferDose->m_pYK16Image->SetZoom(vZoomVal); ui.labelCompDose->m_pYK16Image->SetZoom(vZoomVal); ui.labelGammaMap3D->m_pYK16Image->SetZoom(vZoomVal); if (ui.labelGammaMap2D->m_pYK16Image != NULL) ui.labelGammaMap2D->m_pYK16Image->SetZoom(vZoomVal); } else //change slice { double fWeighting = 1.0; enPLANE curPlane = PLANE_AXIAL; float probePosX = ui.lineEdit_ProbePosX->text().toFloat(); float probePosY = ui.lineEdit_ProbePosY->text().toFloat(); float probePosZ = ui.lineEdit_ProbePosZ->text().toFloat(); if (ui.radioButtonAxial->isChecked()) { curPlane = PLANE_AXIAL; probePosZ = probePosZ + ui.labelCompDose->m_iMouseWheelDelta*fWeighting; if (probePosZ <= ptLimitStart.z) probePosZ = ptLimitStart.z; if (probePosZ >= ptLimitEnd.z) probePosZ = ptLimitEnd.z; ui.lineEdit_ProbePosZ->setText(QString::number(probePosZ, 'f', 1)); } else if (ui.radioButtonSagittal->isChecked()) { curPlane = PLANE_SAGITTAL; probePosX = probePosX + ui.labelCompDose->m_iMouseWheelDelta*fWeighting; if (probePosX <= ptLimitStart.x) probePosX = ptLimitStart.x; if (probePosX >= ptLimitEnd.x) probePosX = ptLimitEnd.x; ui.lineEdit_ProbePosX->setText(QString::number(probePosX, 'f', 1)); } else if (ui.radioButtonFrontal->isChecked()) { curPlane = PLANE_FRONTAL; probePosY = probePosY + ui.labelCompDose->m_iMouseWheelDelta*fWeighting; if (probePosY <= ptLimitStart.y) probePosY = ptLimitStart.y; if (probePosY >= ptLimitEnd.y) probePosY = ptLimitEnd.y; ui.lineEdit_ProbePosY->setText(QString::number(probePosY, 'f', 1)); } } SLT_DrawAll(); } void gamma_gui::SLT_MouseWheelUpdateGamma2D() { } void gamma_gui::SLT_MouseWheelUpdateGamma3D() { if (ui.labelReferDose->m_pYK16Image == NULL || ui.labelCompDose->m_pYK16Image == NULL || ui.labelGammaMap3D->m_pYK16Image == NULL) { return; } QComboBox* crntCombo = ui.comboBoxCompareFile; int curIdx = crntCombo->currentIndex(); //this should be basename if (curIdx < 0) return; if (curIdx >= (int)(m_vRefDoseImages.size())) return; FloatImageType::Pointer spCurImg = m_vGammaMapImages.at(curIdx); VEC3D ptLimitStart = { 0.0, 0.0, 0.0 }; VEC3D ptLimitEnd = { 0.0, 0.0, 0.0 }; QUTIL::GetGeometricLimitFloatImg(spCurImg, ptLimitStart, ptLimitEnd); if (ui.checkBox_ScrollZoom->isChecked()) { double oldZoom = ui.labelGammaMap3D->m_pYK16Image->m_fZoom; double fWeighting = 0.2; float vZoomVal = oldZoom + ui.labelGammaMap3D->m_iMouseWheelDelta * fWeighting; ui.labelReferDose->m_pYK16Image->SetZoom(vZoomVal); ui.labelCompDose->m_pYK16Image->SetZoom(vZoomVal); ui.labelGammaMap3D->m_pYK16Image->SetZoom(vZoomVal); if (ui.labelGammaMap2D->m_pYK16Image != NULL) ui.labelGammaMap2D->m_pYK16Image->SetZoom(vZoomVal); } else //change slice { double fWeighting = 1.0; enPLANE curPlane = PLANE_AXIAL; float probePosX = ui.lineEdit_ProbePosX->text().toFloat(); float probePosY = ui.lineEdit_ProbePosY->text().toFloat(); float probePosZ = ui.lineEdit_ProbePosZ->text().toFloat(); if (ui.radioButtonAxial->isChecked()) { curPlane = PLANE_AXIAL; probePosZ = probePosZ + ui.labelGammaMap3D->m_iMouseWheelDelta*fWeighting; if (probePosZ <= ptLimitStart.z) probePosZ = ptLimitStart.z; if (probePosZ >= ptLimitEnd.z) probePosZ = ptLimitEnd.z; ui.lineEdit_ProbePosZ->setText(QString::number(probePosZ, 'f', 1)); } else if (ui.radioButtonSagittal->isChecked()) { curPlane = PLANE_SAGITTAL; probePosX = probePosX + ui.labelGammaMap3D->m_iMouseWheelDelta*fWeighting; if (probePosX <= ptLimitStart.x) probePosX = ptLimitStart.x; if (probePosX >= ptLimitEnd.x) probePosX = ptLimitEnd.x; ui.lineEdit_ProbePosX->setText(QString::number(probePosX, 'f', 1)); } else if (ui.radioButtonFrontal->isChecked()) { curPlane = PLANE_FRONTAL; probePosY = probePosY + ui.labelGammaMap3D->m_iMouseWheelDelta*fWeighting; if (probePosY <= ptLimitStart.y) probePosY = ptLimitStart.y; if (probePosY >= ptLimitEnd.y) probePosY = ptLimitEnd.y; ui.lineEdit_ProbePosY->setText(QString::number(probePosY, 'f', 1)); } } SLT_DrawAll(); } void gamma_gui::SLT_MouseMoveUpdateRef() { } void gamma_gui::SLT_MouseMoveUpdateComp() { } void gamma_gui::SLT_MouseMoveUpdateGamma2D() { } void gamma_gui::SLT_MouseMoveUpdateGamma3D() { } void gamma_gui::SLT_RestoreZoomPan() { if (ui.labelReferDose->m_pYK16Image == NULL || ui.labelCompDose->m_pYK16Image == NULL || ui.labelGammaMap3D->m_pYK16Image == NULL) { return; } ui.labelReferDose->setFixedWidth(DEFAULT_LABEL_WIDTH); ui.labelReferDose->setFixedHeight(DEFAULT_LABEL_HEIGHT); ui.labelCompDose->setFixedWidth(DEFAULT_LABEL_WIDTH); ui.labelCompDose->setFixedHeight(DEFAULT_LABEL_HEIGHT); ui.labelGammaMap3D->setFixedWidth(DEFAULT_LABEL_WIDTH); ui.labelGammaMap3D->setFixedHeight(DEFAULT_LABEL_HEIGHT); ui.labelGammaMap2D->setFixedWidth(DEFAULT_LABEL_WIDTH); ui.labelGammaMap2D->setFixedHeight(DEFAULT_LABEL_HEIGHT); ui.labelReferDose->m_pYK16Image->SetZoom(1.0); ui.labelCompDose->m_pYK16Image->SetZoom(1.0); ui.labelGammaMap3D->m_pYK16Image->SetZoom(1.0); if (ui.labelGammaMap2D->m_pYK16Image != NULL) ui.labelGammaMap2D->m_pYK16Image->SetZoom(1.0); ui.labelReferDose->m_pYK16Image->SetOffset(0,0); ui.labelCompDose->m_pYK16Image->SetOffset(0, 0); ui.labelGammaMap3D->m_pYK16Image->SetOffset(0, 0); if (ui.labelGammaMap2D->m_pYK16Image != NULL) ui.labelGammaMap2D->m_pYK16Image->SetOffset(0, 0); } void gamma_gui::SLT_WhenChangePlane() { ///*ui.labelReferDose->setFixedWidth(DEFAULT_LABEL_WIDTH); //ui.labelReferDose->setFixedHeight(DEFAULT_LABEL_HEIGHT); //ui.labelCompDose->setFixedWidth(DEFAULT_LABEL_WIDTH); //ui.labelCompDose->setFixedHeight(DEFAULT_LABEL_HEIGHT); //ui.labelGammaMap3D->setFixedWidth(DEFAULT_LABEL_WIDTH); //ui.labelGammaMap3D->setFixedHeight(DEFAULT_LABEL_HEIGHT); //ui.labelGammaMap2D->setFixedWidth(DEFAULT_LABEL_WIDTH); //ui.labelGammaMap2D->setFixedHeight(DEFAULT_LABEL_HEIGHT); */ SLT_RestoreZoomPan(); SLT_DrawAll(); } void gamma_gui::SLT_MousePressedRightRef() { m_bMousePressedRightRef = true; WhenMousePressedRight(ui.labelReferDose); } void gamma_gui::WhenMousePressedRight(qyklabel* pWnd) { if (pWnd->m_pYK16Image == NULL) return; m_ptPanStart.setX(pWnd->x); m_ptPanStart.setY(pWnd->y); m_ptOriginalDataOffset.setX(pWnd->m_pYK16Image->m_iOffsetX); m_ptOriginalDataOffset.setY(pWnd->m_pYK16Image->m_iOffsetY); } void gamma_gui::SLT_MousePressedRightComp() { m_bMousePressedRightComp = true; WhenMousePressedRight(ui.labelCompDose); } void gamma_gui::SLT_MousePressedRightGamma3D() { m_bMousePressedRightGamma3D = true; WhenMousePressedRight(ui.labelGammaMap3D); } void gamma_gui::SLT_MousePressedRightGamma2D() { m_bMousePressedRightGamma2D = true; WhenMousePressedRight(ui.labelGammaMap2D); } void gamma_gui::SLT_MouseReleasedRightRef() { m_bMousePressedRightRef = false; } void gamma_gui::SLT_MouseReleasedRightComp() { m_bMousePressedRightComp = false; } void gamma_gui::SLT_MouseReleasedRightGamma3D() { m_bMousePressedRightGamma3D = false; } void gamma_gui::SLT_MouseReleasedRightGamma2D() { m_bMousePressedRightGamma2D = false; } void gamma_gui::UpdatePanCommon(qyklabel* qWnd) { if (qWnd->m_pYK16Image == NULL) return; double dspWidth = qWnd->width(); double dspHeight = qWnd->height(); int dataWidth = qWnd->m_pYK16Image->m_iWidth; int dataHeight = qWnd->m_pYK16Image->m_iHeight; if (dataWidth*dataHeight == 0) return; // int dataX = qWnd->GetDataPtFromMousePos().x(); // int dataY = qWnd->GetDataPtFromMousePos().y(); ////Update offset information of dispImage //GetOriginalDataPos (PanStart) //offset should be 0.. only relative distance matters. offset is in realtime changing QPoint ptDataPanStartRel = qWnd->View2DataExt(m_ptPanStart, dspWidth, dspHeight, dataWidth, dataHeight, QPoint(0, 0), qWnd->m_pYK16Image->m_fZoom); QPoint ptDataPanEndRel = qWnd->View2DataExt(QPoint(qWnd->x, qWnd->y), dspWidth, dspHeight, dataWidth, dataHeight, QPoint(0, 0), qWnd->m_pYK16Image->m_fZoom); //int dspOffsetX = pOverlapWnd->x - m_ptPanStart.x(); //int dspOffsetY = m_ptPanStart.y() - pOverlapWnd->y; /*QPoint ptDataStart= pOverlapWnd->GetDataPtFromViewPt(m_ptPanStart.x(), m_ptPanStart.y()); QPoint ptDataEnd= pOverlapWnd->GetDataPtFromViewPt(pOverlapWnd->x, pOverlapWnd->y);*/ int curOffsetX = ptDataPanEndRel.x() - ptDataPanStartRel.x(); int curOffsetY = ptDataPanEndRel.y() - ptDataPanStartRel.y(); int prevOffsetX = m_ptOriginalDataOffset.x(); int prevOffsetY = m_ptOriginalDataOffset.y(); //double fZoom = qWnd->m_pYK16Image->m_fZoom; qWnd->m_pYK16Image->SetOffset(prevOffsetX - curOffsetX, prevOffsetY - curOffsetY); //SLT_DrawAll(); } void gamma_gui::SLT_UpdatePanSettingRef() //Mouse Move { if (!m_bMousePressedRightRef) return; if (ui.labelReferDose->m_pYK16Image == NULL || ui.labelCompDose->m_pYK16Image == NULL || ui.labelGammaMap3D->m_pYK16Image == NULL) return; UpdatePanCommon(ui.labelReferDose); //Sync offset int offsetX = ui.labelReferDose->m_pYK16Image->m_iOffsetX; int offsetY = ui.labelReferDose->m_pYK16Image->m_iOffsetY; ui.labelCompDose->m_pYK16Image->SetOffset(offsetX, offsetY); ui.labelGammaMap3D->m_pYK16Image->SetOffset(offsetX, offsetY); if (ui.labelGammaMap2D->m_pYK16Image != NULL) ui.labelGammaMap2D->m_pYK16Image->SetOffset(offsetX, offsetY); SLT_DrawAll(); } void gamma_gui::SLT_UpdatePanSettingComp() { if (!m_bMousePressedRightComp) return; if (ui.labelReferDose->m_pYK16Image == NULL || ui.labelCompDose->m_pYK16Image == NULL || ui.labelGammaMap3D->m_pYK16Image == NULL) return; UpdatePanCommon(ui.labelCompDose); //Sync offset int offsetX = ui.labelCompDose->m_pYK16Image->m_iOffsetX; int offsetY = ui.labelCompDose->m_pYK16Image->m_iOffsetY; ui.labelReferDose->m_pYK16Image->SetOffset(offsetX, offsetY); ui.labelGammaMap3D->m_pYK16Image->SetOffset(offsetX, offsetY); if (ui.labelGammaMap2D->m_pYK16Image != NULL) ui.labelGammaMap2D->m_pYK16Image->SetOffset(offsetX, offsetY); SLT_DrawAll(); } void gamma_gui::SLT_UpdatePanSettingGamma3D() { if (!m_bMousePressedRightGamma3D) return; if (ui.labelReferDose->m_pYK16Image == NULL || ui.labelCompDose->m_pYK16Image == NULL || ui.labelGammaMap3D->m_pYK16Image == NULL) return; UpdatePanCommon(ui.labelGammaMap3D); //Sync offset int offsetX = ui.labelGammaMap3D->m_pYK16Image->m_iOffsetX; int offsetY = ui.labelGammaMap3D->m_pYK16Image->m_iOffsetY; ui.labelReferDose->m_pYK16Image->SetOffset(offsetX, offsetY); ui.labelCompDose->m_pYK16Image->SetOffset(offsetX, offsetY); if (ui.labelGammaMap2D->m_pYK16Image != NULL) ui.labelGammaMap2D->m_pYK16Image->SetOffset(offsetX, offsetY); SLT_DrawAll(); } void gamma_gui::SLT_UpdatePanSettingGamma2D() { return; } void gamma_gui::SLTM_RenameRDFilesByDICOMInfo() { QStringList files = QFileDialog::getOpenFileNames(this, "Select one or more files to open", m_strPathInputDir, "DICOM-RD files (*.dcm)"); int cnt = files.size(); if (cnt <= 0) return; QString strMsg = "Original file names will be gone. Backup is strongly recommended. Continue?"; QMessageBox msgBox; msgBox.setText(strMsg); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); int res = msgBox.exec(); if (res == QMessageBox::Yes) { } RenameFileByDCMInfo(files); } void gamma_gui::RenameFileByDCMInfo(QStringList& filenameList) { int size = filenameList.size(); QString crntFilePath; //Rt_study rt_study; for (int a = 0; a < size; a++) { crntFilePath = filenameList.at(a); //1) contructor Dcmtk_rt_study dss(crntFilePath.toLocal8Bit().constData()); //2) parse directory: this will link dicome seriese to proper one (e.g. ds_dose) dss.parse_directory(); Dcmtk_series *pDcmSeries = dss.d_ptr->ds_rtdose; if (pDcmSeries == NULL) continue; //Pt name: 0010, 0010 QString strPtId = QString(pDcmSeries->get_cstr(DcmTagKey(0x0010, 0x0020))); QString strRDType = QString(pDcmSeries->get_cstr(DcmTagKey(0x3004, 0x000A))); //QString strFractionGroup = QString(pDcmSeries->get_cstr(DcmTagKey(0x300C, 0x0022))); //QString strBeamNumberTmp = QString(pDcmSeries->get_cstr(DcmTagKey(0x300C, 0x0006))); //long int iFractionGroup = 0; //long int iBeamNumber = 0; DcmSequenceOfItems *seqRefPlan = 0; bool rc = pDcmSeries->get_sequence(DcmTagKey(0x300c, 0x0002), seqRefPlan); //rc = pDcmSeries->get_sequence(DcmTagKey(0x300C, 0x0020), seqFractionGroup); long int iValBeamNumber = 0; long int iValFractionGroupNumber = 0; if (rc) { //DcmSequenceOfItems *seqFractionGroup = 0; int iNumOfRefPlanSeq = (int)(seqRefPlan->card()); for (int i = 0; i < iNumOfRefPlanSeq; i++) { OFCondition orc; // const char *strVal = 0; DcmItem *itemRefPlan = seqRefPlan->getItem(i); //orc = item->findAndGetString(DcmTagKey(0x0008, 0x1150), strVal);//it works! /*orc = item->findAndGetLongInt(DcmTagKey(0x300C, 0x0022), iVal);*/ /*if (!orc.good()){ continue; }*/ DcmSequenceOfItems *seqFractionGroup = 0; //rc = pDcmSeries->get_sequence(DcmTagKey(0x300c, 0x0020), seqFractionGroup);//ReferencedFractionGroupSequence orc = itemRefPlan->findAndGetSequence(DCM_ReferencedFractionGroupSequence, seqFractionGroup);//ReferencedFractionGroupSequence if (orc.good()) { int iNumOfFractionGroup = seqFractionGroup->card(); DcmItem *itemFractionGroup = 0; for (int j = 0; j < iNumOfFractionGroup; j++) { itemFractionGroup = seqFractionGroup->getItem(j); DcmSequenceOfItems *seqRefBeam = 0; orc = itemFractionGroup->findAndGetLongInt(DCM_ReferencedFractionGroupNumber, iValFractionGroupNumber); //cout << "Group Number changed = " << iValFractionGroupNumber << endl; if (!orc.good()) cout << "error! refFraction group number is not found" << endl; orc = itemFractionGroup->findAndGetSequence(DCM_ReferencedBeamSequence, seqRefBeam);//ReferencedFractionGroupSequence if (!orc.good()) continue; int iNumOfRefBeam = seqRefBeam->card(); for (int k = 0; k < iNumOfRefBeam; k++) { DcmItem *itemBeam = 0; itemBeam = seqRefBeam->getItem(k); //orc = itemBeam->findAndGetLongInt(DcmTagKey(0x300C, 0x0006), iValBeamNumber); orc = itemBeam->findAndGetLongInt(DCM_ReferencedBeamNumber, iValBeamNumber); //cout << "iValBeamNumber changed = " << iValBeamNumber << endl; } } } } //iVal } //long int iFractionGroup = 0; //long int iBeamNumber = 0; //cout << "iFractionGroup " << iValFractionGroupNumber << endl; //cout << "iBeamNumber " << iValBeamNumber << endl; QString strFractionGroupNumber; strFractionGroupNumber = strFractionGroupNumber.sprintf("%02d", (int)iValFractionGroupNumber); QString strBeamNumber; strBeamNumber = strBeamNumber.sprintf("%03d", (int)iValBeamNumber); QFileInfo fileInfo = QFileInfo(crntFilePath); QDir dir = fileInfo.absoluteDir(); QString newBaseName = strPtId + "_" + strRDType + "_" + strFractionGroupNumber + "_" + strBeamNumber; //QString extStr = fileInfo.completeSuffix(); QString newFileName = newBaseName.append(".").append("dcm"); QString newPath = dir.absolutePath() + "/" + newFileName; //cout << newPath.toLocal8Bit().constData() << endl; //extract former part QFile::rename(crntFilePath, newPath); }// end of for, cout << "In total "<< size << " files were successfully renamed" << endl; } void gamma_gui::SaveCurrentGammaWorkSpace(QString& strPathGammaWorkSpace) { ofstream fout; fout.open(strPathGammaWorkSpace.toLocal8Bit().constData()); fout << "#GAMMA_WORK_SPACE_FILE V1.0#" << endl; int cntItem1 = m_strlistPath_RD_Read_Ref.size(); int cntItem2 = m_strlistPath_RD_Read_Comp.size(); int cntItem3 = m_strlistFileBaseName_Ref.size(); int cntItem4 = m_strlistFileBaseName_Comp.size(); //int cntItem5 = m_strlistBatchReport.size(); int cntItem5 = m_strlistPath_Output_Gammamap.size(); int cntItem6 = m_strlistPath_Output_Failure.size(); int cntItem7 = m_strlistPath_Output_Report.size(); int cntItem8 = m_vRefDose.size(); if (cntItem1 < 1 || cntItem1 != cntItem2 || cntItem1 != cntItem3 || cntItem1 != cntItem4 || cntItem1 != cntItem5 || cntItem1 != cntItem6 || cntItem1 != cntItem7 || cntItem1 != cntItem8 ) { cout << "Error! number of item doesn't match" << endl; return; } for (int i = 0; i < cntItem1; i++) { fout << endl; fout << "ITEM_ID" << "\t" << i << endl; fout << "RD_REF" << "\t" << m_strlistPath_RD_Read_Ref.at(i).toLocal8Bit().constData() << endl; fout << "RD_COMP" << "\t" << m_strlistPath_RD_Read_Comp.at(i).toLocal8Bit().constData() << endl; fout << "GAMMA_MAP" << "\t" << m_strlistPath_Output_Gammamap.at(i).toLocal8Bit().constData() << endl; fout << "BASE_REF" << "\t" << m_strlistFileBaseName_Ref.at(i).toLocal8Bit().constData() << endl; fout << "BASE_COMP" << "\t" << m_strlistFileBaseName_Comp.at(i).toLocal8Bit().constData() << endl; fout << "GAMMA_FAILURE" << "\t" << m_strlistPath_Output_Failure.at(i).toLocal8Bit().constData() << endl; fout << "GAMMA_REPORT" << "\t" << m_strlistPath_Output_Report.at(i).toLocal8Bit().constData() << endl; fout << "REF_DOSE[Gy]" << "\t" << m_vRefDose.at(i) << endl; fout << endl; } int numOfLinesInSimpleReport = m_strlistBatchReport.count(); fout << "#BATCH_SIMPLE_REPORT" << endl; for (int i = 0; i < numOfLinesInSimpleReport; i++) { fout << m_strlistBatchReport.at(i).toLocal8Bit().constData() << endl; } fout.close(); } bool gamma_gui::LoadGammaWorkSpace(QString& strPathGammaWorkSpace) { ifstream fin; fin.open(strPathGammaWorkSpace.toLocal8Bit().constData()); if (fin.fail()) { cout << "Error occurred in file reading!" << endl; return false; } //clear all the data m_strlistPath_RD_Read_Ref.clear(); m_strlistPath_RD_Read_Comp.clear(); m_strlistPath_Output_Gammamap.clear(); m_strlistFileBaseName_Ref.clear(); m_strlistFileBaseName_Comp.clear(); m_strlistPath_Output_Failure.clear(); m_strlistPath_Output_Report.clear(); m_vRefDose.clear(); m_strlistBatchReport.clear(); ////This will be also done in loading to mem //m_vRefDoseImages.clear(); //m_vCompDoseImages.clear(); //m_vGammaMapImages.clear(); char str[MAX_LINE_LENGTH]; while (!fin.eof()) { memset(str, 0, MAX_LINE_LENGTH); fin.getline(str, MAX_LINE_LENGTH); QString tmpStr = QString(str); QString trimmed; if (tmpStr.contains("ITEM_ID")) //go into subloop { while (!fin.eof()) { memset(str, 0, MAX_LINE_LENGTH); fin.getline(str, MAX_LINE_LENGTH); tmpStr = QString(str); trimmed = tmpStr.trimmed(); //if any blank line found if (trimmed.length() < 1) break; //parsing QStringList strListTmp = tmpStr.split("\t"); if (tmpStr.contains("RD_REF") && strListTmp.count() == 2) //go into subloop m_strlistPath_RD_Read_Ref.push_back(strListTmp.at(1)); else if (tmpStr.contains("RD_COMP") && strListTmp.count() == 2) //go into subloop m_strlistPath_RD_Read_Comp.push_back(strListTmp.at(1)); else if (tmpStr.contains("GAMMA_MAP") && strListTmp.count() == 2) //go into subloop m_strlistPath_Output_Gammamap.push_back(strListTmp.at(1)); else if (tmpStr.contains("BASE_REF") && strListTmp.count() == 2) //go into subloop m_strlistFileBaseName_Ref.push_back(strListTmp.at(1)); else if (tmpStr.contains("BASE_COMP") && strListTmp.count() == 2) //go into subloop m_strlistFileBaseName_Comp.push_back(strListTmp.at(1)); else if (tmpStr.contains("GAMMA_FAILURE") && strListTmp.count() == 2) //go into subloop m_strlistPath_Output_Failure.push_back(strListTmp.at(1)); else if (tmpStr.contains("GAMMA_REPORT") && strListTmp.count() == 2) //go into subloop m_strlistPath_Output_Report.push_back(strListTmp.at(1)); else if (tmpStr.contains("REF_DOSE[Gy]") && strListTmp.count() == 2) //go into subloop m_vRefDose.push_back(strListTmp.at(1).toFloat()); } }//end of ITEM if (tmpStr.contains("BATCH_SIMPLE_REPORT")) { while (!fin.eof()) { memset(str, 0, MAX_LINE_LENGTH); fin.getline(str, MAX_LINE_LENGTH); tmpStr = QString(str); trimmed = tmpStr.trimmed(); //if any blank line found if (trimmed.length() < 1) continue; m_strlistBatchReport.push_back(tmpStr); } } } //ui.plainTextEdit_RD_Comp->clear(); //m_strlistPath_RD_Comp.clear(); //m_strlistFileBaseName_Comp.clear(); //m_strlistPath_RD_Comp = tmpList; //for (int i = 0; i < iFileCnt; i++) //{ // ui.plainTextEdit_RD_Comp->appendPlainText(m_strlistPath_RD_Comp.at(i)); //just for display // QFileInfo tmpInfo = QFileInfo(m_strlistPath_RD_Comp.at(i)); // m_strlistFileBaseName_Comp.push_back(tmpInfo.completeBaseName()); //} //cout << "File names are successfully loaded" << endl; fin.close(); return true; } void gamma_gui::SLTM_LoadSavedWorkSpace() { QString strPath = QFileDialog::getOpenFileName(this, "Select a gamma workspace file to open", m_strPathDirWorkDir, "AccuGamma workspace file (*.gws)"); if (strPath.length() <= 1) return; if (!LoadGammaWorkSpace(strPath)) //Only reading text files to fill up the vectors, without any auditing { QUTIL::ShowErrorMessage("Error! failed in loading workspace file"); return; } QFileInfo fileInfo(strPath); QDir dir = fileInfo.absoluteDir(); SetWorkDir(dir.absolutePath()); bool bOK = true; QString strWorkDirPath = dir.absolutePath(); //1) Update the previous fileList and convert them according to current wo //rkspace //Get current workspace directoroy //QString ReplaceUpperDirOnly(QString& strOriginalPath, QString& strCurrDirPath, QString& strDelim); int cntItem0 = m_strlistPath_RD_Read_Ref.count(); int cntItem1 = m_strlistPath_RD_Read_Comp.count(); int cntItem2 = m_strlistPath_Output_Gammamap.count(); int cntItem3 = m_strlistPath_Output_Report.count(); int cntItem4 = m_strlistPath_Output_Failure.count(); //not mandatory if (cntItem0 < 1 || cntItem0 != cntItem1 || cntItem0 != cntItem2 || cntItem0 != cntItem3 ) { QUTIL::ShowErrorMessage("Error! Number of read files are not matching each other!"); cout << "RD_ref= " << cntItem0 << endl; cout << "RD_comp= " << cntItem1 << endl; cout << "Gamma= " << cntItem2 << endl; cout << "TxtReport= " << cntItem3 << endl; cout << "Failure= " << cntItem4 << endl; bOK = false; } int cnt = cntItem0; if (!bOK) { SetWorkDir(QString(""));//roll back return; } QString strDelimRef = "DoseRef_"; QString strDelimComp = "DoseComp_"; QString strDelimGamma = "Analysis_"; QString strDelimText = "Analysis_"; QString strDelimFail = "Analysis_"; QString originalPath; QString newPath; //Update file Path for (int i = 0; i < cnt; i++) { originalPath = m_strlistPath_RD_Read_Ref.at(i); newPath = ReplaceUpperDirOnly(originalPath, strWorkDirPath, strDelimRef); m_strlistPath_RD_Read_Ref.replace(i, newPath); originalPath = m_strlistPath_RD_Read_Comp.at(i); newPath = ReplaceUpperDirOnly(originalPath, strWorkDirPath, strDelimComp); m_strlistPath_RD_Read_Comp.replace(i, newPath); originalPath = m_strlistPath_Output_Gammamap.at(i); newPath = ReplaceUpperDirOnly(originalPath, strWorkDirPath, strDelimGamma); m_strlistPath_Output_Gammamap.replace(i, newPath); originalPath = m_strlistPath_Output_Report.at(i); newPath = ReplaceUpperDirOnly(originalPath, strWorkDirPath, strDelimText); m_strlistPath_Output_Report.replace(i, newPath); originalPath = m_strlistPath_Output_Failure.at(i); newPath = ReplaceUpperDirOnly(originalPath, strWorkDirPath, strDelimFail); m_strlistPath_Output_Failure.replace(i, newPath); } SLT_LoadResults(); } QString gamma_gui::ReplaceUpperDirOnly(QString& strOriginalPath, QString& strCurrDirPath, QString& strDelim) { QStringList strListPath = strOriginalPath.split("/"); //if (strListPath.count() < 1) // strListPath = strOriginalPath.split("/"); int cnt = strListPath.count(); int idx = 0; int cntSecondary = 0; for (int i = 0; i < cnt; i++) { if (strListPath.at(i).contains(strDelim)) { idx = i; cntSecondary++; } } if (cntSecondary > 1) { cout << "ERROR! strDelim should be shown once" << endl; return strOriginalPath; } QString strLower; for (int i = idx; i < cnt; i++) { strLower = strLower + "/" + strListPath.at(i); } QString newPath = strCurrDirPath + strLower; return newPath; } void gamma_gui::SLT_SetWorkDir() { //default: current one m_strPathDirWorkDir QString dirPath = QFileDialog::getExistingDirectory(this, tr("Open Gamma Work Directory"), m_strPathDirWorkDir, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); QDir dirIMAGES = QDir(dirPath); if (!dirIMAGES.exists()) return; SetWorkDir(dirPath); } void gamma_gui::SetWorkDir(const QString& strPath) { m_strPathDirWorkDir = strPath; ui.lineEdit_WorkDir->setText(m_strPathDirWorkDir); } void gamma_gui::SLTM_ExportBatchReport() { QString filePath = QFileDialog::getSaveFileName(this, "Save batch report file", m_strPathDirWorkDir, "report (*.txt)", 0, 0); if (filePath.length() < 1) return; QFileInfo fInfo(filePath); if (fInfo.suffix() != "txt" && fInfo.suffix() != "TXT") { cout << "Saving filter didn't work. Saving this file as txt." << endl; filePath = filePath + ".txt"; } SaveBatchGamma3DSimpleReport(filePath); } void gamma_gui::SLTM_LoadProtonDoseSetFile() { QStringList tmpList = QFileDialog::getOpenFileNames(this, "Select proton dose set file to open", m_strPathDirWorkDir, "Proton dose set file (*.set)"); int iFileCnt = tmpList.size(); if (iFileCnt < 1) return; vector vProtonSetHeader; for (int i = 0; i < iFileCnt; i++) { QString curTextSetFilePath = tmpList.at(i); ProtonSetFileMGH tmpProtonSetHeader; //Read text and fill the class with as it is. if (!ReadProtonDoseSet(curTextSetFilePath, tmpProtonSetHeader)) //Only reading text files to fill up the vectors, without any auditing { //do nothing } cout << "FilePathRef= " << tmpProtonSetHeader.strPathRefDose.toLocal8Bit().constData() << endl; cout << "FilePathComp= " << tmpProtonSetHeader.strPathCompDose.toLocal8Bit().constData() << endl; QFileInfo fInfoRef(tmpProtonSetHeader.strPathRefDose); QFileInfo fInfoComp(tmpProtonSetHeader.strPathCompDose); if (fInfoRef.exists() && fInfoComp.exists()) //both files should exists. { vProtonSetHeader.push_back(tmpProtonSetHeader); } } if (vProtonSetHeader.empty()) { cout << "Error. No file was found" << endl; return; } //Ref clear ui.plainTextEdit_RD_Ref->clear(); m_strlistPath_RD_Original_Ref.clear(); m_strlistFileBaseName_Ref.clear(); //Comp Clear ui.plainTextEdit_RD_Comp->clear(); m_strlistPath_RD_Original_Comp.clear(); m_strlistFileBaseName_Comp.clear(); //output clear m_strlistPath_Output_Gammamap.clear(); m_strlistPath_Output_Failure.clear(); m_strlistPath_Output_Report.clear(); m_strlistBatchReport.clear(); //Ref dose clear; m_vRefDose.clear(); //Conversion vector::iterator it; for (it = vProtonSetHeader.begin(); it != vProtonSetHeader.end(); ++it) { ProtonSetFileMGH tempDoseSet = (*it); QString strPathMhaRef = ConvertMGHProtonDoseToMha(tempDoseSet.strPathRefDose, tempDoseSet.fDim, tempDoseSet.fOrigin, tempDoseSet.fSpacing); QString strPathMhaComp = ConvertMGHProtonDoseToMha(tempDoseSet.strPathCompDose, tempDoseSet.fDim, tempDoseSet.fOrigin, tempDoseSet.fSpacing); QFileInfo fInfoMhaRef(strPathMhaRef); QFileInfo fInfoMhaComp(strPathMhaComp); if (fInfoMhaRef.exists()) { m_strlistPath_RD_Original_Ref.push_back(strPathMhaRef); m_strlistFileBaseName_Ref.push_back(fInfoMhaRef.completeBaseName()); ui.plainTextEdit_RD_Ref->appendPlainText(strPathMhaRef); //just for display } if (fInfoMhaComp.exists()) { m_strlistPath_RD_Original_Comp.push_back(strPathMhaComp); m_strlistFileBaseName_Comp.push_back(fInfoMhaComp.completeBaseName()); ui.plainTextEdit_RD_Comp->appendPlainText(strPathMhaComp); //just for display } } if (m_strlistPath_RD_Original_Ref.size() > 0) { QFileInfo finfo(m_strlistPath_RD_Original_Ref.at(0)); QDir crntDir = finfo.absoluteDir(); m_strPathInputDir = crntDir.absolutePath(); SetWorkDir(m_strPathInputDir); //optional //Change the plane to Frontal ui.radioButtonFrontal->setChecked(true); } } bool gamma_gui::ReadProtonDoseSet(QString& strPathProtonDoseSet, ProtonSetFileMGH& protonSetInfo) //strPathProtonDoseSet text file { //protonSetInfo /*protonSetInfo.fDim = { 1.0, 1.0, 1.0 }; protonSetInfo.fOrigin = { 0.0, 0.0, 0.0 }; protonSetInfo.fSpacing = { 1.0, 1.0, 1.0 };*/ protonSetInfo.fDim.x = 1.0; protonSetInfo.fDim.y = 1.0; protonSetInfo.fDim.z = 1.0; protonSetInfo.fOrigin.x = 0.0; protonSetInfo.fOrigin.y = 0.0; protonSetInfo.fOrigin.z = 0.0; protonSetInfo.fSpacing.x = 1.0; protonSetInfo.fSpacing.y = 1.0; protonSetInfo.fSpacing.z = 1.0; protonSetInfo.strCTDir = ""; protonSetInfo.strPathRefDose = ""; protonSetInfo.strPathCompDose = ""; QFileInfo fInfoBase(strPathProtonDoseSet); ifstream fin; fin.open(strPathProtonDoseSet.toLocal8Bit().constData()); if (fin.fail()) { cout << "Error occurred in file reading!" << endl; return false; } char str[MAX_LINE_LENGTH]; while (!fin.eof()) { memset(str, 0, MAX_LINE_LENGTH); fin.getline(str, MAX_LINE_LENGTH); QString tmpStrLine = QString(str); QStringList strListData = tmpStrLine.split(" \""); QString strHeader, strData; if (strListData.count() == 2) { strHeader = strListData.at(0); strData = strListData.at(1); strData = strData.remove("\""); } strData = strData.trimmed(); //very important for Linux system!!!!! if (strHeader.contains("calc-vol")) { QStringList strlistVolInfo = strData.split(","); if (strlistVolInfo.count() == 9) //should be { //First 3 digits: size in mm. X (Lat), Y(SI), Z(AntPost), IEC VEC3D fLength, fOrigin, fDim, fSpacing; fLength.x = strlistVolInfo.at(0).toDouble(); fLength.y = strlistVolInfo.at(1).toDouble(); fLength.z = strlistVolInfo.at(2).toDouble(); fOrigin.x = strlistVolInfo.at(3).toDouble(); fOrigin.y = strlistVolInfo.at(4).toDouble(); fOrigin.z = strlistVolInfo.at(5).toDouble(); fDim.x = strlistVolInfo.at(6).toDouble(); fDim.y = strlistVolInfo.at(7).toDouble(); fDim.z = strlistVolInfo.at(8).toDouble(); if (fDim.x != 0 && fDim.y != 0 && fDim.z != 0) { fSpacing.x = fLength.x / fDim.x; fSpacing.y = fLength.y / fDim.y; fSpacing.z = fLength.z / fDim.z; } else { fSpacing.x = 1.0; fSpacing.y = 1.0; fSpacing.z = 1.0; } protonSetInfo.fDim = fDim; protonSetInfo.fOrigin = fOrigin; protonSetInfo.fSpacing = fSpacing; } } else if (strHeader.contains("ct-dir")) { protonSetInfo.strCTDir = strData; } else if (strHeader.trimmed() == "dose") { strData = strData + ".MC"; protonSetInfo.strPathCompDose = fInfoBase.absolutePath() + "/" +strData; } else if (strHeader.trimmed() == "ref-dose") { strData = strData + ".orig"; protonSetInfo.strPathRefDose = fInfoBase.absolutePath() + "/" + strData; } } fin.close(); return true; } QString gamma_gui::ConvertMGHProtonDoseToMha(QString& strPathBinary, VEC3D& fDim, VEC3D& fOrigin, VEC3D& fSpacing) { QString strResult = ""; ///Create a mha file QFileInfo fInfo(strPathBinary); if (!fInfo.exists()) { cout << "Cannot find the binary file: " << strPathBinary.toLocal8Bit().constData() << endl; return strResult; } QFile binFile(strPathBinary); binFile.open(QIODevice::ReadOnly); QDataStream in(&binFile); in.setByteOrder(QDataStream::BigEndian); //qint32 voxData; quint32 voxData; //Coordinate conversion: IEC --> DICOM --> not possible! //fDim = IEC int width_DCM = (int)fDim.x; // int height_DCM = (int)fDim.z; // int length_DCM = (int)fDim.y; // //Create a float itk image 3D FloatImageType::Pointer spItkFloat = FloatImageType::New(); FloatImageType::SizeType size; size[0] = width_DCM; size[1] = height_DCM; size[2] = length_DCM; FloatImageType::IndexType idxStart; idxStart[0] = 0; idxStart[1] = 0; idxStart[2] = 0; FloatImageType::SpacingType spacing; spacing[0] = fSpacing.x; spacing[1] = fSpacing.z; spacing[2] = fSpacing.y; FloatImageType::PointType origin; origin[0] = fOrigin.x; origin[1] = -fOrigin.z; origin[2] = fOrigin.y; FloatImageType::RegionType region; region.SetSize(size); region.SetIndex(idxStart); spItkFloat->SetRegions(region); spItkFloat->SetSpacing(spacing); spItkFloat->SetOrigin(origin); spItkFloat->Allocate(); /*ofstream fout; fout.open("D:/testDoseOut.txt");*/ //itk::ImageRegionIterator it(spItkFloat, spItkFloat->GetLargestPossibleRegion()); itk::ImageSliceIteratorWithIndex it(spItkFloat, spItkFloat->GetLargestPossibleRegion()); it.SetFirstDirection(0); //dicom x it.SetSecondDirection(2); //dicom z. -2 doesn't work it.GoToBegin(); //for (int k = 3; k < 4; k++) float doseGyVal = 0.0; for (int k = 0; k < height_DCM && !it.IsAtEnd(); k++) { for (int i = 0; i < length_DCM && !it.IsAtEndOfSlice(); i++) //coronal plane { for (int j = 0; j < width_DCM && !it.IsAtEndOfLine(); j++) { //converted mha file: Gy, float //current file: cGy, uint in >> voxData; doseGyVal = voxData / 100.0; //cGy to Gy it.Set(doseGyVal); ++it; // fout << voxData << ","; } it.NextLine(); // fout << endl; } it.NextSlice(); //fout << "Plane=" << k << endl; } binFile.close(); typedef itk::FlipImageFilter< FloatImageType > FilterType; FilterType::Pointer flipFilter = FilterType::New(); typedef FilterType::FlipAxesArrayType FlipAxesArrayType; FlipAxesArrayType arrFlipAxes; arrFlipAxes[0] = 0; arrFlipAxes[1] = 0; arrFlipAxes[2] = 1;//SI flip flipFilter->SetFlipAxes(arrFlipAxes); flipFilter->SetInput(spItkFloat); //plan CT, USHORT image flipFilter->Update(); spItkFloat = flipFilter->GetOutput(); spItkFloat->SetOrigin(origin); //origin was reverted after the flipping QString strDirPath = fInfo.absolutePath(); QString strFileName = fInfo.fileName() + ".mha"; strResult = strDirPath + "/" + strFileName; typedef itk::ImageFileWriter WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetFileName(strResult.toLocal8Bit().constData()); writer->SetUseCompression(true); //not exist in original code (rtkfdk) writer->SetInput(spItkFloat); writer->Update(); //cout << "Writing image file was succeeded: " << strPath.toLocal8Bit().constData() << endl; //fout.close(); QFileInfo fInfoOut(strResult); if (!fInfoOut.exists()) { strResult = ""; cout << "Error!File conversion failed" << endl; } else cout << "Successfully converted to a mha file:" << strResult.toLocal8Bit().constData() < vXVal; vector vYVal; float* pFloatImg = NULL; int imgSize = 0; while (!fin.eof()) { memset(str, 0, MAX_LINE_LENGTH); fin.getline(str, MAX_LINE_LENGTH); QString tmpStr = QString(str); QString trimmed; QStringList strListLine; QString strHeader; QString strData; if (tmpStr.contains("")) //go into subloop { while (!fin.eof()) { strHeader = ""; strData = ""; memset(str, 0, MAX_LINE_LENGTH); fin.getline(str, MAX_LINE_LENGTH); tmpStr = QString(str); strListLine = tmpStr.split(" ");// at least two consec. spaces if (strListLine.count() >= 2) { strHeader = strListLine.at(0); strData = tmpStr.right(tmpStr.length() - strHeader.length()); strData = strData.trimmed(); } //trimmed = tmpStr.trimmed(); //if any blank line found //if (trimmed.length() < 1) // break; if (strHeader.contains("Data Type:") && strData.length() > 0) //go into subloop { if (strData.contains("Abs. Dose")) bAbsDose = true; else bAbsDose = false; } else if (strHeader.contains("Data Factor:") && strData.length() > 0) //go into subloop { fDataFactor = strData.toDouble(); } else if (strHeader.contains("Data Unit:") && strData.length() > 0) //go into subloop { strDataUnit = strData; if (!strDataUnit.contains("mGy")) { cout << "Error! unit should be mGy. Current = " << strDataUnit.toLocal8Bit().constData() << endl; } } else if (strHeader.contains("Length Unit:") && strData.length() > 0) //go into subloop { strLengthUnit = strData; if (!strLengthUnit.contains("cm")) { cout << "Error! unit should be cm. Current = " << strLengthUnit.toLocal8Bit().constData() << endl; } } else if (strHeader.contains("No. of Columns:") && strData.length() > 0) //go into subloop { iColumns = strData.toInt(); } else if (strHeader.contains("No. of Rows:") && strData.length() > 0) //go into subloop { iRows = strData.toInt(); } else if (strHeader.contains("Number of Bodies:") && strData.length() > 0) //go into subloop { iBody = strData.toInt(); } else if (strHeader.contains("Operators Note:") && strData.length() > 0) //go into subloop { strNote = strData; } //else if (strHeader.contains("")) //go into subloop else if (tmpStr.contains("")) //go into subloop { break; } }// end of while }//end of if tmpStr.contains("" if (tmpStr.contains("")) //go into subloop { imgSize = iColumns*iRows; if (imgSize > 1) pFloatImg = new float[imgSize]; while (!fin.eof()) { memset(str, 0, MAX_LINE_LENGTH); fin.getline(str, MAX_LINE_LENGTH); tmpStr = QString(str); if (tmpStr.contains("X[cm]")) { strListLine = tmpStr.split(" "); int iCntItem = strListLine.count(); vXVal.clear(); QStringList strListValidX; QString strTestX; for (int i = 1; i 0) { strListValidX.push_back(strTestX); } } int iValidXCnt = strListValidX.count(); cout << "Valid only" << endl; for (int i = 0; i < iValidXCnt; i++) { vXVal.push_back(strListValidX.at(i).toDouble()); cout << strListValidX.at(i).toDouble() << endl; } /*if ((int)(vXVal.size()) != iColumns) { cout << "Error! X[cm] data count = " << vXVal.size() << ", X header info = " << iColumns << endl; return false; } */ } else if (tmpStr.contains("Y[cm]")) { vYVal.clear(); int iYLineCnt = 0; while (!fin.eof()) { memset(str, 0, MAX_LINE_LENGTH); fin.getline(str, MAX_LINE_LENGTH); tmpStr = QString(str); if (tmpStr.contains("")) break; strListLine = tmpStr.split("\t");// at least two consec. spaces int iDataCnt = strListLine.count(); if (iDataCnt > 1) { vYVal.push_back(strListLine.at(0).toDouble()); } QStringList strListValid; QString strTest; for (int i = 1; i 0) { strListValid.push_back(strTest); } } if (strListValid.count() != iColumns) { cout << "Error! X data count = " << strListValid.count() << " vs " << iColumns << endl; return false; } int curIdx = 0; for (int i = 0; i < iColumns; i++) { curIdx = iColumns*iYLineCnt + i; if (curIdx < imgSize) pFloatImg[curIdx] = (strListValid.at(i).toDouble())*fDataFactor / 1000.0; //Unit: Gy } iYLineCnt++; }//end of sub while if (iYLineCnt != iRows) { cout << "Error! Y data count = " << iYLineCnt << " vs " << iRows << endl; return false; } }// end of Y cm }//end of asciibody while }//if asciibody } // main while fin.close(); //img array to itk image if (vXVal.size() < 2 || vYVal.size() < 2) return false; FloatImage2DType::PointType ptOriginItk; FloatImage2DType::SizeType imgSizeItk; FloatImage2DType::SpacingType imgSpacingItk; ptOriginItk[0] = vXVal.at(0)*10.0; ptOriginItk[1] = vYVal.at(0)*10.0; imgSizeItk[0] = iColumns; imgSizeItk[1] = iRows; imgSpacingItk[0] = fabs(vXVal.at(1) - vXVal.at(0))*10.0; // cm to mm imgSpacingItk[1] = fabs(vYVal.at(1) - vYVal.at(0))*10.0; FloatImage2DType::IndexType idxStart; idxStart[0] = 0; idxStart[1] = 0; FloatImage2DType::RegionType region; region.SetSize(imgSizeItk); region.SetIndex(idxStart); FloatImage2DType::Pointer spFloatDoseImg = FloatImage2DType::New(); spFloatDoseImg->SetRegions(region); spFloatDoseImg->SetSpacing(imgSpacingItk); spFloatDoseImg->SetOrigin(ptOriginItk); spFloatDoseImg->Allocate(); spFloatDoseImg->FillBuffer(0.0); itk::ImageRegionIterator it(spFloatDoseImg, spFloatDoseImg->GetLargestPossibleRegion()); int idx = 0; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { if (idx < imgSize) { float curVal = pFloatImg[idx]; it.Set(curVal); } idx++; } if (pFloatImg != NULL) delete[] pFloatImg; QUTIL::SaveFloatImage2D(strFilePathMHA.toLocal8Bit().constData(), spFloatDoseImg); return true; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/gamma_gui.h000066400000000000000000000137571321604176500310630ustar00rootroot00000000000000#ifndef GAMMA_GUI_H #define GAMMA_GUI_H #include #include "ui_gamma_gui.h" #include #include #include "yk_config.h" //#include "itkImageFileReader.h" //#include "itkImageFileWriter.h" #include "itk_image_type.h" //#include "YK16GrayImage.h" //#include using namespace std; class Gamma_parms; class DlgGammaView; class YK16GrayImage; class qyklabel; class QStandardItemModel; class gamma_gui : public QMainWindow { Q_OBJECT public: gamma_gui(QWidget *parent = 0, Qt::WFlags flags = 0); ~gamma_gui(); QString GammaMain(Gamma_parms* parms, float& refDoseGy, const QString& strPathBkupRef = QString(""), const QString& strPathBkupComp = QString("")); void Load_FilesToMem();//all ref, comp, gamma map should be prepared void UpdateProbePos(qyklabel* qlabel); void UpdateTable(vector& vData1, vector& vData2, vector& vData3, float fNorm1, float fNorm2, float fNorm3, float fMag1, float fMag2, float fMag3); void WhenMousePressedRight(qyklabel* pWnd); void UpdatePanCommon(qyklabel* qWnd); void RenameFileByDCMInfo(QStringList& filenameList); void SaveCurrentGammaWorkSpace(QString& strPathGammaWorkSpace); bool LoadGammaWorkSpace(QString& strPathGammaWorkSpace); bool ReadProtonDoseSet(QString& strPathProtonDoseSet, ProtonSetFileMGH& protonSetInfo); void SaveBatchGamma3DSimpleReport(QString& strFilePath); void SetWorkDir(const QString& strPath); QString ReplaceUpperDirOnly(QString& strOriginalPath, QString& strCurrDirPath, QString& strDelim); QString ConvertMGHProtonDoseToMha(QString& strPathBinnary, VEC3D& fDim, VEC3D& fOrigin, VEC3D& fSpacing); bool ConvertOPG2FloatMHA(QString& strFilePathOPG, QString& strFilePathMHA); public slots: void SLT_Load_RD_Ref(); void SLT_Load_RD_Comp(); void SLT_LoadResults(); void SLT_RunBatchGamma(); void SLT_ProfileView(); void SLT_DrawDoseImages();// refer to probe positions, selected 3D file (spPointer), plane direction void SLT_DrawGammaMap3D(); void SLT_DrawGammaMap2D(); void SLT_UpdateComboContents(); void SLT_WhenSelectCombo(); void SLT_DrawAll(); void SLT_DrawTable(); void SLT_DrawChart(); void SLT_WhenChangePlane();//restore zoom and pan then draw all void SLT_UpdateReportTxt(); void SLT_UpdateProbePosRef(); void SLT_UpdateProbePosComp(); void SLT_UpdateProbePosGamma2D(); void SLT_UpdateProbePosGamma3D(); void SLT_CopyTableToClipboard(); //void SLT_DrawGraph(); void SLT_DrawGraph(bool bInitMinMax = false); void SLT_RunGamma2D(); void SLT_GoCenterPosRef(); void SLT_GoCenterPosComp(); void SLT_NormCompFromRefNorm(); void SaveDoseIBAGenericTXTFromItk(QString strFilePath, FloatImage2DType::Pointer& spFloatDose); void SLT_MouseWheelUpdateRef(); void SLT_MouseWheelUpdateComp(); void SLT_MouseWheelUpdateGamma2D(); void SLT_MouseWheelUpdateGamma3D(); void SLT_RestoreZoomPan(); void SLT_MouseMoveUpdateRef(); void SLT_MouseMoveUpdateComp(); void SLT_MouseMoveUpdateGamma2D(); void SLT_MouseMoveUpdateGamma3D(); void SLT_MousePressedRightRef(); void SLT_MousePressedRightComp(); void SLT_MousePressedRightGamma3D(); void SLT_MousePressedRightGamma2D(); void SLT_MouseReleasedRightRef(); void SLT_MouseReleasedRightComp(); void SLT_MouseReleasedRightGamma3D(); void SLT_MouseReleasedRightGamma2D(); void SLT_UpdatePanSettingRef(); void SLT_UpdatePanSettingComp(); void SLT_UpdatePanSettingGamma3D(); void SLT_UpdatePanSettingGamma2D(); void SLTM_RenameRDFilesByDICOMInfo(); void SLTM_LoadSavedWorkSpace(); void SLTM_SaveBatchModeSimpleReport(); void SLT_SetWorkDir(); void SLTM_ExportBatchReport(); void SLTM_LoadProtonDoseSetFile(); void SLTM_ConvertIBAOPG_Files(); public: QStringList m_strlistPath_RD_Original_Ref; //RD files, before the conversion QStringList m_strlistPath_RD_Original_Comp; QStringList m_strlistPath_RD_Read_Ref; //mha files, after the conversion QStringList m_strlistPath_RD_Read_Comp; QStringList m_strlistFileBaseName_Ref; QStringList m_strlistFileBaseName_Comp; QStringList m_strlistBatchReport; QStringList m_strlistPath_Output_Gammamap; QStringList m_strlistPath_Output_Failure; QStringList m_strlistPath_Output_Report; vector m_vRefDose; //DlgGammaView* m_pView; vector m_vRefDoseImages; vector m_vCompDoseImages; vector m_vGammaMapImages; //checkBox_low_mem FloatImageType::Pointer m_spDummyLowMemImg; FloatImage2DType::Pointer m_spCurRef2D; FloatImage2DType::Pointer m_spCurComp2D; FloatImage2DType::Pointer m_spGamma2DResult; //Read from output of 2D gamma /*FloatImageType::Pointer m_spRefDoseImages; FloatImageType::Pointer m_spCompDoseImages; FloatImageType::Pointer m_spGammaMapImages;*/ YK16GrayImage* m_pCurImageRef; YK16GrayImage* m_pCurImageComp; YK16GrayImage* m_pCurImageGamma3D; YK16GrayImage* m_pCurImageGamma2D; QStandardItemModel *m_pTableModel; vector m_vColormapDose; vector m_vColormapGamma; bool m_bGamma2DIsDone; bool m_bMousePressedRightRef; bool m_bMousePressedRightComp; bool m_bMousePressedRightGamma3D; bool m_bMousePressedRightGamma2D; QPoint m_ptPanStart; QPoint m_ptOriginalDataOffset; QString m_strPathDirWorkDir;//this is for output QString m_strPathInputDir;//this is for input DCM. initialized when Load Ref files or Load Comp files int m_iLastLoadedIndex; private: Ui::gamma_guiClass ui; }; #endif // gamma_gui_H plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/gamma_gui.ui000066400000000000000000001165571321604176500312530ustar00rootroot00000000000000 gamma_guiClass 0 0 1210 862 Plastimatch EasyGamma3D 10 10 141 31 Load Reference 10 50 311 151 true 330 50 311 151 true 670 20 501 141 Gamma parameters 150 30 31 21 1 190 30 31 16 mm 10 30 141 17 Inherent resample false 230 30 131 17 Interp-search false 370 30 111 17 Local gamma false 370 50 111 17 Global gamma true 90 60 41 21 140 60 121 20 (blank = use dmax) 10 60 81 20 Ref. dose[Gy] 70 90 41 21 3.0 10 90 61 20 DTA [mm] 120 90 81 20 Dose diff [%] 200 90 41 21 3.0 250 90 91 20 Cut-off dose[%] 340 90 41 21 10.0 390 80 101 31 Run 3D Gamma 330 10 141 31 Load Compare 670 180 501 81 Analysis 3D 10 40 41 21 0 70 40 41 21 0 130 40 41 21 0 10 20 51 20 DCM_X 70 20 51 20 DCM_Y 130 20 51 20 DCM_Z 290 50 61 17 8 Axial true 360 50 71 17 8 Sagittal 430 50 71 17 Frontal 310 20 181 22 270 20 41 16 File 180 30 71 31 Go position 270 270 256 256 QFrame::Box 270 530 256 256 QFrame::Box 90 250 101 16 Ref. dose 350 250 121 16 Compared dose 350 790 121 16 3D Gamma map 10 530 256 256 QFrame::Box 100 790 111 16 2D Gamma map 540 300 31 191 10000 10 100 200 Qt::Vertical 600 300 31 191 10000 10 100 200 200 Qt::Vertical 590 540 381 231 540 540 41 20 130 540 750 41 20 0 600 780 51 20 920 780 51 20 980 520 201 251 980 480 211 31 CopyToClipboard 530 250 131 16 Norm. dose (cGy) 10 270 256 256 QFrame::Box 530 270 51 22 10000 200 590 270 51 22 10000 200 750 480 221 51 Profile direction 20 20 111 17 Horizontal true 140 20 71 17 Vertical true 680 780 101 17 Auto Adjust true 900 260 111 31 Run 2D Gamma 650 300 271 171 true 730 270 121 16 3D Gamma report 1030 270 121 16 2D Gamma report 920 300 271 171 true 800 780 101 17 Normalized true 580 500 41 20 1.00 530 500 51 16 NormF 630 501 61 20 apply 230 240 101 17 scroll_zoom false 20 210 101 20 Save directory 180 210 461 21 130 210 41 21 set 500 20 151 17 low memory option false 0 0 1210 21 File View Tool TopToolBarArea false false Profile View Rename RD files Import workspace file Export simple batch report Import proton dose file (*.set) Export Comp Profile as RFA300 Convert IBA OPG files QCustomPlot QWidget
qcustomplot.h
1
qyklabel QLabel
qyklabel.h
pushButton_Open_RD_Comp released() gamma_guiClass SLT_Load_RD_Comp() 385 73 544 85 pushButton_Open_RD_Ref released() gamma_guiClass SLT_Load_RD_Ref() 84 73 155 93 pushButton_RunBatchGamma released() gamma_guiClass SLT_RunBatchGamma() 1060 163 121 418 actionProfile_View triggered() gamma_guiClass SLT_ProfileView() -1 -1 597 428 sliderNormRef valueChanged(int) spinBoxNormRef setValue(int) 557 352 574 313 spinBoxNormRef valueChanged(int) sliderNormRef setValue(int) 543 311 543 369 spinBoxNormComp valueChanged(int) sliderNormComp setValue(int) 634 318 626 348 sliderNormComp valueChanged(int) spinBoxNormComp setValue(int) 613 372 602 308 sliderNormRef valueChanged(int) gamma_guiClass SLT_DrawAll() 555 508 563 553 sliderNormComp valueChanged(int) gamma_guiClass SLT_DrawAll() 626 501 655 530 pushButtonGoForcedProbe released() gamma_guiClass SLT_DrawAll() 876 273 690 408 radioButtonAxial toggled(bool) gamma_guiClass SLT_WhenChangePlane() 991 279 913 567 radioButtonSagittal toggled(bool) gamma_guiClass SLT_WhenChangePlane() 1072 279 1075 508 radioButtonFrontal toggled(bool) gamma_guiClass SLT_WhenChangePlane() 1146 279 1075 404 pushButtonCopyTableToClipboard released() gamma_guiClass SLT_CopyTableToClipboard() 1020 519 960 563 checkBoxAutoAdjust clicked(bool) gamma_guiClass SLT_DrawGraph(bool) 735 829 875 823 lineEditYMax textEdited(QString) gamma_guiClass SLT_DrawGraph() 552 582 601 618 lineEditYMin textEdited(QString) gamma_guiClass SLT_DrawGraph() 568 802 618 766 lineEditXMin textEdited(QString) gamma_guiClass SLT_DrawGraph() 637 832 725 823 lineEditXMax textEdited(QString) gamma_guiClass SLT_DrawGraph() 964 827 977 812 radioButtonHor released() gamma_guiClass SLT_DrawAll() 818 549 934 520 radioButtonVert released() gamma_guiClass SLT_DrawAll() 908 549 946 536 comboBoxCompareFile currentIndexChanged(int) gamma_guiClass SLT_WhenSelectCombo() 1152 254 1075 331 pushButton_Run2DGamma released() gamma_guiClass SLT_RunGamma2D() 990 311 911 303 checkBoxNormalized released() gamma_guiClass SLT_DrawAll() 837 820 906 832 pushButtonNormApply released() gamma_guiClass SLT_NormCompFromRefNorm() 669 543 692 548 actionRename_RD_files triggered() gamma_guiClass SLTM_RenameRDFilesByDICOMInfo() -1 -1 612 428 actionLoad_saved_results triggered() gamma_guiClass SLTM_LoadSavedWorkSpace() -1 -1 612 428 pushButtonSetWorkDir released() gamma_guiClass SLT_SetWorkDir() 142 253 161 275 actionExport_simple_batch_report triggered() gamma_guiClass SLTM_ExportBatchReport() -1 -1 612 428 actionLoad_proton_dose_file_set triggered() gamma_guiClass SLTM_LoadProtonDoseSetFile() -1 -1 612 428 actionConvert_IBA_OPG_files triggered() gamma_guiClass SLTM_ConvertIBAOPG_Files() -1 -1 604 430 SLT_Load_RD_Ref() SLT_Load_RD_Comp() SLT_RunBatchGamma() SLT_ProfileView() SLT_LoadResults() SLT_DrawAll() SLT_UpdateReportTxt() SLT_CopyTableToClipboard() SLT_DrawGraph(bool) SLT_DrawGraph() SLT_RunGamma2D() SLT_NormCompFromRefNorm() SLT_WhenSelectCombo() SLT_WhenChangePlane() SLTM_RenameRDFilesByDICOMInfo() SLTM_LoadSavedWorkSpace() SLT_SetWorkDir() SLTM_ExportBatchReport() SLTM_LoadProtonDoseSetFile() SLTM_ExportCompProfileRFA300_ASC() SLTM_ConvertIBAOPG_Files()
gamma_gui_main.cpp000066400000000000000000000002521321604176500323250ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "gamma_gui.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); gamma_gui w; w.show(); return a.exec(); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/group_add.cxx000066400000000000000000000221211321604176500314350ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "aperture.h" #include "plm_math.h" #include "proj_volume.h" #include "ray_trace_probe.h" #include "rpl_volume.h" #include "rt_beam.h" #include "rt_plan.h" #include "volume.h" #include "volume_limit.h" #include "wed_parms.h" //For sure #include "print_and_exit.h" #include #include "plm_image.h" #include "plm_image_header.h" #include "itkImageRegionIterator.h" #include "pcmd_synth.h" #include "pcmd_synth.cxx" #include "synthetic_mha.h" class group_add_parms { public: group_add_parms(){ file=""; for (int i=0;i!=3;++i) {offset[i]=0.;} weight=0.; } std::string file; float offset[3]; double weight; }; int get_group_lines(char* groupfile) { std::string line; std::ifstream text(groupfile); int numlines = 0; if (text.is_open()) { while (text.good()) { getline(text,line); if ( (!line.empty()) && (line.compare(0,1,"#")) ) { numlines++; } } } return numlines; } void parse_group(int argc, char** argv, int linenumber, std::vector *parms_vec) { group_add_parms parms; int linecounter = 0; std::string line; std::ifstream text(argv[1]); if (text.is_open()) { while (text.good()) { getline(text,line); if ( (!line.empty()) && (line.compare(0,1,"#")) ) { if (linecounter == linenumber) { std::string pvol_file; std::string dose_file; std::string dose_wed_file; float offset[3]; double weight; std::stringstream linestream(line); linestream >> pvol_file >> dose_file >> dose_wed_file >> offset[0] >> offset[1] >> offset[2] >> weight; if (dose_wed_file.size()>=4) { if (dose_wed_file.compare(dose_wed_file.size()-4,4,".mha")) { print_and_exit ("%s is not in .mha format.\n", dose_wed_file.c_str()); return; } } else {print_and_exit ("%s is not in .mha format.\n", dose_wed_file.c_str());} parms.file = dose_wed_file; for (int i=0;i!=3;++i) {parms.offset[i] = offset[i];} parms.weight = weight; parms_vec->push_back(parms); } linecounter++; } } } } void resize_3d_vect(std::vector< std::vector< std::vector > > &input_vector, plm_long size[]) { input_vector.resize( size[0] ); for (int i=0;i!=size[0];++i) { input_vector[i].resize( size[1] ); for (int j=0;j!= size[1];++j) { input_vector[i][j].resize( size[2] ); for (int k=0;k!= size[2];++k) { input_vector[i][j][k]=0.; } } } } int main (int argc, char* argv[]) { std::string Output_FN = "Added_output.mha"; typedef itk::ImageRegionIterator< FloatImageType > FloatIteratorType; std::vector *parms_vec = new std::vector(); int numlines = get_group_lines(argv[1]); Plm_image_header image_header; plm_long image_dim[3]; float spacing[3]; float origin[3]; for (int i=0;i!=numlines;++i) { parse_group(argc, argv, i, parms_vec); } Plm_image *input_image = new Plm_image(); std::cout<<"Number of files in list to add is "<size()<<":"< > > added_vect, input_vect; for (std::vector::iterator it = parms_vec->begin(); it != parms_vec->end();++it) { input_image->load_native(it->file); image_header.set_from_plm_image(input_image); image_header.get_dim(image_dim); image_header.get_spacing(spacing); image_header.get_origin(origin); //Here we calculate the new dimensions, spacing, and origin of the added image if (it == parms_vec->begin()) { for (int i=0;i!=3;++i) { added_spacing[i]=spacing[i]; added_origin[i]=origin[i] + (it->offset[i]); added_dim[i]=image_dim[i]; } } else { for (int i=0;i!=3;++i) { if ( added_spacing[i] > spacing[i] ) {added_spacing[i]=spacing[i];} //Set added resolution to highest res. member if ( added_origin[i] > (origin[i] + it->offset[i]) ) { aobuffer = added_origin[i]; added_origin[i]=origin[i] + (it->offset[i]); added_dim[i] += aobuffer - added_origin[i]; } if ( (added_dim[i]+added_origin[i]) < (image_dim[i]+origin[i]+it->offset[i]) ) {added_dim[i]=image_dim[i]+(origin[i]-added_origin[i]+(it->offset[i]));} } } } //Synth the new, added image with default value 0 Synthetic_mha_main_parms added_parms; for (int i=0;i!=3;++i) { added_parms.sm_parms.dim[i] = (plm_long) added_dim[i]; added_parms.sm_parms.spacing[i] = added_spacing[i]; added_parms.sm_parms.origin[i] = added_origin[i]; added_parms.sm_parms.background = 0.; //set background to 0 for wed doses } added_parms.output_fn = Output_FN; do_synthetic_mha(&added_parms); std::cout<<"Empty file \""<::iterator it = parms_vec->begin(); it != parms_vec->end();++it) { input_image->load_native(it->file); image_header.set_from_plm_image(input_image); image_header.get_dim(image_dim); image_header.get_spacing(spacing); image_header.get_origin(origin); plm_long n_voxels = image_dim[0]*image_dim[1]*image_dim[2]; Volume::Pointer& input_volume = input_image->get_volume_float(); float *in_img = (float*) input_volume->img; resize_3d_vect(input_vect,image_dim); plm_long ijk[3]; for (plm_long zz=0; zz!=n_voxels; ++zz) { COORDS_FROM_INDEX(ijk,zz,image_dim); input_vect[ ijk[0] ][ ijk[1] ][ ijk[2] ] = in_img[zz]; } float x_low,x_high,y_low,y_high,z_low,z_high; int x_low2,x_high2,y_low2,y_high2,z_low2,z_high2; for (int i=0; i!=image_dim[0]; ++i) { for (int j=0; j!=image_dim[1]; ++j) { for (int k=0; k!=image_dim[2]; ++k) { x_low = origin[0] + it->offset[0] + (i-.5)*spacing[0]; x_high = x_low+spacing[0]; y_low = origin[1] + it->offset[1] + (j-.5)*spacing[1]; y_high = y_low+spacing[1]; z_low = origin[2] + it->offset[2] + (k-.5)*spacing[2]; z_high = z_low+spacing[2]; //The extra "if's" account for some fuzziness with the maximum values not being cut off - //chopping off everything above the added max value. x_low2 = (int) floor((x_low-added_origin[0])/added_spacing[0]+.5); x_high2 = (int) floor((x_high-added_origin[0])/added_spacing[0]+.5); if (x_high2 > added_length[0]-1) {x_high2 = added_length[0]-1;} y_low2 = (int) floor((y_low-added_origin[1])/added_spacing[1]+.5); y_high2 = (int) floor((y_high-added_origin[1])/added_spacing[1]+.5); if (y_high2 > added_length[1]-1) {y_high2 = added_length[1]-1;} z_low2 = (int) floor((z_low-added_origin[2])/added_spacing[2]+.5); z_high2 = (int) floor((z_high-added_origin[2])/added_spacing[2]+.5); if (z_high2 > added_length[2]-1) {z_high2 = added_length[2]-1;} for (int ii=x_low2; ii<=x_high2; ++ii) { for (int jj=y_low2; jj<=y_high2; ++jj) { for (int kk=z_low2; kk<=z_high2; ++kk) { float unit = 1.; //fraction of the input voxel in each added cell: if (ii==x_low2) {unit *= (1 - ((x_low-added_origin[0])/added_spacing[0]+.5 - x_low2));} if (ii==x_high2) {unit *= ((x_high-added_origin[0])/added_spacing[0]+.5 - x_high2);} if (jj==y_low2) {unit *= (1 - ((y_low-added_origin[1])/added_spacing[1]+.5 - y_low2));} if (jj==y_high2) {unit *= ((y_high-added_origin[1])/added_spacing[1]+.5 - y_high2);} if (kk==z_low2) {unit *= (1 - ((z_low-added_origin[2])/added_spacing[2]+.5 - z_low2));} if (kk==z_high2) {unit *= ((z_high-added_origin[2])/added_spacing[2]+.5 - z_high2);} if ((x_low2<0)||(y_low2<0)||(z_low2<0)||(x_high2>=added_dim[0])||(y_high2>=added_dim[1])||(z_high2>=added_dim[2])) {continue;} added_vect[ii][jj][kk] += unit*input_vect[i][j][k]*it->weight; } } } } } } } Plm_image *output_image = new Plm_image(); output_image->load_native("Added_output.mha"); FloatImageType::Pointer img_out = output_image->m_itk_float; FloatImageType::RegionType rg_out = img_out->GetLargestPossibleRegion (); FloatIteratorType image_out_it (img_out, rg_out); plm_long ijk[3]; int zz = 0; for (image_out_it.GoToBegin(); !image_out_it.IsAtEnd(); ++image_out_it) { COORDS_FROM_INDEX(ijk,zz,added_length); image_out_it.Set( added_vect[ ijk[0] ][ ijk[1] ][ ijk[2] ] ); zz++; } itk_image_save_float (img_out, "Added_output.mha"); delete output_image; delete parms_vec; delete input_image; return 0; } hnd_to_pfm.cxx000066400000000000000000000021751321604176500315360ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "file_util.h" #include "path_util.h" #include "print_and_exit.h" #include "proj_image.h" int main (int argc, char* argv[]) { Proj_image *proj; char *hnd_fn, *pfm_fn, *mat_fn, *tmp; if (argc != 3) { printf ("Usage: hndtopfm hndfile pfmfile\n"); return 1; } hnd_fn = argv[1]; pfm_fn = argv[2]; /* Create filename for matrix file */ tmp = strdup (pfm_fn); strip_extension (tmp); mat_fn = (char*) malloc (strlen (tmp) + 5); sprintf (mat_fn, "%s.txt", tmp); free (tmp); /* Read image */ double xy_offset[2] = {0., 0.}; proj = new Proj_image (hnd_fn, xy_offset); if (!proj->have_image ()) { print_and_exit ("Couldn't load file for read: %s\n", hnd_fn); } /* Write image and header */ proj->save (pfm_fn, mat_fn); delete proj; return 0; } landmark_diff_main.cxx000066400000000000000000000013651321604176500332060ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include "landmark_diff.h" #include "raw_pointset.h" int main (int argc, char** argv) { int rv; Raw_pointset *lm0; Raw_pointset *lm1; if (argc < 3) { printf ("Usage:\n" " landmark_diff file_1 file_2\n\n" ); return 0; } lm0 = pointset_load (argv[1]); lm1 = pointset_load (argv[2]); rv = landmark_diff (lm0, lm1); pointset_destroy (lm0); pointset_destroy (lm1); return rv; } merge_vector_fields.cxx000066400000000000000000000120501321604176500334210ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* This program can merge vector fields based on the binary masks of non-overlapping regions (e.g., moving and non-moving tissues). It should be called with 5 input parameters. Besides the vf1, vf2, and output vf names, the additional 2 files are mask1 and mask2. The program will compose the vector fields according to the masks and leave zero vectors for the area that is outside both masks. */ #include "plm_config.h" #include #include #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkAffineTransform.h" #include "itkImageRegionIterator.h" #include "itkImageToImageFilter.h" #include "itkInterpolateImageFunction.h" #include "itkLinearInterpolateImageFunction.h" const unsigned int Dimension = 3; typedef unsigned char MaskPixelType; typedef itk::Image < unsigned char, 3 > UCharImageType; typedef itk::Image < MaskPixelType, Dimension > MaskImageType; typedef itk::ImageFileReader < UCharImageType > MhaUCharReaderType; typedef itk::ImageRegionIterator< UCharImageType > UCharIteratorType; template void load_mha_rdr(RdrT reader, char *fn) { reader->SetFileName(fn); try { reader->Update(); } catch(itk::ExceptionObject & ex) { printf ("Exception reading mha file: %s!\n",fn); std::cout << ex << std::endl; getchar(); exit(1); } } int main( int argc, char *argv[] ) { if (argc!=6) { std::cerr << "Wrong Parameters " << std::endl; std::cerr << "Usage: " << argv[0]; std::cerr << " vector_field1 vector_field2"; std::cerr << " outputVectorFieldFile"; std::cerr << " vector_field_mask1 vector_field_mask2 " << std::endl; return 1; } //load vector2 field file typedef itk::Vector< float, Dimension > VectorType; typedef itk::Image< VectorType, Dimension > DeformationFieldType; typedef itk::ImageFileReader< DeformationFieldType > FieldReaderType; typedef itk::Image< float, Dimension > FloatImageType; typedef itk::InterpolateImageFunction InterpolatorType; FieldReaderType::Pointer fieldReader1 = FieldReaderType::New(); fieldReader1->SetFileName( argv[1] ); try { fieldReader1->Update(); } catch (itk::ExceptionObject& excp) { std::cerr << "Exception thrown " << std::endl; std::cerr << excp << std::endl; return 0; } DeformationFieldType::Pointer deform_field1 = fieldReader1->GetOutput(); //load vector2 field file FieldReaderType::Pointer fieldReader = FieldReaderType::New(); fieldReader->SetFileName( argv[2] ); try { fieldReader->Update(); } catch (itk::ExceptionObject& excp) { std::cerr << "Exception thrown " << std::endl; std::cerr << excp << std::endl; return 0; } DeformationFieldType::Pointer deform_field2 = fieldReader->GetOutput(); printf("loaded two vf\n" ); DeformationFieldType::Pointer field_out = DeformationFieldType::New(); MaskImageType::Pointer mask1 = MaskImageType::New(); MaskImageType::Pointer mask2 = MaskImageType::New(); MhaUCharReaderType::Pointer mask_reader1 = MhaUCharReaderType::New(); MhaUCharReaderType::Pointer mask_reader2 = MhaUCharReaderType::New(); load_mha_rdr(mask_reader1, argv[4]); mask1 = mask_reader1->GetOutput(); load_mha_rdr(mask_reader2, argv[5]); mask2 = mask_reader2->GetOutput(); UCharIteratorType it1(mask1, mask1->GetBufferedRegion()); UCharIteratorType it2(mask2, mask1->GetBufferedRegion()); printf("masks loaded\n" ); field_out->SetRegions (deform_field2->GetBufferedRegion()); field_out->SetOrigin (deform_field2->GetOrigin()); field_out->SetSpacing (deform_field2->GetSpacing()); field_out->Allocate(); printf("allocated out vector field\n" ); typedef itk::ImageRegionIterator< DeformationFieldType > FieldIterator; FieldIterator d_f1 (deform_field1, deform_field1->GetBufferedRegion()); FieldIterator d_f2 (deform_field2, deform_field2->GetBufferedRegion()); FieldIterator f_out (field_out, deform_field2->GetBufferedRegion()); // populate the output field f_out.GoToBegin(); d_f1.GoToBegin(); d_f2.GoToBegin(); it1.GoToBegin(); it2.GoToBegin(); while (!f_out.IsAtEnd()) { unsigned char m1 = it1.Get(); unsigned char m2 = it2.Get(); VectorType vf; if (m1>0) { vf = d_f1.Get(); } else if (m2>0) { vf = d_f2.Get(); } else { vf[0] = 0; vf[1] = 0; vf[2] = 0; } f_out.Set(vf); ++f_out; ++d_f1; ++d_f2; ++it1; ++it2; } printf("produced out vector field\n" ); typedef itk::ImageFileWriter< DeformationFieldType > FieldWriterType; FieldWriterType::Pointer fieldWriter = FieldWriterType::New(); fieldWriter->SetInput (field_out); fieldWriter->SetFileName (argv[3]); try { fieldWriter->Update(); } catch (itk::ExceptionObject& excp) { std::cerr << "Exception thrown " << std::endl; std::cerr << excp << std::endl; } return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/mha_to_raw.c000066400000000000000000000043351321604176500312400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* Converts ITK mha format to a raw cube */ #include "plm_config.h" #include #include #include #include "plm_config.h" #define BUFLEN 1024 void swap_short(unsigned char *pntr) { unsigned char b0, b1; b0 = *pntr; b1 = *(pntr+1); *pntr = b1; *(pntr+1) = b0; } int main (int argc, char* argv[]) { FILE *fp1, *fp2; int nx, ny, nz, nb = 0; long bytesz; float sx, sy, sz; int i; unsigned char c; char buf[1024]; if (argc != 3) { printf ("Usage: %s infile outfile\n", argv[0]); exit (1); } if (!(fp1 = fopen(argv[1],"rb"))) { printf ("Error opening file \"%s\" for read\n", argv[1]); exit (1); } if (!(fp2 = fopen(argv[2],"wb"))) { printf ("Error opening file \"%s\" for write\n", argv[2]); exit (1); } for (i=0; i<30; i++) { // 30 lines of MHA should have passed the header if (fgets(buf,1024,fp1) == NULL) { printf ("File error.\n"); exit (1); } if (strstr(buf, "DimSize")!=NULL) { sscanf(&(buf[9]), "%d%d%d", &nx, &ny, &nz); } else if (strstr(buf, "ElementSpacing")!=NULL) { sscanf(&(buf[16]), "%f%f%f", &sx, &sy, &sz); } else if (strstr(buf, "ElementType")!=NULL) { if (!strcmp(buf, "ElementType = MET_SHORT\n")) { nb = 2; } else if (!strcmp(buf, "ElementType = MET_USHORT\n")) { nb = 2; } else if (!strcmp(buf, "ElementType = MET_UCHAR\n")) { nb = 1; } else if (!strcmp(buf, "ElementType = MET_FLOAT\n")) { nb = 4; } } } printf("Writing...\n"); //image bytesz = (long) nx * ny * nz * nb; printf("%ld bytes of image data!\n", bytesz); fseek(fp1, -bytesz, SEEK_END); fread(&c,1,1,fp1); while (!feof(fp1)) { fwrite(&c,1,1,fp2); fread(&c,1,1,fp1); } fclose(fp1); fclose(fp2); return 0; } nki2mha_converter.cpp000066400000000000000000000305701321604176500330210ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "nki2mha_converter.h" #include #include #include #include //#include "YK16GrayImage.h" #include #include "mha_io.h" #include "nki_io.h" //#include "volume.h" #include "plm_image.h" #include "rt_study_metadata.h" nki2mha_converter::nki2mha_converter(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { ui.setupUi(this); //m_pImgOffset = NULL; //m_pImgGain = NULL; ////Badpixmap; //m_pImgOffset = new YK16GrayImage(IMG_WIDTH, IMG_HEIGHT); //m_pImgGain = new YK16GrayImage(IMG_WIDTH, IMG_HEIGHT); // const char* inFileName = "C:\\test.scan"; // const char* outFileName = "C:\\test.mha"; /*Volume *v = nki_load (inFileName); if (!v) { printf("file reading error\n"); } write_mha(outFileName, v);*/ } nki2mha_converter::~nki2mha_converter() { //delete m_pImgOffset; //delete m_pImgGain; //m_vPixelReplMap.clear(); //not necessary } void nki2mha_converter::SLT_OpenMultipleRaw() { QStringList tmpList = QFileDialog::getOpenFileNames(this,"Select one or more files to open","/home","3D Image file (*.scan *.mha)"); int iFileCnt = tmpList.size(); if (iFileCnt < 1) return; m_strlistPath = tmpList; ui.plainTextEdit_Raw->clear(); ui.plainTextEdit_Corrected->clear(); for (int i = 0 ; iappendPlainText(m_strlistPath.at(i)); //just for display } //ui.listView_Raw-> //ui.plainTextEdit_Raw //QPlainTextEdit* text; } // QString nki2mha_converter::CorrectSingle_NKI2MHA(const char* filePath) { Volume *v = nki_load (filePath); if (!v) { printf("file reading error\n"); return ""; } //Load raw file //filePath //QString exportName = filePath; //corrImg.SaveDataAsRaw(); QString endFix = "_conv"; QFileInfo srcFileInfo = QFileInfo(filePath); QDir dir = srcFileInfo.absoluteDir(); QString baseName = srcFileInfo.completeBaseName(); QString extName = "mha"; QString newFileName = baseName.append(endFix).append(".").append(extName); QString newPath = dir.absolutePath() + "/" + newFileName; write_mha(newPath.toLocal8Bit().constData(), v); return newPath; //corrImg.ReleaseBuffer(); } // void nki2mha_converter::SLT_Correct_NKI2MHA() { //1) Load files from m_strlistPath //2) offset or gain correction //3) bad pixel correction if available int listSize = m_strlistPath.size(); if (listSize < 1) return; int cnt = 0; for (int i = 0 ; i 0 ) { ui.plainTextEdit_Corrected->appendPlainText(corrFilePath); cnt++; } } QString msgStr = QString("%1 files were converted").arg(cnt); QMessageBox::information(this, "Procedure Done",msgStr); cout << "MHA Conversion completed" << endl; } void nki2mha_converter::SLT_Correct_NKI2DCM() { int listSize = m_strlistPath.size(); if (listSize < 1) return; QString strPatientID = ui.lineEditPatientID->text(); QString strPatientName = ui.lineEditPatientName->text(); bool bPatientIDExist = false; if (strPatientID.length() > 1 && strPatientName.length() > 1) { bPatientIDExist = true; } int cnt = 0; for (int i = 0 ; i 1) { int index = i+1; strPatientID = strPatientID + QString("%1").arg(index); } QString filePath = m_strlistPath.at(i); QFileInfo fileInfo = QFileInfo(filePath); QString extName = fileInfo.completeSuffix(); QString corrFilePath; if (extName == "scan" || extName == "SCAN") { if (bPatientIDExist) corrFilePath = CorrectSingle_NKI2DCM(filePath.toLocal8Bit().constData(), strPatientID,strPatientName); else corrFilePath = CorrectSingle_NKI2DCM(filePath.toLocal8Bit().constData()); } else if (extName == "mha" || extName == "MHA") { if (bPatientIDExist) corrFilePath = CorrectSingle_MHA2DCM(filePath.toLocal8Bit().constData(), strPatientID,strPatientName); else corrFilePath = CorrectSingle_MHA2DCM(filePath.toLocal8Bit().constData()); } if (corrFilePath.length() > 0 ) { ui.plainTextEdit_Corrected->appendPlainText(corrFilePath); cnt++; } } QString msgStr = QString("%1 files were converted").arg(cnt); QMessageBox::information(this, "Procedure Done",msgStr); cout << "DCM Conversion completed" << endl; } void nki2mha_converter::SLT_Correct_NKI2RAW() { int listSize = m_strlistPath.size(); if (listSize < 1) return; int cnt = 0; for (int i = 0 ; i 0 ) { ui.plainTextEdit_Corrected->appendPlainText(corrFilePath); cnt++; } } QString msgStr = QString("%1 files were converted").arg(cnt); QMessageBox::information(this, "Procedure Done",msgStr); cout << "RAW Conversion completed" << endl; } QString nki2mha_converter::CorrectSingle_NKI2DCM( const char* filePath ) { Volume *v = nki_load (filePath); if (!v) { printf("file reading error\n"); return ""; } Plm_image plm_img(v); QString endFix = "_DCM"; QFileInfo srcFileInfo = QFileInfo(filePath); QDir dir = srcFileInfo.absoluteDir(); QString baseName = srcFileInfo.completeBaseName(); baseName.append(endFix); QString newDirPath = dir.absolutePath() + "/" + baseName; QDir dirNew(newDirPath); if (!dirNew.exists()){ dirNew.mkdir("."); } Rt_study_metadata rsm; rsm.set_patient_id(baseName.toLocal8Bit().constData()); rsm.set_patient_name(baseName.toLocal8Bit().constData()); plm_img.save_short_dicom(newDirPath.toLocal8Bit().constData(), &rsm); return newDirPath; } QString nki2mha_converter::CorrectSingle_NKI2DCM( const char* filePath, QString patientID, QString patientName ) { Volume *v = nki_load (filePath); if (!v) { printf("file reading error\n"); return ""; } Plm_image plm_img(v); //QString endFix = "_DCM"; QFileInfo srcFileInfo = QFileInfo(filePath); QDir dir = srcFileInfo.absoluteDir(); QString baseName = srcFileInfo.completeBaseName(); //baseName.append(endFix); //baseName.append(endFix); QString dirName; if (patientID.length() > 1) dirName = patientID; else dirName = baseName; QString newDirPath = dir.absolutePath() + "/" + dirName; QDir dirNew(newDirPath); if (!dirNew.exists()){ dirNew.mkdir("."); } Rt_study_metadata rsm; rsm.set_patient_id(patientID.toLocal8Bit().constData()); rsm.set_patient_name(patientName.toLocal8Bit().constData()); plm_img.save_short_dicom(newDirPath.toLocal8Bit().constData(), &rsm); return newDirPath; } QString nki2mha_converter::CorrectSingle_MHA2DCM( const char* filePath) { //Volume *v = nki_load (filePath); Volume *v = read_mha(filePath); if (!v) { printf("file reading error\n"); return ""; } Plm_image plm_img(v); QString endFix = "_DCM"; QFileInfo srcFileInfo = QFileInfo(filePath); QDir dir = srcFileInfo.absoluteDir(); QString baseName = srcFileInfo.completeBaseName(); baseName.append(endFix); QString newDirPath = dir.absolutePath() + "/" + baseName; QDir dirNew(newDirPath); if (!dirNew.exists()){ dirNew.mkdir("."); } //ID: baseName.toLocal8Bit().constData(); //Name: baseName.toLocal8Bit().constData(); Rt_study_metadata rsm; rsm.set_patient_id(baseName.toLocal8Bit().constData()); rsm.set_patient_name(baseName.toLocal8Bit().constData()); plm_img.save_short_dicom(newDirPath.toLocal8Bit().constData(), &rsm); //plm_img.save_short_dicom(newDirPath.toLocal8Bit().constData(), 0, baseName.toLocal8Bit().constData(),baseName.toLocal8Bit().constData()); return newDirPath; } QString nki2mha_converter::CorrectSingle_MHA2DCM( const char* filePath, QString patientID, QString patientName) { //Volume *v = nki_load (filePath); Volume *v = read_mha(filePath); if (!v) { printf("file reading error\n"); return ""; } Plm_image plm_img(v); //QString endFix = "_DCM"; QFileInfo srcFileInfo = QFileInfo(filePath); QDir dir = srcFileInfo.absoluteDir(); QString baseName = srcFileInfo.completeBaseName(); //baseName.append(endFix); //QString newDirPath = dir.absolutePath() + "/" + baseName; QString dirName; if (patientID.length() > 1) dirName = patientID; else dirName = baseName; QString newDirPath = dir.absolutePath() + "/" + dirName; QDir dirNew(newDirPath); if (!dirNew.exists()){ dirNew.mkdir("."); } //ID: baseName.toLocal8Bit().constData(); //Name: baseName.toLocal8Bit().constData(); Rt_study_metadata rsm; rsm.set_patient_id(patientID.toLocal8Bit().constData()); rsm.set_patient_name(patientName.toLocal8Bit().constData()); plm_img.save_short_dicom(newDirPath.toLocal8Bit().constData(), &rsm); //plm_img.save_short_dicom(newDirPath.toLocal8Bit().constData(), 0, baseName.toLocal8Bit().constData(),baseName.toLocal8Bit().constData()); return newDirPath; } QString nki2mha_converter::CorrectSingle_NKI2RAW( const char* filePath ) { Volume *v = nki_load (filePath); if (!v) { printf("file reading error\n"); return ""; } Plm_image plm_img(v); QString endFix = "_RAW"; QFileInfo srcFileInfo = QFileInfo(filePath); QDir dir = srcFileInfo.absoluteDir(); QString baseName = srcFileInfo.completeBaseName(); baseName.append(endFix); QString newDirPath = dir.absolutePath() + "/" + baseName; QDir dirNew(newDirPath); if (!dirNew.exists()){ dirNew.mkdir("."); } //cout << v->npix << endl;//44378400 = 410 * 410 * 264 //cout << v->vox_planes << endl;//0 //cout << v->pix_size << endl; //2 //cout << v->dim[0] << v->dim[1] << v->dim[2] << endl; //410 410 264 int imgWidth = v->dim[0]; int imgHeight = v->dim[1]; int imgSliceNum = v->dim[2]; if ( v->pix_size != 2)//USHORT or short only { cout << "not supported file format. only USHORT 16 bit is compatible" << endl; return ""; } int img2DSize = imgWidth*imgHeight; for (int k = 0 ; k< imgSliceNum ; k++) { FILE* fd = NULL; QString filePath; filePath.sprintf("%s\\image%03d_w%d_h%d.raw", newDirPath.toLocal8Bit().constData(), k, imgWidth, imgHeight); fd = fopen(filePath.toLocal8Bit().constData(), "wb"); for (int i = 0 ; iimg) + ((k*img2DSize+i)*2), 2, 1, fd); --> Error occurrs fwrite((signed short*)(v->img) + (k*img2DSize+i), 2, 1, fd); } fclose(fd); } //Export raw info file in same folder QString rawInfoPath; rawInfoPath.sprintf("%s\\00RawInfo.txt", newDirPath.toLocal8Bit().constData()); std::ofstream fout; fout.open (rawInfoPath.toLocal8Bit().constData()); fout << "Raw File Info" << endl; fout << "Original_NKI(*.SCAN)_FileName" << " " << filePath << endl; fout << "Pixel_Type" << " " << "Signed Short" << endl; fout << "Image_Width[px]" << " " << imgWidth << endl; fout << "Image_Height[px]" << " " << imgHeight << endl; fout << "Number_of_Slice" << " " << imgSliceNum << endl; fout << "Spacing_X_Y_Z[mm]" << " " << v->spacing[0]<< " " << v->spacing[1] << " " << v->spacing[2] << endl; fout << "Bytes_per_Pixel" << " " << v->pix_size << endl; fout.close(); return newDirPath; } nki2mha_converter.h000066400000000000000000000031201321604176500324550ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#ifndef NKI2MHA_CONVERTER_H #define NKI2MHA_CONVERTER_H //#ifndef nki2mha_converter_H //#define nki2mha_converter_H #include #include "ui_nki2mha_converter.h" #include #include using namespace std; class nki2mha_converter : public QMainWindow { Q_OBJECT public: nki2mha_converter(QWidget *parent = 0, Qt::WFlags flags = 0); ~nki2mha_converter(); QString CorrectSingle_NKI2MHA(const char* filePath); QString CorrectSingle_NKI2DCM(const char* filePath); QString CorrectSingle_NKI2DCM( const char* filePath, QString patientID, QString patientName); QString CorrectSingle_NKI2RAW( const char* filePath ); QString CorrectSingle_MHA2DCM(const char* filePath ); QString CorrectSingle_MHA2DCM( const char* filePath, QString patientID, QString patientName); //void LoadBadPixelMap(const char* filePath); //void BadPixReplacement(YK16GrayImage* targetImg); //void SaveBadPixelMap(vector& vBadPixels); public slots: //void SLT_OpenOffsetFile(); //void SLT_OpenGainFile(); //void SLT_OpenBadpixelFile(); void SLT_OpenMultipleRaw(); void SLT_Correct_NKI2MHA(); //NKI to MHA void SLT_Correct_NKI2DCM(); //NKI to MHA void SLT_Correct_NKI2RAW(); //NKI to RAW: signed short! public: //YK16GrayImage* m_pImgOffset; //YK16GrayImage* m_pImgGain; //Badpixmap; //vector m_vPixelReplMap; //vector m_vpRawImg; QStringList m_strlistPath; private: Ui::nki2mha_converterClass ui; }; #endif // nki2mha_converter_H nki2mha_converter.qrc000066400000000000000000000001151321604176500330140ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone nki2mha_converter.ui000066400000000000000000000175441321604176500326620ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone nki2mha_converterClass 0 0 689 652 Platimatch NKI /MHA file converter (bug report to: ykpark@mgh.harvard.edu) Load Qt::Horizontal 40 20 Files to be converted (*.SCAN, *.mha) #Warning! Program may crash if a single file size is too big! ToMHA ToRAW Qt::Horizontal 40 20 DICOM conversion ToDCM Patient ID Patient Name # if patient ID is left blank, file name will be regarded as ID/Name # For multiplie conversion, 1-based endfix will be used (~1,2,3..) for ID Files generated by conversion horizontalLayoutWidget horizontalLayoutWidget_3 plainTextEdit_Raw horizontalLayoutWidget_4 verticalLayoutWidget_2 verticalLayoutWidget_3 horizontalLayoutWidget_5 0 0 689 21 TopToolBarArea false pushButton_OpenRaw pressed() nki2mha_converterClass SLT_OpenMultipleRaw() 110 73 220 179 pushButton_ToMHA pressed() nki2mha_converterClass SLT_Correct_NKI2MHA() 180 273 331 385 pushButton__ToDCM released() nki2mha_converterClass SLT_Correct_NKI2DCM() 336 258 402 260 pushButton_ToRAW released() nki2mha_converterClass SLT_Correct_NKI2RAW() 509 247 561 242 SLT_OpenOffsetFile() SLT_OpenGainFile() SLT_OpenBadpixelFile() SLT_OpenMultipleRaw() SLT_Correct_NKI2MHA() SLT_Correct_NKI2DCM() SLT_Correct_NKI2RAW() nki2mha_converter_main.cpp000066400000000000000000000002631321604176500340210ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "nki2mha_converter.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); nki2mha_converter w; w.show(); return a.exec(); } opencl_probe.cl000077500000000000000000000007401321604176500316630ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* A simple test kernel */ __kernel void kernel_1 ( __global unsigned int * output, __global unsigned int * input, const unsigned int multiplier ) { uint tid = get_global_id(0); output[tid] = input[tid] * multiplier; } opencl_probe.cxx000066400000000000000000000034331321604176500320660ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "delayload.h" #include "opencl_probe.h" #include "opencl_util.h" /* opencl_probe() * Return 1 if working device found, 0 if not found */ int opencl_probe () { Opencl_device ocl_dev; Opencl_buf *ocl_buf_in, *ocl_buf_out; cl_uint buf_entries; cl_uint buf_size; cl_uint *buf_in, *buf_out; cl_uint multiplier = 2; cl_int status; bool opencl_works; status = opencl_open_device (&ocl_dev); if (status != CL_SUCCESS) { return 0; } opencl_load_programs (&ocl_dev, "opencl_probe.cl"); buf_entries = 100; buf_size = buf_entries * sizeof (cl_uint); buf_in = (cl_uint*) malloc (buf_size); buf_out = (cl_uint*) malloc (buf_size); for (cl_uint i = 0; i < buf_entries; i++) { buf_in[i] = i; buf_out[i] = 0; } ocl_buf_in = opencl_buf_create (&ocl_dev, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, buf_size, buf_in); ocl_buf_out = opencl_buf_create (&ocl_dev, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, buf_size, buf_out); opencl_kernel_create (&ocl_dev, "kernel_1"); opencl_set_kernel_args ( &ocl_dev, sizeof (cl_mem), &ocl_buf_out[0], sizeof (cl_mem), &ocl_buf_in[0], sizeof (cl_uint), &multiplier, (size_t) 0 ); opencl_kernel_enqueue (&ocl_dev, buf_entries, 1); opencl_buf_read (&ocl_dev, ocl_buf_out, buf_size, buf_out); opencl_works = 1; for (cl_uint i = 0; i < buf_entries; i++) { if (buf_out[i] != 2 * i) { opencl_works = 0; } } return opencl_works; } opencl_probe.h000066400000000000000000000007271321604176500315160ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _opencl_probe_h_ #define _opencl_probe_h_ #include "plm_config.h" #include "delayload.h" #if defined __cplusplus extern "C" { #endif plmopencl_EXPORT ( int opencl_probe, void ); #if defined __cplusplus } #endif #endif opencl_probe_main.c000066400000000000000000000012771321604176500325160ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include "opencl_probe.h" #include "delayload.h" int main (int argc, char* argv[]) { int opencl_works; LOAD_LIBRARY_SAFE (libplmopencl); LOAD_SYMBOL (opencl_probe, libplmopencl); opencl_works = opencl_probe (); if (opencl_works) { printf ("Opencl works ok.\n"); } else { printf ("Opencl does not work.\n"); } UNLOAD_LIBRARY (libplmopencl); return 0; } photon_dose_main.cxx000066400000000000000000000014141321604176500327410ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "plm_math.h" #include "photon_dose.h" #include "photon_parms.h" #include "photon_plan.h" #include "volume.h" int main (int argc, char* argv[]) { time_t tbegin, tend; double texec =0.; tbegin = time(NULL); Photon_parms parms; if (!parms.parse_args (argc, argv)) { return 1; } tend = time(NULL); texec = difftime(tend,tbegin); printf("Execution time : %lg secondes.\n",texec); return 0; } proton_dose_main.cxx000066400000000000000000000012451321604176500327550ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "plm_math.h" #include "plm_timer.h" #include "rt_plan.h" #include "volume.h" int main (int argc, char* argv[]) { Plm_timer timer; Rt_plan plan; timer.start (); if (plan.parse_args (argc, argv) != PLM_SUCCESS) { return 1; } plan.compute_plan (); printf("Execution time : %f secondes.\n", timer.report ()); return 0; } qcustomplot.cpp000066400000000000000000017633171321604176500320100ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/*************************************************************************** ** ** ** QCustomPlot, a simple to use, modern plotting widget for Qt ** ** Copyright (C) 2012 Emanuel Eichhammer ** ** ** ** 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 3 of the License, 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, see http://www.gnu.org/licenses/. ** ** ** **************************************************************************** ** Author: Emanuel Eichhammer ** ** Website/Contact: http://www.WorksLikeClockwork.com/ ** ** Date: 09.06.12 ** ****************************************************************************/ /*! \mainpage %QCustomPlot Documentation Below is a brief overview of and guide to the classes and their relations. If you are new to QCustomPlot and just want to start using it, it's recommended to look at the examples/tutorials at http://www.WorksLikeClockWork.com/index.php/components/qt-plotting-widget This documentation is especially helpful when you're familiar with the basic concept of how to use %QCustomPlot and you wish to learn more about specific functionality. \section simpleoverview Simplified Class Overview \image latex ClassesOverviewSimplified.png "" width=1.2\textwidth \image html ClassesOverviewSimplified.png
Simplified diagram of most important classes, view the \ref classoverview "Class Overview" to see a full overview.
The central widget which displays the plottables and axes on its surface is QCustomPlot. Usually, you don't create the axes yourself, but you use the ones already inside every QCustomPlot instance (xAxis, yAxis, xAxis2, yAxis2). \section plottables Plottables \a Plottables are classes that display any kind of data inside the QCustomPlot. They all derive from QCPAbstractPlottable. For example, the QCPGraph class is a plottable that displays a graph inside the plot with different line styles, scatter styles, filling etc. Since plotting graphs is such a dominant use case, QCustomPlot has a special interface for working with QCPGraph plottables, that makes it very easy to handle them:\n You create a new graph with QCustomPlot::addGraph and access them with QCustomPlot::graph. For all other plottables, you need to use the normal plottable interface:\n First, you create an instance of the plottable you want, e.g. \code QCPCurve *newCurve = new QCPCurve(customPlot->xAxis, customPlot->yAxis);\endcode add it to the customPlot with QCustomPlot::addPlottable: \code customPlot->addPlottable(newCurve);\endcode and then modify the properties of the newly created plottable via newCurve. Plottables (including graphs) can be retrieved via QCustomPlot::plottable. Since the return type of that function is the abstract base class of all plottables, QCPAbstractPlottable, you will probably want to qobject_cast (or dynamic_cast) the returned pointer to the respective plottable subclass. (As usual, if the cast returns zero, the plottable wasn't of that specific subclass.) All further interfacing with plottables (e.g how to set data) is specific to the plottable type. See the documentations of the subclasses: QCPGraph, QCPCurve, QCPBars, QCPStatisticalBox. \section axes Controlling the Axes As mentioned, QCustomPlot has four axes by default: \a xAxis (bottom), \a yAxis (left), \a xAxis2 (top), \a yAxis2 (right). Their range is handled by the simple QCPRange class. You can set the range with the QCPAxis::setRange function. By default, the axes represent a linear scale. To set a logarithmic scale, set QCPAxis::setScaleType to QCPAxis::stLogarithmic. The logarithm base can be set freely with QCPAxis::setScaleLogBase. By default, an axis automatically creates and labels ticks in a sensible manner, i.e. with a tick interval that's pleasing to the viewer. See the following functions for tick manipulation:\n QCPAxis::setTicks, QCPAxis::setAutoTicks, QCPAxis::setAutoTickCount, QCPAxis::setAutoTickStep, QCPAxis::setTickLabels, QCPAxis::setTickLabelType, QCPAxis::setTickLabelRotation, QCPAxis::setTickStep, QCPAxis::setTickLength,... Each axis can be given an axis label (e.g. "Voltage [mV]") with QCPAxis::setLabel. The distance of an axis backbone to the respective QCustomPlot widget border is called its margin. Normally, the margins are calculated automatically. To change this, set QCustomPlot::setAutoMargin to false and set the margins manually with QCustomPlot::setMargin. \section legend Plot Legend Every QCustomPlot owns a QCPLegend (as \a legend). That's a small window inside the plot which lists the plottables with an icon of the plottable line/symbol and a description. The Description is retrieved from the plottable name (QCPAbstractPlottable::setName). Plottables can be added and removed from the legend via \ref QCPAbstractPlottable::addToLegend and \ref QCPAbstractPlottable::removeFromLegend. By default, adding a plottable to QCustomPlot automatically adds it to the legend, too. This behaviour can be modified with the QCustomPlot::setAutoAddPlottableToLegend property. The QCPLegend provides an interface to access, add and remove legend items directly, too. See QCPLegend::item, QCPLegend::itemWithPlottable, QCPLegend::addItem, QCPLegend::removeItem for example. \section userinteraction User Interactions QCustomPlot currently supports dragging axis ranges with the mouse (\ref QCustomPlot::setRangeDrag), zooming axis ranges with the mouse wheel (\ref QCustomPlot::setRangeZoom) and a complete selection mechanism of most objects. The availability of these interactions is controlled with \ref QCustomPlot::setInteractions. For details about the interaction system, see the documentation there. Further, QCustomPlot always emits corresponding signals, when objects are clicked or doubleClicked. See \ref QCustomPlot::plottableClick, \ref QCustomPlot::plottableDoubleClick and \ref QCustomPlot::axisClick for example. \section items Items Apart from plottables there is another category of plot objects that are important: Items. The base class of all items is QCPAbstractItem. An item sets itself apart from plottables in that it's not necessarily bound to any axes. This means it may also be positioned in absolute pixel coordinates or placed at a relative position on the axis rect. Further it usually doesn't represent data directly but acts as decoration, emphasis, description etc. Multiple items can be arranged in a parent-child-hierarchy allowing for dynamical behaviour. For example, you could place the head of an arrow at a certain plot coordinate, so it always points to some important part of your data. The tail of the arrow can be fixed at a text label item which always resides in the top center of the axis rect (independent of where the user drags the axis ranges). For a more detailed introduction, see the QCPAbstractItem documentation, and from there the documentations of the individual built-in items, to find out how to use them. \section performancetweaks Performance Tweaks Although QCustomPlot is quite fast, some features like semi-transparent fills and antialiasing can cause a significant slow down. Here are some thoughts on how to increase performance. By far the most time is spent in the drawing functions, specifically the drawing of graphs. For maximum performance, consider the following (most recommended/effective measures first): \li use Qt 4.8.0 and up. Performance has doubled or tripled with respect to Qt 4.7.4. However they broke QPainter, drawing pixel precise things, e.g. scatters, isn't possible with Qt 4.8.0/1. So it's a performance vs. plot quality tradeoff when switching to Qt 4.8. \li To increase responsiveness during dragging, consider setting \ref QCustomPlot::setNoAntialiasingOnDrag to true. \li On X11 (linux), avoid the (slow) native drawing system, use raster by supplying "-graphicssystem raster" as command line argument or calling QApplication::setGraphicsSystem("raster") before creating the QApplication object. \li On all operating systems, use OpenGL hardware acceleration by supplying "-graphicssystem opengl" as command line argument or calling QApplication::setGraphicsSystem("opengl"). If OpenGL is available, this will slightly decrease the quality of antialiasing, but extremely increase performance especially with alpha (semi-transparent) fills, much antialiasing and a large QCustomPlot drawing surface. Note however, that the maximum frame rate might be constrained by the vertical sync frequency of your monitor (VSync can be disabled in the graphics card driver configuration). So for simple plots (where the potential framerate is far above 60 frames per second), OpenGL acceleration might achieve numerically lower frame rates than the other graphics systems, because they are not capped at the VSync frequency. \li Avoid any kind of alpha (transparency), especially in fills \li Avoid any kind of antialiasing, especially in graph lines (see QCustomPlot::setNotAntialiasedElements) \li Avoid repeatedly setting the complete data set with QCPGraph::setData. Use QCPGraph::addData instead, if most data points stay unchanged, e.g. in a running measurement. \li Set the \a copy parameter of the setData functions to false, so only pointers get transferred. (Relevant only if preparing data maps with a large number of points, i.e. over 10000) */ /*! \page classoverview Class Overview \image latex ClassesOverview.png "Overview of all classes and their relations" width=1.2\textwidth \image html ClassesOverview.png "Overview of all classes and their relations" */ #include "qcustomplot.h" // ================================================================================ // =================== QCPData // ================================================================================ /*! \class QCPData \brief Holds the data of one single data point for QCPGraph. The stored data is: \li \a key: coordinate on the key axis of this data point \li \a value: coordinate on the value axis of this data point \li \a keyErrorMinus: negative error in the key dimension (for error bars) \li \a keyErrorPlus: positive error in the key dimension (for error bars) \li \a valueErrorMinus: negative error in the value dimension (for error bars) \li \a valueErrorPlus: positive error in the value dimension (for error bars) \see QCPDataMap */ /*! Constructs a data point with key, value and all errors set to zero. */ QCPData::QCPData() : key(0), value(0), keyErrorPlus(0), keyErrorMinus(0), valueErrorPlus(0), valueErrorMinus(0) { } /*! Constructs a data point with the specified \a key and \a value. All errors are set to zero. */ QCPData::QCPData(double key, double value) : key(key), value(value), keyErrorPlus(0), keyErrorMinus(0), valueErrorPlus(0), valueErrorMinus(0) { } // ================================================================================ // =================== QCPCurveData // ================================================================================ /*! \class QCPCurveData \brief Holds the data of one single data point for QCPCurve. The stored data is: \li \a t: the free parameter of the curve at this curve point (cp. the mathematical vector (x(t), y(t))) \li \a key: coordinate on the key axis of this curve point \li \a value: coordinate on the value axis of this curve point \see QCPCurveDataMap */ /*! Constructs a curve data point with t, key and value set to zero. */ QCPCurveData::QCPCurveData() : t(0), key(0), value(0) { } /*! Constructs a curve data point with the specified \a t, \a key and \a value. */ QCPCurveData::QCPCurveData(double t, double key, double value) : t(t), key(key), value(value) { } // ================================================================================ // =================== QCPBarData // ================================================================================ /*! \class QCPBarData \brief Holds the data of one single data point (one bar) for QCPBars. The stored data is: \li \a key: coordinate on the key axis of this bar \li \a value: height coordinate on the value axis of this bar \see QCPBarDataaMap */ /*! Constructs a bar data point with key and value set to zero. */ QCPBarData::QCPBarData() : key(0), value(0) { } /*! Constructs a bar data point with the specified \a key and \a value. */ QCPBarData::QCPBarData(double key, double value) : key(key), value(value) { } // ================================================================================ // =================== QCPGraph // ================================================================================ /*! \class QCPGraph \brief A plottable representing a graph in a plot. Usually QCustomPlot creates it internally via QCustomPlot::addGraph and the resulting instance is accessed via QCustomPlot::graph. To plot data, assign it with the \ref setData or \ref addData functions. \section appearance Changing the appearance The appearance of the graph is mainly determined by the line style, scatter style, brush and pen of the graph (\ref setLineStyle, \ref setScatterStyle, \ref setBrush, \ref setPen). \subsection filling Filling under or between graphs QCPGraph knows two types of fills: Normal graph fills towards the zero-value-line parallel to the key axis of the graph, and fills between two graphs, called channel fills. To enable a fill, just set a brush with \ref setBrush which is neither Qt::NoBrush nor fully transparent. By default, a normal fill towards the zero-value-line will be drawn. To set up a channel fill between this graph and another one, call \ref setChannelFillGraph with the other graph as parameter. \see QCustomPlot::addGraph, QCustomPlot::graph, QCPLegend::addGraph */ /*! Constructs a graph which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. The constructed QCPGraph can be added to the plot with QCustomPlot::addPlottable, QCustomPlot then takes ownership of the graph. To directly create a graph inside a plot, you can also use the simpler QCustomPlot::addGraph function. */ QCPGraph::QCPGraph(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable(keyAxis, valueAxis) { mData = new QCPDataMap; setPen(QPen(Qt::blue)); setErrorPen(QPen(Qt::black)); setBrush(Qt::NoBrush); setSelectedPen(QPen(QColor(80, 80, 255), 2.5)); setSelectedBrush(Qt::NoBrush); setLineStyle(lsLine); setScatterStyle(QCP::ssNone); setScatterSize(6); setErrorType(etNone); setErrorBarSize(6); setErrorBarSkipSymbol(true); setChannelFillGraph(0); } QCPGraph::~QCPGraph() { if (mParentPlot) { // if another graph has a channel fill towards this graph, set it to zero for (int i=0; igraphCount(); ++i) { if (mParentPlot->graph(i)->channelFillGraph() == this) mParentPlot->graph(i)->setChannelFillGraph(0); } } delete mData; } /*! Replaces the current data with the provided \a data. If \a copy is set to true, data points in \a data will only be copied. if false, the graph takes ownership of the passed data and replaces the internal data pointer with it. This is significantly faster than copying for large datasets. */ void QCPGraph::setData(QCPDataMap *data, bool copy) { if (copy) { *mData = *data; } else { delete mData; mData = data; } } /*! \overload Replaces the current data with the provided points in \a key and \a value pairs. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. */ void QCPGraph::setData(const QVector &key, const QVector &value) { mData->clear(); int n = key.size(); n = qMin(n, value.size()); QCPData newData; for (int i=0; iinsertMulti(newData.key, newData); } } /*! Replaces the current data with the provided points in \a key and \a value pairs. Additionally the symmetrical value error of the data points are set to the values in \a valueError. For error bars to show appropriately, see \ref setErrorType. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. For asymmetrical errors (plus different from minus), see the overloaded version of this function. */ void QCPGraph::setDataValueError(const QVector &key, const QVector &value, const QVector &valueError) { mData->clear(); int n = key.size(); n = qMin(n, value.size()); n = qMin(n, valueError.size()); QCPData newData; for (int i=0; iinsertMulti(key[i], newData); } } /*! \overload Replaces the current data with the provided points in \a key and \a value pairs. Additionally the negative value error of the data points are set to the values in \a valueErrorMinus, the positive value error to \a valueErrorPlus. For error bars to show appropriately, see \ref setErrorType. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. */ void QCPGraph::setDataValueError(const QVector &key, const QVector &value, const QVector &valueErrorMinus, const QVector &valueErrorPlus) { mData->clear(); int n = key.size(); n = qMin(n, value.size()); n = qMin(n, valueErrorMinus.size()); n = qMin(n, valueErrorPlus.size()); QCPData newData; for (int i=0; iinsertMulti(key[i], newData); } } /*! Replaces the current data with the provided points in \a key and \a value pairs. Additionally the symmetrical key error of the data points are set to the values in \a keyError. For error bars to show appropriately, see \ref setErrorType. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. For asymmetrical errors (plus different from minus), see the overloaded version of this function. */ void QCPGraph::setDataKeyError(const QVector &key, const QVector &value, const QVector &keyError) { mData->clear(); int n = key.size(); n = qMin(n, value.size()); n = qMin(n, keyError.size()); QCPData newData; for (int i=0; iinsertMulti(key[i], newData); } } /*! \overload Replaces the current data with the provided points in \a key and \a value pairs. Additionally the negative key error of the data points are set to the values in \a keyErrorMinus, the positive key error to \a keyErrorPlus. For error bars to show appropriately, see \ref setErrorType. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. */ void QCPGraph::setDataKeyError(const QVector &key, const QVector &value, const QVector &keyErrorMinus, const QVector &keyErrorPlus) { mData->clear(); int n = key.size(); n = qMin(n, value.size()); n = qMin(n, keyErrorMinus.size()); n = qMin(n, keyErrorPlus.size()); QCPData newData; for (int i=0; iinsertMulti(key[i], newData); } } /*! Replaces the current data with the provided points in \a key and \a value pairs. Additionally the symmetrical key and value errors of the data points are set to the values in \a keyError and \a valueError. For error bars to show appropriately, see \ref setErrorType. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. For asymmetrical errors (plus different from minus), see the overloaded version of this function. */ void QCPGraph::setDataBothError(const QVector &key, const QVector &value, const QVector &keyError, const QVector &valueError) { mData->clear(); int n = key.size(); n = qMin(n, value.size()); n = qMin(n, valueError.size()); n = qMin(n, keyError.size()); QCPData newData; for (int i=0; iinsertMulti(key[i], newData); } } /*! \overload Replaces the current data with the provided points in \a key and \a value pairs. Additionally the negative key and value errors of the data points are set to the values in \a keyErrorMinus and \a valueErrorMinus. The positive key and value errors are set to the values in \a keyErrorPlus \a valueErrorPlus. For error bars to show appropriately, see \ref setErrorType. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. */ void QCPGraph::setDataBothError(const QVector &key, const QVector &value, const QVector &keyErrorMinus, const QVector &keyErrorPlus, const QVector &valueErrorMinus, const QVector &valueErrorPlus) { mData->clear(); int n = key.size(); n = qMin(n, value.size()); n = qMin(n, valueErrorMinus.size()); n = qMin(n, valueErrorPlus.size()); n = qMin(n, keyErrorMinus.size()); n = qMin(n, keyErrorPlus.size()); QCPData newData; for (int i=0; iinsertMulti(key[i], newData); } } /*! Sets how the single data points are connected in the plot or how they are represented visually apart from the scatter symbol. For scatter-only plots, set \a ls to \ref lsNone and \ref setScatterStyle to the desired scatter style. \see setScatterStyle */ void QCPGraph::setLineStyle(LineStyle ls) { mLineStyle = ls; } /*! Sets the visual appearance of single data points in the plot. If set to \ref QCP::ssNone, no scatter points are drawn (e.g. for line-only-plots with appropriate line style). \see ScatterStyle, setLineStyle */ void QCPGraph::setScatterStyle(QCP::ScatterStyle ss) { mScatterStyle = ss; } /*! This defines how big (in pixels) single scatters are drawn, if scatter style (\ref setScatterStyle) isn't \ref QCP::ssNone, \ref QCP::ssDot or \ref QCP::ssPixmap. Floating point values are allowed for fine grained control over optical appearance with antialiased painting. \see ScatterStyle */ void QCPGraph::setScatterSize(double size) { mScatterSize = size; } /*! If the scatter style (\ref setScatterStyle) is set to ssPixmap, this function defines the QPixmap that will be drawn centered on the data point coordinate. \see ScatterStyle */ void QCPGraph::setScatterPixmap(const QPixmap &pixmap) { mScatterPixmap = pixmap; } /*! Sets which kind of error bars (Key Error, Value Error or both) should be drawn on each data point. If you set \a errorType to something other than \ref etNone, make sure to actually pass error data via the specific setData functions along with the data points (e.g. \ref setDataValueError, \ref setDataKeyError, \ref setDataBothError). \see ErrorType */ void QCPGraph::setErrorType(ErrorType errorType) { mErrorType = errorType; } /*! Sets the pen with which the error bars will be drawn. \see setErrorBarSize, setErrorType */ void QCPGraph::setErrorPen(const QPen &pen) { mErrorPen = pen; } /*! Sets the width of the handles at both ends of an error bar in pixels. */ void QCPGraph::setErrorBarSize(double size) { mErrorBarSize = size; } /*! If \a enabled is set to true, the error bar will not be drawn as a solid line under the scatter symbol but leave some free space around the symbol. This feature uses the current scatter size (\ref setScatterSize) to determine the size of the area to leave blank. So when drawing Pixmaps as scatter points (\ref QCP::ssPixmap), the scatter size must be set manually to a value corresponding to the size of the Pixmap, if the error bars should leave gaps to its boundaries. */ void QCPGraph::setErrorBarSkipSymbol(bool enabled) { mErrorBarSkipSymbol = enabled; } /*! Sets the target graph for filling the area between this graph and \a targetGraph with the current brush (\ref setBrush). When \a targetGraph is set to 0, a normal graph fill will be produced. This means, when the brush is not Qt::NoBrush or fully transparent, a fill all the way to the zero-value-line parallel to the key axis of this graph will be drawn. To disable any filling, set the brush to Qt::NoBrush. \see setBrush */ void QCPGraph::setChannelFillGraph(QCPGraph *targetGraph) { // prevent setting channel target to this graph itself: if (targetGraph == this) { qDebug() << Q_FUNC_INFO << "targetGraph is this graph itself"; mChannelFillGraph = 0; return; } // prevent setting channel target to a graph not in the plot: if (targetGraph && targetGraph->mParentPlot != mParentPlot) { qDebug() << Q_FUNC_INFO << "targetGraph not in same plot"; mChannelFillGraph = 0; return; } mChannelFillGraph = targetGraph; } /*! Adds the provided data points in \a dataMap to the current data. \see removeData */ void QCPGraph::addData(const QCPDataMap &dataMap) { mData->unite(dataMap); } /*! \overload Adds the provided single data point in \a data to the current data. \see removeData */ void QCPGraph::addData(const QCPData &data) { mData->insertMulti(data.key, data); } /*! \overload Adds the provided single data point as \a key and \a value pair to the current data. \see removeData */ void QCPGraph::addData(double key, double value) { QCPData newData; newData.key = key; newData.value = value; mData->insertMulti(newData.key, newData); } /*! \overload Adds the provided data points as \a key and \a value pairs to the current data. \see removeData */ void QCPGraph::addData(const QVector &keys, const QVector &values) { int n = qMin(keys.size(), values.size()); QCPData newData; for (int i=0; iinsertMulti(newData.key, newData); } } /*! Removes all data points with keys smaller than \a key. \see addData, clearData */ void QCPGraph::removeDataBefore(double key) { QCPDataMap::iterator it = mData->begin(); while (it != mData->end() && it.key() < key) it = mData->erase(it); } /*! Removes all data points with keys greater than \a key. \see addData, clearData */ void QCPGraph::removeDataAfter(double key) { if (mData->isEmpty()) return; QCPDataMap::iterator it = mData->upperBound(key); while (it != mData->end()) it = mData->erase(it); } /*! Removes all data points with keys between \a fromKey and \a toKey. if \a fromKey is greater or equal to \a toKey, the function does nothing. To remove a single data point with known key, use \ref removeData(double key). \see addData, clearData */ void QCPGraph::removeData(double fromKey, double toKey) { if (fromKey >= toKey || mData->isEmpty()) return; QCPDataMap::iterator it = mData->upperBound(fromKey); QCPDataMap::iterator itEnd = mData->upperBound(toKey); while (it != itEnd) it = mData->erase(it); } /*! \overload Removes a single data point at \a key. If the position is not known with absolute precision, consider using \ref removeData(double fromKey, double toKey) with a small fuzziness interval around the suspected position, depeding on the precision with which the key is known. \see addData, clearData */ void QCPGraph::removeData(double key) { mData->remove(key); } /*! Removes all data points. \see removeData, removeDataAfter, removeDataBefore */ void QCPGraph::clearData() { mData->clear(); } /* inherits documentation from base class */ double QCPGraph::selectTest(const QPointF &pos) const { if (mData->isEmpty() || !mVisible) return -1; return pointDistance(pos); } /*! \overload Allows to define whether error bars are taken into consideration when determining the new axis range. */ void QCPGraph::rescaleAxes(bool onlyEnlarge, bool includeErrorBars) const { rescaleKeyAxis(onlyEnlarge, includeErrorBars); rescaleValueAxis(onlyEnlarge, includeErrorBars); } /*! \overload Allows to define whether error bars (of kind \ref QCPGraph::etKey) are taken into consideration when determining the new axis range. */ void QCPGraph::rescaleKeyAxis(bool onlyEnlarge, bool includeErrorBars) const { // this code is a copy of QCPAbstractPlottable::rescaleKeyAxis with the only change // that getKeyRange is passed the includeErrorBars value. if (mData->isEmpty()) return; SignDomain signDomain = sdBoth; if (mKeyAxis->scaleType() == QCPAxis::stLogarithmic) signDomain = (mKeyAxis->range().upper < 0 ? sdNegative : sdPositive); bool validRange; QCPRange newRange = getKeyRange(validRange, signDomain, includeErrorBars); if (validRange) { if (onlyEnlarge) { if (mKeyAxis->range().lower < newRange.lower) newRange.lower = mKeyAxis->range().lower; if (mKeyAxis->range().upper > newRange.upper) newRange.upper = mKeyAxis->range().upper; } mKeyAxis->setRange(newRange); } } /*! \overload Allows to define whether error bars (of kind \ref QCPGraph::etValue) are taken into consideration when determining the new axis range. */ void QCPGraph::rescaleValueAxis(bool onlyEnlarge, bool includeErrorBars) const { // this code is a copy of QCPAbstractPlottable::rescaleValueAxis with the only change // is that getValueRange is passed the includeErrorBars value. if (mData->isEmpty()) return; SignDomain signDomain = sdBoth; if (mValueAxis->scaleType() == QCPAxis::stLogarithmic) signDomain = (mValueAxis->range().upper < 0 ? sdNegative : sdPositive); bool validRange; QCPRange newRange = getValueRange(validRange, signDomain, includeErrorBars); if (validRange) { if (onlyEnlarge) { if (mValueAxis->range().lower < newRange.lower) newRange.lower = mValueAxis->range().lower; if (mValueAxis->range().upper > newRange.upper) newRange.upper = mValueAxis->range().upper; } mValueAxis->setRange(newRange); } } /* inherits documentation from base class */ void QCPGraph::draw(QCPPainter *painter) { if (mKeyAxis->range().size() <= 0 || mData->isEmpty()) return; if (mLineStyle == lsNone && mScatterStyle == QCP::ssNone) return; // allocate line and (if necessary) point vectors: QVector *lineData = new QVector; QVector *pointData = 0; if (mScatterStyle != QCP::ssNone) pointData = new QVector; // fill vectors with data appropriate to plot style: getPlotData(lineData, pointData); // draw fill of graph: drawFill(painter, lineData); // draw line: if (mLineStyle == lsImpulse) drawImpulsePlot(painter, lineData); else if (mLineStyle != lsNone) drawLinePlot(painter, lineData); // also step plots can be drawn as a line plot // draw scatters: if (pointData) drawScatterPlot(painter, pointData); // free allocated line and point vectors: delete lineData; if (pointData) delete pointData; } /* inherits documentation from base class */ void QCPGraph::drawLegendIcon(QCPPainter *painter, const QRect &rect) const { // draw fill: if (mBrush.style() != Qt::NoBrush) { applyFillAntialiasingHint(painter); painter->fillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush); } // draw line vertically centered: if (mLineStyle != lsNone) { applyDefaultAntialiasingHint(painter); painter->setPen(mPen); painter->drawLine(QLineF(rect.left(), rect.top()+rect.height()/2.0, rect.right()+5, rect.top()+rect.height()/2.0)); // +5 on x2 else last segment is missing from dashed/dotted pens } // draw scatter symbol: if (mScatterStyle != QCP::ssNone) { if (mScatterStyle == QCP::ssPixmap && (mScatterPixmap.size().width() > rect.width() || mScatterPixmap.size().height() > rect.height())) { // handle pixmap scatters that are larger than legend icon rect separately. // We resize them and draw them manually, instead of calling drawScatter: QSize newSize = mScatterPixmap.size(); newSize.scale(rect.size(), Qt::KeepAspectRatio); QRect targetRect; targetRect.setSize(newSize); targetRect.moveCenter(rect.center()); bool smoothBackup = painter->testRenderHint(QPainter::SmoothPixmapTransform); painter->setRenderHint(QPainter::SmoothPixmapTransform, true); painter->drawPixmap(targetRect, mScatterPixmap); painter->setRenderHint(QPainter::SmoothPixmapTransform, smoothBackup); } else { applyScattersAntialiasingHint(painter); painter->setPen(mPen); painter->drawScatter(QRectF(rect).center().x(), QRectF(rect).center().y(), mScatterSize, mScatterStyle); } } } /*! \internal This function branches out to the line style specific "get(...)PlotData" functions, according to the line style of the graph. \param lineData will be filled with raw points that will be drawn with the according draw functions, e.g. \ref drawLinePlot and \ref drawImpulsePlot. These aren't necessarily the original data points, since for step plots for example, additional points are needed for drawing lines that make up steps. If the line style of the graph is \ref lsNone, the \a lineData vector will be left untouched. \param pointData will be filled with the original data points so \ref drawScatterPlot can draw the scatter symbols accordingly. If no scatters need to be drawn, i.e. scatter style is \ref QCP::ssNone, pass 0 as \a pointData, and this step will be skipped. \see getScatterPlotData, getLinePlotData, getStepLeftPlotData, getStepRightPlotData, getStepCenterPlotData, getImpulsePlotData */ void QCPGraph::getPlotData(QVector *lineData, QVector *pointData) const { switch(mLineStyle) { case lsNone: getScatterPlotData(pointData); break; case lsLine: getLinePlotData(lineData, pointData); break; case lsStepLeft: getStepLeftPlotData(lineData, pointData); break; case lsStepRight: getStepRightPlotData(lineData, pointData); break; case lsStepCenter: getStepCenterPlotData(lineData, pointData); break; case lsImpulse: getImpulsePlotData(lineData, pointData); break; } } /*! \internal If line style is \ref lsNone and scatter style is not \ref QCP::ssNone, this function serves at providing the visible data points in \a pointData, so the \ref drawScatterPlot function can draw the scatter points accordingly. If line style is not \ref lsNone, this function is not called and the data for the scatter points are (if needed) calculated inside the corresponding other "get(...)PlotData" functions. \see drawScatterPlot */ void QCPGraph::getScatterPlotData(QVector *pointData) const { if (!pointData) return; // get visible data range: QCPDataMap::const_iterator lower, upper; int dataCount; getVisibleDataBounds(lower, upper, dataCount); // prepare vectors: if (pointData) pointData->resize(dataCount); // position data points: QCPDataMap::const_iterator it = lower; QCPDataMap::const_iterator upperEnd = upper+1; int i = 0; if (mKeyAxis->orientation() == Qt::Vertical) { while (it != upperEnd) { (*pointData)[i] = it.value(); ++i; ++it; } } else // key axis is horizontal { while (it != upperEnd) { (*pointData)[i] = it.value(); ++i; ++it; } } } /*! \internal Places the raw data points needed for a normal linearly connected plot in \a lineData. As for all plot data retrieval functions, \a pointData just contains all unaltered data (scatter) points that are visible, for drawing scatter points, if necessary. If drawing scatter points is disabled (i.e. scatter style \ref QCP::ssNone), pass 0 as \a pointData, and the function will skip filling the vector. \see drawLinePlot */ void QCPGraph::getLinePlotData(QVector *lineData, QVector *pointData) const { // get visible data range: QCPDataMap::const_iterator lower, upper; int dataCount; getVisibleDataBounds(lower, upper, dataCount); // prepare vectors: if (lineData) { // added 2 to reserve memory for lower/upper fill base points that might be needed for fill lineData->reserve(dataCount+2); lineData->resize(dataCount); } if (pointData) pointData->resize(dataCount); // position data points: QCPDataMap::const_iterator it = lower; QCPDataMap::const_iterator upperEnd = upper+1; int i = 0; if (mKeyAxis->orientation() == Qt::Vertical) { while (it != upperEnd) { if (pointData) (*pointData)[i] = it.value(); (*lineData)[i].setX(mValueAxis->coordToPixel(it.value().value)); (*lineData)[i].setY(mKeyAxis->coordToPixel(it.key())); ++i; ++it; } } else // key axis is horizontal { while (it != upperEnd) { if (pointData) (*pointData)[i] = it.value(); (*lineData)[i].setX(mKeyAxis->coordToPixel(it.key())); (*lineData)[i].setY(mValueAxis->coordToPixel(it.value().value)); ++i; ++it; } } } /*! \internal Places the raw data points needed for a step plot with left oriented steps in \a lineData. As for all plot data retrieval functions, \a pointData just contains all unaltered data (scatter) points that are visible, for drawing scatter points, if necessary. If drawing scatter points is disabled (i.e. scatter style \ref QCP::ssNone), pass 0 as \a pointData, and the function will skip filling the vector. \see drawLinePlot */ void QCPGraph::getStepLeftPlotData(QVector *lineData, QVector *pointData) const { // get visible data range: QCPDataMap::const_iterator lower, upper; int dataCount; getVisibleDataBounds(lower, upper, dataCount); // prepare vectors: if (lineData) { // added 2 to reserve memory for lower/upper fill base points that might be needed for fill // multiplied by 2 because step plot needs two polyline points per one actual data point lineData->reserve(dataCount*2+2); lineData->resize(dataCount*2); } if (pointData) pointData->resize(dataCount); // position data points: QCPDataMap::const_iterator it = lower; QCPDataMap::const_iterator upperEnd = upper+1; int i = 0; int ipoint = 0; if (mKeyAxis->orientation() == Qt::Vertical) { double lastValue = mValueAxis->coordToPixel(it.value().value); double key; while (it != upperEnd) { if (pointData) { (*pointData)[ipoint] = it.value(); ++ipoint; } key = mKeyAxis->coordToPixel(it.key()); (*lineData)[i].setX(lastValue); (*lineData)[i].setY(key); ++i; lastValue = mValueAxis->coordToPixel(it.value().value); (*lineData)[i].setX(lastValue); (*lineData)[i].setY(key); ++i; ++it; } } else // key axis is horizontal { double lastValue = mValueAxis->coordToPixel(it.value().value); double key; while (it != upperEnd) { if (pointData) { (*pointData)[ipoint] = it.value(); ++ipoint; } key = mKeyAxis->coordToPixel(it.key()); (*lineData)[i].setX(key); (*lineData)[i].setY(lastValue); ++i; lastValue = mValueAxis->coordToPixel(it.value().value); (*lineData)[i].setX(key); (*lineData)[i].setY(lastValue); ++i; ++it; } } } /*! \internal Places the raw data points needed for a step plot with right oriented steps in \a lineData. As for all plot data retrieval functions, \a pointData just contains all unaltered data (scatter) points that are visible, for drawing scatter points, if necessary. If drawing scatter points is disabled (i.e. scatter style \ref QCP::ssNone), pass 0 as \a pointData, and the function will skip filling the vector. \see drawLinePlot */ void QCPGraph::getStepRightPlotData(QVector *lineData, QVector *pointData) const { // get visible data range: QCPDataMap::const_iterator lower, upper; int dataCount; getVisibleDataBounds(lower, upper, dataCount); // prepare vectors: if (lineData) { // added 2 to reserve memory for lower/upper fill base points that might be needed for fill // multiplied by 2 because step plot needs two polyline points per one actual data point lineData->reserve(dataCount*2+2); lineData->resize(dataCount*2); } if (pointData) pointData->resize(dataCount); // position points: QCPDataMap::const_iterator it = lower; QCPDataMap::const_iterator upperEnd = upper+1; int i = 0; int ipoint = 0; if (mKeyAxis->orientation() == Qt::Vertical) { double lastKey = mKeyAxis->coordToPixel(it.key()); double value; while (it != upperEnd) { if (pointData) { (*pointData)[ipoint] = it.value(); ++ipoint; } value = mValueAxis->coordToPixel(it.value().value); (*lineData)[i].setX(value); (*lineData)[i].setY(lastKey); ++i; lastKey = mKeyAxis->coordToPixel(it.key()); (*lineData)[i].setX(value); (*lineData)[i].setY(lastKey); ++i; ++it; } } else // key axis is horizontal { double lastKey = mKeyAxis->coordToPixel(it.key()); double value; while (it != upperEnd) { if (pointData) { (*pointData)[ipoint] = it.value(); ++ipoint; } value = mValueAxis->coordToPixel(it.value().value); (*lineData)[i].setX(lastKey); (*lineData)[i].setY(value); ++i; lastKey = mKeyAxis->coordToPixel(it.key()); (*lineData)[i].setX(lastKey); (*lineData)[i].setY(value); ++i; ++it; } } } /*! \internal Places the raw data points needed for a step plot with centered steps in \a lineData. As for all plot data retrieval functions, \a pointData just contains all unaltered data (scatter) points that are visible, for drawing scatter points, if necessary. If drawing scatter points is disabled (i.e. scatter style \ref QCP::ssNone), pass 0 as \a pointData, and the function will skip filling the vector. \see drawLinePlot */ void QCPGraph::getStepCenterPlotData(QVector *lineData, QVector *pointData) const { // get visible data range: QCPDataMap::const_iterator lower, upper; int dataCount; getVisibleDataBounds(lower, upper, dataCount); // prepare vectors: if (lineData) { // added 2 to reserve memory for lower/upper fill base points that might be needed for base fill // multiplied by 2 because step plot needs two polyline points per one actual data point lineData->reserve(dataCount*2+2); lineData->resize(dataCount*2); } if (pointData) pointData->resize(dataCount); // position points: QCPDataMap::const_iterator it = lower; QCPDataMap::const_iterator upperEnd = upper+1; int i = 0; int ipoint = 0; if (mKeyAxis->orientation() == Qt::Vertical) { double lastKey = mKeyAxis->coordToPixel(it.key()); double lastValue = mValueAxis->coordToPixel(it.value().value); double key; if (pointData) { (*pointData)[ipoint] = it.value(); ++ipoint; } (*lineData)[i].setX(lastValue); (*lineData)[i].setY(lastKey); ++it; ++i; while (it != upperEnd) { if (pointData) { (*pointData)[ipoint] = it.value(); ++ipoint; } key = (mKeyAxis->coordToPixel(it.key())-lastKey)*0.5 + lastKey; (*lineData)[i].setX(lastValue); (*lineData)[i].setY(key); ++i; lastValue = mValueAxis->coordToPixel(it.value().value); lastKey = mKeyAxis->coordToPixel(it.key()); (*lineData)[i].setX(lastValue); (*lineData)[i].setY(key); ++it; ++i; } (*lineData)[i].setX(lastValue); (*lineData)[i].setY(lastKey); } else // key axis is horizontal { double lastKey = mKeyAxis->coordToPixel(it.key()); double lastValue = mValueAxis->coordToPixel(it.value().value); double key; if (pointData) { (*pointData)[ipoint] = it.value(); ++ipoint; } (*lineData)[i].setX(lastKey); (*lineData)[i].setY(lastValue); ++it; ++i; while (it != upperEnd) { if (pointData) { (*pointData)[ipoint] = it.value(); ++ipoint; } key = (mKeyAxis->coordToPixel(it.key())-lastKey)*0.5 + lastKey; (*lineData)[i].setX(key); (*lineData)[i].setY(lastValue); ++i; lastValue = mValueAxis->coordToPixel(it.value().value); lastKey = mKeyAxis->coordToPixel(it.key()); (*lineData)[i].setX(key); (*lineData)[i].setY(lastValue); ++it; ++i; } (*lineData)[i].setX(lastKey); (*lineData)[i].setY(lastValue); } } /*! \internal Places the raw data points needed for an impulse plot in \a lineData. As for all plot data retrieval functions, \a pointData just contains all unaltered data (scatter) points that are visible, for drawing scatter points, if necessary. If drawing scatter points is disabled (i.e. scatter style \ref QCP::ssNone), pass 0 as \a pointData, and the function will skip filling the vector. \see drawImpulsePlot */ void QCPGraph::getImpulsePlotData(QVector *lineData, QVector *pointData) const { // get visible data range: QCPDataMap::const_iterator lower, upper; int dataCount; getVisibleDataBounds(lower, upper, dataCount); // prepare vectors: if (lineData) { // no need to reserve 2 extra points, because there is no fill for impulse plot lineData->resize(dataCount*2); } if (pointData) pointData->resize(dataCount); // position data points: QCPDataMap::const_iterator it = lower; QCPDataMap::const_iterator upperEnd = upper+1; int i = 0; int ipoint = 0; if (mKeyAxis->orientation() == Qt::Vertical) { double zeroPointX = mValueAxis->coordToPixel(0); double key; while (it != upperEnd) { if (pointData) { (*pointData)[ipoint] = it.value(); ++ipoint; } key = mKeyAxis->coordToPixel(it.key()); (*lineData)[i].setX(zeroPointX); (*lineData)[i].setY(key); ++i; (*lineData)[i].setX(mValueAxis->coordToPixel(it.value().value)); (*lineData)[i].setY(key); ++i; ++it; } } else // key axis is horizontal { double zeroPointY = mValueAxis->coordToPixel(0); double key; while (it != upperEnd) { if (pointData) { (*pointData)[ipoint] = it.value(); ++ipoint; } key = mKeyAxis->coordToPixel(it.key()); (*lineData)[i].setX(key); (*lineData)[i].setY(zeroPointY); ++i; (*lineData)[i].setX(key); (*lineData)[i].setY(mValueAxis->coordToPixel(it.value().value)); ++i; ++it; } } } /*! \internal Draws the fill of the graph with the specified brush. If the fill is a normal "base" fill, i.e. under the graph toward the zero-value-line, only the \a lineData is required (and two extra points at the zero-value-line, which are added by \ref addFillBasePoints and removed by \ref removeFillBasePoints after the fill drawing is done). If the fill is a channel fill between this graph and another graph (mChannelFillGraph), the more complex polygon is calculated with the \ref getChannelFillPolygon function. \see drawLinePlot */ void QCPGraph::drawFill(QCPPainter *painter, QVector *lineData) const { if (mLineStyle == lsImpulse) return; // fill doesn't make sense for impulse plot if (mainBrush().style() == Qt::NoBrush || mainBrush().color().alpha() == 0) return; applyFillAntialiasingHint(painter); if (!mChannelFillGraph) { // draw base fill under graph, fill goes all the way to the zero-value-line: addFillBasePoints(lineData); painter->setPen(Qt::NoPen); painter->setBrush(mainBrush()); painter->drawPolygon(QPolygonF(*lineData)); removeFillBasePoints(lineData); } else { // draw channel fill between this graph and mChannelFillGraph: painter->setPen(Qt::NoPen); painter->setBrush(mainBrush()); painter->drawPolygon(getChannelFillPolygon(lineData)); } } /*! \internal Draws scatter symbols at every data point passed in \a pointData. scatter symbols are independent of the line style and are always drawn if scatter style is not \ref QCP::ssNone. Hence, the \a pointData vector is outputted by all "get(...)PlotData" functions, together with the (line style dependent) line data. \see drawLinePlot, drawImpulsePlot */ void QCPGraph::drawScatterPlot(QCPPainter *painter, QVector *pointData) const { // draw error bars: if (mErrorType != etNone) { applyErrorBarsAntialiasingHint(painter); painter->setPen(mErrorPen); if (mKeyAxis->orientation() == Qt::Vertical) { for (int i=0; isize(); ++i) drawError(painter, mValueAxis->coordToPixel(pointData->at(i).value), mKeyAxis->coordToPixel(pointData->at(i).key), pointData->at(i)); } else { for (int i=0; isize(); ++i) drawError(painter, mKeyAxis->coordToPixel(pointData->at(i).key), mValueAxis->coordToPixel(pointData->at(i).value), pointData->at(i)); } } // draw scatter point symbols: applyScattersAntialiasingHint(painter); painter->setPen(mainPen()); painter->setBrush(mainBrush()); painter->setScatterPixmap(mScatterPixmap); if (mKeyAxis->orientation() == Qt::Vertical) { for (int i=0; isize(); ++i) painter->drawScatter(mValueAxis->coordToPixel(pointData->at(i).value), mKeyAxis->coordToPixel(pointData->at(i).key), mScatterSize, mScatterStyle); } else { for (int i=0; isize(); ++i) painter->drawScatter(mKeyAxis->coordToPixel(pointData->at(i).key), mValueAxis->coordToPixel(pointData->at(i).value), mScatterSize, mScatterStyle); } } /*! \internal Draws line graphs from the provided data. It connects all points in \a lineData, which was created by one of the "get(...)PlotData" functions for line styles that require simple line connections between the point vector they create. These are for example \ref getLinePlotData, \ref getStepLeftPlotData, \ref getStepRightPlotData and \ref getStepCenterPlotData. \see drawScatterPlot, drawImpulsePlot */ void QCPGraph::drawLinePlot(QCPPainter *painter, QVector *lineData) const { // draw line of graph: if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0) { applyDefaultAntialiasingHint(painter); painter->setPen(mainPen()); painter->setBrush(Qt::NoBrush); /* Draws polyline in batches, currently not used: int p = 0; while (p < lineData->size()) { int batch = qMin(25, lineData->size()-p); if (p != 0) { ++batch; --p; // to draw the connection lines between two batches } painter->drawPolyline(lineData->constData()+p, batch); p += batch; } */ // if drawing solid line and not in PDF, use much faster line drawing instead of polyline: if (mParentPlot->plottingHints().testFlag(QCP::phFastPolylines) && painter->pen().style() == Qt::SolidLine && !painter->pdfExportMode()) { for (int i=1; isize(); ++i) painter->drawLine(lineData->at(i-1), lineData->at(i)); } else { painter->drawPolyline(QPolygonF(*lineData)); } } } /*! \internal Draws impulses graphs from the provided data, i.e. it connects all line pairs in \a lineData, which was created by \ref getImpulsePlotData. \see drawScatterPlot, drawLinePlot */ void QCPGraph::drawImpulsePlot(QCPPainter *painter, QVector *lineData) const { // draw impulses: if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0) { applyDefaultAntialiasingHint(painter); QPen pen = mainPen(); pen.setCapStyle(Qt::FlatCap); // so impulse line doesn't reach beyond zero-line painter->setPen(pen); painter->setBrush(Qt::NoBrush); painter->drawLines(*lineData); } } /*! \internal called by the scatter drawing function (\ref drawScatterPlot) to draw the error bars on one data point. \a x and \a y pixel positions of the data point are passed since they are already known in pixel coordinates in the drawing function, so we save some extra coordToPixel transforms here. \a data is therefore only used for the errors, not key and value. */ void QCPGraph::drawError(QCPPainter *painter, double x, double y, const QCPData &data) const { double a, b; // positions of error bar bounds in pixels double barWidthHalf = mErrorBarSize*0.5; double skipSymbolMargin = mScatterSize*1.25; // pixels left blank per side, when mErrorBarSkipSymbol is true if (mKeyAxis->orientation() == Qt::Vertical) { // draw key error vertically and value error horizontally if (mErrorType == etKey || mErrorType == etBoth) { a = mKeyAxis->coordToPixel(data.key-data.keyErrorMinus); b = mKeyAxis->coordToPixel(data.key+data.keyErrorPlus); if (mKeyAxis->rangeReversed()) qSwap(a,b); // draw spine: if (mErrorBarSkipSymbol) { if (a-y > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin painter->drawLine(QLineF(x, a, x, y+skipSymbolMargin)); if (y-b > skipSymbolMargin) painter->drawLine(QLineF(x, y-skipSymbolMargin, x, b)); } else painter->drawLine(QLineF(x, a, x, b)); // draw handles: painter->drawLine(QLineF(x-barWidthHalf, a, x+barWidthHalf, a)); painter->drawLine(QLineF(x-barWidthHalf, b, x+barWidthHalf, b)); } if (mErrorType == etValue || mErrorType == etBoth) { a = mValueAxis->coordToPixel(data.value-data.valueErrorMinus); b = mValueAxis->coordToPixel(data.value+data.valueErrorPlus); if (mValueAxis->rangeReversed()) qSwap(a,b); // draw spine: if (mErrorBarSkipSymbol) { if (x-a > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin painter->drawLine(QLineF(a, y, x-skipSymbolMargin, y)); if (b-x > skipSymbolMargin) painter->drawLine(QLineF(x+skipSymbolMargin, y, b, y)); } else painter->drawLine(QLineF(a, y, b, y)); // draw handles: painter->drawLine(QLineF(a, y-barWidthHalf, a, y+barWidthHalf)); painter->drawLine(QLineF(b, y-barWidthHalf, b, y+barWidthHalf)); } } else // mKeyAxis->orientation() is Qt::Horizontal { // draw value error vertically and key error horizontally if (mErrorType == etKey || mErrorType == etBoth) { a = mKeyAxis->coordToPixel(data.key-data.keyErrorMinus); b = mKeyAxis->coordToPixel(data.key+data.keyErrorPlus); if (mKeyAxis->rangeReversed()) qSwap(a,b); // draw spine: if (mErrorBarSkipSymbol) { if (x-a > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin painter->drawLine(QLineF(a, y, x-skipSymbolMargin, y)); if (b-x > skipSymbolMargin) painter->drawLine(QLineF(x+skipSymbolMargin, y, b, y)); } else painter->drawLine(QLineF(a, y, b, y)); // draw handles: painter->drawLine(QLineF(a, y-barWidthHalf, a, y+barWidthHalf)); painter->drawLine(QLineF(b, y-barWidthHalf, b, y+barWidthHalf)); } if (mErrorType == etValue || mErrorType == etBoth) { a = mValueAxis->coordToPixel(data.value-data.valueErrorMinus); b = mValueAxis->coordToPixel(data.value+data.valueErrorPlus); if (mValueAxis->rangeReversed()) qSwap(a,b); // draw spine: if (mErrorBarSkipSymbol) { if (a-y > skipSymbolMargin) // don't draw spine if error is so small it's within skipSymbolmargin painter->drawLine(QLineF(x, a, x, y+skipSymbolMargin)); if (y-b > skipSymbolMargin) painter->drawLine(QLineF(x, y-skipSymbolMargin, x, b)); } else painter->drawLine(QLineF(x, a, x, b)); // draw handles: painter->drawLine(QLineF(x-barWidthHalf, a, x+barWidthHalf, a)); painter->drawLine(QLineF(x-barWidthHalf, b, x+barWidthHalf, b)); } } } /*! \internal called by the specific plot data generating functions "get(...)PlotData" to determine which data range is visible, so only that needs to be processed. \param[out] lower returns an iterator to the lowest data point that needs to be taken into account when plotting. Note that in order to get a clean plot all the way to the edge of the axes, \a lower may still be outside the visible range. \param[out] upper returns an iterator to the highest data point. Same as before, \a upper may also lie outside of the visible range. \param[out] count number of data points that need plotting, i.e. points between \a lower and \a upper, including them. This is useful for allocating the array of QPointFs in the specific drawing functions. */ void QCPGraph::getVisibleDataBounds(QCPDataMap::const_iterator &lower, QCPDataMap::const_iterator &upper, int &count) const { // get visible data range as QMap iterators QCPDataMap::const_iterator lbound = mData->lowerBound(mKeyAxis->range().lower); QCPDataMap::const_iterator ubound = mData->upperBound(mKeyAxis->range().upper)-1; bool lowoutlier = lbound != mData->constBegin(); // indicates whether there exist points below axis range bool highoutlier = ubound+1 != mData->constEnd(); // indicates whether there exist points above axis range lower = (lowoutlier ? lbound-1 : lbound); // data pointrange that will be actually drawn upper = (highoutlier ? ubound+1 : ubound); // data pointrange that will be actually drawn // count number of points in range lower to upper (including them), so we can allocate array for them in draw functions: QCPDataMap::const_iterator it = lower; count = 1; while (it != upper) { ++it; ++count; } } /*! \internal The line data vector generated by e.g. getLinePlotData contains only the line that connects the data points. If the graph needs to be filled, two additional points need to be added at the value-zero-line in the lower and upper key positions, the graph reaches. This function calculates these points and adds them to the end of \a lineData. Since the fill is typically drawn before the line stroke, these added points need to be removed again after the fill is done, with the removeFillBasePoints function. The expanding of \a lineData by two points will not cause unnecessary memory reallocations, because the data vector generation functions (getLinePlotData etc.) reserve two extra points when they allocate memory for \a lineData. \see removeFillBasePoints, lowerFillBasePoint, upperFillBasePoint */ void QCPGraph::addFillBasePoints(QVector *lineData) const { // append points that close the polygon fill at the key axis: if (mKeyAxis->orientation() == Qt::Vertical) { *lineData << upperFillBasePoint(lineData->last().y()); *lineData << lowerFillBasePoint(lineData->first().y()); } else { *lineData << upperFillBasePoint(lineData->last().x()); *lineData << lowerFillBasePoint(lineData->first().x()); } } /*! \internal removes the two points from \a lineData that were added by addFillBasePoints. \see addFillBasePoints, lowerFillBasePoint, upperFillBasePoint */ void QCPGraph::removeFillBasePoints(QVector *lineData) const { lineData->remove(lineData->size()-2, 2); } /*! \internal called by addFillBasePoints to conveniently assign the point which closes the fill polygon on the lower side of the zero-value-line parallel to the key axis. The logarithmic axis scale case is a bit special, since the zero-value-line in pixel coordinates is in positive or negative infinity. So this case is handled separately by just closing the fill polygon on the axis which lies in the direction towards the zero value. \param lowerKey pixel position of the lower key of the point. Depending on whether the key axis is horizontal or vertical, \a lowerKey will end up as the x or y value of the returned point, respectively. \see upperFillBasePoint, addFillBasePoints */ QPointF QCPGraph::lowerFillBasePoint(double lowerKey) const { QPointF point; if (mValueAxis->scaleType() == QCPAxis::stLinear) { if (mKeyAxis->axisType() == QCPAxis::atLeft) { point.setX(mValueAxis->coordToPixel(0)); point.setY(lowerKey); } else if (mKeyAxis->axisType() == QCPAxis::atRight) { point.setX(mValueAxis->coordToPixel(0)); point.setY(lowerKey); } else if (mKeyAxis->axisType() == QCPAxis::atTop) { point.setX(lowerKey); point.setY(mValueAxis->coordToPixel(0)); } else if (mKeyAxis->axisType() == QCPAxis::atBottom) { point.setX(lowerKey); point.setY(mValueAxis->coordToPixel(0)); } } else // mValueAxis->mScaleType == QCPAxis::stLogarithmic { // In logarithmic scaling we can't just draw to value zero so we just fill all the way // to the axis which is in the direction towards zero if (mKeyAxis->orientation() == Qt::Vertical) { if ((mValueAxis->range().upper < 0 && !mValueAxis->rangeReversed()) || (mValueAxis->range().upper > 0 && mValueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis point.setX(mKeyAxis->axisRect().right()); else point.setX(mKeyAxis->axisRect().left()); point.setY(lowerKey); } else if (mKeyAxis->axisType() == QCPAxis::atTop || mKeyAxis->axisType() == QCPAxis::atBottom) { point.setX(lowerKey); if ((mValueAxis->range().upper < 0 && !mValueAxis->rangeReversed()) || (mValueAxis->range().upper > 0 && mValueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis point.setY(mKeyAxis->axisRect().top()); else point.setY(mKeyAxis->axisRect().bottom()); } } return point; } /*! \internal called by addFillBasePoints to conveniently assign the point which closes the fill polygon on the upper side of the zero-value-line parallel to the key axis. The logarithmic axis scale case is a bit special, since the zero-value-line in pixel coordinates is in positive or negative infinity. So this case is handled separately by just closing the fill polygon on the axis which lies in the direction towards the zero value. \param upperKey pixel position of the upper key of the point. Depending on whether the key axis is horizontal or vertical, \a upperKey will end up as the x or y value of the returned point, respectively. \see lowerFillBasePoint, addFillBasePoints */ QPointF QCPGraph::upperFillBasePoint(double upperKey) const { QPointF point; if (mValueAxis->scaleType() == QCPAxis::stLinear) { if (mKeyAxis->axisType() == QCPAxis::atLeft) { point.setX(mValueAxis->coordToPixel(0)); point.setY(upperKey); } else if (mKeyAxis->axisType() == QCPAxis::atRight) { point.setX(mValueAxis->coordToPixel(0)); point.setY(upperKey); } else if (mKeyAxis->axisType() == QCPAxis::atTop) { point.setX(upperKey); point.setY(mValueAxis->coordToPixel(0)); } else if (mKeyAxis->axisType() == QCPAxis::atBottom) { point.setX(upperKey); point.setY(mValueAxis->coordToPixel(0)); } } else // mValueAxis->mScaleType == QCPAxis::stLogarithmic { // In logarithmic scaling we can't just draw to value 0 so we just fill all the way // to the axis which is in the direction towards 0 if (mKeyAxis->orientation() == Qt::Vertical) { if ((mValueAxis->range().upper < 0 && !mValueAxis->rangeReversed()) || (mValueAxis->range().upper > 0 && mValueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis point.setX(mKeyAxis->axisRect().right()); else point.setX(mKeyAxis->axisRect().left()); point.setY(upperKey); } else if (mKeyAxis->axisType() == QCPAxis::atTop || mKeyAxis->axisType() == QCPAxis::atBottom) { point.setX(upperKey); if ((mValueAxis->range().upper < 0 && !mValueAxis->rangeReversed()) || (mValueAxis->range().upper > 0 && mValueAxis->rangeReversed())) // if range is negative, zero is on opposite side of key axis point.setY(mKeyAxis->axisRect().top()); else point.setY(mKeyAxis->axisRect().bottom()); } } return point; } /*! \internal Generates the polygon needed for drawing channel fills between this graph (data passed via \a lineData) and the graph specified by mChannelFillGraph (data generated by calling its \ref getPlotData function). May return an empty polygon if the key ranges have no overlap or fill target graph and this graph don't have same orientation (i.e. both key axes horizontal or both key axes vertical). For increased performance (due to implicit sharing), keep the returned QPolygonF const. */ const QPolygonF QCPGraph::getChannelFillPolygon(const QVector *lineData) const { if (mChannelFillGraph->mKeyAxis->orientation() != mKeyAxis->orientation()) return QPolygonF(); // don't have same axis orientation, can't fill that (Note: if keyAxis fits, valueAxis will fit too, because it's always orthogonal to keyAxis) if (lineData->isEmpty()) return QPolygonF(); QVector otherData; mChannelFillGraph->getPlotData(&otherData, 0); if (otherData.isEmpty()) return QPolygonF(); QVector thisData; thisData.reserve(lineData->size()+otherData.size()); // because we will join both vectors at end of this function for (int i=0; isize(); ++i) // don't use the vector<<(vector), it squeezes internally, which ruins the performance tuning with reserve() thisData << lineData->at(i); // pointers to be able to swap them, depending which data range needs cropping: QVector *staticData = &thisData; QVector *croppedData = &otherData; // crop both vectors to ranges in which the keys overlap (which coord is key, depends on axisType): if (mKeyAxis->orientation() == Qt::Horizontal) { // x is key // if an axis range is reversed, the data point keys will be descending. Reverse them, since following algorithm assumes ascending keys: if (staticData->first().x() > staticData->last().x()) { int size = staticData->size(); for (int i=0; ifirst().x() > croppedData->last().x()) { int size = croppedData->size(); for (int i=0; ifirst().x() < croppedData->first().x()) // other one must be cropped qSwap(staticData, croppedData); int lowBound = findIndexBelowX(croppedData, staticData->first().x()); if (lowBound == -1) return QPolygonF(); // key ranges have no overlap croppedData->remove(0, lowBound); // set lowest point of cropped data to fit exactly key position of first static data // point via linear interpolation: if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation double slope; if (croppedData->at(1).x()-croppedData->at(0).x() != 0) slope = (croppedData->at(1).y()-croppedData->at(0).y())/(croppedData->at(1).x()-croppedData->at(0).x()); else slope = 0; (*croppedData)[0].setY(croppedData->at(0).y()+slope*(staticData->first().x()-croppedData->at(0).x())); (*croppedData)[0].setX(staticData->first().x()); // crop upper bound: if (staticData->last().x() > croppedData->last().x()) // other one must be cropped qSwap(staticData, croppedData); int highBound = findIndexAboveX(croppedData, staticData->last().x()); if (highBound == -1) return QPolygonF(); // key ranges have no overlap croppedData->remove(highBound+1, croppedData->size()-(highBound+1)); // set highest point of cropped data to fit exactly key position of last static data // point via linear interpolation: if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation int li = croppedData->size()-1; // last index if (croppedData->at(li).x()-croppedData->at(li-1).x() != 0) slope = (croppedData->at(li).y()-croppedData->at(li-1).y())/(croppedData->at(li).x()-croppedData->at(li-1).x()); else slope = 0; (*croppedData)[li].setY(croppedData->at(li-1).y()+slope*(staticData->last().x()-croppedData->at(li-1).x())); (*croppedData)[li].setX(staticData->last().x()); } else // mKeyAxis->orientation() == Qt::Vertical { // y is key // similar to "x is key" but switched x,y. Further, lower/upper meaning is inverted compared to x, // because in pixel coordinates, y increases from top to bottom, not bottom to top like data coordinate. // if an axis range is reversed, the data point keys will be descending. Reverse them, since following algorithm assumes ascending keys: if (staticData->first().y() < staticData->last().y()) { int size = staticData->size(); for (int i=0; ifirst().y() < croppedData->last().y()) { int size = croppedData->size(); for (int i=0; ifirst().y() > croppedData->first().y()) // other one must be cropped qSwap(staticData, croppedData); int lowBound = findIndexAboveY(croppedData, staticData->first().y()); if (lowBound == -1) return QPolygonF(); // key ranges have no overlap croppedData->remove(0, lowBound); // set lowest point of cropped data to fit exactly key position of first static data // point via linear interpolation: if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation double slope; if (croppedData->at(1).y()-croppedData->at(0).y() != 0) // avoid division by zero in step plots slope = (croppedData->at(1).x()-croppedData->at(0).x())/(croppedData->at(1).y()-croppedData->at(0).y()); else slope = 0; (*croppedData)[0].setX(croppedData->at(0).x()+slope*(staticData->first().y()-croppedData->at(0).y())); (*croppedData)[0].setY(staticData->first().y()); // crop upper bound: if (staticData->last().y() < croppedData->last().y()) // other one must be cropped qSwap(staticData, croppedData); int highBound = findIndexBelowY(croppedData, staticData->last().y()); if (highBound == -1) return QPolygonF(); // key ranges have no overlap croppedData->remove(highBound+1, croppedData->size()-(highBound+1)); // set highest point of cropped data to fit exactly key position of last static data // point via linear interpolation: if (croppedData->size() < 2) return QPolygonF(); // need at least two points for interpolation int li = croppedData->size()-1; // last index if (croppedData->at(li).y()-croppedData->at(li-1).y() != 0) // avoid division by zero in step plots slope = (croppedData->at(li).x()-croppedData->at(li-1).x())/(croppedData->at(li).y()-croppedData->at(li-1).y()); else slope = 0; (*croppedData)[li].setX(croppedData->at(li-1).x()+slope*(staticData->last().y()-croppedData->at(li-1).y())); (*croppedData)[li].setY(staticData->last().y()); } // return joined: for (int i=otherData.size()-1; i>=0; --i) // insert reversed, otherwise the polygon will be twisted thisData << otherData.at(i); return QPolygonF(thisData); } /*! \internal Finds the smallest index of \a data, whose points x value is just above \a x. Assumes x values in \a data points are ordered ascending, as is the case when plotting with horizontal key axis. Used to calculate the channel fill polygon, see \ref getChannelFillPolygon. */ int QCPGraph::findIndexAboveX(const QVector *data, double x) const { for (int i=data->size()-1; i>=0; --i) { if (data->at(i).x() < x) { if (isize()-1) return i+1; else return data->size()-1; } } return -1; } /*! \internal Finds the greatest index of \a data, whose points x value is just below \a x. Assumes x values in \a data points are ordered ascending, as is the case when plotting with horizontal key axis. Used to calculate the channel fill polygon, see \ref getChannelFillPolygon. */ int QCPGraph::findIndexBelowX(const QVector *data, double x) const { for (int i=0; isize(); ++i) { if (data->at(i).x() > x) { if (i>0) return i-1; else return 0; } } return -1; } /*! \internal Finds the smallest index of \a data, whose points y value is just above \a y. Assumes y values in \a data points are ordered descending, as is the case when plotting with vertical key axis. Used to calculate the channel fill polygon, see \ref getChannelFillPolygon. */ int QCPGraph::findIndexAboveY(const QVector *data, double y) const { for (int i=0; isize(); ++i) { if (data->at(i).y() < y) { if (i>0) return i-1; else return 0; } } return -1; } /*! \internal Calculates the (minimum) distance (in pixels) the graph's representation has from the given \a pixelPoint in pixels. This is used to determine whether the graph was clicked or not, e.g. in \ref selectTest. */ double QCPGraph::pointDistance(const QPointF &pixelPoint) const { if (mData->isEmpty()) { qDebug() << Q_FUNC_INFO << "requested point distance on graph" << mName << "without data"; return 500; } if (mData->size() == 1) { QPointF dataPoint = coordsToPixels(mData->constBegin().key(), mData->constBegin().value().value); return QVector2D(dataPoint-pixelPoint).length(); } if (mLineStyle == lsNone && mScatterStyle == QCP::ssNone) return 500; // calculate minimum distances to graph representation: if (mLineStyle == lsNone) { // no line displayed, only calculate distance to scatter points: QVector *pointData = new QVector; getScatterPlotData(pointData); double minDistSqr = std::numeric_limits::max(); QPointF ptA; QPointF ptB = coordsToPixels(pointData->at(0).key, pointData->at(0).value); // getScatterPlotData returns in plot coordinates, so transform to pixels for (int i=1; isize(); ++i) { ptA = ptB; ptB = coordsToPixels(pointData->at(i).key, pointData->at(i).value); double currentDistSqr = distSqrToLine(ptA, ptB, pixelPoint); if (currentDistSqr < minDistSqr) minDistSqr = currentDistSqr; } delete pointData; return sqrt(minDistSqr); } else { // line displayed calculate distance to line segments: QVector *lineData = new QVector; getPlotData(lineData, 0); // unlike with getScatterPlotData we get pixel coordinates here double minDistSqr = std::numeric_limits::max(); if (mLineStyle == lsImpulse) { // impulse plot differs from other line styles in that the lineData points are only pairwise connected: for (int i=0; isize()-1; i+=2) // iterate pairs { double currentDistSqr = distSqrToLine(lineData->at(i), lineData->at(i+1), pixelPoint); if (currentDistSqr < minDistSqr) minDistSqr = currentDistSqr; } } else { // all other line plots (line and step) connect points directly: for (int i=0; isize()-1; ++i) { double currentDistSqr = distSqrToLine(lineData->at(i), lineData->at(i+1), pixelPoint); if (currentDistSqr < minDistSqr) minDistSqr = currentDistSqr; } } delete lineData; return sqrt(minDistSqr); } } /*! \internal Finds the greatest index of \a data, whose points y value is just below \a y. Assumes y values in \a data points are ordered descending, as is the case when plotting with vertical key axis (since keys are ordered ascending). Used to calculate the channel fill polygon, see \ref getChannelFillPolygon. */ int QCPGraph::findIndexBelowY(const QVector *data, double y) const { for (int i=data->size()-1; i>=0; --i) { if (data->at(i).y() > y) { if (isize()-1) return i+1; else return data->size()-1; } } return -1; } /* inherits documentation from base class */ QCPRange QCPGraph::getKeyRange(bool &validRange, SignDomain inSignDomain) const { // just call the specialized version which takes an additional argument whether error bars // should also be taken into consideration for range calculation. We set this to true here. return getKeyRange(validRange, inSignDomain, true); } /* inherits documentation from base class */ QCPRange QCPGraph::getValueRange(bool &validRange, SignDomain inSignDomain) const { // just call the specialized version which takes an additional argument whether error bars // should also be taken into consideration for range calculation. We set this to true here. return getValueRange(validRange, inSignDomain, true); } /*! \overload Allows to specify whether the error bars should be included in the range calculation. \see getKeyRange(bool &validRange, SignDomain inSignDomain) */ QCPRange QCPGraph::getKeyRange(bool &validRange, SignDomain inSignDomain, bool includeErrors) const { QCPRange range; bool haveLower = false; bool haveUpper = false; double current, currentErrorMinus, currentErrorPlus; if (inSignDomain == sdBoth) // range may be anywhere { QCPDataMap::const_iterator it = mData->constBegin(); while (it != mData->constEnd()) { current = it.value().key; currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0); currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0); if (current-currentErrorMinus < range.lower || !haveLower) { range.lower = current-currentErrorMinus; haveLower = true; } if (current+currentErrorPlus > range.upper || !haveUpper) { range.upper = current+currentErrorPlus; haveUpper = true; } ++it; } } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain { QCPDataMap::const_iterator it = mData->constBegin(); while (it != mData->constEnd()) { current = it.value().key; currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0); currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0); if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0) { range.lower = current-currentErrorMinus; haveLower = true; } if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0) { range.upper = current+currentErrorPlus; haveUpper = true; } if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point. { if ((current < range.lower || !haveLower) && current < 0) { range.lower = current; haveLower = true; } if ((current > range.upper || !haveUpper) && current < 0) { range.upper = current; haveUpper = true; } } ++it; } } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain { QCPDataMap::const_iterator it = mData->constBegin(); while (it != mData->constEnd()) { current = it.value().key; currentErrorMinus = (includeErrors ? it.value().keyErrorMinus : 0); currentErrorPlus = (includeErrors ? it.value().keyErrorPlus : 0); if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0) { range.lower = current-currentErrorMinus; haveLower = true; } if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0) { range.upper = current+currentErrorPlus; haveUpper = true; } if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point. { if ((current < range.lower || !haveLower) && current > 0) { range.lower = current; haveLower = true; } if ((current > range.upper || !haveUpper) && current > 0) { range.upper = current; haveUpper = true; } } ++it; } } validRange = haveLower && haveUpper; return range; } /*! \overload Allows to specify whether the error bars should be included in the range calculation. \see getValueRange(bool &validRange, SignDomain inSignDomain) */ QCPRange QCPGraph::getValueRange(bool &validRange, SignDomain inSignDomain, bool includeErrors) const { QCPRange range; bool haveLower = false; bool haveUpper = false; double current, currentErrorMinus, currentErrorPlus; if (inSignDomain == sdBoth) // range may be anywhere { QCPDataMap::const_iterator it = mData->constBegin(); while (it != mData->constEnd()) { current = it.value().value; currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0); currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0); if (current-currentErrorMinus < range.lower || !haveLower) { range.lower = current-currentErrorMinus; haveLower = true; } if (current+currentErrorPlus > range.upper || !haveUpper) { range.upper = current+currentErrorPlus; haveUpper = true; } ++it; } } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain { QCPDataMap::const_iterator it = mData->constBegin(); while (it != mData->constEnd()) { current = it.value().value; currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0); currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0); if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0) { range.lower = current-currentErrorMinus; haveLower = true; } if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0) { range.upper = current+currentErrorPlus; haveUpper = true; } if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point. { if ((current < range.lower || !haveLower) && current < 0) { range.lower = current; haveLower = true; } if ((current > range.upper || !haveUpper) && current < 0) { range.upper = current; haveUpper = true; } } ++it; } } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain { QCPDataMap::const_iterator it = mData->constBegin(); while (it != mData->constEnd()) { current = it.value().value; currentErrorMinus = (includeErrors ? it.value().valueErrorMinus : 0); currentErrorPlus = (includeErrors ? it.value().valueErrorPlus : 0); if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0) { range.lower = current-currentErrorMinus; haveLower = true; } if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0) { range.upper = current+currentErrorPlus; haveUpper = true; } if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point. { if ((current < range.lower || !haveLower) && current > 0) { range.lower = current; haveLower = true; } if ((current > range.upper || !haveUpper) && current > 0) { range.upper = current; haveUpper = true; } } ++it; } } validRange = haveLower && haveUpper; return range; } // ================================================================================ // =================== QCPRange // ================================================================================ /*! \class QCPRange \brief Represents the range an axis is encompassing. contains a \a lower and \a upper double value and provides convenience input, output and modification functions. \see QCPAxis::setRange */ /*! Minimum range size (\a upper - \a lower) the range changing functions will accept. Smaller intervals would cause errors due to the 11-bit exponent of double precision numbers, corresponding to a minimum magnitude of roughly 1e-308. \see validRange, maxRange */ const double QCPRange::minRange = 1e-280; /*! Maximum values (negative and positive) the range will accept in range-changing functions. Larger absolute values would cause errors due to the 11-bit exponent of double precision numbers, corresponding to a maximum magnitude of roughly 1e308. Since the number of planck-volumes in the entire visible universe is only ~1e183, this should be enough. \see validRange, minRange */ const double QCPRange::maxRange = 1e250; /*! Constructs a range with \a lower and \a upper set to zero. */ QCPRange::QCPRange() : lower(0), upper(0) { } /*! \overload Constructs a range with the specified \a lower and \a upper values. */ QCPRange::QCPRange(double lower, double upper) : lower(lower), upper(upper) { normalize(); } /*! Returns the size of the range, i.e. \a upper-\a lower */ double QCPRange::size() const { return upper-lower; } /*! Returns the center of the range, i.e. (\a upper+\a lower)*0.5 */ double QCPRange::center() const { return (upper+lower)*0.5; } /*! Makes sure \a lower is numerically smaller than \a upper. If this is not the case, the values are swapped. */ void QCPRange::normalize() { if (lower > upper) qSwap(lower, upper); } /*! Returns a sanitized version of the range. Sanitized means for logarithmic scales, that the range won't span the positive and negative sign domain, i.e. contain zero. Further \a lower will always be numerically smaller (or equal) to \a upper. If the original range does span positive and negative sign domains or contains zero, the returned range will try to approximate the original range as good as possible. If the positive interval of the original range is wider than the negative interval, the returned range will only contain the positive interval, with lower bound set to \a rangeFac or \a rangeFac *\a upper, whichever is closer to zero. Same procedure is used if the negative interval is wider than the positive interval, this time by changing the \a upper bound. */ QCPRange QCPRange::sanitizedForLogScale() const { double rangeFac = 1e-3; QCPRange sanitizedRange(lower, upper); sanitizedRange.normalize(); // can't have range spanning negative and positive values in log plot, so change range to fix it //if (qFuzzyCompare(sanitizedRange.lower+1, 1) && !qFuzzyCompare(sanitizedRange.upper+1, 1)) if (sanitizedRange.lower == 0.0 && sanitizedRange.upper != 0.0) { // case lower is 0 if (rangeFac < sanitizedRange.upper*rangeFac) sanitizedRange.lower = rangeFac; else sanitizedRange.lower = sanitizedRange.upper*rangeFac; } //else if (!qFuzzyCompare(lower+1, 1) && qFuzzyCompare(upper+1, 1)) else if (sanitizedRange.lower != 0.0 && sanitizedRange.upper == 0.0) { // case upper is 0 if (-rangeFac > sanitizedRange.lower*rangeFac) sanitizedRange.upper = -rangeFac; else sanitizedRange.upper = sanitizedRange.lower*rangeFac; } else if (sanitizedRange.lower < 0 && sanitizedRange.upper > 0) { // find out whether negative or positive interval is wider to decide which sign domain will be chosen if (-sanitizedRange.lower > sanitizedRange.upper) { // negative is wider, do same as in case upper is 0 if (-rangeFac > sanitizedRange.lower*rangeFac) sanitizedRange.upper = -rangeFac; else sanitizedRange.upper = sanitizedRange.lower*rangeFac; } else { // positive is wider, do same as in case lower is 0 if (rangeFac < sanitizedRange.upper*rangeFac) sanitizedRange.lower = rangeFac; else sanitizedRange.lower = sanitizedRange.upper*rangeFac; } } // due to normalization, case lower>0 && upper<0 should never occur, because that implies upper= lower && value <= upper; } /*! Checks, whether the specified range is within valid bounds, which are defined as QCPRange::maxRange and QCPRange::minRange. A valid range means: \li range bounds within -maxRange and maxRange \li range size above minRange \li range size below maxRange */ bool QCPRange::validRange(double lower, double upper) { /* return (lower > -maxRange && upper < maxRange && qAbs(lower-upper) > minRange && (lower < -minRange || lower > minRange) && (upper < -minRange || upper > minRange)); */ return (lower > -maxRange && upper < maxRange && qAbs(lower-upper) > minRange && qAbs(lower-upper) < maxRange); } /*! \overload Checks, whether the specified range is within valid bounds, which are defined as QCPRange::maxRange and QCPRange::minRange. A valid range means: \li range bounds within -maxRange and maxRange \li range size above minRange \li range size below maxRange */ bool QCPRange::validRange(const QCPRange &range) { /* return (range.lower > -maxRange && range.upper < maxRange && qAbs(range.lower-range.upper) > minRange && qAbs(range.lower-range.upper) < maxRange && (range.lower < -minRange || range.lower > minRange) && (range.upper < -minRange || range.upper > minRange)); */ return (range.lower > -maxRange && range.upper < maxRange && qAbs(range.lower-range.upper) > minRange && qAbs(range.lower-range.upper) < maxRange); } // ================================================================================ // =================== QCPLegend // ================================================================================ /*! \class QCPLegend \brief Manages a legend inside a QCustomPlot. Doesn't need to be instantiated externally, rather access QCustomPlot::legend */ /* start of documentation of signals */ /*! \fn void QCPLegend::selectionChanged(QCPLegend::SelectableParts selection); This signal is emitted when the selection state of this legend has changed. \see setSelected, setSelectable */ /* end of documentation of signals */ /*! Constructs a new QCPLegend instance with \a parentPlot as the containing plot and default values. Under normal usage, QCPLegend needn't be instantiated outside of QCustomPlot. Access QCustomPlot::legend to modify the legend (set to invisible by default, see \ref setVisible). */ QCPLegend::QCPLegend(QCustomPlot *parentPlot) : QCPLayerable(parentPlot) { setAntialiased(false); setPositionStyle(psTopRight); setSize(100, 28); setMinimumSize(100, 0); setIconSize(32, 18); setAutoSize(true); setMargin(12, 12, 12, 12); setPadding(8, 8, 3, 3); setItemSpacing(3); setIconTextPadding(7); setSelectable(spLegendBox | spItems); setSelected(spNone); setBorderPen(QPen(Qt::black)); setSelectedBorderPen(QPen(Qt::blue, 2)); setIconBorderPen(Qt::NoPen); setSelectedIconBorderPen(QPen(Qt::blue, 2)); setBrush(Qt::white); setSelectedBrush(Qt::white); setFont(parentPlot->font()); setSelectedFont(parentPlot->font()); setTextColor(Qt::black); setSelectedTextColor(Qt::blue); } QCPLegend::~QCPLegend() { clearItems(); } /*! Sets the pen, the border of the entire legend is drawn with. */ void QCPLegend::setBorderPen(const QPen &pen) { mBorderPen = pen; } /*! Sets the brush of the legend background. */ void QCPLegend::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the default font of legend text. Legend items that draw text (e.g. the name of a graph) will use this font by default. However, a different font can be specified on a per-item-basis by accessing the specific legend item. This function will also set \a font on all already existing legend items. \see QCPAbstractLegendItem::setFont */ void QCPLegend::setFont(const QFont &font) { mFont = font; for (int i=0; isetFont(mFont); } /*! Sets the default color of legend text. Legend items that draw text (e.g. the name of a graph) will use this color by default. However, a different colors can be specified on a per-item-basis by accessing the specific legend item. This function will also set \a color on all already existing legend items. \see QCPAbstractLegendItem::setTextColor */ void QCPLegend::setTextColor(const QColor &color) { mTextColor = color; for (int i=0; isetTextColor(color); } /*! Sets the position style of the legend. If the \a legendPositionStyle is not \ref psManual, the position is found automatically depending on the specific \a legendPositionStyle and the legend margins. If \a legendPositionStyle is \ref psManual, the exact pixel position of the legend must be specified via \ref setPosition. Margins have no effect in that case. \see setMargin */ void QCPLegend::setPositionStyle(PositionStyle legendPositionStyle) { mPositionStyle = legendPositionStyle; } /*! Sets the exact pixel Position of the legend inside the QCustomPlot widget, if \ref setPositionStyle is set to \ref psManual. Margins have no effect in that case. */ void QCPLegend::setPosition(const QPoint &pixelPosition) { mPosition = pixelPosition; } /*! Sets whether the size of the legend should be calculated automatically to fit all the content (plus padding), or whether the size must be specified manually with \ref setSize. If the autoSize mechanism is enabled, the legend will have the smallest possible size to still display all its content. For items with text wrapping (QCPPlottableLegendItem::setTextWrap) this means, they would become very compressed, i.e. wrapped at every word. To prevent this, set a reasonable \ref setMinimumSize width. */ void QCPLegend::setAutoSize(bool on) { mAutoSize = on; } /*! Sets the size of the legend. Setting the size manually with this function only has an effect, if \ref setAutoSize is set to false. If you want to control the minimum size (or the text-wrapping width) while still leaving the autoSize mechanism enabled, consider using \ref setMinimumSize. \see setAutoSize, setMinimumSize */ void QCPLegend::setSize(const QSize &size) { mSize = size; } /*! \overload */ void QCPLegend::setSize(int width, int height) { mSize = QSize(width, height); } /*! Sets the minimum size of the legend when \ref setAutoSize is enabled. If text wrapping is enabled in the legend items (e.g. \ref QCPPlottableLegendItem::setTextWrap), this minimum \a size defines the width at which the wrapping will occur. Note that the wrapping will happen only at word boundaries, so the actual size might still be bigger than the \a size given here, but not smaller. If \ref setAutoSize is not enabled, the minimum \a size is ignored. Setting a smaller legend size with \ref setSize manually, is not prevented. \see setAutoSize, setSize, QCPPlottableLegendItem::setTextWrap */ void QCPLegend::setMinimumSize(const QSize &size) { mMinimumSize = size; } /*! \overload */ void QCPLegend::setMinimumSize(int width, int height) { mMinimumSize = QSize(width, height); } /*! Sets the left padding of the legend. Padding is the space by what the legend box is made larger than minimally needed for the content to fit. I.e. it's the space left blank on each side inside the legend. */ void QCPLegend::setPaddingLeft(int padding) { mPaddingLeft = padding; } /*! Sets the right padding of the legend. Padding is the space by what the legend box is made larger than minimally needed for the content to fit. I.e. it's the space left blank on each side inside the legend. */ void QCPLegend::setPaddingRight(int padding) { mPaddingRight = padding; } /*! Sets the top padding of the legend. Padding is the space by what the legend box is made larger than minimally needed for the content to fit. I.e. it's the space left blank on each side inside the legend. */ void QCPLegend::setPaddingTop(int padding) { mPaddingTop = padding; } /*! Sets the bottom padding of the legend. Padding is the space by what the legend box is made larger than minimally needed for the content to fit. I.e. it's the space left blank on each side inside the legend. */ void QCPLegend::setPaddingBottom(int padding) { mPaddingBottom = padding; } /*! Sets the padding of the legend. Padding is the space by what the legend box is made larger than minimally needed for the content to fit. I.e. it's the space left blank on each side inside the legend. */ void QCPLegend::setPadding(int left, int right, int top, int bottom) { mPaddingLeft = left; mPaddingRight = right; mPaddingTop = top; mPaddingBottom = bottom; } /*! Sets the left margin of the legend. Margins are the distances the legend will keep to the axis rect, when \ref setPositionStyle is not \ref psManual. */ void QCPLegend::setMarginLeft(int margin) { mMarginLeft = margin; } /*! Sets the right margin of the legend. Margins are the distances the legend will keep to the axis rect, when \ref setPositionStyle is not \ref psManual. */ void QCPLegend::setMarginRight(int margin) { mMarginRight = margin; } /*! Sets the top margin of the legend. Margins are the distances the legend will keep to the axis rect, when \ref setPositionStyle is not \ref psManual. */ void QCPLegend::setMarginTop(int margin) { mMarginTop = margin; } /*! Sets the bottom margin of the legend. Margins are the distances the legend will keep to the axis rect, when \ref setPositionStyle is not \ref psManual. */ void QCPLegend::setMarginBottom(int margin) { mMarginBottom = margin; } /*! Sets the margin of the legend. Margins are the distances the legend will keep to the axis rect, when \ref setPositionStyle is not \ref psManual. */ void QCPLegend::setMargin(int left, int right, int top, int bottom) { mMarginLeft = left; mMarginRight = right; mMarginTop = top; mMarginBottom = bottom; } /*! Sets the vertical space between two legend items in the legend. \see setIconTextPadding, setPadding */ void QCPLegend::setItemSpacing(int spacing) { mItemSpacing = spacing; } /*! Sets the size of legend icons. Legend items that draw an icon (e.g. a visual representation of the graph) will use this size by default. */ void QCPLegend::setIconSize(const QSize &size) { mIconSize = size; } /*! \overload */ void QCPLegend::setIconSize(int width, int height) { mIconSize.setWidth(width); mIconSize.setHeight(height); } /*! Sets the horizontal space in pixels between the legend icon and the text next to it. Legend items that draw an icon (e.g. a visual representation of the graph) and text (e.g. the name of the graph) will use this space by default. \see setItemSpacing */ void QCPLegend::setIconTextPadding(int padding) { mIconTextPadding = padding; } /*! Sets the pen used to draw a border around each legend icon. Legend items that draw an icon (e.g. a visual representation of the graph) will use this pen by default. If no border is wanted, set this to \a Qt::NoPen. */ void QCPLegend::setIconBorderPen(const QPen &pen) { mIconBorderPen = pen; } /*! Sets whether the user can (de-)select the parts in \a selectable by clicking on the QCustomPlot surface. (When \ref QCustomPlot::setInteractions contains iSelectLegend.) However, even when \a selectable is set to a value not allowing the selection of a specific part, it is still possible to set the selection of this part manually, by calling \ref setSelected directly. \see SelectablePart, setSelected */ void QCPLegend::setSelectable(const SelectableParts &selectable) { mSelectable = selectable; } /*! Sets the selected state of the respective legend parts described by \ref SelectablePart. When a part is selected, it uses a different pen/font and brush. If some legend items are selected and \a selected doesn't contain \ref spItems, those items become deselected. The entire selection mechanism is handled automatically when \ref QCustomPlot::setInteractions contains iSelectLegend. You only need to call this function when you wish to change the selection state manually. This function can change the selection state of a part even when \ref setSelectable was set to a value that actually excludes the part. emits the \ref selectionChanged signal when \a selected is different from the previous selection state. Note that it doesn't make sense to set the selected state \ref spItems here when it wasn't set before, because there's no way to specify which exact items to newly select. Do this by calling \ref QCPAbstractLegendItem::setSelected directly on the legend item you wish to select. \see SelectablePart, setSelectable, selectTest, setSelectedBorderPen, setSelectedIconBorderPen, setSelectedBrush, setSelectedFont */ void QCPLegend::setSelected(const SelectableParts &selected) { if (mSelected != selected) { if (!selected.testFlag(spItems) && mSelected.testFlag(spItems)) // some items are selected, but new selection state doesn't contain spItems, so deselect them { for (int i=0; isetSelected(false); mSelected = selected; // not necessary to emit selectionChanged here because this will have happened for the last setSelected(false) on mItems already, via updateSelectionState() } else { mSelected = selected; emit selectionChanged(mSelected); } } } /*! When the legend box is selected, this pen is used to draw the border instead of the normal pen set via \ref setBorderPen. \see setSelected, setSelectable, setSelectedBrush */ void QCPLegend::setSelectedBorderPen(const QPen &pen) { mSelectedBorderPen = pen; } /*! Sets the pen legend items will use to draw their icon borders, when they are selected. \see setSelected, setSelectable, setSelectedFont */ void QCPLegend::setSelectedIconBorderPen(const QPen &pen) { mSelectedIconBorderPen = pen; } /*! When the legend box is selected, this brush is used to draw the legend background instead of the normal brush set via \ref setBrush. \see setSelected, setSelectable, setSelectedBorderPen */ void QCPLegend::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /*! Sets the default font that is used by legend items when they are selected. This function will also set \a font on all already existing legend items. \see setFont, QCPAbstractLegendItem::setSelectedFont */ void QCPLegend::setSelectedFont(const QFont &font) { mSelectedFont = font; for (int i=0; isetSelectedFont(font); } /*! Sets the default text color that is used by legend items when they are selected. This function will also set \a color on all already existing legend items. \see setTextColor, QCPAbstractLegendItem::setSelectedTextColor */ void QCPLegend::setSelectedTextColor(const QColor &color) { mSelectedTextColor = color; for (int i=0; isetSelectedTextColor(color); } /*! Returns the item with index \a i. \see itemCount */ QCPAbstractLegendItem *QCPLegend::item(int index) const { if (index >= 0 && index < mItems.size()) return mItems[index]; else return 0; } /*! Returns the QCPPlottableLegendItem which is associated with \a plottable (e.g. a \ref QCPGraph*). If such an item isn't in the legend, returns 0. \see hasItemWithPlottable */ QCPPlottableLegendItem *QCPLegend::itemWithPlottable(const QCPAbstractPlottable *plottable) const { for (int i=0; i(mItems.at(i))) { if (pli->plottable() == plottable) return pli; } } return 0; } /*! Returns the number of items currently in the legend. \see item */ int QCPLegend::itemCount() const { return mItems.size(); } /*! Returns whether the legend contains \a item. */ bool QCPLegend::hasItem(QCPAbstractLegendItem *item) const { return mItems.contains(item); } /*! Returns whether the legend contains a QCPPlottableLegendItem which is associated with \a plottable (e.g. a \ref QCPGraph*). If such an item isn't in the legend, returns false. \see itemWithPlottable */ bool QCPLegend::hasItemWithPlottable(const QCPAbstractPlottable *plottable) const { return itemWithPlottable(plottable); } /*! Adds \a item to the legend, if it's not present already. Returns true on sucess, i.e. if the item wasn't in the list already and has been successfuly added. The legend takes ownership of the item. */ bool QCPLegend::addItem(QCPAbstractLegendItem *item) { if (!mItems.contains(item)) { mItems.append(item); return true; } else return false; } /*! Removes the item with index \a index from the legend. Returns true, if successful. \see itemCount, clearItems */ bool QCPLegend::removeItem(int index) { if (index >= 0 && index < mItems.size()) { mItemBoundingBoxes.remove(mItems.at(index)); delete mItems.at(index); mItems.removeAt(index); return true; } else return false; } /*! \overload Removes \a item from the legend. Returns true, if successful. \see clearItems */ bool QCPLegend::removeItem(QCPAbstractLegendItem *item) { return removeItem(mItems.indexOf(item)); } /*! Removes all items from the legend. */ void QCPLegend::clearItems() { qDeleteAll(mItems); mItems.clear(); mItemBoundingBoxes.clear(); } /*! Returns the legend items that are currently selected. If no items are selected, the list is empty. \see QCPAbstractLegendItem::setSelected, setSelectable */ QList QCPLegend::selectedItems() const { QList result; for (int i=0; iselected()) result.append(mItems.at(i)); } return result; } /*! If \ref setAutoSize is true, the size needed to fit all legend contents is calculated and applied. Finally, the automatic positioning of the legend is performed, depending on the \ref setPositionStyle setting. */ void QCPLegend::reArrange() { if (mAutoSize) { calculateAutoSize(); } calculateAutoPosition(); } /*! Returns whether the point \a pos in pixels hits the legend rect. \see selectTestItem */ bool QCPLegend::selectTestLegend(const QPointF &pos) const { return QRect(mPosition, mSize).contains(pos.toPoint()); } /*! When the point \a pos in pixels hits a legend item, the item is returned. If no item is hit, 0 is returned. \see selectTestLegend */ QCPAbstractLegendItem *QCPLegend::selectTestItem(const QPoint pos) const { QMap::const_iterator it; for (it = mItemBoundingBoxes.constBegin(); it != mItemBoundingBoxes.constEnd(); ++it) { if (it.value().contains(pos) && mItems.contains(it.key())) return it.key(); } return 0; } /*! \internal Updates the spItems part of the selection state of this legend by going through all child items and checking their selected state. If no items are selected and the current selected state contains spItems, it is removed and the \ref selectionChanged signal is emitted. If at least one item is selected and the current selection state does not contain spItems, it is added and the signal is emitted, too. This function is called in the QCPAbstractLegendItem::setSelected functions to propagate their change to the parent legend. */ void QCPLegend::updateSelectionState() { bool hasSelections = false; for (int i=0; iselected()) { hasSelections = true; break; } } // in the following we don't use setSelected because it would cause unnecessary // logic looping through items if spItems isn't set in the new state. (look at setSelected and you'll understand) if (hasSelections && !mSelected.testFlag(spItems)) { mSelected |= spItems; emit selectionChanged(mSelected); } else if (!hasSelections && mSelected.testFlag(spItems)) { mSelected &= ~spItems; emit selectionChanged(mSelected); } } /*! \internal Handles the selection \a event and returns true when the selection event hit any parts of the legend. If the selection state of any parts of the legend was changed, the output parameter \a modified is set to true. When \a additiveSelecton is true, any new selections become selected in addition to the recent selections. The recent selections are not cleared. Further, clicking on one object multiple times in additive selection mode, toggles the selection of that object on and off. To indicate that an event deselects the legend (i.e. the parts that are deselectable by the user, see \ref setSelectable), pass 0 as \a event. */ bool QCPLegend::handleLegendSelection(QMouseEvent *event, bool additiveSelection, bool &modified) { modified = false; bool selectionFound = false; if (event && selectTestLegend(event->pos())) // clicked inside legend somewhere { QCPAbstractLegendItem *ali = selectTestItem(event->pos()); if (selectable().testFlag(QCPLegend::spItems) && ali && ali->selectable()) // items shall be selectable and item ali was clicked { selectionFound = true; // deselect legend box: if (!additiveSelection && selected().testFlag(QCPLegend::spLegendBox) && selectable().testFlag(QCPLegend::spLegendBox)) setSelected(selected() & ~QCPLegend::spLegendBox); // first select clicked item: if (!ali->selected() || additiveSelection) // if additive selection, we toggle selection on and off per click { modified = true; ali->setSelected(!ali->selected()); } // finally, deselect all other items (if we had deselected all first, the selectionChanged signal of QCPLegend might have been emitted twice): if (!additiveSelection) { for (int i=0; iselected() && item(i)->selectable()) { modified = true; item(i)->setSelected(false); } } } } else // no specific item clicked or items not selectable { // if items actually were selectable, this means none were clicked, deselect them: if (selectable().testFlag(QCPLegend::spItems) && selected().testFlag(QCPLegend::spItems) && !additiveSelection) { for (int i=0; iselectable()) item(i)->setSelected(false); } modified = true; } // if legend box is selectable, select it: if (selectable().testFlag(QCPLegend::spLegendBox)) { if (!selected().testFlag(QCPLegend::spLegendBox) || additiveSelection) { selectionFound = true; setSelected(selected() ^ QCPLegend::spLegendBox); // xor because we always toggle modified = true; } } } } else if (selected() != QCPLegend::spNone && selectable() != QCPLegend::spNone && !additiveSelection) // legend not clicked, deselect it if selectable allows that (and all child items) { // only deselect parts that are allowed to be changed by user according to selectable() // deselect child items (and automatically removes spItems from selected state of legend, if last item gets deselected): if (selectable().testFlag(spItems)) { for (int i=0; iselected() && item(i)->selectable()) { item(i)->setSelected(false); modified = true; } } } // only deselect parts that are allowed to be changed (are selectable). Don't forcibly remove // spItems, because some selected items might not be selectable, i.e. allowed to be deselected // by user interaction. If that's not the case, spItems will have been removed from selected() // state in previous loop by individual setSelected(false) calls on the items anyway. QCPLegend::SelectableParts newState = selected() & ~(selectable()&~spItems); if (newState != selected()) { setSelected(newState); modified = true; } } return selectionFound; } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing main legend elements. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set e.g. with \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased */ void QCPLegend::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeLegend); } /*! \internal Returns the pen used to paint the border of the legend, taking into account the selection state of the legend box. */ QPen QCPLegend::getBorderPen() const { return mSelected.testFlag(spLegendBox) ? mSelectedBorderPen : mBorderPen; } /*! \internal Returns the brush used to paint the background of the legend, taking into account the selection state of the legend box. */ QBrush QCPLegend::getBrush() const { return mSelected.testFlag(spLegendBox) ? mSelectedBrush : mBrush; } /*! \internal Draws the legend with the provided \a painter. */ void QCPLegend::draw(QCPPainter *painter) { painter->setBrush(getBrush()); painter->setPen(getBorderPen()); // draw background rect: painter->drawRect(QRect(mPosition, mSize)); // draw legend items: painter->setClipRect(QRect(mPosition, mSize).adjusted(1, 1, 0, 0)); painter->setPen(QPen()); painter->setBrush(Qt::NoBrush); int currentTop = mPosition.y()+mPaddingTop; for (int i=0; isize(QSize(mSize.width(), 0)); QRect itemRect = QRect(QPoint(mPosition.x()+mPaddingLeft, currentTop), itemSize); mItemBoundingBoxes.insert(mItems.at(i), itemRect); painter->save(); mItems.at(i)->applyAntialiasingHint(painter); mItems.at(i)->draw(painter, itemRect); painter->restore(); currentTop += itemSize.height()+mItemSpacing; } } /*! \internal Goes through similar steps as \ref draw and calculates the width and height needed to fit all items and padding in the legend. The new calculated size is then applied to the mSize of this legend. */ void QCPLegend::calculateAutoSize() { int width = mMinimumSize.width()-mPaddingLeft-mPaddingRight; // start with minimum width and only expand from there int currentTop; bool repeat = true; int repeatCount = 0; while (repeat && repeatCount < 3) // repeat until we find self-consistent width (usually 2 runs) { repeat = false; currentTop = mPaddingTop; for (int i=0; isize(QSize(width, 0)); currentTop += s.height(); if (i < mItems.size()-1) // vertical spacer for all but last item currentTop += mItemSpacing; if (width < s.width()) { width = s.width(); repeat = true; // changed width, so need a new run with new width to let other items adapt their height to that new width } } repeatCount++; } if (repeat) qDebug() << Q_FUNC_INFO << "hit repeat limit for iterative width calculation"; currentTop += mPaddingBottom; width += mPaddingLeft+mPaddingRight; mSize.setWidth(width); if (currentTop > mMinimumSize.height()) mSize.setHeight(currentTop); else mSize.setHeight(mMinimumSize.height()); } /*! \internal Sets the position dependant on the \ref setPositionStyle setting and the margins. */ void QCPLegend::calculateAutoPosition() { switch (mPositionStyle) { case psTopLeft: mPosition = mParentPlot->mAxisRect.topLeft() + QPoint(mMarginLeft, mMarginTop); break; case psTop: mPosition = mParentPlot->mAxisRect.topLeft() + QPoint(mParentPlot->mAxisRect.width()/2.0-mSize.width()/2.0, mMarginTop); break; case psTopRight: mPosition = mParentPlot->mAxisRect.topRight() + QPoint(-mMarginRight-mSize.width(), mMarginTop); break; case psRight: mPosition = mParentPlot->mAxisRect.topRight() + QPoint(-mMarginRight-mSize.width(), mParentPlot->mAxisRect.height()/2.0-mSize.height()/2.0); break; case psBottomRight: mPosition = mParentPlot->mAxisRect.bottomRight() + QPoint(-mMarginRight-mSize.width(), -mMarginBottom-mSize.height()); break; case psBottom: mPosition = mParentPlot->mAxisRect.bottomLeft() + QPoint(mParentPlot->mAxisRect.width()/2.0-mSize.width()/2.0, -mMarginBottom-mSize.height()); break; case psBottomLeft: mPosition = mParentPlot->mAxisRect.bottomLeft() + QPoint(mMarginLeft, -mMarginBottom-mSize.height()); break; case psLeft: mPosition = mParentPlot->mAxisRect.topLeft() + QPoint(mMarginLeft, mParentPlot->mAxisRect.height()/2.0-mSize.height()/2.0); break; case psManual: break; } } // ================================================================================ // =================== QCPAxis // ================================================================================ /*! \class QCPAxis \brief Manages a single axis inside a QCustomPlot. Usually doesn't need to be instantiated externally. Access %QCustomPlot's axes via QCustomPlot::xAxis (bottom), QCustomPlot::yAxis (left), QCustomPlot::xAxis2 (top) and QCustomPlot::yAxis2 (right). */ /* start of documentation of inline functions */ /*! \fn Qt::Orientation QCPAxis::orientation() const Returns the orientation of the axis. The axis orientation (horizontal or vertical) is deduced from the axis type (left, top, right or bottom). */ /* end of documentation of inline functions */ /* start of documentation of signals */ /*! \fn void QCPAxis::ticksRequest() This signal is emitted when \ref setAutoTicks is false and the axis is about to generate tick labels and replot itself. Modifying the tick positions can be done with \ref setTickVector. If you also want to control the tick labels, set \ref setAutoTickLabels to false and also provide the labels with \ref setTickVectorLabels. If you only want static ticks you probably don't need this signal, since you can just set the tick vector (and possibly tick label vector) once. However, if you want to provide ticks (and maybe labels) dynamically, e.g. depending on the current axis range, connect a slot to this signal and set the vector/vectors there. */ /*! \fn void QCPAxis::rangeChanged(const QCPRange &newRange) This signal is emitted when the range of this axis has changed. You can connect it to the \ref setRange slot of another axis to communicate the new range to the other axis, in order for it to be synchronized. */ /*! \fn void QCPAxis::selectionChanged(QCPAxis::SelectableParts selection) This signal is emitted when the selection state of this axis has changed, either by user interaction or by a direct call to \ref setSelected. */ /* end of documentation of signals */ /*! Constructs an Axis instance of Type \a type inside \a parentPlot. */ QCPAxis::QCPAxis(QCustomPlot *parentPlot, AxisType type) : QCPLayerable(parentPlot) { mLowestVisibleTick = 0; mHighestVisibleTick = -1; mGrid = new QCPGrid(this); setAxisType(type); setAxisRect(parentPlot->axisRect()); setScaleType(stLinear); setScaleLogBase(10); setAntialiased(false); setRange(0, 5); setRangeReversed(false); setTicks(true); setTickStep(1); setAutoTickCount(6); setAutoTicks(true); setAutoTickLabels(true); setAutoTickStep(true); setTickLabelFont(parentPlot->font()); setTickLabelColor(Qt::black); setTickLength(5); setTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)); setTickLabels(true); setTickLabelType(ltNumber); setTickLabelRotation(0); setDateTimeFormat("hh:mm:ss\ndd.MM.yy"); setNumberFormat("gbd"); setNumberPrecision(6); setLabel(""); setLabelFont(parentPlot->font()); setLabelColor(Qt::black); setAutoSubTicks(true); setSubTickCount(4); setSubTickLength(2); setSubTickPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)); setBasePen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap)); setSelected(spNone); setSelectable(spAxis | spTickLabels | spAxisLabel); QFont selTickLabelFont = tickLabelFont(); selTickLabelFont.setBold(true); setSelectedTickLabelFont(selTickLabelFont); QFont selLabelFont = labelFont(); selLabelFont.setBold(true); setSelectedLabelFont(selLabelFont); setSelectedTickLabelColor(Qt::blue); setSelectedLabelColor(Qt::blue); QPen blueThickPen(Qt::blue, 2); setSelectedBasePen(blueThickPen); setSelectedTickPen(blueThickPen); setSelectedSubTickPen(blueThickPen); setPadding(0); if (type == atTop) { setTickLabelPadding(3); setLabelPadding(6); } else if (type == atRight) { setTickLabelPadding(7); setLabelPadding(12); } else if (type == atBottom) { setTickLabelPadding(3); setLabelPadding(3); } else if (type == atLeft) { setTickLabelPadding(5); setLabelPadding(10); } } QCPAxis::~QCPAxis() { delete mGrid; } /* No documentation as it is a property getter */ QString QCPAxis::numberFormat() const { QString result; result.append(mNumberFormatChar); if (mNumberBeautifulPowers) { result.append("b"); if (mNumberMultiplyCross) result.append("c"); } return result; } /*! \internal Sets the axis type. This determines the \ref orientation and together with the current axis rect (see \ref setAxisRect), the position of the axis. Depending on \a type, ticks, tick labels, and label are drawn on corresponding sides of the axis base line. */ void QCPAxis::setAxisType(AxisType type) { mAxisType = type; mOrientation = (type == atBottom || type == atTop) ? Qt::Horizontal : Qt::Vertical; } /*! \internal Sets the axis rect. The axis uses this rect to position itself within the plot, together with the information of its type (\ref setAxisType). Theoretically it's possible to give a plot's axes different axis rects (e.g. for gaps between them), however, they are currently all synchronized by the QCustomPlot::setAxisRect function. */ void QCPAxis::setAxisRect(const QRect &rect) { mAxisRect = rect; } /*! Sets whether the axis uses a linear scale or a logarithmic scale. If \a type is set to \ref stLogarithmic, the logarithm base can be set with \ref setScaleLogBase. In logarithmic axis scaling, major tick marks appear at all powers of the logarithm base. Properties like tick step (\ref setTickStep) don't apply in logarithmic scaling. If you wish a decimal base but less major ticks, consider choosing a logarithm base of 100, 1000 or even higher. If \a type is \ref stLogarithmic and the number format (\ref setNumberFormat) uses the 'b' option (beautifully typeset decimal powers), the display usually is "1 [multiplication sign] 10 [superscript] n", which looks unnatural for logarithmic scaling (the "1 [multiplication sign]" part). To only display the decimal power, set the number precision to zero with \ref setNumberPrecision. */ void QCPAxis::setScaleType(ScaleType type) { mScaleType = type; if (mScaleType == stLogarithmic) mRange = mRange.sanitizedForLogScale(); } /*! If \ref setScaleType is set to \ref stLogarithmic, \a base will be the logarithm base of the scaling. In logarithmic axis scaling, major tick marks appear at all powers of \a base. Properties like tick step (\ref setTickStep) don't apply in logarithmic scaling. If you wish a decimal base but less major ticks, consider choosing \a base 100, 1000 or even higher. */ void QCPAxis::setScaleLogBase(double base) { if (base > 1) { mScaleLogBase = base; mScaleLogBaseLogInv = 1.0/qLn(mScaleLogBase); // buffer for faster baseLog() calculation } else qDebug() << Q_FUNC_INFO << "Invalid logarithmic scale base (must be greater 1):" << base; } /*! Sets the range of the axis. This slot may be connected with the \ref rangeChanged signal of another axis so this axis is always synchronized with the other axis range, when it changes. To invert the direction of an axis range, use \ref setRangeReversed. */ void QCPAxis::setRange(const QCPRange &range) { if (range.lower == mRange.lower && range.upper == mRange.upper) return; if (!QCPRange::validRange(range)) return; if (mScaleType == stLogarithmic) { mRange = range.sanitizedForLogScale(); } else { mRange = range.sanitizedForLinScale(); } emit rangeChanged(mRange); } /*! Sets whether the user can (de-)select the parts in \a selectable by clicking on the QCustomPlot surface. (When \ref QCustomPlot::setInteractions contains iSelectAxes.) However, even when \a selectable is set to a value not allowing the selection of a specific part, it is still possible to set the selection of this part manually, by calling \ref setSelected directly. \see SelectablePart, setSelected */ void QCPAxis::setSelectable(const SelectableParts &selectable) { mSelectable = selectable; } /*! Sets the selected state of the respective axis parts described by \ref SelectablePart. When a part is selected, it uses a different pen/font. The entire selection mechanism for axes is handled automatically when \ref QCustomPlot::setInteractions contains iSelectAxes. You only need to call this function when you wish to change the selection state manually. This function can change the selection state of a part even when \ref setSelectable was set to a value that actually excludes the part. emits the \ref selectionChanged signal when \a selected is different from the previous selection state. \see SelectablePart, setSelectable, selectTest, setSelectedBasePen, setSelectedTickPen, setSelectedSubTickPen, setSelectedTickLabelFont, setSelectedLabelFont, setSelectedTickLabelColor, setSelectedLabelColor */ void QCPAxis::setSelected(const SelectableParts &selected) { if (mSelected != selected) { mSelected = selected; emit selectionChanged(mSelected); } } /*! \overload Sets the lower and upper bound of the axis range. To invert the direction of an axis range, use \ref setRangeReversed. There is also a slot to set a range, see \ref setRange(const QCPRange &range). */ void QCPAxis::setRange(double lower, double upper) { if (lower == mRange.lower && upper == mRange.upper) return; if (!QCPRange::validRange(lower, upper)) return; mRange.lower = lower; mRange.upper = upper; if (mScaleType == stLogarithmic) { mRange = mRange.sanitizedForLogScale(); } else { mRange = mRange.sanitizedForLinScale(); } emit rangeChanged(mRange); } /*! \overload Sets the range of the axis. \param position the \a position coordinate indicates together with the \a alignment parameter, where the new range will be positioned. \param size defines the size (upper-lower) of the new axis range. \param alignment determines how \a position is to be interpreted.\n If \a alignment is Qt::AlignLeft, \a position will be the lower bound of the range.\n If \a alignment is Qt::AlignRight, \a position will be the upper bound of the range.\n If \a alignment is Qt::AlignCenter, the new range will be centered around \a position.\n Any other values for \a alignment will default to Qt::AlignCenter. */ void QCPAxis::setRange(double position, double size, Qt::AlignmentFlag alignment) { if (alignment == Qt::AlignLeft) setRange(position, position+size); else if (alignment == Qt::AlignRight) setRange(position-size, position); else // alignment == Qt::AlignCenter setRange(position-size/2.0, position+size/2.0); } /*! Sets the lower bound of the axis range, independently of the upper bound. \see setRange */ void QCPAxis::setRangeLower(double lower) { if (mRange.lower == lower) return; mRange.lower = lower; if (mScaleType == stLogarithmic) { mRange = mRange.sanitizedForLogScale(); } else { mRange = mRange.sanitizedForLinScale(); } emit rangeChanged(mRange); } /*! Sets the upper bound of the axis range, independently of the lower bound. \see setRange */ void QCPAxis::setRangeUpper(double upper) { if (mRange.upper == upper) return; mRange.upper = upper; if (mScaleType == stLogarithmic) { mRange = mRange.sanitizedForLogScale(); } else { mRange = mRange.sanitizedForLinScale(); } emit rangeChanged(mRange); } /*! Sets whether the axis range (direction) is displayed reversed. Normally, the values on horizontal axes increase left to right, on vertical axes bottom to top. When \a reversed is set to true, the direction of increasing values is inverted. Note that the range and data interface stays the same for reversed axes, e.g. the \a lower part of the \ref setRange interface will still reference the mathematically smaller number than the \a upper part. */ void QCPAxis::setRangeReversed(bool reversed) { mRangeReversed = reversed; } /*! Sets whether the grid of this axis is drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPAxis::setAntialiasedGrid(bool enabled) { mGrid->setAntialiased(enabled); } /*! Sets whether the sub grid of this axis is drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPAxis::setAntialiasedSubGrid(bool enabled) { mGrid->setAntialiasedSubGrid(enabled); } /*! Sets whether the zero line of this axis is drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPAxis::setAntialiasedZeroLine(bool enabled) { mGrid->setAntialiasedZeroLine(enabled); } /*! Sets whether the grid lines are visible. \see setSubGrid, setGridPen, setZeroLinePen */ void QCPAxis::setGrid(bool show) { mGrid->setVisible(show); } /*! Sets whether the sub grid lines are visible. \see setGrid, setSubGridPen, setZeroLinePen */ void QCPAxis::setSubGrid(bool show) { mGrid->setSubGridVisible(show); } /*! Sets whether the tick positions should be calculated automatically (either from an automatically generated tick step or a tick step provided manually via \ref setTickStep, see \ref setAutoTickStep). If \a on is set to false, you must provide the tick positions manually via \ref setTickVector. For these manual ticks you may let QCPAxis generate the appropriate labels automatically by setting/leaving \ref setAutoTickLabels true. If you also wish to control the displayed labels manually, set \ref setAutoTickLabels to false and provide the label strings with \ref setTickVectorLabels. If you need dynamically calculated tick vectors (and possibly tick label vectors), set the vectors in a slot connected to the \ref ticksRequest signal. */ void QCPAxis::setAutoTicks(bool on) { mAutoTicks = on; } /*! When \ref setAutoTickStep is true, \a approximateCount determines how many ticks should be generated in the visible range approximately. */ void QCPAxis::setAutoTickCount(int approximateCount) { mAutoTickCount = approximateCount; } /*! Sets whether the tick labels are generated automatically depending on the tick label type (\ref ltNumber or \ref ltDateTime). If \a on is set to false, you should provide the tick labels via \ref setTickVectorLabels. This is usually used in a combination with \ref setAutoTicks set to false for complete control over tick positions and labels, e.g. when the ticks should be at multiples of pi and show "2pi", "3pi" etc. as tick labels. If you need dynamically calculated tick vectors (and possibly tick label vectors), set the vectors in a slot connected to the \ref ticksRequest signal. */ void QCPAxis::setAutoTickLabels(bool on) { mAutoTickLabels = on; } /*! Sets whether the tick step, i.e. the interval between two (major) ticks, is calculated automatically. If \a on is set to true, the axis finds a tick step that is reasonable for human readable plots. This means the tick step mantissa is chosen such that it's either a multiple of two or ends in 0.5. The number of ticks the algorithm aims for within the visible range can be set with \ref setAutoTickCount. It's not guaranteed that this number of ticks is met exactly, but approximately within a tolerance of two or three. If \a on is set to false, you may set the tick step manually with \ref setTickStep. */ void QCPAxis::setAutoTickStep(bool on) { mAutoTickStep = on; } /*! Sets whether the number of sub ticks in one tick interval is determined automatically. This works, as long as the tick step mantissa is a multiple of 0.5 (which it is, when \ref setAutoTickStep is enabled).\n When \a on is set to false, you may set the sub tick count with \ref setSubTickCount manually. */ void QCPAxis::setAutoSubTicks(bool on) { mAutoSubTicks = on; } /*! Sets whether tick marks are displayed. Setting \a show to false does not imply, that tick labels are invisible, too. To achieve that, see \ref setTickLabels. */ void QCPAxis::setTicks(bool show) { mTicks = show; } /*! Sets whether tick labels are displayed. */ void QCPAxis::setTickLabels(bool show) { mTickLabels = show; } /*! Sets the distance between the axis base line (or any tick marks pointing outward) and the tick labels. \see setLabelPadding, setPadding */ void QCPAxis::setTickLabelPadding(int padding) { mTickLabelPadding = padding; } /*! Sets whether the tick labels display numbers or dates/times.\n If \a type is set to \ref ltNumber, the format specifications of \ref setNumberFormat apply.\n If \a type is set to \ref ltDateTime, the format specifications of \ref setDateTimeFormat apply.\n In QCustomPlot, date/time coordinates are double numbers representing the seconds since 1970-01-01T00:00:00 UTC. This format can be retrieved from QDateTime objects with the QDateTime::toTime_t() function. Since this only gives a resolution of one second, there is also the QDateTime::toMSecsSinceEpoch() function which returns the timespan described above in milliseconds. Divide its return value by 1000.0 to get a value with the format needed for date/time plotting, this time with a resolution of one millisecond. */ void QCPAxis::setTickLabelType(LabelType type) { mTickLabelType = type; } /*! Sets the font of the tick labels, i.e. the numbers drawn next to tick marks. \see setTickLabelColor */ void QCPAxis::setTickLabelFont(const QFont &font) { mTickLabelFont = font; } /*! Sets the color of the tick labels, i.e. the numbers drawn next to tick marks. \see setTickLabelFont */ void QCPAxis::setTickLabelColor(const QColor &color) { mTickLabelColor = color; } /*! Sets the rotation of the tick labels, i.e. the numbers drawn next to tick marks. If \a degrees is zero, the labels are drawn normally. Else, the tick labels are drawn rotated by \a degrees clockwise. The specified angle is bound to values from -90 to 90 degrees. */ void QCPAxis::setTickLabelRotation(double degrees) { mTickLabelRotation = qBound(-90.0, degrees, 90.0); } /*! Sets the format in which dates and times are displayed as tick labels, if \ref setTickLabelType is \ref ltDateTime. for details about the \a format string, see the documentation of QDateTime::toString(). Newlines can be inserted with "\n". */ void QCPAxis::setDateTimeFormat(const QString &format) { mDateTimeFormat = format; } /*! Sets the number format for the numbers drawn as tick labels (if tick label type is \ref ltNumber). This \a formatCode is an extended version of the format code used e.g. by QString::number() and QLocale::toString(). For reference about that, see the "Argument Formats" section in the detailed description of the QString class. \a formatCode is a string of one, two or three characters. The first character is identical to the normal format code used by Qt. In short, this means: 'e'/'E' scientific format, 'f' fixed format, 'g'/'G' scientific or fixed, whichever is shorter. The second and third characters are optional and specific to QCustomPlot:\n If the first char was 'e' or 'g', numbers are/might be displayed in the scientific format, e.g. "5.5e9", which is ugly in a plot. So when the second char of \a formatCode is set to 'b' (for "beautiful"), those exponential numbers are formatted in a more natural way, i.e. "5.5 [multiplication sign] 10 [superscript] 9". By default, the multiplication sign is a centered dot. If instead a cross should be shown (as is usual in the USA), the third char of \a formatCode can be set to 'c'. The inserted multiplication signs are the UTF-8 characters 215 (0xD7) for the cross and 183 (0xB7) for the dot. If the scale type (\ref setScaleType) is \ref stLogarithmic and the \a formatCode uses the 'b' option (beautifully typeset decimal powers), the display usually is "1 [multiplication sign] 10 [superscript] n", which looks unnatural for logarithmic scaling (the "1 [multiplication sign]" part). To only display the decimal power, set the number precision to zero with \ref setNumberPrecision. Examples for \a formatCode: \li \c g normal format code behaviour. If number is small, fixed format is used, if number is large, normal scientific format is used \li \c gb If number is small, fixed format is used, if number is large, scientific format is used with beautifully typeset decimal powers and a dot as multiplication sign \li \c ebc All numbers are in scientific format with beautifully typeset decimal power and a cross as multiplication sign \li \c fb illegal format code, since fixed format doesn't support (or need) beautifully typeset decimal powers. Format code will be reduced to 'f'. \li \c hello illegal format code, since first char is not 'e', 'E', 'f', 'g' or 'G'. Current format code will not be changed. */ void QCPAxis::setNumberFormat(const QString &formatCode) { if (formatCode.length() < 1) return; // interpret first char as number format char: QString allowedFormatChars = "eEfgG"; if (allowedFormatChars.contains(formatCode.at(0))) { mNumberFormatChar = formatCode.at(0).toAscii(); } else { qDebug() << Q_FUNC_INFO << "Invalid number format code (first char not in 'eEfgG'):" << formatCode; return; } if (formatCode.length() < 2) { mNumberBeautifulPowers = false; mNumberMultiplyCross = false; return; } // interpret second char as indicator for beautiful decimal powers: if (formatCode.at(1) == 'b' && (mNumberFormatChar == 'e' || mNumberFormatChar == 'g')) { mNumberBeautifulPowers = true; } else { qDebug() << Q_FUNC_INFO << "Invalid number format code (second char not 'b' or first char neither 'e' nor 'g'):" << formatCode; return; } if (formatCode.length() < 3) { mNumberMultiplyCross = false; return; } // interpret third char as indicator for dot or cross multiplication symbol: if (formatCode.at(2) == 'c') { mNumberMultiplyCross = true; } else if (formatCode.at(2) == 'd') { mNumberMultiplyCross = false; } else { qDebug() << Q_FUNC_INFO << "Invalid number format code (third char neither 'c' nor 'd'):" << formatCode; return; } } /*! Sets the precision of the numbers drawn as tick labels. See QLocale::toString(double i, char f, int prec) for details. The effect of precisions are most notably for number Formats starting with 'e', see \ref setNumberFormat If the scale type (\ref setScaleType) is \ref stLogarithmic and the number format (\ref setNumberFormat) uses the 'b' format code (beautifully typeset decimal powers), the display usually is "1 [multiplication sign] 10 [superscript] n", which looks unnatural for logarithmic scaling (the "1 [multiplication sign]" part). To only display the decimal power, set \a precision to zero. */ void QCPAxis::setNumberPrecision(int precision) { mNumberPrecision = precision; } /*! If \ref setAutoTickStep is set to false, use this function to set the tick step manually. The tick step is the interval between (major) ticks, in plot coordinates. \see setSubTickCount */ void QCPAxis::setTickStep(double step) { mTickStep = step; } /*! If you want full control over what ticks (and possibly labels) the axes show, this function is used to set the coordinates at which ticks will appear.\ref setAutoTicks must be disabled, else the provided tick vector will be overwritten with automatically generated tick coordinates. The labels of the ticks can either be generated automatically when \ref setAutoTickLabels is left enabled, or be set manually with \ref setTickVectorLabels, when \ref setAutoTickLabels is disabled. \a vec is a vector containing the positions of the ticks. \see setTickVectorLabels */ void QCPAxis::setTickVector(const QVector &vec) { mTickVector = vec; } /*! If you want full control over what ticks and labels the axes show, this function is used to set a number of QStrings that will be displayed at the tick positions which you need to provide with \ref setTickVector. These two vectors should have the same size. (Note that you need to disable \ref setAutoTicks and \ref setAutoTickLabels first.) \a vec is a vector containing the labels of the ticks. \see setTickVector */ void QCPAxis::setTickVectorLabels(const QVector &vec) { mTickVectorLabels = vec; } /*! Sets the length of the ticks in pixels. \a inside is the length the ticks will reach inside the plot and \a outside is the length they will reach outside the plot. If \a outside is greater than zero, the tick labels will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setSubTickLength */ void QCPAxis::setTickLength(int inside, int outside) { mTickLengthIn = inside; mTickLengthOut = outside; } /*! Sets the number of sub ticks in one (major) tick step. A sub tick count of three for example, divides the tick intervals in four sub intervals. By default, the number of sub ticks is chosen automatically in a reasonable manner as long as the mantissa of the tick step is a multiple of 0.5 (which it is, when \ref setAutoTickStep is enabled). If you want to disable automatic sub ticks and use this function to set the count manually, see \ref setAutoSubTicks. */ void QCPAxis::setSubTickCount(int count) { mSubTickCount = count; } /*! Sets the length of the subticks in pixels. \a inside is the length the subticks will reach inside the plot and \a outside is the length they will reach outside the plot. If \a outside is greater than zero, the tick labels will increase their distance to the axis accordingly, so they won't collide with the ticks. \see setTickLength */ void QCPAxis::setSubTickLength(int inside, int outside) { mSubTickLengthIn = inside; mSubTickLengthOut = outside; } /*! Sets the pen, the axis base line is drawn with. \see setTickPen, setSubTickPen */ void QCPAxis::setBasePen(const QPen &pen) { mBasePen = pen; } /*! Sets the pen, grid lines are drawn with. \see setSubGridPen, setZeroLinePen */ void QCPAxis::setGridPen(const QPen &pen) { mGrid->setPen(pen); } /*! Sets the pen, the sub grid lines are drawn with. (By default, subgrid drawing needs to be enabled first with \ref setSubGrid.) \see setGridPen, setZeroLinePen */ void QCPAxis::setSubGridPen(const QPen &pen) { mGrid->setSubGridPen(pen); } /*! Sets the pen with which a single grid-like line will be drawn at value position zero. The line will be drawn instead of a grid line at that position, and not on top. To disable the drawing of a zero-line, set \a pen to Qt::NoPen. Then, if \ref setGrid is enabled, a grid line will be drawn instead. \see setGrid, setGridPen */ void QCPAxis::setZeroLinePen(const QPen &pen) { mGrid->setZeroLinePen(pen); } /*! Sets the pen, tick marks will be drawn with. \see setTickLength, setBasePen */ void QCPAxis::setTickPen(const QPen &pen) { mTickPen = pen; } /*! Sets the pen, subtick marks will be drawn with. \see setSubTickCount, setSubTickLength, setBasePen */ void QCPAxis::setSubTickPen(const QPen &pen) { mSubTickPen = pen; } /*! Sets the font of the axis label. \see setLabelColor */ void QCPAxis::setLabelFont(const QFont &font) { mLabelFont = font; } /*! Sets the color of the axis label. \see setLabelFont */ void QCPAxis::setLabelColor(const QColor &color) { mLabelColor = color; } /*! Sets the axis label that will be shown below/above or next to the axis, depending on its orientation. */ void QCPAxis::setLabel(const QString &str) { mLabel = str; } /*! Sets the distance between the tick labels and the axis label. \see setTickLabelPadding, setPadding */ void QCPAxis::setLabelPadding(int padding) { mLabelPadding = padding; } /*! Sets the padding of the axis. When \ref QCustomPlot::setAutoMargin is enabled, the padding is the additional distance to the respective widget border, that is left blank. If \a padding is zero (default), the auto margin mechanism will find a margin that the axis label (or tick label, if no axis label is set) barely fits inside the QCustomPlot widget. To give the label closest to the border some freedom, increase \a padding. The axis padding has no meaning if \ref QCustomPlot::setAutoMargin is disabled. \see setLabelPadding, setTickLabelPadding */ void QCPAxis::setPadding(int padding) { mPadding = padding; } /*! Sets the font that is used for tick labels when they are selected. \see setTickLabelFont, setSelectable, setSelected, QCustomPlot::setInteractions */ void QCPAxis::setSelectedTickLabelFont(const QFont &font) { mSelectedTickLabelFont = font; } /*! Sets the font that is used for the axis label when it is selected. \see setLabelFont, setSelectable, setSelected, QCustomPlot::setInteractions */ void QCPAxis::setSelectedLabelFont(const QFont &font) { mSelectedLabelFont = font; } /*! Sets the color that is used for tick labels when they are selected. \see setTickLabelColor, setSelectable, setSelected, QCustomPlot::setInteractions */ void QCPAxis::setSelectedTickLabelColor(const QColor &color) { mSelectedTickLabelColor = color; } /*! Sets the color that is used for the axis label when it is selected. \see setLabelColor, setSelectable, setSelected, QCustomPlot::setInteractions */ void QCPAxis::setSelectedLabelColor(const QColor &color) { mSelectedLabelColor = color; } /*! Sets the pen that is used to draw the axis base line when selected. \see setBasePen, setSelectable, setSelected, QCustomPlot::setInteractions */ void QCPAxis::setSelectedBasePen(const QPen &pen) { mSelectedBasePen = pen; } /*! Sets the pen that is used to draw the (major) ticks when selected. \see setTickPen, setSelectable, setSelected, QCustomPlot::setInteractions */ void QCPAxis::setSelectedTickPen(const QPen &pen) { mSelectedTickPen = pen; } /*! Sets the pen that is used to draw the subticks when selected. \see setSubTickPen, setSelectable, setSelected, QCustomPlot::setInteractions */ void QCPAxis::setSelectedSubTickPen(const QPen &pen) { mSelectedSubTickPen = pen; } /*! If the scale type (\ref setScaleType) is \ref stLinear, \a diff is added to the lower and upper bounds of the range. The range is simply moved by \a diff. If the scale type is \ref stLogarithmic, the range bounds are multiplied by \a diff. This corresponds to an apparent "linear" move in logarithmic scaling by a distance of log(diff). */ void QCPAxis::moveRange(double diff) { if (mScaleType == stLinear) { mRange.lower += diff; mRange.upper += diff; } else // mScaleType == stLogarithmic { mRange.lower *= diff; mRange.upper *= diff; } emit rangeChanged(mRange); } /*! Scales the range of this axis by \a factor around the coordinate \a center. For example, if \a factor is 2.0, \a center is 1.0, then the axis range will double its size, and the point at coordinate 1.0 won't have changed its position in the QCustomPlot widget (i.e. coordinates around 1.0 will have moved symmetrically closer to 1.0). */ void QCPAxis::scaleRange(double factor, double center) { if (mScaleType == stLinear) { QCPRange newRange; newRange.lower = (mRange.lower-center)*factor + center; newRange.upper = (mRange.upper-center)*factor + center; if (QCPRange::validRange(newRange)) mRange = newRange.sanitizedForLinScale(); } else // mScaleType == stLogarithmic { if ((mRange.upper < 0 && center < 0) || (mRange.upper > 0 && center > 0)) // make sure center has same sign as range { QCPRange newRange; newRange.lower = pow(mRange.lower/center, factor)*center; newRange.upper = pow(mRange.upper/center, factor)*center; if (QCPRange::validRange(newRange)) mRange = newRange.sanitizedForLogScale(); } else qDebug() << Q_FUNC_INFO << "center of scaling operation doesn't lie in same logarithmic sign domain as range:" << center; } emit rangeChanged(mRange); } /*! Sets the range of this axis to have a certain scale \a ratio to \a otherAxis. For example, if \a ratio is 1, this axis is the \a yAxis and \a otherAxis is \a xAxis, graphs plotted with those axes will appear in a 1:1 ratio, independent of the aspect ratio the axis rect has. This is an operation that changes the range of this axis once, it doesn't fix the scale ratio indefinitely. Consequently calling this function in the constructor won't have the desired effect, since the widget's dimensions aren't defined yet, and a resizeEvent will follow. */ void QCPAxis::setScaleRatio(const QCPAxis *otherAxis, double ratio) { int otherPixelSize, ownPixelSize; if (otherAxis->orientation() == Qt::Horizontal) otherPixelSize = otherAxis->mAxisRect.width(); else otherPixelSize = otherAxis->mAxisRect.height(); if (orientation() == Qt::Horizontal) ownPixelSize = mAxisRect.width(); else ownPixelSize = mAxisRect.height(); double newRangeSize = ratio*otherAxis->mRange.size()*ownPixelSize/(double)otherPixelSize; setRange(range().center(), newRangeSize, Qt::AlignCenter); } /*! Transforms \a value (in pixel coordinates of the QCustomPlot widget) to axis coordinates. */ double QCPAxis::pixelToCoord(double value) const { if (orientation() == Qt::Horizontal) { if (mScaleType == stLinear) { if (!mRangeReversed) return (value-mAxisRect.left())/(double)mAxisRect.width()*mRange.size()+mRange.lower; else return -(value-mAxisRect.left())/(double)mAxisRect.width()*mRange.size()+mRange.upper; } else // mScaleType == stLogarithmic { if (!mRangeReversed) return pow(mRange.upper/mRange.lower, (value-mAxisRect.left())/(double)mAxisRect.width())*mRange.lower; else return pow(mRange.upper/mRange.lower, (mAxisRect.left()-value)/(double)mAxisRect.width())*mRange.upper; } } else // orientation() == Qt::Vertical { if (mScaleType == stLinear) { if (!mRangeReversed) return (mAxisRect.bottom()-value)/(double)mAxisRect.height()*mRange.size()+mRange.lower; else return -(mAxisRect.bottom()-value)/(double)mAxisRect.height()*mRange.size()+mRange.upper; } else // mScaleType == stLogarithmic { if (!mRangeReversed) return pow(mRange.upper/mRange.lower, (mAxisRect.bottom()-value)/(double)mAxisRect.height())*mRange.lower; else return pow(mRange.upper/mRange.lower, (value-mAxisRect.bottom())/(double)mAxisRect.height())*mRange.upper; } } } /*! Transforms \a value (in coordinates of the axis) to pixel coordinates of the QCustomPlot widget. */ double QCPAxis::coordToPixel(double value) const { if (orientation() == Qt::Horizontal) { if (mScaleType == stLinear) { if (!mRangeReversed) return (value-mRange.lower)/mRange.size()*mAxisRect.width()+mAxisRect.left(); else return (mRange.upper-value)/mRange.size()*mAxisRect.width()+mAxisRect.left(); } else // mScaleType == stLogarithmic { if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it outside visible range return !mRangeReversed ? mAxisRect.right()+200 : mAxisRect.left()-200; else if (value <= 0 && mRange.upper > 0) // invalid value for logarithmic scale, just draw it outside visible range return !mRangeReversed ? mAxisRect.left()-200 : mAxisRect.right()+200; else { if (!mRangeReversed) return baseLog(value/mRange.lower)/baseLog(mRange.upper/mRange.lower)*mAxisRect.width()+mAxisRect.left(); else return baseLog(mRange.upper/value)/baseLog(mRange.upper/mRange.lower)*mAxisRect.width()+mAxisRect.left(); } } } else // orientation() == Qt::Vertical { if (mScaleType == stLinear) { if (!mRangeReversed) return mAxisRect.bottom()-(value-mRange.lower)/mRange.size()*mAxisRect.height(); else return mAxisRect.bottom()-(mRange.upper-value)/mRange.size()*mAxisRect.height(); } else // mScaleType == stLogarithmic { if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it outside visible range return !mRangeReversed ? mAxisRect.top()-200 : mAxisRect.bottom()+200; else if (value <= 0 && mRange.upper > 0) // invalid value for logarithmic scale, just draw it outside visible range return !mRangeReversed ? mAxisRect.bottom()+200 : mAxisRect.top()-200; else { if (!mRangeReversed) return mAxisRect.bottom()-baseLog(value/mRange.lower)/baseLog(mRange.upper/mRange.lower)*mAxisRect.height(); else return mAxisRect.bottom()-baseLog(mRange.upper/value)/baseLog(mRange.upper/mRange.lower)*mAxisRect.height(); } } } } /*! Returns the part of the axis that is hit by \a pos (in pixels). The return value of this function is independent of the user-selectable parts defined with \ref setSelectable. Further, this function does not change the current selection state of the axis. If the axis is not visible (\ref setVisible), this function always returns \ref spNone. \see setSelected, setSelectable, QCustomPlot::setInteractions */ QCPAxis::SelectablePart QCPAxis::selectTest(const QPointF &pos) const { if (!mVisible) return spNone; if (mAxisSelectionBox.contains(pos.toPoint())) return spAxis; else if (mTickLabelsSelectionBox.contains(pos.toPoint())) return spTickLabels; else if (mLabelSelectionBox.contains(pos.toPoint())) return spAxisLabel; else return spNone; } /*! \internal This function is called before the grid and axis is drawn, in order to prepare the tick vector, sub tick vector and tick label vector. If \ref setAutoTicks is set to true, appropriate tick values are determined automatically via \ref generateAutoTicks. If it's set to false, the signal ticksRequest is emitted, which can be used to provide external tick positions. Then the sub tick vectors and tick label vectors are created. */ void QCPAxis::setupTickVectors() { if ((!mTicks && !mTickLabels && !mGrid->visible()) || mRange.size() <= 0) return; // fill tick vectors, either by auto generating or by notifying user to fill the vectors himself if (mAutoTicks) { generateAutoTicks(); } else { emit ticksRequest(); } visibleTickBounds(mLowestVisibleTick, mHighestVisibleTick); if (mTickVector.isEmpty()) { mSubTickVector.clear(); return; } // generate subticks between ticks: mSubTickVector.resize((mTickVector.size()-1)*mSubTickCount); if (mSubTickCount > 0) { double subTickStep = 0; double subTickPosition = 0; int subTickIndex = 0; bool done = false; for (int i=1; i mRange.upper) { done = true; break; } mSubTickVector[subTickIndex] = subTickPosition; subTickIndex++; } if (done) break; } mSubTickVector.resize(subTickIndex); } // generate tick labels according to tick positions: mExponentialChar = mParentPlot->locale().exponential(); // will be needed when drawing the numbers generated here, in drawTickLabel() mPositiveSignChar = mParentPlot->locale().positiveSign(); // will be needed when drawing the numbers generated here, in drawTickLabel() if (mAutoTickLabels) { int vecsize = mTickVector.size(); mTickVectorLabels.resize(vecsize); if (mTickLabelType == ltNumber) { for (int i=0; ilocale().toString(mTickVector.at(i), mNumberFormatChar, mNumberPrecision); } else if (mTickLabelType == ltDateTime) { for (int i=0; ilocale().toString(QDateTime::fromTime_t(mTickVector.at(i)), mDateTimeFormat); #else mTickVectorLabels[i] = mParentPlot->locale().toString(QDateTime::fromMSecsSinceEpoch(mTickVector.at(i)*1000), mDateTimeFormat); #endif } } } else // mAutoTickLabels == false { if (mAutoTicks) // ticks generated automatically, but not ticklabels, so emit ticksRequest here for labels { emit ticksRequest(); } // make sure provided tick label vector has correct (minimal) length: if (mTickVectorLabels.size() < mTickVector.size()) mTickVectorLabels.resize(mTickVector.size()); } } /*! \internal If \ref setAutoTicks is set to true, this function is called by \ref setupTickVectors to generate reasonable tick positions (and subtick count). The algorithm tries to create approximately mAutoTickCount ticks (set via \ref setAutoTickCount), taking into account, that tick mantissas that are divisable by two or end in .5 are nice to look at and practical in linear scales. If the scale is logarithmic, one tick is generated at every power of the current logarithm base, set via \ref setScaleLogBase. */ void QCPAxis::generateAutoTicks() { if (mScaleType == stLinear) { if (mAutoTickStep) { // Generate tick positions according to linear scaling: mTickStep = mRange.size()/(double)(mAutoTickCount+1e-10); // mAutoTickCount ticks on average, the small addition is to prevent jitter on exact integers double magnitudeFactor = qPow(10.0, qFloor(qLn(mTickStep)/qLn(10.0))); // get magnitude factor e.g. 0.01, 1, 10, 1000 etc. double tickStepMantissa = mTickStep/magnitudeFactor; if (tickStepMantissa < 5) { // round digit after decimal point to 0.5 mTickStep = (int)(tickStepMantissa*2)/2.0*magnitudeFactor; } else { // round to first digit in multiples of 2 mTickStep = (int)((tickStepMantissa/10.0)*5)/5.0*10*magnitudeFactor; } } if (mAutoSubTicks) mSubTickCount = calculateAutoSubTickCount(mTickStep); // Generate tick positions according to mTickStep: int firstStep = floor(mRange.lower/mTickStep); int lastStep = ceil(mRange.upper/mTickStep); int tickcount = lastStep-firstStep+1; if (tickcount < 0) tickcount = 0; mTickVector.resize(tickcount); for (int i=0; i 0 && mRange.upper > 0) // positive range { double lowerMag = basePow((int)floor(baseLog(mRange.lower))); double currentMag = lowerMag; mTickVector.clear(); mTickVector.append(currentMag); while (currentMag < mRange.upper && currentMag > 0) // currentMag might be zero for ranges ~1e-300, just cancel in that case { currentMag *= mScaleLogBase; mTickVector.append(currentMag); } } else if (mRange.lower < 0 && mRange.upper < 0) // negative range { double lowerMag = -basePow((int)ceil(baseLog(-mRange.lower))); double currentMag = lowerMag; mTickVector.clear(); mTickVector.append(currentMag); while (currentMag < mRange.upper && currentMag < 0) // currentMag might be zero for ranges ~1e-300, just cancel in that case { currentMag /= mScaleLogBase; mTickVector.append(currentMag); } } else // invalid range for logarithmic scale, because lower and upper have different sign { mTickVector.clear(); qDebug() << Q_FUNC_INFO << "Invalid range for logarithmic plot: " << mRange.lower << "-" << mRange.upper; } } } /*! \internal Called by generateAutoTicks when \ref setAutoSubTicks is set to true. Depending on the \a tickStep between two major ticks on the axis, a different number of sub ticks is appropriate. For Example taking 4 sub ticks for a \a tickStep of 1 makes more sense than taking 5 sub ticks, because this corresponds to a sub tick step of 0.2, instead of the less intuitive 0.16666. Note that a subtick count of 4 means dividing the major tick step into 5 sections. This is implemented by a hand made lookup for integer tick steps as well as fractional tick steps with a fractional part of (approximately) 0.5. If a tick step is different (i.e. has no fractional part close to 0.5), the currently set sub tick count (\ref setSubTickCount) is returned. */ int QCPAxis::calculateAutoSubTickCount(double tickStep) const { int result = mSubTickCount; // default to current setting, if no proper value can be found // get mantissa of tickstep: double magnitudeFactor = qPow(10.0, qFloor(qLn(tickStep)/qLn(10.0))); // get magnitude factor e.g. 0.01, 1, 10, 1000 etc. double tickStepMantissa = tickStep/magnitudeFactor; // separate integer and fractional part of mantissa: double epsilon = 0.01; double intPartf; int intPart; double fracPart = modf(tickStepMantissa, &intPartf); intPart = intPartf; // handle cases with (almost) integer mantissa: if (fracPart < epsilon || 1.0-fracPart < epsilon) { if (1.0-fracPart < epsilon) intPart++; switch (intPart) { case 1: result = 4; break; // 1.0 -> 0.2 substep case 2: result = 3; break; // 2.0 -> 0.5 substep case 3: result = 2; break; // 3.0 -> 1.0 substep case 4: result = 3; break; // 4.0 -> 1.0 substep case 5: result = 4; break; // 5.0 -> 1.0 substep case 6: result = 2; break; // 6.0 -> 2.0 substep case 7: result = 6; break; // 7.0 -> 1.0 substep case 8: result = 3; break; // 8.0 -> 2.0 substep case 9: result = 2; break; // 9.0 -> 3.0 substep } } else { // handle cases with significantly fractional mantissa: if (qAbs(fracPart-0.5) < epsilon) // *.5 mantissa { switch (intPart) { case 1: result = 2; break; // 1.5 -> 0.5 substep case 2: result = 4; break; // 2.5 -> 0.5 substep case 3: result = 4; break; // 3.5 -> 0.7 substep case 4: result = 2; break; // 4.5 -> 1.5 substep case 5: result = 4; break; // 5.5 -> 1.1 substep (won't occur with autoTickStep from here on) case 6: result = 4; break; // 6.5 -> 1.3 substep case 7: result = 2; break; // 7.5 -> 2.5 substep case 8: result = 4; break; // 8.5 -> 1.7 substep case 9: result = 4; break; // 9.5 -> 1.9 substep } } // if mantissa fraction isnt 0.0 or 0.5, don't bother finding good sub tick marks, leave default } return result; } /*! \internal The main draw function of an axis, called by QCustomPlot::draw for each axis. Draws axis baseline, major ticks, subticks, tick labels and axis label. The selection boxes (mAxisSelectionBox, mTickLabelsSelectionBox, mLabelSelectionBox) are set here, too. */ void QCPAxis::draw(QCPPainter *painter) { QPoint origin; if (mAxisType == atLeft) origin = mAxisRect.bottomLeft(); else if (mAxisType == atRight) origin = mAxisRect.bottomRight(); else if (mAxisType == atTop) origin = mAxisRect.topLeft(); else if (mAxisType == atBottom) origin = mAxisRect.bottomLeft(); double xCor = 0, yCor = 0; // paint system correction, for pixel exact matches (affects baselines and ticks of top/right axes) switch (mAxisType) { case atTop: yCor = -1; break; case atRight: xCor = 1; break; default: break; } int margin = 0; int lowTick = mLowestVisibleTick; int highTick = mHighestVisibleTick; double t; // helper variable, result of coordinate-to-pixel transforms // draw baseline: painter->setPen(getBasePen()); if (orientation() == Qt::Horizontal) painter->drawLine(QLineF(origin+QPointF(xCor, yCor), origin+QPointF(mAxisRect.width()+xCor, yCor))); else painter->drawLine(QLineF(origin+QPointF(xCor, yCor), origin+QPointF(xCor, -mAxisRect.height()+yCor))); // draw ticks: if (mTicks) { painter->setPen(getTickPen()); // direction of ticks ("inward" is right for left axis and left for right axis) int tickDir = (mAxisType == atBottom || mAxisType == atRight) ? -1 : 1; if (orientation() == Qt::Horizontal) { for (int i=lowTick; i <= highTick; ++i) { t = coordToPixel(mTickVector.at(i)); // x painter->drawLine(QLineF(t+xCor, origin.y()-mTickLengthOut*tickDir+yCor, t+xCor, origin.y()+mTickLengthIn*tickDir+yCor)); } } else { for (int i=lowTick; i <= highTick; ++i) { t = coordToPixel(mTickVector.at(i)); // y painter->drawLine(QLineF(origin.x()-mTickLengthOut*tickDir+xCor, t+yCor, origin.x()+mTickLengthIn*tickDir+xCor, t+yCor)); } } } // draw subticks: if (mTicks && mSubTickCount > 0) { painter->setPen(getSubTickPen()); // direction of ticks ("inward" is right for left axis and left for right axis) int tickDir = (mAxisType == atBottom || mAxisType == atRight) ? -1 : 1; if (orientation() == Qt::Horizontal) { for (int i=0; idrawLine(QLineF(t+xCor, origin.y()-mSubTickLengthOut*tickDir+yCor, t+xCor, origin.y()+mSubTickLengthIn*tickDir+yCor)); } } else { for (int i=0; idrawLine(QLineF(origin.x()-mSubTickLengthOut*tickDir+xCor, t+yCor, origin.x()+mSubTickLengthIn*tickDir+xCor, t+yCor)); } } } margin += qMax(0, qMax(mTickLengthOut, mSubTickLengthOut)); // tick labels: QSize tickLabelsSize(0, 0); // size of largest tick label, for offset calculation of axis label if (mTickLabels) { margin += mTickLabelPadding; painter->setFont(getTickLabelFont()); painter->setPen(QPen(getTickLabelColor())); for (int i=lowTick; i <= highTick; ++i) { t = coordToPixel(mTickVector.at(i)); drawTickLabel(painter, t, margin, mTickVectorLabels.at(i), &tickLabelsSize); } } if (orientation() == Qt::Horizontal) margin += tickLabelsSize.height(); else margin += tickLabelsSize.width(); // axis label: QRect labelBounds; if (!mLabel.isEmpty()) { margin += mLabelPadding; painter->setFont(getLabelFont()); painter->setPen(QPen(getLabelColor())); labelBounds = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip, mLabel); if (mAxisType == atLeft) { QTransform oldTransform = painter->transform(); painter->translate((origin.x()-margin-labelBounds.height()), origin.y()); painter->rotate(-90); painter->drawText(0, 0, mAxisRect.height(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, mLabel); painter->setTransform(oldTransform); } else if (mAxisType == atRight) { QTransform oldTransform = painter->transform(); painter->translate((origin.x()+margin+labelBounds.height()), origin.y()-mAxisRect.height()); painter->rotate(90); painter->drawText(0, 0, mAxisRect.height(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, mLabel); painter->setTransform(oldTransform); } else if (mAxisType == atTop) painter->drawText(origin.x(), origin.y()-margin-labelBounds.height(), mAxisRect.width(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, mLabel); else if (mAxisType == atBottom) painter->drawText(origin.x(), origin.y()+margin, mAxisRect.width(), labelBounds.height(), Qt::TextDontClip | Qt::AlignCenter, mLabel); } // set selection boxes: int selAxisOutSize = qMax(qMax(mTickLengthOut, mSubTickLengthOut), mParentPlot->selectionTolerance()); int selAxisInSize = mParentPlot->selectionTolerance(); int selTickLabelSize = (orientation()==Qt::Horizontal ? tickLabelsSize.height() : tickLabelsSize.width()); int selTickLabelOffset = qMax(mTickLengthOut, mSubTickLengthOut)+mTickLabelPadding; int selLabelSize = labelBounds.height(); int selLabelOffset = selTickLabelOffset+selTickLabelSize+mLabelPadding; if (mAxisType == atLeft) { mAxisSelectionBox.setCoords(mAxisRect.left()-selAxisOutSize, mAxisRect.top(), mAxisRect.left()+selAxisInSize, mAxisRect.bottom()); mTickLabelsSelectionBox.setCoords(mAxisRect.left()-selTickLabelOffset-selTickLabelSize, mAxisRect.top(), mAxisRect.left()-selTickLabelOffset, mAxisRect.bottom()); mLabelSelectionBox.setCoords(mAxisRect.left()-selLabelOffset-selLabelSize, mAxisRect.top(), mAxisRect.left()-selLabelOffset, mAxisRect.bottom()); } else if (mAxisType == atRight) { mAxisSelectionBox.setCoords(mAxisRect.right()-selAxisInSize, mAxisRect.top(), mAxisRect.right()+selAxisOutSize, mAxisRect.bottom()); mTickLabelsSelectionBox.setCoords(mAxisRect.right()+selTickLabelOffset+selTickLabelSize, mAxisRect.top(), mAxisRect.right()+selTickLabelOffset, mAxisRect.bottom()); mLabelSelectionBox.setCoords(mAxisRect.right()+selLabelOffset+selLabelSize, mAxisRect.top(), mAxisRect.right()+selLabelOffset, mAxisRect.bottom()); } else if (mAxisType == atTop) { mAxisSelectionBox.setCoords(mAxisRect.left(), mAxisRect.top()-selAxisOutSize, mAxisRect.right(), mAxisRect.top()+selAxisInSize); mTickLabelsSelectionBox.setCoords(mAxisRect.left(), mAxisRect.top()-selTickLabelOffset-selTickLabelSize, mAxisRect.right(), mAxisRect.top()-selTickLabelOffset); mLabelSelectionBox.setCoords(mAxisRect.left(), mAxisRect.top()-selLabelOffset-selLabelSize, mAxisRect.right(), mAxisRect.top()-selLabelOffset); } else if (mAxisType == atBottom) { mAxisSelectionBox.setCoords(mAxisRect.left(), mAxisRect.bottom()-selAxisInSize, mAxisRect.right(), mAxisRect.bottom()+selAxisOutSize); mTickLabelsSelectionBox.setCoords(mAxisRect.left(), mAxisRect.bottom()+selTickLabelOffset+selTickLabelSize, mAxisRect.right(), mAxisRect.bottom()+selTickLabelOffset); mLabelSelectionBox.setCoords(mAxisRect.left(), mAxisRect.bottom()+selLabelOffset+selLabelSize, mAxisRect.right(), mAxisRect.bottom()+selLabelOffset); } // draw hitboxes for debug purposes: //painter->drawRects(QVector() << mAxisSelectionBox << mTickLabelsSelectionBox << mLabelSelectionBox); } /*! \internal Draws a single tick label with the provided \a painter. The tick label is always bound to an axis in one direction (distance to axis in that direction is however controllable via \a distanceToAxis in pixels). The position in the other direction is passed in the \a position parameter. Hence for the bottom axis, \a position would indicate the horizontal pixel position (not coordinate!), at which the label should be drawn. In order to draw the axis label after all the tick labels in a position, that doesn't overlap with the tick labels, we need to know the largest tick label size. This is done by passing a \a tickLabelsSize to all \ref drawTickLabel calls during the process of drawing all tick labels of one axis. \a tickLabelSize is only expanded, if the drawn label exceeds the value \a tickLabelsSize currently holds. This function is also responsible for turning ugly exponential numbers "5.5e9" into a more beautifully typeset format "5.5 [multiplication sign] 10 [superscript] 9". This feature is controlled with \ref setNumberFormat. The label is drawn with the font and pen that are currently set on the \a painter. To draw superscripted powers, the font is temporarily made smaller by a fixed factor. */ void QCPAxis::drawTickLabel(QCPPainter *painter, double position, int distanceToAxis, const QString &text, QSize *tickLabelsSize) { // warning: if you change anything here, also adapt getMaxTickLabelSize() accordingly! // determine whether beautiful decimal powers should be used bool useBeautifulPowers = false; int ePos = -1; if (mAutoTickLabels && mNumberBeautifulPowers && mTickLabelType == ltNumber) { ePos = text.indexOf('e'); if (ePos > -1) useBeautifulPowers = true; } // calculate text bounding rects and do string preparation for beautiful decimal powers: QRect bounds, baseBounds, expBounds; QString basePart, expPart; QFont bugFixFont(painter->font()); bugFixFont.setPointSizeF(bugFixFont.pointSizeF()+0.05); // QFontMetrics.boundingRect has a bug for exact point sizes that make the results oscillate due to internal rounding QFont expFont; if (useBeautifulPowers) { // split string parts for part of number/symbol that will be drawn normally and part that will be drawn as exponent: basePart = text.left(ePos); // in log scaling, we want to turn "1*10^n" into "10^n", else add multiplication sign and decimal base: if (mScaleType == stLogarithmic && basePart == "1") basePart = "10"; else basePart += (mNumberMultiplyCross ? QString(QChar(215)) : QString(QChar(183))) + "10"; expPart = text.mid(ePos+1); // clip "+" and leading zeros off expPart: while (expPart.at(1) == '0' && expPart.length() > 2) // length > 2 so we leave one zero when numberFormatChar is 'e' expPart.remove(1, 1); if (expPart.at(0) == mPositiveSignChar) expPart.remove(0, 1); // prepare smaller font for exponent: expFont = painter->font(); expFont.setPointSize(expFont.pointSize()*0.75); // calculate bounding rects of base part, exponent part and total one: QFontMetrics fontMetrics(bugFixFont); baseBounds = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip, basePart); QFontMetrics expFontMetrics(expFont); expBounds = expFontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip, expPart); bounds = baseBounds.adjusted(0, 0, expBounds.width(), 0); } else // useBeautifulPowers == false { QFontMetrics fontMetrics(bugFixFont); bounds = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter, text); } // if using rotated tick labels, transform bounding rect, too: QRect rotatedBounds = bounds; if (!qFuzzyIsNull(mTickLabelRotation)) { QTransform transform; transform.rotate(mTickLabelRotation); rotatedBounds = transform.mapRect(bounds); } // expand passed tickLabelsSize if current tick label is larger: if (rotatedBounds.width() > tickLabelsSize->width()) tickLabelsSize->setWidth(rotatedBounds.width()); if (rotatedBounds.height() > tickLabelsSize->height()) tickLabelsSize->setHeight(rotatedBounds.height()); /* calculate coordinates (non-trivial, for best visual appearance): short explanation for bottom axis: The anchor, i.e. the point in the label that is placed horizontally under the corresponding tick is always on the label side that is closer to the axis (e.g. the left side of the text when we're rotating clockwise). On that side, the height is halved and the resulting point is defined the anchor. This way, a 90 degree rotated text will be centered under the tick (i.e. displaced horizontally by half its height). At the same time, a 45 degree rotated text will "point toward" its tick, as is typical for rotated tick labels. */ bool doRotation = !qFuzzyIsNull(mTickLabelRotation); double radians = mTickLabelRotation/180.0*M_PI; int x=0,y=0; if (mAxisType == atLeft) { if (doRotation) { if (mTickLabelRotation > 0) { x = mAxisRect.left()-qCos(radians)*bounds.width()-distanceToAxis; y = position-qSin(radians)*bounds.width()-qCos(radians)*bounds.height()/2.0; } else { x = mAxisRect.left()-qCos(-radians)*bounds.width()-qSin(-radians)*bounds.height()-distanceToAxis; y = position+qSin(-radians)*bounds.width()-qCos(-radians)*bounds.height()/2.0; } } else { x = mAxisRect.left()-bounds.width()-distanceToAxis; y = position-bounds.height()/2.0; } } else if (mAxisType == atRight) { if (doRotation) { if (mTickLabelRotation > 0) { x = mAxisRect.right()+qSin(radians)*bounds.height()+distanceToAxis; y = position-qCos(radians)*bounds.height()/2.0; } else { x = mAxisRect.right()+distanceToAxis; y = position-qCos(-radians)*bounds.height()/2.0; } } else { x = mAxisRect.right()+distanceToAxis; y = position-bounds.height()/2.0; } } else if (mAxisType == atTop) { if (doRotation) { if (mTickLabelRotation > 0) { x = position-qCos(radians)*bounds.width()+qSin(radians)*bounds.height()/2.0; y = mAxisRect.top()-qSin(radians)*bounds.width()-qCos(radians)*bounds.height()-distanceToAxis; } else { x = position-qSin(-radians)*bounds.height()/2.0; y = mAxisRect.top()-qCos(-radians)*bounds.height()-distanceToAxis; } } else { x = position-bounds.width()/2.0; y = mAxisRect.top()-bounds.height()-distanceToAxis; } } else if (mAxisType == atBottom) { if (doRotation) { if (mTickLabelRotation > 0) { x = position+qSin(radians)*bounds.height()/2.0; y = mAxisRect.bottom()+distanceToAxis; } else { x = position-qCos(-radians)*bounds.width()-qSin(-radians)*bounds.height()/2.0; y = mAxisRect.bottom()+qSin(-radians)*bounds.width()+distanceToAxis; } } else { x = position-bounds.width()/2.0; y = mAxisRect.bottom()+distanceToAxis; } } // if label would be partly clipped by widget border on sides, don't draw it: if (orientation() == Qt::Horizontal) { if (x+bounds.width() > mParentPlot->mViewport.right() || x < mParentPlot->mViewport.left()) return; } else { if (y+bounds.height() > mParentPlot->mViewport.bottom() || y < mParentPlot->mViewport.top()) return; } // transform painter to position/rotation: QTransform oldTransform = painter->transform(); painter->translate(x, y); if (doRotation) painter->rotate(mTickLabelRotation); // draw text: if (useBeautifulPowers) { // draw base: painter->drawText(0, 0, 0, 0, Qt::TextDontClip, basePart); // draw exponent: QFont normalFont = painter->font(); painter->setFont(expFont); painter->drawText(baseBounds.width()+1, 0, expBounds.width(), expBounds.height(), Qt::TextDontClip, expPart); painter->setFont(normalFont); } else // useBeautifulPowers == false { painter->drawText(0, 0, bounds.width(), bounds.height(), Qt::TextDontClip | Qt::AlignHCenter, text); } // reset rotation/translation transform to what it was before: painter->setTransform(oldTransform); } /*! \internal Simulates the steps done by \ref drawTickLabel by calculating bounding boxes of the text label to be drawn, depending on number format etc. Since we only want the largest tick label for the margin calculation, the passed \a tickLabelsSize isn't overridden with the calculated label size, but it's only expanded, if it's currently set to a smaller width/height. */ void QCPAxis::getMaxTickLabelSize(const QFont &font, const QString &text, QSize *tickLabelsSize) const { // This function does the same as drawTickLabel but omits the actual drawing // changes involve creating extra QFontMetrics instances for font, since painter->fontMetrics() isn't available // determine whether beautiful powers should be used bool useBeautifulPowers = false; int ePos=-1; if (mAutoTickLabels && mNumberBeautifulPowers && mTickLabelType == ltNumber) { ePos = text.indexOf(mExponentialChar); if (ePos > -1) useBeautifulPowers = true; } // calculate and draw text, depending on whether beautiful powers are applicable or not: QRect bounds, baseBounds, expBounds; QString basePart, expPart; QFont bugFixFont(font); bugFixFont.setPointSizeF(bugFixFont.pointSizeF()+0.05); // QFontMetrics.boundingRect has a bug for exact point sizes that make the results oscillate due to internal rounding QFont expFont; if (useBeautifulPowers) { // split string parts for part of number/symbol that will be drawn normally and part that will be drawn as exponent: basePart = text.left(ePos); // in log scaling, we want to turn "1*10^n" into "10^n", else add multiplication sign and decimal base: if (mScaleType == stLogarithmic && basePart == "1") basePart = "10"; else basePart += (mNumberMultiplyCross ? QString(QChar(215)) : QString(QChar(183))) + "10"; expPart = text.mid(ePos+1); // clip "+" and leading zeros off expPart: while (expPart.at(1) == '0' && expPart.length() > 2) // length > 2 so we leave one zero when numberFormatChar is 'e' expPart.remove(1, 1); if (expPart.at(0) == mPositiveSignChar) expPart.remove(0, 1); // prepare smaller font for exponent: expFont = font; expFont.setPointSize(expFont.pointSize()*0.75); // calculate bounding rects of base part, exponent part and total one: QFontMetrics baseFontMetrics(bugFixFont); baseBounds = baseFontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip, basePart); QFontMetrics expFontMetrics(expFont); expBounds = expFontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip, expPart); bounds = baseBounds.adjusted(0, 0, expBounds.width(), 0); } else // useBeautifulPowers == false { QFontMetrics fontMetrics(bugFixFont); bounds = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter, text); } // if rotated tick labels, transform bounding rect, too: QRect rotatedBounds = bounds; if (!qFuzzyIsNull(mTickLabelRotation)) { QTransform transform; transform.rotate(mTickLabelRotation); rotatedBounds = transform.mapRect(bounds); } // expand passed tickLabelsSize if current tick label is larger: if (rotatedBounds.width() > tickLabelsSize->width()) tickLabelsSize->setWidth(rotatedBounds.width()); if (rotatedBounds.height() > tickLabelsSize->height()) tickLabelsSize->setHeight(rotatedBounds.height()); } /*! \internal Handles the selection \a event and returns true when the selection event hit any parts of the axis. If the selection state of any parts of the axis was changed, the output parameter \a modified is set to true. When \a additiveSelecton is true, any new selections become selected in addition to the recent selections. The recent selections are not cleared. Further, clicking on one object multiple times in additive selection mode, toggles the selection of that object on and off. To indicate that an event deselects the axis (i.e. the parts that are deselectable by the user, see \ref setSelectable), pass 0 as \a event. */ bool QCPAxis::handleAxisSelection(QMouseEvent *event, bool additiveSelection, bool &modified) { bool selectionFound = false; if (event) { SelectablePart selectedAxisPart = selectTest(event->pos()); if (selectedAxisPart == spNone || !selectable().testFlag(selectedAxisPart)) { // deselect parts that are changeable (selectable): SelectableParts newState = selected() & ~selectable(); if (newState != selected() && !additiveSelection) { modified = true; setSelected(newState); } } else { selectionFound = true; if (additiveSelection) { // additive selection, so toggle selected part: setSelected(selected() ^ selectedAxisPart); modified = true; } else { // not additive selection, so select part and deselect all others that are changeable (selectable): SelectableParts newState = (selected() & ~selectable()) | selectedAxisPart; if (newState != selected()) { modified = true; setSelected(newState); } } } } else // event == 0, so deselect all changeable parts { SelectableParts newState = selected() & ~selectable(); if (newState != selected()) { modified = true; setSelected(newState); } } return selectionFound; } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing axis lines. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set e.g. with \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased */ void QCPAxis::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeAxes); } /*! \internal Returns via \a lowIndex and \a highIndex, which ticks in the current tick vector are visible in the current range. The return values are indices of the tick vector, not the positions of the ticks themselves. The actual use of this function is when we have an externally provided tick vector, which might exceed far beyond the currently displayed range, and would cause unnecessary calculations e.g. of subticks. */ void QCPAxis::visibleTickBounds(int &lowIndex, int &highIndex) const { lowIndex = 0; highIndex = -1; // make sure only ticks that are in visible range are returned for (int i=0; i < mTickVector.size(); ++i) { lowIndex = i; if (mTickVector.at(i) >= mRange.lower) break; } for (int i=mTickVector.size()-1; i >= 0; --i) { highIndex = i; if (mTickVector.at(i) <= mRange.upper) break; } } /*! \internal A log function with the base mScaleLogBase, used mostly for coordinate transforms in logarithmic scales with arbitrary log base. Uses the buffered mScaleLogBaseLogInv for faster calculation. This is set to 1.0/qLn(mScaleLogBase) in \ref setScaleLogBase. \see basePow, setScaleLogBase, setScaleType */ double QCPAxis::baseLog(double value) const { return qLn(value)*mScaleLogBaseLogInv; } /*! \internal A power function with the base mScaleLogBase, used mostly for coordinate transforms in logarithmic scales with arbitrary log base. \see baseLog, setScaleLogBase, setScaleType */ double QCPAxis::basePow(double value) const { return qPow(mScaleLogBase, value); } /*! \internal Returns the pen that is used to draw the axis base line. Depending on the selection state, this is either mSelectedBasePen or mBasePen. */ QPen QCPAxis::getBasePen() const { return mSelected.testFlag(spAxis) ? mSelectedBasePen : mBasePen; } /*! \internal Returns the pen that is used to draw the (major) ticks. Depending on the selection state, this is either mSelectedTickPen or mTickPen. */ QPen QCPAxis::getTickPen() const { return mSelected.testFlag(spAxis) ? mSelectedTickPen : mTickPen; } /*! \internal Returns the pen that is used to draw the subticks. Depending on the selection state, this is either mSelectedSubTickPen or mSubTickPen. */ QPen QCPAxis::getSubTickPen() const { return mSelected.testFlag(spAxis) ? mSelectedSubTickPen : mSubTickPen; } /*! \internal Returns the font that is used to draw the tick labels. Depending on the selection state, this is either mSelectedTickLabelFont or mTickLabelFont. */ QFont QCPAxis::getTickLabelFont() const { return mSelected.testFlag(spTickLabels) ? mSelectedTickLabelFont : mTickLabelFont; } /*! \internal Returns the font that is used to draw the axis label. Depending on the selection state, this is either mSelectedLabelFont or mLabelFont. */ QFont QCPAxis::getLabelFont() const { return mSelected.testFlag(spAxisLabel) ? mSelectedLabelFont : mLabelFont; } /*! \internal Returns the color that is used to draw the tick labels. Depending on the selection state, this is either mSelectedTickLabelColor or mTickLabelColor. */ QColor QCPAxis::getTickLabelColor() const { return mSelected.testFlag(spTickLabels) ? mSelectedTickLabelColor : mTickLabelColor; } /*! \internal Returns the color that is used to draw the axis label. Depending on the selection state, this is either mSelectedLabelColor or mLabelColor. */ QColor QCPAxis::getLabelColor() const { return mSelected.testFlag(spAxisLabel) ? mSelectedLabelColor : mLabelColor; } /*! \internal Simulates the steps of \ref draw by calculating all appearing text bounding boxes. From this information, the appropriate margin for this axis is determined, so nothing is drawn beyond the widget border in the actual \ref draw function (if \ref QCustomPlot::setAutoMargin is set to true). The margin consists of: tick label padding, tick label size, label padding, label size. The return value is the calculated margin for this axis. Thus, an axis with axis type \ref atLeft will return an appropriate left margin, \ref atBottom will return an appropriate bottom margin and so forth. \warning if anything is changed in this function, make sure it's synchronized with the actual drawing function \ref draw. */ int QCPAxis::calculateMargin() const { // run through similar steps as QCPAxis::draw, and caluclate margin needed to fit axis and its labels int margin = 0; if (mVisible) { int lowTick, highTick; visibleTickBounds(lowTick, highTick); // get length of tick marks reaching outside axis rect: margin += qMax(0, qMax(mTickLengthOut, mSubTickLengthOut)); // calculate size of tick labels: QSize tickLabelsSize(0, 0); if (mTickLabels) { for (int i=lowTick; i <= highTick; ++i) { getMaxTickLabelSize(mTickLabelFont, mTickVectorLabels.at(i), &tickLabelsSize); // don't use getTickLabelFont() because we don't want margin to possibly change on selection } if (orientation() == Qt::Horizontal) margin += tickLabelsSize.height() + mTickLabelPadding; else margin += tickLabelsSize.width() + mTickLabelPadding; } // calculate size of axis label (only height needed, because left/right labels are rotated by 90 degrees): if (!mLabel.isEmpty()) { QFontMetrics fontMetrics(mLabelFont); // don't use getLabelFont() because we don't want margin to possibly change on selection QRect bounds; bounds = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip | Qt::AlignHCenter | Qt::AlignVCenter, mLabel); margin += bounds.height() + mLabelPadding; } } margin += mPadding; if (margin < 15) // need a bit of margin if no axis text is shown at all (i.e. only baseline and tick lines, or no axis at all) margin = 15; return margin; } // ================================================================================ // =================== QCustomPlot // ================================================================================ /*! \class QCustomPlot \brief The central class of the library, the QWidget which displays the plot and interacts with the user. For tutorials on how to use QCustomPlot, see the website\n http://www.WorksLikeClockWork.com/index.php/components/qt-plotting-widget */ /* start of documentation of inline functions */ /*! \fn QRect QCustomPlot::viewport() const Returns the viewport rect of this QCustomPlot instance. The viewport is the area the plot is drawn in, all mechanisms, e.g. margin caluclation take the viewport to be the outer border of the plot. The viewport normally is the rect() of the QCustomPlot widget, i.e. a rect with top left (0, 0) and size of the QCustomPlot widget. Don't confuse the viewport with the axisRect. An axisRect is the rect defined by two axes, where the graphs/plottables are drawn in. The viewport is larger and contains also the axes themselves, their tick numbers, their labels, the plot title etc. Only when saving to a file (see \ref savePng, savePdf etc.) the viewport is temporarily modified to allow saving plots with sizes independent of the current widget size. */ /* end of documentation of inline functions */ /* start of documentation of signals */ /*! \fn void QCustomPlot::mouseDoubleClick(QMouseEvent *event) This signal is emitted when the QCustomPlot receives a mouse double click event. */ /*! \fn void QCustomPlot::mousePress(QMouseEvent *event) This signal is emitted when the QCustomPlot receives a mouse press event. It is emitted before the QCustomPlot handles its range dragging mechanism, so a slot connected to this signal can still influence the behaviour e.g. with \ref setRangeDrag or \ref setRangeDragAxes. */ /*! \fn void QCustomPlot::mouseMove(QMouseEvent *event) This signal is emitted when the QCustomPlot receives a mouse move event. It is emitted before the QCustomPlot handles its range dragging mechanism, so a slot connected to this signal can still influence the behaviour e.g. with \ref setRangeDrag. \warning It is discouraged to change the drag-axes with \ref setRangeDragAxes here, because the dragging starting point was saved the moment the mouse was pressed. Thus it only has a sensible meaning for the range drag axes that were set at that moment. If you want to change the drag axes, consider doing this in the \ref mousePress signal instead. */ /*! \fn void QCustomPlot::mouseRelease(QMouseEvent *event) This signal is emitted when the QCustomPlot receives a mouse release event. It is emitted before the QCustomPlot handles its selection mechanism, so a slot connected to this signal can still influence the behaviour e.g. with \ref setInteractions or \ref QCPAbstractPlottable::setSelectable. */ /*! \fn void QCustomPlot::mouseWheel(QMouseEvent *event) This signal is emitted when the QCustomPlot receives a mouse wheel event. It is emitted before the QCustomPlot handles its range zooming mechanism, so a slot connected to this signal can still influence the behaviour e.g. with \ref setRangeZoom, \ref setRangeZoomAxes or \ref setRangeZoomFactor. */ /*! \fn void QCustomPlot::plottableClick(QCPAbstractPlottable *plottable, QMouseEvent *event) This signal is emitted when a plottable is clicked. \a event is the mouse event that caused the click and \a plottable is the plottable that received the click. \see plottableDoubleClick */ /*! \fn void QCustomPlot::plottableDoubleClick(QCPAbstractPlottable *plottable, QMouseEvent *event) This signal is emitted when a plottable is double clicked. \a event is the mouse event that caused the click and \a plottable is the plottable that received the click. \see plottableClick */ /*! \fn void QCustomPlot::itemClick(QCPAbstractItem *item, QMouseEvent *event) This signal is emitted when an item is clicked. \a event is the mouse event that caused the click and \a item is the item that received the click. \see itemDoubleClick */ /*! \fn void QCustomPlot::itemDoubleClick(QCPAbstractItem *item, QMouseEvent *event) This signal is emitted when an item is double clicked. \a event is the mouse event that caused the click and \a item is the item that received the click. \see itemClick */ /*! \fn void QCustomPlot::axisClick(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event) This signal is emitted when an axis is clicked. \a event is the mouse event that caused the click, \a axis is the axis that received the click and \a part indicates the part of the axis that was clicked. \see axisDoubleClick */ /*! \fn void QCustomPlot::axisDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event) This signal is emitted when an axis is double clicked. \a event is the mouse event that caused the click, \a axis is the axis that received the click and \a part indicates the part of the axis that was clicked. \see axisClick */ /*! \fn void QCustomPlot::legendClick(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event) This signal is emitted when a legend (item) is clicked. \a event is the mouse event that caused the click, \a legend is the legend that received the click and \a item is the legend item that received the click. If only the legend and no item is clicked, \a item is 0 (e.g. a click inside the legend padding, which is not part of any item). \see legendDoubleClick */ /*! \fn void QCustomPlot::legendDoubleClick(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event) This signal is emitted when a legend (item) is double clicked. \a event is the mouse event that caused the click, \a legend is the legend that received the click and \a item is the legend item that received the click. If only the legend and no item is clicked, \a item is 0 (e.g. a click inside the legend padding, which is not part of any item). \see legendClick */ /*! \fn void QCustomPlot:: titleClick(QMouseEvent *event) This signal is emitted when the plot title is clicked. \a event is the mouse event that caused the click. \see titleDoubleClick */ /*! \fn void QCustomPlot::titleDoubleClick(QMouseEvent *event) This signal is emitted when the plot title is double clicked. \a event is the mouse event that caused the click. \see titleClick */ /*! \fn void QCustomPlot::selectionChangedByUser() This signal is emitted after the user has changed the selection in the QCustomPlot, e.g. by clicking. It is not emitted, when the selection state of an object has changed programmatically, e.g. by a direct call to setSelected() on a plottable or by calling \ref deselectAll. See the documentation of \ref setInteractions for how to find out which objects are currently selected. \see setInteractions, QCPAbstractPlottable::selectionChanged, QCPAxis::selectionChanged */ /*! \fn void QCustomPlot::beforeReplot() This signal is emitted immediately before a replot takes place (caused by a call to the slot \ref replot). It is safe to mutually connect the replot slot with this signal on two QCustomPlots to make them replot synchronously (i.e. it won't cause an infinite recursion). \see replot, afterReplot */ /*! \fn void QCustomPlot::afterReplot() This signal is emitted immediately after a replot has taken place (caused by a call to the slot \ref replot). It is safe to mutually connect the replot slot with this signal on two QCustomPlots to make them replot synchronously (i.e. it won't cause an infinite recursion). \see replot, beforeReplot */ /* end of documentation of signals */ /*! Constructs a QCustomPlot and sets reasonable default values. Four axes are created at the bottom, left, top and right sides (xAxis, yAxis, xAxis2, yAxis2), however, only the bottom and left axes are set to be visible. The legend is also set to be invisible initially. */ QCustomPlot::QCustomPlot(QWidget *parent) : QWidget(parent), mDragging(false), mReplotting(false), mPlottingHints(QCP::phNone) { setAttribute(Qt::WA_NoMousePropagation); setAttribute(Qt::WA_OpaquePaintEvent); setMouseTracking(true); QLocale currentLocale = locale(); currentLocale.setNumberOptions(QLocale::OmitGroupSeparator); setLocale(currentLocale); // create very first layers: QCPLayer *gridLayer = new QCPLayer(this, "grid"); QCPLayer *mainLayer = new QCPLayer(this, "main"); QCPLayer *axesLayer = new QCPLayer(this, "axes"); mLayers.append(gridLayer); mLayers.append(mainLayer); mLayers.append(axesLayer); setCurrentLayer(mainLayer); mPaintBuffer = QPixmap(size()); legend = new QCPLegend(this); legend->setVisible(false); legend->setLayer(axesLayer); xAxis = new QCPAxis(this, QCPAxis::atBottom); yAxis = new QCPAxis(this, QCPAxis::atLeft); xAxis2 = new QCPAxis(this, QCPAxis::atTop); yAxis2 = new QCPAxis(this, QCPAxis::atRight); xAxis2->setGrid(false); yAxis2->setGrid(false); xAxis2->setZeroLinePen(Qt::NoPen); yAxis2->setZeroLinePen(Qt::NoPen); xAxis2->setVisible(false); yAxis2->setVisible(false); xAxis->setLayer(axesLayer); yAxis->setLayer(axesLayer); xAxis2->setLayer(axesLayer); yAxis2->setLayer(axesLayer); xAxis->mGrid->setLayer(gridLayer); yAxis->mGrid->setLayer(gridLayer); xAxis2->mGrid->setLayer(gridLayer); yAxis2->mGrid->setLayer(gridLayer); mViewport = rect(); setNoAntialiasingOnDrag(false); setAutoAddPlottableToLegend(true); setAxisBackgroundScaled(true); setAxisBackgroundScaledMode(Qt::KeepAspectRatioByExpanding); setTitleFont(QFont(font().family(), 14, QFont::Bold)); setTitleColor(Qt::black); setSelectedTitleFont(QFont(font().family(), 14, QFont::Bold)); setSelectedTitleColor(Qt::blue); setTitleSelected(false); setTitle(""); setColor(Qt::white); #ifdef Q_WS_WIN setPlottingHint(QCP::phForceRepaint); #endif setAntialiasedElements(QCP::aeNone); setNotAntialiasedElements(QCP::aeNone); setInteractions(iRangeDrag|iRangeZoom); setMultiSelectModifier(Qt::ControlModifier); setRangeDragAxes(xAxis, yAxis); setRangeZoomAxes(xAxis, yAxis); setRangeDrag(0); setRangeZoom(0); setRangeZoomFactor(0.85); setSelectionTolerance(8); setMargin(0, 0, 0, 0); // also initializes the mAxisRect setAutoMargin(true); replot(); } QCustomPlot::~QCustomPlot() { clearPlottables(); clearItems(); delete legend; delete xAxis; delete yAxis; delete xAxis2; delete yAxis2; qDeleteAll(mLayers); mLayers.clear(); } /*! Returns the range drag axis of the \a orientation provided \see setRangeDragAxes */ QCPAxis *QCustomPlot::rangeDragAxis(Qt::Orientation orientation) { return (orientation == Qt::Horizontal ? mRangeDragHorzAxis : mRangeDragVertAxis); } /*! Returns the range zoom axis of the \a orientation provided \see setRangeZoomAxes */ QCPAxis *QCustomPlot::rangeZoomAxis(Qt::Orientation orientation) { return (orientation == Qt::Horizontal ? mRangeZoomHorzAxis : mRangeZoomVertAxis); } /*! Returns the range zoom factor of the \a orientation provided \see setRangeZoomFactor */ double QCustomPlot::rangeZoomFactor(Qt::Orientation orientation) { return (orientation == Qt::Horizontal ? mRangeZoomFactorHorz : mRangeZoomFactorVert); } /*! Sets the plot title which will be drawn centered at the top of the widget. The title position is not dependant on the actual position of the axes. However, if \ref setAutoMargin is set to true, the top margin will be adjusted appropriately, so the top axis labels/tick labels will not overlap with the title. \see setTitleFont, setTitleColor */ void QCustomPlot::setTitle(const QString &title) { mTitle = title; } /*! Sets the font of the plot title \see setTitleColor, setTitle */ void QCustomPlot::setTitleFont(const QFont &font) { mTitleFont = font; } /*! Sets the text color of the plot title \see setTitleFont, setTitle */ void QCustomPlot::setTitleColor(const QColor &color) { mTitleColor = color; } /*! An alternative way to set the margins, by directly setting the wanted axis rect. The rect will be translated into appropriate margin values. \warning Setting the axis rect with this function does not guarantee that the axis rect will stay like this indefinitely. In QCustomPlot, margins are the fixed values (if \ref setAutoMargin is false). Hence the axis rect is automatically changed when the widget size changes, but the margins (distances between axis rect sides and widget/viewport rect sides) stay the same. \see setMargin */ void QCustomPlot::setAxisRect(const QRect &arect) { mMarginLeft = arect.left()-mViewport.left(); mMarginRight = mViewport.right()-arect.right(); mMarginTop = arect.top()-mViewport.top(); mMarginBottom = mViewport.bottom()-arect.bottom(); updateAxisRect(); } /*! Sets the left margin manually. Will only have effect, if \ref setAutoMargin is set to false. see \ref setMargin for an explanation of what margins mean in QCustomPlot. */ void QCustomPlot::setMarginLeft(int margin) { mMarginLeft = margin; updateAxisRect(); } /*! Sets the right margin manually. Will only have effect, if \ref setAutoMargin is set to false. see \ref setMargin for an explanation of what margins mean in QCustomPlot. */ void QCustomPlot::setMarginRight(int margin) { mMarginRight = margin; updateAxisRect(); } /*! Sets the top margin manually. Will only have effect, if \ref setAutoMargin is set to false. see \ref setMargin for an explanation of what margins mean in QCustomPlot. */ void QCustomPlot::setMarginTop(int margin) { mMarginTop = margin; updateAxisRect(); } /*! Sets the bottom margin manually. Will only have effect, if \ref setAutoMargin is set to false. see \ref setMargin for an explanation of what margins mean in QCustomPlot. */ void QCustomPlot::setMarginBottom(int margin) { mMarginBottom = margin; updateAxisRect(); } /*! Sets the margins manually. Will only have effect, if \ref setAutoMargin is set to false. The margins are the distances in pixels between the axes box and the viewport box. The viewport box normally is the entire QCustomPlot widget or the entire image, if using one of the export functions. Positive margin values always mean the axes box is shrinked, going inward from the sides of the viewport box. */ void QCustomPlot::setMargin(int left, int right, int top, int bottom) { mMarginLeft = left; mMarginRight = right; mMarginTop = top; mMarginBottom = bottom; updateAxisRect(); } /*! Sets whether the margins are calculated automatically depeding on the sizes of the tick labels, axis labels, paddings etc. If disabled, the margins must be set manually with the \a setMargin functions. \see setMargin, QCPAxis::setLabelPadding, QCPAxis::setTickLabelPadding */ void QCustomPlot::setAutoMargin(bool enabled) { mAutoMargin = enabled; } /*! Sets the background color of the QCustomPlot widget. */ void QCustomPlot::setColor(const QColor &color) { mColor = color; } /*! Sets which axis orientation may be range dragged by the user with mouse interaction. What orientation corresponds to which specific axis can be set with \ref setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical). By default, the horizontal axis is the bottom axis (xAxis) and the vertical axis is the left axis (yAxis). To disable range dragging entirely, pass 0 as \a orientations or remove \ref iRangeDrag from \ref setInteractions. To enable range dragging for both directions, pass Qt::Horizontal | Qt::Vertical as \a orientations. In addition to setting \a orientations to a non-zero value, make sure \ref setInteractions contains \ref iRangeDrag to enable the range dragging interaction. \see setRangeZoom, setRangeDragAxes, setNoAntialiasingOnDrag */ void QCustomPlot::setRangeDrag(Qt::Orientations orientations) { mRangeDrag = orientations; } /*! Sets which axis orientation may be zoomed by the user with the mouse wheel. What orientation corresponds to which specific axis can be set with \ref setRangeZoomAxes(QCPAxis *horizontal, QCPAxis *vertical). By default, the horizontal axis is the bottom axis (xAxis) and the vertical axis is the left axis (yAxis). To disable range zooming entirely, pass 0 as \a orientations or remove \ref iRangeZoom from \ref setInteractions. To enable range zooming for both directions, pass Qt::Horizontal | Qt::Vertical as \a orientations. In addition to setting \a orientations to a non-zero value, make sure \ref setInteractions contains \ref iRangeZoom to enable the range zooming interaction. \see setRangeZoomFactor, setRangeZoomAxes, setRangeDrag */ void QCustomPlot::setRangeZoom(Qt::Orientations orientations) { mRangeZoom = orientations; } /*! Sets the axes whose range will be dragged when \ref setRangeDrag enables mouse range dragging on the QCustomPlot widget. \see setRangeZoomAxes */ void QCustomPlot::setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical) { if (horizontal) mRangeDragHorzAxis = horizontal; if (vertical) mRangeDragVertAxis = vertical; } /*! Sets the axes whose range will be zoomed when \ref setRangeZoom enables mouse wheel zooming on the QCustomPlot widget. The two axes can be zoomed with different strengths, when different factors are passed to \ref setRangeZoomFactor(double horizontalFactor, double verticalFactor). \see setRangeDragAxes */ void QCustomPlot::setRangeZoomAxes(QCPAxis *horizontal, QCPAxis *vertical) { if (horizontal) mRangeZoomHorzAxis = horizontal; if (vertical) mRangeZoomVertAxis = vertical; } /*! Sets how strong one rotation step of the mouse wheel zooms, when range zoom was activated with \ref setRangeZoom. The two parameters \a horizontalFactor and \a verticalFactor provide a way to let the horizontal axis zoom at different rates than the vertical axis. Which axis is horizontal and which is vertical, can be set with \ref setRangeZoomAxes. When the zoom factor is greater than one, scrolling the mouse wheel backwards (towards the user) will zoom in (make the currently visible range smaller). For zoom factors smaller than one, the same scrolling direction will zoom out. */ void QCustomPlot::setRangeZoomFactor(double horizontalFactor, double verticalFactor) { mRangeZoomFactorHorz = horizontalFactor; mRangeZoomFactorVert = verticalFactor; } /*! \overload Sets both the horizontal and vertical zoom \a factor. */ void QCustomPlot::setRangeZoomFactor(double factor) { mRangeZoomFactorHorz = factor; mRangeZoomFactorVert = factor; } /*! Sets which elements are forcibly drawn antialiased as an or combination of QCP::AntialiasedElement. This overrides the antialiasing settings for whole element groups, normally controlled with the \a setAntialiasing function on the individual elements. If an element is neither specified in \ref setAntialiasedElements nor in \ref setNotAntialiasedElements, the antialiasing setting on each individual element instance is used. For example, if \a antialiasedElements contains \ref QCP::aePlottables, all plottables will be drawn antialiased, no matter what the specific QCPAbstractPlottable::setAntialiased value was set to. \see setNotAntialiasedElements */ void QCustomPlot::setAntialiasedElements(const QCP::AntialiasedElements &antialiasedElements) { mAntialiasedElements = antialiasedElements; // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously: if ((mNotAntialiasedElements & mAntialiasedElements) != 0) mNotAntialiasedElements |= ~mAntialiasedElements; } /*! Sets whether the specified \a antialiasedElement is forcibly drawn antialiased. This overrides the antialiasing settings for whole element groups, normally controlled with the \a setAntialiasing function on the individual elements. If an element is neither specified in \ref setAntialiasedElements nor in \ref setNotAntialiasedElements, the antialiasing setting on each individual element instance is used. For example, if \a enabled is true and \a antialiasedElement is \ref QCP::aePlottables, all plottables will be drawn antialiased, no matter what the specific QCPAbstractPlottable::setAntialiased value was set to. \see setNotAntialiasedElement */ void QCustomPlot::setAntialiasedElement(QCP::AntialiasedElement antialiasedElement, bool enabled) { if (!enabled && mAntialiasedElements.testFlag(antialiasedElement)) mAntialiasedElements &= ~antialiasedElement; else if (enabled && !mAntialiasedElements.testFlag(antialiasedElement)) mAntialiasedElements |= antialiasedElement; // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously: if ((mNotAntialiasedElements & mAntialiasedElements) != 0) mNotAntialiasedElements |= ~mAntialiasedElements; } /*! Sets which elements are forcibly drawn not antialiased as an or combination of QCP::AntialiasedElement. This overrides the antialiasing settings for whole element groups, normally controlled with the \a setAntialiasing function on the individual elements. If an element is neither specified in \ref setAntialiasedElements nor in \ref setNotAntialiasedElements, the antialiasing setting on each individual element instance is used. For example, if \a notAntialiasedElements contains \ref QCP::aePlottables, no plottables will be drawn antialiased, no matter what the specific QCPAbstractPlottable::setAntialiased value was set to. if an element in \a notAntialiasedElements is already set in \ref setAntialiasedElements, it is removed from there. \see setAntialiasedElements */ void QCustomPlot::setNotAntialiasedElements(const QCP::AntialiasedElements ¬AntialiasedElements) { mNotAntialiasedElements = notAntialiasedElements; // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously: if ((mNotAntialiasedElements & mAntialiasedElements) != 0) mAntialiasedElements |= ~mNotAntialiasedElements; } /*! Sets whether the specified \a notAntialiasedElement is forcibly drawn not antialiased. This overrides the antialiasing settings for whole element groups, normally controlled with the \a setAntialiasing function on the individual elements. If an element is neither specified in \ref setAntialiasedElements nor in \ref setNotAntialiasedElements, the antialiasing setting on each individual element instance is used. For example, if \a enabled is true and \a notAntialiasedElement is \ref QCP::aePlottables, no plottables will be drawn antialiased, no matter what the specific QCPAbstractPlottable::setAntialiased value was set to. if \a enabled is true and \a notAntialiasedElement is already set with \ref setAntialiasedElement, it is removed from there. \see setAntialiasedElement */ void QCustomPlot::setNotAntialiasedElement(QCP::AntialiasedElement notAntialiasedElement, bool enabled) { if (!enabled && mNotAntialiasedElements.testFlag(notAntialiasedElement)) mNotAntialiasedElements &= ~notAntialiasedElement; else if (enabled && !mNotAntialiasedElements.testFlag(notAntialiasedElement)) mNotAntialiasedElements |= notAntialiasedElement; // make sure elements aren't in mNotAntialiasedElements and mAntialiasedElements simultaneously: if ((mNotAntialiasedElements & mAntialiasedElements) != 0) mAntialiasedElements |= ~mNotAntialiasedElements; } /*! If set to true, adding a plottable (e.g. a graph) to the QCustomPlot automatically also adds the newly created plottable to the legend. \see addPlottable, addGraph, QCPLegend::addItem */ void QCustomPlot::setAutoAddPlottableToLegend(bool on) { mAutoAddPlottableToLegend = on; } /*! Sets \a pm as the axis background pixmap. The axis background pixmap will be drawn inside the current axis rect, before anything else (e.g. the axes themselves, grids, graphs, etc.) is drawn. If the provided pixmap doesn't have the same size as the axis rect, scaling can be enabled with \ref setAxisBackgroundScaled and the scaling mode (i.e. whether and how the aspect ratio is preserved) can be set with \ref setAxisBackgroundScaledMode. To set all these options in one call, consider using the overloaded version of this function. \see setAxisBackgroundScaled, setAxisBackgroundScaledMode */ void QCustomPlot::setAxisBackground(const QPixmap &pm) { mAxisBackground = pm; mScaledAxisBackground = QPixmap(); } /*! \overload Allows setting the background pixmap, whether it shall be scaled and how it shall be scaled in one call. \see setAxisBackground(const QPixmap &pm), setAxisBackgroundScaled, setAxisBackgroundScaledMode */ void QCustomPlot::setAxisBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode) { mAxisBackground = pm; mScaledAxisBackground = QPixmap(); mAxisBackgroundScaled = scaled; mAxisBackgroundScaledMode = mode; } /*! Sets whether the axis background pixmap shall be scaled to fit the current axis rect or not. If \a scaled is set to true, you may control whether and how the aspect ratio of the original pixmap is preserved with \ref setAxisBackgroundScaledMode. Note that the scaled version of the original pixmap is buffered, so there is no performance penalty on replots, when enabling the scaling. (Except of course, the axis rect is continuously changed, but that's not very likely.) \see setAxisBackground, setAxisBackgroundScaledMode */ void QCustomPlot::setAxisBackgroundScaled(bool scaled) { mAxisBackgroundScaled = scaled; } /*! If scaling of the axis background pixmap is enabled (\ref setAxisBackgroundScaled), use this function to define whether and how the aspect ratio of the original pixmap passed to \ref setAxisBackground is preserved. \see setAxisBackground, setAxisBackgroundScaled */ void QCustomPlot::setAxisBackgroundScaledMode(Qt::AspectRatioMode mode) { mAxisBackgroundScaledMode = mode; } /*! Sets the possible interactions of this QCustomPlot as an or-combination of \ref Interaction enums. There are the following types of interactions: Axis range manipulation is controlled via \ref iRangeDrag and \ref iRangeZoom. When the respective interaction is enabled, the user may drag axes ranges and zoom with the mouse wheel. For details how to control which axes the user may drag/zoom and in what orientations, see \ref setRangeDrag, \ref setRangeZoom, \ref setRangeDragAxes, \ref setRangeZoomAxes. Plottable selection is controlled by \ref iSelectPlottables. If \ref iSelectPlottables is set, the user may select plottables (e.g. graphs, curves, bars,...) by clicking on them or in their vicinity, see \ref setSelectionTolerance. Whether the user can actually select a plottable can further be restricted with the \ref QCPAbstractPlottable::setSelectable function on the specific plottable. To find out whether a specific plottable is selected, call QCPAbstractPlottable::selected(). To retrieve a list of all currently selected plottables, call \ref selectedPlottables. If you're only interested in QCPGraphs, you may use the convenience function \ref selectedGraphs. Item selection is controlled by \ref iSelectItems. If \ref iSelectItems is set, the user may select items (e.g. QCPItemLine, QCPItemText,...) by clicking on them or in their vicinity. To find out whether a specific item is selected, call QCPAbstractItem::selected(). To retrieve a list of all currently selected items, call \ref selectedItems. Axis selection is controlled with \ref iSelectAxes. If \ref iSelectAxes is set, the user may select parts of the axes by clicking on them. What parts exactly (e.g. Axis base line, tick labels, axis label) are selectable can be controlled via \ref QCPAxis::setSelectable for each axis. To retrieve a list of all axes that currently contain selected parts, call \ref selectedAxes. Which parts of an axis are selected, can be retrieved with QCPAxis::selected(). Legend selection is controlled with \ref iSelectLegend. If this is set, the user may select the legend itself or individual items by clicking on them. What parts exactly are selectable can be controlled via \ref QCPLegend::setSelectable. To find out whether the legend or any child items are selected, check the value of QCPLegend::selected. To find out which child items are selected, call \ref QCPLegend::selectedItems. Plot title selection is controlled with \ref iSelectTitle. If set, the user may select the plot title by clicking on it. To find out whether the title is currently selected, call QCustomPlot::titleSelected(). If the selection state has changed by user interaction, the \ref selectionChangedByUser signal is emitted. Each selectable object additionally emits an individual selectionChanged signal whenever their selection state has changed, i.e. not only by user interaction. To allow multiple objects to be selected by holding the modifier set with \ref setMultiSelectModifier, set the flag \ref iMultiSelect. \note In addition to the selection mechanism presented here, QCustomPlot always emits corresponding signals, when an object is clicked or double clicked. see \ref plottableClick and \ref plottableDoubleClick for example. \see setInteraction, setSelectionTolerance */ void QCustomPlot::setInteractions(const Interactions &interactions) { mInteractions = interactions; } /*! Sets the single \a interaction of this QCustomPlot to \a enabled. For details about the interaction system, see \ref setInteractions. \see setInteractions */ void QCustomPlot::setInteraction(const QCustomPlot::Interaction &interaction, bool enabled) { if (!enabled && mInteractions.testFlag(interaction)) mInteractions &= ~interaction; else if (enabled && !mInteractions.testFlag(interaction)) mInteractions |= interaction; } /*! Sets the tolerance that is used when deciding whether a click on the QCustomPlot surface selects an object (e.g. a plottable) or not. If for example the user clicks in the vicinity of the line of a QCPGraph, it's only regarded as a potential selection when the minimum distance between the click position and the graph line is smaller than \a pixels. Objects that are defined by an area (e.g. QCPBars) only react to clicks directly inside the area and ignore this selection tolerance. In other words it only has meaning for parts of objects that are too thin to exactly hit with a click and thus need such a tolerance. \see setInteractions, QCPAbstractPlottable::selectTest */ void QCustomPlot::setSelectionTolerance(int pixels) { mSelectionTolerance = pixels; } /*! This \a font is used to draw the title, when it is selected. \see setTitleSelected, setTitleFont */ void QCustomPlot::setSelectedTitleFont(const QFont &font) { mSelectedTitleFont = font; } /*! This \a color is used to draw the title, when it is selected. \see setTitleSelected, setTitleColor */ void QCustomPlot::setSelectedTitleColor(const QColor &color) { mSelectedTitleColor = color; } /*! Sets whether the plot title is selected. \see setInteractions, setSelectedTitleFont, setSelectedTitleColor, setTitle */ void QCustomPlot::setTitleSelected(bool selected) { mTitleSelected = selected; } /*! Sets whether antialiasing is disabled for all elements while the user is dragging axes ranges. If many objects, especially plottables, are normally drawn antialiased, this greatly improves performance during dragging. Thus it creates a more responsive user experience. As soon as the user stops dragging, the last replot is done with normal antialiasing, to restore high image quality. \see setAntialiasedElements, setNotAntialiasedElements */ void QCustomPlot::setNoAntialiasingOnDrag(bool enabled) { mNoAntialiasingOnDrag = enabled; } /*! Sets the plotting hints for this QCustomPlot instance. \see setPlottingHint */ void QCustomPlot::setPlottingHints(const QCP::PlottingHints &hints) { mPlottingHints = hints; } /*! Sets the specified plotting \a hint to \a enabled. \see setPlottingHints */ void QCustomPlot::setPlottingHint(QCP::PlottingHint hint, bool enabled) { QCP::PlottingHints newHints = mPlottingHints; if (!enabled) newHints &= ~hint; else newHints |= hint; if (newHints != mPlottingHints) setPlottingHints(newHints); } /*! Sets the keyboard modifier that will be recognized as multi-select-modifier. If \ref iMultiSelect is specified in \ref setInteractions, the user may select multiple objects by clicking on them one after the other while holding down \a modifier. By default the multi-select-modifier is set to Qt::ControlModifier. \see setInteractions */ void QCustomPlot::setMultiSelectModifier(Qt::KeyboardModifier modifier) { mMultiSelectModifier = modifier; } /*! Returns the plottable with \a index. If the index is invalid, returns 0. There is an overloaded version of this function with no parameter which returns the last added plottable, see QCustomPlot::plottable() \see plottableCount, addPlottable */ QCPAbstractPlottable *QCustomPlot::plottable(int index) { if (index >= 0 && index < mPlottables.size()) { return mPlottables.at(index); } else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return 0; } } /*! \overload Returns the last plottable, that was added with \ref addPlottable. If there are no plottables in the plot, returns 0. \see plottableCount, addPlottable */ QCPAbstractPlottable *QCustomPlot::plottable() { if (!mPlottables.isEmpty()) { return mPlottables.last(); } else return 0; } /*! Adds the specified plottable to the plot and, if \ref setAutoAddPlottableToLegend is enabled, to the legend. QCustomPlot takes ownership of the plottable. Returns true on success, i.e. when \a plottable wasn't already added to the plot and the parent plot of \a plottable is this QCustomPlot (the latter is controlled by what axes the plottable was passed in the constructor). \see plottable, plottableCount, removePlottable, clearPlottables */ bool QCustomPlot::addPlottable(QCPAbstractPlottable *plottable) { if (mPlottables.contains(plottable)) { qDebug() << Q_FUNC_INFO << "plottable already added to this QCustomPlot:" << reinterpret_cast(plottable); return false; } if (plottable->parentPlot() != this) { qDebug() << Q_FUNC_INFO << "plottable not created with this QCustomPlot as parent:" << reinterpret_cast(plottable); return false; } mPlottables.append(plottable); // possibly add plottable to legend: if (mAutoAddPlottableToLegend) plottable->addToLegend(); // special handling for QCPGraphs to maintain the simple graph interface: if (QCPGraph *graph = qobject_cast(plottable)) mGraphs.append(graph); if (!plottable->layer()) // usually the layer is already set in the constructor of the plottable (via QCPLayerable constructor) plottable->setLayer(currentLayer()); return true; } /*! Removes the specified plottable from the plot and, if necessary, from the legend. Returns true on success. \see addPlottable, clearPlottables */ bool QCustomPlot::removePlottable(QCPAbstractPlottable *plottable) { if (!mPlottables.contains(plottable)) { qDebug() << Q_FUNC_INFO << "plottable not in list:" << reinterpret_cast(plottable); return false; } // remove plottable from legend: plottable->removeFromLegend(); // special handling for QCPGraphs to maintain the simple graph interface: if (QCPGraph *graph = qobject_cast(plottable)) mGraphs.removeOne(graph); // remove plottable: delete plottable; mPlottables.removeOne(plottable); return true; } /*! \overload Removes the plottable by its \a index. */ bool QCustomPlot::removePlottable(int index) { if (index >= 0 && index < mPlottables.size()) return removePlottable(mPlottables[index]); else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return false; } } /*! Removes all plottables from the plot (and the legend, if necessary). Returns the number of plottables removed. \see removePlottable */ int QCustomPlot::clearPlottables() { int c = mPlottables.size(); for (int i=c-1; i >= 0; --i) removePlottable(mPlottables[i]); return c; } /*! Returns the number of currently existing plottables in the plot \see plottable, addPlottable */ int QCustomPlot::plottableCount() const { return mPlottables.size(); } /*! Returns a list of the selected plottables. If no plottables are currently selected, the list is empty. There is a convenience function if you're only interested in selected graphs, see \ref selectedGraphs. \see setInteractions, QCPAbstractPlottable::setSelectable, QCPAbstractPlottable::setSelected, selectedGraphs */ QList QCustomPlot::selectedPlottables() const { QList result; for (int i=0; iselected()) result.append(mPlottables.at(i)); } return result; } /*! Returns the plottable at the pixel position \a pos. Plottables that only consist of single lines (e.g. graphs) have a tolerance band around them, see \ref setSelectionTolerance. If multiple plottables come into consideration, the one closest to \a pos is returned. If \a onlySelectable is true, only plottables that are selectable (QCPAbstractPlottable::setSelectable) are considered. If there is no plottable at \a pos, the return value is 0. */ QCPAbstractPlottable *QCustomPlot::plottableAt(const QPointF &pos, bool onlySelectable) const { QCPAbstractPlottable *resultPlottable = 0; double resultDistance = mSelectionTolerance; // only regard clicks with distances smaller than mSelectionTolerance as selections, so initialize with that value for (int i=0; iselectable()) continue; if ((currentPlottable->keyAxis()->axisRect() | currentPlottable->valueAxis()->axisRect()).contains(pos.toPoint())) // only consider clicks inside the rect that is spanned by the plottable's key/value axes { double currentDistance = currentPlottable->selectTest(pos); if (currentDistance >= 0 && currentDistance < resultDistance) { resultPlottable = currentPlottable; resultDistance = currentDistance; } } } return resultPlottable; } /*! Returns whether this QCustomPlot instance contains the \a plottable. \see addPlottable */ bool QCustomPlot::hasPlottable(QCPAbstractPlottable *plottable) const { return mPlottables.contains(plottable); } /*! Returns the graph with \a index. If the index is invalid, returns 0. There is an overloaded version of this function with no parameter which returns the last created graph, see QCustomPlot::graph() \see graphCount, addGraph */ QCPGraph *QCustomPlot::graph(int index) const { if (index >= 0 && index < mGraphs.size()) { return mGraphs.at(index); } else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return 0; } } /*! \overload Returns the last graph, that was created with \ref addGraph. If there are no graphs in the plot, returns 0. \see graphCount, addGraph */ QCPGraph *QCustomPlot::graph() const { if (!mGraphs.isEmpty()) { return mGraphs.last(); } else return 0; } /*! Creates a new graph inside the plot. If \a keyAxis and \a valueAxis are left unspecified (0), the bottom (xAxis) is used as key and the left (yAxis) is used as value. If specified, \a keyAxis and \a valueAxis must reside in this QCustomPlot. \a keyAxis will be used as key axis (typically "x") and \a valueAxis as value axis (typically "y") for the graph. Returns a pointer to the newly created graph. \see graph, graphCount, removeGraph, clearGraphs */ QCPGraph *QCustomPlot::addGraph(QCPAxis *keyAxis, QCPAxis *valueAxis) { if (!keyAxis) keyAxis = xAxis; if (!valueAxis) valueAxis = yAxis; if (keyAxis->parentPlot() != this || valueAxis->parentPlot() != this) { qDebug() << Q_FUNC_INFO << "passed keyAxis or valueAxis doesn't have this QCustomPlot as parent"; return 0; } QCPGraph *newGraph = new QCPGraph(keyAxis, valueAxis); if (addPlottable(newGraph)) { newGraph->setName("Graph "+QString::number(mGraphs.size())); return newGraph; } else { delete newGraph; return 0; } } /*! Removes the specified \a graph from the plot and, if necessary, from the legend. If any other graphs in the plot have a channel fill set towards the removed graph, the channel fill property of those graphs is reset to zero (no channel fill). Returns true on success. \see clearGraphs */ bool QCustomPlot::removeGraph(QCPGraph *graph) { return removePlottable(graph); } /*! \overload Removes the graph by its \a index. */ bool QCustomPlot::removeGraph(int index) { if (index >= 0 && index < mGraphs.size()) return removeGraph(mGraphs[index]); else return false; } /*! Removes all graphs from the plot (and the legend, if necessary). Returns the number of graphs removed. \see removeGraph */ int QCustomPlot::clearGraphs() { int c = mGraphs.size(); for (int i=c-1; i >= 0; --i) removeGraph(mGraphs[i]); return c; } /*! Returns the number of currently existing graphs in the plot \see graph, addGraph */ int QCustomPlot::graphCount() const { return mGraphs.size(); } /*! Returns a list of the selected graphs. If no graphs are currently selected, the list is empty. \note Even if the returned list is empty, it might still be, that there are selected plottables in the plot that are not of type QCPGraph (e.g. QCPCurve, QCPBars, etc.), see \ref selectedPlottables. Of course, this only applies, if you actually add non-QCPGraph plottables. \see setInteractions, selectedPlottables, QCPAbstractPlottable::setSelectable, QCPAbstractPlottable::setSelected */ QList QCustomPlot::selectedGraphs() const { QList result; for (int i=0; iselected()) result.append(mGraphs.at(i)); } return result; } /*! Returns the item with \a index. If the index is invalid, returns 0. There is an overloaded version of this function with no parameter which returns the last added item, see QCustomPlot::item() \see itemCount, addItem */ QCPAbstractItem *QCustomPlot::item(int index) const { if (index >= 0 && index < mItems.size()) { return mItems.at(index); } else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return 0; } } /*! \overload Returns the last item, that was added with \ref addItem. If there are no items in the plot, returns 0. \see itemCount, addItem */ QCPAbstractItem *QCustomPlot::item() const { if (!mItems.isEmpty()) { return mItems.last(); } else return 0; } /*! Adds the specified item to the plot. QCustomPlot takes ownership of the item. Returns true on success, i.e. when \a item wasn't already added to the plot and the parent plot of \a item is this QCustomPlot. \see item, itemCount, removeItem, clearItems */ bool QCustomPlot::addItem(QCPAbstractItem *item) { if (!mItems.contains(item) && item->parentPlot() == this) { mItems.append(item); return true; } else { qDebug() << Q_FUNC_INFO << "item either already in list or not created with this QCustomPlot as parent:" << reinterpret_cast(item); return false; } } /*! Removes the specified item from the plot. Returns true on success. \see addItem, clearItems */ bool QCustomPlot::removeItem(QCPAbstractItem *item) { if (mItems.contains(item)) { delete item; mItems.removeOne(item); return true; } else { qDebug() << Q_FUNC_INFO << "item not in list:" << reinterpret_cast(item); return false; } } /*! \overload Removes the item by its \a index. */ bool QCustomPlot::removeItem(int index) { if (index >= 0 && index < mItems.size()) return removeItem(mItems[index]); else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return false; } } /*! Removes all items from the plot. Returns the number of items removed. \see removeItem */ int QCustomPlot::clearItems() { int c = mItems.size(); for (int i=c-1; i >= 0; --i) removeItem(mItems[i]); return c; } /*! Returns the number of currently existing items in the plot \see item, addItem */ int QCustomPlot::itemCount() const { return mItems.size(); } /*! Returns a list of the selected items. If no items are currently selected, the list is empty. \see setInteractions, QCPAbstractItem::setSelectable, QCPAbstractItem::setSelected */ QList QCustomPlot::selectedItems() const { QList result; for (int i=0; iselected()) result.append(mItems.at(i)); } return result; } /*! Returns the item at the pixel position \a pos. Items that only consist of single lines (e.g. \ref QCPItemLine or \ref QCPItemCurve) have a tolerance band around them, see \ref setSelectionTolerance. If multiple items come into consideration, the one closest to \a pos is returned. If \a onlySelectable is true, only items that are selectable (QCPAbstractItem::setSelectable) are considered. If there is no item at \a pos, the return value is 0. */ QCPAbstractItem *QCustomPlot::itemAt(const QPointF &pos, bool onlySelectable) const { QCPAbstractItem *resultItem = 0; double resultDistance = mSelectionTolerance; // only regard clicks with distances smaller than mSelectionTolerance as selections, so initialize with that value for (int i=0; iselectable()) continue; if (!currentItem->clipToAxisRect() || currentItem->clipRect().contains(pos.toPoint())) // only consider clicks inside axis cliprect of the item if actually clipped to it { double currentDistance = currentItem->selectTest(pos); if (currentDistance >= 0 && currentDistance < resultDistance) { resultItem = currentItem; resultDistance = currentDistance; } } } return resultItem; } /*! Returns the layer with the specified \a name. \see addLayer, moveLayer, removeLayer */ QCPLayer *QCustomPlot::layer(const QString &name) const { for (int i=0; iname() == name) return mLayers.at(i); } return 0; } /*! \overload Returns the layer by index. \see addLayer, moveLayer, removeLayer */ QCPLayer *QCustomPlot::layer(int index) const { if (index >= 0 && index < mLayers.size()) { return mLayers.at(index); } else { qDebug() << Q_FUNC_INFO << "index out of bounds:" << index; return 0; } } /*! Returns the layer that is set as current layer (see \ref setCurrentLayer). */ QCPLayer *QCustomPlot::currentLayer() const { return mCurrentLayer; } /*! Sets the layer with the specified \a name to be the current layer. All newly created/added layerables (\ref QCPLayerable), e.g. plottables and items, are initially placed on the current layer. Returns true on success, i.e. if there is a layer with the specified \a name in the QCustomPlot. \see addLayer, moveLayer, removeLayer */ bool QCustomPlot::setCurrentLayer(const QString &name) { if (QCPLayer *newCurrentLayer = layer(name)) { return setCurrentLayer(newCurrentLayer); } else { qDebug() << Q_FUNC_INFO << "layer with name doesn't exist:" << name; return false; } } /*! \overload Sets the provided \a layer to be the current layer. Returns true on success, i.e. when \a layer is a valid layer in the QCustomPlot. \see addLayer, moveLayer, removeLayer */ bool QCustomPlot::setCurrentLayer(QCPLayer *layer) { if (!mLayers.contains(layer)) { qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast(layer); return false; } mCurrentLayer = layer; return true; } /*! Returns the number of currently existing layers in the plot \see layer, addLayer */ int QCustomPlot::layerCount() const { return mLayers.size(); } /*! Adds a new layer to this QCustomPlot instance. The new layer will have the name \a name, which must be unique. It is positioned either below or above \a otherLayer, which can be controlled with \a insertMode. Returns true on success, i.e. if there is no other layer named \a name and \a otherLayer is a valid layer inside this QCustomPlot. If \a otherLayer is 0, the highest layer in the QCustomPlot will be used. For an explanation of what layers are in QCustomPlot, see the documentation of \ref QCPLayer. \see layer, moveLayer, removeLayer */ bool QCustomPlot::addLayer(const QString &name, QCPLayer *otherLayer, QCustomPlot::LayerInsertMode insertMode) { if (!otherLayer) otherLayer = mLayers.last(); if (!mLayers.contains(otherLayer)) { qDebug() << Q_FUNC_INFO << "otherLayer not a layer of this QCustomPlot:" << reinterpret_cast(otherLayer); return false; } if (layer(name)) { qDebug() << Q_FUNC_INFO << "A layer exists already with the name" << name; return false; } QCPLayer *newLayer = new QCPLayer(this, name); mLayers.insert(otherLayer->index() + (insertMode==limAbove ? 1:0), newLayer); return true; } /*! Removes the specified \a layer and returns true on success. All layerables (e.g. plottables and items) on the removed layer will be moved to the layer below \a layer. If \a layer is the bottom layer, the layerables are moved to the layer above. In both cases, the total rendering order of all layerables in the QCustomPlot is preserved. If \a layer is the current layer (\ref setCurrentLayer), the layer below (or above, if bottom layer) becomes the new current layer. Note that it is not possible to remove the last layer. \see layer, addLayer, moveLayer */ bool QCustomPlot::removeLayer(QCPLayer *layer) { if (!mLayers.contains(layer)) { qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast(layer); return false; } //if (!mLayers.size() > 1) if (mLayers.size() <= 1) { qDebug() << Q_FUNC_INFO << "can't remove last layer"; return false; } // append all children of this layer to layer below (if this is lowest layer, prepend to layer above) int removedIndex = layer->index(); bool isFirstLayer = removedIndex==0; QCPLayer *targetLayer = isFirstLayer ? mLayers.at(removedIndex+1) : mLayers.at(removedIndex-1); QList children = layer->children(); if (isFirstLayer) // prepend in reverse order (so order relative to each other stays the same) { for (int i=children.size()-1; i>=0; --i) children.at(i)->moveToLayer(targetLayer, true); } else // append normally { for (int i=0; imoveToLayer(targetLayer, false); } // if removed layer is current layer, change current layer to layer below/above: if (layer == mCurrentLayer) setCurrentLayer(targetLayer); // remove layer: delete layer; mLayers.removeOne(layer); return true; } /*! Moves the specified \a layer to the position relative to \a otherLayer. Whether \a layer is placed above or below \a otherLayer can be controlled with \a insertMode. Returns true on success, i.e. when both \a layer and \a otherLayer are valid layers in the QCustomPlot. \see layer, addLayer, moveLayer */ bool QCustomPlot::moveLayer(QCPLayer *layer, QCPLayer *otherLayer, QCustomPlot::LayerInsertMode insertMode) { if (!mLayers.contains(layer)) { qDebug() << Q_FUNC_INFO << "layer not a layer of this QCustomPlot:" << reinterpret_cast(layer); return false; } if (!mLayers.contains(otherLayer)) { qDebug() << Q_FUNC_INFO << "otherLayer not a layer of this QCustomPlot:" << reinterpret_cast(otherLayer); return false; } mLayers.move(layer->index(), otherLayer->index() + (insertMode==limAbove ? 1:0)); return true; } /*! Returns the axes that currently have selected parts, i.e. whose selection is not \ref QCPAxis::spNone. \see selectedPlottables, selectedLegends, setInteractions, QCPAxis::setSelected, QCPAxis::setSelectable */ QList QCustomPlot::selectedAxes() const { QList result = QList() << xAxis << yAxis << xAxis2 << yAxis2; for (int i=result.size()-1; i>=0; --i) { if (result.at(i)->selected() == QCPAxis::spNone) result.removeAt(i); } return result; } /*! Returns the legends (typically one or zero) that currently have selected parts, i.e. whose selection is not \ref QCPLegend::spNone. \see selectedPlottables, selectedAxes, setInteractions, QCPLegend::setSelected, QCPLegend::setSelectable, QCPLegend::selectedItems */ QList QCustomPlot::selectedLegends() const { /* for now, we only have the one legend. Maybe later, there will be a mechanism to have more. */ QList result; if (legend->selected() != QCPLegend::spNone) result.append(legend); return result; } /*! Deselects everything in the QCustomPlot (plottables, items, axes, legend and title). Since calling this function is not a user interaction, this does not emit the \ref selectionChangedByUser signal. The individual selectionChanged signals are emitted though, if the objects were previously selected. \see setInteractions, selectedPlottables, selectedItems, selectedAxes, selectedLegends */ void QCustomPlot::deselectAll() { // deselect plottables: QList selPlottables = selectedPlottables(); for (int i=0; isetSelected(false); // deselect items: QList selItems = selectedItems(); for (int i=0; isetSelected(false); // deselect axes: QList selAxes = selectedAxes(); for (int i=0; isetSelected(QCPAxis::spNone); // deselect legend (and legend items): legend->setSelected(QCPLegend::spNone); // deselect title: setTitleSelected(false); } /*! Causes a complete replot (axes, labels, graphs, etc.) into the internal buffer. Finally, update() is called, to redraw the buffer on the QCustomPlot widget surface. Before the replot happens, the signal \ref beforeReplot is emitted. After the replot, \ref afterReplot is emitted. It is safe to mutually connect the replot slot with any of those two signals on two QCustomPlots to make them replot synchronously (i.e. it won't cause an infinite recursion). */ void QCustomPlot::replot() { if (mReplotting) // incase signals loop back to replot slot return; mReplotting = true; emit beforeReplot(); mPaintBuffer.fill(mColor); QCPPainter painter; painter.begin(&mPaintBuffer); if (painter.isActive()) { painter.setRenderHint(QPainter::HighQualityAntialiasing); draw(&painter); if (mPlottingHints.testFlag(QCP::phForceRepaint)) repaint(); else update(); painter.end(); } else // might happen if QCustomPlot has width or height zero qDebug() << Q_FUNC_INFO << "Couldn't activate painter on buffer"; emit afterReplot(); mReplotting = false; } /*! Convenience function to make the top and right axes visible and assign them the following properties from their corresponding bottom/left axes: \li range (\ref QCPAxis::setRange) \li range reversed (\ref QCPAxis::setRangeReversed) \li scale type (\ref QCPAxis::setScaleType) \li scale log base (\ref QCPAxis::setScaleLogBase) \li ticks (\ref QCPAxis::setTicks) \li auto (major) tick count (\ref QCPAxis::setAutoTickCount) \li sub tick count (\ref QCPAxis::setSubTickCount) \li auto sub ticks (\ref QCPAxis::setAutoSubTicks) \li tick step (\ref QCPAxis::setTickStep) \li auto tick step (\ref QCPAxis::setAutoTickStep) Tick labels (\ref QCPAxis::setTickLabels) however, is always set to false. This function does \a not connect the rangeChanged signals of the bottom and left axes to the \ref QCPAxis::setRange slots of the top and right axes in order to synchronize the ranges permanently. */ void QCustomPlot::setupFullAxesBox() { xAxis2->setVisible(true); yAxis2->setVisible(true); xAxis2->setTickLabels(false); yAxis2->setTickLabels(false); xAxis2->setAutoSubTicks(xAxis->autoSubTicks()); yAxis2->setAutoSubTicks(yAxis->autoSubTicks()); xAxis2->setAutoTickCount(xAxis->autoTickCount()); yAxis2->setAutoTickCount(yAxis->autoTickCount()); xAxis2->setAutoTickStep(xAxis->autoTickStep()); yAxis2->setAutoTickStep(yAxis->autoTickStep()); xAxis2->setScaleType(xAxis->scaleType()); yAxis2->setScaleType(yAxis->scaleType()); xAxis2->setScaleLogBase(xAxis->scaleLogBase()); yAxis2->setScaleLogBase(yAxis->scaleLogBase()); xAxis2->setTicks(xAxis->ticks()); yAxis2->setTicks(yAxis->ticks()); xAxis2->setSubTickCount(xAxis->subTickCount()); yAxis2->setSubTickCount(yAxis->subTickCount()); xAxis2->setTickStep(xAxis->tickStep()); yAxis2->setTickStep(yAxis->tickStep()); xAxis2->setRange(xAxis->range()); yAxis2->setRange(yAxis->range()); xAxis2->setRangeReversed(xAxis->rangeReversed()); yAxis2->setRangeReversed(yAxis->rangeReversed()); } /*! Rescales the axes such that all plottables (e.g. graphs) in the plot are fully visible. It does this by calling \ref QCPAbstractPlottable::rescaleAxes on all plottables. \see QCPAbstractPlottable::rescaleAxes */ void QCustomPlot::rescaleAxes() { if (mPlottables.isEmpty()) return; mPlottables.at(0)->rescaleAxes(false); // onlyEnlarge disabled on first plottable for (int i=1; irescaleAxes(true); // onlyEnlarge enabled on all other plottables } /*! Saves a PDF with the vectorized plot to the file \a fileName. The axis ratio as well as the scale of texts and lines will be derived from the specified \a width and \a height. This means, the output will look like the normal on-screen output of a QCustomPlot widget with the corresponding pixel width and height. If either \a width or \a height is zero, the exported image will have the same dimensions as the QCustomPlot widget currently has. \a noCosmeticPen disables the use of cosmetic pens when drawing to the PDF file. Cosmetic pens are pens with numerical width 0, which are always drawn as a one pixel wide line, no matter what zoom factor is set in the PDF-Viewer. For more information about cosmetic pens, see QPainter and QPen documentation. The objects of the plot will appear in the current selection state. So when you don't want e.g. selected axes to be painted in their selected look, deselect everything with \ref deselectAll before calling this function. Returns true on success. \warning \li If you plan on editing the exported PDF file with a vector graphics editor like Inkscape, it is advised to set \a noCosmeticPen to true to avoid losing those cosmetic lines (which might be quite many, because cosmetic pens are the default for e.g. axes and tick marks). \li If calling this function inside the constructor of the parent of the QCustomPlot widget (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this function uses the current width and height of the QCustomPlot widget. However, in Qt, these aren't defined yet inside the constructor, so you would get an image that has strange widths/heights. \see savePng, saveBmp, saveJpg, saveRastered */ bool QCustomPlot::savePdf(const QString &fileName, bool noCosmeticPen, int width, int height) { bool success = false; int newWidth, newHeight; if (width == 0 || height == 0) { newWidth = this->width(); newHeight = this->height(); } else { newWidth = width; newHeight = height; } QPrinter printer(QPrinter::ScreenResolution); printer.setOutputFileName(fileName); printer.setFullPage(true); QRect oldViewport = mViewport; mViewport = QRect(0, 0, newWidth, newHeight); updateAxisRect(); printer.setPaperSize(mViewport.size(), QPrinter::DevicePixel); QCPPainter printpainter; if (printpainter.begin(&printer)) { printpainter.setPdfExportMode(true); printpainter.setWindow(mViewport); printpainter.setRenderHint(QPainter::NonCosmeticDefaultPen, noCosmeticPen); if (mColor != Qt::white && mColor != Qt::transparent && mColor.alpha() > 0) // draw pdf background color if not white/transparent printpainter.fillRect(mViewport, mColor); draw(&printpainter); printpainter.end(); success = true; } mViewport = oldViewport; updateAxisRect(); return success; } /*! Saves a PNG image file to \a fileName on disc. The output plot will have the dimensions \a width and \a height in pixels. If either \a width or \a height is zero, the exported image will have the same dimensions as the QCustomPlot widget currently has. Line widths and texts etc. are not scaled up when larger widths/heights are used. If you want that effect, use the \a scale parameter. For example, if you set both \a width and \a height to 100 and \a scale to 2, you will end up with an image file of size 200*200 in which all graphical elements are scaled up by factor 2 (line widths, texts, etc.). This scaling is not done by stretching a 100*100 image, the result will have full 200*200 pixel resolution. \warning If calling this function inside the constructor of the parent of the QCustomPlot widget (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this function uses the current width and height of the QCustomPlot widget. However, in Qt, these aren't defined yet inside the constructor, so you would get an image that has strange widths/heights. The objects of the plot will appear in the current selection state. If you don't want any selected objects to be painted in their selected look, deselect everything with \ref deselectAll before calling this function. If you want the plot to be painted in a PNG with transparent background, call \ref setColor with a transparent color, e.g. Qt::transparent, before saving. PNG compression can be controlled with the \a quality parameter which must be between 0 and 100 or -1 to use the default setting. Returns true on success. If this function fails, most likely the PNG format isn't supported by the system, see Qt docs about QImageWriter::supportedImageFormats(). \see savePdf, saveBmp, saveJpg, saveRastered */ bool QCustomPlot::savePng(const QString &fileName, int width, int height, double scale, int quality) { return saveRastered(fileName, width, height, scale, "PNG", quality); } /*! Saves a JPG image file to \a fileName on disc. The output plot will have the dimensions \a width and \a height in pixels. If either \a width or \a height is zero, the exported image will have the same dimensions as the QCustomPlot widget currently has. Line widths and texts etc. are not scaled up when larger widths/heights are used. If you want that effect, use the \a scale parameter. For example, if you set both \a width and \a height to 100 and \a scale to 2, you will end up with an image file of size 200*200 in which all graphical elements are scaled up by factor 2 (line widths, texts, etc.). This scaling is not done by stretching a 100*100 image, the result will have full 200*200 pixel resolution. \warning If calling this function inside the constructor of the parent of the QCustomPlot widget (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this function uses the current width and height of the QCustomPlot widget. However, in Qt, these aren't defined yet inside the constructor, so you would get an image that has strange widths/heights. The objects of the plot will appear in the current selection state. If you don't want any selected objects to be painted in their selected look, deselect everything with \ref deselectAll before calling this function. JPG compression can be controlled with the \a quality parameter which must be between 0 and 100 or -1 to use the default setting. Returns true on success. If this function fails, most likely the JPG format isn't supported by the system, see Qt docs about QImageWriter::supportedImageFormats(). \see savePdf, savePng, saveBmp, saveRastered */ bool QCustomPlot::saveJpg(const QString &fileName, int width, int height, double scale, int quality) { return saveRastered(fileName, width, height, scale, "JPG", quality); } /*! Saves a BMP image file to \a fileName on disc. The output plot will have the dimensions \a width and \a height in pixels. If either \a width or \a height is zero, the exported image will have the same dimensions as the QCustomPlot widget currently has. Line widths and texts etc. are not scaled up when larger widths/heights are used. If you want that effect, use the \a scale parameter. For example, if you set both \a width and \a height to 100 and \a scale to 2, you will end up with an image file of size 200*200 in which all graphical elements are scaled up by factor 2 (line widths, texts, etc.). This scaling is not done by stretching a 100*100 image, the result will have full 200*200 pixel resolution. \warning If calling this function inside the constructor of the parent of the QCustomPlot widget (i.e. the MainWindow constructor, if QCustomPlot is inside the MainWindow), always provide explicit non-zero widths and heights. If you leave \a width or \a height as 0 (default), this function uses the current width and height of the QCustomPlot widget. However, in Qt, these aren't defined yet inside the constructor, so you would get an image that has strange widths/heights. The objects of the plot will appear in the current selection state. If you don't want any selected objects to be painted in their selected look, deselect everything with \ref deselectAll before calling this function. Returns true on success. If this function fails, most likely the BMP format isn't supported by the system, see Qt docs about QImageWriter::supportedImageFormats(). \see savePdf, savePng, saveJpg, saveRastered */ bool QCustomPlot::saveBmp(const QString &fileName, int width, int height, double scale) { return saveRastered(fileName, width, height, scale, "BMP"); } /*! \internal Returns a minimum size hint of QSize(50, 50). This prevents QCustomPlot from being collapsed to size/width zero when placed in a layout where other components try to take in as much space as possible (e.g. QMdiArea). (To overwrite this minimum size hint of QCustomPlot, simply call QWidget::setMinimumSize in the QCustomPlot widget.) */ QSize QCustomPlot::minimumSizeHint() const { return QSize(50, 50); } /*! \internal Event handler for when the QCustomPlot widget needs repainting. This does not cause a replot, but draws the internal buffer on the widget surface. */ void QCustomPlot::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter painter(this); painter.drawPixmap(0, 0, mPaintBuffer); } /*! \internal Event handler for a resize of the QCustomPlot widget. Causes the internal buffer to be resized to the new size. The viewport and the axis rect are resized appropriately. Finally a replot is performed. */ void QCustomPlot::resizeEvent(QResizeEvent *event) { // resize and repaint the buffer: mPaintBuffer = QPixmap(event->size()); mViewport = rect(); updateAxisRect(); replot(); } /*! \internal Event handler for when a double click occurs. */ void QCustomPlot::mouseDoubleClickEvent(QMouseEvent *event) { emit mouseDoubleClick(event); // emit specialized object double click signals: bool foundHit = false; // for legend: if (receivers(SIGNAL(legendDoubleClick(QCPLegend*,QCPAbstractLegendItem*,QMouseEvent*))) > 0) { if (legend->selectTestLegend(event->pos())) { emit legendDoubleClick(legend, legend->selectTestItem(event->pos()), event); foundHit = true; } } // for plottables: if (!foundHit && receivers(SIGNAL(plottableDoubleClick(QCPAbstractPlottable*,QMouseEvent*))) > 0) { if (QCPAbstractPlottable *ap = plottableAt(event->pos(), false)) { emit plottableDoubleClick(ap, event); foundHit = true; } } // for items: if (!foundHit && receivers(SIGNAL(itemDoubleClick(QCPAbstractItem*,QMouseEvent*))) > 0) { if (QCPAbstractItem *ai = itemAt(event->pos(), false)) { emit itemDoubleClick(ai, event); foundHit = true; } } // for axes: if (!foundHit && receivers(SIGNAL(axisDoubleClick(QCPAxis*,QCPAxis::SelectablePart,QMouseEvent*))) > 0) { QVector axes = QVector() << xAxis << yAxis << xAxis2 << yAxis2; for (int i=0; iselectTest(event->pos()); if (part != QCPAxis::spNone) { foundHit = true; emit axisDoubleClick(axes.at(i), part, event); break; } } } // for title: if (!foundHit && receivers(SIGNAL(titleDoubleClick(QMouseEvent*))) > 0) { if (selectTestTitle(event->pos())) { emit titleDoubleClick(event); foundHit = true; } } } /*! \internal Event handler for when a mouse button is pressed. If the left mouse button is pressed, the range dragging interaction is initialized (the actual range manipulation happens in the \ref mouseMoveEvent). The mDragging flag is set to true and some anchor points are set that are needed to determine the distance the mouse was dragged in the mouse move/release events later. \see mouseMoveEvent, mouseReleaseEvent */ void QCustomPlot::mousePressEvent(QMouseEvent *event) { emit mousePress(event); mDragStart = event->pos(); // need this even when not LeftButton is pressed, to determine in releaseEvent whether it was a full click (no position change between press and release) if (event->buttons() & Qt::LeftButton) { mDragging = true; // initialize antialiasing backup in case we start dragging: if (mNoAntialiasingOnDrag) { mAADragBackup = antialiasedElements(); mNotAADragBackup = notAntialiasedElements(); } // Mouse range dragging interaction: if (mInteractions.testFlag(iRangeDrag)) { mDragStartHorzRange = mRangeDragHorzAxis->range(); mDragStartVertRange = mRangeDragVertAxis->range(); } } QWidget::mousePressEvent(event); } /*! \internal Event handler for when the cursor is moved. This is where the built-in range dragging mechanism is handled. \see mousePressEvent, mouseReleaseEvent */ void QCustomPlot::mouseMoveEvent(QMouseEvent *event) { emit mouseMove(event); // Mouse range dragging interaction: if (mInteractions.testFlag(iRangeDrag)) { if (mDragging) { if (mRangeDrag.testFlag(Qt::Horizontal)) { if (mRangeDragHorzAxis->mScaleType == QCPAxis::stLinear) { double diff = mRangeDragHorzAxis->pixelToCoord(mDragStart.x()) - mRangeDragHorzAxis->pixelToCoord(event->pos().x()); mRangeDragHorzAxis->setRange(mDragStartHorzRange.lower+diff, mDragStartHorzRange.upper+diff); } else if (mRangeDragHorzAxis->mScaleType == QCPAxis::stLogarithmic) { double diff = mRangeDragHorzAxis->pixelToCoord(mDragStart.x()) / mRangeDragHorzAxis->pixelToCoord(event->pos().x()); mRangeDragHorzAxis->setRange(mDragStartHorzRange.lower*diff, mDragStartHorzRange.upper*diff); } } if (mRangeDrag.testFlag(Qt::Vertical)) { if (mRangeDragVertAxis->mScaleType == QCPAxis::stLinear) { double diff = mRangeDragVertAxis->pixelToCoord(mDragStart.y()) - mRangeDragVertAxis->pixelToCoord(event->pos().y()); mRangeDragVertAxis->setRange(mDragStartVertRange.lower+diff, mDragStartVertRange.upper+diff); } else if (mRangeDragVertAxis->mScaleType == QCPAxis::stLogarithmic) { double diff = mRangeDragVertAxis->pixelToCoord(mDragStart.y()) / mRangeDragVertAxis->pixelToCoord(event->pos().y()); mRangeDragVertAxis->setRange(mDragStartVertRange.lower*diff, mDragStartVertRange.upper*diff); } } if (mRangeDrag != 0) // if either vertical or horizontal drag was enabled, do a replot { if (mNoAntialiasingOnDrag) setNotAntialiasedElements(QCP::aeAll); replot(); } } } QWidget::mouseMoveEvent(event); } /*! \internal Event handler for when a mouse button is released. This is where the selection mechanism is handled. \see mousePressEvent, mouseMoveEvent */ void QCustomPlot::mouseReleaseEvent(QMouseEvent *event) { emit mouseRelease(event); mDragging = false; bool doReplot = false; if (mNoAntialiasingOnDrag) { setAntialiasedElements(mAADragBackup); setNotAntialiasedElements(mNotAADragBackup); doReplot = true; } // determine whether it was a drag or click operation: if ((mDragStart-event->pos()).manhattanLength() < 5) // was a click { // Mouse selection interaction: if ((mInteractions & (iSelectPlottables|iSelectItems|iSelectAxes|iSelectLegend|iSelectTitle)) > 0 && event->button() == Qt::LeftButton) { bool selectionFound = false; bool emitChangedSignal = false; bool additiveSelection = mInteractions.testFlag(iMultiSelect) && event->modifiers().testFlag(mMultiSelectModifier); // Mouse selection of legend: if (mInteractions.testFlag(iSelectLegend)) selectionFound |= legend->handleLegendSelection(event, additiveSelection, emitChangedSignal); // Mouse selection of plottables: if (mInteractions.testFlag(iSelectPlottables)) selectionFound |= handlePlottableSelection((!selectionFound || additiveSelection) ? event : 0, additiveSelection, emitChangedSignal); // Mouse selection of items: if (mInteractions.testFlag(iSelectItems)) selectionFound |= handleItemSelection((!selectionFound || additiveSelection) ? event : 0, additiveSelection, emitChangedSignal); // Mouse selection of axes: if (mInteractions.testFlag(iSelectAxes)) selectionFound |= handleAxisSelection((!selectionFound || additiveSelection) ? event : 0, additiveSelection, emitChangedSignal); // Mouse selection of title: if (mInteractions.testFlag(iSelectTitle)) selectionFound |= handleTitleSelection((!selectionFound || additiveSelection) ? event : 0, additiveSelection, emitChangedSignal); if (emitChangedSignal) emit selectionChangedByUser(); doReplot = true; } // emit specialized object click signals: bool foundHit = false; // for legend: if (receivers(SIGNAL(legendClick(QCPLegend*,QCPAbstractLegendItem*,QMouseEvent*))) > 0) { if (legend->selectTestLegend(event->pos())) { emit legendClick(legend, legend->selectTestItem(event->pos()), event); foundHit = true; } } // for plottables: if (!foundHit && receivers(SIGNAL(plottableClick(QCPAbstractPlottable*,QMouseEvent*))) > 0) { if (QCPAbstractPlottable *ap = plottableAt(event->pos(), false)) { emit plottableClick(ap, event); foundHit = true; } } // for items: if (!foundHit && receivers(SIGNAL(itemClick(QCPAbstractItem*,QMouseEvent*))) > 0) { if (QCPAbstractItem *ai = itemAt(event->pos(), false)) { emit itemClick(ai, event); foundHit = true; } } // for axes: if (!foundHit && receivers(SIGNAL(axisClick(QCPAxis*,QCPAxis::SelectablePart,QMouseEvent*))) > 0) { QVector axes = QVector() << xAxis << yAxis << xAxis2 << yAxis2; for (int i=0; iselectTest(event->pos()); if (part != QCPAxis::spNone) { foundHit = true; emit axisClick(axes.at(i), part, event); break; } } } // for title: if (!foundHit && receivers(SIGNAL(titleClick(QMouseEvent*))) > 0) { if (selectTestTitle(event->pos())) { emit titleClick(event); foundHit = true; } } } // was a click end if (doReplot) replot(); QWidget::mouseReleaseEvent(event); } /*! \internal Event handler for mouse wheel events. First, the mouseWheel signal is emitted. If rangeZoom is Qt::Horizontal, Qt::Vertical or both, the ranges of the axes defined as rangeZoomHorzAxis and rangeZoomVertAxis are scaled. The center of the scaling operation is the current cursor position inside the plot. The scaling factor is dependant on the mouse wheel delta (which direction the wheel was rotated) to provide a natural zooming feel. The Strength of the zoom can be controlled via \ref setRangeZoomFactor. Note, that event->delta() is usually +/-120 for single rotation steps. However, if the mouse wheel is turned rapidly, many steps may bunch up to one event, so the event->delta() may then be multiples of 120. This is taken into account here, by calculating \a wheelSteps and using it as exponent of the range zoom factor. This takes care of the wheel direction automatically, by inverting the factor, when the wheel step is negative (f^-1 = 1/f). */ void QCustomPlot::wheelEvent(QWheelEvent *event) { emit mouseWheel(event); // Mouse range zooming interaction: if (mInteractions.testFlag(iRangeZoom)) { if (mRangeZoom != 0) { double factor; double wheelSteps = event->delta()/120.0; // a single step delta is +/-120 usually if (mRangeZoom.testFlag(Qt::Horizontal)) { factor = pow(mRangeZoomFactorHorz, wheelSteps); mRangeZoomHorzAxis->scaleRange(factor, mRangeZoomHorzAxis->pixelToCoord(event->pos().x())); } if (mRangeZoom.testFlag(Qt::Vertical)) { factor = pow(mRangeZoomFactorVert, wheelSteps); mRangeZoomVertAxis->scaleRange(factor, mRangeZoomVertAxis->pixelToCoord(event->pos().y())); } replot(); } } QWidget::wheelEvent(event); } /*! \internal Handles a mouse \a event for the plottable selection interaction. Returns true, when a selectable plottable was hit by the mouse event. The output variable \a modified is set to true when the selection state of a plottable has changed. When \a additiveSelecton is true, any new selections become selected in addition to the recent selections. The recent selections are not cleared. Further, clicking on one object multiple times in additive selection mode, toggles the selection of that object on and off. To indicate that all plottables that are selectable shall be deselected, pass 0 as \a event. Unlike for axis and legend selection, this function can't be exported to the respective class itself (i.e. QCPAbstractPlottable). The function needs to know the distance of the mouse event to all plottables in the plot, in order to choose the plottable with the smallest distance. This wouldn't work if it were local to a single plottable. */ bool QCustomPlot::handlePlottableSelection(QMouseEvent *event, bool additiveSelection, bool &modified) { // Note: This code is basically identical to handleItemSelection, only for plottables bool selectionFound = false; if (event) { QCPAbstractPlottable *plottableSelection = plottableAt(event->pos(), true); // handle selection of found plottable: if (plottableSelection) { selectionFound = true; if (!plottableSelection->selected() || additiveSelection) { plottableSelection->setSelected(!plottableSelection->selected()); modified = true; } } // deselect all others (if plottableSelection is 0, all plottables are deselected): if (!additiveSelection) { for (int i=0; iselected() && mPlottables.at(i)->selectable()) { mPlottables.at(i)->setSelected(false); modified = true; } } } } else // event == 0, so deselect selectable plottables { for (int i=0; iselected() && mPlottables.at(i)->selectable()) { mPlottables.at(i)->setSelected(false); modified = true; } } } return selectionFound; } /*! \internal Handles a mouse \a event for the item selection interaction. Returns true, when a selectable item was hit by the mouse event. The output variable \a modified is set to true when the selection state of an item has changed. When \a additiveSelecton is true, any new selections become selected in addition to the recent selections. The recent selections are not cleared. Further, clicking on one object multiple times in additive selection mode, toggles the selection of that object on and off. To indicate that all items that are selectable shall be deselected, pass 0 as \a event. Unlike for axis and legend selection, this function can't be exported to the respective class itself (i.e. QCPAbstractItem). The function needs to know the distance of the mouse event to all items in the plot, in order to choose the item with the smallest distance. This wouldn't work if it were local to a single item. */ bool QCustomPlot::handleItemSelection(QMouseEvent *event, bool additiveSelection, bool &modified) { // Note: This code is basically identical to handlePlottableSelection, only for items bool selectionFound = false; if (event) { QCPAbstractItem *itemSelection = itemAt(event->pos(), true); // handle selection of found plottable: if (itemSelection) { selectionFound = true; if (!itemSelection->selected() || additiveSelection) { itemSelection->setSelected(!itemSelection->selected()); modified = true; } } // deselect all others (if itemSelection is 0, all items are deselected): if (!additiveSelection) { for (int i=0; iselected() && mItems.at(i)->selectable()) { mItems.at(i)->setSelected(false); modified = true; } } } } else // event == 0, so deselect selectable items { for (int i=0; iselected() && mItems.at(i)->selectable()) { mItems.at(i)->setSelected(false); modified = true; } } } return selectionFound; } /*! \internal Handles a mouse \a event for the axis selection interaction. Returns true, when a selectable axis part was hit by the mouse event. The output variable \a modified is set to true when the selection state of an axis has changed. When \a additiveSelecton is true, any new selections become selected in addition to the recent selections. The recent selections are not cleared. Further, clicking on one object multiple times in additive selection mode, toggles the selection of that object on and off. To indicate that all axes shall be deselected, pass 0 as \a event. */ bool QCustomPlot::handleAxisSelection(QMouseEvent *event, bool additiveSelection, bool &modified) { bool selectionFound = false; QVector axes = QVector() << xAxis << yAxis << xAxis2 << yAxis2; for (int i=0; ihandleAxisSelection((!selectionFound || additiveSelection) ? event : 0, additiveSelection, modified); return selectionFound; } /*! \internal Handles a mouse \a event for the title selection interaction. Returns true, when the title was hit by the mouse event. The output variable \a modified is set to true when the selection state of the title has changed. When \a additiveSelecton is true, any new selections become selected in addition to the recent selections. The recent selections are not cleared. Further, clicking on one object multiple times in additive selection mode, toggles the selection of that object on and off. To indicate that the title shall be deselected, pass 0 as \a event. */ bool QCustomPlot::handleTitleSelection(QMouseEvent *event, bool additiveSelection, bool &modified) { bool selectionFound = false; if (event && selectTestTitle(event->pos())) // hit, select title { selectionFound = true; if (!titleSelected() || additiveSelection) { setTitleSelected(!titleSelected()); modified = true; } } else // no hit or event == 0, deselect title { if (titleSelected() && !additiveSelection) { setTitleSelected(false); modified = true; } } return selectionFound; } /*! \internal This is the main draw function which first generates the tick vectors of all axes, calculates and applies appropriate margins if autoMargin is true and finally draws all elements with the passed \a painter. (axis background, title, subgrid, grid, axes, plottables) */ void QCustomPlot::draw(QCPPainter *painter) { // calculate title bounding box: if (!mTitle.isEmpty()) { painter->setFont(titleSelected() ? mSelectedTitleFont : mTitleFont); mTitleBoundingBox = painter->fontMetrics().boundingRect(mViewport, Qt::TextDontClip | Qt::AlignHCenter, mTitle); } else mTitleBoundingBox = QRect(); // prepare values of ticks and tick strings: xAxis->setupTickVectors(); yAxis->setupTickVectors(); xAxis2->setupTickVectors(); yAxis2->setupTickVectors(); // set auto margin such that tick/axis labels etc. are not clipped: if (mAutoMargin) { setMargin(yAxis->calculateMargin(), yAxis2->calculateMargin(), xAxis2->calculateMargin()+mTitleBoundingBox.height(), xAxis->calculateMargin()); } // position legend: legend->reArrange(); // draw axis background: drawAxisBackground(painter); // draw all layered objects (grid, axes, plottables, items, legend,...): for (int layerIndex=0; layerIndex < mLayers.size(); ++layerIndex) { QList layerChildren = mLayers.at(layerIndex)->children(); for (int k=0; k < layerChildren.size(); ++k) { QCPLayerable *child = layerChildren.at(k); if (child->visible()) { painter->save(); painter->setClipRect(child->clipRect().translated(0, -1)); child->applyDefaultAntialiasingHint(painter); child->draw(painter); painter->restore(); } } } // draw title: if (!mTitle.isEmpty()) { painter->setFont(titleSelected() ? mSelectedTitleFont : mTitleFont); painter->setPen(QPen(titleSelected() ? mSelectedTitleColor : mTitleColor)); painter->drawText(mTitleBoundingBox, Qt::TextDontClip | Qt::AlignHCenter, mTitle); } } /*! \internal If an axis background is provided via \ref setAxisBackground, this function first buffers the scaled version depending on \ref setAxisBackgroundScaled and \ref setAxisBackgroundScaledMode and then draws it inside the current axisRect with the provided \a painter. The scaled version is buffered in mScaledAxisBackground to prevent the need for rescaling at every redraw. It is only updated, when the axisRect has changed in a way that requires a rescale of the background pixmap (this is dependant on the \ref setAxisBackgroundScaledMode), or when a differend axis backgroud was set. \see draw, setAxisBackground, setAxisBackgroundScaled, setAxisBackgroundScaledMode */ void QCustomPlot::drawAxisBackground(QCPPainter *painter) { if (!mAxisBackground.isNull()) { if (mAxisBackgroundScaled) { // check whether mScaledAxisBackground needs to be updated: QSize scaledSize(mAxisBackground.size()); scaledSize.scale(mAxisRect.size(), mAxisBackgroundScaledMode); if (mScaledAxisBackground.size() != scaledSize) mScaledAxisBackground = mAxisBackground.scaled(mAxisRect.size(), mAxisBackgroundScaledMode, Qt::SmoothTransformation); painter->drawPixmap(mAxisRect.topLeft(), mScaledAxisBackground, QRect(0, 0, mAxisRect.width(), mAxisRect.height()) & mScaledAxisBackground.rect()); } else { painter->drawPixmap(mAxisRect.topLeft(), mAxisBackground, QRect(0, 0, mAxisRect.width(), mAxisRect.height())); } } } /*! \internal calculates mAxisRect by applying the margins inward to mViewport. The axisRect is then passed on to all axes via QCPAxis::setAxisRect \see setMargin, setAxisRect */ void QCustomPlot::updateAxisRect() { mAxisRect = mViewport.adjusted(mMarginLeft, mMarginTop, -mMarginRight, -mMarginBottom); xAxis->setAxisRect(mAxisRect); yAxis->setAxisRect(mAxisRect); xAxis2->setAxisRect(mAxisRect); yAxis2->setAxisRect(mAxisRect); } /*! \internal Returns whether the point \a pos in pixels hits the plot title. */ bool QCustomPlot::selectTestTitle(const QPointF &pos) const { return mTitleBoundingBox.contains(pos.toPoint()); } /*! Saves the plot to a rastered image file \a fileName in the image format \a format. The plot is sized to \a width and \a height in pixels and scaled with \a scale. (width 100 and scale 2.0 lead to a full resolution file with width 200) If the \a format supports compression, \a quality may be between 0 and 100 to control it. Returns true on success. If this function fails, most likely the given \a format isn't supported by the system, see Qt docs about QImageWriter::supportedImageFormats(). \see saveBmp, saveJpg, savePng */ bool QCustomPlot::saveRastered(const QString &fileName, int width, int height, double scale, const char *format, int quality) { int newWidth, newHeight; if (width == 0 || height == 0) { newWidth = this->width(); newHeight = this->height(); } else { newWidth = width; newHeight = height; } int scaledWidth = qRound(scale*newWidth); int scaledHeight = qRound(scale*newHeight); QPixmap pngBuffer(scaledWidth, scaledHeight); // use QPixmap instead of QImage (like live painting buffer), because it supports background transparency (of mColor). pngBuffer.fill(mColor); QCPPainter painter(&pngBuffer); QRect oldViewport = mViewport; mViewport = QRect(0, 0, newWidth, newHeight); updateAxisRect(); if (!qFuzzyCompare(scale, 1.0)) { if (scale > 1.0) // for scale < 1 we always want cosmetic pens where possible, because else lines would disappear { painter.setScaledExportMode(true); painter.setRenderHint(QPainter::NonCosmeticDefaultPen); } painter.scale(scale, scale); } draw(&painter); mViewport = oldViewport; updateAxisRect(); return pngBuffer.save(fileName, format, quality); } // ================================================================================ // =================== QCPAbstractPlottable // ================================================================================ /*! \class QCPAbstractPlottable \brief The abstract base class for all data representing objects in a plot. It defines a very basic interface like name, pen, brush, visibility etc. Since this class is abstract, it can't be instantiated. Use one of the subclasses or create a subclass yourself (see below), to create new ways of displaying data. All further specifics are in the subclasses, for example: \li A normal graph with possibly a line, scatter points and error bars is displayed by \ref QCPGraph (typically created with \ref QCustomPlot::addGraph). \li A parametric curve can be displayed with \ref QCPCurve. \li A stackable bar chart can be achieved with \ref QCPBars. \li A box of a statistical box plot is created with \ref QCPStatisticalBox. \section plottables-subclassing Creating own plottables To create an own plottable, you implement a subclass of QCPAbstractPlottable. These are the pure virtual functions, you must implement: \li \ref clearData \li \ref selectTest \li \ref draw \li \ref drawLegendIcon \li \ref getKeyRange \li \ref getValueRange See the documentation of those functions for what they need to do. For drawing your plot, you can use the \ref coordsToPixels functions to translate a point in plot coordinates to pixel coordinates. This function is quite convenient, because it takes the orientation of the key and value axes into account for you (x and y are swapped when the key axis is vertical and the value axis horizontal). If you are worried about performance (i.e. you need to translate many points in a loop like QCPGraph), you can directly use \ref QCPAxis::coordToPixel. However, you must then take care about the orientation of the axis yourself. From QCPAbstractPlottable you inherit the following members you may use:
QCustomPlot *\b mParentPlot A pointer to the parent QCustomPlot instance. This is adopted from the axes that are passed in the constructor.
QString \b mName The name of the plottable.
bool \b mVisible Whether the plot is visible or not. When this is false, you shouldn't draw the data in the \ref draw function (\ref draw is always called, no matter what mVisible is).
QPen \b mPen The generic pen of the plottable. You should use this pen for the most prominent data representing lines in the plottable (e.g QCPGraph uses this pen for its graph lines and scatters)
QPen \b mSelectedPen The generic pen that should be used when the plottable is selected (hint: \ref mainPen gives you the right pen, depending on selection state).
QBrush \b mBrush The generic brush of the plottable. You should use this brush for the most prominent fillable structures in the plottable (e.g. QCPGraph uses this brush to control filling under the graph)
QBrush \b mSelectedBrush The generic brush that should be used when the plottable is selected (hint: \ref mainBrush gives you the right brush, depending on selection state).
QCPAxis *\b mKeyAxis, *\b mValueAxis The key and value axes this plottable is attached to. Call their QCPAxis::coordToPixel functions to translate coordinates to pixels in either the key or value dimension.
bool \b mSelected indicates whether the plottable is selected or not.
*/ /* start of documentation of pure virtual functions */ /*! \fn void QCPAbstractPlottable::clearData() = 0 Clears all data in the plottable. */ /*! \fn double QCPAbstractPlottable::selectTest(const QPointF &pos) const = 0 This function is used to decide whether a click hits a plottable or not. \a pos is a point in pixel coordinates on the QCustomPlot surface. This function returns the shortest pixel distance of this point to the plottable (e.g. to the scatters/lines of a graph). If the plottable is either invisible, contains no data or the distance couldn't be determined, -1.0 is returned. \ref setSelectable has no influence on the return value of this function. If the plottable is represented not by single lines but by an area like QCPBars or QCPStatisticalBox, a click inside the area returns a constant value greater zero (typically 99% of the selectionTolerance of the parent QCustomPlot). If the click lies outside the area, this function returns -1.0. Providing a constant value for area objects allows selecting line objects even when they are obscured by such area objects, by clicking close to the lines (i.e. closer than 0.99*selectionTolerance). The actual setting of the selection state is not done by this function. This is handled by the parent QCustomPlot when the mouseReleaseEvent occurs. \see setSelected, QCustomPlot::setInteractions */ /*! \fn void QCPAbstractPlottable::draw(QCPPainter *painter) = 0 \internal Draws this plottable with the provided \a painter. Called by \ref QCustomPlot::draw on all its visible plottables. The cliprect of the provided painter is set to the axis rect of the key/value axis of this plottable (what \ref clipRect returns), before this function is called. */ /*! \fn void QCPAbstractPlottable::drawLegendIcon(QCPPainter *painter, const QRect &rect) const = 0 \internal called by QCPLegend::draw (via QCPPlottableLegendItem::draw) to create a graphical representation of this plottable inside \a rect, next to the plottable name. */ /*! \fn QCPRange QCPAbstractPlottable::getKeyRange(bool &validRange, SignDomain inSignDomain) const = 0 \internal called by rescaleAxes functions to get the full data key bounds. For logarithmic plots, one can set \a inSignDomain to either \ref sdNegative or \ref sdPositive in order to restrict the returned range to that sign domain. E.g. when only negative range is wanted, set \a inSignDomain to \ref sdNegative and all positive points will be ignored for range calculation. For no restriction, just set \a inSignDomain to \ref sdBoth (default). \a validRange is an output parameter that indicates whether a proper range could be found or not. If this is false, you shouldn't use the returned range (e.g. no points in data). \see rescaleAxes, getValueRange */ /*! \fn QCPRange QCPAbstractPlottable::getValueRange(bool &validRange, SignDomain inSignDomain) const = 0 \internal called by rescaleAxes functions to get the full data value bounds. For logarithmic plots, one can set \a inSignDomain to either \ref sdNegative or \ref sdPositive in order to restrict the returned range to that sign domain. E.g. when only negative range is wanted, set \a inSignDomain to \ref sdNegative and all positive points will be ignored for range calculation. For no restriction, just set \a inSignDomain to \ref sdBoth (default). \a validRange is an output parameter that indicates whether a proper range could be found or not. If this is false, you shouldn't use the returned range (e.g. no points in data). \see rescaleAxes, getKeyRange */ /* end of documentation of pure virtual functions */ /* start of documentation of signals */ /*! \fn void QCPAbstractPlottable::selectionChanged(bool selected) This signal is emitted when the selection state of this plottable has changed, either by user interaction or by a direct call to \ref setSelected. */ /* end of documentation of signals */ /*! Constructs an abstract plottable which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. Since QCPAbstractPlottable is an abstract class that defines the basic interface to plottables (i.e. any form of data representation inside a plot, like graphs, curves etc.), it can't be directly instantiated. You probably want one of the subclasses like \ref QCPGraph and \ref QCPCurve instead. \see setKeyAxis, setValueAxis */ QCPAbstractPlottable::QCPAbstractPlottable(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPLayerable(keyAxis->parentPlot()), mName(""), mAntialiasedFill(true), mAntialiasedScatters(true), mAntialiasedErrorBars(false), mPen(Qt::black), mSelectedPen(Qt::black), mBrush(Qt::NoBrush), mSelectedBrush(Qt::NoBrush), mKeyAxis(keyAxis), mValueAxis(valueAxis), mSelected(false), mSelectable(true) { if (keyAxis->parentPlot() != valueAxis->parentPlot()) qDebug() << Q_FUNC_INFO << "Parent plot of keyAxis is not the same as that of valueAxis."; if (keyAxis->orientation() == valueAxis->orientation()) qDebug() << Q_FUNC_INFO << "keyAxis and valueAxis must be orthogonal to each other."; } /*! The name is the textual representation of this plottable as it is displayed in the QCPLegend of the parent QCustomPlot. It may contain any utf-8 characters, including newlines. */ void QCPAbstractPlottable::setName(const QString &name) { mName = name; } /*! Sets whether fills of this plottable is drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPAbstractPlottable::setAntialiasedFill(bool enabled) { mAntialiasedFill = enabled; } /*! Sets whether the scatter symbols of this plottable are drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPAbstractPlottable::setAntialiasedScatters(bool enabled) { mAntialiasedScatters = enabled; } /*! Sets whether the error bars of this plottable are drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPAbstractPlottable::setAntialiasedErrorBars(bool enabled) { mAntialiasedErrorBars = enabled; } /*! The pen is used to draw basic lines that make up the plottable representation in the plot. For example, the \ref QCPGraph subclass draws its graph lines and scatter points with this pen. \see setBrush */ void QCPAbstractPlottable::setPen(const QPen &pen) { mPen = pen; } /*! When the plottable is selected, this pen is used to draw basic lines instead of the normal pen set via \ref setPen. \see setSelected, setSelectable, setSelectedBrush, selectTest */ void QCPAbstractPlottable::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! The brush is used to draw basic fills of the plottable representation in the plot. The Fill can be a color, gradient or texture, see the usage of QBrush. For example, the \ref QCPGraph subclass draws the fill under the graph with this brush, when it's not set to Qt::NoBrush. \see setPen */ void QCPAbstractPlottable::setBrush(const QBrush &brush) { mBrush = brush; } /*! When the plottable is selected, this brush is used to draw fills instead of the normal brush set via \ref setBrush. \see setSelected, setSelectable, setSelectedPen, selectTest */ void QCPAbstractPlottable::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /*! The key axis of a plottable can be set to any axis of a QCustomPlot, as long as it is orthogonal to the plottable's value axis. This function performs no checks to make sure this is the case. The typical mathematical choice is to use the x-axis (QCustomPlot::xAxis) as key axis and the y-axis (QCustomPlot::yAxis) as value axis. Normally, the key and value axes are set in the constructor of the plottable (or \ref QCustomPlot::addGraph when working with QCPGraphs through the dedicated graph interface). \see setValueAxis */ void QCPAbstractPlottable::setKeyAxis(QCPAxis *axis) { mKeyAxis = axis; } /*! The value axis of a plottable can be set to any axis of a QCustomPlot, as long as it is orthogonal to the plottable's key axis. This function performs no checks to make sure this is the case. The typical mathematical choice is to use the x-axis (QCustomPlot::xAxis) as key axis and the y-axis (QCustomPlot::yAxis) as value axis. Normally, the key and value axes are set in the constructor of the plottable (or \ref QCustomPlot::addGraph when working with QCPGraphs through the dedicated graph interface). \see setKeyAxis */ void QCPAbstractPlottable::setValueAxis(QCPAxis *axis) { mValueAxis = axis; } /*! Sets whether the user can (de-)select this plottable by clicking on the QCustomPlot surface. (When \ref QCustomPlot::setInteractions contains iSelectPlottables.) However, even when \a selectable was set to false, it is possible to set the selection manually, by calling \ref setSelected directly. \see setSelected */ void QCPAbstractPlottable::setSelectable(bool selectable) { mSelectable = selectable; } /*! Sets whether this plottable is selected or not. When selected, it uses a different pen and brush to draw its lines and fills, see \ref setSelectedPen and \ref setSelectedBrush. The entire selection mechanism for plottables is handled automatically when \ref QCustomPlot::setInteractions contains iSelectPlottables. You only need to call this function when you wish to change the selection state manually. This function can change the selection state even when \ref setSelectable was set to false. emits the \ref selectionChanged signal when \a selected is different from the previous selection state. \see selectTest */ void QCPAbstractPlottable::setSelected(bool selected) { if (mSelected != selected) { mSelected = selected; emit selectionChanged(mSelected); } } /*! Rescales the key and value axes associated with this plottable to contain all displayed data, so the whole plottable is visible. If the scaling of an axis is logarithmic, rescaleAxes will make sure not to rescale to an illegal range i.e. a range containing different signs and/or zero. Instead it will stay in the current sign domain and ignore all parts of the plottable that lie outside of that domain. \a onlyEnlarge makes sure the ranges are only expanded, never reduced. So it's possible to show multiple plottables in their entirety by multiple calls to rescaleAxes where the first call has \a onlyEnlarge set to false (the default), and all subsequent set to true. */ void QCPAbstractPlottable::rescaleAxes(bool onlyEnlarge) const { rescaleKeyAxis(onlyEnlarge); rescaleValueAxis(onlyEnlarge); } /*! Rescales the key axis of the plottable so the whole plottable is visible. See \ref rescaleAxes for detailed behaviour. */ void QCPAbstractPlottable::rescaleKeyAxis(bool onlyEnlarge) const { SignDomain signDomain = sdBoth; if (mKeyAxis->scaleType() == QCPAxis::stLogarithmic) signDomain = (mKeyAxis->range().upper < 0 ? sdNegative : sdPositive); bool validRange; QCPRange newRange = getKeyRange(validRange, signDomain); if (validRange) { if (onlyEnlarge) { if (mKeyAxis->range().lower < newRange.lower) newRange.lower = mKeyAxis->range().lower; if (mKeyAxis->range().upper > newRange.upper) newRange.upper = mKeyAxis->range().upper; } mKeyAxis->setRange(newRange); } } /*! Rescales the value axis of the plottable so the whole plottable is visible. See \ref rescaleAxes for detailed behaviour. */ void QCPAbstractPlottable::rescaleValueAxis(bool onlyEnlarge) const { SignDomain signDomain = sdBoth; if (mValueAxis->scaleType() == QCPAxis::stLogarithmic) signDomain = (mValueAxis->range().upper < 0 ? sdNegative : sdPositive); bool validRange; QCPRange newRange = getValueRange(validRange, signDomain); if (validRange) { if (onlyEnlarge) { if (mValueAxis->range().lower < newRange.lower) newRange.lower = mValueAxis->range().lower; if (mValueAxis->range().upper > newRange.upper) newRange.upper = mValueAxis->range().upper; } mValueAxis->setRange(newRange); } } /*! Adds this plottable to the legend of the parent QCustomPlot. Normally, a QCPPlottableLegendItem is created and inserted into the legend. If the plottable needs a more specialized representation in the plot, this function will take this into account and instead create the specialized subclass of QCPAbstractLegendItem. Returns true on success, i.e. when a legend item associated with this plottable isn't already in the legend. \see removeFromLegend, QCPLegend::addItem */ bool QCPAbstractPlottable::addToLegend() { if (!mParentPlot->legend->hasItemWithPlottable(this)) { mParentPlot->legend->addItem(new QCPPlottableLegendItem(mParentPlot->legend, this)); return true; } else return false; } /*! Removes the plottable from the legend of the parent QCustomPlot. This means the QCPAbstractLegendItem (usually a QCPPlottableLegendItem) that is associated with this plottable is removed. Returns true on success, i.e. if a legend item associated with this plottable was found and removed from the legend. \see addToLegend, QCPLegend::removeItem */ bool QCPAbstractPlottable::removeFromLegend() const { if (QCPPlottableLegendItem *lip = mParentPlot->legend->itemWithPlottable(this)) return mParentPlot->legend->removeItem(lip); else return false; } /* inherits documentation from base class */ QRect QCPAbstractPlottable::clipRect() const { return mKeyAxis->axisRect() | mValueAxis->axisRect(); } /*! \internal Convenience function for transforming a key/value pair to pixels on the QCustomPlot surface, taking the orientations of the axes associated with this plottable into account (e.g. whether key represents x or y). \a key and \a value are transformed to the coodinates in pixels and are written to \a x and \a y. \see pixelsToCoords, QCPAxis::coordToPixel */ void QCPAbstractPlottable::coordsToPixels(double key, double value, double &x, double &y) const { if (mKeyAxis->orientation() == Qt::Horizontal) { x = mKeyAxis->coordToPixel(key); y = mValueAxis->coordToPixel(value); } else { y = mKeyAxis->coordToPixel(key); x = mValueAxis->coordToPixel(value); } } /*! \internal \overload Returns the input as pixel coordinates in a QPointF. */ const QPointF QCPAbstractPlottable::coordsToPixels(double key, double value) const { if (mKeyAxis->orientation() == Qt::Horizontal) return QPointF(mKeyAxis->coordToPixel(key), mValueAxis->coordToPixel(value)); else return QPointF(mValueAxis->coordToPixel(value), mKeyAxis->coordToPixel(key)); } /*! \internal Convenience function for transforming a x/y pixel pair on the QCustomPlot surface to plot coordinates, taking the orientations of the axes associated with this plottable into account (e.g. whether key represents x or y). \a x and \a y are transformed to the plot coodinates and are written to \a key and \a value. \see coordsToPixels, QCPAxis::coordToPixel */ void QCPAbstractPlottable::pixelsToCoords(double x, double y, double &key, double &value) const { if (mKeyAxis->orientation() == Qt::Horizontal) { key = mKeyAxis->pixelToCoord(x); value = mValueAxis->pixelToCoord(y); } else { key = mKeyAxis->pixelToCoord(y); value = mValueAxis->pixelToCoord(x); } } /*! \internal \overload Returns the pixel input \a pixelPos as plot coordinates \a key and \a value. */ void QCPAbstractPlottable::pixelsToCoords(const QPointF &pixelPos, double &key, double &value) const { pixelsToCoords(pixelPos.x(), pixelPos.y(), key, value); } /*! \internal Returns the pen that should be used for drawing lines of the plottable. Returns mPen when the graph is not selected and mSelectedPen when it is. */ QPen QCPAbstractPlottable::mainPen() const { return mSelected ? mSelectedPen : mPen; } /*! \internal Returns the brush that should be used for drawing fills of the plottable. Returns mBrush when the graph is not selected and mSelectedBrush when it is. */ QBrush QCPAbstractPlottable::mainBrush() const { return mSelected ? mSelectedBrush : mBrush; } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing plottable lines. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set e.g. with \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased, applyFillAntialiasingHint, applyScattersAntialiasingHint, applyErrorBarsAntialiasingHint */ void QCPAbstractPlottable::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aePlottables); } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing plottable fills. This function takes into account the local setting of the fill antialiasing flag as well as the overrides set e.g. with \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased, applyDefaultAntialiasingHint, applyScattersAntialiasingHint, applyErrorBarsAntialiasingHint */ void QCPAbstractPlottable::applyFillAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiasedFill, QCP::aeFills); } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing plottable scatter points. This function takes into account the local setting of the scatters antialiasing flag as well as the overrides set e.g. with \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased, applyFillAntialiasingHint, applyDefaultAntialiasingHint, applyErrorBarsAntialiasingHint */ void QCPAbstractPlottable::applyScattersAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiasedScatters, QCP::aeScatters); } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing plottable error bars. This function takes into account the local setting of the error bars antialiasing flag as well as the overrides set e.g. with \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased, applyFillAntialiasingHint, applyScattersAntialiasingHint, applyDefaultAntialiasingHint */ void QCPAbstractPlottable::applyErrorBarsAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiasedErrorBars, QCP::aeErrorBars); } /*! \internal Finds the shortest squared distance of \a point to the line segment defined by \a start and \a end. This function may be used to help with the implementation of the \ref selectTest function for specific plottables. \note This function is identical to QCPAbstractItem::distSqrToLine */ double QCPAbstractPlottable::distSqrToLine(const QPointF &start, const QPointF &end, const QPointF &point) const { QVector2D a(start); QVector2D b(end); QVector2D p(point); QVector2D v(b-a); double vLengthSqr = v.lengthSquared(); if (!qFuzzyIsNull(vLengthSqr)) { double mu = QVector2D::dotProduct(p-a, v)/vLengthSqr; if (mu < 0) return (a-p).lengthSquared(); else if (mu > 1) return (b-p).lengthSquared(); else return ((a + mu*v)-p).lengthSquared(); } else return (a-p).lengthSquared(); } // ================================================================================ // =================== QCPAbstractLegendItem // ================================================================================ /*! \class QCPAbstractLegendItem \brief The abstract base class for all items in a QCPLegend. It defines a very basic interface to items in a QCPLegend. For representing plottables in the legend, the subclass QCPPlottableLegendItem is more suitable. Only derive directly from this class when you need absolute freedom (i.e. a legend item that's not associated with a plottable). You must implement the following pure virtual functions: \li \ref draw \li \ref size You inherit the following members you may use:
QCPLegend *\b mParentLegend A pointer to the parent QCPLegend.
QFont \b mFont The generic font of the item. You should use this font for all or at least the most prominent text of the item.
*/ /* start documentation of pure virtual functions */ /*! \fn void QCPAbstractLegendItem::draw(QCPPainter *painter, const QRect &rect) const = 0; Draws this legend item with \a painter inside the specified \a rect. The \a rect typically has the size which was returned from a preceding \ref size call. */ /*! \fn QSize QCPAbstractLegendItem::size(const QSize &targetSize) const = 0; Returns the size this item occupies in the legend. The legend will adapt its layout with the help of this function. If this legend item can have a variable width (e.g. auto-wrapping text), this function tries to find a size with a width close to the width of \a targetSize. The height of \a targetSize only may have meaning in specific sublasses. Typically, it's ignored. */ /* end documentation of pure virtual functions */ /* start of documentation of signals */ /*! \fn void QCPAbstractLegendItem::selectionChanged(bool selected) This signal is emitted when the selection state of this legend item has changed, either by user interaction or by a direct call to \ref setSelected. */ /* end of documentation of signals */ /*! Constructs a QCPAbstractLegendItem and associates it with the QCPLegend \a parent. This does not cause the item to be added to \a parent, so \ref QCPLegend::addItem must be called separately. */ QCPAbstractLegendItem::QCPAbstractLegendItem(QCPLegend *parent) : QObject(parent), mParentLegend(parent), mAntialiased(false), mFont(parent->font()), mTextColor(parent->textColor()), mSelectedFont(parent->selectedFont()), mSelectedTextColor(parent->selectedTextColor()), mSelectable(true), mSelected(false) { } /*! Sets whether this legend item is drawn antialiased or not. Note that this setting may be overridden by \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPAbstractLegendItem::setAntialiased(bool enabled) { mAntialiased = enabled; } /*! Sets the default font of this specific legend item to \a font. \see setTextColor, QCPLegend::setFont */ void QCPAbstractLegendItem::setFont(const QFont &font) { mFont = font; } /*! Sets the default text color of this specific legend item to \a color. \see setFont, QCPLegend::setTextColor */ void QCPAbstractLegendItem::setTextColor(const QColor &color) { mTextColor = color; } /*! When this legend item is selected, \a font is used to draw generic text, instead of the normal font set with \ref setFont. \see setFont, QCPLegend::setSelectedFont */ void QCPAbstractLegendItem::setSelectedFont(const QFont &font) { mSelectedFont = font; } /*! When this legend item is selected, \a color is used to draw generic text, instead of the normal color set with \ref setTextColor. \see setTextColor, QCPLegend::setSelectedTextColor */ void QCPAbstractLegendItem::setSelectedTextColor(const QColor &color) { mSelectedTextColor = color; } /*! Sets whether this specific legend item is selectable. \see setSelected, QCustomPlot::setInteractions */ void QCPAbstractLegendItem::setSelectable(bool selectable) { mSelectable = selectable; } /*! Sets whether this specific legend item is selected. The selection state of the parent QCPLegend is updated correspondingly. It is possible to set the selection state of this item by calling this function directly, even if setSelectable is set to false. \see setSelectable, QCustomPlot::setInteractions */ void QCPAbstractLegendItem::setSelected(bool selected) { if (mSelected != selected) { mSelected = selected; emit selectionChanged(mSelected); mParentLegend->updateSelectionState(); } } /*! \internal Sets the QPainter::Antialiasing render hint on the provided \a painter, depending on the \ref setAntialiased state of this legend item as well as the overrides \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. */ void QCPAbstractLegendItem::applyAntialiasingHint(QCPPainter *painter) const { if (mParentLegend->mParentPlot->notAntialiasedElements().testFlag(QCP::aeLegendItems)) painter->setAntialiasing(false); else if (mParentLegend->mParentPlot->antialiasedElements().testFlag(QCP::aeLegendItems)) painter->setAntialiasing(true); else painter->setAntialiasing(mAntialiased); } // ================================================================================ // =================== QCPPlottableLegendItem // ================================================================================ /*! \class QCPPlottableLegendItem \brief A legend item representing a plottable with an icon and the plottable name. This is the standard legend item for plottables. It displays an icon of the plottable next to the plottable name. The icon is drawn by the respective plottable itself (\ref QCPAbstractPlottable::drawLegendIcon), and tries to give an intuitive symbol for the plottable. For example, the QCPGraph draws a centered horizontal line with a single scatter point in the middle and filling (if enabled) below. Legend items of this type are always associated with one plottable (retrievable via the plottable() function and settable with the constructor). You may change the font of the plottable name with \ref setFont. If \ref setTextWrap is set to true, the plottable name will wrap at the right legend boundary (see \ref QCPLegend::setMinimumSize). Icon padding and border pen is taken from the parent QCPLegend, see \ref QCPLegend::setIconBorderPen and \ref QCPLegend::setIconTextPadding. The function \ref QCPAbstractPlottable::addToLegend/\ref QCPAbstractPlottable::removeFromLegend creates/removes legend items of this type in the default implementation. However, these functions may be reimplemented such that a different kind of legend item (e.g a direct subclass of QCPAbstractLegendItem) is used for that plottable. */ /*! Creates a new legend item associated with \a plottable. Once it's created, it can be added to the legend via \ref QCPLegend::addItem. A more convenient way of adding/removing a plottable to/from the legend is via the functions \ref QCPAbstractPlottable::addToLegend and \ref QCPAbstractPlottable::removeFromLegend. */ QCPPlottableLegendItem::QCPPlottableLegendItem(QCPLegend *parent, QCPAbstractPlottable *plottable) : QCPAbstractLegendItem(parent), mPlottable(plottable), mTextWrap(false) { } /*! Sets whether the text of the legend item is wrapped at word boundaries to fit the with of the legend. To prevent the legend autoSize feature (QCPLegend::setAutoSize) from compressing the text too strong by wrapping it very often, set an appropriate minimum width with QCPLegend::setMinimumSize. */ void QCPPlottableLegendItem::setTextWrap(bool wrap) { mTextWrap = wrap; } /*! \internal Returns the pen that shall be used to draw the icon border, taking into account the selection state of this item. */ QPen QCPPlottableLegendItem::getIconBorderPen() const { return mSelected ? mParentLegend->selectedIconBorderPen() : mParentLegend->iconBorderPen(); } /*! \internal Returns the text color that shall be used to draw text, taking into account the selection state of this item. */ QColor QCPPlottableLegendItem::getTextColor() const { return mSelected ? mSelectedTextColor : mTextColor; } /*! \internal Returns the font that shall be used to draw text, taking into account the selection state of this item. */ QFont QCPPlottableLegendItem::getFont() const { return mSelected ? mSelectedFont : mFont; } /*! \internal Draws the item with \a painter into \a rect. The width of the passed rect is used as text wrapping width, when \ref setTextWrap is enabled. The height is ignored. The rect is not used as a clipping rect (overpainting is not prevented inside this function), so you should set an appropriate clipping rect on the painter before calling this function. Ideally, the width of the rect should be the result of a preceding call to \ref size. */ void QCPPlottableLegendItem::draw(QCPPainter *painter, const QRect &rect) const { if (!mPlottable) return; painter->setFont(getFont()); painter->setPen(QPen(getTextColor())); int iconTextPadding = mParentLegend->iconTextPadding(); QSize iconSize = mParentLegend->iconSize(); QRect textRect; QRect iconRect(rect.topLeft(), iconSize); if (mTextWrap) { // take width from rect since our text should wrap there (only icon must fit at least): textRect = painter->fontMetrics().boundingRect(0, 0, rect.width()-iconTextPadding-iconSize.width(), rect.height(), Qt::TextDontClip | Qt::TextWordWrap, mPlottable->name()); if (textRect.height() < iconSize.height()) // text smaller than icon, center text vertically in icon height { painter->drawText(rect.x()+iconSize.width()+iconTextPadding, rect.y(), rect.width()-iconTextPadding-iconSize.width(), iconSize.height(), Qt::TextDontClip | Qt::TextWordWrap, mPlottable->name()); } else // text bigger than icon, position top of text with top of icon { painter->drawText(rect.x()+iconSize.width()+iconTextPadding, rect.y(), rect.width()-iconTextPadding-iconSize.width(), textRect.height(), Qt::TextDontClip | Qt::TextWordWrap, mPlottable->name()); } } else { // text can't wrap (except with explicit newlines), center at current item size (icon size) textRect = painter->fontMetrics().boundingRect(0, 0, 0, rect.height(), Qt::TextDontClip, mPlottable->name()); if (textRect.height() < iconSize.height()) // text smaller than icon, center text vertically in icon height { painter->drawText(rect.x()+iconSize.width()+iconTextPadding, rect.y(), rect.width(), iconSize.height(), Qt::TextDontClip, mPlottable->name()); } else // text bigger than icon, position top of text with top of icon { painter->drawText(rect.x()+iconSize.width()+iconTextPadding, rect.y(), rect.width(), textRect.height(), Qt::TextDontClip, mPlottable->name()); } } // draw icon: painter->save(); painter->setClipRect(iconRect, Qt::IntersectClip); mPlottable->drawLegendIcon(painter, iconRect); painter->restore(); // draw icon border: if (getIconBorderPen().style() != Qt::NoPen) { painter->setPen(getIconBorderPen()); painter->setBrush(Qt::NoBrush); painter->drawRect(iconRect); } } /*! \internal Calculates and returns the size of this item. If \ref setTextWrap is enabled, the width of \a targetSize will be used as the text wrapping width. This does not guarantee, that the width of the returned QSize is the same as the width of \a targetSize, since wrapping occurs only at word boundaries. So a single word that extends beyond the width of \a targetSize, will stretch the returned QSize accordingly. The height of \a targetSize is ignored. The height of the returned QSize is either the height of the icon or the height of the text bounding box, whichever is larger. */ QSize QCPPlottableLegendItem::size(const QSize &targetSize) const { if (!mPlottable) return QSize(); QSize result(0, 0); QRect textRect; QFontMetrics fontMetrics(getFont()); int iconTextPadding = mParentLegend->iconTextPadding(); QSize iconSize = mParentLegend->iconSize(); if (mTextWrap) { // take width from targetSize since our text can wrap (Only icon must fit at least): textRect = fontMetrics.boundingRect(0, 0, targetSize.width()-iconTextPadding-iconSize.width(), iconSize.height(), Qt::TextDontClip | Qt::TextWordWrap, mPlottable->name()); } else { // text can't wrap (except with explicit newlines), center at current item size (icon size) textRect = fontMetrics.boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPlottable->name()); } result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width()); result.setHeight(qMax(textRect.height(), iconSize.height())); return result; } // ================================================================================ // =================== QCPCurve // ================================================================================ /*! \class QCPCurve \brief A plottable representing a parametric curve in a plot. To plot data, assign it with the \ref setData or \ref addData functions. \section appearance Changing the appearance The appearance of the curve is determined by the pen and the brush (\ref setPen, \ref setBrush). \section usage Usage Like all data representing objects in QCustomPlot, the QCPCurve is a plottable (QCPAbstractPlottable). So the plottable-interface of QCustomPlot applies (QCustomPlot::plottable, QCustomPlot::addPlottable, QCustomPlot::removePlottable, etc.) Usually, you first create an instance: \code QCPCurve *newCurve = new QCPCurve(customPlot->xAxis, customPlot->yAxis);\endcode add it to the customPlot with QCustomPlot::addPlottable: \code customPlot->addPlottable(newCurve);\endcode and then modify the properties of the newly created plottable, e.g.: \code newCurve->setName("Fermat's Spiral"); newCurve->setData(tData, xData, yData);\endcode */ /*! Constructs a curve which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. The constructed QCPCurve can be added to the plot with QCustomPlot::addPlottable, QCustomPlot then takes ownership of the graph. */ QCPCurve::QCPCurve(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable(keyAxis, valueAxis) { mData = new QCPCurveDataMap; mPen.setColor(Qt::blue); mPen.setStyle(Qt::SolidLine); mBrush.setColor(Qt::blue); mBrush.setStyle(Qt::NoBrush); mSelectedPen = mPen; mSelectedPen.setWidthF(2.5); mSelectedPen.setColor(QColor(80, 80, 255)); // lighter than Qt::blue of mPen mSelectedBrush = mBrush; setScatterSize(6); setScatterStyle(QCP::ssNone); setLineStyle(lsLine); } QCPCurve::~QCPCurve() { delete mData; } /*! Replaces the current data with the provided \a data. If \a copy is set to true, data points in \a data will only be copied. if false, the plottable takes ownership of the passed data and replaces the internal data pointer with it. This is significantly faster than copying for large datasets. */ void QCPCurve::setData(QCPCurveDataMap *data, bool copy) { if (copy) { *mData = *data; } else { delete mData; mData = data; } } /*! \overload Replaces the current data with the provided points in \a t, \a key and \a value tuples. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. */ void QCPCurve::setData(const QVector &t, const QVector &key, const QVector &value) { mData->clear(); int n = t.size(); n = qMin(n, key.size()); n = qMin(n, value.size()); QCPCurveData newData; for (int i=0; iinsertMulti(newData.t, newData); } } /*! \overload Replaces the current data with the provided \a key and \a value pairs. The t parameter of each data point will be set to the integer index of the respective key/value pair. */ void QCPCurve::setData(const QVector &key, const QVector &value) { mData->clear(); int n = key.size(); n = qMin(n, value.size()); QCPCurveData newData; for (int i=0; iinsertMulti(newData.t, newData); } } /*! Sets the visual appearance of single data points in the plot. If set to \ref QCP::ssNone, no scatter points are drawn (e.g. for line-only-plots with appropriate line style). \see ScatterStyle, setLineStyle */ void QCPCurve::setScatterStyle(QCP::ScatterStyle style) { mScatterStyle = style; } /*! This defines how big (in pixels) single scatters are drawn, if scatter style (\ref setScatterStyle) isn't \ref QCP::ssNone, \ref QCP::ssDot or \ref QCP::ssPixmap. Floating point values are allowed for fine grained control over optical appearance with antialiased painting. \see ScatterStyle */ void QCPCurve::setScatterSize(double size) { mScatterSize = size; } /*! If the scatter style (\ref setScatterStyle) is set to ssPixmap, this function defines the QPixmap that will be drawn centered on the data point coordinate. \see ScatterStyle */ void QCPCurve::setScatterPixmap(const QPixmap &pixmap) { mScatterPixmap = pixmap; } /*! Sets how the single data points are connected in the plot or how they are represented visually apart from the scatter symbol. For scatter-only plots, set \a style to \ref lsNone and \ref setScatterStyle to the desired scatter style. \see setScatterStyle */ void QCPCurve::setLineStyle(QCPCurve::LineStyle style) { mLineStyle = style; } /*! Adds the provided data points in \a dataMap to the current data. \see removeData */ void QCPCurve::addData(const QCPCurveDataMap &dataMap) { mData->unite(dataMap); } /*! \overload Adds the provided single data point in \a data to the current data. \see removeData */ void QCPCurve::addData(const QCPCurveData &data) { mData->insertMulti(data.t, data); } /*! \overload Adds the provided single data point as \a t, \a key and \a value tuple to the current data \see removeData */ void QCPCurve::addData(double t, double key, double value) { QCPCurveData newData; newData.t = t; newData.key = key; newData.value = value; mData->insertMulti(newData.t, newData); } /*! \overload Adds the provided single data point as \a key and \a value pair to the current data The t parameter of the data point is set to the t of the last data point plus 1. If there is no last data point, t will be set to 0. \see removeData */ void QCPCurve::addData(double key, double value) { QCPCurveData newData; if (!mData->isEmpty()) newData.t = (mData->constEnd()-1).key()+1; else newData.t = 0; newData.key = key; newData.value = value; mData->insertMulti(newData.t, newData); } /*! \overload Adds the provided data points as \a t, \a key and \a value tuples to the current data. \see removeData */ void QCPCurve::addData(const QVector &ts, const QVector &keys, const QVector &values) { int n = ts.size(); n = qMin(n, keys.size()); n = qMin(n, values.size()); QCPCurveData newData; for (int i=0; iinsertMulti(newData.t, newData); } } /*! Removes all data points with curve parameter t smaller than \a t. \see addData, clearData */ void QCPCurve::removeDataBefore(double t) { QCPCurveDataMap::iterator it = mData->begin(); while (it != mData->end() && it.key() < t) it = mData->erase(it); } /*! Removes all data points with curve parameter t greater than \a t. \see addData, clearData */ void QCPCurve::removeDataAfter(double t) { if (mData->isEmpty()) return; QCPCurveDataMap::iterator it = mData->upperBound(t); while (it != mData->end()) it = mData->erase(it); } /*! Removes all data points with curve parameter t between \a fromt and \a tot. if \a fromt is greater or equal to \a tot, the function does nothing. To remove a single data point with known t, use \ref removeData(double t). \see addData, clearData */ void QCPCurve::removeData(double fromt, double tot) { if (fromt >= tot || mData->isEmpty()) return; QCPCurveDataMap::iterator it = mData->upperBound(fromt); QCPCurveDataMap::iterator itEnd = mData->upperBound(tot); while (it != itEnd) it = mData->erase(it); } /*! \overload Removes a single data point at curve parameter \a t. If the position is not known with absolute precision, consider using \ref removeData(double fromt, double tot) with a small fuzziness interval around the suspected position, depeding on the precision with which the curve parameter is known. \see addData, clearData */ void QCPCurve::removeData(double t) { mData->remove(t); } /*! Removes all data points. \see removeData, removeDataAfter, removeDataBefore */ void QCPCurve::clearData() { mData->clear(); } /* inherits documentation from base class */ double QCPCurve::selectTest(const QPointF &pos) const { if (mData->isEmpty() || !mVisible) return -1; return pointDistance(pos); } /* inherits documentation from base class */ void QCPCurve::draw(QCPPainter *painter) { if (mData->isEmpty()) return; // allocate line vector: QVector *lineData = new QVector; // fill with curve data: getCurveData(lineData); // draw curve fill: if (mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0) { applyFillAntialiasingHint(painter); painter->setPen(Qt::NoPen); painter->setBrush(mainBrush()); painter->drawPolygon(QPolygonF(*lineData)); } // draw curve line: if (mLineStyle != lsNone && mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0) { applyDefaultAntialiasingHint(painter); painter->setPen(mainPen()); painter->setBrush(Qt::NoBrush); // if drawing solid line and not in PDF, use much faster line drawing instead of polyline: if (mParentPlot->plottingHints().testFlag(QCP::phFastPolylines) && painter->pen().style() == Qt::SolidLine && !painter->pdfExportMode()) { for (int i=1; isize(); ++i) painter->drawLine(lineData->at(i-1), lineData->at(i)); } else { painter->drawPolyline(QPolygonF(*lineData)); } } // draw scatters: if (mScatterStyle != QCP::ssNone) drawScatterPlot(painter, lineData); // free allocated line data: delete lineData; } /* inherits documentation from base class */ void QCPCurve::drawLegendIcon(QCPPainter *painter, const QRect &rect) const { // draw fill: if (mBrush.style() != Qt::NoBrush) { applyFillAntialiasingHint(painter); painter->fillRect(QRectF(rect.left(), rect.top()+rect.height()/2.0, rect.width(), rect.height()/3.0), mBrush); } // draw line vertically centered: if (mLineStyle != lsNone) { applyDefaultAntialiasingHint(painter); painter->setPen(mPen); painter->drawLine(QLineF(rect.left(), rect.top()+rect.height()/2.0, rect.right()+5, rect.top()+rect.height()/2.0)); // +5 on x2 else last segment is missing from dashed/dotted pens } // draw scatter symbol: if (mScatterStyle != QCP::ssNone) { if (mScatterStyle == QCP::ssPixmap && (mScatterPixmap.size().width() > rect.width() || mScatterPixmap.size().height() > rect.height())) { // handle pixmap scatters that are larger than legend icon rect separately. // We resize them and draw them manually, instead of calling drawScatter: QSize newSize = mScatterPixmap.size(); newSize.scale(rect.size(), Qt::KeepAspectRatio); QRect targetRect; targetRect.setSize(newSize); targetRect.moveCenter(rect.center()); bool smoothBackup = painter->testRenderHint(QPainter::SmoothPixmapTransform); painter->setRenderHint(QPainter::SmoothPixmapTransform, true); painter->drawPixmap(targetRect, mScatterPixmap); painter->setRenderHint(QPainter::SmoothPixmapTransform, smoothBackup); } else { applyScattersAntialiasingHint(painter); painter->setPen(mPen); painter->drawScatter(QRectF(rect).center().x(), QRectF(rect).center().y(), mScatterSize, mScatterStyle); } } } /*! \internal Draws scatter symbols at every data point passed in \a pointData. scatter symbols are independent of the line style and are always drawn if scatter style is not \ref QCP::ssNone. */ void QCPCurve::drawScatterPlot(QCPPainter *painter, const QVector *pointData) const { // draw scatter point symbols: applyScattersAntialiasingHint(painter); painter->setPen(mainPen()); painter->setBrush(mainBrush()); painter->setScatterPixmap(mScatterPixmap); for (int i=0; isize(); ++i) painter->drawScatter(pointData->at(i).x(), pointData->at(i).y(), mScatterSize, mScatterStyle); } /*! \internal called by QCPCurve::draw to generate a point vector (pixels) which represents the line of the curve. Line segments that aren't visible in the current axis rect are handled in an optimized way. */ void QCPCurve::getCurveData(QVector *lineData) const { /* Extended sides of axis rect R divide space into 9 regions: 1__|_4_|__7 2__|_R_|__8 3 | 6 | 9 General idea: If the two points of a line segment are in the same region (that is not R), the line segment corner is removed. Curves outside R become straight lines closely outside of R which greatly reduces drawing time, yet keeps the look of lines and fills inside R consistent. The region R has index 5. */ lineData->reserve(mData->size()); QCPCurveDataMap::const_iterator it; int lastRegion = 5; int currentRegion = 5; double RLeft = mKeyAxis->range().lower; double RRight = mKeyAxis->range().upper; double RBottom = mValueAxis->range().lower; double RTop = mValueAxis->range().upper; double x, y; // current key/value bool addedLastAlready = true; bool firstPoint = true; // first point must always be drawn, to make sure fill works correctly for (it = mData->constBegin(); it != mData->constEnd(); ++it) { x = it.value().key; y = it.value().value; // determine current region: if (x < RLeft) // region 123 { if (y > RTop) currentRegion = 1; else if (y < RBottom) currentRegion = 3; else currentRegion = 2; } else if (x > RRight) // region 789 { if (y > RTop) currentRegion = 7; else if (y < RBottom) currentRegion = 9; else currentRegion = 8; } else // region 456 { if (y > RTop) currentRegion = 4; else if (y < RBottom) currentRegion = 6; else currentRegion = 5; } /* Watch out, the next part is very tricky. It modifies the curve such that it seems like the whole thing is still drawn, but actually the points outside the axisRect are simplified ("optimized") greatly. There are some subtle special cases when line segments are large and thereby each subsequent point may be in a different region or even skip some. */ // determine whether to keep current point: if (currentRegion == 5 || (firstPoint && mBrush.style() != Qt::NoBrush)) // current is in R, add current and last if it wasn't added already { if (!addedLastAlready) // in case curve just entered R, make sure the last point outside R is also drawn correctly lineData->append(coordsToPixels((it-1).value().key, (it-1).value().value)); // add last point to vector else if (lastRegion != 5) // added last already. If that's the case, we probably added it at optimized position. So go back and make sure it's at original position (else the angle changes under which this segment enters R) { if (!firstPoint) // because on firstPoint, currentRegion is 5 and addedLastAlready is true, although there is no last point lineData->replace(lineData->size()-1, coordsToPixels((it-1).value().key, (it-1).value().value)); } lineData->append(coordsToPixels(it.value().key, it.value().value)); // add current point to vector addedLastAlready = true; // so in next iteration, we don't add this point twice } else if (currentRegion != lastRegion) // changed region, add current and last if not added already { // using outsideCoordsToPixels instead of coorsToPixels for optimized point placement (places points just outside axisRect instead of potentially far away) // if we're coming from R or we skip diagonally over the corner regions (so line might still be visible in R), we can't place points optimized if (lastRegion == 5 || // coming from R ((lastRegion==2 && currentRegion==4) || (lastRegion==4 && currentRegion==2)) || // skip top left diagonal ((lastRegion==4 && currentRegion==8) || (lastRegion==8 && currentRegion==4)) || // skip top right diagonal ((lastRegion==8 && currentRegion==6) || (lastRegion==6 && currentRegion==8)) || // skip bottom right diagonal ((lastRegion==6 && currentRegion==2) || (lastRegion==2 && currentRegion==6)) // skip bottom left diagonal ) { // always add last point if not added already, original: if (!addedLastAlready) lineData->append(coordsToPixels((it-1).value().key, (it-1).value().value)); // add current point, original: lineData->append(coordsToPixels(it.value().key, it.value().value)); } else // no special case that forbids optimized point placement, so do it: { // always add last point if not added already, optimized: if (!addedLastAlready) lineData->append(outsideCoordsToPixels((it-1).value().key, (it-1).value().value, currentRegion)); // add current point, optimized: lineData->append(outsideCoordsToPixels(it.value().key, it.value().value, currentRegion)); } addedLastAlready = true; // so that if next point enters 5, or crosses another region boundary, we don't add this point twice } else // neither in R, nor crossed a region boundary, skip current point { addedLastAlready = false; } lastRegion = currentRegion; firstPoint = false; } // If curve ends outside R, we want to add very last point so the fill looks like it should when the curve started inside R: if (lastRegion != 5 && mBrush.style() != Qt::NoBrush && !mData->isEmpty()) lineData->append(coordsToPixels((mData->constEnd()-1).value().key, (mData->constEnd()-1).value().value)); } /*! \internal Calculates the (minimum) distance (in pixels) the curve's representation has from the given \a pixelPoint in pixels. This is used to determine whether the curve was clicked or not, e.g. in \ref selectTest. */ double QCPCurve::pointDistance(const QPointF &pixelPoint) const { if (mData->isEmpty()) { qDebug() << Q_FUNC_INFO << "requested point distance on curve" << mName << "without data"; return 500; } if (mData->size() == 1) { QPointF dataPoint = coordsToPixels(mData->constBegin().key(), mData->constBegin().value().value); return QVector2D(dataPoint-pixelPoint).length(); } // calculate minimum distance to line segments: QVector *lineData = new QVector; getCurveData(lineData); double minDistSqr = std::numeric_limits::max(); for (int i=0; isize()-1; ++i) { double currentDistSqr = distSqrToLine(lineData->at(i), lineData->at(i+1), pixelPoint); if (currentDistSqr < minDistSqr) minDistSqr = currentDistSqr; } delete lineData; return sqrt(minDistSqr); } /*! \internal This is a specialized \ref coordsToPixels function for points that are outside the visible axisRect and just crossing a boundary (since \ref getCurveData reduces non-visible curve segments to those line segments that cross region boundaries, see documentation there). It only uses the coordinate parallel to the region boundary of the axisRect. The other coordinate is picked 10 pixels outside the axisRect. Together with the optimization in \ref getCurveData this improves performance for large curves (or zoomed in ones) significantly while keeping the illusion the whole curve and its filling is still being drawn for the viewer. */ QPointF QCPCurve::outsideCoordsToPixels(double key, double value, int region) const { int margin = 10; QRect axisRect = mKeyAxis->axisRect() | mValueAxis->axisRect(); QPointF result = coordsToPixels(key, value); switch (region) { case 2: result.setX(axisRect.left()-margin); break; // left case 8: result.setX(axisRect.right()+margin); break; // right case 4: result.setY(axisRect.top()-margin); break; // top case 6: result.setY(axisRect.bottom()+margin); break; // bottom case 1: result.setX(axisRect.left()-margin); result.setY(axisRect.top()-margin); break; // top left case 7: result.setX(axisRect.right()+margin); result.setY(axisRect.top()-margin); break; // top right case 9: result.setX(axisRect.right()+margin); result.setY(axisRect.bottom()+margin); break; // bottom right case 3: result.setX(axisRect.left()-margin); result.setY(axisRect.bottom()+margin); break; // bottom left } return result; } /* inherits documentation from base class */ QCPRange QCPCurve::getKeyRange(bool &validRange, SignDomain inSignDomain) const { QCPRange range; bool haveLower = false; bool haveUpper = false; double current; QCPCurveDataMap::const_iterator it = mData->constBegin(); while (it != mData->constEnd()) { current = it.value().key; if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0)) { if (current < range.lower || !haveLower) { range.lower = current; haveLower = true; } if (current > range.upper || !haveUpper) { range.upper = current; haveUpper = true; } } ++it; } validRange = haveLower && haveUpper; return range; } /* inherits documentation from base class */ QCPRange QCPCurve::getValueRange(bool &validRange, SignDomain inSignDomain) const { QCPRange range; bool haveLower = false; bool haveUpper = false; double current; QCPCurveDataMap::const_iterator it = mData->constBegin(); while (it != mData->constEnd()) { current = it.value().value; if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0)) { if (current < range.lower || !haveLower) { range.lower = current; haveLower = true; } if (current > range.upper || !haveUpper) { range.upper = current; haveUpper = true; } } ++it; } validRange = haveLower && haveUpper; return range; } // ================================================================================ // =================== QCPBars // ================================================================================ /*! \class QCPBars \brief A plottable representing a bar chart in a plot. To plot data, assign it with the \ref setData or \ref addData functions. \section appearance Changing the appearance The appearance of the bars is determined by the pen and the brush (\ref setPen, \ref setBrush). Bar charts are stackable. This means, Two QCPBars plottables can be placed on top of each other (see \ref QCPBars::moveAbove). Then, when two bars are at the same key position, they will appear stacked. \section usage Usage Like all data representing objects in QCustomPlot, the QCPBars is a plottable (QCPAbstractPlottable). So the plottable-interface of QCustomPlot applies (QCustomPlot::plottable, QCustomPlot::addPlottable, QCustomPlot::removePlottable, etc.) Usually, you first create an instance: \code QCPBars *newBars = new QCPBars(customPlot->xAxis, customPlot->yAxis);\endcode add it to the customPlot with QCustomPlot::addPlottable: \code customPlot->addPlottable(newBars);\endcode and then modify the properties of the newly created plottable, e.g.: \code newBars->setName("Country population"); newBars->setData(xData, yData);\endcode */ /*! \fn QCPBars *QCPBars::barBelow() const Returns the bars plottable that is directly below this bars plottable. If there is no such plottable, returns 0. \see barAbove, moveBelow, moveAbove */ /*! \fn QCPBars *QCPBars::barAbove() const Returns the bars plottable that is directly above this bars plottable. If there is no such plottable, returns 0. \see barBelow, moveBelow, moveAbove */ /*! Constructs a bar chart which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. The constructed QCPBars can be added to the plot with QCustomPlot::addPlottable, QCustomPlot then takes ownership of the bar chart. */ QCPBars::QCPBars(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable(keyAxis, valueAxis), mBarBelow(0), mBarAbove(0) { mData = new QCPBarDataMap; mPen.setColor(Qt::blue); mPen.setStyle(Qt::SolidLine); mBrush.setColor(QColor(40, 50, 255, 30)); mBrush.setStyle(Qt::SolidPattern); mSelectedPen = mPen; mSelectedPen.setWidthF(2.5); mSelectedPen.setColor(QColor(80, 80, 255)); // lighter than Qt::blue of mPen mSelectedBrush = mBrush; mWidth = 0.75; } QCPBars::~QCPBars() { if (mBarBelow || mBarAbove) connectBars(mBarBelow, mBarAbove); // take this bar out of any stacking delete mData; } /*! Sets the width of the bars in plot (key) coordinates. */ void QCPBars::setWidth(double width) { mWidth = width; } /*! Replaces the current data with the provided \a data. If \a copy is set to true, data points in \a data will only be copied. if false, the plottable takes ownership of the passed data and replaces the internal data pointer with it. This is significantly faster than copying for large datasets. */ void QCPBars::setData(QCPBarDataMap *data, bool copy) { if (copy) { *mData = *data; } else { delete mData; mData = data; } } /*! \overload Replaces the current data with the provided points in \a key and \a value tuples. The provided vectors should have equal length. Else, the number of added points will be the size of the smallest vector. */ void QCPBars::setData(const QVector &key, const QVector &value) { mData->clear(); int n = key.size(); n = qMin(n, value.size()); QCPBarData newData; for (int i=0; iinsertMulti(newData.key, newData); } } /*! Moves this bars plottable below \a bars. In other words, the bars of this plottable will appear below the bars of \a bars. The move target \a bars must use the same key and value axis as this plottable. Inserting into and removing from existing bar stacking is handled gracefully. If \a bars already has a bars object below itself, this bars object is inserted between the two. If this bars object is already between two other bars, the two other bars will be stacked on top of each other after the operation. To remove this bars plottable from any stacking, set \a bars to 0. \see moveBelow, barAbove, barBelow */ void QCPBars::moveBelow(QCPBars *bars) { if (bars == this) return; if (bars->keyAxis() != mKeyAxis || bars->valueAxis() != mValueAxis) { qDebug() << Q_FUNC_INFO << "passed QCPBars* doesn't have same key and value axis as this QCPBars"; return; } // remove from stacking: connectBars(mBarBelow, mBarAbove); // Note: also works if one (or both) of them is 0 // if new bar given, insert this bar below it: if (bars) { if (bars->mBarBelow) connectBars(bars->mBarBelow, this); connectBars(this, bars); } } /*! Moves this bars plottable above \a bars. In other words, the bars of this plottable will appear above the bars of \a bars. The move target \a bars must use the same key and value axis as this plottable. Inserting into and removing from existing bar stacking is handled gracefully. If \a bars already has a bars object below itself, this bars object is inserted between the two. If this bars object is already between two other bars, the two other bars will be stacked on top of each other after the operation. To remove this bars plottable from any stacking, set \a bars to 0. \see moveBelow, barBelow, barAbove */ void QCPBars::moveAbove(QCPBars *bars) { if (bars == this) return; if (bars && (bars->keyAxis() != mKeyAxis || bars->valueAxis() != mValueAxis)) { qDebug() << Q_FUNC_INFO << "passed QCPBars* doesn't have same key and value axis as this QCPBars"; return; } // remove from stacking: connectBars(mBarBelow, mBarAbove); // Note: also works if one (or both) of them is 0 // if new bar given, insert this bar above it: if (bars) { if (bars->mBarAbove) connectBars(this, bars->mBarAbove); connectBars(bars, this); } } /*! Adds the provided data points in \a dataMap to the current data. \see removeData */ void QCPBars::addData(const QCPBarDataMap &dataMap) { mData->unite(dataMap); } /*! \overload Adds the provided single data point in \a data to the current data. \see removeData */ void QCPBars::addData(const QCPBarData &data) { mData->insertMulti(data.key, data); } /*! \overload Adds the provided single data point as \a key and \a value tuple to the current data \see removeData */ void QCPBars::addData(double key, double value) { QCPBarData newData; newData.key = key; newData.value = value; mData->insertMulti(newData.key, newData); } /*! \overload Adds the provided data points as \a key and \a value tuples to the current data. \see removeData */ void QCPBars::addData(const QVector &keys, const QVector &values) { int n = keys.size(); n = qMin(n, values.size()); QCPBarData newData; for (int i=0; iinsertMulti(newData.key, newData); } } /*! Removes all data points with key smaller than \a key. \see addData, clearData */ void QCPBars::removeDataBefore(double key) { QCPBarDataMap::iterator it = mData->begin(); while (it != mData->end() && it.key() < key) it = mData->erase(it); } /*! Removes all data points with key greater than \a key. \see addData, clearData */ void QCPBars::removeDataAfter(double key) { if (mData->isEmpty()) return; QCPBarDataMap::iterator it = mData->upperBound(key); while (it != mData->end()) it = mData->erase(it); } /*! Removes all data points with key between \a fromKey and \a toKey. if \a fromKey is greater or equal to \a toKey, the function does nothing. To remove a single data point with known key, use \ref removeData(double key). \see addData, clearData */ void QCPBars::removeData(double fromKey, double toKey) { if (fromKey >= toKey || mData->isEmpty()) return; QCPBarDataMap::iterator it = mData->upperBound(fromKey); QCPBarDataMap::iterator itEnd = mData->upperBound(toKey); while (it != itEnd) it = mData->erase(it); } /*! \overload Removes a single data point at \a key. If the position is not known with absolute precision, consider using \ref removeData(double fromKey, double toKey) with a small fuzziness interval around the suspected position, depeding on the precision with which the key is known. \see addData, clearData */ void QCPBars::removeData(double key) { mData->remove(key); } /*! Removes all data points. \see removeData, removeDataAfter, removeDataBefore */ void QCPBars::clearData() { mData->clear(); } /* inherits documentation from base class */ double QCPBars::selectTest(const QPointF &pos) const { QCPBarDataMap::ConstIterator it; double posKey, posValue; pixelsToCoords(pos, posKey, posValue); for (it = mData->constBegin(); it != mData->constEnd(); ++it) { double baseValue = getBaseValue(it.key(), it.value().value >=0); QCPRange keyRange(it.key()-mWidth*0.5, it.key()+mWidth*0.5); QCPRange valueRange(baseValue, baseValue+it.value().value); if (keyRange.contains(posKey) && valueRange.contains(posValue)) return mParentPlot->selectionTolerance()*0.99; } return -1; } /* inherits documentation from base class */ void QCPBars::draw(QCPPainter *painter) { if (mData->isEmpty()) return; QCPBarDataMap::const_iterator it; for (it = mData->constBegin(); it != mData->constEnd(); ++it) { if (it.key()+mWidth*0.5 < mKeyAxis->range().lower || it.key()-mWidth*0.5 > mKeyAxis->range().upper) continue; QPolygonF barPolygon = getBarPolygon(it.key(), it.value().value); // draw bar fill: if (mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0) { applyFillAntialiasingHint(painter); painter->setPen(Qt::NoPen); painter->setBrush(mainBrush()); painter->drawPolygon(barPolygon); } // draw bar line: if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0) { applyDefaultAntialiasingHint(painter); painter->setPen(mainPen()); painter->setBrush(Qt::NoBrush); painter->drawPolyline(barPolygon); } } } /* inherits documentation from base class */ void QCPBars::drawLegendIcon(QCPPainter *painter, const QRect &rect) const { // draw filled rect: applyDefaultAntialiasingHint(painter); painter->setBrush(mBrush); painter->setPen(mPen); QRectF r = QRectF(0, 0, rect.width()*0.67, rect.height()*0.67); r.moveCenter(rect.center()); painter->drawRect(r); } /*! \internal Returns the polygon of a single bar with \a key and \a value. The Polygon is open at the bottom and shifted according to the bar stacking (see \ref moveAbove). */ QPolygonF QCPBars::getBarPolygon(double key, double value) const { QPolygonF result; double baseValue = getBaseValue(key, value >= 0); result << coordsToPixels(key-mWidth*0.5, baseValue); result << coordsToPixels(key-mWidth*0.5, baseValue+value); result << coordsToPixels(key+mWidth*0.5, baseValue+value); result << coordsToPixels(key+mWidth*0.5, baseValue); return result; } /*! \internal This function is called to find at which value to start drawing the base of a bar at \a key, when it is stacked on top of another QCPBars (e.g. with \ref moveAbove). positive and negative bars are separated per stack (positive are stacked above 0-value upwards, negative are stacked below 0-value downwards). This can be indicated with \a positive. So if the bar for which we need the base value is negative, set \a positive to false. */ double QCPBars::getBaseValue(double key, bool positive) const { if (mBarBelow) { double max = 0; // find bars of mBarBelow that are approximately at key and find largest one: QCPBarDataMap::const_iterator it = mBarBelow->mData->lowerBound(key-mWidth*0.1); QCPBarDataMap::const_iterator itEnd = mBarBelow->mData->upperBound(key+mWidth*0.1); while (it != itEnd) { if ((positive && it.value().value > max) || (!positive && it.value().value < max)) max = it.value().value; ++it; } // recurse down the bar-stack to find the total height: return max + mBarBelow->getBaseValue(key, positive); } else return 0; } /*! \internal Connects \a below and \a above to each other via their mBarAbove/mBarBelow properties. The bar(s) currently below lower and upper will become disconnected to lower/upper. If lower is zero, upper will be disconnected at the bottom. If upper is zero, lower will be disconnected at the top. */ void QCPBars::connectBars(QCPBars *lower, QCPBars *upper) { if (!lower && !upper) return; if (!lower) // disconnect upper at bottom { // disconnect old bar below upper: if (upper->mBarBelow && upper->mBarBelow->mBarAbove == upper) upper->mBarBelow->mBarAbove = 0; upper->mBarBelow = 0; } else if (!upper) // disconnect lower at top { // disconnect old bar above lower: if (lower->mBarAbove && lower->mBarAbove->mBarBelow == lower) lower->mBarAbove->mBarBelow = 0; lower->mBarAbove = 0; } else // connect lower and upper { // disconnect old bar above lower: if (lower->mBarAbove && lower->mBarAbove->mBarBelow == lower) lower->mBarAbove->mBarBelow = 0; // disconnect old bar below upper: if (upper->mBarBelow && upper->mBarBelow->mBarAbove == upper) upper->mBarBelow->mBarAbove = 0; lower->mBarAbove = upper; upper->mBarBelow = lower; } } /* inherits documentation from base class */ QCPRange QCPBars::getKeyRange(bool &validRange, SignDomain inSignDomain) const { QCPRange range; bool haveLower = false; bool haveUpper = false; double current; double barWidthHalf = mWidth*0.5; QCPBarDataMap::const_iterator it = mData->constBegin(); while (it != mData->constEnd()) { current = it.value().key; if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current+barWidthHalf < 0) || (inSignDomain == sdPositive && current-barWidthHalf > 0)) { if (current-barWidthHalf < range.lower || !haveLower) { range.lower = current-barWidthHalf; haveLower = true; } if (current+barWidthHalf > range.upper || !haveUpper) { range.upper = current+barWidthHalf; haveUpper = true; } } ++it; } validRange = haveLower && haveUpper; return range; } /* inherits documentation from base class */ QCPRange QCPBars::getValueRange(bool &validRange, SignDomain inSignDomain) const { QCPRange range; bool haveLower = true; // set to true, because 0 should always be visible in bar charts bool haveUpper = true; // set to true, because 0 should always be visible in bar charts double current; QCPBarDataMap::const_iterator it = mData->constBegin(); while (it != mData->constEnd()) { current = it.value().value + getBaseValue(it.value().key, it.value().value >= 0); if (inSignDomain == sdBoth || (inSignDomain == sdNegative && current < 0) || (inSignDomain == sdPositive && current > 0)) { if (current < range.lower || !haveLower) { range.lower = current; haveLower = true; } if (current > range.upper || !haveUpper) { range.upper = current; haveUpper = true; } } ++it; } validRange = range.lower < range.upper; return range; } // ================================================================================ // =================== QCPStatisticalBox // ================================================================================ /*! \class QCPStatisticalBox \brief A plottable representing a single statistical box in a plot. To plot data, assign it with the individual parameter functions or use \ref setData to set all parameters at once. The individual funcions are: \li \ref setMinimum \li \ref setLowerQuartile \li \ref setMedian \li \ref setUpperQuartile \li \ref setMaximum Additionally you can define a list of outliers, drawn as circle datapoints: \li \ref setOutliers \section appearance Changing the appearance The appearance of the box itself is controlled via \ref setPen and \ref setBrush. You may change the width of the box with \ref setWidth in plot coordinates (not pixels). Analog functions exist for the minimum/maximum-whiskers: \ref setWhiskerPen, \ref setWhiskerBarPen, \ref setWhiskerWidth. The whisker width is the width of the bar at the top (maximum) or bottom (minimum). The median indicator line has its own pen, \ref setMedianPen. If the pens are changed, especially the whisker pen, make sure to set the capStyle to Qt::FlatCap. Else, e.g. the whisker line might exceed the bar line by a few pixels due to the pen cap being not perfectly flat. The Outlier data points are drawn normal scatter points. Their look can be controlled with \ref setOutlierStyle and \ref setOutlierPen. The size (diameter) can be set with \ref setOutlierSize in pixels. \section usage Usage Like all data representing objects in QCustomPlot, the QCPStatisticalBox is a plottable (QCPAbstractPlottable). So the plottable-interface of QCustomPlot applies (QCustomPlot::plottable, QCustomPlot::addPlottable, QCustomPlot::removePlottable, etc.) Usually, you first create an instance: \code QCPStatisticalBox *newBox = new QCPStatisticalBox(customPlot->xAxis, customPlot->yAxis);\endcode add it to the customPlot with QCustomPlot::addPlottable: \code customPlot->addPlottable(newBox);\endcode and then modify the properties of the newly created plottable, e.g.: \code newBox->setName("Measurement Series 1"); newBox->setData(1, 3, 4, 5, 7); newBox->setOutliers(QVector() << 0.5 << 0.64 << 7.2 << 7.42);\endcode */ /*! Constructs a statistical box which uses \a keyAxis as its key axis ("x") and \a valueAxis as its value axis ("y"). \a keyAxis and \a valueAxis must reside in the same QCustomPlot instance and not have the same orientation. If either of these restrictions is violated, a corresponding message is printed to the debug output (qDebug), the construction is not aborted, though. The constructed statistical box can be added to the plot with QCustomPlot::addPlottable, QCustomPlot then takes ownership of the statistical box. */ QCPStatisticalBox::QCPStatisticalBox(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPAbstractPlottable(keyAxis, valueAxis), mKey(0), mMinimum(0), mLowerQuartile(0), mMedian(0), mUpperQuartile(0), mMaximum(0) { setOutlierStyle(QCP::ssCircle); setOutlierSize(5); setWhiskerWidth(0.2); setWidth(0.5); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue, 2.5)); setMedianPen(QPen(Qt::black, 3, Qt::SolidLine, Qt::FlatCap)); setWhiskerPen(QPen(Qt::black, 0, Qt::DashLine, Qt::FlatCap)); setWhiskerBarPen(QPen(Qt::black)); setOutlierPen(QPen(Qt::blue)); setBrush(Qt::NoBrush); setSelectedBrush(Qt::NoBrush); } QCPStatisticalBox::~QCPStatisticalBox() { } /*! Sets the key coordinate of the statistical box. */ void QCPStatisticalBox::setKey(double key) { mKey = key; } /*! Sets the parameter "minimum" of the statistical box plot. This is the position of the lower whisker, typically the minimum measurement of the sample that's not considered an outlier. \see setMaximum, setWhiskerPen, setWhiskerBarPen, setWhiskerWidth */ void QCPStatisticalBox::setMinimum(double value) { mMinimum = value; } /*! Sets the parameter "lower Quartile" of the statistical box plot. This is the lower end of the box. The lower and the upper quartiles are the two statistical quartiles around the median of the sample, they contain 50% of the sample data. \see setUpperQuartile, setPen, setBrush, setWidth */ void QCPStatisticalBox::setLowerQuartile(double value) { mLowerQuartile = value; } /*! Sets the parameter "median" of the statistical box plot. This is the value of the median mark inside the quartile box. The median separates the sample data in half (50% of the sample data is below/above the median). \see setMedianPen */ void QCPStatisticalBox::setMedian(double value) { mMedian = value; } /*! Sets the parameter "upper Quartile" of the statistical box plot. This is the upper end of the box. The lower and the upper quartiles are the two statistical quartiles around the median of the sample, they contain 50% of the sample data. \see setLowerQuartile, setPen, setBrush, setWidth */ void QCPStatisticalBox::setUpperQuartile(double value) { mUpperQuartile = value; } /*! Sets the parameter "maximum" of the statistical box plot. This is the position of the upper whisker, typically the maximum measurement of the sample that's not considered an outlier. \see setMinimum, setWhiskerPen, setWhiskerBarPen, setWhiskerWidth */ void QCPStatisticalBox::setMaximum(double value) { mMaximum = value; } /*! Sets a vector of outlier values that will be drawn as circles. Any data points in the sample that are not within the whiskers (\ref setMinimum, \ref setMaximum) should be considered outliers and displayed as such. \see setOutlierPen, setOutlierBrush, setOutlierSize */ void QCPStatisticalBox::setOutliers(const QVector &values) { mOutliers = values; } /*! Sets all parameters of the statistical box plot at once. \see setKey, setMinimum, setLowerQuartile, setMedian, setUpperQuartile, setMaximum */ void QCPStatisticalBox::setData(double key, double minimum, double lowerQuartile, double median, double upperQuartile, double maximum) { setKey(key); setMinimum(minimum); setLowerQuartile(lowerQuartile); setMedian(median); setUpperQuartile(upperQuartile); setMaximum(maximum); } /*! Sets the width of the box in key coordinates. \see setWhiskerWidth */ void QCPStatisticalBox::setWidth(double width) { mWidth = width; } /*! Sets the width of the whiskers (\ref setMinimum, \ref setMaximum) in key coordinates. \see setWidth */ void QCPStatisticalBox::setWhiskerWidth(double width) { mWhiskerWidth = width; } /*! Sets the pen used for drawing the whisker backbone (That's the line parallel to the value axis). Make sure to set the \a pen capStyle to Qt::FlatCap to prevent the backbone from reaching a few pixels past the bars, when using a non-zero pen width. \see setWhiskerBarPen */ void QCPStatisticalBox::setWhiskerPen(const QPen &pen) { mWhiskerPen = pen; } /*! Sets the pen used for drawing the whisker bars (Those are the lines parallel to the key axis at each end of the backbone). \see setWhiskerPen */ void QCPStatisticalBox::setWhiskerBarPen(const QPen &pen) { mWhiskerBarPen = pen; } /*! Sets the pen used for drawing the median indicator line inside the statistical box. Make sure to set the \a pen capStyle to Qt::FlatCap to prevent the median line from reaching a few pixels outside the box, when using a non-zero pen width. */ void QCPStatisticalBox::setMedianPen(const QPen &pen) { mMedianPen = pen; } /*! Sets the pixel size of the scatter symbols that represent the outlier data points. \see setOutlierPen, setOutliers */ void QCPStatisticalBox::setOutlierSize(double pixels) { mOutlierSize = pixels; } /*! Sets the pen used to draw the outlier data points. \see setOutlierSize, setOutliers */ void QCPStatisticalBox::setOutlierPen(const QPen &pen) { mOutlierPen = pen; } /*! Sets the scatter style of the outlier data points. \see setOutlierSize, setOutlierPen, setOutliers */ void QCPStatisticalBox::setOutlierStyle(QCP::ScatterStyle style) { mOutlierStyle = style; } /* inherits documentation from base class */ void QCPStatisticalBox::clearData() { setOutliers(QVector()); setKey(0); setMinimum(0); setLowerQuartile(0); setMedian(0); setUpperQuartile(0); setMaximum(0); } /* inherits documentation from base class */ double QCPStatisticalBox::selectTest(const QPointF &pos) const { double posKey, posValue; pixelsToCoords(pos, posKey, posValue); // quartile box: QCPRange keyRange(mKey-mWidth*0.5, mKey+mWidth*0.5); QCPRange valueRange(mLowerQuartile, mUpperQuartile); if (keyRange.contains(posKey) && valueRange.contains(posValue)) return mParentPlot->selectionTolerance()*0.99; // min/max whiskers: if (QCPRange(mMinimum, mMaximum).contains(posValue)) return qAbs(mKeyAxis->coordToPixel(mKey)-mKeyAxis->coordToPixel(posKey)); return -1; } /* inherits documentation from base class */ void QCPStatisticalBox::draw(QCPPainter *painter) { QRectF quartileBox; drawQuartileBox(painter, &quartileBox); painter->save(); painter->setClipRect(quartileBox, Qt::IntersectClip); drawMedian(painter); painter->restore(); drawWhiskers(painter); drawOutliers(painter); } /* inherits documentation from base class */ void QCPStatisticalBox::drawLegendIcon(QCPPainter *painter, const QRect &rect) const { // draw filled rect: applyDefaultAntialiasingHint(painter); painter->setPen(mPen); painter->setBrush(mBrush); QRectF r = QRectF(0, 0, rect.width()*0.67, rect.height()*0.67); r.moveCenter(rect.center()); painter->drawRect(r); } /*! \internal Draws the quartile box. \a box is an output parameter that returns the quartile box (in pixel coordinates) which is used to set the clip rect of the painter before calling \ref drawMedian (so the median doesn't draw outside the quartile box). */ void QCPStatisticalBox::drawQuartileBox(QCPPainter *painter, QRectF *quartileBox) const { QRectF box; box.setTopLeft(coordsToPixels(mKey-mWidth*0.5, mUpperQuartile)); box.setBottomRight(coordsToPixels(mKey+mWidth*0.5, mLowerQuartile)); applyDefaultAntialiasingHint(painter); painter->setPen(mainPen()); painter->setBrush(mainBrush()); painter->drawRect(box); if (quartileBox) *quartileBox = box; } /*! \internal Draws the median line inside the quartile box. */ void QCPStatisticalBox::drawMedian(QCPPainter *painter) const { QLineF medianLine; medianLine.setP1(coordsToPixels(mKey-mWidth*0.5, mMedian)); medianLine.setP2(coordsToPixels(mKey+mWidth*0.5, mMedian)); applyDefaultAntialiasingHint(painter); painter->setPen(mMedianPen); painter->drawLine(medianLine); } /*! \internal Draws both whisker backbones and bars. */ void QCPStatisticalBox::drawWhiskers(QCPPainter *painter) const { QLineF backboneMin, backboneMax, barMin, barMax; backboneMax.setPoints(coordsToPixels(mKey, mUpperQuartile), coordsToPixels(mKey, mMaximum)); backboneMin.setPoints(coordsToPixels(mKey, mLowerQuartile), coordsToPixels(mKey, mMinimum)); barMax.setPoints(coordsToPixels(mKey-mWhiskerWidth*0.5, mMaximum), coordsToPixels(mKey+mWhiskerWidth*0.5, mMaximum)); barMin.setPoints(coordsToPixels(mKey-mWhiskerWidth*0.5, mMinimum), coordsToPixels(mKey+mWhiskerWidth*0.5, mMinimum)); applyErrorBarsAntialiasingHint(painter); painter->setPen(mWhiskerPen); painter->drawLine(backboneMin); painter->drawLine(backboneMax); painter->setPen(mWhiskerBarPen); painter->drawLine(barMin); painter->drawLine(barMax); } /*! \internal Draws the outlier circles. */ void QCPStatisticalBox::drawOutliers(QCPPainter *painter) const { applyScattersAntialiasingHint(painter); painter->setPen(mOutlierPen); painter->setBrush(Qt::NoBrush); for (int i=0; idrawScatter(dataPoint.x(), dataPoint.y(), mOutlierSize, mOutlierStyle); } } /* inherits documentation from base class */ QCPRange QCPStatisticalBox::getKeyRange(bool &validRange, SignDomain inSignDomain) const { validRange = mWidth > 0; if (inSignDomain == sdBoth) { return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5); } else if (inSignDomain == sdNegative) { if (mKey+mWidth*0.5 < 0) return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5); else if (mKey < 0) return QCPRange(mKey-mWidth*0.5, mKey); else { validRange = false; return QCPRange(); } } else if (inSignDomain == sdPositive) { if (mKey-mWidth*0.5 > 0) return QCPRange(mKey-mWidth*0.5, mKey+mWidth*0.5); else if (mKey > 0) return QCPRange(mKey, mKey+mWidth*0.5); else { validRange = false; return QCPRange(); } } validRange = false; return QCPRange(); } /* inherits documentation from base class */ QCPRange QCPStatisticalBox::getValueRange(bool &validRange, SignDomain inSignDomain) const { if (inSignDomain == sdBoth) { double lower = qMin(mMinimum, qMin(mMedian, mLowerQuartile)); double upper = qMax(mMaximum, qMax(mMedian, mUpperQuartile)); for (int i=0; i upper) upper = mOutliers.at(i); } validRange = upper > lower; return QCPRange(lower, upper); } else { QVector values; // values that must be considered (i.e. all outliers and the five box-parameters) values.reserve(mOutliers.size() + 5); values << mMaximum << mUpperQuartile << mMedian << mLowerQuartile << mMinimum; values << mOutliers; // go through values and find the ones in legal range: bool haveUpper = false; bool haveLower = false; double upper = 0; double lower = 0; for (int i=0; i 0)) { if (values.at(i) > upper || !haveUpper) { upper = values.at(i); haveUpper = true; } if (values.at(i) < lower || !haveLower) { lower = values.at(i); haveLower = true; } } } // return the bounds if we found some sensible values: if (haveLower && haveUpper && lower < upper) { validRange = true; return QCPRange(lower, upper); } else { validRange = false; return QCPRange(); } } } // ================================================================================ // =================== QCPAbstractItem // ================================================================================ /*! \class QCPAbstractItem \brief The abstract base class for all items in a plot. In QCustomPlot, items are supplemental graphical elements that are neither plottables (QCPAbstractPlottable) nor axes (QCPAxis). While plottables are always tied to two axes and thus plot coordinates, items can also be placed in absolute coordinates independent of any axes. Each specific item has at least one QCPItemPosition member which controls the positioning. Some items are defined by more than one coordinate and thus have two or more QCPItemPosition members (For example, QCPItemRect has \a topLeft and \a bottomRight). This abstract base class defines a very basic interface like visibility and clipping. Since this class is abstract, it can't be instantiated. Use one of the subclasses or create a subclass yourself to create new items. The built-in items are:
QCPItemLineA line defined by a start and an end point. May have different ending styles on each side (e.g. arrows).
QCPItemStraightLineA straight line defined by a start and a direction point. Unlike QCPItemLine, the straight line is infinitely long and has no endings.
QCPItemCurveA curve defined by start, end and two intermediate control points. May have different ending styles on each side (e.g. arrows).
QCPItemRectA rectangle
QCPItemEllipseAn ellipse
QCPItemPixmapAn arbitrary pixmap
QCPItemTextA text label
QCPItemBracketA bracket which may be used to reference/highlight certain parts in the plot.
QCPItemTracerAn item that can be attached to a QCPGraph and sticks to its data points, given a key coordinate.
\section items-using Using items First you instantiate the item you want to use and add it to the plot: \code QCPItemLine *line = new QCPItemLine(customPlot); customPlot->addItem(line); \endcode by default, the positions of the item are bound to the x- and y-Axis of the plot. So we can just set the plot coordinates where the line should start/end: \code line->start->setCoords(-0.1, 0.8); line->end->setCoords(1.1, 0.2); \endcode If we wanted the line to be positioned not in plot coordinates but a different coordinate system, e.g. absolute pixel positions on the QCustomPlot surface, we would have changed the position type like this: \code line->start->setType(QCPItemPosition::ptAbsolute); line->end->setType(QCPItemPosition::ptAbsolute); \endcode Then we can set the coordinates, this time in pixels: \code line->start->setCoords(100, 200); line->end->setCoords(450, 320); \endcode \section items-subclassing Creating own items To create an own item, you implement a subclass of QCPAbstractItem. These are the pure virtual functions, you must implement: \li \ref selectTest \li \ref draw See the documentation of those functions for what they need to do. \subsection items-positioning Allowing the item to be positioned As mentioned, item positions are represented by QCPItemPosition members. Let's assume the new item shall have only one coordinate as its position (as opposed to two like a rect or multiple like a polygon). You then add a public member of type QCPItemPosition like so: \code QCPItemPosition * const myPosition;\endcode the const makes sure the pointer itself can't be modified from the user of your new item (the QCPItemPosition instance it points to, can be modified, of course). The initialization of this pointer is made easy with the \ref createPosition function. Just assign the return value of this function to each QCPItemPosition in the constructor of your item. \ref createPosition takes a string which is the name of the position, typically this is identical to the variable name. For example, the constructor of QCPItemExample could look like this: \code QCPItemExample::QCPItemExample(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), myPosition(createPosition("myPosition")) { // other constructor code } \endcode \subsection items-drawing The draw function Your implementation of the draw function should check whether the item is visible (\a mVisible) and then draw the item. You can retrieve its position in pixel coordinates from the position member(s) via \ref QCPItemPosition::pixelPoint. To optimize performance you should calculate a bounding rect first (don't forget to take the pen width into account), check whether it intersects the \ref clipRect, and only draw the item at all if this is the case. \subsection items-selection The selectTest function Your implementation of the \ref selectTest function may use the helpers \ref distSqrToLine and \ref rectSelectTest. With these, the implementation of the selection test becomes significantly simpler for most items. \subsection anchors Providing anchors Providing anchors (QCPItemAnchor) starts off like adding a position. First you create a public member, e.g. \code QCPItemAnchor * const bottom;\endcode and create it in the constructor with the \ref createAnchor function, assigning it a name and an anchor id (an integer enumerating all anchors on the item, you may create an own enum for this). Since anchors can be placed anywhere, relative to the item's position(s), your item needs to provide the position of every anchor with the reimplementation of the \ref anchorPixelPoint(int anchorId) function. In essence the QCPItemAnchor is merely an intermediary that itself asks your item for the pixel position when anything attached to the anchor needs to know the coordinates. */ /* start of documentation of inline functions */ /*! \fn QList QCPAbstractItem::positions() const Returns all positions of the item in a list. \see anchors, position */ /*! \fn QList QCPAbstractItem::anchors() const Returns all anchors of the item in a list. Note that since a position (QCPItemPosition) is always also an anchor, the list will also contain the positions of this item. \see positions, anchor */ /* end of documentation of inline functions */ /* start documentation of pure virtual functions */ /*! \fn double QCPAbstractItem::selectTest(const QPointF &pos) const = 0 This function is used to decide whether a click hits an item or not. \a pos is a point in pixel coordinates on the QCustomPlot surface. This function returns the shortest pixel distance of this point to the item. If the item is either invisible or the distance couldn't be determined, -1.0 is returned. \ref setSelectable has no influence on the return value of this function. If the item is represented not by single lines but by an area like QCPItemRect or QCPItemText, a click inside the area returns a constant value greater zero (typically 99% of the selectionTolerance of the parent QCustomPlot). If the click lies outside the area, this function returns -1.0. Providing a constant value for area objects allows selecting line objects even when they are obscured by such area objects, by clicking close to the lines (i.e. closer than 0.99*selectionTolerance). The actual setting of the selection state is not done by this function. This is handled by the parent QCustomPlot when the mouseReleaseEvent occurs. \see setSelected, QCustomPlot::setInteractions */ /*! \fn void QCPAbstractItem::draw(QCPPainter *painter) = 0 \internal Draws this item with the provided \a painter. Called by \ref QCustomPlot::draw on all its visible items. The cliprect of the provided painter is set to the rect returned by \ref clipRect before this function is called. For items this depends on the clipping settings defined by \ref setClipToAxisRect, \ref setClipKeyAxis and \ref setClipValueAxis. */ /* end documentation of pure virtual functions */ /* start documentation of signals */ /*! \fn void QCPAbstractItem::selectionChanged(bool selected) This signal is emitted when the selection state of this item has changed, either by user interaction or by a direct call to \ref setSelected. */ /* end documentation of signals */ /*! Base class constructor which initializes base class members. */ QCPAbstractItem::QCPAbstractItem(QCustomPlot *parentPlot) : QCPLayerable(parentPlot), mClipToAxisRect(true), mClipKeyAxis(parentPlot->xAxis), mClipValueAxis(parentPlot->yAxis), mSelectable(true), mSelected(false) { } QCPAbstractItem::~QCPAbstractItem() { // don't delete mPositions because every position is also an anchor and thus in mAnchors qDeleteAll(mAnchors); } /*! Sets whether the item shall be clipped to the axis rect or whether it shall be visible on the entire QCustomPlot. The axis rect is defined by the clip axes which can be set via \ref setClipAxes or individually with \ref setClipKeyAxis and \ref setClipValueAxis. */ void QCPAbstractItem::setClipToAxisRect(bool clip) { mClipToAxisRect = clip; } /*! Sets both clip axes. Together they define the axis rect that will be used to clip the item when \ref setClipToAxisRect is set to true. \see setClipToAxisRect, setClipKeyAxis, setClipValueAxis */ void QCPAbstractItem::setClipAxes(QCPAxis *keyAxis, QCPAxis *valueAxis) { mClipKeyAxis = keyAxis; mClipValueAxis = valueAxis; } /*! Sets the clip key axis. Together with the clip value axis it defines the axis rect that will be used to clip the item when \ref setClipToAxisRect is set to true. \see setClipToAxisRect, setClipAxes, setClipValueAxis */ void QCPAbstractItem::setClipKeyAxis(QCPAxis *axis) { mClipKeyAxis = axis; } /*! Sets the clip value axis. Together with the clip key axis it defines the axis rect that will be used to clip the item when \ref setClipToAxisRect is set to true. \see setClipToAxisRect, setClipAxes, setClipKeyAxis */ void QCPAbstractItem::setClipValueAxis(QCPAxis *axis) { mClipValueAxis = axis; } /*! Sets whether the user can (de-)select this item by clicking on the QCustomPlot surface. (When \ref QCustomPlot::setInteractions contains QCustomPlot::iSelectItems.) However, even when \a selectable was set to false, it is possible to set the selection manually, by calling \ref setSelected directly. \see QCustomPlot::setInteractions, setSelected */ void QCPAbstractItem::setSelectable(bool selectable) { mSelectable = selectable; } /*! Sets whether this item is selected or not. When selected, it might use a different visual appearance (e.g. pen and brush), this depends on the specific item, though. The entire selection mechanism for items is handled automatically when \ref QCustomPlot::setInteractions contains QCustomPlot::iSelectItems. You only need to call this function when you wish to change the selection state manually. This function can change the selection state even when \ref setSelectable was set to false. emits the \ref selectionChanged signal when \a selected is different from the previous selection state. \see selectTest */ void QCPAbstractItem::setSelected(bool selected) { if (mSelected != selected) { mSelected = selected; emit selectionChanged(mSelected); } } /*! Returns the QCPItemPosition with the specified \a name. If this item doesn't have a position by that name, returns 0. This function provides an alternative way to access item positions. Normally, you access positions direcly by their member pointers (which typically have the same variable name as \a name). \see positions, anchor */ QCPItemPosition *QCPAbstractItem::position(const QString &name) const { for (int i=0; iname() == name) return mPositions.at(i); } qDebug() << Q_FUNC_INFO << "position with name not found:" << name; return 0; } /*! Returns the QCPItemAnchor with the specified \a name. If this item doesn't have an anchor by that name, returns 0. This function provides an alternative way to access item anchors. Normally, you access anchors direcly by their member pointers (which typically have the same variable name as \a name). \see anchors, position */ QCPItemAnchor *QCPAbstractItem::anchor(const QString &name) const { for (int i=0; iname() == name) return mAnchors.at(i); } qDebug() << Q_FUNC_INFO << "anchor with name not found:" << name; return 0; } /*! Returns whether this item has an anchor with the specified \a name. Note that you can check for positions with this function, too, because every position is also an anchor (QCPItemPosition inherits from QCPItemAnchor). \see anchor, position */ bool QCPAbstractItem::hasAnchor(const QString &name) const { for (int i=0; iname() == name) return true; } return false; } /*! \internal Returns the rect the visual representation of this item is clipped to. This depends on the current setting of \ref setClipToAxisRect aswell as the clip axes set with \ref setClipAxes. If the item is not clipped to an axis rect, the \ref QCustomPlot::viewport rect is returned. \see draw */ QRect QCPAbstractItem::clipRect() const { if (mClipToAxisRect) { if (mClipKeyAxis && mClipValueAxis) return mClipKeyAxis->axisRect() | mClipValueAxis->axisRect(); else if (mClipKeyAxis) return mClipKeyAxis->axisRect(); else if (mClipValueAxis) return mClipValueAxis->axisRect(); } return mParentPlot->viewport(); } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing item lines. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set e.g. with \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased */ void QCPAbstractItem::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeItems); } /*! \internal Finds the shortest squared distance of \a point to the line segment defined by \a start and \a end. This function may be used to help with the implementation of the \ref selectTest function for specific items. \note This function is identical to QCPAbstractPlottable::distSqrToLine \see rectSelectTest */ double QCPAbstractItem::distSqrToLine(const QPointF &start, const QPointF &end, const QPointF &point) const { QVector2D a(start); QVector2D b(end); QVector2D p(point); QVector2D v(b-a); double vLengthSqr = v.lengthSquared(); if (!qFuzzyIsNull(vLengthSqr)) { double mu = QVector2D::dotProduct(p-a, v)/vLengthSqr; if (mu < 0) return (a-p).lengthSquared(); else if (mu > 1) return (b-p).lengthSquared(); else return ((a + mu*v)-p).lengthSquared(); } else return (a-p).lengthSquared(); } /*! \internal A convenience function which returns the selectTest value for a specified \a rect and a specified click position \a pos. \a filledRect defines whether a click inside the rect should also be considered a hit or whether only the rect border is sensitive to hits. This function may be used to help with the implementation of the \ref selectTest function for specific items. For example, if your item consists of four rects, call this function four times, once for each rect, in your \ref selectTest reimplementation. Finally, return the minimum of all four returned values which were greater or equal to zero. (Because this function may return -1.0 when \a pos doesn't hit \a rect at all). If all calls returned -1.0, return -1.0, too, because your item wasn't hit. \see distSqrToLine */ double QCPAbstractItem::rectSelectTest(const QRectF &rect, const QPointF &pos, bool filledRect) const { double result = -1; // distance to border: QList lines; lines << QLineF(rect.topLeft(), rect.topRight()) << QLineF(rect.bottomLeft(), rect.bottomRight()) << QLineF(rect.topLeft(), rect.bottomLeft()) << QLineF(rect.topRight(), rect.bottomRight()); double minDistSqr = std::numeric_limits::max(); for (int i=0; i mParentPlot->selectionTolerance()*0.99) { if (rect.contains(pos)) result = mParentPlot->selectionTolerance()*0.99; } return result; } /*! \internal Returns the pixel position of the anchor with Id \a anchorId. This function must be reimplemented in item subclasses if they want to provide anchors (QCPItemAnchor). For example, if the item has two anchors with id 0 and 1, this function takes one of these anchor ids and returns the respective pixel points of the specified anchor. \see createAnchor */ QPointF QCPAbstractItem::anchorPixelPoint(int anchorId) const { qDebug() << Q_FUNC_INFO << "called on item which shouldn't have any anchors (anchorPixelPos not reimplemented). anchorId" << anchorId; return QPointF(); } /*! \internal Creates a QCPItemPosition, registers it with this item and returns a pointer to it. The specified \a name must be a unique string that is usually identical to the variable name of the position member (This is needed to provide the name based \ref position access to positions). Don't delete positions created by this function manually, as the item will take care of it. Use this function in the constructor (initialization list) of the specific item subclass to create each position member. Don't create QCPItemPositions with \b new yourself, because they won't be registered with the item properly. \see createAnchor */ QCPItemPosition *QCPAbstractItem::createPosition(const QString &name) { if (hasAnchor(name)) qDebug() << Q_FUNC_INFO << "anchor/position with name exists already:" << name; QCPItemPosition *newPosition = new QCPItemPosition(mParentPlot, this, name); mPositions.append(newPosition); mAnchors.append(newPosition); // every position is also an anchor newPosition->setType(QCPItemPosition::ptPlotCoords); newPosition->setAxes(mParentPlot->xAxis, mParentPlot->yAxis); newPosition->setCoords(0, 0); return newPosition; } /*! \internal Creates a QCPItemAnchor, registers it with this item and returns a pointer to it. The specified \a name must be a unique string that is usually identical to the variable name of the anchor member (This is needed to provide the name based \ref anchor access to anchors). The \a anchorId must be a number identifying the created anchor. It is recommended to create an enum (e.g. "AnchorIndex") for this on each item that uses anchors. This id is used by the anchor to identify itself when it calls QCPAbstractItem::anchorPixelPoint. That function then returns the correct pixel coordinates for the passed anchor id. Don't delete anchors created by this function manually, as the item will take care of it. Use this function in the constructor (initialization list) of the specific item subclass to create each anchor member. Don't create QCPItemAnchors with \b new yourself, because then they won't be registered with the item properly. \see createPosition */ QCPItemAnchor *QCPAbstractItem::createAnchor(const QString &name, int anchorId) { if (hasAnchor(name)) qDebug() << Q_FUNC_INFO << "anchor/position with name exists already:" << name; QCPItemAnchor *newAnchor = new QCPItemAnchor(mParentPlot, this, name, anchorId); mAnchors.append(newAnchor); return newAnchor; } // ================================================================================ // =================== QCPItemPosition // ================================================================================ /*! \class QCPItemPosition \brief Manages the position of an item. Every item has at least one public QCPItemPosition member pointer which provides ways to position the item on the QCustomPlot surface. Some items have multiple positions, for example QCPItemRect has two: \a topLeft and \a bottomRight. QCPItemPosition has a type (\ref PositionType) that can be set with \ref setType. This type defines how coordinates passed to \ref setCoords are to be interpreted, e.g. as absolute pixel coordinates, as plot coordinates of certain axes, etc. Further, QCPItemPosition may have a parent QCPItemAnchor, see \ref setParentAnchor. (Note that every QCPItemPosition inherits from QCPItemAnchor and thus can itself be used as parent anchor for other positions.) This way you can tie multiple items together. If the QCPItemPosition has a parent, the coordinates set with \ref setCoords are considered to be absolute values in the reference frame of the parent anchor, where (0, 0) means directly ontop of the parent anchor. For example, You could attach the \a start position of a QCPItemLine to the \a bottom anchor of a QCPItemText to make the starting point of the line always be centered under the text label, no matter where the text is moved to, or is itself tied to. To set the apparent pixel position on the QCustomPlot surface directly, use \ref setPixelPoint. This works no matter what type this QCPItemPosition is or what parent-child situation it is in, as \ref setPixelPoint transforms the coordinates appropriately, to make the position appear at the specified pixel values. */ /*! Creates a new QCPItemPosition. You shouldn't create QCPItemPosition instances directly, even if you want to make a new item subclass. Use \ref QCPAbstractItem::createPosition instead, as explained in the subclassing section of the QCPAbstractItem documentation. */ QCPItemPosition::QCPItemPosition(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString name) : QCPItemAnchor(parentPlot, parentItem, name), mPositionType(ptAbsolute), mKeyAxis(0), mValueAxis(0), mKey(0), mValue(0), mParentAnchor(0) { } QCPItemPosition::~QCPItemPosition() { // unregister as parent at children: // Note: this is done in ~QCPItemAnchor again, but it's important QCPItemPosition does it itself, because only then // the setParentAnchor(0) call the correct QCPItemPosition::pixelPos function instead of QCPItemAnchor::pixelPos QList currentChildren(mChildren.toList()); for (int i=0; isetParentAnchor(0); // this acts back on this anchor and child removes itself from mChildren // unregister as child in parent: if (mParentAnchor) mParentAnchor->removeChild(this); } /*! Sets the type of the position. The type defines how the coordinates passed to \ref setCoords should be handled and how the QCPItemPosition should behave in the plot. Note that the position type \ref ptPlotCoords is only available (and sensible) when the position has no parent anchor (\ref setParentAnchor). The possible values for \a type can be separated in two main categories: \li The position is regarded as a point in plot coordinates. This corresponds to \ref ptPlotCoords and requires two axes that define the plot coordinate system. They can be specified with \ref setAxes. By default, the QCustomPlot's x- and yAxis are used. \li The position is fixed on the QCustomPlot surface, i.e. independant of axis ranges. This corresponds to all other types, i.e. \ref ptAbsolute, \ref ptViewportRatio and \ref ptAxisRectRatio. They differ only in the way the absolute position is described, see the documentation of PositionType for details. \note If the type is changed, the apparent pixel position on the plot is preserved. This means the coordinates as retrieved with coords() and set with \ref setCoords may change in the process. */ void QCPItemPosition::setType(QCPItemPosition::PositionType type) { if (mPositionType != type) { QPointF pixelP = pixelPoint(); mPositionType = type; setPixelPoint(pixelP); } } /*! Sets the parent of this QCPItemPosition to \a parentAnchor. This means the position will now follow any position changes of the anchor. The local coordinate system of positions with a parent anchor always is absolute with (0, 0) being exactly on top of the parent anchor. (Hence the type shouldn't be \ref ptPlotCoords for positions with parent anchors.) if \a keepPixelPosition is true, the current pixel position of the QCPItemPosition is preserved during reparenting. If it's set to false, the coordinates are set to (0, 0), i.e. the position will be exactly on top of the parent anchor. To remove this QCPItemPosition from any parent anchor, set \a parentAnchor to 0. \note If the QCPItemPosition previously had no parent and the type is \ref ptPlotCoords, the type is set to \ref ptAbsolute, to keep the position in a valid state. */ bool QCPItemPosition::setParentAnchor(QCPItemAnchor *parentAnchor, bool keepPixelPosition) { // make sure self is not assigned as parent: if (parentAnchor == this) { qDebug() << Q_FUNC_INFO << "can't set self as parent anchor" << reinterpret_cast(parentAnchor); return false; } // make sure no recursive parent-child-relationships are created: QCPItemAnchor *currentParent = parentAnchor; while (currentParent) { if (QCPItemPosition *currentParentPos = dynamic_cast(currentParent)) { // is a QCPItemPosition, might have further parent, so keep iterating if (currentParentPos == this) { qDebug() << Q_FUNC_INFO << "can't create recursive parent-child-relationship" << reinterpret_cast(parentAnchor); return false; } currentParent = currentParentPos->mParentAnchor; } else { // is a QCPItemAnchor, can't have further parent, so just compare parent items if (currentParent->mParentItem == mParentItem) { qDebug() << Q_FUNC_INFO << "can't create recursive parent-child-relationship" << reinterpret_cast(parentAnchor); return false; } break; } } // if previously no parent set and PosType is still ptPlotCoords, set to ptAbsolute: if (!mParentAnchor && mPositionType == ptPlotCoords) setType(ptAbsolute); // save pixel position: QPointF pixelP; if (keepPixelPosition) pixelP = pixelPoint(); // unregister at current parent anchor: if (mParentAnchor) mParentAnchor->removeChild(this); // register at new parent anchor: if (parentAnchor) parentAnchor->addChild(this); mParentAnchor = parentAnchor; // restore pixel position under new parent: if (keepPixelPosition) setPixelPoint(pixelP); else setCoords(0, 0); return true; } /*! Sets the coordinates of this QCPItemPosition. What the coordinates mean, is defined by the type (\ref setType). For example, if the type is \ref ptAbsolute, \a key and \a value mean the x and y pixel position on the QCustomPlot surface where the origin (0, 0) is in the top left corner of the QCustomPlot viewport. If the type is \ref ptPlotCoords, \a key and \a value mean a point in the plot coordinate system defined by the axes set by \ref setAxes. (By default the QCustomPlot's x- and yAxis.) \see setPixelPoint */ void QCPItemPosition::setCoords(double key, double value) { mKey = key; mValue = value; } /*! \overload Sets the coordinates as a QPointF \a pos where pos.x has the meaning of \a key and pos.y the meaning of \a value of the \ref setCoords(double key, double value) function. */ void QCPItemPosition::setCoords(const QPointF &pos) { setCoords(pos.x(), pos.y()); } /*! Returns the final absolute pixel position of the QCPItemPosition on the QCustomPlot surface. It includes all effects of type (\ref setType) and possible parent anchors (\ref setParentAnchor). \see setPixelPoint */ QPointF QCPItemPosition::pixelPoint() const { switch (mPositionType) { case ptAbsolute: { if (mParentAnchor) return QPointF(mKey, mValue) + mParentAnchor->pixelPoint(); else return QPointF(mKey, mValue); } case ptViewportRatio: { if (mParentAnchor) { return QPointF(mKey*mParentPlot->viewport().width(), mValue*mParentPlot->viewport().height()) + mParentAnchor->pixelPoint(); } else { return QPointF(mKey*mParentPlot->viewport().width(), mValue*mParentPlot->viewport().height()) + mParentPlot->viewport().topLeft(); } } case ptAxisRectRatio: { if (mParentAnchor) { return QPointF(mKey*mParentPlot->axisRect().width(), mValue*mParentPlot->axisRect().height()) + mParentAnchor->pixelPoint(); } else { return QPointF(mKey*mParentPlot->axisRect().width(), mValue*mParentPlot->axisRect().height()) + mParentPlot->axisRect().topLeft(); } } case ptPlotCoords: { double x, y; if (mKeyAxis && mValueAxis) { // both key and value axis are given, translate key/value to x/y coordinates: if (mKeyAxis->orientation() == Qt::Horizontal) { x = mKeyAxis->coordToPixel(mKey); y = mValueAxis->coordToPixel(mValue); } else { y = mKeyAxis->coordToPixel(mKey); x = mValueAxis->coordToPixel(mValue); } } else if (mKeyAxis) { // only key axis is given, depending on orientation only transform x or y to key coordinate, other stays pixel: if (mKeyAxis->orientation() == Qt::Horizontal) { x = mKeyAxis->coordToPixel(mKey); y = mValue; } else { y = mKeyAxis->coordToPixel(mKey); x = mValue; } } else if (mValueAxis) { // only value axis is given, depending on orientation only transform x or y to value coordinate, other stays pixel: if (mValueAxis->orientation() == Qt::Horizontal) { x = mValueAxis->coordToPixel(mValue); y = mKey; } else { y = mValueAxis->coordToPixel(mValue); x = mKey; } } else { // no axis given, basically the same as if mAnchorType were atNone x = mKey; y = mValue; } return QPointF(x, y); } } return QPointF(); } /*! When \ref setType is ptPlotCoords, this function may be used to specify the axes the coordinates set with \ref setCoords relate to. */ void QCPItemPosition::setAxes(QCPAxis *keyAxis, QCPAxis *valueAxis) { mKeyAxis = keyAxis; mValueAxis = valueAxis; } /*! Sets the apparent pixel position. This works no matter what type this QCPItemPosition is or what parent-child situation it is in, as \ref setPixelPoint transforms the coordinates appropriately, to make the position appear at the specified pixel values. Only if the type is \ref ptAbsolute and no parent anchor is set, this function is identical to \ref setCoords. \see setCoords */ void QCPItemPosition::setPixelPoint(const QPointF &pixelPoint) { switch (mPositionType) { case ptAbsolute: { if (mParentAnchor) setCoords(pixelPoint-mParentAnchor->pixelPoint()); else setCoords(pixelPoint); break; } case ptViewportRatio: { if (mParentAnchor) { QPointF p(pixelPoint-mParentAnchor->pixelPoint()); p.rx() /= (double)mParentPlot->viewport().width(); p.ry() /= (double)mParentPlot->viewport().height(); setCoords(p); } else { QPointF p(pixelPoint-mParentPlot->viewport().topLeft()); p.rx() /= (double)mParentPlot->viewport().width(); p.ry() /= (double)mParentPlot->viewport().height(); setCoords(p); } break; } case ptAxisRectRatio: { if (mParentAnchor) { QPointF p(pixelPoint-mParentAnchor->pixelPoint()); p.rx() /= (double)mParentPlot->axisRect().width(); p.ry() /= (double)mParentPlot->axisRect().height(); setCoords(p); } else { QPointF p(pixelPoint-mParentPlot->axisRect().topLeft()); p.rx() /= (double)mParentPlot->axisRect().width(); p.ry() /= (double)mParentPlot->axisRect().height(); setCoords(p); } break; } case ptPlotCoords: { double newKey, newValue; if (mKeyAxis && mValueAxis) { // both key and value axis are given, translate point to key/value coordinates: if (mKeyAxis->orientation() == Qt::Horizontal) { newKey = mKeyAxis->pixelToCoord(pixelPoint.x()); newValue = mValueAxis->pixelToCoord(pixelPoint.y()); } else { newKey = mKeyAxis->pixelToCoord(pixelPoint.y()); newValue = mValueAxis->pixelToCoord(pixelPoint.x()); } } else if (mKeyAxis) { // only key axis is given, depending on orientation only transform x or y to key coordinate, other stays pixel: if (mKeyAxis->orientation() == Qt::Horizontal) { newKey = mKeyAxis->pixelToCoord(pixelPoint.x()); newValue = pixelPoint.y(); } else { newKey = mKeyAxis->pixelToCoord(pixelPoint.y()); newValue = pixelPoint.x(); } } else if (mValueAxis) { // only value axis is given, depending on orientation only transform x or y to value coordinate, other stays pixel: if (mValueAxis->orientation() == Qt::Horizontal) { newKey = pixelPoint.y(); newValue = mValueAxis->pixelToCoord(pixelPoint.x()); } else { newKey = pixelPoint.x(); newValue = mValueAxis->pixelToCoord(pixelPoint.y()); } } else { // no axis given, basically the same as if mAnchorType were atNone newKey = pixelPoint.x(); newValue = pixelPoint.y(); } setCoords(newKey, newValue); break; } } } // ================================================================================ // =================== QCPItemStraightLine // ================================================================================ /*! \class QCPItemStraightLine \brief A straight line that spans infinitely in both directions \image html QCPItemStraightLine.png "Straight line example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a point1 and \a point2, which define the straight line. */ /*! Creates a straight line item and sets default values. The constructed item can be added to the plot with QCustomPlot::addItem. */ QCPItemStraightLine::QCPItemStraightLine(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), point1(createPosition("point1")), point2(createPosition("point2")) { point1->setCoords(0, 0); point2->setCoords(1, 1); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue,2)); } QCPItemStraightLine::~QCPItemStraightLine() { } /*! Sets the pen that will be used to draw the line \see setSelectedPen */ void QCPItemStraightLine::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line when selected \see setPen, setSelected */ void QCPItemStraightLine::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /* inherits documentation from base class */ double QCPItemStraightLine::selectTest(const QPointF &pos) const { if (!mVisible) return -1; return distToStraightLine(QVector2D(point1->pixelPoint()), QVector2D(point2->pixelPoint()-point1->pixelPoint()), QVector2D(pos)); } /* inherits documentation from base class */ void QCPItemStraightLine::draw(QCPPainter *painter) { QVector2D start(point1->pixelPoint()); QVector2D end(point2->pixelPoint()); // get visible segment of straight line inside clipRect: double clipPad = mainPen().widthF(); QLineF line = getRectClippedStraightLine(start, end-start, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad)); // paint visible segment, if existent: if (!line.isNull()) { painter->setPen(mainPen()); painter->drawLine(line); } } /*! \internal finds the shortest distance of \a point to the straight line defined by the base point \a base and the direction vector \a vec. This is a helper function for \ref selectTest. */ double QCPItemStraightLine::distToStraightLine(const QVector2D &base, const QVector2D &vec, const QVector2D &point) const { return qAbs((base.y()-point.y())*vec.x()-(base.x()-point.x())*vec.y())/vec.length(); } /*! \internal Returns the section of the straight line defined by \a base and direction vector \a vec, that is visible in the specified \a rect. This is a helper function for \ref draw. */ QLineF QCPItemStraightLine::getRectClippedStraightLine(const QVector2D &base, const QVector2D &vec, const QRect &rect) const { double bx, by; double gamma; QLineF result; if (vec.x() == 0 && vec.y() == 0) return result; if (qFuzzyIsNull(vec.x())) // line is vertical { // check top of rect: bx = rect.left(); by = rect.top(); gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y(); if (gamma >= 0 && gamma <= rect.width()) result.setLine(bx+gamma, rect.top(), bx+gamma, rect.bottom()); // no need to check bottom because we know line is vertical } else if (qFuzzyIsNull(vec.y())) // line is horizontal { // check left of rect: bx = rect.left(); by = rect.top(); gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x(); if (gamma >= 0 && gamma <= rect.height()) result.setLine(rect.left(), by+gamma, rect.right(), by+gamma); // no need to check right because we know line is horizontal } else // line is skewed { QList pointVectors; // check top of rect: bx = rect.left(); by = rect.top(); gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y(); if (gamma >= 0 && gamma <= rect.width()) pointVectors.append(QVector2D(bx+gamma, by)); // check bottom of rect: bx = rect.left(); by = rect.bottom(); gamma = base.x()-bx + (by-base.y())*vec.x()/vec.y(); if (gamma >= 0 && gamma <= rect.width()) pointVectors.append(QVector2D(bx+gamma, by)); // check left of rect: bx = rect.left(); by = rect.top(); gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x(); if (gamma >= 0 && gamma <= rect.height()) pointVectors.append(QVector2D(bx, by+gamma)); // check right of rect: bx = rect.right(); by = rect.top(); gamma = base.y()-by + (bx-base.x())*vec.y()/vec.x(); if (gamma >= 0 && gamma <= rect.height()) pointVectors.append(QVector2D(bx, by+gamma)); // evaluate points: if (pointVectors.size() == 2) { result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF()); } else if (pointVectors.size() > 2) { // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance: double distSqrMax = 0; QVector2D pv1, pv2; for (int i=0; i distSqrMax) { pv1 = pointVectors.at(i); pv2 = pointVectors.at(k); distSqrMax = distSqr; } } } result.setPoints(pv1.toPointF(), pv2.toPointF()); } } return result; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemStraightLine::mainPen() const { return mSelected ? mSelectedPen : mPen; } // ================================================================================ // =================== QCPItemLine // ================================================================================ /*! \class QCPItemLine \brief A line from one point to another \image html QCPItemLine.png "Line example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a start and \a end, which define the end points of the line. With \ref setHead and \ref setTail you may set different line ending styles, e.g. to create an arrow. */ /*! Creates a line item and sets default values. The constructed item can be added to the plot with QCustomPlot::addItem. */ QCPItemLine::QCPItemLine(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), start(createPosition("start")), end(createPosition("end")) { start->setCoords(0, 0); end->setCoords(1, 1); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue,2)); } QCPItemLine::~QCPItemLine() { } /*! Sets the pen that will be used to draw the line \see setSelectedPen */ void QCPItemLine::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line when selected \see setPen, setSelected */ void QCPItemLine::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the line ending style of the head. The head corresponds to the \a end position. Note that due to the overloaded QCPLineEnding constructor, you may directly specify a QCPLineEnding::EndingStyle here, e.g. \code setHead(QCPLineEnding::esSpikeArrow) \endcode \see setTail */ void QCPItemLine::setHead(const QCPLineEnding &head) { mHead = head; } /*! Sets the line ending style of the tail. The tail corresponds to the \a start position. Note that due to the overloaded QCPLineEnding constructor, you may directly specify a QCPLineEnding::EndingStyle here, e.g. \code setTail(QCPLineEnding::esSpikeArrow) \endcode \see setHead */ void QCPItemLine::setTail(const QCPLineEnding &tail) { mTail = tail; } /* inherits documentation from base class */ double QCPItemLine::selectTest(const QPointF &pos) const { if (!mVisible) return -1; return qSqrt(distSqrToLine(start->pixelPoint(), end->pixelPoint(), pos)); } /* inherits documentation from base class */ void QCPItemLine::draw(QCPPainter *painter) { QVector2D startVec(start->pixelPoint()); QVector2D endVec(end->pixelPoint()); if (startVec.toPoint() == endVec.toPoint()) return; // get visible segment of straight line inside clipRect: double clipPad = qMax(mHead.boundingDistance(), mTail.boundingDistance()); clipPad = qMax(clipPad, mainPen().widthF()); QLineF line = getRectClippedLine(startVec, endVec, clipRect().adjusted(-clipPad, -clipPad, clipPad, clipPad)); // paint visible segment, if existent: if (!line.isNull()) { painter->setPen(mainPen()); painter->drawLine(line); painter->setBrush(Qt::SolidPattern); if (mTail.style() != QCPLineEnding::esNone) mTail.draw(painter, startVec, startVec-endVec); if (mHead.style() != QCPLineEnding::esNone) mHead.draw(painter, endVec, endVec-startVec); } } /*! \internal Returns the section of the line defined by \a start and \a end, that is visible in the specified \a rect. This is a helper function for \ref draw. */ QLineF QCPItemLine::getRectClippedLine(const QVector2D &start, const QVector2D &end, const QRect &rect) const { bool containsStart = rect.contains(start.x(), start.y()); bool containsEnd = rect.contains(end.x(), end.y()); if (containsStart && containsEnd) return QLineF(start.toPointF(), end.toPointF()); QVector2D base = start; QVector2D vec = end-start; double bx, by; double gamma, mu; QLineF result; QList pointVectors; if (!qFuzzyIsNull(vec.y())) // line is not horizontal { // check top of rect: bx = rect.left(); by = rect.top(); mu = (by-base.y())/vec.y(); if (mu >= 0 && mu <= 1) { gamma = base.x()-bx + mu*vec.x(); if (gamma >= 0 && gamma <= rect.width()) pointVectors.append(QVector2D(bx+gamma, by)); } // check bottom of rect: bx = rect.left(); by = rect.bottom(); mu = (by-base.y())/vec.y(); if (mu >= 0 && mu <= 1) { gamma = base.x()-bx + mu*vec.x(); if (gamma >= 0 && gamma <= rect.width()) pointVectors.append(QVector2D(bx+gamma, by)); } } if (!qFuzzyIsNull(vec.x())) // line is not vertical { // check left of rect: bx = rect.left(); by = rect.top(); mu = (bx-base.x())/vec.x(); if (mu >= 0 && mu <= 1) { gamma = base.y()-by + mu*vec.y(); if (gamma >= 0 && gamma <= rect.height()) pointVectors.append(QVector2D(bx, by+gamma)); } // check right of rect: bx = rect.right(); by = rect.top(); mu = (bx-base.x())/vec.x(); if (mu >= 0 && mu <= 1) { gamma = base.y()-by + mu*vec.y(); if (gamma >= 0 && gamma <= rect.height()) pointVectors.append(QVector2D(bx, by+gamma)); } } if (containsStart) pointVectors.append(start); if (containsEnd) pointVectors.append(end); // evaluate points: if (pointVectors.size() == 2) { result.setPoints(pointVectors.at(0).toPointF(), pointVectors.at(1).toPointF()); } else if (pointVectors.size() > 2) { // line probably goes through corner of rect, and we got two points there. single out the point pair with greatest distance: double distSqrMax = 0; QVector2D pv1, pv2; for (int i=0; i distSqrMax) { pv1 = pointVectors.at(i); pv2 = pointVectors.at(k); distSqrMax = distSqr; } } } result.setPoints(pv1.toPointF(), pv2.toPointF()); } return result; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemLine::mainPen() const { return mSelected ? mSelectedPen : mPen; } // ================================================================================ // =================== QCPItemEllipse // ================================================================================ /*! \class QCPItemEllipse \brief An ellipse \image html QCPItemEllipse.png "Ellipse example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a topLeft and \a bottomRight, which define the rect the ellipse will be drawn in. */ /*! Creates an ellipse item and sets default values. The constructed item can be added to the plot with QCustomPlot::addItem. */ QCPItemEllipse::QCPItemEllipse(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), topLeft(createPosition("topLeft")), bottomRight(createPosition("bottomRight")), topLeftRim(createAnchor("topLeftRim", aiTopLeftRim)), top(createAnchor("top", aiTop)), topRightRim(createAnchor("topRightRim", aiTopRightRim)), right(createAnchor("right", aiRight)), bottomRightRim(createAnchor("bottomRightRim", aiBottomRightRim)), bottom(createAnchor("bottom", aiBottom)), bottomLeftRim(createAnchor("bottomLeftRim", aiBottomLeftRim)), left(createAnchor("left", aiLeft)) { topLeft->setCoords(0, 1); bottomRight->setCoords(1, 0); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue, 2)); setBrush(Qt::NoBrush); setSelectedBrush(Qt::NoBrush); } QCPItemEllipse::~QCPItemEllipse() { } /*! Sets the pen that will be used to draw the line of the ellipse \see setSelectedPen, setBrush */ void QCPItemEllipse::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line of the ellipse when selected \see setPen, setSelected */ void QCPItemEllipse::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the brush that will be used to fill the ellipse. To disable filling, set \a brush to Qt::NoBrush. \see setSelectedBrush, setPen */ void QCPItemEllipse::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the brush that will be used to fill the ellipse when selected. To disable filling, set \a brush to Qt::NoBrush. \see setBrush */ void QCPItemEllipse::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /* inherits documentation from base class */ double QCPItemEllipse::selectTest(const QPointF &pos) const { double result = -1; QPointF p1 = topLeft->pixelPoint(); QPointF p2 = bottomRight->pixelPoint(); QPointF center((p1+p2)/2.0); double a = qAbs(p1.x()-p2.x())/2.0; double b = qAbs(p1.y()-p2.y())/2.0; double x = pos.x()-center.x(); double y = pos.y()-center.y(); // distance to border: double c = 1.0/qSqrt(x*x/(a*a)+y*y/(b*b)); result = qAbs(c-1)*qSqrt(x*x+y*y); // filled ellipse, allow click inside to count as hit: if (result > mParentPlot->selectionTolerance()*0.99 && mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0) { if (x*x/(a*a) + y*y/(b*b) <= 1) result = mParentPlot->selectionTolerance()*0.99; } return result; } /* inherits documentation from base class */ void QCPItemEllipse::draw(QCPPainter *painter) { QPointF p1 = topLeft->pixelPoint(); QPointF p2 = bottomRight->pixelPoint(); if (p1.toPoint() == p2.toPoint()) return; QRectF ellipseRect = QRectF(p1, p2).normalized(); QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF()); if (ellipseRect.intersects(clip)) // only draw if bounding rect of ellipse is visible in cliprect { painter->setPen(mainPen()); painter->setBrush(mainBrush()); try { painter->drawEllipse(ellipseRect); } catch (...) { qDebug() << Q_FUNC_INFO << "Item too large for memory, setting invisible"; setVisible(false); } } } /* inherits documentation from base class */ QPointF QCPItemEllipse::anchorPixelPoint(int anchorId) const { QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint()); switch (anchorId) { case aiTopLeftRim: return rect.center()+(rect.topLeft()-rect.center())*1/qSqrt(2); case aiTop: return (rect.topLeft()+rect.topRight())*0.5; case aiTopRightRim: return rect.center()+(rect.topRight()-rect.center())*1/qSqrt(2); case aiRight: return (rect.topRight()+rect.bottomRight())*0.5; case aiBottomRightRim: return rect.center()+(rect.bottomRight()-rect.center())*1/qSqrt(2); case aiBottom: return (rect.bottomLeft()+rect.bottomRight())*0.5; case aiBottomLeftRim: return rect.center()+(rect.bottomLeft()-rect.center())*1/qSqrt(2); case aiLeft: return (rect.topLeft()+rect.bottomLeft())*0.5;; } qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId; return QPointF(); } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemEllipse::mainPen() const { return mSelected ? mSelectedPen : mPen; } /*! \internal Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item is not selected and mSelectedBrush when it is. */ QBrush QCPItemEllipse::mainBrush() const { return mSelected ? mSelectedBrush : mBrush; } // ================================================================================ // =================== QCPItemRect // ================================================================================ /*! \class QCPItemRect \brief A rectangle \image html QCPItemRect.png "Rectangle example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a topLeft and \a bottomRight, which define the rectangle. */ /*! Creates a rectangle item and sets default values. The constructed item can be added to the plot with QCustomPlot::addItem. */ QCPItemRect::QCPItemRect(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), topLeft(createPosition("topLeft")), bottomRight(createPosition("bottomRight")), top(createAnchor("top", aiTop)), topRight(createAnchor("topRight", aiTopRight)), right(createAnchor("right", aiRight)), bottom(createAnchor("bottom", aiBottom)), bottomLeft(createAnchor("bottomLeft", aiBottomLeft)), left(createAnchor("left", aiLeft)) { topLeft->setCoords(0, 1); bottomRight->setCoords(1, 0); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue,2)); setBrush(Qt::NoBrush); setSelectedBrush(Qt::NoBrush); } QCPItemRect::~QCPItemRect() { } /*! Sets the pen that will be used to draw the line of the rectangle \see setSelectedPen, setBrush */ void QCPItemRect::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line of the rectangle when selected \see setPen, setSelected */ void QCPItemRect::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the brush that will be used to fill the rectangle. To disable filling, set \a brush to Qt::NoBrush. \see setSelectedBrush, setPen */ void QCPItemRect::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the brush that will be used to fill the rectangle when selected. To disable filling, set \a brush to Qt::NoBrush. \see setBrush */ void QCPItemRect::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /* inherits documentation from base class */ double QCPItemRect::selectTest(const QPointF &pos) const { if (!mVisible) return -1; QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint()).normalized(); bool filledRect = mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0; return rectSelectTest(rect, pos, filledRect); } /* inherits documentation from base class */ void QCPItemRect::draw(QCPPainter *painter) { QPointF p1 = topLeft->pixelPoint(); QPointF p2 = bottomRight->pixelPoint(); if (p1.toPoint() == p2.toPoint()) return; QRectF rect = QRectF(p1, p2).normalized(); double clipPad = mainPen().widthF(); QRectF boundingRect = rect.adjusted(-clipPad, -clipPad, clipPad, clipPad); if (boundingRect.intersects(clipRect())) // only draw if bounding rect of rect item is visible in cliprect { painter->setPen(mainPen()); painter->setBrush(mainBrush()); painter->drawRect(rect); } } /* inherits documentation from base class */ QPointF QCPItemRect::anchorPixelPoint(int anchorId) const { QRectF rect = QRectF(topLeft->pixelPoint(), bottomRight->pixelPoint()); switch (anchorId) { case aiTop: return (rect.topLeft()+rect.topRight())*0.5; case aiTopRight: return rect.topRight(); case aiRight: return (rect.topRight()+rect.bottomRight())*0.5; case aiBottom: return (rect.bottomLeft()+rect.bottomRight())*0.5; case aiBottomLeft: return rect.bottomLeft(); case aiLeft: return (rect.topLeft()+rect.bottomLeft())*0.5;; } qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId; return QPointF(); } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemRect::mainPen() const { return mSelected ? mSelectedPen : mPen; } /*! \internal Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item is not selected and mSelectedBrush when it is. */ QBrush QCPItemRect::mainBrush() const { return mSelected ? mSelectedBrush : mBrush; } // ================================================================================ // =================== QCPItemPixmap // ================================================================================ /*! \class QCPItemPixmap \brief An arbitrary pixmap \image html QCPItemPixmap.png "Pixmap example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a topLeft and \a bottomRight, which define the rectangle the pixmap will be drawn in. Depending on the scale setting (\ref setScaled), the pixmap will be either scaled to fit the rectangle or be drawn aligned to the topLeft position. If scaling is enabled and \a topLeft is further to the bottom/right than \a bottomRight (as shown on the right side of the example image), the pixmap will be flipped in the respective orientations. */ /*! Creates a rectangle item and sets default values. The constructed item can be added to the plot with QCustomPlot::addItem. */ QCPItemPixmap::QCPItemPixmap(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), topLeft(createPosition("topLeft")), bottomRight(createPosition("bottomRight")), top(createAnchor("top", aiTop)), topRight(createAnchor("topRight", aiTopRight)), right(createAnchor("right", aiRight)), bottom(createAnchor("bottom", aiBottom)), bottomLeft(createAnchor("bottomLeft", aiBottomLeft)), left(createAnchor("left", aiLeft)) { topLeft->setCoords(0, 1); bottomRight->setCoords(1, 0); setPen(Qt::NoPen); setSelectedPen(QPen(Qt::blue)); setScaled(false, Qt::KeepAspectRatio); } QCPItemPixmap::~QCPItemPixmap() { } /*! Sets the pixmap that will be displayed. */ void QCPItemPixmap::setPixmap(const QPixmap &pixmap) { mPixmap = pixmap; } /*! Sets whether the pixmap will be scaled to fit the rectangle defined by the \a topLeft and \a bottomRight positions. */ void QCPItemPixmap::setScaled(bool scaled, Qt::AspectRatioMode aspectRatioMode) { mScaled = scaled; mAspectRatioMode = aspectRatioMode; updateScaledPixmap(); } /*! Sets the pen that will be used to draw a border around the pixmap. \see setSelectedPen, setBrush */ void QCPItemPixmap::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw a border around the pixmap when selected \see setPen, setSelected */ void QCPItemPixmap::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /* inherits documentation from base class */ double QCPItemPixmap::selectTest(const QPointF &pos) const { if (!mVisible) return -1; return rectSelectTest(getFinalRect(), pos, true); } /* inherits documentation from base class */ void QCPItemPixmap::draw(QCPPainter *painter) { bool flipHorz = false; bool flipVert = false; QRect rect = getFinalRect(&flipHorz, &flipVert); double clipPad = mainPen().style() == Qt::NoPen ? 0 : mainPen().widthF(); QRect boundingRect = rect.adjusted(-clipPad, -clipPad, clipPad, clipPad); if (boundingRect.intersects(clipRect())) { updateScaledPixmap(rect, flipHorz, flipVert); painter->drawPixmap(rect.topLeft(), mScaled ? mScaledPixmap : mPixmap); QPen pen = mainPen(); if (pen.style() != Qt::NoPen) { painter->setPen(pen); painter->setBrush(Qt::NoBrush); painter->drawRect(rect); } } } /* inherits documentation from base class */ QPointF QCPItemPixmap::anchorPixelPoint(int anchorId) const { bool flipHorz; bool flipVert; QRect rect = getFinalRect(&flipHorz, &flipVert); // we actually want denormal rects (negative width/height) here, so restore // the flipped state: if (flipHorz) rect.adjust(rect.width(), 0, -rect.width(), 0); if (flipVert) rect.adjust(0, rect.height(), 0, -rect.height()); switch (anchorId) { case aiTop: return (rect.topLeft()+rect.topRight())*0.5; case aiTopRight: return rect.topRight(); case aiRight: return (rect.topRight()+rect.bottomRight())*0.5; case aiBottom: return (rect.bottomLeft()+rect.bottomRight())*0.5; case aiBottomLeft: return rect.bottomLeft(); case aiLeft: return (rect.topLeft()+rect.bottomLeft())*0.5;; } qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId; return QPointF(); } /*! \internal Creates the buffered scaled image (\a mScaledPixmap) to fit the specified \a finalRect. The parameters \a flipHorz and \a flipVert control whether the resulting image shall be flipped horizontally or vertically. (This is used when \a topLeft is further to the bottom/right than \a bottomRight.) This function only creates the scaled pixmap when the buffered pixmap has a different size than the expected result, so calling this function repeatedly, e.g. in the \ref draw function, does not cause expensive rescaling every time. If scaling is disabled, sets mScaledPixmap to a null QPixmap. */ void QCPItemPixmap::updateScaledPixmap(QRect finalRect, bool flipHorz, bool flipVert) { if (mScaled) { if (finalRect.isNull()) finalRect = getFinalRect(&flipHorz, &flipVert); if (finalRect.size() != mScaledPixmap.size()) { mScaledPixmap = mPixmap.scaled(finalRect.size(), mAspectRatioMode, Qt::SmoothTransformation); if (flipHorz || flipVert) mScaledPixmap = QPixmap::fromImage(mScaledPixmap.toImage().mirrored(flipHorz, flipVert)); } } else if (!mScaledPixmap.isNull()) mScaledPixmap = QPixmap(); } /*! \internal Returns the final (tight) rect the pixmap is drawn in, depending on the current item positions and scaling settings. The output parameters \a flippedHorz and \a flippedVert return whether the pixmap should be drawn flipped horizontally or vertically in the returned rect. (The returned rect itself is always normalized, i.e. the top left corner of the rect is actually further to the top/left than the bottom right corner). This is the case when the item position \a topLeft is further to the bottom/right than \a bottomRight. If scaling is disabled, returns a rect with size of the original pixmap and the top left corner aligned with the item position \a topLeft. The position \a bottomRight is ignored. */ QRect QCPItemPixmap::getFinalRect(bool *flippedHorz, bool *flippedVert) const { QRect result; bool flipHorz = false; bool flipVert = false; QPoint p1 = topLeft->pixelPoint().toPoint(); QPoint p2 = bottomRight->pixelPoint().toPoint(); if (p1 == p2) return QRect(p1, QSize(0, 0)); if (mScaled) { QSize newSize = QSize(p2.x()-p1.x(), p2.y()-p1.y()); QPoint topLeft = p1; if (newSize.width() < 0) { flipHorz = true; newSize.rwidth() *= -1; topLeft.setX(p2.x()); } if (newSize.height() < 0) { flipVert = true; newSize.rheight() *= -1; topLeft.setY(p2.y()); } QSize scaledSize = mPixmap.size(); scaledSize.scale(newSize, mAspectRatioMode); result = QRect(topLeft, scaledSize); } else { result = QRect(p1, mPixmap.size()); } if (flippedHorz) *flippedHorz = flipHorz; if (flippedVert) *flippedVert = flipVert; return result; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemPixmap::mainPen() const { return mSelected ? mSelectedPen : mPen; } // ================================================================================ // =================== QCPItemText // ================================================================================ /*! \class QCPItemText \brief A text label \image html QCPItemText.png "Text example. Blue dotted circles are anchors, solid blue discs are positions." Its position is defined by the member \a position and the setting of \ref setPositionAlignment. The latter controls which part of the text rect shall be aligned with \a position. The text alignment itself (i.e. left, center, right) can be controlled with \ref setTextAlignment. The text may be rotated around the \a position point with \ref setRotation. */ /*! Creates a text item and sets default values. The constructed item can be added to the plot with QCustomPlot::addItem. */ QCPItemText::QCPItemText(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), position(createPosition("position")), topLeft(createAnchor("topLeft", aiTopLeft)), top(createAnchor("top", aiTop)), topRight(createAnchor("topRight", aiTopRight)), right(createAnchor("right", aiRight)), bottomRight(createAnchor("bottomRight", aiBottomRight)), bottom(createAnchor("bottom", aiBottom)), bottomLeft(createAnchor("bottomLeft", aiBottomLeft)), left(createAnchor("left", aiLeft)) { position->setCoords(0, 0); setRotation(0); setTextAlignment(Qt::AlignTop|Qt::AlignHCenter); setPositionAlignment(Qt::AlignCenter); setText("text"); setPen(Qt::NoPen); setSelectedPen(Qt::NoPen); setBrush(Qt::NoBrush); setSelectedBrush(Qt::NoBrush); setColor(Qt::black); setSelectedColor(Qt::blue); } QCPItemText::~QCPItemText() { } /*! Sets the color of the text. */ void QCPItemText::setColor(const QColor &color) { mColor = color; } /*! Sets the color of the text that will be used when the item is selected. */ void QCPItemText::setSelectedColor(const QColor &color) { mSelectedColor = color; } /*! Sets the pen that will be used do draw a rectangular border around the text. To disable the border, set \a pen to Qt::NoPen. \see setSelectedPen, setBrush, setPadding */ void QCPItemText::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used do draw a rectangular border around the text, when the item is selected. To disable the border, set \a pen to Qt::NoPen. \see setPen */ void QCPItemText::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the brush that will be used do fill the background of the text. To disable the background, set \a brush to Qt::NoBrush. \see setSelectedBrush, setPen, setPadding */ void QCPItemText::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the brush that will be used do fill the background of the text, when the item is selected. To disable the background, set \a brush to Qt::NoBrush. \see setBrush */ void QCPItemText::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /*! Sets the font of the text. \see setSelectedFont, setColor */ void QCPItemText::setFont(const QFont &font) { mFont = font; } /*! Sets the font of the text that will be used when the item is selected. \see setFont */ void QCPItemText::setSelectedFont(const QFont &font) { mSelectedFont = font; } /*! Sets the text that will be displayed. Multi-line texts are supported by inserting a line break character, e.g. '\n'. \see setFont, setColor, setTextAlignment */ void QCPItemText::setText(const QString &text) { mText = text; } /*! Sets which point of the text rect shall be aligned with \a position. Examples: \li If \a alignment is Qt::AlignHCenter | Qt::AlignTop, the text will be positioned such that the top of the text rect will be horizontally centered on \a position. \li If \a alignment is Qt::AlignLeft | Qt::AlignBottom, \a position will indicate the bottom left corner of the text rect. If you want to control the alignment of (multi-lined) text within the text rect, use \ref setTextAlignment. */ void QCPItemText::setPositionAlignment(Qt::Alignment alignment) { mPositionAlignment = alignment; } /*! Controls how (multi-lined) text is aligned inside the text rect (typically Qt::AlignLeft, Qt::AlignCenter or Qt::AlignRight). */ void QCPItemText::setTextAlignment(Qt::Alignment alignment) { mTextAlignment = alignment; } /*! Sets the angle in degrees by which the text (and the text rectangle, if visible) will be rotated around \a position. */ void QCPItemText::setRotation(double degrees) { mRotation = degrees; } /*! Sets the distance between the border of the text rectangle and the text. The appearance (and visibility) of the text rectangle can be controlled with \ref setPen and \ref setBrush. */ void QCPItemText::setPadding(const QMargins &padding) { mPadding = padding; } /* inherits documentation from base class */ double QCPItemText::selectTest(const QPointF &pos) const { if (!mVisible) return -1; // The rect may be rotated, so we transform the actual clicked pos to the rotated // coordinate system, wo we can use the normal rectSelectTest function for non-rotated rects: QPointF positionPixels(position->pixelPoint()); QTransform inputTransform; inputTransform.translate(positionPixels.x(), positionPixels.y()); inputTransform.rotate(-mRotation); inputTransform.translate(-positionPixels.x(), -positionPixels.y()); QPointF rotatedPos = inputTransform.map(pos); QFontMetrics fontMetrics(mFont); QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText); QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom()); QPointF textPos = getTextDrawPoint(positionPixels, textBoxRect, mPositionAlignment); textBoxRect.moveTopLeft(textPos.toPoint()); return rectSelectTest(textBoxRect, rotatedPos, true); } /* inherits documentation from base class */ void QCPItemText::draw(QCPPainter *painter) { QPointF pos(position->pixelPoint()); QTransform transform; transform.translate(pos.x(), pos.y()); if (!qFuzzyIsNull(mRotation)) transform.rotate(mRotation); painter->setFont(mainFont()); QRect textRect = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText); QRect textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom()); QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation textRect.moveTopLeft(textPos.toPoint()+QPoint(mPadding.left(), mPadding.top())); textBoxRect.moveTopLeft(textPos.toPoint()); double clipPad = mainPen().widthF(); QRect boundingRect = textBoxRect.adjusted(-clipPad, -clipPad, clipPad, clipPad); if (transform.mapRect(boundingRect).intersects(clipRect())) { painter->setTransform(transform); if ((mainBrush().style() != Qt::NoBrush && mainBrush().color().alpha() != 0) || (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0)) { painter->setPen(mainPen()); painter->setBrush(mainBrush()); painter->drawRect(textBoxRect); } painter->setBrush(Qt::NoBrush); painter->setPen(QPen(mainColor())); painter->drawText(textRect, Qt::TextDontClip|mTextAlignment, mText); } } /* inherits documentation from base class */ QPointF QCPItemText::anchorPixelPoint(int anchorId) const { // get actual rect points (pretty much copied from draw function): QPointF pos(position->pixelPoint()); QTransform transform; transform.translate(pos.x(), pos.y()); if (!qFuzzyIsNull(mRotation)) transform.rotate(mRotation); QFontMetrics fontMetrics(mainFont()); QRect textRect = fontMetrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip|mTextAlignment, mText); QRectF textBoxRect = textRect.adjusted(-mPadding.left(), -mPadding.top(), mPadding.right(), mPadding.bottom()); QPointF textPos = getTextDrawPoint(QPointF(0, 0), textBoxRect, mPositionAlignment); // 0, 0 because the transform does the translation textBoxRect.moveTopLeft(textPos.toPoint()); QPolygonF rectPoly = transform.map(QPolygonF(textBoxRect)); switch (anchorId) { case aiTopLeft: return rectPoly.at(0); case aiTop: return (rectPoly.at(0)+rectPoly.at(1))*0.5; case aiTopRight: return rectPoly.at(1); case aiRight: return (rectPoly.at(1)+rectPoly.at(2))*0.5; case aiBottomRight: return rectPoly.at(2); case aiBottom: return (rectPoly.at(2)+rectPoly.at(3))*0.5; case aiBottomLeft: return rectPoly.at(3); case aiLeft: return (rectPoly.at(3)+rectPoly.at(0))*0.5; } qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId; return QPointF(); } /*! \internal Returns the point that must be given to the QPainter::drawText function (which expects the top left point of the text rect), according to the position \a pos, the text bounding box \a rect and the requested \a positionAlignment. For example, if \a positionAlignment is Qt::AlignLeft | Qt::AlignBottom the returned point will be shifted upward by the height of \a rect, starting from \a pos. So if the text is finally drawn at that point, the lower left corner of the resulting text rect is at \a pos. */ QPointF QCPItemText::getTextDrawPoint(const QPointF &pos, const QRectF &rect, Qt::Alignment positionAlignment) const { if (positionAlignment == 0 || positionAlignment == (Qt::AlignLeft|Qt::AlignTop)) return pos; QPointF result = pos; // start at top left if (positionAlignment.testFlag(Qt::AlignHCenter)) result.rx() -= rect.width()/2.0; else if (positionAlignment.testFlag(Qt::AlignRight)) result.rx() -= rect.width(); if (positionAlignment.testFlag(Qt::AlignVCenter)) result.ry() -= rect.height()/2.0; else if (positionAlignment.testFlag(Qt::AlignBottom)) result.ry() -= rect.height(); return result; } /*! \internal Returns the font that should be used for drawing text. Returns mFont when the item is not selected and mSelectedFont when it is. */ QFont QCPItemText::mainFont() const { return mSelected ? mSelectedFont : mFont; } /*! \internal Returns the color that should be used for drawing text. Returns mColor when the item is not selected and mSelectedColor when it is. */ QColor QCPItemText::mainColor() const { return mSelected ? mSelectedColor : mColor; } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemText::mainPen() const { return mSelected ? mSelectedPen : mPen; } /*! \internal Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item is not selected and mSelectedBrush when it is. */ QBrush QCPItemText::mainBrush() const { return mSelected ? mSelectedBrush : mBrush; } // ================================================================================ // =================== QCPPainter // ================================================================================ /*! \class QCPPainter \brief QPainter subclass used internally This internal class is used to provide some extended functionality e.g. for tweaking position consistency between antialiased and non-antialiased painting and drawing common shapes (like scatter symbols). Further it provides workarounds for QPainter quirks. \warning This class intentionally hides non-virtual functions of QPainter, e.g. setPen, save and restore. So while it is possible to pass a QCPPainter instance to a function that expects a QPainter pointer, some of the workarounds and tweaks will be unavailable to the function (because it will call the base class implementations of the functions actually hidden by QCPPainter). */ /*! Creates a new QCPPainter instance and sets default values */ QCPPainter::QCPPainter() : QPainter(), mScaledExportMode(false), mPdfExportMode(false), mIsAntialiasing(false) { } /*! Creates a new QCPPainter instance on the specified paint \a device and sets default values. Just like the analogous QPainter constructor, begins painting on \a device immediately. */ QCPPainter::QCPPainter(QPaintDevice *device) : QPainter(device), mScaledExportMode(false), mPdfExportMode(false), mIsAntialiasing(false) { } QCPPainter::~QCPPainter() { } /*! Sets the pixmap that will be used to draw scatters with \ref drawScatter, when the style is QCP::ssPixmap. */ void QCPPainter::setScatterPixmap(const QPixmap pm) { mScatterPixmap = pm; } /*! Sets the pen of the painter and applies certain fixes to it, depending on the mode of this QCPPainter. \note this function hides the non-virtual base class implementation. */ void QCPPainter::setPen(const QPen &pen) { QPainter::setPen(pen); if (mScaledExportMode) fixScaledPen(); } /*! \overload Sets the pen (by color) of the painter and applies certain fixes to it, depending on the mode of this QCPPainter. \note this function hides the non-virtual base class implementation. */ void QCPPainter::setPen(const QColor &color) { QPainter::setPen(color); if (mScaledExportMode) fixScaledPen(); } /*! \overload Sets the pen (by style) of the painter and applies certain fixes to it, depending on the mode of this QCPPainter. \note this function hides the non-virtual base class implementation. */ void QCPPainter::setPen(Qt::PenStyle penStyle) { QPainter::setPen(penStyle); if (mScaledExportMode) fixScaledPen(); } /*! \overload Works around a Qt bug introduced with Qt 4.8 which makes drawing QLineF unpredictable when antialiasing is disabled. \note this function hides the non-virtual base class implementation. */ void QCPPainter::drawLine(const QLineF &line) { if (mIsAntialiasing) QPainter::drawLine(line); else QPainter::drawLine(line.toLine()); } /*! Sets whether painting uses antialiasing or not. Use this method instead of using setRenderHint with QPainter::Antialiasing directly, as it allows QCPPainter to regain pixel exactness between antialiased and non-antialiased painting (Since Qt uses slightly different coordinate systems for AA/Non-AA painting). */ void QCPPainter::setAntialiasing(bool enabled) { if (mPdfExportMode) return; setRenderHint(QPainter::Antialiasing, enabled); if (mIsAntialiasing != enabled) { if (mIsAntialiasing) translate(-0.5, -0.5); else translate(0.5, 0.5); mIsAntialiasing = enabled; } } /*! Saves the painter (see QPainter::save). Since QCPPainter adds some new internal state to QPainter, the save/restore functions are reimplemented to also save/restore those members. \note this function hides the non-virtual base class implementation. \see restore */ void QCPPainter::save() { mAntialiasingStack.push(mIsAntialiasing); QPainter::save(); } /*! Restores the painter (see QPainter::restore). Since QCPPainter adds some new internal state to QPainter, the save/restore functions are reimplemented to also save/restore those members. \note this function hides the non-virtual base class implementation. \see save */ void QCPPainter::restore() { if (!mAntialiasingStack.isEmpty()) mIsAntialiasing = mAntialiasingStack.pop(); else qDebug() << Q_FUNC_INFO << "Unbalanced save/restore"; QPainter::restore(); } /*! Sets whether the painter shall adjust its fixes/workarounds optimized for vectorized pdf export. This means for example, that the antialiasing/non-antialiasing fix introduced with \ref setAntialiasing is not used, since PDF is not rastered and thus works with floating point data natively. */ void QCPPainter::setPdfExportMode(bool enabled) { mPdfExportMode = enabled; } /*! Sets whether the painter shall adjust its fixes/workarounds optimized for scaled export to rastered image formats. For example this provides a workaround for a QPainter bug that prevents scaling of pen widths for pens with width 0, although the QPainter::NonCosmeticDefaultPen render hint is set. */ void QCPPainter::setScaledExportMode(bool enabled) { mScaledExportMode = enabled; } /*! Provides a workaround for a QPainter bug that prevents scaling of pen widths for pens with width 0, although the QPainter::NonCosmeticDefaultPen render hint is set. Changes the pen width from 0 to 1, if appropriate. Does nothing if the QCPPainter is not in scaled export mode (\ref setScaledExportMode). */ void QCPPainter::fixScaledPen() { if (mScaledExportMode && pen().isCosmetic() && qFuzzyIsNull(pen().widthF())) { QPen p = pen(); p.setWidth(1); QPainter::setPen(p); } } /*! Draws a single scatter point with the specified \a style and \a size in pixels at the pixel position \a x and \a y. If the \a style is ssPixmap, make sure to pass the respective pixmap with \ref setScatterPixmap before calling this function. */ void QCPPainter::drawScatter(double x, double y, double size, QCP::ScatterStyle style) { double w = size/2.0; switch (style) { case QCP::ssNone: break; case QCP::ssDot: { drawPoint(QPointF(x, y)); break; } case QCP::ssCross: { drawLine(QLineF(x-w, y-w, x+w, y+w)); drawLine(QLineF(x-w, y+w, x+w, y-w)); break; } case QCP::ssPlus: { drawLine(QLineF(x-w, y, x+w, y)); drawLine(QLineF(x, y+w, x, y-w)); break; } case QCP::ssCircle: { setBrush(Qt::NoBrush); drawEllipse(QPointF(x,y), w, w); break; } case QCP::ssDisc: { setBrush(QBrush(pen().color())); drawEllipse(QPointF(x,y), w, w); break; } case QCP::ssSquare: { setBrush(Qt::NoBrush); drawRect(QRectF(x-w, y-w, size, size)); break; } case QCP::ssDiamond: { setBrush(Qt::NoBrush); drawLine(QLineF(x-w, y, x, y-w)); drawLine(QLineF(x, y-w, x+w, y)); drawLine(QLineF(x+w, y, x, y+w)); drawLine(QLineF(x, y+w, x-w, y)); break; } case QCP::ssStar: { drawLine(QLineF(x-w, y, x+w, y)); drawLine(QLineF(x, y+w, x, y-w)); drawLine(QLineF(x-w*0.707, y-w*0.707, x+w*0.707, y+w*0.707)); drawLine(QLineF(x-w*0.707, y+w*0.707, x+w*0.707, y-w*0.707)); break; } case QCP::ssTriangle: { drawLine(QLineF(x-w, y+0.755*w, x+w, y+0.755*w)); drawLine(QLineF(x+w, y+0.755*w, x, y-0.977*w)); drawLine(QLineF(x, y-0.977*w, x-w, y+0.755*w)); break; } case QCP::ssTriangleInverted: { drawLine(QLineF(x-w, y-0.755*w, x+w, y-0.755*w)); drawLine(QLineF(x+w, y-0.755*w, x, y+0.977*w)); drawLine(QLineF(x, y+0.977*w, x-w, y-0.755*w)); break; } case QCP::ssCrossSquare: { setBrush(Qt::NoBrush); drawLine(QLineF(x-w, y-w, x+w*0.95, y+w*0.95)); drawLine(QLineF(x-w, y+w*0.95, x+w*0.95, y-w)); drawRect(QRectF(x-w,y-w,size,size)); break; } case QCP::ssPlusSquare: { setBrush(Qt::NoBrush); drawLine(QLineF(x-w, y, x+w*0.95, y)); drawLine(QLineF(x, y+w, x, y-w)); drawRect(QRectF(x-w, y-w, size, size)); break; } case QCP::ssCrossCircle: { setBrush(Qt::NoBrush); drawLine(QLineF(x-w*0.707, y-w*0.707, x+w*0.67, y+w*0.67)); drawLine(QLineF(x-w*0.707, y+w*0.67, x+w*0.67, y-w*0.707)); drawEllipse(QPointF(x,y), w, w); break; } case QCP::ssPlusCircle: { setBrush(Qt::NoBrush); drawLine(QLineF(x-w, y, x+w, y)); drawLine(QLineF(x, y+w, x, y-w)); drawEllipse(QPointF(x,y), w, w); break; } case QCP::ssPeace: { setBrush(Qt::NoBrush); drawLine(QLineF(x, y-w, x, y+w)); drawLine(QLineF(x, y, x-w*0.707, y+w*0.707)); drawLine(QLineF(x, y, x+w*0.707, y+w*0.707)); drawEllipse(QPointF(x,y), w, w); break; } case QCP::ssPixmap: { drawPixmap(x-mScatterPixmap.width()*0.5, y-mScatterPixmap.height()*0.5, mScatterPixmap); // if something in here is changed, adapt QCP::ssPixmap special case in drawLegendIcon(), too break; } } } // ================================================================================ // =================== QCPLineEnding // ================================================================================ /*! \class QCPLineEnding \brief Handles the different ending decorations for line-like items \image html QCPLineEnding.png "The various ending styles currently supported" For every ending a line-like item has, an instance of this class exists. For example, QCPItemLine has two endings which can be set with QCPItemLine::setHead and QCPItemLine::setTail. The styles themselves are defined via the enum QCPLineEnding::EndingStyle. Most decorations can be modified regarding width and length, see \ref setWidth and \ref setLength. The direction of the ending decoration (e.g. direction an arrow is pointing) is controlled by the line-like item. For example, when both endings of a QCPItemLine are set to be arrows, they will point to opposite directions, e.g. "outward". This can be changed by \ref setInverted, which would make the respective arrow point inward. Note that due to the overloaded QCPLineEnding constructor, you may directly specify a QCPLineEnding::EndingStyle where actually a QCPLineEnding is expected, e.g. \code myItemLine->setHead(QCPLineEnding::esSpikeArrow) \endcode */ /*! Creates a QCPLineEnding instance with default values (style \ref esNone). */ QCPLineEnding::QCPLineEnding() : mStyle(esNone), mWidth(8), mLength(10), mInverted(false) { } /*! Creates a QCPLineEnding instance with the specified values. */ QCPLineEnding::QCPLineEnding(QCPLineEnding::EndingStyle style, double width, double length, bool inverted) : mStyle(style), mWidth(width), mLength(length), mInverted(inverted) { } /*! Sets the style of the ending decoration. */ void QCPLineEnding::setStyle(QCPLineEnding::EndingStyle style) { mStyle = style; } /*! Sets the width of the ending decoration, if the style supports it. On arrows, for example, the width defines the size perpendicular to the arrow's pointing direction. \see setLength */ void QCPLineEnding::setWidth(double width) { mWidth = width; } /*! Sets the length of the ending decoration, if the style supports it. On arrows, for example, the length defines the size in pointing direction. \see setWidth */ void QCPLineEnding::setLength(double length) { mLength = length; } /*! Sets whether the direction of the ending decoration shall be inverted with respect to the natural direction given by the parent item. For example, an arrow decoration will point inward when \a inverted is set to true. */ void QCPLineEnding::setInverted(bool inverted) { mInverted = inverted; } /*! \internal Returns the maximum pixel radius the ending decoration might cover, starting from the position the decoration is drawn at (typically a line ending/\ref QCPItemPosition of an item). This is relevant for clipping. Only omit painting of the decoration when the position where the decoration is supposed to be drawn is farther away from the clipping rect than the returned distance. */ double QCPLineEnding::boundingDistance() const { switch (mStyle) { case esNone: return 0; case esFlatArrow: case esSpikeArrow: case esLineArrow: return qSqrt(mWidth*mWidth+mLength*mLength); // items that have width and length case esDisc: case esSquare: case esDiamond: case esBar: return mWidth*1.42; // items that only have a width -> with*sqrt(2) } return 0; } /*! \internal Draws the line ending with the specified \a painter at the position \a pos. The direction of the line ending is controlled with \a dir. */ void QCPLineEnding::draw(QCPPainter *painter, const QVector2D &pos, const QVector2D &dir) const { if (mStyle == esNone) return; QVector2D lengthVec(dir.normalized()*(mInverted ? -1 : 1)); if (lengthVec.isNull()) lengthVec = QVector2D(1, 0); QVector2D widthVec(-lengthVec.y(), lengthVec.x()); lengthVec *= mLength; widthVec *= mWidth*0.5; QPen penBackup = painter->pen(); QPen miterPen = penBackup; miterPen.setJoinStyle(Qt::MiterJoin); switch (mStyle) { case esNone: break; case esFlatArrow: { QPointF points[3] = {pos.toPointF(), (pos-lengthVec+widthVec).toPointF(), (pos-lengthVec-widthVec).toPointF() }; painter->setPen(miterPen); painter->drawConvexPolygon(points, 3); painter->setPen(penBackup); break; } case esSpikeArrow: { QPointF points[4] = {pos.toPointF(), (pos-lengthVec+widthVec).toPointF(), (pos-lengthVec*0.8).toPointF(), (pos-lengthVec-widthVec).toPointF() }; painter->setPen(miterPen); painter->drawConvexPolygon(points, 4); painter->setPen(penBackup); break; } case esLineArrow: { QPointF points[3] = {(pos-lengthVec+widthVec).toPointF(), pos.toPointF(), (pos-lengthVec-widthVec).toPointF() }; painter->setPen(miterPen); painter->drawPolyline(points, 3); painter->setPen(penBackup); break; } case esDisc: { painter->drawEllipse(pos.toPointF(), mWidth*0.5, mWidth*0.5); break; } case esSquare: { QVector2D widthVecPerp(-widthVec.y(), widthVec.x()); QPointF points[4] = {(pos-widthVecPerp+widthVec).toPointF(), (pos-widthVecPerp-widthVec).toPointF(), (pos+widthVecPerp-widthVec).toPointF(), (pos+widthVecPerp+widthVec).toPointF() }; painter->setPen(miterPen); painter->drawConvexPolygon(points, 4); painter->setPen(penBackup); break; } case esDiamond: { QVector2D widthVecPerp(-widthVec.y(), widthVec.x()); QPointF points[4] = {(pos-widthVecPerp).toPointF(), (pos-widthVec).toPointF(), (pos+widthVecPerp).toPointF(), (pos+widthVec).toPointF() }; painter->setPen(miterPen); painter->drawConvexPolygon(points, 4); painter->setPen(penBackup); break; } case esBar: { painter->drawLine((pos+widthVec).toPointF(), (pos-widthVec).toPointF()); break; } } } /*! \internal \overload Draws the line ending. The direction is controlled with the \a angle parameter in radians. */ void QCPLineEnding::draw(QCPPainter *painter, const QVector2D &pos, double angle) const { draw(painter, pos, QVector2D(qCos(angle), qSin(angle))); } // ================================================================================ // =================== QCPItemCurve // ================================================================================ /*! \class QCPItemCurve \brief A curved line from one point to another \image html QCPItemCurve.png "Curve example. Blue dotted circles are anchors, solid blue discs are positions." It has four positions, \a start and \a end, which define the end points of the line, and two control points which define the direction the line exits from the start and the direction from which it approaches the end: \a startDir and \a endDir. With \ref setHead and \ref setTail you may set different line ending styles, e.g. to create an arrow. Often it is desirable for the control points to stay at fixed relative positions to the start/end point. This can be achieved by setting the parent anchor e.g. of \a startDir simply to \a start, and then specify the desired pixel offset with QCPItemPosition::setCoords on \a startDir. */ /*! Creates a curve item and sets default values. The constructed item can be added to the plot with QCustomPlot::addItem. */ QCPItemCurve::QCPItemCurve(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), start(createPosition("start")), startDir(createPosition("startDir")), endDir(createPosition("endDir")), end(createPosition("end")) { start->setCoords(0, 0); startDir->setCoords(0.5, 0); endDir->setCoords(0, 0.5); end->setCoords(1, 1); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue,2)); } QCPItemCurve::~QCPItemCurve() { } /*! Sets the pen that will be used to draw the line \see setSelectedPen */ void QCPItemCurve::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line when selected \see setPen, setSelected */ void QCPItemCurve::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the line ending style of the head. The head corresponds to the \a end position. Note that due to the overloaded QCPLineEnding constructor, you may directly specify a QCPLineEnding::EndingStyle here, e.g. \code setHead(QCPLineEnding::esSpikeArrow) \endcode \see setTail */ void QCPItemCurve::setHead(const QCPLineEnding &head) { mHead = head; } /*! Sets the line ending style of the tail. The tail corresponds to the \a start position. Note that due to the overloaded QCPLineEnding constructor, you may directly specify a QCPLineEnding::EndingStyle here, e.g. \code setTail(QCPLineEnding::esSpikeArrow) \endcode \see setHead */ void QCPItemCurve::setTail(const QCPLineEnding &tail) { mTail = tail; } /* inherits documentation from base class */ double QCPItemCurve::selectTest(const QPointF &pos) const { if (!mVisible) return -1; QPointF startVec(start->pixelPoint()); QPointF startDirVec(startDir->pixelPoint()); QPointF endDirVec(endDir->pixelPoint()); QPointF endVec(end->pixelPoint()); QPainterPath cubicPath(startVec); cubicPath.cubicTo(startDirVec, endDirVec, endVec); QPolygonF polygon = cubicPath.toSubpathPolygons().first(); double minDistSqr = std::numeric_limits::max(); for (int i=1; ipixelPoint()); QPointF startDirVec(startDir->pixelPoint()); QPointF endDirVec(endDir->pixelPoint()); QPointF endVec(end->pixelPoint()); if (QVector2D(endVec-startVec).length() > 1e10) // too large curves cause crash return; QPainterPath cubicPath(startVec); cubicPath.cubicTo(startDirVec, endDirVec, endVec); // paint visible segment, if existent: QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF()); QRect cubicRect = cubicPath.controlPointRect().toRect(); if (cubicRect.isEmpty()) // may happen when start and end exactly on same x or y position cubicRect.adjust(0, 0, 1, 1); if (clip.intersects(cubicRect)) { painter->setPen(mainPen()); painter->drawPath(cubicPath); painter->setBrush(Qt::SolidPattern); if (mTail.style() != QCPLineEnding::esNone) mTail.draw(painter, QVector2D(startVec), M_PI-cubicPath.angleAtPercent(0)/180.0*M_PI); if (mHead.style() != QCPLineEnding::esNone) mHead.draw(painter, QVector2D(endVec), -cubicPath.angleAtPercent(1)/180.0*M_PI); } } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemCurve::mainPen() const { return mSelected ? mSelectedPen : mPen; } // ================================================================================ // =================== QCPLayer // ================================================================================ /*! \class QCPLayer \brief A layer that may contain objects, to control the rendering order The Layering system of QCustomPlot is the mechanism to control the rendering order of the elements inside the plot, e.g. that the grid is drawn behind plottables etc. It is based on the two classes QCPLayer and QCPLayerable. A QCustomPlot contains an ordered list of one or more instances of QCPLayer (see QCustomPlot::addLayer, QCustomPlot::layer, QCustomPlot::moveLayer, etc.). The layers are drawn in the order they are in the list. A QCPLayer itself contains an ordered list of QCPLayerable instances. QCPLayerable is an abstract base class from which almost all visible objects derive, like axes, grids, graphs, items, etc. By default, QCustomPlot has three layers: "grid", "main" and "axes" (in that order). Initially the QCPGrid instances are on the "grid" layer, so the grid will be drawn beneath the objects on the other two layers. The top layer is "axes" and contains all four axes, so they will be drawn on top. Between these two layers, there is the "main" layer. It is initially empty and set as the current layer (see QCustomPlot::setCurrentLayer). This means, all new plottables, items etc. are created on this layer by default, and are thus drawn above the grid but below the axes. Controlling the ordering of objects is easy: Create a new layer in the position you want it to be, e.g. above "main", with QCustomPlot::addLayer. Then set the current layer with QCustomPlot::setCurrentLayer to that new layer and finally create the objects normally. They will be placed on the new layer automatically, due to the current layer setting. Alternatively you could have also ignored the current layer setting and just moved the objects with QCPLayerable::setLayer to the desired layer after creating them. It is also possible to move whole layers. For example, If you want the grid to be shown in front of all plottables/items on the "main" layer, just move it above "main" with QCustomPlot::moveLayer. This way the ordering might now be "main", "grid", "axes", so while the grid will still be beneath the axes, it will now be drawn above plottables/items on "main", as intended. The rendering order within one layer is simply by order of creation. The item created last (or added last to the layer), is drawn on top of all other objects on that layer. When a layer is deleted, the objects on it are not deleted with it, but fall on the layer below the deleted layer, see QCustomPlot::removeLayer. */ /* start documentation of inline functions */ /*! \fn QList QCPLayer::children() const Returns a list of all layerables on this layer. The order corresponds to the rendering order, i.e. layerables with higher indices are drawn above layerables with lower indices. */ /* end documentation of inline functions */ /*! Creates a new QCPLayer instance. Normally you shouldn't directly create layers like this, use QCustomPlot::addLayer instead. \warning It is not checked that \a layerName is actually an unique layer name in \a parentPlot. This check is only performed by QCustomPlot::addLayer. */ QCPLayer::QCPLayer(QCustomPlot *parentPlot, const QString &layerName) : mParentPlot(parentPlot), mName(layerName) { // Note: no need to make sure layerName doesn't already, because layer // management is done with QCustomPlot functions. } QCPLayer::~QCPLayer() { } /*! Returns the index this layer has in the QCustomPlot. The index is the integer number by which this layer can be accessed via QCustomPlot::layer. Layers with greater indices will be drawn above layers with smaller indices. */ int QCPLayer::index() const { return mParentPlot->mLayers.indexOf(const_cast(this)); } /*! \internal Adds the \a layerable to the list of this layer. If \a prepend is set to true, the layerable will be prepended to the list, i.e. be drawn beneath the other layerables already in the list. This function does not change the \a mLayer member of \a layerable to this layer. (Use QCPLayerable::setLayer to change the layer of an object, not this function.) \see removeChild */ void QCPLayer::addChild(QCPLayerable *layerable, bool prepend) { if (!mChildren.contains(layerable)) { if (prepend) mChildren.prepend(layerable); else mChildren.append(layerable); } else qDebug() << Q_FUNC_INFO << "layerable is already child of this layer" << reinterpret_cast(layerable); } /*! \internal Removes the \a layerable from the list of this layer. This function does not change the \a mLayer member of \a layerable. (Use QCPLayerable::setLayer to change the layer of an object, not this function.) \see addChild */ void QCPLayer::removeChild(QCPLayerable *layerable) { if (!mChildren.removeOne(layerable)) qDebug() << Q_FUNC_INFO << "layerable is not child of this layer" << reinterpret_cast(layerable); } // ================================================================================ // =================== QCPLayerable // ================================================================================ /*! \class QCPLayerable \brief Base class for all objects that can be placed on layers This is the abstract base class most visible objects derive from, e.g. plottables, axes, grid etc. Every layerable is on a layer (QCPLayer) which allows controlling the rendering order by stacking the layers accordingly. For details about the layering mechanism, see the QCPLayer documentation. */ /* start documentation of pure virtual functions */ /*! \fn virtual void QCPLayerable::applyDefaultAntialiasingHint(QCPPainter *painter) const = 0 \internal This function applies the default antialiasing setting to the specified \a painter, using the function \ref applyAntialiasingHint. This is the antialiasing state the painter is in, when \ref draw is called on the layerable. If the layerable has multiple entities whose antialiasing setting may be specified individually, this function should set the antialiasing state of the most prominent entity. In this case however, the \ref draw function usually calls the specialized versions of this function before drawing each entity, effectively overriding the setting of the default antialiasing hint. First example: QCPGraph has multiple entities that have an antialiasing setting: The graph line, fills, scatters and error bars. Those can be configured via QCPGraph::setAntialiased, QCPGraph::setAntialiasedFill, QCPGraph::setAntialiasedScatters etc. Consequently, there isn't only the QCPGraph::applyDefaultAntialiasingHint function (which corresponds to the graph line's antialiasing), but specialized ones like QCPGraph::applyFillAntialiasingHint and QCPGraph::applyScattersAntialiasingHint. So before drawing one of those entities, QCPGraph::draw calls the respective specialized applyAntialiasingHint function. Second example: QCPItemLine consists only of a line so there is only one antialiasing setting which can be controlled with QCPItemLine::setAntialiased. (This function is inherited by all layerables. The specialized functions, as seen on QCPGraph, must be added explicitly to the respective layerable subclass.) Consequently it only has the normal QCPItemLine::applyDefaultAntialiasingHint. The \ref QCPItemLine::draw function doesn't need to care about setting any antialiasing states, because the default antialiasing hint is already set on the painter when the \ref draw function is called, and that's the state it wants to draw the line with. */ /*! \fn virtual void QCPLayerable::draw(QCPPainter *painter) const = 0 \internal This function draws the layerable to the specified \a painter. Before this function is called, the painter's antialiasing state is set via \ref applyDefaultAntialiasingHint, see the documentation there. Further, its clipping rectangle was set to \ref clipRect. */ /* end documentation of pure virtual functions */ /*! Creates a new QCPLayerable instance. Since QCPLayerable is an abstract base class, it can't be instantiated directly. Use one of the derived classes. */ QCPLayerable::QCPLayerable(QCustomPlot *parentPlot) : QObject(0), // rather not bind to parentPlot, incase we want to allow moving of objects between customplots some day mVisible(true), mParentPlot(parentPlot), mLayer(0), mAntialiased(true) { if (mParentPlot) setLayer(mParentPlot->currentLayer()); } QCPLayerable::~QCPLayerable() { if (mLayer) { mLayer->removeChild(this); mLayer = 0; } } /*! Sets the visibility of this layerable object. If an object is not visible, it will not be drawn on the QCustomPlot surface, and user interaction with it (e.g. click/selection) is not possible. */ void QCPLayerable::setVisible(bool on) { mVisible = on; } /*! Sets the \a layer of this layerable object. The object will be placed on top of the other objects already on \a layer. Returns true on success, i.e. if \a layer is a valid layer. */ bool QCPLayerable::setLayer(QCPLayer *layer) { return moveToLayer(layer, false); } /*! \overload Sets the layer of this layerable object by name Returns true on success, i.e. if \a layerName is a valid layer name. */ bool QCPLayerable::setLayer(const QString &layerName) { if (!mParentPlot) { qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set"; return false; } if (QCPLayer *layer = mParentPlot->layer(layerName)) { return setLayer(layer); } else { qDebug() << Q_FUNC_INFO << "there is no layer with name" << layerName; return false; } } /*! Sets whether this object will be drawn antialiased or not. Note that antialiasing settings may be overridden by QCustomPlot::setAntialiasedElements and QCustomPlot::setNotAntialiasedElements. */ void QCPLayerable::setAntialiased(bool enabled) { mAntialiased = enabled; } /*! \internal Moves this layerable object to \a layer. If \a prepend is true, this object will be prepended to the new layer's list, i.e. it will be drawn below the objects already on the layer. If it is false, the object will be appended. Returns true on success, i.e. if \a layer is a valid layer. */ bool QCPLayerable::moveToLayer(QCPLayer *layer, bool prepend) { if (!mParentPlot) { qDebug() << Q_FUNC_INFO << "no parent QCustomPlot set"; return false; } if (layer && layer->parentPlot() != mParentPlot) { qDebug() << Q_FUNC_INFO << "layer" << layer->name() << "is not in same QCustomPlot as this layerable"; return false; } if (mLayer) mLayer->removeChild(this); mLayer = layer; if (mLayer) mLayer->addChild(this, prepend); return true; } /*! \internal Sets the QPainter::Antialiasing render hint on the provided \a painter, depending on the \a localAntialiased value as well as the overrides \ref QCustomPlot::setAntialiasedElements and \ref QCustomPlot::setNotAntialiasedElements. Which override enum this function takes into account is controlled via \a overrideElement. */ void QCPLayerable::applyAntialiasingHint(QCPPainter *painter, bool localAntialiased, QCP::AntialiasedElement overrideElement) const { if (mParentPlot && mParentPlot->notAntialiasedElements().testFlag(overrideElement)) painter->setAntialiasing(false); else if (mParentPlot && mParentPlot->antialiasedElements().testFlag(overrideElement)) painter->setAntialiasing(true); else painter->setAntialiasing(localAntialiased); } /*! \internal Returns the clipping rectangle of this layerable object. By default, this is the viewport of the parent QCustomPlot. Specific subclasses may reimplement this function to provide different clipping rects. The returned clipping rect is set on the painter before the draw function of the respective object is called. */ QRect QCPLayerable::clipRect() const { if (mParentPlot) return mParentPlot->viewport(); else return QRect(); } // ================================================================================ // =================== QCPGrid // ================================================================================ /*! \class QCPGrid \brief Responsible for drawing the grid of a QCPAxis. This class is tightly bound to QCPAxis. Every axis owns a grid instance internally and uses it to draw the grid. Normally, you don't need to interact with the QCPGrid instance, because QCPAxis reproduces the grid interface in its own interface. The axis and grid drawing was split into two classes to allow them to be placed on different layers (both QCPAxis and QCPGrid inherit from QCPLayerable). So it is possible to have the grid at the background and the axes in the foreground, and any plottables/items in between. This described situation is the default setup, see QCPLayer documentation. */ /*! Creates a QCPGrid instance and sets default values. You shouldn't instantiate grids on their own, since every QCPAxis brings its own QCPGrid internally */ QCPGrid::QCPGrid(QCPAxis *parentAxis) : QCPLayerable(parentAxis->parentPlot()), mParentAxis(parentAxis) { setPen(QPen(QColor(200,200,200), 0, Qt::DotLine)); setSubGridPen(QPen(QColor(220,220,220), 0, Qt::DotLine)); setZeroLinePen(QPen(QColor(200,200,200), 0, Qt::SolidLine)); setSubGridVisible(false); setAntialiased(false); setAntialiasedSubGrid(false); setAntialiasedZeroLine(false); } QCPGrid::~QCPGrid() { } /*! Sets whether grid lines at sub tick marks are drawn. \see setSubGridPen */ void QCPGrid::setSubGridVisible(bool visible) { mSubGridVisible = visible; } /*! Sets whether sub grid lines are drawn antialiased. */ void QCPGrid::setAntialiasedSubGrid(bool enabled) { mAntialiasedSubGrid = enabled; } /*! Sets whether zero lines are drawn antialiased. */ void QCPGrid::setAntialiasedZeroLine(bool enabled) { mAntialiasedZeroLine = enabled; } /*! Sets the pen with which (major) grid lines are drawn. */ void QCPGrid::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen with which sub grid lines are drawn. */ void QCPGrid::setSubGridPen(const QPen &pen) { mSubGridPen = pen; } /*! Sets the pen with which zero lines are drawn. Zero lines are lines at coordinate 0 which may be drawn with a different pen than other grid lines. To disable zero lines and just draw normal grid lines at zero, set \a pen to Qt::NoPen. */ void QCPGrid::setZeroLinePen(const QPen &pen) { mZeroLinePen = pen; } /*! \internal A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter before drawing the major grid lines. This is the antialiasing state the painter passed to the \ref draw method is in by default. This function takes into account the local setting of the antialiasing flag as well as the overrides set e.g. with \ref QCustomPlot::setNotAntialiasedElements. \see setAntialiased */ void QCPGrid::applyDefaultAntialiasingHint(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiased, QCP::aeGrid); } /*! \internal Draws grid lines and sub grid lines at the positions of (sub) ticks of the parent axis, spanning over the complete axis rect. Also draws the zero line, if appropriate (\ref setZeroLinePen). Called by QCustomPlot::draw to draw the grid of an axis. */ void QCPGrid::draw(QCPPainter *painter) { if (!mParentAxis->visible()) return; // also don't draw grid when parent axis isn't visible if (mSubGridVisible) drawSubGridLines(painter); drawGridLines(painter); } /*! \internal Draws the main grid lines and possibly a zero line with the specified painter. This is a helper function called by \ref draw. */ void QCPGrid::drawGridLines(QCPPainter *painter) const { int lowTick = mParentAxis->mLowestVisibleTick; int highTick = mParentAxis->mHighestVisibleTick; double t; // helper variable, result of coordinate-to-pixel transforms if (mParentAxis->orientation() == Qt::Horizontal) { // draw zeroline: int zeroLineIndex = -1; if (mZeroLinePen.style() != Qt::NoPen && mParentAxis->mRange.lower < 0 && mParentAxis->mRange.upper > 0) { applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine); painter->setPen(mZeroLinePen); double epsilon = mParentAxis->range().size()*1E-6; // for comparing double to zero for (int i=lowTick; i <= highTick; ++i) { if (qAbs(mParentAxis->mTickVector.at(i)) < epsilon) { zeroLineIndex = i; t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // x painter->drawLine(QLineF(t, mParentAxis->mAxisRect.bottom(), t, mParentAxis->mAxisRect.top())); break; } } } applyDefaultAntialiasingHint(painter); painter->setPen(mPen); for (int i=lowTick; i <= highTick; ++i) { if (i == zeroLineIndex) continue; // don't draw a gridline on top of the zeroline t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // x painter->drawLine(QLineF(t, mParentAxis->mAxisRect.bottom(), t, mParentAxis->mAxisRect.top())); } } else { // draw zeroline: int zeroLineIndex = -1; if (mZeroLinePen.style() != Qt::NoPen && mParentAxis->mRange.lower < 0 && mParentAxis->mRange.upper > 0) { applyAntialiasingHint(painter, mAntialiasedZeroLine, QCP::aeZeroLine); painter->setPen(mZeroLinePen); double epsilon = mParentAxis->mRange.size()*1E-6; // for comparing double to zero for (int i=lowTick; i <= highTick; ++i) { if (qAbs(mParentAxis->mTickVector.at(i)) < epsilon) { zeroLineIndex = i; t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // y painter->drawLine(QLineF(mParentAxis->mAxisRect.left(), t, mParentAxis->mAxisRect.right(), t)); break; } } } // draw grid lines: applyDefaultAntialiasingHint(painter); painter->setPen(mPen); for (int i=lowTick; i <= highTick; ++i) { if (i == zeroLineIndex) continue; // don't draw a gridline on top of the zeroline t = mParentAxis->coordToPixel(mParentAxis->mTickVector.at(i)); // y painter->drawLine(QLineF(mParentAxis->mAxisRect.left(), t, mParentAxis->mAxisRect.right(), t)); } } } /*! \internal Draws the sub grid lines with the specified painter. This is a helper function called by \ref draw. */ void QCPGrid::drawSubGridLines(QCPPainter *painter) const { applyAntialiasingHint(painter, mAntialiasedSubGrid, QCP::aeSubGrid); double t; // helper variable, result of coordinate-to-pixel transforms painter->setPen(mSubGridPen); if (mParentAxis->orientation() == Qt::Horizontal) { for (int i=0; imSubTickVector.size(); ++i) { t = mParentAxis->coordToPixel(mParentAxis->mSubTickVector.at(i)); // x painter->drawLine(QLineF(t, mParentAxis->mAxisRect.bottom(), t, mParentAxis->mAxisRect.top())); } } else { for (int i=0; imSubTickVector.size(); ++i) { t = mParentAxis->coordToPixel(mParentAxis->mSubTickVector.at(i)); // y painter->drawLine(QLineF(mParentAxis->mAxisRect.left(), t, mParentAxis->mAxisRect.right(), t)); } } } // ================================================================================ // =================== QCPItemAnchor // ================================================================================ /*! \class QCPItemAnchor \brief An anchor of an item to which positions can be attached to. An item (QCPAbstractItem) may have one or more anchors. Unlike QCPItemPosition, an anchor doesn't control anything on its item, but provides a way to tie other items via their positions to the anchor. For example, a QCPItemRect is defined by its positions \a topLeft and \a bottomRight. Additionally it has various anchors like \a top, \a topRight or \a bottomLeft etc. So you can attach the \a start (which is a QCPItemPosition) of a QCPItemLine to one of the anchors by calling QCPItemPosition::setParentAnchor on \a start, passing the wanted anchor of the QCPItemRect. This way the start of the line will now always follow the respective anchor location on the rect item. Note that QCPItemPosition derives from QCPItemAnchor, so every position can also serve as an anchor to other positions. To learn how to provide anchors in your own item subclasses, see the subclassing section of the QCPAbstractItem documentation. */ /*! Creates a new QCPItemAnchor. You shouldn't create QCPItemAnchor instances directly, even if you want to make a new item subclass. Use \ref QCPAbstractItem::createAnchor instead, as explained in the subclassing section of the QCPAbstractItem documentation. */ QCPItemAnchor::QCPItemAnchor(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString name, int anchorId) : mParentPlot(parentPlot), mParentItem(parentItem), mAnchorId(anchorId), mName(name) { } QCPItemAnchor::~QCPItemAnchor() { // unregister as parent at children: QList currentChildren(mChildren.toList()); for (int i=0; isetParentAnchor(0); // this acts back on this anchor and child removes itself from mChildren } /*! Returns the final absolute pixel position of the QCPItemAnchor on the QCustomPlot surface. The pixel information is internally retrieved via QCPAbstractItem::anchorPixelPosition of the parent item, QCPItemAnchor is just an intermediary. */ QPointF QCPItemAnchor::pixelPoint() const { if (mParentItem) { if (mAnchorId > -1) { return mParentItem->anchorPixelPoint(mAnchorId); } else { qDebug() << Q_FUNC_INFO << "no valid anchor id set:" << mAnchorId; return QPointF(); } } else { qDebug() << Q_FUNC_INFO << "no parent item set"; return QPointF(); } } /*! \internal Adds \a pos to the child list of this anchor. This is necessary to notify the children prior to destruction of the anchor. Note that this function does not change the parent setting in \a pos. */ void QCPItemAnchor::addChild(QCPItemPosition *pos) { if (!mChildren.contains(pos)) mChildren.insert(pos); else qDebug() << Q_FUNC_INFO << "provided pos is child already" << reinterpret_cast(pos); } /*! \internal Removes \a pos from the child list of this anchor. Note that this function does not change the parent setting in \a pos. */ void QCPItemAnchor::removeChild(QCPItemPosition *pos) { if (!mChildren.remove(pos)) qDebug() << Q_FUNC_INFO << "provided pos isn't child" << reinterpret_cast(pos); } // ================================================================================ // =================== QCPItemBracket // ================================================================================ /*! \class QCPItemBracket \brief A bracket for referencing/highlighting certain parts in the plot. \image html QCPItemBracket.png "Bracket example. Blue dotted circles are anchors, solid blue discs are positions." It has two positions, \a left and \a right, which define the span of the bracket. If \a left is actually farther to the left than \a right, the bracket is opened to the bottom, as shown in the example image. The bracket supports multiple styles via \ref setStyle. The length, i.e. how far the bracket stretches away from the embraced span, can be controlled with \ref setLength. \image html QCPItemBracket-length.png
Demonstrating the effect of different values for \ref setLength, for styles \ref bsCalligraphic and \ref bsSquare. Anchors and positions are displayed for reference.
It provides an anchor \a center, to allow connection of other items, e.g. an arrow (QCPItemLine or QCPItemCurve) or a text label (QCPItemText), to the bracket. */ /*! Creates a bracket item and sets default values. The constructed item can be added to the plot with QCustomPlot::addItem. */ QCPItemBracket::QCPItemBracket(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), left(createPosition("left")), right(createPosition("right")), center(createAnchor("center", aiCenter)) { left->setCoords(0, 0); right->setCoords(1, 1); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue, 2)); setLength(8); setStyle(bsCalligraphic); } QCPItemBracket::~QCPItemBracket() { } /*! Sets the pen that will be used to draw the bracket. Note that when the style is \ref bsCalligraphic, only the color will be taken from the pen, the stroke and width are ignored. To change the apparent stroke width of a calligraphic bracket, use \ref setLength, which has a similar effect. \see setSelectedPen */ void QCPItemBracket::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the bracket when selected \see setPen, setSelected */ void QCPItemBracket::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the \a length in pixels how far the bracket extends in the direction towards the embraced span of the bracket (i.e. perpendicular to the left-right-direction) \image html QCPItemBracket-length.png
Demonstrating the effect of different values for \ref setLength, for styles \ref bsCalligraphic and \ref bsSquare. Anchors and positions are displayed for reference.
*/ void QCPItemBracket::setLength(double length) { mLength = length; } /*! Sets the style of the bracket, i.e. the shape/visual appearance. \see setPen */ void QCPItemBracket::setStyle(QCPItemBracket::BracketStyle style) { mStyle = style; } /* inherits documentation from base class */ double QCPItemBracket::selectTest(const QPointF &pos) const { if (!mVisible) return -1; QVector2D leftVec(left->pixelPoint()); QVector2D rightVec(right->pixelPoint()); if (leftVec.toPoint() == rightVec.toPoint()) return -1; QVector2D widthVec = (rightVec-leftVec)*0.5; QVector2D lengthVec(-widthVec.y(), widthVec.x()); lengthVec = lengthVec.normalized()*mLength; QVector2D centerVec = (rightVec+leftVec)*0.5-lengthVec; return qSqrt(distSqrToLine((centerVec-widthVec).toPointF(), (centerVec+widthVec).toPointF(), pos)); } /* inherits documentation from base class */ void QCPItemBracket::draw(QCPPainter *painter) { QVector2D leftVec(left->pixelPoint()); QVector2D rightVec(right->pixelPoint()); if (leftVec.toPoint() == rightVec.toPoint()) return; QVector2D widthVec = (rightVec-leftVec)*0.5; QVector2D lengthVec(-widthVec.y(), widthVec.x()); lengthVec = lengthVec.normalized()*mLength; QVector2D centerVec = (rightVec+leftVec)*0.5-lengthVec; QPolygon boundingPoly; boundingPoly << leftVec.toPoint() << rightVec.toPoint() << (rightVec-lengthVec).toPoint() << (leftVec-lengthVec).toPoint(); QRect clip = clipRect().adjusted(-mainPen().widthF(), -mainPen().widthF(), mainPen().widthF(), mainPen().widthF()); if (clip.intersects(boundingPoly.boundingRect())) { painter->setPen(mainPen()); switch (mStyle) { case bsSquare: { painter->drawLine((centerVec+widthVec).toPointF(), (centerVec-widthVec).toPointF()); painter->drawLine((centerVec+widthVec).toPointF(), (centerVec+widthVec+lengthVec).toPointF()); painter->drawLine((centerVec-widthVec).toPointF(), (centerVec-widthVec+lengthVec).toPointF()); break; } case bsRound: { painter->setBrush(Qt::NoBrush); QPainterPath path; path.moveTo((centerVec+widthVec+lengthVec).toPointF()); path.cubicTo((centerVec+widthVec).toPointF(), (centerVec+widthVec).toPointF(), centerVec.toPointF()); path.cubicTo((centerVec-widthVec).toPointF(), (centerVec-widthVec).toPointF(), (centerVec-widthVec+lengthVec).toPointF()); painter->drawPath(path); break; } case bsCurly: { painter->setBrush(Qt::NoBrush); QPainterPath path; path.moveTo((centerVec+widthVec+lengthVec).toPointF()); path.cubicTo((centerVec+widthVec*1-lengthVec*0.8).toPointF(), (centerVec+0.4*widthVec+1*lengthVec).toPointF(), centerVec.toPointF()); path.cubicTo((centerVec-0.4*widthVec+1*lengthVec).toPointF(), (centerVec-widthVec*1-lengthVec*0.8).toPointF(), (centerVec-widthVec+lengthVec).toPointF()); painter->drawPath(path); break; } case bsCalligraphic: { painter->setPen(Qt::NoPen); painter->setBrush(QBrush(mainPen().color())); QPainterPath path; path.moveTo((centerVec+widthVec+lengthVec).toPointF()); path.cubicTo((centerVec+widthVec*1-lengthVec*0.8).toPointF(), (centerVec+0.4*widthVec+0.8*lengthVec).toPointF(), centerVec.toPointF()); path.cubicTo((centerVec-0.4*widthVec+0.8*lengthVec).toPointF(), (centerVec-widthVec*1-lengthVec*0.8).toPointF(), (centerVec-widthVec+lengthVec).toPointF()); path.cubicTo((centerVec-widthVec*1-lengthVec*0.5).toPointF(), (centerVec-0.2*widthVec+1.2*lengthVec).toPointF(), (centerVec+lengthVec*0.2).toPointF()); path.cubicTo((centerVec+0.2*widthVec+1.2*lengthVec).toPointF(), (centerVec+widthVec*1-lengthVec*0.5).toPointF(), (centerVec+widthVec+lengthVec).toPointF()); painter->drawPath(path); break; } } } } /* inherits documentation from base class */ QPointF QCPItemBracket::anchorPixelPoint(int anchorId) const { QVector2D leftVec(left->pixelPoint()); QVector2D rightVec(right->pixelPoint()); if (leftVec.toPoint() == rightVec.toPoint()) return leftVec.toPointF(); QVector2D widthVec = (rightVec-leftVec)*0.5; QVector2D lengthVec(-widthVec.y(), widthVec.x()); lengthVec = lengthVec.normalized()*mLength; QVector2D centerVec = (rightVec+leftVec)*0.5-lengthVec; switch (anchorId) { case aiCenter: return centerVec.toPointF(); } qDebug() << Q_FUNC_INFO << "invalid anchorId" << anchorId; return QPointF(); } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemBracket::mainPen() const { return mSelected ? mSelectedPen : mPen; } // ================================================================================ // =================== QCPItemTracer // ================================================================================ /*! \class QCPItemTracer \brief Item that sticks to QCPGraph data points \image html QCPItemTracer.png "Tracer example. Blue dotted circles are anchors, solid blue discs are positions." The tracer can be connected with a QCPGraph via \ref setGraph. Then it will automatically adopt the coordinate axes of the graph and update its \a position to be on the graph's data. This means the key stays controllable via \ref setGraphKey, but the value will follow the graph data. If a QCPGraph is connected, note that setting the coordinates directly via \a position will have no effect, i.e. be overriden in the next redraw (this is when the coodinate update happens). If the specified key in \ref setGraphKey is outside the key bounds of the graph, the tracer will stay at the respective end of the graph. With \ref setInterpolating you may specify whether the tracer may only stay exactly on data points or whether it interpolates data points linearly, if given a key that lies between two data points of the graph. The tracer has different visual styles, see \ref setStyle. It is also possible to make the tracer have no own visual appearance (set the style to \ref tsNone), and just connect other item positions to the tracer \a position (used as an anchor) via \ref QCPItemPosition::setParentAnchor. \note The tracer position is only automatically updated upon redraws. This means when, for example, the data of the graph changes and you immediately afterwards (without a redraw) read the \a position coordinates of the tracer, they will not reflect the updated data of the graph. In this case you should call \ref updatePosition manually, prior to reading the tracer coordinates. */ /*! Creates a tracer item and sets default values. The constructed item can be added to the plot with QCustomPlot::addItem. */ QCPItemTracer::QCPItemTracer(QCustomPlot *parentPlot) : QCPAbstractItem(parentPlot), position(createPosition("position")), mGraph(0) { position->setCoords(0, 0); setBrush(Qt::NoBrush); setSelectedBrush(Qt::NoBrush); setPen(QPen(Qt::black)); setSelectedPen(QPen(Qt::blue, 2)); setStyle(tsCrosshair); setSize(6); setInterpolating(false); setGraphKey(0); } QCPItemTracer::~QCPItemTracer() { } /*! Sets the pen that will be used to draw the line of the tracer \see setSelectedPen, setBrush */ void QCPItemTracer::setPen(const QPen &pen) { mPen = pen; } /*! Sets the pen that will be used to draw the line of the tracer when selected \see setPen, setSelected */ void QCPItemTracer::setSelectedPen(const QPen &pen) { mSelectedPen = pen; } /*! Sets the brush that will be used to draw any fills of the tracer \see setSelectedBrush, setPen */ void QCPItemTracer::setBrush(const QBrush &brush) { mBrush = brush; } /*! Sets the brush that will be used to draw any fills of the tracer, when selected. \see setBrush, setSelected */ void QCPItemTracer::setSelectedBrush(const QBrush &brush) { mSelectedBrush = brush; } /*! Sets the size of the tracer in pixels, if the style supports setting a size (e.g. \ref tsSquare does, \ref tsCrosshair does not). */ void QCPItemTracer::setSize(double size) { mSize = size; } /*! Sets the style/visual appearance of the tracer. If you only want to use the tracer \a position as an anchor for other items, set \a style to \ref tsNone. */ void QCPItemTracer::setStyle(QCPItemTracer::TracerStyle style) { mStyle = style; } /*! Sets the QCPGraph this tracer sticks to. The tracer \a position will be set to type QCPItemPosition::ptPlotCoords and the axes will be set to the axes of \a graph. To free the tracer from any graph, set \a graph to 0. The tracer \a position can then be placed freely like any other item position. This is the state the tracer will assume when its graph gets deleted while still attached to it. \see setGraphKey */ void QCPItemTracer::setGraph(QCPGraph *graph) { if (graph) { if (graph->parentPlot() == mParentPlot) { position->setType(QCPItemPosition::ptPlotCoords); position->setAxes(graph->keyAxis(), graph->valueAxis()); mGraph = graph; updatePosition(); } else qDebug() << Q_FUNC_INFO << "graph isn't in same QCustomPlot instance as this item"; } else { mGraph = 0; } } /*! Sets the key of the graph's data point the tracer will be positioned at. This is the only free cordinate of a tracer when attached to a graph. Depending on \ref setInterpolating, the tracer will be either positioned on the data point closest to \a key, or will stay exactly at \a key and interpolate the value linearly. \see setGraph, setInterpolating */ void QCPItemTracer::setGraphKey(double key) { mGraphKey = key; } /*! Sets whether the value of the graph's data points shall be interpolated, when positioning the tracer. If \a enabled is set to false and a key is given with \ref setGraphKey, the tracer is placed on the data point of the graph which is closest to the key, but which is not necessarily exactly there. If \a enabled is true, the tracer will be positioned exactly at the specified key, and the appropriate value will be interpolated from the graph's data points linearly. \see setGraph, setGraphKey */ void QCPItemTracer::setInterpolating(bool enabled) { mInterpolating = enabled; } /* inherits documentation from base class */ double QCPItemTracer::selectTest(const QPointF &pos) const { if (!mVisible || mStyle == tsNone) return -1; QPointF center(position->pixelPoint()); double w = mSize/2.0; QRect clip = clipRect(); switch (mStyle) { case tsNone: return -1; case tsPlus: { if (clipRect().intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) return qSqrt(qMin(distSqrToLine(center+QPointF(-w, 0), center+QPointF(w, 0), pos), distSqrToLine(center+QPointF(0, -w), center+QPointF(0, w), pos))); break; } case tsCrosshair: { return qSqrt(qMin(distSqrToLine(QPointF(clip.left(), center.y()), QPointF(clip.right(), center.y()), pos), distSqrToLine(QPointF(center.x(), clip.top()), QPointF(center.x(), clip.bottom()), pos))); break; } case tsCircle: { if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) { // distance to border: double centerDist = QVector2D(center-pos).length(); double circleLine = w; double result = qAbs(centerDist-circleLine); // filled ellipse, allow click inside to count as hit: if (result > mParentPlot->selectionTolerance()*0.99 && mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0) { if (centerDist <= circleLine) result = mParentPlot->selectionTolerance()*0.99; } return result; } break; } case tsSquare: { if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) { QRectF rect = QRectF(center-QPointF(w, w), center+QPointF(w, w)); bool filledRect = mBrush.style() != Qt::NoBrush && mBrush.color().alpha() != 0; return rectSelectTest(rect, pos, filledRect); } break; } } return -1; } /* inherits documentation from base class */ void QCPItemTracer::draw(QCPPainter *painter) { updatePosition(); if (mStyle == tsNone) return; painter->setPen(mainPen()); painter->setBrush(mainBrush()); QPointF center(position->pixelPoint()); double w = mSize/2.0; QRect clip = clipRect(); switch (mStyle) { case tsNone: return; case tsPlus: { if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) { painter->drawLine(QLineF(center+QPointF(-w, 0), center+QPointF(w, 0))); painter->drawLine(QLineF(center+QPointF(0, -w), center+QPointF(0, w))); } break; } case tsCrosshair: { if (center.y() > clip.top() && center.y() < clip.bottom()) painter->drawLine(QLineF(clip.left(), center.y(), clip.right(), center.y())); if (center.x() > clip.left() && center.x() < clip.right()) painter->drawLine(QLineF(center.x(), clip.top(), center.x(), clip.bottom())); break; } case tsCircle: { if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) painter->drawEllipse(center, w, w); break; } case tsSquare: { if (clip.intersects(QRectF(center-QPointF(w, w), center+QPointF(w, w)).toRect())) painter->drawRect(QRectF(center-QPointF(w, w), center+QPointF(w, w))); break; } } } /*! If the tracer is connected with a graph (\ref setGraph), this function updates the tracer's \a position to reside on the graph data, depending on the configured key (\ref setGraphKey). It is called automatically on every redraw and normally doesn't need to be called manually. One exception is when you want to read the tracer coordinates via \a position and are not sure that the graph's data (or the tracer key with \ref setGraphKey) hasn't changed since the last redraw. In that situation, call this function before accessing \a position, to make sure you don't get out-of-date coordinates. If there is no graph set on this tracer, this function does nothing. */ void QCPItemTracer::updatePosition() { if (mGraph) { if (mParentPlot->hasPlottable(mGraph)) { if (mGraph->data()->size() > 1) { QCPDataMap::const_iterator first = mGraph->data()->constBegin(); QCPDataMap::const_iterator last = mGraph->data()->constEnd()-1; if (mGraphKey < first.key()) position->setCoords(first.key(), first.value().value); else if (mGraphKey > last.key()) position->setCoords(last.key(), last.value().value); else { QCPDataMap::const_iterator it = first; it = mGraph->data()->lowerBound(mGraphKey); if (it != first) // mGraphKey is somewhere between iterators { QCPDataMap::const_iterator prevIt = it-1; if (mInterpolating) { // interpolate between iterators around mGraphKey: double slope = (it.value().value-prevIt.value().value)/(it.key()-prevIt.key()); position->setCoords(mGraphKey, (mGraphKey-prevIt.key())*slope+prevIt.value().value); } else { // find iterator with key closest to mGraphKey: if (mGraphKey < (prevIt.key()+it.key())*0.5) it = prevIt; position->setCoords(it.key(), it.value().value); } } else // mGraphKey is exactly on first iterator position->setCoords(it.key(), it.value().value); } } else if (mGraph->data()->size() == 1) { QCPDataMap::const_iterator it = mGraph->data()->constBegin(); position->setCoords(it.key(), it.value().value); } else qDebug() << Q_FUNC_INFO << "graph has no data"; } else qDebug() << Q_FUNC_INFO << "graph not contained in QCustomPlot instance (anymore)"; } } /*! \internal Returns the pen that should be used for drawing lines. Returns mPen when the item is not selected and mSelectedPen when it is. */ QPen QCPItemTracer::mainPen() const { return mSelected ? mSelectedPen : mPen; } /*! \internal Returns the brush that should be used for drawing fills of the item. Returns mBrush when the item is not selected and mSelectedBrush when it is. */ QBrush QCPItemTracer::mainBrush() const { return mSelected ? mSelectedBrush : mBrush; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/qcustomplot.h000066400000000000000000002502531321604176500315210ustar00rootroot00000000000000/*************************************************************************** ** ** ** QCustomPlot, a simple to use, modern plotting widget for Qt ** ** Copyright (C) 2012 Emanuel Eichhammer ** ** ** ** 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 3 of the License, 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, see http://www.gnu.org/licenses/. ** ** ** **************************************************************************** ** Author: Emanuel Eichhammer ** ** Website/Contact: http://www.WorksLikeClockwork.com/ ** ** Date: 09.06.12 ** ****************************************************************************/ /*! \file */ #ifndef QCUSTOMPLOT_H #define QCUSTOMPLOT_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // decl definitions for shared library compilation/usage: #if defined(QCUSTOMPLOT_COMPILE_LIBRARY) # define QCP_LIB_DECL Q_DECL_EXPORT #elif defined(QCUSTOMPLOT_USE_LIBRARY) # define QCP_LIB_DECL Q_DECL_IMPORT #else # define QCP_LIB_DECL #endif class QCustomPlot; class QCPLegend; class QCPRange; class QCPLayerable; class QCPAbstractItem; class QCPItemPosition; class QCPAxis; class QCPData; /*! The QCP Namespace contains general enums and QFlags */ namespace QCP { /*! Defines the symbol used for scatter points. On plottables/items that draw scatters, the sizes of these visualizations (with exception of \ref QCP::ssDot and \ref QCP::ssPixmap) can be controlled with a \a setScatterSize function. Scatters are in general drawn with the main pen set on the plottable/item. \see QCPGraph::setScatterStyle, QCPStatisticalBox::setOutlierStyle */ enum ScatterStyle { ssNone ///< no scatter symbols are drawn (e.g. in QCPGraph, data only represented with lines) ,ssDot ///< a single pixel ,ssCross ///< a cross (x) ,ssPlus ///< a plus (+) ,ssCircle ///< a circle which is not filled ,ssDisc ///< a circle which is filled with the color of the pen (not the brush!) ,ssSquare ///< a square which is not filled ,ssDiamond ///< a diamond which is not filled ,ssStar ///< a star with eight arms, i.e. a combination of cross and plus ,ssTriangle ///< an equilateral triangle which is not filled, standing on baseline ,ssTriangleInverted ///< an equilateral triangle which is not filled, standing on corner ,ssCrossSquare ///< a square which is not filled, with a cross inside ,ssPlusSquare ///< a square which is not filled, with a plus inside ,ssCrossCircle ///< a circle which is not filled, with a cross inside ,ssPlusCircle ///< a circle which is not filled, with a plus inside ,ssPeace ///< a circle which is not filled, with one vertical and two downward diagonal lines ,ssPixmap ///< a custom pixmap specified by setScatterPixmap, centered on the data point coordinates }; /*! Defines what elements of a plot can be forcibly drawn antialiased/not antialiased. If an element is neither forcibly drawn antialiased nor forcibly drawn not antialiased, it is up to the respective element how it is drawn. Typically it provides a \a setAntialiased function for this. \c AntialiasedElements is a flag of or-combined elements of this enum type. \see QCustomPlot::setAntialiasedElements, QCustomPlot::setNotAntialiasedElements */ enum AntialiasedElement { aeAxes = 0x0001 ///< 0x0001 Axis base line and tick marks ,aeGrid = 0x0002 ///< 0x0002 Grid lines ,aeSubGrid = 0x0004 ///< 0x0004 Sub grid lines ,aeLegend = 0x0008 ///< 0x0008 Legend box ,aeLegendItems = 0x0010 ///< 0x0010 Legend items ,aePlottables = 0x0020 ///< 0x0020 Main lines of plottables (excluding error bars, see element \ref aeErrorBars) ,aeItems = 0x0040 ///< 0x0040 Main lines of items ,aeScatters = 0x0080 ///< 0x0080 Scatter symbols of plottables (excluding scatter symbols of type ssPixmap) ,aeErrorBars = 0x0100 ///< 0x0100 Error bars ,aeFills = 0x0200 ///< 0x0200 Borders of fills (e.g. under or between graphs) ,aeZeroLine = 0x0400 ///< 0x0400 Zero-lines, see \ref QCPAxis::setZeroLinePen ,aeAll = 0xFFFF ///< 0xFFFF All elements ,aeNone = 0x0000 ///< 0x0000 No elements }; Q_DECLARE_FLAGS(AntialiasedElements, AntialiasedElement) /*! Defines plotting hints that control various aspects of the quality and speed of plotting. \see QCustomPlot::setPlottingHints */ enum PlottingHint { phNone = 0x000 ///< 0x000 No hints are set ,phFastPolylines = 0x001 ///< 0x001 Graph/Curve lines are drawn with a faster method. This reduces the quality ///< especially of the line segment joins. (Only used for solid line pens.) ,phForceRepaint = 0x002 ///< 0x002 causes an immediate repaint() instead of a soft update() when QCustomPlot::replot() is called. This is set by default ///< on Windows-Systems to prevent the plot from freezing on fast consecutive replots (e.g. user drags ranges with mouse). }; Q_DECLARE_FLAGS(PlottingHints, PlottingHint) } Q_DECLARE_OPERATORS_FOR_FLAGS(QCP::AntialiasedElements) Q_DECLARE_OPERATORS_FOR_FLAGS(QCP::PlottingHints) class QCP_LIB_DECL QCPData { public: QCPData(); QCPData(double key, double value); double key, value; double keyErrorPlus, keyErrorMinus; double valueErrorPlus, valueErrorMinus; }; Q_DECLARE_TYPEINFO(QCPData, Q_MOVABLE_TYPE); /*! \typedef QCPDataMap Container for storing QCPData items in a sorted fashion. The key of the map is the key member of the QCPData instance. This is the container in which QCPGraph holds its data. \see QCPData, QCPGraph::setData */ typedef QMap QCPDataMap; typedef QMapIterator QCPDataMapIterator; typedef QMutableMapIterator QCPDataMutableMapIterator; class QCP_LIB_DECL QCPCurveData { public: QCPCurveData(); QCPCurveData(double t, double key, double value); double t, key, value; }; Q_DECLARE_TYPEINFO(QCPCurveData, Q_MOVABLE_TYPE); /*! \typedef QCPCurveDataMap Container for storing QCPCurveData items in a sorted fashion. The key of the map is the t member of the QCPCurveData instance. This is the container in which QCPCurve holds its data. \see QCPCurveData, QCPCurve::setData */ typedef QMap QCPCurveDataMap; typedef QMapIterator QCPCurveDataMapIterator; typedef QMutableMapIterator QCPCurveDataMutableMapIterator; class QCP_LIB_DECL QCPBarData { public: QCPBarData(); QCPBarData(double key, double value); double key, value; }; Q_DECLARE_TYPEINFO(QCPBarData, Q_MOVABLE_TYPE); /*! \typedef QCPBarDataMap Container for storing QCPBarData items in a sorted fashion. The key of the map is the key member of the QCPBarData instance. This is the container in which QCPBars holds its data. \see QCPBarData, QCPBars::setData */ typedef QMap QCPBarDataMap; typedef QMapIterator QCPBarDataMapIterator; typedef QMutableMapIterator QCPBarDataMutableMapIterator; class QCP_LIB_DECL QCPPainter : public QPainter { public: QCPPainter(); QCPPainter(QPaintDevice *device); ~QCPPainter(); // getters: QPixmap scatterPixmap() const { return mScatterPixmap; } bool antialiasing() const { return testRenderHint(QPainter::Antialiasing); } bool pdfExportMode() const { return mPdfExportMode; } bool scaledExportMode() const { return mScaledExportMode; } // setters: void setScatterPixmap(const QPixmap pm); void setAntialiasing(bool enabled); void setPdfExportMode(bool enabled); void setScaledExportMode(bool enabled); // methods hiding non-virtual base class functions (QPainter bug workarounds): void setPen(const QPen &pen); void setPen(const QColor &color); void setPen(Qt::PenStyle penStyle); void drawLine(const QLineF &line); void drawLine(const QPointF &p1, const QPointF &p2) {drawLine(QLineF(p1, p2));} void save(); void restore(); // helpers: void fixScaledPen(); void drawScatter(double x, double y, double size, QCP::ScatterStyle style); protected: QPixmap mScatterPixmap; bool mScaledExportMode; bool mPdfExportMode; bool mIsAntialiasing; QStack mAntialiasingStack; }; class QCP_LIB_DECL QCPLineEnding { public: /*! Defines the type of ending decoration for line-like items, e.g. an arrow. \image html QCPLineEnding.png The width and length of these decorations can be controlled with the functions \ref setWidth and \ref setLength. Some decorations like \ref esDisc, \ref esSquare, \ref esDiamond and \ref esBar only support a width, the length property is ignored. \see QCPItemLine::setHead, QCPItemLine::setTail, QCPItemCurve::setHead, QCPItemCurve::setTail */ enum EndingStyle { esNone ///< No ending decoration ,esFlatArrow ///< A filled arrow head with a straight/flat back (a triangle) ,esSpikeArrow ///< A filled arrow head with an indented back ,esLineArrow ///< A non-filled arrow head with open back ,esDisc ///< A filled circle ,esSquare ///< A filled square ,esDiamond ///< A filled diamond (45?rotated square) ,esBar ///< A bar perpendicular to the line }; QCPLineEnding(); QCPLineEnding(EndingStyle style, double width=8, double length=10, bool inverted=false); // getters: EndingStyle style() const { return mStyle; } double width() const { return mWidth; } double length() const { return mLength; } bool inverted() const { return mInverted; } // setters: void setStyle(EndingStyle style); void setWidth(double width); void setLength(double length); void setInverted(bool inverted); // non-property methods: double boundingDistance() const; void draw(QCPPainter *painter, const QVector2D &pos, const QVector2D &dir) const; void draw(QCPPainter *painter, const QVector2D &pos, double angle) const; protected: EndingStyle mStyle; double mWidth, mLength; bool mInverted; }; Q_DECLARE_TYPEINFO(QCPLineEnding, Q_MOVABLE_TYPE); class QCP_LIB_DECL QCPLayer { public: QCPLayer(QCustomPlot* parentPlot, const QString &layerName); ~QCPLayer(); // getters: QCustomPlot *parentPlot() const { return mParentPlot; } QString name() const { return mName; } int index() const; QList children() const { return mChildren; } protected: QCustomPlot *mParentPlot; QString mName; QList mChildren; void addChild(QCPLayerable *layerable, bool prepend); void removeChild(QCPLayerable *layerable); private: Q_DISABLE_COPY(QCPLayer) friend class QCPLayerable; }; class QCP_LIB_DECL QCPLayerable : public QObject { Q_OBJECT public: QCPLayerable(QCustomPlot *parentPlot); ~QCPLayerable(); // getters: bool visible() const { return mVisible; } QCustomPlot *parentPlot() const { return mParentPlot; } QCPLayer *layer() const { return mLayer; } bool antialiased() const { return mAntialiased; } // setters: void setVisible(bool on); bool setLayer(QCPLayer *layer); bool setLayer(const QString &layerName); void setAntialiased(bool enabled); protected: bool mVisible; QCustomPlot *mParentPlot; QCPLayer *mLayer; bool mAntialiased; // non-property methods: bool moveToLayer(QCPLayer *layer, bool prepend); void applyAntialiasingHint(QCPPainter *painter, bool localAntialiased, QCP::AntialiasedElement overrideElement) const; virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const = 0; virtual QRect clipRect() const; virtual void draw(QCPPainter *painter) = 0; private: Q_DISABLE_COPY(QCPLayerable) friend class QCustomPlot; }; class QCP_LIB_DECL QCPAbstractPlottable : public QCPLayerable { Q_OBJECT public: QCPAbstractPlottable(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPAbstractPlottable() {} // getters: QString name() const { return mName; } bool antialiasedFill() const { return mAntialiasedFill; } bool antialiasedScatters() const { return mAntialiasedScatters; } bool antialiasedErrorBars() const { return mAntialiasedErrorBars; } QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QBrush brush() const { return mBrush; } QBrush selectedBrush() const { return mSelectedBrush; } QCPAxis *keyAxis() const { return mKeyAxis; } QCPAxis *valueAxis() const { return mValueAxis; } bool selectable() const { return mSelectable; } bool selected() const { return mSelected; } // setters: void setName(const QString &name); void setAntialiasedFill(bool enabled); void setAntialiasedScatters(bool enabled); void setAntialiasedErrorBars(bool enabled); void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setBrush(const QBrush &brush); void setSelectedBrush(const QBrush &brush); void setKeyAxis(QCPAxis *axis); void setValueAxis(QCPAxis *axis); void setSelectable(bool selectable); void setSelected(bool selected); // non-property methods: void rescaleAxes(bool onlyEnlarge=false) const; void rescaleKeyAxis(bool onlyEnlarge=false) const; void rescaleValueAxis(bool onlyEnlarge=false) const; virtual void clearData() = 0; virtual double selectTest(const QPointF &pos) const = 0; virtual bool addToLegend(); virtual bool removeFromLegend() const; signals: void selectionChanged(bool selected); protected: /*! Represents negative and positive sign domain for passing to \ref getKeyRange and \ref getValueRange. */ enum SignDomain { sdNegative ///< The negative sign domain, i.e. numbers smaller than zero ,sdBoth ///< Both sign domains, including zero, i.e. all (rational) numbers ,sdPositive ///< The positive sign domain, i.e. numbers greater than zero }; QString mName; bool mAntialiasedFill, mAntialiasedScatters, mAntialiasedErrorBars; QPen mPen, mSelectedPen; QBrush mBrush, mSelectedBrush; QCPAxis *mKeyAxis, *mValueAxis; bool mSelected, mSelectable; virtual QRect clipRect() const; virtual void draw(QCPPainter *painter) = 0; virtual void drawLegendIcon(QCPPainter *painter, const QRect &rect) const = 0; virtual QCPRange getKeyRange(bool &validRange, SignDomain inSignDomain=sdBoth) const = 0; virtual QCPRange getValueRange(bool &validRange, SignDomain inSignDomain=sdBoth) const = 0; // painting and coordinate transformation helpers: void coordsToPixels(double key, double value, double &x, double &y) const; const QPointF coordsToPixels(double key, double value) const; void pixelsToCoords(double x, double y, double &key, double &value) const; void pixelsToCoords(const QPointF &pixelPos, double &key, double &value) const; QPen mainPen() const; QBrush mainBrush() const; void applyDefaultAntialiasingHint(QCPPainter *painter) const; void applyFillAntialiasingHint(QCPPainter *painter) const; void applyScattersAntialiasingHint(QCPPainter *painter) const; void applyErrorBarsAntialiasingHint(QCPPainter *painter) const; // selection test helpers: double distSqrToLine(const QPointF &start, const QPointF &end, const QPointF &point) const; private: Q_DISABLE_COPY(QCPAbstractPlottable) friend class QCustomPlot; friend class QCPPlottableLegendItem; }; class QCP_LIB_DECL QCPGraph : public QCPAbstractPlottable { Q_OBJECT public: /*! Defines how the graph's line is represented visually in the plot. The line is drawn with the current pen of the graph (\ref setPen). \see setLineStyle */ enum LineStyle { lsNone ///< data points are not connected with any lines (e.g. data only represented ///< with symbols according to the scatter style, see \ref setScatterStyle) ,lsLine ///< data points are connected by a straight line ,lsStepLeft ///< line is drawn as steps where the step height is the value of the left data point ,lsStepRight ///< line is drawn as steps where the step height is the value of the right data point ,lsStepCenter ///< line is drawn as steps where the step is in between two data points ,lsImpulse ///< each data point is represented by a line parallel to the value axis, which reaches from the data point to the zero-value-line }; Q_ENUMS(LineStyle) /*! Defines what kind of error bars are drawn for each data point */ enum ErrorType { etNone ///< No error bars are shown ,etKey ///< Error bars for the key dimension of the data point are shown ,etValue ///< Error bars for the value dimension of the data point are shown ,etBoth ///< Error bars for both key and value dimensions of the data point are shown }; Q_ENUMS(ErrorType) explicit QCPGraph(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPGraph(); // getters: const QCPDataMap *data() const { return mData; } LineStyle lineStyle() const { return mLineStyle; } QCP::ScatterStyle scatterStyle() const { return mScatterStyle; } double scatterSize() const { return mScatterSize; } const QPixmap scatterPixmap() const { return mScatterPixmap; } ErrorType errorType() const { return mErrorType; } QPen errorPen() const { return mErrorPen; } double errorBarSize() const { return mErrorBarSize; } bool errorBarSkipSymbol() const { return mErrorBarSkipSymbol; } QCPGraph *channelFillGraph() const { return mChannelFillGraph; } // setters: void setData(QCPDataMap *data, bool copy=false); void setData(const QVector &key, const QVector &value); void setDataKeyError(const QVector &key, const QVector &value, const QVector &keyError); void setDataKeyError(const QVector &key, const QVector &value, const QVector &keyErrorMinus, const QVector &keyErrorPlus); void setDataValueError(const QVector &key, const QVector &value, const QVector &valueError); void setDataValueError(const QVector &key, const QVector &value, const QVector &valueErrorMinus, const QVector &valueErrorPlus); void setDataBothError(const QVector &key, const QVector &value, const QVector &keyError, const QVector &valueError); void setDataBothError(const QVector &key, const QVector &value, const QVector &keyErrorMinus, const QVector &keyErrorPlus, const QVector &valueErrorMinus, const QVector &valueErrorPlus); void setLineStyle(LineStyle ls); void setScatterStyle(QCP::ScatterStyle ss); void setScatterSize(double size); void setScatterPixmap(const QPixmap &pixmap); void setErrorType(ErrorType errorType); void setErrorPen(const QPen &pen); void setErrorBarSize(double size); void setErrorBarSkipSymbol(bool enabled); void setChannelFillGraph(QCPGraph *targetGraph); // non-property methods: void addData(const QCPDataMap &dataMap); void addData(const QCPData &data); void addData(double key, double value); void addData(const QVector &keys, const QVector &values); void removeDataBefore(double key); void removeDataAfter(double key); void removeData(double fromKey, double toKey); void removeData(double key); virtual void clearData(); virtual double selectTest(const QPointF &pos) const; using QCPAbstractPlottable::rescaleAxes; using QCPAbstractPlottable::rescaleKeyAxis; using QCPAbstractPlottable::rescaleValueAxis; virtual void rescaleAxes(bool onlyEnlarge, bool includeErrorBars) const; // overloads base class interface virtual void rescaleKeyAxis(bool onlyEnlarge, bool includeErrorBars) const; // overloads base class interface virtual void rescaleValueAxis(bool onlyEnlarge, bool includeErrorBars) const; // overloads base class interface protected: QCPDataMap *mData; QPen mErrorPen; LineStyle mLineStyle; QCP::ScatterStyle mScatterStyle; double mScatterSize; QPixmap mScatterPixmap; ErrorType mErrorType; double mErrorBarSize; bool mErrorBarSkipSymbol; QCPGraph *mChannelFillGraph; virtual void draw(QCPPainter *painter); virtual void drawLegendIcon(QCPPainter *painter, const QRect &rect) const; // functions to generate plot data points in pixel coordinates: void getPlotData(QVector *lineData, QVector *pointData) const; // plot style specific functions to generate plot data, used by getPlotData: void getScatterPlotData(QVector *pointData) const; void getLinePlotData(QVector *lineData, QVector *pointData) const; void getStepLeftPlotData(QVector *lineData, QVector *pointData) const; void getStepRightPlotData(QVector *lineData, QVector *pointData) const; void getStepCenterPlotData(QVector *lineData, QVector *pointData) const; void getImpulsePlotData(QVector *lineData, QVector *pointData) const; // helper functions for drawing: void drawFill(QCPPainter *painter, QVector *lineData) const; void drawScatterPlot(QCPPainter *painter, QVector *pointData) const; void drawLinePlot(QCPPainter *painter, QVector *lineData) const; void drawImpulsePlot(QCPPainter *painter, QVector *lineData) const; void drawError(QCPPainter *painter, double x, double y, const QCPData &data) const; // helper functions: void getVisibleDataBounds(QCPDataMap::const_iterator &lower, QCPDataMap::const_iterator &upper, int &count) const; void addFillBasePoints(QVector *lineData) const; void removeFillBasePoints(QVector *lineData) const; QPointF lowerFillBasePoint(double lowerKey) const; QPointF upperFillBasePoint(double upperKey) const; const QPolygonF getChannelFillPolygon(const QVector *lineData) const; int findIndexBelowX(const QVector *data, double x) const; int findIndexAboveX(const QVector *data, double x) const; int findIndexBelowY(const QVector *data, double y) const; int findIndexAboveY(const QVector *data, double y) const; double pointDistance(const QPointF &pixelPoint) const; virtual QCPRange getKeyRange(bool &validRange, SignDomain inSignDomain=sdBoth) const; virtual QCPRange getValueRange(bool &validRange, SignDomain inSignDomain=sdBoth) const; virtual QCPRange getKeyRange(bool &validRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface virtual QCPRange getValueRange(bool &validRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface friend class QCustomPlot; friend class QCPLegend; }; class QCP_LIB_DECL QCPCurve : public QCPAbstractPlottable { Q_OBJECT public: /*! Defines how the curve's line is represented visually in the plot. The line is drawn with the current pen of the curve (\ref setPen). \see setLineStyle */ enum LineStyle { lsNone, ///< No line is drawn between data points (e.g. only scatters) lsLine ///< Data points are connected with a straight line }; explicit QCPCurve(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPCurve(); // getters: const QCPCurveDataMap *data() const { return mData; } QCP::ScatterStyle scatterStyle() const { return mScatterStyle; } double scatterSize() const { return mScatterSize; } QPixmap scatterPixmap() const { return mScatterPixmap; } LineStyle lineStyle() const { return mLineStyle; } // setters: void setData(QCPCurveDataMap *data, bool copy=false); void setData(const QVector &t, const QVector &key, const QVector &value); void setData(const QVector &key, const QVector &value); void setScatterStyle(QCP::ScatterStyle style); void setScatterSize(double size); void setScatterPixmap(const QPixmap &pixmap); void setLineStyle(LineStyle style); // non-property methods: void addData(const QCPCurveDataMap &dataMap); void addData(const QCPCurveData &data); void addData(double t, double key, double value); void addData(double key, double value); void addData(const QVector &ts, const QVector &keys, const QVector &values); void removeDataBefore(double t); void removeDataAfter(double t); void removeData(double fromt, double tot); void removeData(double t); virtual void clearData(); virtual double selectTest(const QPointF &pos) const; protected: QCPCurveDataMap *mData; QCP::ScatterStyle mScatterStyle; double mScatterSize; QPixmap mScatterPixmap; LineStyle mLineStyle; virtual void draw(QCPPainter *painter); virtual void drawLegendIcon(QCPPainter *painter, const QRect &rect) const; // drawing helpers: virtual void drawScatterPlot(QCPPainter *painter, const QVector *pointData) const; // helper functions: void getCurveData(QVector *lineData) const; double pointDistance(const QPointF &pixelPoint) const; QPointF outsideCoordsToPixels(double key, double value, int region) const; virtual QCPRange getKeyRange(bool &validRange, SignDomain inSignDomain=sdBoth) const; virtual QCPRange getValueRange(bool &validRange, SignDomain inSignDomain=sdBoth) const; friend class QCustomPlot; friend class QCPLegend; }; class QCP_LIB_DECL QCPBars : public QCPAbstractPlottable { Q_OBJECT public: explicit QCPBars(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPBars(); // getters: double width() const { return mWidth; } QCPBars *barBelow() const { return mBarBelow; } QCPBars *barAbove() const { return mBarAbove; } const QCPBarDataMap *data() const { return mData; } // setters: void setWidth(double width); void setData(QCPBarDataMap *data, bool copy=false); void setData(const QVector &key, const QVector &value); // non-property methods: void moveBelow(QCPBars *bars); void moveAbove(QCPBars *bars); void addData(const QCPBarDataMap &dataMap); void addData(const QCPBarData &data); void addData(double key, double value); void addData(const QVector &keys, const QVector &values); void removeDataBefore(double key); void removeDataAfter(double key); void removeData(double fromKey, double toKey); void removeData(double key); virtual void clearData(); virtual double selectTest(const QPointF &pos) const; protected: QCPBarDataMap *mData; double mWidth; QCPBars *mBarBelow, *mBarAbove; virtual void draw(QCPPainter *painter); virtual void drawLegendIcon(QCPPainter *painter, const QRect &rect) const; QPolygonF getBarPolygon(double key, double value) const; double getBaseValue(double key, bool positive) const; static void connectBars(QCPBars* lower, QCPBars* upper); virtual QCPRange getKeyRange(bool &validRange, SignDomain inSignDomain=sdBoth) const; virtual QCPRange getValueRange(bool &validRange, SignDomain inSignDomain=sdBoth) const; friend class QCustomPlot; friend class QCPLegend; }; class QCP_LIB_DECL QCPStatisticalBox : public QCPAbstractPlottable { Q_OBJECT public: explicit QCPStatisticalBox(QCPAxis *keyAxis, QCPAxis *valueAxis); virtual ~QCPStatisticalBox(); // getters: double key() const { return mKey; } double minimum() const { return mMinimum; } double lowerQuartile() const { return mLowerQuartile; } double median() const { return mMedian; } double upperQuartile() const { return mUpperQuartile; } double maximum() const { return mMaximum; } QVector outliers() const { return mOutliers; } double width() const { return mWidth; } double whiskerWidth() const { return mWhiskerWidth; } QPen whiskerPen() const { return mWhiskerPen; } QPen whiskerBarPen() const { return mWhiskerBarPen; } QPen medianPen() const { return mMedianPen; } double outlierSize() const { return mOutlierSize; } QPen outlierPen() const { return mOutlierPen; } QCP::ScatterStyle outlierStyle() const { return mOutlierStyle; } // setters: void setKey(double key); void setMinimum(double value); void setLowerQuartile(double value); void setMedian(double value); void setUpperQuartile(double value); void setMaximum(double value); void setOutliers(const QVector &values); void setData(double key, double minimum, double lowerQuartile, double median, double upperQuartile, double maximum); void setWidth(double width); void setWhiskerWidth(double width); void setWhiskerPen(const QPen &pen); void setWhiskerBarPen(const QPen &pen); void setMedianPen(const QPen &pen); void setOutlierSize(double pixels); void setOutlierPen(const QPen &pen); void setOutlierStyle(QCP::ScatterStyle style); // non-property methods: virtual void clearData(); virtual double selectTest(const QPointF &pos) const; protected: QVector mOutliers; double mKey, mMinimum, mLowerQuartile, mMedian, mUpperQuartile, mMaximum; double mWidth; double mWhiskerWidth; double mOutlierSize; QPen mWhiskerPen, mWhiskerBarPen, mOutlierPen, mMedianPen; QCP::ScatterStyle mOutlierStyle; virtual void draw(QCPPainter *painter); virtual void drawLegendIcon(QCPPainter *painter, const QRect &rect) const; virtual void drawQuartileBox(QCPPainter *painter, QRectF *quartileBox=0) const; virtual void drawMedian(QCPPainter *painter) const; virtual void drawWhiskers(QCPPainter *painter) const; virtual void drawOutliers(QCPPainter *painter) const; virtual QCPRange getKeyRange(bool &validRange, SignDomain inSignDomain=sdBoth) const; virtual QCPRange getValueRange(bool &validRange, SignDomain inSignDomain=sdBoth) const; friend class QCustomPlot; friend class QCPLegend; }; class QCP_LIB_DECL QCPItemAnchor { public: QCPItemAnchor(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString name, int anchorId=-1); virtual ~QCPItemAnchor(); QString name() const { return mName; } virtual QPointF pixelPoint() const; protected: QCustomPlot *mParentPlot; QCPAbstractItem *mParentItem; int mAnchorId; QString mName; // non-property members: QSet mChildren; void addChild(QCPItemPosition* pos); // called from pos when this anchor is set as parent void removeChild(QCPItemPosition *pos); // called from pos when its parent anchor is reset or pos deleted private: Q_DISABLE_COPY(QCPItemAnchor) friend class QCPItemPosition; }; class QCP_LIB_DECL QCPItemPosition : public QCPItemAnchor { public: /*! Defines the ways an item position can be specified. Thus it defines what the numbers passed to \ref setCoords actually mean. \see setType */ enum PositionType { ptAbsolute ///< Static positioning in pixels, starting from the top left corner of the viewport/widget. ,ptViewportRatio ///< Static positioning given by a ratio of the current viewport (coordinates 0 to 1). ,ptAxisRectRatio ///< Static positioning given by a ratio of the current axis rect (coordinates 0 to 1). ,ptPlotCoords ///< Dynamic positioning at a plot coordinate defined by two axes (see \ref setAxes). }; QCPItemPosition(QCustomPlot *parentPlot, QCPAbstractItem *parentItem, const QString name); virtual ~QCPItemPosition(); // getters: PositionType type() const { return mPositionType; } QCPItemAnchor *parentAnchor() const { return mParentAnchor; } double key() const { return mKey; } double value() const { return mValue; } QPointF coords() const { return QPointF(mKey, mValue); } QCPAxis *keyAxis() const { return mKeyAxis; } QCPAxis *valueAxis() const { return mValueAxis; } virtual QPointF pixelPoint() const; // setters: void setType(PositionType type); bool setParentAnchor(QCPItemAnchor *parentAnchor, bool keepPixelPosition=false); void setCoords(double key, double value); void setCoords(const QPointF &coords); void setAxes(QCPAxis* keyAxis, QCPAxis* valueAxis); void setPixelPoint(const QPointF &pixelPoint); protected: PositionType mPositionType; QCPAxis *mKeyAxis, *mValueAxis; double mKey, mValue; QCPItemAnchor *mParentAnchor; private: Q_DISABLE_COPY(QCPItemPosition) }; class QCP_LIB_DECL QCPAbstractItem : public QCPLayerable { Q_OBJECT public: QCPAbstractItem(QCustomPlot *parentPlot); virtual ~QCPAbstractItem(); // getters: bool clipToAxisRect() const { return mClipToAxisRect; } QCPAxis *clipKeyAxis() const { return mClipKeyAxis; } QCPAxis *clipValueAxis() const { return mClipValueAxis; } bool selectable() const { return mSelectable; } bool selected() const { return mSelected; } // setters: void setClipToAxisRect(bool clip); void setClipAxes(QCPAxis *keyAxis, QCPAxis *valueAxis); void setClipKeyAxis(QCPAxis *axis); void setClipValueAxis(QCPAxis *axis); void setSelectable(bool selectable); void setSelected(bool selected); // non-property methods: virtual double selectTest(const QPointF &pos) const = 0; QList positions() const { return mPositions; } QList anchors() const { return mAnchors; } QCPItemPosition *position(const QString &name) const; QCPItemAnchor *anchor(const QString &name) const; bool hasAnchor(const QString &name) const; protected: bool mClipToAxisRect; QCPAxis *mClipKeyAxis, *mClipValueAxis; bool mSelectable, mSelected; QList mPositions; QList mAnchors; virtual QRect clipRect() const; virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const; virtual void draw(QCPPainter *painter) = 0; // helper functions for subclasses: double distSqrToLine(const QPointF &start, const QPointF &end, const QPointF &point) const; double rectSelectTest(const QRectF &rect, const QPointF &pos, bool filledRect) const; // anchor/position interface: virtual QPointF anchorPixelPoint(int anchorId) const; QCPItemPosition *createPosition(const QString &name); QCPItemAnchor *createAnchor(const QString &name, int anchorId); signals: void selectionChanged(bool selected); private: Q_DISABLE_COPY(QCPAbstractItem) friend class QCustomPlot; friend class QCPItemAnchor; }; class QCP_LIB_DECL QCPItemStraightLine : public QCPAbstractItem { Q_OBJECT public: QCPItemStraightLine(QCustomPlot *parentPlot); virtual ~QCPItemStraightLine(); // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); // non-property methods: virtual double selectTest(const QPointF &pos) const; QCPItemPosition * const point1; QCPItemPosition * const point2; protected: QPen mPen, mSelectedPen; virtual void draw(QCPPainter *painter); // helper functions: double distToStraightLine(const QVector2D &point1, const QVector2D &vec, const QVector2D &point) const; QLineF getRectClippedStraightLine(const QVector2D &point1, const QVector2D &vec, const QRect &rect) const; QPen mainPen() const; }; class QCP_LIB_DECL QCPItemLine : public QCPAbstractItem { Q_OBJECT public: QCPItemLine(QCustomPlot *parentPlot); virtual ~QCPItemLine(); // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QCPLineEnding head() const { return mHead; } QCPLineEnding tail() const { return mTail; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setHead(const QCPLineEnding &head); void setTail(const QCPLineEnding &tail); // non-property methods: virtual double selectTest(const QPointF &pos) const; QCPItemPosition * const start; QCPItemPosition * const end; protected: QPen mPen, mSelectedPen; QCPLineEnding mHead, mTail; virtual void draw(QCPPainter *painter); // helper functions: QLineF getRectClippedLine(const QVector2D &start, const QVector2D &end, const QRect &rect) const; QPen mainPen() const; }; class QCP_LIB_DECL QCPItemEllipse : public QCPAbstractItem { Q_OBJECT public: QCPItemEllipse(QCustomPlot *parentPlot); virtual ~QCPItemEllipse(); // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QBrush brush() const { return mBrush; } QBrush selectedBrush() const { return mSelectedBrush; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setBrush(const QBrush &brush); void setSelectedBrush(const QBrush &brush); // non-property methods: virtual double selectTest(const QPointF &pos) const; QCPItemPosition * const topLeft; QCPItemPosition * const bottomRight; QCPItemAnchor * const topLeftRim; QCPItemAnchor * const top; QCPItemAnchor * const topRightRim; QCPItemAnchor * const right; QCPItemAnchor * const bottomRightRim; QCPItemAnchor * const bottom; QCPItemAnchor * const bottomLeftRim; QCPItemAnchor * const left; protected: enum AnchorIndex {aiTopLeftRim, aiTop, aiTopRightRim, aiRight, aiBottomRightRim, aiBottom, aiBottomLeftRim, aiLeft}; QPen mPen, mSelectedPen; QBrush mBrush, mSelectedBrush; virtual void draw(QCPPainter *painter); virtual QPointF anchorPixelPoint(int anchorId) const; // helper functions: QPen mainPen() const; QBrush mainBrush() const; }; class QCP_LIB_DECL QCPItemRect : public QCPAbstractItem { Q_OBJECT public: QCPItemRect(QCustomPlot *parentPlot); virtual ~QCPItemRect(); // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QBrush brush() const { return mBrush; } QBrush selectedBrush() const { return mSelectedBrush; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setBrush(const QBrush &brush); void setSelectedBrush(const QBrush &brush); // non-property methods: virtual double selectTest(const QPointF &pos) const; QCPItemPosition * const topLeft; QCPItemPosition * const bottomRight; QCPItemAnchor * const top; QCPItemAnchor * const topRight; QCPItemAnchor * const right; QCPItemAnchor * const bottom; QCPItemAnchor * const bottomLeft; QCPItemAnchor * const left; protected: enum AnchorIndex {aiTop, aiTopRight, aiRight, aiBottom, aiBottomLeft, aiLeft}; QPen mPen, mSelectedPen; QBrush mBrush, mSelectedBrush; virtual void draw(QCPPainter *painter); virtual QPointF anchorPixelPoint(int anchorId) const; // helper functions: QPen mainPen() const; QBrush mainBrush() const; }; class QCP_LIB_DECL QCPItemPixmap : public QCPAbstractItem { Q_OBJECT public: QCPItemPixmap(QCustomPlot *parentPlot); virtual ~QCPItemPixmap(); // getters: QPixmap pixmap() const { return mPixmap; } bool scaled() const { return mScaled; } Qt::AspectRatioMode aspectRatioMode() const { return mAspectRatioMode; } QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } // setters; void setPixmap(const QPixmap &pixmap); void setScaled(bool scaled, Qt::AspectRatioMode aspectRatioMode=Qt::KeepAspectRatio); void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); // non-property methods: virtual double selectTest(const QPointF &pos) const; QCPItemPosition * const topLeft; QCPItemPosition * const bottomRight; QCPItemAnchor * const top; QCPItemAnchor * const topRight; QCPItemAnchor * const right; QCPItemAnchor * const bottom; QCPItemAnchor * const bottomLeft; QCPItemAnchor * const left; protected: enum AnchorIndex {aiTop, aiTopRight, aiRight, aiBottom, aiBottomLeft, aiLeft}; QPixmap mPixmap; QPixmap mScaledPixmap; bool mScaled; Qt::AspectRatioMode mAspectRatioMode; QPen mPen, mSelectedPen; virtual void draw(QCPPainter *painter); virtual QPointF anchorPixelPoint(int anchorId) const; // helper functions: void updateScaledPixmap(QRect finalRect=QRect(), bool flipHorz=false, bool flipVert=false); QRect getFinalRect(bool *flippedHorz=0, bool *flippedVert=0) const; QPen mainPen() const; }; class QCP_LIB_DECL QCPItemText : public QCPAbstractItem { Q_OBJECT public: QCPItemText(QCustomPlot *parentPlot); virtual ~QCPItemText(); // getters: QColor color() const { return mColor; } QColor selectedColor() const { return mSelectedColor; } QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QBrush brush() const { return mBrush; } QBrush selectedBrush() const { return mSelectedBrush; } QFont font() const { return mFont; } QFont selectedFont() const { return mSelectedFont; } QString text() const { return mText; } Qt::Alignment positionAlignment() const { return mPositionAlignment; } Qt::Alignment textAlignment() const { return mTextAlignment; } double rotation() const { return mRotation; } QMargins padding() const { return mPadding; } // setters; void setColor(const QColor &color); void setSelectedColor(const QColor &color); void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setBrush(const QBrush &brush); void setSelectedBrush(const QBrush &brush); void setFont(const QFont &font); void setSelectedFont(const QFont &font); void setText(const QString &text); void setPositionAlignment(Qt::Alignment alignment); void setTextAlignment(Qt::Alignment alignment); void setRotation(double degrees); void setPadding(const QMargins &padding); // non-property methods: virtual double selectTest(const QPointF &pos) const; QCPItemPosition * const position; QCPItemAnchor * const topLeft; QCPItemAnchor * const top; QCPItemAnchor * const topRight; QCPItemAnchor * const right; QCPItemAnchor * const bottomRight; QCPItemAnchor * const bottom; QCPItemAnchor * const bottomLeft; QCPItemAnchor * const left; protected: enum AnchorIndex {aiTopLeft, aiTop, aiTopRight, aiRight, aiBottomRight, aiBottom, aiBottomLeft, aiLeft}; QColor mColor, mSelectedColor; QPen mPen, mSelectedPen; QBrush mBrush, mSelectedBrush; QFont mFont, mSelectedFont; QString mText; Qt::Alignment mPositionAlignment; Qt::Alignment mTextAlignment; double mRotation; QMargins mPadding; virtual void draw(QCPPainter *painter); virtual QPointF anchorPixelPoint(int anchorId) const; // helper functions: QPointF getTextDrawPoint(const QPointF &pos, const QRectF &rect, Qt::Alignment positionAlignment) const; QFont mainFont() const; QColor mainColor() const; QPen mainPen() const; QBrush mainBrush() const; }; class QCP_LIB_DECL QCPItemCurve : public QCPAbstractItem { Q_OBJECT public: QCPItemCurve(QCustomPlot *parentPlot); virtual ~QCPItemCurve(); // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QCPLineEnding head() const { return mHead; } QCPLineEnding tail() const { return mTail; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setHead(const QCPLineEnding &head); void setTail(const QCPLineEnding &tail); // non-property methods: virtual double selectTest(const QPointF &pos) const; QCPItemPosition * const start; QCPItemPosition * const startDir; QCPItemPosition * const endDir; QCPItemPosition * const end; protected: QPen mPen, mSelectedPen; QCPLineEnding mHead, mTail; virtual void draw(QCPPainter *painter); // helper functions: QPen mainPen() const; }; class QCP_LIB_DECL QCPItemBracket : public QCPAbstractItem { Q_OBJECT public: enum BracketStyle { bsSquare ///< A brace with angled edges ,bsRound ///< A brace with round edges ,bsCurly ///< A curly brace ,bsCalligraphic ///< A curly brace with varying stroke width giving a calligraphic impression }; QCPItemBracket(QCustomPlot *parentPlot); virtual ~QCPItemBracket(); // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } double length() const { return mLength; } BracketStyle style() const { return mStyle; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setLength(double length); void setStyle(BracketStyle style); // non-property methods: virtual double selectTest(const QPointF &pos) const; QCPItemPosition * const left; QCPItemPosition * const right; QCPItemAnchor * const center; protected: enum AnchorIndex {aiCenter}; QPen mPen, mSelectedPen; double mLength; BracketStyle mStyle; virtual void draw(QCPPainter *painter); virtual QPointF anchorPixelPoint(int anchorId) const; // helper functions: QPen mainPen() const; }; class QCP_LIB_DECL QCPItemTracer : public QCPAbstractItem { Q_OBJECT public: /*! The different visual appearances a tracer item can have. Some styles size may be controlled with \ref setSize. \see setStyle */ enum TracerStyle { tsNone ///< The tracer is not visible ,tsPlus ///< A plus shaped crosshair with limited size ,tsCrosshair ///< A plus shaped crosshair which spans the complete axis rect ,tsCircle ///< A circle ,tsSquare ///< A square }; Q_ENUMS(TracerStyle) QCPItemTracer(QCustomPlot *parentPlot); virtual ~QCPItemTracer(); // getters: QPen pen() const { return mPen; } QPen selectedPen() const { return mSelectedPen; } QBrush brush() const { return mBrush; } QBrush selectedBrush() const { return mSelectedBrush; } double size() const { return mSize; } TracerStyle style() const { return mStyle; } QCPGraph *graph() const { return mGraph; } double graphKey() const { return mGraphKey; } bool interpolating() const { return mInterpolating; } // setters; void setPen(const QPen &pen); void setSelectedPen(const QPen &pen); void setBrush(const QBrush &brush); void setSelectedBrush(const QBrush &brush); void setSize(double size); void setStyle(TracerStyle style); void setGraph(QCPGraph *graph); void setGraphKey(double key); void setInterpolating(bool enabled); // non-property methods: virtual double selectTest(const QPointF &pos) const; void updatePosition(); QCPItemPosition * const position; protected: QPen mPen, mSelectedPen; QBrush mBrush, mSelectedBrush; double mSize; TracerStyle mStyle; QCPGraph *mGraph; double mGraphKey; bool mInterpolating; virtual void draw(QCPPainter *painter); // helper functions: QPen mainPen() const; QBrush mainBrush() const; }; class QCP_LIB_DECL QCPRange { public: double lower, upper; QCPRange(); QCPRange(double lower, double upper); double size() const; double center() const; void normalize(); QCPRange sanitizedForLogScale() const; QCPRange sanitizedForLinScale() const; bool contains(double value) const; static bool validRange(double lower, double upper); static bool validRange(const QCPRange &range); static const double minRange; //1e-280; static const double maxRange; //1e280; }; Q_DECLARE_TYPEINFO(QCPRange, Q_MOVABLE_TYPE); class QCP_LIB_DECL QCPAbstractLegendItem : public QObject { Q_OBJECT public: QCPAbstractLegendItem(QCPLegend *parent); virtual ~QCPAbstractLegendItem() {} // getters: bool antialiased() const { return mAntialiased; } QFont font() const { return mFont; } QColor textColor() const { return mTextColor; } QFont selectedFont() const { return mSelectedFont; } QColor selectedTextColor() const { return mSelectedTextColor; } bool selectable() const { return mSelectable; } bool selected() const { return mSelected; } // setters: void setAntialiased(bool enabled); void setFont(const QFont &font); void setTextColor(const QColor &color); void setSelectedFont(const QFont &font); void setSelectedTextColor(const QColor &color); void setSelectable(bool selectable); void setSelected(bool selected); signals: void selectionChanged(bool selected); protected: QCPLegend *mParentLegend; bool mAntialiased; QFont mFont; QColor mTextColor; QFont mSelectedFont; QColor mSelectedTextColor; bool mSelectable, mSelected; virtual void draw(QCPPainter *painter, const QRect &rect) const = 0; virtual QSize size(const QSize &targetSize) const = 0; void applyAntialiasingHint(QCPPainter *painter) const; private: Q_DISABLE_COPY(QCPAbstractLegendItem) friend class QCPLegend; }; class QCP_LIB_DECL QCPPlottableLegendItem : public QCPAbstractLegendItem { Q_OBJECT public: QCPPlottableLegendItem(QCPLegend *parent, QCPAbstractPlottable *plottable); virtual ~QCPPlottableLegendItem() {} // getters: QCPAbstractPlottable *plottable() { return mPlottable; } bool textWrap() const { return mTextWrap; } // setters: void setTextWrap(bool wrap); protected: QCPAbstractPlottable *mPlottable; bool mTextWrap; QPen getIconBorderPen() const; QColor getTextColor() const; QFont getFont() const; virtual void draw(QCPPainter *painter, const QRect &rect) const; virtual QSize size(const QSize &targetSize) const; }; class QCP_LIB_DECL QCPLegend : public QCPLayerable { Q_OBJECT public: /*! Defines where the legend is positioned inside the QCustomPlot axis rect. */ enum PositionStyle { psManual ///< Position is not changed automatically. Set manually via \ref setPosition ,psTopLeft ///< Legend is positioned in the top left corner of the axis rect with distance to the border corresponding to the currently set top and left margins ,psTop ///< Legend is horizontally centered at the top of the axis rect with distance to the border corresponding to the currently set top margin ,psTopRight ///< Legend is positioned in the top right corner of the axis rect with distance to the border corresponding to the currently set top and right margins ,psRight ///< Legend is vertically centered at the right of the axis rect with distance to the border corresponding to the currently set right margin ,psBottomRight ///< Legend is positioned in the bottom right corner of the axis rect with distance to the border corresponding to the currently set bottom and right margins ,psBottom ///< Legend is horizontally centered at the bottom of the axis rect with distance to the border corresponding to the currently set bottom margin ,psBottomLeft ///< Legend is positioned in the bottom left corner of the axis rect with distance to the border corresponding to the currently set bottom and left margins ,psLeft ///< Legend is vertically centered at the left of the axis rect with distance to the border corresponding to the currently set left margin }; Q_ENUMS(PositionStyle) /*! Defines the selectable parts of a legend */ enum SelectablePart { spNone = 0 ///< None ,spLegendBox = 0x001 ///< The legend box (frame) ,spItems = 0x002 ///< Legend items individually (see \ref selectedItems) }; Q_ENUMS(SelectablePart) Q_DECLARE_FLAGS(SelectableParts, SelectablePart) explicit QCPLegend(QCustomPlot *parentPlot); virtual ~QCPLegend(); // getters: QPen borderPen() const { return mBorderPen; } QBrush brush() const { return mBrush; } QFont font() const { return mFont; } QColor textColor() const { return mTextColor; } PositionStyle positionStyle() const { return mPositionStyle; } QPoint position() const { return mPosition; } bool autoSize() const { return mAutoSize; } QSize size() const { return mSize; } QSize minimumSize() const { return mMinimumSize; } int paddingLeft() const { return mPaddingLeft; } int paddingRight() const { return mPaddingRight; } int paddingTop() const { return mPaddingTop; } int paddingBottom() const { return mPaddingBottom; } int marginLeft() const { return mMarginLeft; } int marginRight() const { return mMarginRight; } int marginTop() const { return mMarginTop; } int marginBottom() const { return mMarginBottom; } int itemSpacing() const { return mItemSpacing; } QSize iconSize() const { return mIconSize; } int iconTextPadding() const { return mIconTextPadding; } QPen iconBorderPen() const { return mIconBorderPen; } SelectableParts selectable() const { return mSelectable; } SelectableParts selected() const { return mSelected; } QPen selectedBorderPen() const { return mSelectedBorderPen; } QPen selectedIconBorderPen() const { return mSelectedIconBorderPen; } QBrush selectedBrush() const { return mSelectedBrush; } QFont selectedFont() const { return mSelectedFont; } QColor selectedTextColor() const { return mSelectedTextColor; } // setters: void setBorderPen(const QPen &pen); void setBrush(const QBrush &brush); void setFont(const QFont &font); void setTextColor(const QColor &color); void setPositionStyle(PositionStyle legendPositionStyle); void setPosition(const QPoint &pixelPosition); void setAutoSize(bool on); void setSize(const QSize &size); void setSize(int width, int height); void setMinimumSize(const QSize &size); void setMinimumSize(int width, int height); void setPaddingLeft(int padding); void setPaddingRight(int padding); void setPaddingTop(int padding); void setPaddingBottom(int padding); void setPadding(int left, int right, int top, int bottom); void setMarginLeft(int margin); void setMarginRight(int margin); void setMarginTop(int margin); void setMarginBottom(int margin); void setMargin(int left, int right, int top, int bottom); void setItemSpacing(int spacing); void setIconSize(const QSize &size); void setIconSize(int width, int height); void setIconTextPadding(int padding); void setIconBorderPen(const QPen &pen); void setSelectable(const SelectableParts &selectable); void setSelected(const SelectableParts &selected); void setSelectedBorderPen(const QPen &pen); void setSelectedIconBorderPen(const QPen &pen); void setSelectedBrush(const QBrush &brush); void setSelectedFont(const QFont &font); void setSelectedTextColor(const QColor &color); // non-property methods: QCPAbstractLegendItem *item(int index) const; QCPPlottableLegendItem *itemWithPlottable(const QCPAbstractPlottable *plottable) const; int itemCount() const; bool hasItem(QCPAbstractLegendItem *item) const; bool hasItemWithPlottable(const QCPAbstractPlottable *plottable) const; bool addItem(QCPAbstractLegendItem *item); bool removeItem(int index); bool removeItem(QCPAbstractLegendItem *item); void clearItems(); QList selectedItems() const; void reArrange(); bool selectTestLegend(const QPointF &pos) const; QCPAbstractLegendItem *selectTestItem(const QPoint pos) const; signals: void selectionChanged(QCPLegend::SelectableParts selection); protected: // simple properties with getters and setters: QPen mBorderPen, mIconBorderPen; QBrush mBrush; QFont mFont; QColor mTextColor; QPoint mPosition; QSize mSize, mMinimumSize, mIconSize; PositionStyle mPositionStyle; bool mAutoSize; int mPaddingLeft, mPaddingRight, mPaddingTop, mPaddingBottom; int mMarginLeft, mMarginRight, mMarginTop, mMarginBottom; int mItemSpacing, mIconTextPadding; SelectableParts mSelected, mSelectable; QPen mSelectedBorderPen, mSelectedIconBorderPen; QBrush mSelectedBrush; QFont mSelectedFont; QColor mSelectedTextColor; // internal or not explicitly exposed properties: QList mItems; QMap mItemBoundingBoxes; virtual void updateSelectionState(); virtual bool handleLegendSelection(QMouseEvent *event, bool additiveSelection, bool &modified); // introduced methods: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const; virtual void draw(QCPPainter *painter); virtual void calculateAutoSize(); virtual void calculateAutoPosition(); // drawing helpers: QPen getBorderPen() const; QBrush getBrush() const; private: Q_DISABLE_COPY(QCPLegend) friend class QCustomPlot; friend class QCPAbstractLegendItem; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QCPLegend::SelectableParts) class QCP_LIB_DECL QCPGrid : public QCPLayerable { Q_OBJECT public: QCPGrid(QCPAxis *parentAxis); ~QCPGrid(); // getters: bool subGridVisible() const { return mSubGridVisible; } bool antialiasedSubGrid() const { return mAntialiasedSubGrid; } bool antialiasedZeroLine() const { return mAntialiasedZeroLine; } QPen pen() const { return mPen; } QPen subGridPen() const { return mSubGridPen; } QPen zeroLinePen() const { return mZeroLinePen; } // setters: void setSubGridVisible(bool visible); void setAntialiasedSubGrid(bool enabled); void setAntialiasedZeroLine(bool enabled); void setPen(const QPen &pen); void setSubGridPen(const QPen &pen); void setZeroLinePen(const QPen &pen); protected: QCPAxis *mParentAxis; bool mSubGridVisible; bool mAntialiasedSubGrid, mAntialiasedZeroLine; QPen mPen, mSubGridPen, mZeroLinePen; virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const; virtual void draw(QCPPainter *painter); // drawing helpers: void drawGridLines(QCPPainter *painter) const; void drawSubGridLines(QCPPainter *painter) const; friend class QCPAxis; }; class QCP_LIB_DECL QCPAxis : public QCPLayerable { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(AxisType axisType READ axisType WRITE setAxisType) Q_PROPERTY(ScaleType scaleType READ scaleType WRITE setScaleType) Q_PROPERTY(double scaleLogBase READ scaleLogBase WRITE setScaleLogBase) Q_PROPERTY(QRect axisRect READ axisRect WRITE setAxisRect) Q_PROPERTY(QCPRange range READ range WRITE setRange) Q_PROPERTY(bool grid READ grid WRITE setGrid) Q_PROPERTY(bool subGrid READ subGrid WRITE setSubGrid) Q_PROPERTY(bool autoTicks READ autoTicks WRITE setAutoTicks) Q_PROPERTY(int autoTickCount READ autoTickCount WRITE setAutoTickCount) Q_PROPERTY(bool autoTickLabels READ autoTickLabels WRITE setAutoTickLabels) Q_PROPERTY(bool autoTickStep READ autoTickStep WRITE setAutoTickStep) Q_PROPERTY(bool autoSubTicks READ autoSubTicks WRITE setAutoSubTicks) Q_PROPERTY(bool ticks READ ticks WRITE setTicks) Q_PROPERTY(bool tickLabels READ tickLabels WRITE setTickLabels) Q_PROPERTY(int tickLabelPadding READ tickLabelPadding WRITE setTickLabelPadding) Q_PROPERTY(LabelType tickLabelType READ tickLabelType WRITE setTickLabelType) Q_PROPERTY(QFont tickLabelFont READ tickLabelFont WRITE setTickLabelFont) Q_PROPERTY(double tickLabelRotation READ tickLabelRotation WRITE setTickLabelRotation) Q_PROPERTY(QString dateTimeFormat READ dateTimeFormat WRITE setDateTimeFormat) Q_PROPERTY(QString numberFormat READ numberFormat WRITE setNumberFormat) Q_PROPERTY(double tickStep READ tickStep WRITE setTickStep) Q_PROPERTY(QVector tickVector READ tickVector WRITE setTickVector) Q_PROPERTY(QVector tickVectorLabels READ tickVectorLabels WRITE setTickVectorLabels) Q_PROPERTY(int subTickCount READ subTickCount WRITE setSubTickCount) Q_PROPERTY(QPen basePen READ basePen WRITE setBasePen) Q_PROPERTY(QPen gridPen READ gridPen WRITE setGridPen) Q_PROPERTY(QPen subGridPen READ subGridPen WRITE setSubGridPen) Q_PROPERTY(QPen tickPen READ tickPen WRITE setTickPen) Q_PROPERTY(QPen subTickPen READ subTickPen WRITE setSubTickPen) Q_PROPERTY(QFont labelFont READ labelFont WRITE setLabelFont) Q_PROPERTY(QString label READ label WRITE setLabel) Q_PROPERTY(int labelPadding READ labelPadding WRITE setLabelPadding) /// \endcond public: /*! Defines at which side of the axis rect the axis will appear. This also affects how the tick marks are drawn, on which side the labels are placed etc. \see setAxisType */ enum AxisType { atLeft ///< Axis is vertical and on the left side of the axis rect of the parent QCustomPlot ,atRight ///< Axis is vertical and on the right side of the axis rect of the parent QCustomPlot ,atTop ///< Axis is horizontal and on the top side of the axis rect of the parent QCustomPlot ,atBottom ///< Axis is horizontal and on the bottom side of the axis rect of the parent QCustomPlot }; Q_ENUMS(AxisType) /*! When automatic tick label generation is enabled (\ref setAutoTickLabels), defines how the numerical value (coordinate) of the tick position is translated into a string that will be drawn at the tick position. \see setTickLabelType */ enum LabelType { ltNumber ///< Tick coordinate is regarded as normal number and will be displayed as such. (see \ref setNumberFormat) ,ltDateTime ///< Tick coordinate is regarded as a date/time (seconds since 1970-01-01T00:00:00 UTC, see QDateTime::toTime_t) and will be displayed and formatted as such. (see \ref setDateTimeFormat) }; Q_ENUMS(LabelType) /*! Defines the scale of an axis. \see setScaleType */ enum ScaleType { stLinear ///< Normal linear scaling ,stLogarithmic ///< Logarithmic scaling with correspondingly transformed plots and (major) tick marks at every base power (see \ref setScaleLogBase). }; Q_ENUMS(ScaleType) /*! Defines the selectable parts of an axis. \see setSelectable, setSelected */ enum SelectablePart { spNone = 0 ///< None of the selectable parts ,spAxis = 0x001 ///< The axis backbone and tick marks ,spTickLabels = 0x002 ///< Tick labels (numbers) of this axis (as a whole, not individually) ,spAxisLabel = 0x004 ///< The axis label }; Q_ENUMS(SelectablePart) Q_DECLARE_FLAGS(SelectableParts, SelectablePart) explicit QCPAxis(QCustomPlot *parentPlot, AxisType type); virtual ~QCPAxis(); // getters: AxisType axisType() const { return mAxisType; } QRect axisRect() const { return mAxisRect; } ScaleType scaleType() const { return mScaleType; } double scaleLogBase() const { return mScaleLogBase; } const QCPRange range() const { return mRange; } bool rangeReversed() const { return mRangeReversed; } bool antialiasedGrid() const { return mGrid->antialiased(); } bool antialiasedSubGrid() const { return mGrid->antialiasedSubGrid(); } bool antialiasedZeroLine() const { return mGrid->antialiasedZeroLine(); } bool grid() const { return mGrid->visible(); } bool subGrid() const { return mGrid->subGridVisible(); } bool autoTicks() const { return mAutoTicks; } int autoTickCount() const { return mAutoTickCount; } bool autoTickLabels() const { return mAutoTickLabels; } bool autoTickStep() const { return mAutoTickStep; } bool autoSubTicks() const { return mAutoSubTicks; } bool ticks() const { return mTicks; } bool tickLabels() const { return mTickLabels; } int tickLabelPadding() const { return mTickLabelPadding; } LabelType tickLabelType() const { return mTickLabelType; } QFont tickLabelFont() const { return mTickLabelFont; } QColor tickLabelColor() const { return mTickLabelColor; } double tickLabelRotation() const { return mTickLabelRotation; } QString dateTimeFormat() const { return mDateTimeFormat; } QString numberFormat() const; int numberPrecision() const { return mNumberPrecision; } double tickStep() const { return mTickStep; } QVector tickVector() const { return mTickVector; } QVector tickVectorLabels() const { return mTickVectorLabels; } int tickLengthIn() const { return mTickLengthIn; } int tickLengthOut() const { return mTickLengthOut; } int subTickCount() const { return mSubTickCount; } int subTickLengthIn() const { return mSubTickLengthIn; } int subTickLengthOut() const { return mSubTickLengthOut; } QPen basePen() const { return mBasePen; } QPen gridPen() const { return mGrid->pen(); } QPen subGridPen() const { return mGrid->subGridPen(); } QPen zeroLinePen() const { return mGrid->zeroLinePen(); } QPen tickPen() const { return mTickPen; } QPen subTickPen() const { return mSubTickPen; } QFont labelFont() const { return mLabelFont; } QColor labelColor() const { return mLabelColor; } QString label() const { return mLabel; } int labelPadding() const { return mLabelPadding; } int padding() const { return mPadding; } SelectableParts selected() const { return mSelected; } SelectableParts selectable() const { return mSelectable; } QFont selectedTickLabelFont() const { return mSelectedTickLabelFont; } QFont selectedLabelFont() const { return mSelectedLabelFont; } QColor selectedTickLabelColor() const { return mSelectedTickLabelColor; } QColor selectedLabelColor() const { return mSelectedLabelColor; } QPen selectedBasePen() const { return mSelectedBasePen; } QPen selectedTickPen() const { return mSelectedTickPen; } QPen selectedSubTickPen() const { return mSelectedSubTickPen; } // setters: void setScaleType(ScaleType type); void setScaleLogBase(double base); void setRange(double lower, double upper); void setRange(double position, double size, Qt::AlignmentFlag alignment); void setRangeLower(double lower); void setRangeUpper(double upper); void setRangeReversed(bool reversed); void setAntialiasedGrid(bool enabled); void setAntialiasedSubGrid(bool enabled); void setAntialiasedZeroLine(bool enabled); void setGrid(bool show); void setSubGrid(bool show); void setAutoTicks(bool on); void setAutoTickCount(int approximateCount); void setAutoTickLabels(bool on); void setAutoTickStep(bool on); void setAutoSubTicks(bool on); void setTicks(bool show); void setTickLabels(bool show); void setTickLabelPadding(int padding); void setTickLabelType(LabelType type); void setTickLabelFont(const QFont &font); void setTickLabelColor(const QColor &color); void setTickLabelRotation(double degrees); void setDateTimeFormat(const QString &format); void setNumberFormat(const QString &formatCode); void setNumberPrecision(int precision); void setTickStep(double step); void setTickVector(const QVector &vec); void setTickVectorLabels(const QVector &vec); void setTickLength(int inside, int outside=0); void setSubTickCount(int count); void setSubTickLength(int inside, int outside=0); void setBasePen(const QPen &pen); void setGridPen(const QPen &pen); void setSubGridPen(const QPen &pen); void setZeroLinePen(const QPen &pen); void setTickPen(const QPen &pen); void setSubTickPen(const QPen &pen); void setLabelFont(const QFont &font); void setLabelColor(const QColor &color); void setLabel(const QString &str); void setLabelPadding(int padding); void setPadding(int padding); void setSelectedTickLabelFont(const QFont &font); void setSelectedLabelFont(const QFont &font); void setSelectedTickLabelColor(const QColor &color); void setSelectedLabelColor(const QColor &color); void setSelectedBasePen(const QPen &pen); void setSelectedTickPen(const QPen &pen); void setSelectedSubTickPen(const QPen &pen); // non-property methods: Qt::Orientation orientation() const { return mOrientation; } void moveRange(double diff); void scaleRange(double factor, double center); void setScaleRatio(const QCPAxis *otherAxis, double ratio=1.0); double pixelToCoord(double value) const; double coordToPixel(double value) const; SelectablePart selectTest(const QPointF &pos) const; public slots: // slot setters: void setRange(const QCPRange &range); void setSelectable(const QCPAxis::SelectableParts &selectable); void setSelected(const QCPAxis::SelectableParts &selected); signals: void ticksRequest(); void rangeChanged(const QCPRange &newRange); void selectionChanged(QCPAxis::SelectableParts selection); protected: // simple properties with getters and setters: QVector mTickVector; QVector mTickVectorLabels; QCPRange mRange; QString mDateTimeFormat; QString mLabel; QRect mAxisRect; QPen mBasePen, mTickPen, mSubTickPen; QFont mTickLabelFont, mLabelFont; QColor mTickLabelColor, mLabelColor; LabelType mTickLabelType; ScaleType mScaleType; AxisType mAxisType; double mTickStep; double mScaleLogBase, mScaleLogBaseLogInv; int mSubTickCount, mTickLengthIn, mTickLengthOut, mSubTickLengthIn, mSubTickLengthOut; int mAutoTickCount; int mTickLabelPadding, mLabelPadding, mPadding; double mTickLabelRotation; bool mTicks, mTickLabels, mAutoTicks, mAutoTickLabels, mAutoTickStep, mAutoSubTicks; bool mRangeReversed; SelectableParts mSelectable, mSelected; QFont mSelectedTickLabelFont, mSelectedLabelFont; QColor mSelectedTickLabelColor, mSelectedLabelColor; QPen mSelectedBasePen, mSelectedTickPen, mSelectedSubTickPen; QRect mAxisSelectionBox, mTickLabelsSelectionBox, mLabelSelectionBox; // internal or not explicitly exposed properties: QCPGrid *mGrid; QVector mSubTickVector; QChar mExponentialChar, mPositiveSignChar; int mNumberPrecision; char mNumberFormatChar; bool mNumberBeautifulPowers, mNumberMultiplyCross; Qt::Orientation mOrientation; int mLowestVisibleTick, mHighestVisibleTick; // internal setters: void setAxisType(AxisType type); void setAxisRect(const QRect &rect); // introduced methods: virtual void setupTickVectors(); virtual void generateAutoTicks(); virtual int calculateAutoSubTickCount(double tickStep) const; virtual int calculateMargin() const; virtual bool handleAxisSelection(QMouseEvent *event, bool additiveSelection, bool &modified); // drawing: virtual void applyDefaultAntialiasingHint(QCPPainter *painter) const; virtual void draw(QCPPainter *painter); virtual void drawTickLabel(QCPPainter *painter, double position, int distanceToAxis, const QString &text, QSize *tickLabelsSize); virtual void getMaxTickLabelSize(const QFont &font, const QString &text, QSize *tickLabelsSize) const; // basic non virtual helpers: void visibleTickBounds(int &lowIndex, int &highIndex) const; double baseLog(double value) const; double basePow(double value) const; // helpers to get the right pen/font depending on selection state: QPen getBasePen() const; QPen getTickPen() const; QPen getSubTickPen() const; QFont getTickLabelFont() const; QFont getLabelFont() const; QColor getTickLabelColor() const; QColor getLabelColor() const; private: Q_DISABLE_COPY(QCPAxis) friend class QCustomPlot; friend class QCPGrid; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QCPAxis::SelectableParts) class QCP_LIB_DECL QCustomPlot : public QWidget { Q_OBJECT /// \cond INCLUDE_QPROPERTIES Q_PROPERTY(QString title READ title WRITE setTitle) Q_PROPERTY(QRect axisRect READ axisRect WRITE setAxisRect) Q_PROPERTY(int marginLeft READ marginLeft WRITE setMarginLeft) Q_PROPERTY(int marginRight READ marginRight WRITE setMarginRight) Q_PROPERTY(int marginTop READ marginTop WRITE setMarginTop) Q_PROPERTY(int marginBottom READ marginBottom WRITE setMarginBottom) Q_PROPERTY(int autoMargin READ autoMargin WRITE setAutoMargin) Q_PROPERTY(QColor color READ color WRITE setColor) Q_PROPERTY(Qt::Orientations rangeDrag READ rangeDrag WRITE setRangeDrag) Q_PROPERTY(Qt::Orientations rangeZoom READ rangeZoom WRITE setRangeZoom) /// \endcond public: /*! Defines the mouse interactions possible with QCustomPlot \c Interactions is a flag of or-combined elements of this enum type. \see setInteractions, setInteraction */ enum Interaction { iRangeDrag = 0x001 ///< 0x001 Axis ranges are draggable (see \ref setRangeDrag, \ref setRangeDragAxes) ,iRangeZoom = 0x002 ///< 0x002 Axis ranges are zoomable with the mouse wheel (see \ref setRangeZoom, \ref setRangeZoomAxes) ,iMultiSelect = 0x004 ///< 0x004 The user can select multiple objects by holding the modifier set by \ref setMultiSelectModifier while clicking ,iSelectTitle = 0x008 ///< 0x008 The plot title is selectable ,iSelectPlottables = 0x010 ///< 0x010 Plottables are selectable ,iSelectAxes = 0x020 ///< 0x020 Axes are selectable (or parts of them, see QCPAxis::setSelectable) ,iSelectLegend = 0x040 ///< 0x040 Legends are selectable (or their child items, see QCPLegend::setSelectable) ,iSelectItems = 0x080 ///< 0x080 Items are selectable (Rectangles, Arrows, Textitems, etc. see \ref QCPAbstractItem) }; Q_ENUMS(Interaction) Q_DECLARE_FLAGS(Interactions, Interaction) /*! Defines how a layer should be inserted relative to a specified other layer. \see addLayer, moveLayer */ enum LayerInsertMode { limBelow ///< Layer is inserted below other layer ,limAbove ///< Layer is inserted above other layer }; Q_ENUMS(LayerInsertMode) explicit QCustomPlot(QWidget *parent = 0); virtual ~QCustomPlot(); // getters: QString title() const { return mTitle; } QFont titleFont() const { return mTitleFont; } QColor titleColor() const { return mTitleColor; } QRect axisRect() const { return mAxisRect; } QRect viewport() const { return mViewport; } int marginLeft() const { return mMarginLeft; } int marginRight() const { return mMarginRight; } int marginTop() const { return mMarginTop; } int marginBottom() const { return mMarginBottom; } bool autoMargin() const { return mAutoMargin; } QColor color() const { return mColor; } Qt::Orientations rangeDrag() const { return mRangeDrag; } Qt::Orientations rangeZoom() const { return mRangeZoom; } QCPAxis *rangeDragAxis(Qt::Orientation orientation); QCPAxis *rangeZoomAxis(Qt::Orientation orientation); double rangeZoomFactor(Qt::Orientation orientation); QCP::AntialiasedElements antialiasedElements() const { return mAntialiasedElements; } QCP::AntialiasedElements notAntialiasedElements() const { return mNotAntialiasedElements; } bool autoAddPlottableToLegend() const { return mAutoAddPlottableToLegend; } QPixmap axisBackground() const { return mAxisBackground; } bool axisBackgroundScaled() const { return mAxisBackgroundScaled; } Qt::AspectRatioMode axisBackgroundScaledMode() const { return mAxisBackgroundScaledMode; } const Interactions interactions() const { return mInteractions; } int selectionTolerance() const { return mSelectionTolerance; } QFont selectedTitleFont() const { return mSelectedTitleFont; } QColor selectedTitleColor() const { return mSelectedTitleColor; } bool titleSelected() const { return mTitleSelected; } bool noAntialiasingOnDrag() const { return mNoAntialiasingOnDrag; } QCP::PlottingHints plottingHints() const { return mPlottingHints; } Qt::KeyboardModifier multiSelectModifier() const { return mMultiSelectModifier; } // setters: void setTitle(const QString &title); void setTitleFont(const QFont &font); void setTitleColor(const QColor &color); void setAxisRect(const QRect &arect); void setMarginLeft(int margin); void setMarginRight(int margin); void setMarginTop(int margin); void setMarginBottom(int margin); void setMargin(int left, int right, int top, int bottom); void setAutoMargin(bool enabled); void setColor(const QColor &color); void setRangeDrag(Qt::Orientations orientations); void setRangeZoom(Qt::Orientations orientations); void setRangeDragAxes(QCPAxis *horizontal, QCPAxis *vertical); void setRangeZoomAxes(QCPAxis *horizontal, QCPAxis *vertical); void setRangeZoomFactor(double horizontalFactor, double verticalFactor); void setRangeZoomFactor(double factor); void setAntialiasedElements(const QCP::AntialiasedElements &antialiasedElements); void setAntialiasedElement(QCP::AntialiasedElement antialiasedElement, bool enabled=true); void setNotAntialiasedElements(const QCP::AntialiasedElements ¬AntialiasedElements); void setNotAntialiasedElement(QCP::AntialiasedElement notAntialiasedElement, bool enabled=true); void setAutoAddPlottableToLegend(bool on); void setAxisBackground(const QPixmap &pm); void setAxisBackground(const QPixmap &pm, bool scaled, Qt::AspectRatioMode mode=Qt::KeepAspectRatioByExpanding); void setAxisBackgroundScaled(bool scaled); void setAxisBackgroundScaledMode(Qt::AspectRatioMode mode); void setInteractions(const Interactions &interactions); void setInteraction(const Interaction &interaction, bool enabled=true); void setSelectionTolerance(int pixels); void setSelectedTitleFont(const QFont &font); void setSelectedTitleColor(const QColor &color); void setTitleSelected(bool selected); void setNoAntialiasingOnDrag(bool enabled); void setPlottingHints(const QCP::PlottingHints &hints); void setPlottingHint(QCP::PlottingHint hint, bool enabled=true); void setMultiSelectModifier(Qt::KeyboardModifier modifier); // non-property methods: // plottable interface: QCPAbstractPlottable *plottable(int index); QCPAbstractPlottable *plottable(); bool addPlottable(QCPAbstractPlottable *plottable); bool removePlottable(QCPAbstractPlottable *plottable); bool removePlottable(int index); int clearPlottables(); int plottableCount() const; QList selectedPlottables() const; QCPAbstractPlottable *plottableAt(const QPointF &pos, bool onlySelectable=false) const; bool hasPlottable(QCPAbstractPlottable *plottable) const; // specialized interface for QCPGraph: QCPGraph *graph(int index) const; QCPGraph *graph() const; QCPGraph *addGraph(QCPAxis *keyAxis=0, QCPAxis *valueAxis=0); bool removeGraph(QCPGraph *graph); bool removeGraph(int index); int clearGraphs(); int graphCount() const; QList selectedGraphs() const; // item interface: QCPAbstractItem *item(int index) const; QCPAbstractItem *item() const; bool addItem(QCPAbstractItem* item); bool removeItem(QCPAbstractItem *item); bool removeItem(int index); int clearItems(); int itemCount() const; QList selectedItems() const; QCPAbstractItem *itemAt(const QPointF &pos, bool onlySelectable=false) const; // layer interface: QCPLayer *layer(const QString &name) const; QCPLayer *layer(int index) const; QCPLayer *currentLayer() const; bool setCurrentLayer(const QString &name); bool setCurrentLayer(QCPLayer *layer); int layerCount() const; bool addLayer(const QString &name, QCPLayer *otherLayer=0, LayerInsertMode insertMode=limAbove); bool removeLayer(QCPLayer *layer); bool moveLayer(QCPLayer *layer, QCPLayer *otherLayer, LayerInsertMode insertMode=limAbove); QList selectedAxes() const; QList selectedLegends() const; void setupFullAxesBox(); bool savePdf(const QString &fileName, bool noCosmeticPen=false, int width=0, int height=0); bool savePng(const QString &fileName, int width=0, int height=0, double scale=1.0, int quality=-1); bool saveJpg(const QString &fileName, int width=0, int height=0, double scale=1.0, int quality=-1); bool saveBmp(const QString &fileName, int width=0, int height=0, double scale=1.0); bool saveRastered(const QString &fileName, int width, int height, double scale, const char *format, int quality=-1); QCPAxis *xAxis, *yAxis, *xAxis2, *yAxis2; QCPLegend *legend; public slots: void deselectAll(); void replot(); void rescaleAxes(); signals: void mouseDoubleClick(QMouseEvent *event); void mousePress(QMouseEvent *event); void mouseMove(QMouseEvent *event); void mouseRelease(QMouseEvent *event); void mouseWheel(QWheelEvent *event); void plottableClick(QCPAbstractPlottable *plottable, QMouseEvent *event); void plottableDoubleClick(QCPAbstractPlottable *plottable, QMouseEvent *event); void itemClick(QCPAbstractItem *item, QMouseEvent *event); void itemDoubleClick(QCPAbstractItem *item, QMouseEvent *event); void axisClick(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event); void axisDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event); void legendClick(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event); void legendDoubleClick(QCPLegend *legend, QCPAbstractLegendItem *item, QMouseEvent *event); void titleClick(QMouseEvent *event); void titleDoubleClick(QMouseEvent *event); void selectionChangedByUser(); void beforeReplot(); void afterReplot(); protected: QString mTitle; QFont mTitleFont, mSelectedTitleFont; QColor mTitleColor, mSelectedTitleColor; QRect mViewport; QRect mAxisRect; int mMarginLeft, mMarginRight, mMarginTop, mMarginBottom; bool mAutoMargin, mAutoAddPlottableToLegend; QColor mColor; QList mPlottables; QList mGraphs; // extra list of items also in mPlottables that are of type QCPGraph QList mItems; QList mLayers; Qt::Orientations mRangeDrag, mRangeZoom; QCPAxis *mRangeDragHorzAxis, *mRangeDragVertAxis, *mRangeZoomHorzAxis, *mRangeZoomVertAxis; double mRangeZoomFactorHorz, mRangeZoomFactorVert; bool mDragging; QCP::AntialiasedElements mAntialiasedElements, mNotAntialiasedElements; QPixmap mAxisBackground; bool mAxisBackgroundScaled; Qt::AspectRatioMode mAxisBackgroundScaledMode; Interactions mInteractions; int mSelectionTolerance; bool mTitleSelected; QRect mTitleBoundingBox; bool mNoAntialiasingOnDrag; // not explicitly exposed properties: QPixmap mPaintBuffer; QPoint mDragStart; QCPRange mDragStartHorzRange, mDragStartVertRange; QPixmap mScaledAxisBackground; bool mReplotting; QCP::AntialiasedElements mAADragBackup, mNotAADragBackup; QCPLayer *mCurrentLayer; QCP::PlottingHints mPlottingHints; Qt::KeyboardModifier mMultiSelectModifier; // reimplemented methods: virtual QSize minimumSizeHint() const; virtual void paintEvent(QPaintEvent *event); virtual void resizeEvent(QResizeEvent *event); virtual void mouseDoubleClickEvent(QMouseEvent *event); virtual void mousePressEvent(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); virtual void wheelEvent(QWheelEvent *event); // event helpers: virtual bool handlePlottableSelection(QMouseEvent *event, bool additiveSelection, bool &modified); virtual bool handleItemSelection(QMouseEvent *event, bool additiveSelection, bool &modified); virtual bool handleAxisSelection(QMouseEvent *event, bool additiveSelection, bool &modified); virtual bool handleTitleSelection(QMouseEvent *event, bool additiveSelection, bool &modified); // introduced methods: virtual void draw(QCPPainter *painter); virtual void drawAxisBackground(QCPPainter *painter); // helpers: void updateAxisRect(); bool selectTestTitle(const QPointF &pos) const; friend class QCPLegend; friend class QCPAxis; friend class QCPLayer; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QCustomPlot::Interactions) #endif // QCUSTOMPLOT_H plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/qt_util.cxx000066400000000000000000001261541321604176500311650ustar00rootroot00000000000000#include "qt_util.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkImageDuplicator.h" #include "itkImageSliceConstIteratorWithIndex.h" #include "itkImageSliceIteratorWithIndex.h" #include "itkImageLinearConstIteratorWithIndex.h" #include //for qRound #include //for qRound #include #include #include "gamma_gui.h" #include #include #include "itk_resample.h" //plm bool QUTIL::QPointF_Compare(const QPointF& ptData1, const QPointF& ptData2) { //return (ptData1.x() > ptData2.x()); //ASCENDING return (ptData1.x() < ptData2.x()); //DESCENDING } void QUTIL::Set2DTo3D(FloatImage2DType::Pointer& spSrcImg2D, UShortImageType::Pointer& spTargetImg3D, int idx, enPLANE iDirection) { if (!spSrcImg2D || !spTargetImg3D) //Target image should be also ready. return; int idxHor = 0; int idxVer = 0; int idxZ = 0; switch (iDirection) { case PLANE_AXIAL: idxHor = 0; idxVer = 1; idxZ = 2; break; case PLANE_FRONTAL: idxHor = 0; idxVer = 2; idxZ = 1; break; case PLANE_SAGITTAL: idxHor = 1; idxVer = 2; idxZ = 0; break; } FloatImage2DType::SizeType imgDim2D = spSrcImg2D->GetBufferedRegion().GetSize(); FloatImage2DType::SpacingType spacing2D = spSrcImg2D->GetSpacing(); FloatImage2DType::PointType origin2D = spSrcImg2D->GetOrigin(); UShortImageType::SizeType imgDim3D = spTargetImg3D->GetBufferedRegion().GetSize(); UShortImageType::SpacingType spacing3D = spTargetImg3D->GetSpacing(); UShortImageType::PointType origin3D = spTargetImg3D->GetOrigin(); //Filtering if (imgDim2D[0] != imgDim3D[idxHor] || imgDim2D[1] != imgDim3D[idxVer] || idx < 0 || idx >= imgDim3D[idxZ]) { cout << "Error: image dimensions is not matching" << endl; cout << "2D= " << imgDim2D << endl; cout << "3D= " << imgDim3D << endl; return; } /*int width = imgDim[idxHor]; int height = imgDim[idxVer];*/ //itk::ImageRegionConstIteratorWithIndex it_2D (spSrcImg2D, spSrcImg2D->GetRequestedRegion()); itk::ImageRegionConstIterator it_2D(spSrcImg2D, spSrcImg2D->GetRequestedRegion()); itk::ImageSliceIteratorWithIndex it_3D(spTargetImg3D, spTargetImg3D->GetRequestedRegion()); it_3D.SetFirstDirection(idxHor); it_3D.SetSecondDirection(idxVer); it_3D.GoToBegin(); int zSize = imgDim3D[idxZ]; it_2D.GoToBegin(); float fVal2D = 0.0; unsigned short outputVal = 0; for (int i = 0; i< zSize && !it_3D.IsAtEnd(); i++) { /*QFileInfo crntFileInfo(arrYKImage[i].m_strFilePath); QString crntFileName = crntFileInfo.fileName(); QString crntPath = strSavingFolder + "/" + crntFileName;*/ //Search matching slice using slice iterator for m_spProjCTImg if (i == idx) { while (!it_3D.IsAtEndOfSlice()) { while (!it_3D.IsAtEndOfLine()) { fVal2D = it_2D.Get(); if (fVal2D < 0.0) outputVal = 0; else if (fVal2D > 65535.0) outputVal = 65535; else outputVal = (unsigned short)qRound(fVal2D); it_3D.Set(outputVal); //float tmpVal = (float)(it_3D.Get()); //in proj image case, this is intensity //it_2D.Set(tmpVal); ++it_2D; ++it_3D; }//while2 it_3D.NextLine(); }//while1 break; } // it_3D.NextSlice(); }//end of for } void QUTIL::Get2DFrom3DByIndex(UShortImageType::Pointer& spSrcImg3D, UShortImage2DType::Pointer& spTargetImg2D, int idx, enPLANE iDirection) { if (!spSrcImg3D) return; int idxHor = 0; int idxVer = 0; int idxZ = 0; switch (iDirection) { case PLANE_AXIAL: idxHor = 0; idxVer = 1; idxZ = 2; break; case PLANE_FRONTAL: idxHor = 0; idxVer = 2; idxZ = 1; break; case PLANE_SAGITTAL: idxHor = 1; idxVer = 2; idxZ = 0; break; } //Create 2D target image based on geometry of 3D UShortImageType::SizeType imgDim = spSrcImg3D->GetBufferedRegion().GetSize(); UShortImageType::SpacingType spacing = spSrcImg3D->GetSpacing(); UShortImageType::PointType origin = spSrcImg3D->GetOrigin(); int width = imgDim[idxHor]; int height = imgDim[idxVer]; int zSize = imgDim[idxZ]; //cout << "Get2DFrom3D zSize = " << zSize << endl; if (idx < 0 || idx >= zSize) { cout << "Error! idx is out of the range" << endl; return; } UShortImage2DType::IndexType idxStart; idxStart[0] = 0; idxStart[1] = 0; UShortImage2DType::SizeType size2D; size2D[0] = imgDim[idxHor]; size2D[1] = imgDim[idxVer]; UShortImage2DType::SpacingType spacing2D; spacing2D[0] = spacing[idxHor]; spacing2D[1] = spacing[idxVer]; UShortImage2DType::PointType origin2D; // origin2D[0] = origin[idxHor]; // origin2D[1] = origin[idxVer]; origin2D[0] = size2D[0] * spacing2D[0] / -2.0; origin2D[1] = size2D[1] * spacing2D[1] / -2.0; UShortImage2DType::RegionType region; region.SetSize(size2D); region.SetIndex(idxStart); //spTargetImg2D is supposed to be empty. if (spTargetImg2D) { cout << "something is here in target image. is it gonna be overwritten?" << endl; } spTargetImg2D = UShortImage2DType::New(); spTargetImg2D->SetRegions(region); spTargetImg2D->SetSpacing(spacing2D); spTargetImg2D->SetOrigin(origin2D); spTargetImg2D->Allocate(); spTargetImg2D->FillBuffer(0); //cout << "src size = " << spSrcImg3D->GetRequestedRegion().GetSize() << " " << endl; //cout << "target image size = " << spTargetImg2D->GetRequestedRegion().GetSize() << " " << endl; itk::ImageSliceConstIteratorWithIndex it_3D(spSrcImg3D, spSrcImg3D->GetRequestedRegion()); itk::ImageRegionIterator it_2D(spTargetImg2D, spTargetImg2D->GetRequestedRegion()); it_3D.SetFirstDirection(idxHor); it_3D.SetSecondDirection(idxVer); it_3D.GoToBegin(); it_2D.GoToBegin(); for (int i = 0; i< zSize && !it_3D.IsAtEnd(); i++) { /*QFileInfo crntFileInfo(arrYKImage[i].m_strFilePath); QString crntFileName = crntFileInfo.fileName(); QString crntPath = strSavingFolder + "/" + crntFileName;*/ //Search matching slice using slice iterator for m_spProjCTImg //cout << "Get2DFrom3D: Slide= " << i << " "; if (i == idx) { while (!it_3D.IsAtEndOfSlice()) //Error here why? { while (!it_3D.IsAtEndOfLine()) { float tmpVal = (float)(it_3D.Get()); //in proj image case, this is intensity it_2D.Set(tmpVal); ++it_2D; ++it_3D; }//while2 it_3D.NextLine(); }//while1 break; } // end if it_3D.NextSlice(); } //end of for //cout << "cnt = " << cnt << " TotCnt " << cntTot << endl; /*YK16GrayImage tmpYK; tmpYK.UpdateFromItkImageFloat(spTargetImg2D); QString str = QString("D:\\testYK\\InsideFunc_%1.raw").arg(idx); tmpYK.SaveDataAsRaw(str.toLocal8Bit().constData());*/ } void QUTIL::Get2DFrom3DByIndex(FloatImageType::Pointer& spSrcImg3D, FloatImage2DType::Pointer& spTargetImg2D, int idx, enPLANE iDirection) { if (!spSrcImg3D) return; int idxHor = 0; int idxVer = 0; int idxZ = 0; switch (iDirection) { case PLANE_AXIAL: idxHor = 0; idxVer = 1; idxZ = 2; break; case PLANE_FRONTAL: idxHor = 0; idxVer = 2; idxZ = 1; break; case PLANE_SAGITTAL: idxHor = 1; idxVer = 2; idxZ = 0; break; } //Create 2D target image based on geometry of 3D FloatImageType::SizeType imgDim = spSrcImg3D->GetBufferedRegion().GetSize(); FloatImageType::SpacingType spacing = spSrcImg3D->GetSpacing(); FloatImageType::PointType origin = spSrcImg3D->GetOrigin(); int width = imgDim[idxHor]; int height = imgDim[idxVer]; int zSize = imgDim[idxZ]; //cout << "Get2DFrom3D zSize = " << zSize << endl; if (idx < 0 || idx >= zSize) { cout << "Error! idx is out of the range" << endl; return; } FloatImage2DType::IndexType idxStart; idxStart[0] = 0; idxStart[1] = 0; FloatImage2DType::SizeType size2D; size2D[0] = imgDim[idxHor]; size2D[1] = imgDim[idxVer]; FloatImage2DType::SpacingType spacing2D; spacing2D[0] = spacing[idxHor]; spacing2D[1] = spacing[idxVer]; FloatImage2DType::PointType origin2D; // origin2D[0] = origin[idxHor]; // origin2D[1] = origin[idxVer]; origin2D[0] = size2D[0] * spacing2D[0] / -2.0; origin2D[1] = size2D[1] * spacing2D[1] / -2.0; FloatImage2DType::RegionType region; region.SetSize(size2D); region.SetIndex(idxStart); //spTargetImg2D is supposed to be empty. if (spTargetImg2D) { cout << "something is here in target image. is it gonna be overwritten?" << endl; } spTargetImg2D = FloatImage2DType::New(); spTargetImg2D->SetRegions(region); spTargetImg2D->SetSpacing(spacing2D); spTargetImg2D->SetOrigin(origin2D); spTargetImg2D->Allocate(); spTargetImg2D->FillBuffer(0); //cout << "src size = " << spSrcImg3D->GetRequestedRegion().GetSize() << " " << endl; //cout << "target image size = " << spTargetImg2D->GetRequestedRegion().GetSize() << " " << endl; itk::ImageSliceConstIteratorWithIndex it_3D(spSrcImg3D, spSrcImg3D->GetRequestedRegion()); itk::ImageRegionIterator it_2D(spTargetImg2D, spTargetImg2D->GetRequestedRegion()); it_3D.SetFirstDirection(idxHor); it_3D.SetSecondDirection(idxVer); it_3D.GoToBegin(); it_2D.GoToBegin(); for (int i = 0; i< zSize && !it_3D.IsAtEnd(); i++) { /*QFileInfo crntFileInfo(arrYKImage[i].m_strFilePath); QString crntFileName = crntFileInfo.fileName(); QString crntPath = strSavingFolder + "/" + crntFileName;*/ //Search matching slice using slice iterator for m_spProjCTImg //cout << "Get2DFrom3D: Slide= " << i << " "; if (i == idx) { while (!it_3D.IsAtEndOfSlice()) //Error here why? { while (!it_3D.IsAtEndOfLine()) { float tmpVal = (float)(it_3D.Get()); //in proj image case, this is intensity it_2D.Set(tmpVal); ++it_2D; ++it_3D; }//while2 it_3D.NextLine(); }//while1 break; } // end if it_3D.NextSlice(); } //end of for } void QUTIL::Get2DFrom3DByPosition(UShortImageType::Pointer& spSrcImg3D, UShortImage2DType::Pointer& spTargImg2D, enPLANE iDirection, double pos, double& finalPos) { if (!spSrcImg3D) return; int idxHor = 0; int idxVer = 0; int idxZ = 0; switch (iDirection) { case PLANE_AXIAL: idxHor = 0; idxVer = 1; idxZ = 2; break; case PLANE_SAGITTAL: idxHor = 1; idxVer = 2; idxZ = 0; break; case PLANE_FRONTAL: idxHor = 0; idxVer = 2; idxZ = 1; break; } //Create 2D target image based on geometry of 3D UShortImageType::SizeType imgDim = spSrcImg3D->GetBufferedRegion().GetSize(); UShortImageType::SpacingType spacing = spSrcImg3D->GetSpacing(); UShortImageType::PointType origin = spSrcImg3D->GetOrigin(); int width = imgDim[idxHor]; int height = imgDim[idxVer]; int zSize = imgDim[idxZ]; //cout << "Get2DFrom3D zSize = " << zSize << endl int iCntSlice = imgDim[idxZ]; int iReqSlice = qRound((pos - origin[idxZ]) / spacing[idxZ]); finalPos = iReqSlice* spacing[idxZ] + origin[idxZ]; if (iReqSlice < 0 || iReqSlice >= iCntSlice) { //cout << "Error! idx is out of the range" << endl; cout << "Error! idx is out of the range" << "iReqSlice= " << iReqSlice << " iCntSlice= " << iCntSlice << endl; cout << " iDirection = " << iDirection << endl; cout << " pos = " << pos << endl; cout << " origin[idxZ] = " << origin[idxZ] << endl; cout << " spacing[idxZ] = " << spacing[idxZ] << endl; return; } UShortImage2DType::IndexType idxStart; idxStart[0] = 0; idxStart[1] = 0; UShortImage2DType::SizeType size2D; size2D[0] = imgDim[idxHor]; size2D[1] = imgDim[idxVer]; UShortImage2DType::SpacingType spacing2D; spacing2D[0] = spacing[idxHor]; spacing2D[1] = spacing[idxVer]; UShortImage2DType::PointType origin2D; origin2D[0] = origin[idxHor]; origin2D[1] = origin[idxVer]; //origin2D[0] = size2D[0] * spacing2D[0] / -2.0; //origin2D[1] = size2D[1] * spacing2D[1] / -2.0; UShortImage2DType::RegionType region; region.SetSize(size2D); region.SetIndex(idxStart); //spTargetImg2D is supposed to be empty. /* if (spTargImg2D) { cout << "something is here in target image. is it gonna be overwritten?" << endl; }*/ spTargImg2D = UShortImage2DType::New(); spTargImg2D->SetRegions(region); spTargImg2D->SetSpacing(spacing2D); spTargImg2D->SetOrigin(origin2D); spTargImg2D->Allocate(); spTargImg2D->FillBuffer(0); itk::ImageSliceConstIteratorWithIndex it_3D(spSrcImg3D, spSrcImg3D->GetRequestedRegion()); itk::ImageRegionIterator it_2D(spTargImg2D, spTargImg2D->GetRequestedRegion()); it_3D.SetFirstDirection(idxHor); it_3D.SetSecondDirection(idxVer); it_3D.GoToBegin(); it_2D.GoToBegin(); for (int i = 0; i< iCntSlice && !it_3D.IsAtEnd(); i++) { if (i == iReqSlice) { while (!it_3D.IsAtEndOfSlice()) //Error here why? { while (!it_3D.IsAtEndOfLine()) { float tmpVal = (float)(it_3D.Get()); //in proj image case, this is intensity it_2D.Set(tmpVal); ++it_2D; ++it_3D; }//while2 it_3D.NextLine(); }//while1 break; } // end if it_3D.NextSlice(); } //end of for } void QUTIL::Get2DFrom3DByPosition(FloatImageType::Pointer& spSrcImg3D, FloatImage2DType::Pointer& spTargImg2D, enPLANE iDirection, double pos, double& finalPos) { if (!spSrcImg3D) return; int idxHor = 0; int idxVer = 0; int idxZ = 0; //bool bUpDownFlip = false; switch (iDirection) { case PLANE_AXIAL: idxHor = 0; idxVer = 1; idxZ = 2; break; case PLANE_SAGITTAL: idxHor = 1; idxVer = 2; idxZ = 0; //bUpDownFlip = true; break; case PLANE_FRONTAL: idxHor = 0; idxVer = 2; idxZ = 1; //bUpDownFlip = true; break; } //Create 2D target image based on geometry of 3D FloatImageType::SizeType imgDim = spSrcImg3D->GetBufferedRegion().GetSize(); FloatImageType::SpacingType spacing = spSrcImg3D->GetSpacing(); FloatImageType::PointType origin = spSrcImg3D->GetOrigin(); int width = imgDim[idxHor]; int height = imgDim[idxVer]; int zSize = imgDim[idxZ]; //cout << "Get2DFrom3D zSize = " << zSize << endl int iCntSlice = imgDim[idxZ]; int iReqSlice = qRound((pos - origin[idxZ]) / spacing[idxZ]); finalPos = iReqSlice* spacing[idxZ] + origin[idxZ]; if (iReqSlice < 0 || iReqSlice >= iCntSlice) { cout << "Error! idx is out of the range" << "iReqSlice= " << iReqSlice << " iCntSlice= " << iCntSlice << endl; cout << " iDirection = " << iDirection << endl; cout << " pos = " << pos << endl; cout << " origin[idxZ] = " << origin[idxZ] << endl; cout << " spacing[idxZ] = " << spacing[idxZ] << endl; return; } FloatImage2DType::IndexType idxStart2D; idxStart2D[0] = 0; idxStart2D[1] = 0; FloatImage2DType::SizeType size2D; size2D[0] = imgDim[idxHor]; size2D[1] = imgDim[idxVer]; FloatImage2DType::SpacingType spacing2D; spacing2D[0] = spacing[idxHor]; spacing2D[1] = spacing[idxVer]; FloatImage2DType::PointType origin2D; origin2D[0] = origin[idxHor]; origin2D[1] = origin[idxVer]; //origin2D[0] = size2D[0] * spacing2D[0] / -2.0; //origin2D[1] = size2D[1] * spacing2D[1] / -2.0; FloatImage2DType::RegionType region; region.SetSize(size2D); region.SetIndex(idxStart2D); //spTargetImg2D is supposed to be empty. /* if (spTargImg2D) { cout << "something is here in target image. is it gonna be overwritten?" << endl; }*/ spTargImg2D = FloatImage2DType::New(); spTargImg2D->SetRegions(region); spTargImg2D->SetSpacing(spacing2D); spTargImg2D->SetOrigin(origin2D); spTargImg2D->Allocate(); spTargImg2D->FillBuffer(0); itk::ImageSliceConstIteratorWithIndex it_3D(spSrcImg3D, spSrcImg3D->GetRequestedRegion()); itk::ImageRegionIterator it_2D(spTargImg2D, spTargImg2D->GetRequestedRegion()); it_3D.SetFirstDirection(idxHor); it_3D.SetSecondDirection(idxVer); it_3D.GoToBegin(); it_2D.GoToBegin(); for (int i = 0; i< iCntSlice && !it_3D.IsAtEnd(); i++) { if (i == iReqSlice) { while (!it_3D.IsAtEndOfSlice()) //Error here why? { while (!it_3D.IsAtEndOfLine()) { float tmpVal = (float)(it_3D.Get()); //in proj image case, this is intensity it_2D.Set(tmpVal); ++it_2D; ++it_3D; }//while2 it_3D.NextLine(); }//while1 break; } // end if it_3D.NextSlice(); } //end of for } bool QUTIL::GetProfile1DByPosition(UShortImage2DType::Pointer& spSrcImg2D, vector& vProfile, float fixedPos, enPROFILE_DIRECTON enDirection) { if (!spSrcImg2D) return false; UShortImage2DType::SizeType imgDim = spSrcImg2D->GetBufferedRegion().GetSize(); UShortImage2DType::SpacingType spacing = spSrcImg2D->GetSpacing(); UShortImage2DType::PointType origin = spSrcImg2D->GetOrigin(); int width = imgDim[0]; int height = imgDim[1]; //itk::ImageSliceConstIteratorWithIndex it_2D(spSrcImg3D, spSrcImg3D->GetRequestedRegion()); itk::ImageLinearConstIteratorWithIndex it_2D(spSrcImg2D, spSrcImg2D->GetRequestedRegion()); //::SetDirection(unsigned int direction) if (!vProfile.empty()) { vProfile.clear(); } QPointF curPt; /*int fixedIdx = 0; int movingIdx = 0;*/ float fValX = 0.0; float fValY = 0.0; it_2D.GoToBegin(); if (enDirection == PRIFLE_HOR) { int fixedY = qRound(fixedPos - origin[1]) / spacing[1]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (i == fixedY) { fValX = (double)(j*spacing[0]) + origin[0]; fValY = (double)(it_2D.Get()); curPt.setX(fValX); curPt.setY(fValY); vProfile.push_back(curPt); } ++it_2D; } if (it_2D.IsAtEnd()) break; } } else if (enDirection == PRIFLE_VER) { int fixedX = qRound(fixedPos - origin[0]) / spacing[0]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (j == fixedX) { fValX = (double)(i*spacing[1]) + origin[1]; // ((i - origin[1])*spacing[1]); fValY = (double)(it_2D.Get()); curPt.setX(fValX); curPt.setY(fValY); vProfile.push_back(curPt); } ++it_2D; } if (it_2D.IsAtEnd()) break; } } if (vProfile.empty()) return false; return true; } bool QUTIL::GetProfile1DByPosition(FloatImage2DType::Pointer& spSrcImg2D, vector& vProfile, float fixedPos, enPROFILE_DIRECTON enDirection) { if (!spSrcImg2D) return false; FloatImage2DType::SizeType imgDim = spSrcImg2D->GetBufferedRegion().GetSize(); FloatImage2DType::SpacingType spacing = spSrcImg2D->GetSpacing(); FloatImage2DType::PointType origin = spSrcImg2D->GetOrigin(); int width = imgDim[0]; int height = imgDim[1]; //itk::ImageSliceConstIteratorWithIndex it_2D(spSrcImg3D, spSrcImg3D->GetRequestedRegion()); itk::ImageLinearConstIteratorWithIndex it_2D(spSrcImg2D, spSrcImg2D->GetRequestedRegion()); //::SetDirection(unsigned int direction) if (!vProfile.empty()) { vProfile.clear(); } QPointF curPt; /*int fixedIdx = 0; int movingIdx = 0;*/ float fValX = 0.0; float fValY = 0.0; it_2D.GoToBegin(); if (enDirection == PRIFLE_HOR) { int fixedY = qRound((fixedPos - origin[1]) / spacing[1]); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (i == fixedY) { fValX = (double)(j*spacing[0]) + origin[0]; fValY = (double)(it_2D.Get()); curPt.setX(fValX); curPt.setY(fValY); vProfile.push_back(curPt); } ++it_2D; } if (it_2D.IsAtEnd()) break; } } else if (enDirection == PRIFLE_VER) { //cout << "PRIFLE_VER" << endl; int fixedX = qRound((fixedPos - origin[0]) / spacing[0]); //cout << "fixedX= " << fixedX << endl; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (j == fixedX) { fValX = (double)(i*spacing[1]) + origin[1]; fValY = (double)(it_2D.Get()); curPt.setX(fValX); curPt.setY(fValY); vProfile.push_back(curPt); } ++it_2D; } if (it_2D.IsAtEnd()) break; } } if (vProfile.empty()) return false; return true; } bool QUTIL::GetProfile1DByIndex(UShortImage2DType::Pointer& spSrcImg2D, vector& vProfile, int fixedIndex, enPROFILE_DIRECTON enDirection) { if (!spSrcImg2D) return false; UShortImage2DType::SizeType imgDim = spSrcImg2D->GetBufferedRegion().GetSize(); UShortImage2DType::SpacingType spacing = spSrcImg2D->GetSpacing(); UShortImage2DType::PointType origin = spSrcImg2D->GetOrigin(); int width = imgDim[0]; int height = imgDim[1]; itk::ImageLinearConstIteratorWithIndex it_2D(spSrcImg2D, spSrcImg2D->GetRequestedRegion()); //::SetDirection(unsigned int direction) if (!vProfile.empty()) { vProfile.clear(); } QPointF curPt; /*int fixedIdx = 0; int movingIdx = 0;*/ float fValX = 0.0; float fValY = 0.0; it_2D.GoToBegin(); if (enDirection == PRIFLE_HOR) { int fixedY = fixedIndex; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (i == fixedY) { fValX = (double)((j - origin[0])*spacing[0]); fValY = (double)(it_2D.Get()); curPt.setX(fValX); curPt.setY(fValY); vProfile.push_back(curPt); } ++it_2D; } if (it_2D.IsAtEnd()) break; } } else if (enDirection == PRIFLE_VER) { int fixedX = fixedIndex; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (j == fixedX) { fValX = (double)((i - origin[1])*spacing[1]); fValY = (double)(it_2D.Get()); curPt.setX(fValX); curPt.setY(fValY); vProfile.push_back(curPt); } ++it_2D; } if (it_2D.IsAtEnd()) break; } } if (vProfile.empty()) return false; return true; } bool QUTIL::GetProfile1DByIndex(FloatImage2DType::Pointer& spSrcImg2D, vector& vProfile, int fixedIndex, enPROFILE_DIRECTON enDirection) { if (!spSrcImg2D) return false; FloatImage2DType::SizeType imgDim = spSrcImg2D->GetBufferedRegion().GetSize(); FloatImage2DType::SpacingType spacing = spSrcImg2D->GetSpacing(); FloatImage2DType::PointType origin = spSrcImg2D->GetOrigin(); int width = imgDim[0]; int height = imgDim[1]; itk::ImageLinearConstIteratorWithIndex it_2D(spSrcImg2D, spSrcImg2D->GetRequestedRegion()); //::SetDirection(unsigned int direction) if (!vProfile.empty()) { vProfile.clear(); } QPointF curPt; /*int fixedIdx = 0; int movingIdx = 0;*/ float fValX = 0.0; float fValY = 0.0; it_2D.GoToBegin(); if (enDirection == PRIFLE_HOR) { int fixedY = fixedIndex; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (i == fixedY) { fValX = (double)((j - origin[0])*spacing[0]); fValY = (double)(it_2D.Get()); curPt.setX(fValX); curPt.setY(fValY); vProfile.push_back(curPt); } ++it_2D; } if (it_2D.IsAtEnd()) break; } } else if (enDirection == PRIFLE_VER) { int fixedX = fixedIndex; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (j == fixedX) { fValX = (double)((i - origin[1])*spacing[1]); fValY = (double)(it_2D.Get()); curPt.setX(fValX); curPt.setY(fValY); vProfile.push_back(curPt); } ++it_2D; } if (it_2D.IsAtEnd()) break; } } if (vProfile.empty()) return false; return true; } void QUTIL::LoadFloatImage2D(const char* filePath, FloatImage2DType::Pointer& spTargImg2D) { typedef itk::ImageFileReader ReaderType; ReaderType::Pointer reader = ReaderType::New(); QString strPath = filePath; if (strPath.length() < 1) return; reader->SetFileName(strPath.toLocal8Bit().constData()); reader->Update(); spTargImg2D = reader->GetOutput(); } void QUTIL::LoadFloatImage3D(const char* filePath, FloatImageType::Pointer& spTargImg3D) { typedef itk::ImageFileReader ReaderType; ReaderType::Pointer reader = ReaderType::New();//error! QString strPath = filePath; //strPath = "D:\\RD_Beam2\\RD_Beam1_comp.mha"; if (strPath.length() < 1) return; reader->SetFileName(strPath.toLocal8Bit().constData()); reader->Update(); spTargImg3D = reader->GetOutput(); } void QUTIL::SaveFloatImage2D(const char* filePath, FloatImage2DType::Pointer& spSrcImg2D) { if (!spSrcImg2D) return; QString strPath = filePath; if (strPath.length() < 1) return; typedef itk::ImageFileWriter WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetFileName(strPath.toLocal8Bit().constData()); writer->SetUseCompression(true); //not exist in original code (rtkfdk) writer->SetInput(spSrcImg2D); writer->Update(); cout << "Writing image file was succeeded: " << strPath.toLocal8Bit().constData() << endl; } void QUTIL::SaveFloatImage3D(const char* filePath, FloatImageType::Pointer& spSrcImg3D) { if (!spSrcImg3D) return; QString strPath = filePath; if (strPath.length() < 1) return; typedef itk::ImageFileWriter WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetFileName(strPath.toLocal8Bit().constData()); writer->SetUseCompression(true); //not exist in original code (rtkfdk) writer->SetInput(spSrcImg3D); writer->Update(); cout << "Writing image file was succeeded: " << strPath.toLocal8Bit().constData() << endl; } QStringList QUTIL::LoadTextFile(const char* txtFilePath) { QStringList resultStrList; ifstream fin; fin.open(txtFilePath); if (fin.fail()) return resultStrList; char str[MAX_LINE_LENGTH]; while (!fin.eof()) { memset(str, 0, MAX_LINE_LENGTH); fin.getline(str, MAX_LINE_LENGTH); QString tmpStr = QString(str); resultStrList.append(tmpStr); //resultStrList.append("\n"); } fin.close(); return resultStrList; } void QUTIL::LoadColorTableFromFile(const char* filePath, vector& vRGBTable) { vRGBTable.clear(); QStringList resultStrList; ifstream fin; fin.open(filePath); if (fin.fail()) { cout << "No such file found: " << filePath << endl; return; } char str[MAX_LINE_LENGTH]; VEC3D curRGB; while (!fin.eof()) { memset(str, 0, MAX_LINE_LENGTH); fin.getline(str, MAX_LINE_LENGTH); QString tmpStr = QString(str); resultStrList = tmpStr.split("\t"); if (resultStrList.count() == 3) { curRGB.x = resultStrList.at(0).toFloat(); curRGB.y = resultStrList.at(1).toFloat(); curRGB.z = resultStrList.at(2).toFloat(); } vRGBTable.push_back(curRGB); } fin.close(); return; } void QUTIL::LoadColorTableInternal(vector& vRGBTable, enCOLOR_TABLE col_table) { vRGBTable.clear(); int i = 0; int iCntItem = 0; VEC3D curRGB; if (col_table == COL_TABLE_JET) { iCntItem = NUM_OF_TBL_ITEM_JET; for (int i = 0; i < iCntItem; i++) { curRGB.x = (float)colormap_jet[i][0]; curRGB.y = (float)colormap_jet[i][1]; curRGB.z = (float)colormap_jet[i][2]; } vRGBTable.push_back(curRGB); } else if (col_table == COL_TABLE_GAMMA) { iCntItem = NUM_OF_TBL_ITEM_GAMMA; for (int i = 0; i < iCntItem; i++) { curRGB.x = (float)colormap_customgamma[i][0]; curRGB.y = (float)colormap_customgamma[i][1]; curRGB.z = (float)colormap_customgamma[i][2]; } vRGBTable.push_back(curRGB); } return; } VEC3D QUTIL::GetRGBValueFromTable(vector& vRGBTable, float fMinGray, float fMaxGray, float fLookupGray) { VEC3D resultRGB = { 0.0, 0.0, 0.0 }; float width = fMaxGray - fMinGray; if (width <= 0) return resultRGB; float fractionGray = (fLookupGray - fMinGray) / width; int numDiscret = vRGBTable.size(); if (numDiscret < 1) return resultRGB; int lookupIdx = qRound(fractionGray*numDiscret); if (lookupIdx < numDiscret) { resultRGB = vRGBTable.at(lookupIdx); } else { resultRGB = vRGBTable.at(numDiscret - 1); } return resultRGB; } QString QUTIL::GetTimeStampDirPath(const QString& curDirPath, const QString& preFix, const QString& endFix) { QDate curDate = QDate::currentDate(); QString strDateStamp = curDate.toString("YYMMDD"); QTime curTime = QTime::currentTime(); QString strTimeStamp = curTime.toString("hhmmss"); //QDir tmpPlmDir = QDir(curDirPath); /* if (!tmpPlmDir.exists()) { cout << "Error! No curDirPath is available." << tmpPlmDir.absolutePath().toLocal8Bit().constData() << endl; return; }*/ QString strOutput = curDirPath + "/" + preFix + strDateStamp+"_" +strTimeStamp + endFix; return strOutput; } QString QUTIL::GetTimeStampDirName(const QString& preFix, const QString& endFix) { QDate curDate = QDate::currentDate(); QString strDateStamp = curDate.toString("yyMMdd"); QTime curTime = QTime::currentTime(); QString strTimeStamp = curTime.toString("hhmmss"); QString strOutput = preFix + strDateStamp + "_" + strTimeStamp + endFix; return strOutput; } void QUTIL::ShowErrorMessage(QString str) { cout << str.toLocal8Bit().constData() << endl; QMessageBox msgBox; msgBox.setText(str); msgBox.exec(); } void QUTIL::CreateItkDummyImg(FloatImageType::Pointer& spTarget, int sizeX, int sizeY, int sizeZ, float fillVal) { FloatImageType::IndexType idxStart; idxStart[0] = 0; idxStart[1] = 0; idxStart[2] = 0; FloatImageType::SizeType size3D; size3D[0] = sizeX; size3D[1] = sizeY; size3D[2] = sizeZ; FloatImageType::SpacingType spacing3D; spacing3D[0] = 1; spacing3D[1] = 1; spacing3D[2] = 1; FloatImageType::PointType origin3D; origin3D[0] = size3D[0] * spacing3D[0] / -2.0; origin3D[1] = size3D[1] * spacing3D[1] / -2.0; FloatImageType::RegionType region; region.SetSize(size3D); region.SetIndex(idxStart); //spTargetImg2D is supposed to be empty. if (spTarget) { cout << "something is here in target image. is it gonna be overwritten?" << endl; } spTarget = FloatImageType::New(); spTarget->SetRegions(region); spTarget->SetSpacing(spacing3D); spTarget->SetOrigin(origin3D); spTarget->Allocate(); spTarget->FillBuffer(fillVal); } void QUTIL::PrintStrList(QStringList& strList) { int size = strList.count(); for (int i = 0; i < size; i++) { cout << strList.at(i).toLocal8Bit().constData() << endl; } } QString QUTIL::GetPathWithEndFix(const QString& curFilePath, const QString& strEndFix) { QFileInfo fInfo(curFilePath); /*QString strDirPath = fInfo.absolutePath(); QString strBaseName = fInfo.completeBaseName(); QString strSuffixName = fInfo.completeSuffix();*/ QString strResult = fInfo.absolutePath() + "/" + fInfo.completeBaseName() + strEndFix + "." + fInfo.completeSuffix(); return strResult; } // //void QUTIL::UpdateFloatTable3(vector& vData1, vector& vData2, vector& vData3, // QStandardItemModel* pTableModel, gamma_gui* pParent) //{ // int numOfData = 3; // // if (pTableModel != NULL) // { // delete pTableModel; // pTableModel = NULL; // } // // int columnSize = 1; // int rowSize1, rowSize2, rowSize3 = 0; // // columnSize = numOfData * 2; // // rowSize1 = vData1.size(); // rowSize2 = vData2.size(); // rowSize3 = vData3.size(); // // int maxRowSize = 0; // if (rowSize1 > rowSize2) // { // if (rowSize1 < rowSize3) // maxRowSize = rowSize3; // else // maxRowSize = rowSize1; // // } // else // { // if (rowSize2 < rowSize3) // maxRowSize = rowSize3; // else // maxRowSize = rowSize2; // } // // if (maxRowSize == 0) // { // cout << "MaxRowSize is 0" << endl; // return; // } // // // pTableModel = new QStandardItemModel(maxRowSize, columnSize, pParent); //2 Rows and 3 Columns // pTableModel->setHorizontalHeaderItem(0, new QStandardItem(QString("x1"))); // pTableModel->setHorizontalHeaderItem(1, new QStandardItem(QString("y1"))); // pTableModel->setHorizontalHeaderItem(2, new QStandardItem(QString("x2"))); // pTableModel->setHorizontalHeaderItem(3, new QStandardItem(QString("y2"))); // pTableModel->setHorizontalHeaderItem(4, new QStandardItem(QString("x3"))); // pTableModel->setHorizontalHeaderItem(5, new QStandardItem(QString("y3"))); // // // for (int i = 0; i < maxRowSize; i++) // { // qreal tmpVal1 = vData1.at(i).x(); // qreal tmpVal2 = vData1.at(i).y(); // // pTableModel->setItem(i, 0, new QStandardItem(QString("%1").arg(tmpVal1))); // pTableModel->setItem(i, 1, new QStandardItem(QString("%1").arg(tmpVal2))); // // if (i < rowSize2) // { // // tmpVal1 = vData2.at(i).x(); // tmpVal2 = vData2.at(i).y(); // pTableModel->setItem(i, 2, new QStandardItem(QString("%1").arg(tmpVal1))); // pTableModel->setItem(i, 3, new QStandardItem(QString("%1").arg(tmpVal2))); // } // // if (i < rowSize3) // { // tmpVal1 = vData3.at(i).x(); // tmpVal2 = vData3.at(i).y(); // pTableModel->setItem(i, 4, new QStandardItem(QString("%1").arg(tmpVal1))); // pTableModel->setItem(i, 5, new QStandardItem(QString("%1").arg(tmpVal2))); // } // } // // if (pTableModel == NULL) // { // cout << "weird!" << endl; // } //} void QUTIL::GenDefaultCommandFile(QString strPathCommandFile, enRegisterOption regiOption) { ofstream fout; fout.open(strPathCommandFile.toLocal8Bit().constData()); if (fout.fail()) { cout << "File writing error! " << endl; return; } fout << "#Plastimatch command file for registration.txt" << endl; fout << "[GLOBAL]" << endl; fout << "fixed=" << "TBD" << endl; fout << "moving=" << "TBD" << endl; /* if (strPathFixedMask.length() > 1) { fout << "fixed_roi=" << "TBD" << endl; }*/ fout << "img_out=" << "TBD" << endl; fout << "xform_out=" << "TBD" << endl; fout << endl; //QString strOptim = "mse"; QString optionStr; QStringList optionList; switch (regiOption) { case PLAST_RIGID: fout << "[STAGE]" << endl; fout << "xform=" << "rigid" << endl; fout << "optim=" << "versor" << endl; fout << "impl=" << "itk" << endl; fout << "threading=" << "openmp" << endl; fout << "background_val=" << "-1024" << endl; //fout << "background_val=" << "0" << endl; //-600 in HU //added fout << "max_its=" << "50" << endl; break; case PLAST_AFFINE: fout << "[STAGE]" << endl; fout << "xform=" << "rigid" << endl; fout << "optim=" << "versor" << endl; fout << "impl=" << "itk" << endl; fout << "threading=" << "openmp" << endl; fout << "background_val=" << "-1024" << endl; //fout << "background_val=" << "0" << endl; //-600 in HU //added fout << "max_its=" << "50" << endl; fout << endl; break; case PLAST_GRADIENT: fout << "#For gradient-based searching, moving image should be smaller than fixed image. So, CBCT image might move rather than CT" << endl; optionStr = "0.7, 0.7, 0.7"; optionList = optionStr.split(","); fout << "[PROCESS]" << endl; fout << "action=adjust" << endl; fout << "# only consider within this intensity values" << endl; fout << "parms=-inf,0,-1000,-1000,4000,4000,inf,0" << endl; fout << "images=fixed,moving" << endl; fout << endl; fout << "[STAGE]" << endl; fout << "metric=gm" << endl; fout << "xform=translation" << endl; fout << "optim=grid_search" << endl; fout << "gridsearch_min_overlap=" << optionList.at(0).toDouble() << " " << optionList.at(1).toDouble() << " " << optionList.at(2).toDouble() << endl; fout << "num_substages=5" << endl; //fout << "debug_dir=" << m_strPathPlastimatch.toLocal8Bit().constData() << endl; break; case PLAST_BSPLINE: fout << "[STAGE]" << endl; fout << "xform=" << "bspline" << endl; fout << "impl=" << "plastimatch" << endl; fout << "threading=" << "openmp" << endl; fout << "regularization_lambda=" << 0.005 << endl; fout << "metric=" << "mse" << endl; fout << "max_its=" << 30 << endl; fout << "grid_spac=" << "30" << " " << "30" << " " << "30" << endl;//20 20 20 --> minimum fout << "res=" << "2" << " " << "2" << " " << "1" << endl; fout << "background_val=" << "-1024" << endl; //-600 in HU //added // fout << "img_out=" << "TBD" << endl; fout << endl; break; } fout.close(); } void QUTIL::GetGeometricLimitFloatImg(FloatImageType::Pointer& spFloatImg, VEC3D& limitStart, VEC3D& limitEnd) { if (!spFloatImg) { limitStart.x = 0.0; limitStart.y = 0.0; limitStart.z = 0.0; limitEnd.x = 0.0; limitEnd.y = 0.0; limitEnd.z = 0.0; return; } FloatImageType::SizeType imgSize = spFloatImg->GetLargestPossibleRegion().GetSize(); FloatImageType::PointType origin = spFloatImg->GetOrigin(); FloatImageType::SpacingType spacing = spFloatImg->GetSpacing(); limitStart.x = origin[0]; limitStart.y = origin[1]; limitStart.z = origin[2]; limitEnd.x = limitStart.x + (imgSize[0] - 1)*spacing[0]; limitEnd.y = limitStart.y + (imgSize[1] - 1)*spacing[1]; limitEnd.z = limitStart.z + (imgSize[2] - 1)*spacing[2]; } void QUTIL::Get1DProfileFromTable(QStandardItemModel* pTable, int iCol_X, int iCol_Y, vector& vOutDoseProfile) { vOutDoseProfile.clear(); QStringList list; int rowCnt = pTable->rowCount(); int columnCnt = pTable->columnCount(); if (iCol_X >= columnCnt && iCol_Y >= columnCnt) { cout << "Error! Wrong column number." << endl; return; } if (rowCnt < 1) { cout << "Error! This table is empty" << endl; return; } for (int i = 0; i < rowCnt; i++) { QPointF dataPt; QStandardItem* itemX = pTable->item(i, iCol_X); QStandardItem* itemY = pTable->item(i, iCol_Y); dataPt.setX(itemX->text().toDouble()); dataPt.setY(itemY->text().toDouble()); vOutDoseProfile.push_back(dataPt); } } void QUTIL::ResampleFloatImg(FloatImageType::Pointer& spFloatInput, FloatImageType::Pointer& spFloatOutput, VEC3D& newSpacing) { float old_spacing[3]; old_spacing[0] = spFloatInput->GetSpacing()[0]; old_spacing[1] = spFloatInput->GetSpacing()[1]; old_spacing[2] = spFloatInput->GetSpacing()[2]; float NewSpacing[3]; NewSpacing[0] = newSpacing.x; NewSpacing[1] = newSpacing.y; NewSpacing[2] = newSpacing.z; spFloatOutput = resample_image(spFloatInput, NewSpacing); if (spFloatOutput) { //cout << "Resampling is done" << "From " << old_spacing << " To " << NewSpacing << endl; } } const char * QUTIL::c_str (const QString& s) { return s.toUtf8().constData(); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/qt_util.h000066400000000000000000000173421321604176500306100ustar00rootroot00000000000000#ifndef QT_UTIL_H #define QT_UTIL_H #include "yk_config.h" #include "itk_image_type.h" //#include "itkImage.h" #include #include #include using namespace std; class QStandardItemModel; class gamma_gui; namespace QUTIL{ void Set2DTo3D(FloatImage2DType::Pointer& spSrcImg2D, UShortImageType::Pointer& spTargetImg3D, int idx, enPLANE iDirection); void Get2DFrom3DByIndex(UShortImageType::Pointer& spSrcImg3D, UShortImage2DType::Pointer& spTargetImg2D, int idx, enPLANE iDirection); void Get2DFrom3DByIndex(FloatImageType::Pointer& spSrcImg3D, FloatImage2DType::Pointer& spTargetImg2D, int idx, enPLANE iDirection); void Get2DFrom3DByPosition(UShortImageType::Pointer& spSrcImg3D, UShortImage2DType::Pointer& spTargImg2D, enPLANE iDirection, double pos, double& finalPos); void Get2DFrom3DByPosition(FloatImageType::Pointer& spSrcImg3D, FloatImage2DType::Pointer& spTargImg2D, enPLANE iDirection, double pos, double& finalPos); bool GetProfile1DByPosition(UShortImage2DType::Pointer& spSrcImg2D, vector& vProfile, float fixedPos, enPROFILE_DIRECTON enDirection); bool GetProfile1DByPosition(FloatImage2DType::Pointer& spSrcImg2D, vector& vProfile, float fixedPos, enPROFILE_DIRECTON enDirection); bool GetProfile1DByIndex(UShortImage2DType::Pointer& spSrcImg2D, vector& vProfile, int fixedIndex, enPROFILE_DIRECTON enDirection); bool GetProfile1DByIndex(FloatImage2DType::Pointer& spSrcImg2D, vector& vProfile, int fixedIndex, enPROFILE_DIRECTON enDirection); void LoadFloatImage2D(const char* filePath, FloatImage2DType::Pointer& spTargImg2D); void LoadFloatImage3D(const char* filePath, FloatImageType::Pointer& spTargImg3D); void SaveFloatImage2D(const char* filePath, FloatImage2DType::Pointer& spSrcImg2D); void SaveFloatImage3D(const char* filePath, FloatImageType::Pointer& spSrcImg3D); QStringList LoadTextFile(const char* txtFilePath); void LoadColorTableFromFile(const char* filePath, vector& vRGBTable); void LoadColorTableInternal(vector& vRGBTable, enCOLOR_TABLE col_table); VEC3D GetRGBValueFromTable(vector& vRGBTable, float fMinGray, float fMaxGray, float fLookupGray); QString GetTimeStampDirPath(const QString& curDirPath, const QString& preFix = QString(""), const QString& endFix = QString("")); QString GetTimeStampDirName(const QString& preFix = QString(""), const QString& endFix = QString("")); void ShowErrorMessage(QString str); void CreateItkDummyImg(FloatImageType::Pointer& spTarget, int sizeX, int sizeY, int sizeZ, float fillVal);//spacing: 1, origin: 0; void PrintStrList(QStringList& strList); QString GetPathWithEndFix(const QString& curFilePath, const QString& strEndFix); void GenDefaultCommandFile(QString strPathCommandFile, enRegisterOption regiOption); void GetGeometricLimitFloatImg (FloatImageType::Pointer& spFloatImg, VEC3D& limitStart, VEC3D& limitEnd); void Get1DProfileFromTable(QStandardItemModel* pTable, int iCol_X, int iCol_Y, vector& vOutDoseProfile); //void UpdateTable3(vector& vData1, vector& vData2, vector& vData3, QTableModel* pTableModel, QTableModel* pTableView); //void UpdateFloatTable3(vector& vData1, vector& vData2, vector& vData3, //QStandardItemModel* pTableModel, gamma_gui* pParent); // typedef itk::ImageFileReader ReaderTypeYK; bool QPointF_Compare(const QPointF& ptData1, const QPointF& ptData2); void ResampleFloatImg(FloatImageType::Pointer& spFloatInput, FloatImageType::Pointer& spFloatOutput, VEC3D& newSpacing); const char *c_str (const QString& s); }; #define NUM_OF_TBL_ITEM_JET 64 #define NUM_OF_TBL_ITEM_GAMMA 100 //Item: 64 //extern const double colormap_jet[][3] = { const double colormap_jet[][3] = { 0, 0, 0.5625, 0, 0, 0.625, 0, 0, 0.6875, 0, 0, 0.75, 0, 0, 0.8125, 0, 0, 0.875, 0, 0, 0.9375, 0, 0, 1, 0, 0.0625, 1, 0, 0.125, 1, 0, 0.1875, 1, 0, 0.25, 1, 0, 0.3125, 1, 0, 0.375, 1, 0, 0.4375, 1, 0, 0.5, 1, 0, 0.5625, 1, 0, 0.625, 1, 0, 0.6875, 1, 0, 0.75, 1, 0, 0.8125, 1, 0, 0.875, 1, 0, 0.9375, 1, 0, 1, 1, 0.0625, 1, 0.9375, 0.125, 1, 0.875, 0.1875, 1, 0.8125, 0.25, 1, 0.75, 0.3125, 1, 0.6875, 0.375, 1, 0.625, 0.4375, 1, 0.5625, 0.5, 1, 0.5, 0.5625, 1, 0.4375, 0.625, 1, 0.375, 0.6875, 1, 0.3125, 0.75, 1, 0.25, 0.8125, 1, 0.1875, 0.875, 1, 0.125, 0.9375, 1, 0.0625, 1, 1, 0, 1, 0.9375, 0, 1, 0.875, 0, 1, 0.8125, 0, 1, 0.75, 0, 1, 0.6875, 0, 1, 0.625, 0, 1, 0.5625, 0, 1, 0.5, 0, 1, 0.4375, 0, 1, 0.375, 0, 1, 0.3125, 0, 1, 0.25, 0, 1, 0.1875, 0, 1, 0.125, 0, 1, 0.0625, 0, 1, 0, 0, 0.9375, 0, 0, 0.875, 0, 0, 0.8125, 0, 0, 0.75, 0, 0, 0.6875, 0, 0, 0.625, 0, 0, 0.5625, 0, 0, 0.5, 0, 0, }; //Num of item = 100 const double colormap_customgamma[][3] = { //extern const double colormap_customgamma[][3] = { 0, 0, 1, 0, 0.015873016, 0.992063492, 0, 0.031746032, 0.984126984, 0, 0.047619048, 0.976190476, 0, 0.063492063, 0.968253968, 0, 0.079365079, 0.96031746, 0, 0.095238095, 0.952380952, 0, 0.111111111, 0.944444444, 0, 0.126984127, 0.936507937, 0, 0.142857143, 0.928571429, 0, 0.158730159, 0.920634921, 0, 0.174603175, 0.912698413, 0, 0.19047619, 0.904761905, 0, 0.206349206, 0.896825397, 0, 0.222222222, 0.888888889, 0, 0.238095238, 0.880952381, 0, 0.253968254, 0.873015873, 0, 0.26984127, 0.865079365, 0, 0.285714286, 0.857142857, 0, 0.301587302, 0.849206349, 0, 0.317460317, 0.841269841, 0, 0.333333333, 0.833333333, 0, 0.349206349, 0.825396825, 0, 0.365079365, 0.817460317, 0, 0.380952381, 0.80952381, 0, 0.396825397, 0.801587302, 0, 0.412698413, 0.793650794, 0, 0.428571429, 0.785714286, 0, 0.444444444, 0.777777778, 0, 0.46031746, 0.76984127, 0, 0.476190476, 0.761904762, 0, 0.492063492, 0.753968254, 0, 0.507936508, 0.746031746, 0, 0.523809524, 0.738095238, 0, 0.53968254, 0.73015873, 0, 0.555555556, 0.722222222, 0, 0.571428571, 0.714285714, 0, 0.587301587, 0.706349206, 0, 0.603174603, 0.698412698, 0, 0.619047619, 0.69047619, 0, 0.634920635, 0.682539683, 0, 0.650793651, 0.674603175, 0, 0.666666667, 0.666666667, 0, 0.682539683, 0.658730159, 0, 0.698412698, 0.650793651, 0, 0.714285714, 0.642857143, 0, 0.73015873, 0.634920635, 0, 0.746031746, 0.626984127, 0, 0.761904762, 0.619047619, 0, 0.777777778, 0.611111111, 1, 0.708333333, 0, 1, 0.6875, 0, 1, 0.666666667, 0, 1, 0.645833333, 0, 1, 0.625, 0, 1, 0.604166667, 0, 1, 0.583333333, 0, 1, 0.5625, 0, 1, 0.541666667, 0, 1, 0.520833333, 0, 1, 0.5, 0, 1, 0.479166667, 0, 1, 0.458333333, 0, 1, 0.4375, 0, 1, 0.416666667, 0, 1, 0.395833333, 0, 1, 0.375, 0, 1, 0.354166667, 0, 1, 0.333333333, 0, 1, 0.3125, 0, 1, 0.291666667, 0, 1, 0.270833333, 0, 1, 0.25, 0, 1, 0.229166667, 0, 1, 0.208333333, 0, 1, 0.1875, 0, 1, 0.166666667, 0, 1, 0.145833333, 0, 1, 0.125, 0, 1, 0.083333333, 0, 1, 0.041666667, 0, 1, 0, 0, 0.958333333, 0, 0, 0.916666667, 0, 0, 0.875, 0, 0, 0.833333333, 0, 0, 0.791666667, 0, 0, 0.75, 0, 0, 0.708333333, 0, 0, 0.666666667, 0, 0, 0.625, 0, 0, 0.583333333, 0, 0, 0.541666667, 0, 0, 0.5, 0, 0, 0.458333333, 0, 0, 0.416666667, 0, 0, 0.375, 0, 0, 0.333333333, 0, 0, 0.291666667, 0, 0, 0.25, 0, 0, }; #endif // QT_UTIL_H plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/qyklabel.cpp000066400000000000000000000321351321604176500312630ustar00rootroot00000000000000#include "qyklabel.h" #include #include "YK16GrayImage.h" using namespace std; qyklabel::qyklabel(QWidget *parent) : QLabel(parent) { m_pYK16Image = NULL; //this->width(); //m_Rt = this->rect(); //m_Rt.setRect() m_bDrawPoints = true; m_iMouseWheelDelta = 0; m_bFocusIn = false; } qyklabel::~qyklabel() { } void qyklabel::mouseMoveEvent( QMouseEvent *ev ) { if (m_pYK16Image == NULL) return; this->x = ev->x(); this->y = ev->y(); emit Mouse_Move(); } void qyklabel::mousePressEvent( QMouseEvent *ev ) { if (m_pYK16Image == NULL) return; this->x = ev->x(); this->y = ev->y(); if (ev->button() == Qt::LeftButton) { emit Mouse_Pressed_Left(); } if (ev->button() == Qt::RightButton) { emit Mouse_Pressed_Right(); } } void qyklabel::mouseDoubleClickEvent(QMouseEvent *ev) { if (m_pYK16Image == NULL) return; if (ev->button() == Qt::LeftButton) { emit Mouse_Left_DoubleClick(); } if (ev->button() == Qt::RightButton) { emit Mouse_Right_DoubleClick(); } } void qyklabel::mouseReleaseEvent( QMouseEvent *ev ) { if (m_pYK16Image == NULL) return; //cout << "Mouse Released from qlabel" << endl;//it worked if (ev->button() == Qt::LeftButton) { emit Mouse_Released_Left(); } if (ev->button() == Qt::RightButton) { emit Mouse_Released_Right(); } } void qyklabel::wheelEvent( QWheelEvent * event ) { if (m_pYK16Image == NULL) return; m_iMouseWheelDelta = (int)(event->delta()/100.0); emit Mouse_Wheel(); } void qyklabel::enterEvent (QEvent *) { if (m_pYK16Image == NULL) return; m_bFocusIn = true; emit FocusIn(); } void qyklabel::leaveEvent( QEvent * ) { if (m_pYK16Image == NULL) return; m_bFocusIn = false; emit FocusOut(); } //void focusInEvent ( QFocusEvent * ev ); //void focusOutEvent ( QFocusEvent * ev ); // //void qyklabel::focusInEvent( QFocusEvent * ) //{ // cout <<"focus in" << endl; // emit FocusIn(); //} // //void qyklabel::focusOutEvent( QFocusEvent * ) //{ // cout <<"focus out" << endl; // emit FocusOut(); //} void qyklabel::paintEvent( QPaintEvent * ) { QPainter painter(this); painter.setPen( QPen(Qt::black, 2)); QRect TargetRt = this->rect(); painter.drawRect(TargetRt); if (m_pYK16Image == NULL) return; if (m_pYK16Image->m_iWidth < 1 || m_pYK16Image->m_iHeight<1) return; double VH_ratio = 0.0; //if horizontal is longer than vertical bool bHorLonger = false; double physHor = 0.0; double physVer = 0.0; int labelNewFixedWidth = 0; int labelNewFixedHeight = 0; if (m_pYK16Image->m_fSpacingX*m_pYK16Image->m_fSpacingY == 0) { physHor = (double)m_pYK16Image->m_iWidth; physVer = (double)m_pYK16Image->m_iHeight; } else { physHor = m_pYK16Image->m_iWidth * m_pYK16Image->m_fSpacingX; physVer = m_pYK16Image->m_iHeight* m_pYK16Image->m_fSpacingY; } VH_ratio = physVer / physHor; if (physHor > physVer) { bHorLonger = true; int newFixedHeight = qRound(this->width() * VH_ratio); this->setFixedHeight(newFixedHeight); } else { bHorLonger = false; int newFixedWidth = qRound(this->height() / VH_ratio); this->setFixedWidth(newFixedWidth); } //Calculate ver / hor ratio. /*VH_ratio = m_pYK16Image->m_iHeight / (double) m_pYK16Image->m_iWidth; int newFixedHeight = qRound(this->width() * VH_ratio); this->setFixedHeight(newFixedHeight);*/ if (m_pYK16Image != NULL) { //QRect imgSrcRect; //imgSrcRect.setRect(0,0,m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight); //painter.drawImage(rect(), m_pYK16Image->m_QImage,imgSrcRect,); //int width = m_pYK16Image->m_QImage.width(); //int height = m_pYK16Image->m_QImage.height(); //m_pYK16Image->m_QImage.save("C:\\111.png"); //QImage tmpQImage = QImage("C:\\FromFillPixmap.png"); //QImage tmpQImage = m_pYK16Image->m_QImage; //painter.drawImage(TargetRt, m_pYK16Image->m_QImage, imgSrcRect, QT::RGB888); //painter.drawImage(TargetRt, m_pYK16Image->m_QImage, imgSrcRect); //painter.drawImage(TargetRt, m_pYK16Image->m_QImage); //it Works!YKTEMP painter.drawImage(TargetRt, m_pYK16Image->m_QImage); //it Works!YKTEMP } if (m_bDrawPoints) { painter.setPen( QPen(Qt::red, 2)); vector::iterator it; for (it = m_vPt.begin() ; it != m_vPt.end() ; it++) { painter.drawPoint((*it).x(),(*it).y()); } } if (m_pYK16Image->m_bDrawROI) { painter.setPen( QPen(Qt::red, 2)); QRect rtDraw; rtDraw.setTopLeft(Data2View(QPoint(m_pYK16Image->m_rtROI.left(), m_pYK16Image->m_rtROI.top()), this->width(), this->height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight)); rtDraw.setBottomRight(Data2View(QPoint(m_pYK16Image->m_rtROI.right(), m_pYK16Image->m_rtROI.bottom()), this->width(), this->height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight)); painter.drawRect(rtDraw); } //if x, y >0 if (m_pYK16Image->m_bDrawProfileX) { QPoint crntViewPt = Data2View(m_pYK16Image->m_ptProfileProbe, this->width(), this->height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight); painter.setPen( QPen(Qt::red, 1, Qt::DotLine)); painter.drawLine(0, crntViewPt.y(), this->width()-1, crntViewPt.y()); } if (m_pYK16Image->m_bDrawProfileY) { QPoint crntViewPt = Data2View(m_pYK16Image->m_ptProfileProbe, this->width(), this->height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight); painter.setPen( QPen(Qt::red, 1, Qt::DotLine)); painter.drawLine(crntViewPt.x(), 0 ,crntViewPt.x(), this->height()-1); } if (m_pYK16Image->m_bDrawFOVCircle) { painter.setPen( QPen(Qt::yellow, 1, Qt::SolidLine)); QPoint crntCenterPt = Data2View(m_pYK16Image->m_ptFOVCenter, this->width(), this->height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight); int crntRadius = (int)(m_pYK16Image->m_iFOVRadius / (double)m_pYK16Image->m_iWidth * this->width()); painter.drawEllipse(crntCenterPt,crntRadius, crntRadius); } if (m_pYK16Image->m_bDrawTableLine) { painter.setPen( QPen(Qt::yellow, 1, Qt::SolidLine)); int crntTablePosY = (int)(m_pYK16Image->m_iTableTopPos / (double)m_pYK16Image->m_iHeight * this->height()); //int crntRadius = (int)(m_pYK16Image->m_iFOVRadius / (double)m_pYK16Image->m_iWidth * this->width()); painter.drawLine(0, crntTablePosY ,this->width()-1, crntTablePosY); //painter.drawEllipse(crntCenterPt,crntRadius, crntRadius); } if (m_pYK16Image->m_bDrawCrosshair) //objects should be addressed one by one { painter.setPen( QPen(Qt::yellow, 1, Qt::SolidLine)); //QPoint crosshair; int dispCrossX = (int)(m_pYK16Image->m_ptCrosshair.x() / (double)m_pYK16Image->m_iWidth * this->width()); int dispCrossY = (int)(m_pYK16Image->m_ptCrosshair.y() / (double)m_pYK16Image->m_iHeight * this->height()); QPoint ptDispCrosshair = GetViewPtFromDataPt(m_pYK16Image->m_ptCrosshair.x(), m_pYK16Image->m_ptCrosshair.y()); //crosshair.setX(crossX); //crosshair.setY(crossY); //int crntRadius = (int)(m_pYK16Image->m_iFOVRadius / (double)m_pYK16Image->m_iWidth * this->width()); painter.drawLine(0, ptDispCrosshair.y() ,this->width()-1, ptDispCrosshair.y()); painter.drawLine(ptDispCrosshair.x(), 0, ptDispCrosshair.x(), this->height()-1); } if (m_pYK16Image->m_bDrawOverlayText && m_pYK16Image->m_strOverlayText.length() > 1) //objects should be addressed one by one { /*this->setText(m_pYK16Image->m_strOverlayText); this->setFont(QFont("Helvetica", 12, 1, false)); this->setAlignment(Qt::AlignBottom);*/ int rtWidth = this->width(); int rtHeight = this->height() / 7.0; int leftPos = 10; int topPos = qRound(this->height() - rtHeight); QRect rt = QRect(leftPos, topPos, rtWidth, rtHeight); painter.setPen(QPen(Qt::white, 3, Qt::SolidLine)); painter.drawText(rt, m_pYK16Image->m_strOverlayText); } } void qyklabel::SetBaseImage( YK16GrayImage* pYKImage ) { if (pYKImage->m_pData != NULL && !pYKImage->m_QImage.isNull()) //YKTEMP m_pYK16Image = pYKImage; } void qyklabel::ConvertAndCopyPoints(vector& vSrcPoint, int iDataWidth, int iDataHeight) { m_vPt.clear(); int dspWidth = this->width(); int dspHeight = this->height(); vector::iterator it; for (it = vSrcPoint.begin() ; it != vSrcPoint.end() ; it++) { QPoint tmpDspPt = Data2View((*it),dspWidth, dspHeight, iDataWidth, iDataHeight); m_vPt.push_back(tmpDspPt); } } QPoint qyklabel::View2Data(QPoint viewPt, int viewWidth, int viewHeight, int dataWidth, int dataHeight) { double fZoomX = viewWidth / (double)dataWidth; double fZoomY = viewHeight / (double)dataHeight; QPoint dataPt; dataPt.setX(qRound(viewPt.x() / fZoomX)); dataPt.setY(qRound(viewPt.y() / fZoomY)); return dataPt; } QPoint qyklabel::Data2View(QPoint dataPt, int viewWidth, int viewHeight, int dataWidth, int dataHeight) { double fZoomX = viewWidth / (double)dataWidth; double fZoomY = viewHeight / (double)dataHeight; QPoint viewPt; viewPt.setX(qRound(dataPt.x() * fZoomX)); viewPt.setY(qRound(dataPt.y() * fZoomY)); return viewPt; } void qyklabel::SetDrawPointToggle(bool bToggle ) { if (bToggle) m_bDrawPoints = true; else m_bDrawPoints = false; update(); } QPoint qyklabel::GetDataPtFromMousePos() { if (m_pYK16Image == NULL) return QPoint(0,0); if (m_pYK16Image->m_fZoom == 1.0 && m_pYK16Image->m_iOffsetX == 0 && m_pYK16Image->m_iOffsetY == 0) return View2Data(QPoint(this->x, this->y), width(), height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight); else return View2DataExt(QPoint(this->x, this->y), width(), height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight, QPoint(m_pYK16Image->m_iOffsetX,m_pYK16Image->m_iOffsetY),m_pYK16Image->m_fZoom ); } QPoint qyklabel::GetDataPtFromViewPt(int viewPtX, int viewPtY) { if (m_pYK16Image == NULL) return QPoint(0,0); if (m_pYK16Image->m_fZoom == 1.0 && m_pYK16Image->m_iOffsetX == 0 && m_pYK16Image->m_iOffsetY == 0) return View2Data(QPoint(viewPtX, viewPtY), width(), height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight); else return View2DataExt(QPoint(viewPtX, viewPtY), width(), height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight, QPoint(m_pYK16Image->m_iOffsetX,m_pYK16Image->m_iOffsetY),m_pYK16Image->m_fZoom ); } QPoint qyklabel::GetViewPtFromDataPt(int dataPtX, int dataPtY) { if (m_pYK16Image == NULL) return QPoint(0,0); if (m_pYK16Image->m_fZoom == 1.0 && m_pYK16Image->m_iOffsetX == 0 && m_pYK16Image->m_iOffsetY == 0) return Data2View(QPoint(dataPtX, dataPtY), width(), height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight); else return Data2ViewExt(QPoint(dataPtX, dataPtY), width(), height(), m_pYK16Image->m_iWidth, m_pYK16Image->m_iHeight, QPoint(m_pYK16Image->m_iOffsetX,m_pYK16Image->m_iOffsetY),m_pYK16Image->m_fZoom ); } QPoint qyklabel::View2DataExt(QPoint viewPt, int viewWidth, int viewHeight, int dataWidth, int dataHeight, QPoint ptDataOffset, double fUserZoom) { // double fZoomX = viewWidth / (double)dataWidth * fUserZoom; // < 1 //double fZoomY = viewHeight / (double)dataHeight * fUserZoom; // dataPt.setX(qRound(viewPt.x() * fZoomX + ptDataOffset.x())); // dataPt.setY(qRound(viewPt.y() * fZoomY + ptDataOffset.y())); int newWidth = qRound(dataWidth/fUserZoom); int newHeight = qRound(dataHeight/fUserZoom); int dataCenterX = ptDataOffset.x() + qRound(dataWidth/2.0); int dataCenterY = ptDataOffset.y() + qRound(dataHeight/2.0); int dataLeftTopX = dataCenterX - qRound(newWidth/2.0);//data position int dataLeftTopY = dataCenterY - qRound(newHeight/2.0); //data position QPoint dataPt; dataPt.setX(qRound(viewPt.x()*newWidth/(double)viewWidth + dataLeftTopX)); dataPt.setY(qRound(viewPt.y()*newHeight/(double)viewHeight + dataLeftTopY)); return dataPt; } QPoint qyklabel::Data2ViewExt( QPoint dataPt, int viewWidth, int viewHeight, int dataWidth, int dataHeight, QPoint ptDataOffset, double fUserZoom ) { int newWidth = qRound(dataWidth/fUserZoom); int newHeight = qRound(dataHeight/fUserZoom); int dataCenterX = ptDataOffset.x() + qRound(dataWidth/2.0); int dataCenterY = ptDataOffset.y() + qRound(dataHeight/2.0); int dataLeftTopX = dataCenterX - qRound(newWidth/2.0);//data position int dataLeftTopY = dataCenterY - qRound(newHeight/2.0); //data position QPoint viewPt; viewPt.setX(qRound((dataPt.x() - dataLeftTopX) * viewWidth/(double)newWidth)); viewPt.setY(qRound((dataPt.y() - dataLeftTopY) * viewHeight/(double)newHeight)); return viewPt; } //void qyklabel::keyPressEvent( QKeyEvent* ev ) //{ // if (!isFocusIn()) // return; // // int enMovingKey = -1; // // if (ev->key() == Qt::Key_Left) // enMovingKey = 0; // else if (ev->key() == Qt::Key_Right) // enMovingKey = 1; // else if (ev->key() == Qt::Key_Up) // enMovingKey = 2; // else if (ev->key() == Qt::Key_Down) // enMovingKey = 3; // else if (ev->key() == Qt::Key_PageUp) // enMovingKey = 4; // else if (ev->key() == Qt::Key_PageUp) // enMovingKey = 5; // // cout << enMovingKey << endl; // // emit ArrowPressed(enMovingKey); //}plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/qyklabel.h000066400000000000000000000045701321604176500307320ustar00rootroot00000000000000#ifndef QYKLABEL_H #define QYKLABEL_H #include #include #include #include //#include class YK16GrayImage; using namespace std; class qyklabel : public QLabel { Q_OBJECT public: YK16GrayImage* m_pYK16Image; QRect m_Rt; std::vector m_vPt; bool m_bDrawPoints; int m_iMouseWheelDelta; bool m_bFocusIn; public: qyklabel(QWidget *parent); ~qyklabel(); bool isFocusIn() {return m_bFocusIn;} // virtual function reimplementation void mousePressEvent(QMouseEvent *ev); //ev->buttons() == Qt::LeftButton void mouseMoveEvent(QMouseEvent *ev); void mouseReleaseEvent(QMouseEvent *ev); void wheelEvent(QWheelEvent * event); //this->setText("Delta Value: "+QString::number(event->delta())); void mouseDoubleClickEvent(QMouseEvent *ev); //void keyPressEvent ( QKeyEvent *ev); //void focusInEvent ( QFocusEvent * ev ); //void focusOutEvent ( QFocusEvent * ev ); void enterEvent (QEvent *); void leaveEvent(QEvent *); int x,y; void SetBaseImage(YK16GrayImage* pYKImage); //void ConvertAndCopyPoints(vector& vSrcPoint); void ConvertAndCopyPoints(vector& vSrcPoint, int iDataWidth, int iDataHeight); QPoint View2Data(QPoint viewPt, int viewWidth, int viewHeight, int dataWidth, int dataHeight); QPoint View2DataExt(QPoint viewPt, int viewWidth, int viewHeight, int dataWidth, int dataHeight, QPoint ptDataOffset, double fUserZoom); QPoint Data2View(QPoint dataPt, int viewWidth, int viewHeight, int dataWidth, int dataHeight); QPoint Data2ViewExt(QPoint dataPt, int viewWidth, int viewHeight, int dataWidth, int dataHeight, QPoint ptDataOffset, double fUserZoom); QPoint GetDataPtFromMousePos(); //Return data position of the mouse position.m_pYK16 image is mandatory QPoint GetDataPtFromViewPt(int viewPtX, int viewPtY); QPoint GetViewPtFromDataPt(int dataPtX, int dataPtY); protected: void paintEvent(QPaintEvent *); signals: void Mouse_Pressed_Left(); void Mouse_Pressed_Right(); void Mouse_Move(); void Mouse_Released_Left(); void Mouse_Released_Right(); void Mouse_Wheel(); void Mouse_Left_DoubleClick(); void Mouse_Right_DoubleClick(); void FocusIn(); void FocusOut(); //void ArrowPressed(int arrowDirection);// 0: Left, 1: Upward, 2: Right, 3: Downward //void OutFromWindow(); public slots: void SetDrawPointToggle(bool bToggle); private: }; #endif // QYKLABEL_H plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/raw_to_mha.c000066400000000000000000000035001321604176500312310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* Convert's Shinichiro's raw format to ITK mha format */ #include #include #include "plm_config.h" #define BUFLEN 1024 /*char header_pat[] = "ObjectType = Image\n" "NDims = 3\n" "BinaryData = True\n" "BinaryDataByteOrderMSB = False\n" "Offset = %s\n" "ElementSpacing = %s\n" "DimSize = %s\n" // "AnatomicalOrientation = RAI\n" "AnatomicalOrientation = LAI\n" "ElementType = MET_SHORT\n" "ElementDataFile = LOCAL\n" ; */ char header_pat[] = "ObjectType = Image\n" "NDims = 3\n" "BinaryData = True\n" "BinaryDataByteOrderMSB = False\n" "TransformMatrix = 1 0 0 0 1 0 0 0 1\n" "Offset = %s\n" "ElementSpacing = %s\n" "DimSize = %s\n" "AnatomicalOrientation = RPI\n" "ElementType = MET_UCHAR\n" "ElementDataFile = LOCAL\n" ; char *dm; char *ps; char *os = "0 0 0"; int main (int argc, char* argv[]) { FILE *fp1, *fp2; unsigned char c; if (argc > 6 || argc <= 4) { printf ("Usage: %s infile outfile dims pix_spacing [offset_string]\n", argv[0]); exit (1); } if (!(fp1 = fopen(argv[1],"rb"))) { printf ("Error opening file \"%s\" for read\n", argv[1]); exit (1); } if (!(fp2 = fopen(argv[2],"wb"))) { printf ("Error opening file \"%s\" for write\n", argv[2]); exit (1); } dm = argv[3]; //printf("dim = %s\n ", dm); ps = argv[4]; //printf("ps = %s\n", ps); if (argc == 6) { os = argv[5]; } fprintf (fp2, header_pat, os, ps, dm); while (1 == fread(&c,1,1,fp1)) { fwrite(&c,1,1,fp2); } fclose (fp1); fclose (fp2); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/read_obj.cxx000066400000000000000000000120331321604176500312370ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "compute_distance.h" #define BUFLEN 2048 void read_obj (FILE* mesh, SURFACE* surface) { char line[BUFLEN]; //char index; char dumm[128]; float x = 0; float y = 0; float z = 0; int first = 0; int second = 0; int third = 0; VERTICES_LIST* vertices; TRIANGLE_LIST* triangles; if (!fgets (line, BUFLEN, mesh)) { fprintf (stderr, "Error while parsing the file occurred, couldn't read the first line\n"); exit (-1); } if (sscanf (line, "g %s", dumm) != 1) { fprintf (stderr, "Error while parsing the file occurred, the first line in the .obj isn't in the correct format\n"); exit (-1); } vertices = &surface->vertices; triangles = &surface->triangles; while (fgets (line, BUFLEN, mesh)) { if (sscanf (line, "v %f %f %f", &x, &y, &z) == 3) { vertices->num_vertices++; vertices->x = (float*) realloc (vertices->x, (vertices->num_vertices) * sizeof(float)); vertices->y = (float*) realloc (vertices->y, (vertices->num_vertices) * sizeof(float)); vertices->z = (float*) realloc (vertices->z, (vertices->num_vertices) * sizeof(float)); //printf("realloc riuscito, ho %d vertici\n",vertices->num_vertices); vertices->x[vertices->num_vertices - 1] = x; vertices->y[vertices->num_vertices - 1] = y; vertices->z[vertices->num_vertices - 1] = z; /* printf("I read: %f %f %f\n", vertices->x[vertices->num_vertices-1], vertices->y[vertices->num_vertices-1],vertices->z[vertices->num_vertices-1]);*/ } else if (strstr (line, "#") != NULL) { printf ("Loading the triangles\n"); } else if (sscanf (line, "f %d %d %d", &first, &second, &third) == 3) { triangles->num_triangles++; triangles->first = (int*) realloc (triangles->first, (triangles->num_triangles) * sizeof(int)); triangles->second = (int*) realloc (triangles->second, (triangles->num_triangles) * sizeof(int)); triangles->third = (int*) realloc (triangles->third, (triangles->num_triangles) * sizeof(int)); triangles->first[triangles->num_triangles - 1] = first; triangles->second[triangles->num_triangles - 1] = second; triangles->third[triangles->num_triangles - 1] = third; } else { fprintf (stderr, "This is not the correct file format!"); exit (-1); } } /*printf("LAST: %d %d %d\n",triangles->first[triangles->num_triangles-1], triangles->second[triangles->num_triangles-1], triangles->third[triangles->num_triangles-1]);*/ fclose (mesh); } void read_MDcontours (FILE* MDpoints, SURFACE* surface) { char line[BUFLEN]; float x = 0; float y = 0; float z = 0; VERTICES_LIST* pointsMD; if (!fgets (line, BUFLEN, MDpoints)) { fprintf (stderr, "Error while parsing the file occurred, couldn't read the first line\n"); exit (-1); } if (strstr (line, "NaN NaN NaN") == NULL) { fprintf (stderr, "Error while parsing MDpoints file occurred, the first line isn't in the correct format\n"); exit (-1); } pointsMD = &surface->MDpoints; while (fgets (line, BUFLEN, MDpoints)) { //fprintf(stderr,"Error while parsing the file occurred, couldn't read something\n"); //exit(-1); //} //fgets(line,BUFLEN,MDpoints); if (strstr (line, "NaN NaN NaN") != NULL) { } else if (sscanf (line, "%f %f %f", &x, &y, &z) == 3) { pointsMD->num_vertices++; pointsMD->x = (float*) realloc (pointsMD->x, (pointsMD->num_vertices) * sizeof(float)); pointsMD->y = (float*) realloc (pointsMD->y, (pointsMD->num_vertices) * sizeof(float)); pointsMD->z = (float*) realloc (pointsMD->z, (pointsMD->num_vertices) * sizeof(float)); //printf("realloc riuscito, ho %d vertici\n",pointsMD->num_vertices); pointsMD->x[pointsMD->num_vertices - 1] = x; pointsMD->y[pointsMD->num_vertices - 1] = y; pointsMD->z[pointsMD->num_vertices - 1] = z; //printf("I read: %f %f %f\n", pointsMD->x[pointsMD->num_vertices-1], // pointsMD->y[pointsMD->num_vertices-1],pointsMD->z[pointsMD->num_vertices-1]); } else fprintf (stderr, "Couldn't read the MDfile for unknown reasons\n"); } fclose (MDpoints); } register_gui.cpp000066400000000000000000002236741321604176500321020ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include #include #include #include #include #include #include #include "YKThreadRegi.h" #include #include #include #include #include #include #include #include "qt_util.h" #include "register_gui.h" register_gui::register_gui(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { ui.setupUi(this); m_pTableModelMain = NULL; m_pTableModelQue = NULL; m_iCurSelRow_Main = -1; m_iCurSelCol_Main = -1; m_iCurSelRow_Que = -1; m_iCurSelCol_Que = -1; m_pArrThreadRegi = NULL; m_iNumOfThreadAll = DEFAULT_MAXNUM_QUE; InitTableMain(DEFAULT_MAXNUM_MAIN, DEFAULT_NUM_COLUMN_MAIN); InitTableQue(DEFAULT_MAXNUM_QUE, DEFAULT_NUM_COLUMN_QUE); /*if (m_pArrThreadRegi != NULL) { DeleteRemainingThreads(); }*/ m_pArrThreadRegi = new YKThreadRegi*[m_iNumOfThreadAll]; //200 threads object, double pointer for (int i = 0; i < m_iNumOfThreadAll; i++) { m_pArrThreadRegi[i] = NULL; } m_timerRunSequential = new QTimer(this); m_timerRunMultiThread = new QTimer(this); connect(m_timerRunSequential, SIGNAL(timeout()), this, SLOT(SLT_TimerRunSEQ())); connect(m_timerRunMultiThread, SIGNAL(timeout()), this, SLOT(SLT_TimerRunMT())); //Set m_strPathCommandTemplateDir in ~/ AppData / Roaming / plastimatch InitConfig(); //Write default templates there WriteDefaultTemplateFiles(m_strPathCommandTemplateDir); // Read config file. Save it, to create if the first invokation. read_application_settings (); write_application_settings (); UpdateCommandFileTemplateList(m_strPathCommandTemplateDir); //from the folder } //make and set m_strPathCommandTemplateDir in ~/AppData/Roaming/plastimatch void register_gui::InitConfig() { // Set up application configuration location QCoreApplication::setOrganizationName("Plastimatch"); QCoreApplication::setOrganizationDomain("plastimatch.org"); QCoreApplication::setApplicationName("register_gui"); // Find location for command file templates. // QT doesn't seem to have an API for getting the // user's application data directory. So we construct // a hypothetical ini file name, then grab the directory. QSettings tmpSetting( QSettings::IniFormat, /* Make sure we get path, not registry */ QSettings::UserScope, /* Get user directory, not system direcory */ "Plastimatch", /* Orginazation name (subfolder within path) */ "register_gui" /* Application name (file name with subfolder) */ ); QString strPathTemplateBase = QFileInfo(tmpSetting.fileName()).absolutePath();//C:\Users\ykp1\AppData\Roaming/plastimatch. however, the directory was not found m_strPathCommandTemplateDir = strPathTemplateBase + "/" + "CommandTemplate"; QDir plm_setting_dir(m_strPathCommandTemplateDir); if (!plm_setting_dir.exists()) { //plm_setting_dir.mkdir(m_strPathCommandTemplateDir); if (!plm_setting_dir.mkpath(m_strPathCommandTemplateDir)) //The function will create all parent directories necessary to create the directory. { cout << "Error! Cannot make a directory for command file templates. You may not able to use templates for command file." << endl; m_strPathCommandTemplateDir = ""; } else { cout << "Command template path: " << m_strPathCommandTemplateDir.toLocal8Bit().constData() << endl; } } } void register_gui::WriteDefaultTemplateFiles(QString& targetDirPath) { QDir curDir(targetDirPath); if (!curDir.exists()) { cout << "Error! Target dir doesn't exist: " << targetDirPath.toLocal8Bit().constData() << endl; return; } CreateDefaultCommandFile(PLAST_RIGID); CreateDefaultCommandFile(PLAST_AFFINE); CreateDefaultCommandFile(PLAST_BSPLINE); CreateDefaultCommandFile(PLAST_GRADIENT); } register_gui::~register_gui() { if (m_pTableModelMain != NULL) { delete m_pTableModelMain; m_pTableModelMain = NULL; } if (m_pTableModelQue != NULL) { delete m_pTableModelQue; m_pTableModelQue = NULL; } m_vRegiQue.clear(); DeleteRemainingThreads(); } void register_gui::SLT_SetDefaultDir() { QString dirPath = QFileDialog::getExistingDirectory ( this, tr("Open Work Directory"), m_strPathDirDefault, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dirPath.length() < 1) return; dirPath.replace(QString("\\"), QString("/")); SetWorkDir(dirPath); write_application_settings (); } void register_gui::SLT_SetDefaultViewer() { QString strPathExecutable = QFileDialog::getOpenFileName ( this, "Open executable file", "", #if WIN32 "executable file (*.exe);;" #endif "all file (*)", 0, 0); if (strPathExecutable.length() < 1) return; SetReadImageApp(strPathExecutable); write_application_settings (); } void register_gui::SetWorkDir(const QString& strPath) { QDir dirDefaultDir = QDir(strPath); if (!dirDefaultDir.exists()) return; m_strPathDirDefault = strPath; ui.lineEdit_WorkingDir->setText(m_strPathDirDefault); } void register_gui::SetReadImageApp(const QString& strPath) { QFileInfo ViewerFileInfo(strPath); if (!ViewerFileInfo.exists()) return; m_strPathReadImageApp = strPath; ui.lineEdit_ImageViewerPath->setText(m_strPathReadImageApp); } void register_gui::SetCommandTemplateDir(const QString& strDirPath) { QDir dir(strDirPath); if (!dir.exists()) return; m_strPathCommandTemplateDir = strDirPath; //ui.lineEditDefaultViewerPath->setText(m_strPathReadImageApp); } void register_gui::InitTableQue(int rowCnt, int columnCnt) { if (m_pTableModelQue != NULL) { delete m_pTableModelQue; m_pTableModelQue = NULL; } if (columnCnt < 3) return; m_pTableModelQue = new QStandardItemModel(rowCnt, columnCnt, this); m_pTableModelQue->setHorizontalHeaderItem(0, new QStandardItem(QString("Fixed image file"))); m_pTableModelQue->setHorizontalHeaderItem(1, new QStandardItem(QString("Moving image file"))); m_pTableModelQue->setHorizontalHeaderItem(2, new QStandardItem(QString("Command file name"))); m_pTableModelQue->setHorizontalHeaderItem(3, new QStandardItem(QString("____Status____"))); m_pTableModelQue->setHorizontalHeaderItem(4, new QStandardItem(QString("Processing time (s)"))); m_pTableModelQue->setHorizontalHeaderItem(5, new QStandardItem(QString("____Score1____"))); m_pTableModelQue->setHorizontalHeaderItem(6, new QStandardItem(QString("____Score2____"))); ui.tableView_que->setModel(m_pTableModelQue); ui.tableView_que->resizeColumnsToContents(); QItemSelectionModel *select = ui.tableView_que->selectionModel(); //connect(select, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(SLT_SelectionChangedQue(QItemSelection, QItemSelection))); } void register_gui::InitTableMain(int rowCnt, int columnCnt) { if (m_pTableModelMain != NULL) { delete m_pTableModelMain; m_pTableModelMain = NULL; } if (columnCnt < 3) return; m_pTableModelMain = new QStandardItemModel(rowCnt, columnCnt, this); m_pTableModelMain->setHorizontalHeaderItem(0, new QStandardItem(QString("Fixed image file"))); m_pTableModelMain->setHorizontalHeaderItem(1, new QStandardItem(QString("Moving image file"))); m_pTableModelMain->setHorizontalHeaderItem(2, new QStandardItem(QString("Command file name"))); //m_pTableModelMain->setHorizontalHeaderItem(3, new QStandardItem(QString(" Status "))); ui.tableView_Stage->setModel(m_pTableModelMain); ui.tableView_Stage->resizeColumnsToContents(); QItemSelectionModel *select = ui.tableView_Stage->selectionModel(); //connect(select, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(SLT_SelectionChangedMain(QItemSelection, QItemSelection))); } void register_gui::SLT_LoadImages() { #if defined (commentout) // Display modal dialog // TODO, make modeless Register_gui_load_dialog *load_dlg = new Register_gui_load_dialog; if (load_dlg->exec () == QDialog::Rejected) { delete load_dlg; return; } Job_group_type action_pattern = load_dlg->get_action_pattern (); QString fixed_pattern = load_dlg->get_fixed_pattern (); QString moving_pattern = load_dlg->get_moving_pattern (); bool repeat_for_peers = load_dlg->get_repeat_for_peers (); printf ("Action: %d\n", action_pattern); printf ("Fixed: %s\n", fixed_pattern.toUtf8().constData()); printf ("Moving: %s\n", moving_pattern.toUtf8().constData()); printf ("Repeat: %s\n", repeat_for_peers ? "true" : "false"); m_actions.append (action_pattern); m_strlistPath_Fixed.append (fixed_pattern); m_strlistPath_Moving.append (moving_pattern); /*for (int i = 0; i < iCntPaths; i++) { QFileInfo tmpInfo = QFileInfo(m_strlistPath_Fixed.at(i)); m_strlistBaseName_Fixed.push_back(tmpInfo.fileName()); }*/ UpdateBaseAndComboFromFullPath(); UpdateTable_Main(DATA2GUI); //When updating table, also do it for combo boxes // ui.statusBar->showMessage(load_dlg->get_fixed_pattern()); // Process modal dialog delete load_dlg; #endif } void register_gui::SLT_LoadFixedFiles() { QFileDialog w; //w.setFileMode(QFileDialog::Directory);//both files and directories are displayed w.setFileMode(QFileDialog::AnyFile);//both files and directories are displayed w.setOption(QFileDialog::DontUseNativeDialog, true); QListView *l = w.findChild("listView"); if (l) { l->setSelectionMode(QAbstractItemView::ExtendedSelection); } w.setDirectory(m_strPathDirDefault); w.exec(); QStringList listPath = w.selectedFiles(); int iCntPaths = listPath.size(); if (iCntPaths < 1) return; //m_strlistPath_Fixed.clear(); //m_strlistBaseName_Fixed.clear(); //ui.comboBox_Fixed->clear(); m_strlistPath_Fixed = listPath; /*for (int i = 0; i < iCntPaths; i++) { QFileInfo tmpInfo = QFileInfo(m_strlistPath_Fixed.at(i)); m_strlistBaseName_Fixed.push_back(tmpInfo.fileName()); }*/ UpdateBaseAndComboFromFullPath(); UpdateTable_Main(DATA2GUI); //When updating table, also do it for combo boxes /* QFileInfo finfo(m_strlistPath_RD_Original_Ref.at(0)); QDir crntDir = finfo.absoluteDir(); m_strPathInputDir = crntDir.absolutePath();*/ } // Used to update Base and ComboList, but now no more combo list void register_gui::UpdateBaseAndComboFromFullPath() { m_strlistBaseName_Fixed.clear(); m_strlistBaseName_Moving.clear(); m_strlistBaseName_Command.clear(); int iCntFixed = m_strlistPath_Fixed.count(); int iCntMoving = m_strlistPath_Moving.count(); int iCntCommand = m_strlistPath_Command.count(); QFileInfo tmpInfo; QString fileName; for (int i = 0; i < iCntFixed; i++) { tmpInfo = QFileInfo(m_strlistPath_Fixed.at(i)); fileName = tmpInfo.fileName(); m_strlistBaseName_Fixed.push_back(fileName); } for (int i = 0; i < iCntMoving; i++) { tmpInfo = QFileInfo(m_strlistPath_Moving.at(i)); fileName = tmpInfo.fileName(); m_strlistBaseName_Moving.push_back(fileName); } for (int i = 0; i < iCntCommand; i++) { tmpInfo = QFileInfo(m_strlistPath_Command.at(i)); fileName = tmpInfo.fileName(); m_strlistBaseName_Command.push_back(fileName); } } void register_gui::SLT_LoadMovingFiles() { //include DICOM dir as well // QStringList tmpList = QFileDialog::getOpenFileNames(this, "Select one or more files to open", m_strPathDirDefault, "image files (*.dcm *.mha *.nrrd)"); QFileDialog w; w.setFileMode(QFileDialog::AnyFile);//both files and directories are displayed w.setOption(QFileDialog::DontUseNativeDialog, true); QListView *l = w.findChild("listView"); if (l) { l->setSelectionMode(QAbstractItemView::ExtendedSelection); } w.setDirectory(m_strPathDirDefault); w.exec(); QStringList listPath = w.selectedFiles(); int iCntPaths = listPath.size(); if (iCntPaths < 1) return; /* m_strlistPath_Moving.clear(); m_strlistBaseName_Moving.clear(); ui.comboBox_Moving->clear(); */ m_strlistPath_Moving = listPath; /* for (int i = 0; i < iCntPaths; i++) { QFileInfo tmpInfo = QFileInfo(m_strlistPath_Moving.at(i)); m_strlistBaseName_Moving.push_back(tmpInfo.fileName()); }*/ UpdateBaseAndComboFromFullPath(); UpdateTable_Main(DATA2GUI); } void register_gui::SLT_LoadCommandFiles() { QStringList tmpList = QFileDialog::getOpenFileNames(this, "Select one or more files to open", m_strPathDirDefault, "text files (*.txt)"); int iCntPathList = tmpList.count(); if (iCntPathList < 1) return; /* m_strlistPath_Command.clear(); m_strlistBaseName_Command.clear(); ui.comboBox_Command->clear();*/ m_strlistPath_Command = tmpList; /* for (int i = 0; i < iCntPathList; i++) { QFileInfo tmpInfo = QFileInfo(m_strlistPath_Command.at(i)); m_strlistBaseName_Command.push_back(tmpInfo.fileName()); }*/ UpdateBaseAndComboFromFullPath(); UpdateTable_Main(DATA2GUI); } void register_gui::EmptyTableModel(QStandardItemModel* pTableModel) { int iRowCount = pTableModel->rowCount(); int iColCount = pTableModel->columnCount(); QString strDummy = ""; for (int i = 0; i < iRowCount; i++) { for (int j = 0; j < iColCount; j++) { pTableModel->setItem(i, j, new QStandardItem(strDummy)); } } } //When updating table, also do it for combo boxes void register_gui::UpdateTable_Main(enUpdateDirection updateDirection) { /* if (m_pTableModel != NULL) { delete m_pTableModel; m_pTableModel = NULL; }*/ if (m_pTableModelMain == NULL) { cout << "error! Initialize table first " << endl; return; } int iCntFixed = m_strlistBaseName_Fixed.count(); int iCntMoving = m_strlistBaseName_Moving.count(); int iCntCommand = m_strlistBaseName_Command.count(); int RowCnt = m_pTableModelMain->rowCount(); int ColCnt = m_pTableModelMain->columnCount(); //fixed image if (iCntFixed > RowCnt) { cout << "Data size is larger than table prepared. Enarge the table first to accomodate bigger data" << endl; iCntFixed = RowCnt; } //moving image if (iCntMoving > RowCnt) { cout << "Data size is larger than table prepared. Enarge the table first to accomodate bigger data" << endl; iCntMoving = RowCnt; } //command file if (iCntCommand > RowCnt) { cout << "Data size is larger than table prepared. Enarge the table first to accomodate bigger data" << endl; iCntCommand = RowCnt; } if (updateDirection == DATA2GUI) { /* if (iCntFixed > 0) ui.comboBox_Fixed->clear(); if (iCntMoving > 0) ui.comboBox_Moving->clear(); if (iCntCommand > 0) ui.comboBox_Command->clear(); */ //Clear the table EmptyTableModel(m_pTableModelMain); //set all text "" for (int i = 0; i < iCntFixed; i++) { QString strFixed = m_strlistBaseName_Fixed.at(i); m_pTableModelMain->setItem(i, 0, new QStandardItem(strFixed)); // ui.comboBox_Fixed->addItem(strFixed); } for (int i = 0; i < iCntMoving; i++) { QString strMoving = m_strlistBaseName_Moving.at(i); m_pTableModelMain->setItem(i, 1, new QStandardItem(strMoving)); // ui.comboBox_Moving->addItem(strMoving); } for (int i = 0; i < iCntCommand; i++) { QString strCommand = m_strlistBaseName_Command.at(i); m_pTableModelMain->setItem(i, 2, new QStandardItem(strCommand)); // ui.comboBox_Command->addItem(strCommand); } } else if (updateDirection == GUI2DATA) //mostly, renaming command files { QStandardItem* item = NULL; for (int i = 0; i < iCntFixed; i++) { item = m_pTableModelMain->item(i, 0); m_strlistBaseName_Fixed[i] = item->text(); } for (int i = 0; i < iCntMoving; i++) { item = m_pTableModelMain->item(i, 1); m_strlistBaseName_Moving[i] = item->text(); } for (int i = 0; i < iCntCommand; i++) { item = m_pTableModelMain->item(i, 2); m_strlistBaseName_Command[i] = item->text(); } //Update strlistPath by renaming files. after it is done, update it with DATA2GUI UpdateStrListFromBase(m_strlistBaseName_Fixed, m_strlistPath_Fixed); UpdateStrListFromBase(m_strlistBaseName_Moving, m_strlistPath_Moving); UpdateStrListFromBase(m_strlistBaseName_Command, m_strlistPath_Command); //UpdateMainTable(DATA2GUI); } } void register_gui::UpdateTable_Que() //only Data2Gui direction { if (m_pTableModelQue == NULL) { cout << "error! Initialize table first " << endl; return; } int iCntData = m_vRegiQue.size(); EmptyTableModel(m_pTableModelQue); //set all text "" for (int i = 0; i < iCntData; i++) { CRegiQueString RegiQue = m_vRegiQue.at(i); m_pTableModelQue->setItem(i, 0, new QStandardItem(RegiQue.GetStrFixed())); m_pTableModelQue->setItem(i, 1, new QStandardItem(RegiQue.GetStrMoving())); m_pTableModelQue->setItem(i, 2, new QStandardItem(RegiQue.GetStrCommand())); m_pTableModelQue->setItem(i, 3, new QStandardItem(RegiQue.GetStrStatus())); m_pTableModelQue->setItem(i, 4, new QStandardItem(RegiQue.GetStrTime())); m_pTableModelQue->setItem(i, 5, new QStandardItem(RegiQue.GetStrScore())); //additional data } } void register_gui::UpdateStrListFromBase(QStringList& strListBase, QStringList& strListFull) { int iCntBase = strListBase.count(); int iCntFull = strListFull.count(); if (iCntBase*iCntFull == 0) return; if (iCntBase != iCntFull) { cout << "Error! count is zero or not matched" << endl; return; } QString tmpStrBase; QString tmpStrBaseTrimmed; QString tmpStrPath; QString strPrevBase; QString strNewPath; for (int i = 0; i < iCntFull; i++) { tmpStrBase = strListBase.at(i); tmpStrPath = strListFull.at(i); tmpStrBaseTrimmed = tmpStrBase.trimmed(); QFileInfo tmpInfo(tmpStrPath); strPrevBase = tmpInfo.fileName(); if (strPrevBase != tmpStrBase) { if (tmpStrBaseTrimmed.length() < 1)//empty -->delete it in the list, not file { strNewPath = tmpInfo.absolutePath() + "/" + "_invalid_.txt"; strListFull[i] = strNewPath; } else { //rename whatever. Actual file name will be changed strNewPath = tmpInfo.absolutePath() + "/" + tmpStrBase; //if (tmpInfo.exists()) //rename it! //{ if (QFile::rename(tmpStrPath, strNewPath)) strListFull[i] = strNewPath; //} } } } QStringList newListFull; //trim the list: for (int i = 0; i < iCntFull; i++) { tmpStrPath = strListFull.at(i); QFileInfo newInfo(tmpStrPath); tmpStrBase = newInfo.fileName(); if (tmpStrBase.contains("_invalid_")) { // strListFull.removeAt(i); } else newListFull.push_back(tmpStrPath); } strListFull.clear(); strListFull = newListFull; //UpdateBase from modified full list int iCntNewList = strListFull.count(); strListBase.clear(); for (int i = 0; i < iCntNewList; i++) { tmpStrPath = strListFull.at(i); QFileInfo newInfo2(tmpStrPath); strListBase.push_back(newInfo2.fileName()); } } void register_gui::AdaptCommandFileToNewPath(QString& strPathCommand, QString& strPathFixed, QString& strPathMoving) { QStringList strListOriginal; QString strBaseNameFixed; QString strBaseNameMoving; QString strBaseNameCommand; QString strMiddleDirName; QString strPathOutputDir; strListOriginal = GetStringListFromFile(strPathCommand); QFileInfo fInfoCommand(strPathCommand); strBaseNameCommand = fInfoCommand.completeBaseName(); QFileInfo fInfoFixed(strPathFixed); strBaseNameFixed = fInfoFixed.completeBaseName(); QFileInfo fInfoMoving(strPathMoving); strBaseNameMoving = fInfoMoving.completeBaseName(); strMiddleDirName = "/" + strBaseNameFixed + "/" + strBaseNameMoving + "/" + strBaseNameCommand + "/"; strPathOutputDir = m_strPathDirDefault + strMiddleDirName; //cout << strPathOutputDir.toLocal8Bit().constData() << endl; QStringList newList; newList = ModifyCommandFile(strListOriginal, strPathFixed, strPathMoving, strPathOutputDir); //Change fixed and moving according to current path //QUTIL::PrintStrList(newList); //Save text file SaveCommandText(strPathCommand, newList); } QStringList register_gui::ModifyCommandFile(QStringList& strlistOriginal, QString& strPathFixed, QString& strPathMoving, QString& strPathOut) { QStringList resultList; int cntList = strlistOriginal.count(); QString modLine; QString originalLine; int iStage = 0; QString strEndFix; for (int i = 0; i < cntList; i++) { originalLine = strlistOriginal.at(i); modLine = originalLine; if (originalLine.contains("STAGE")) { iStage = iStage + 1; resultList.push_back(modLine); continue; } if (iStage == 0) strEndFix = "_glb"; else strEndFix = QString("%1%2").arg("_s").arg(iStage); QStringList listStr = originalLine.split("="); QString firstStr = listStr.at(0); if (firstStr.contains("fixed")) { modLine = "fixed=" + strPathFixed; } else if (firstStr.contains("moving")) { modLine = "moving=" + strPathMoving; } else if (firstStr.contains("img_out")) { modLine = "img_out=" + strPathOut + "output_img" + strEndFix + ".mha"; } else if (firstStr.contains("xform_out")) { modLine = "xform_out=" + strPathOut + "output_xform" + strEndFix + ".txt"; } resultList.push_back(modLine); } return resultList; } QStringList register_gui::GetStringListFromFile(const QString& strFile) { QStringList resultStrList; QFile file(strFile); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return resultStrList; QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); resultStrList.push_back(line); } file.close(); return resultStrList; } void register_gui::SLT_ReadCommandFile_Main(QModelIndex index) { //cout << "Activation occurred" << endl; // cout << index.column() << ", " << index.row() << endl; //works only when command file is clicked int row = index.row(); int col = index.column(); QStringList listCurCommand; if (col != 2 || m_strlistPath_Command.count() <= row) { SetCommandViewerText_Main(listCurCommand); return; } //Get path of command file //if it is blank, QStandardItem* item = m_pTableModelMain->itemFromIndex(index); QString curStr = item->text(); if (curStr != m_strlistBaseName_Command.at(row)) { cout << "File name doesn't match" << endl; cout << curStr.toLocal8Bit().constData() << " vs "; cout << m_strlistBaseName_Command.at(row).toLocal8Bit().constData() << endl; return; } //Read the text file and display it QString strPathCommand = m_strlistPath_Command.at(row); ReadCommandFile(strPathCommand, listCurCommand); //Update command file viewer SetCommandViewerText_Main(listCurCommand); QString strDisp = curStr + ".txt"; ui.label_CommandFileCurrent->setText(strDisp); //ui.plainTextEdit->setEnabled(true); //EnableUIForCommandfile(true); } void register_gui::ReadCommandFile(QString& strPathCommandFile, QStringList& strListOutput) { strListOutput.clear(); QFile file(strPathCommandFile); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return; QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); strListOutput.push_back(line); } file.close(); } void register_gui::SLT_ReadCommandFile_Que(QModelIndex index) { int row = index.row(); int col = index.column(); QStringList listCurCommand; int iCntQueItem = m_vRegiQue.size(); if (iCntQueItem <= row) { SetCommandViewerText_Que(listCurCommand); //empty return; } ////Get path of command file //Read the text file and display it //QString strPathCommand = m_strlistPath_Command.at(row); QString strPathCommand = m_vRegiQue.at(row).m_quePathCommand; ReadCommandFile(strPathCommand, listCurCommand); /* QFile file(strPathCommand); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return; QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); listCurCommand.push_back(line); } file.close();*/ //Update command file viewer SetCommandViewerText_Que(listCurCommand); } void register_gui::SLT_UpdateFileList() { UpdateTable_Main(GUI2DATA);//rename and etc... UpdateBaseAndComboFromFullPath(); UpdateTable_Main(DATA2GUI); } //curItem prevItem void register_gui::SLT_SelectionChangedMain(QItemSelection curItem, QItemSelection prevItem) { //return; //only valid if single selection take place //UpdateMainTable(GUI2DATA);//if something renamed. sometimes it should not change the name QModelIndexList listModelIndexCur = curItem.indexes(); int iCntCur = listModelIndexCur.count(); if (iCntCur != 1) return; QModelIndex mIdx = listModelIndexCur.at(0); m_iCurSelRow_Main = mIdx.row(); m_iCurSelCol_Main = mIdx.column(); if (mIdx.column() == 2) SLT_ReadCommandFile_Main(mIdx); } void register_gui::SLT_ItemClickedMain() //single clicked { QModelIndex mIdx = ui.tableView_Stage->currentIndex(); m_iCurSelRow_Main = mIdx.row(); m_iCurSelCol_Main = mIdx.column(); if (mIdx.column() == 2) SLT_ReadCommandFile_Main(mIdx); } //void register_gui::SLT_TableItemSelectedMain() void register_gui::SLT_SelectionChangedQue(QItemSelection curItem, QItemSelection prevItem) { QModelIndexList listModelIndexCur = curItem.indexes(); int iCntCur = listModelIndexCur.count(); //7, all cells in a line were selected if (iCntCur < 1) return; QModelIndex mIdx = listModelIndexCur.at(0);//get first cell m_iCurSelRow_Que = mIdx.row(); m_iCurSelCol_Que = mIdx.column(); SLT_ReadCommandFile_Que(mIdx); } void register_gui::SLT_ItemClickedQue() //single clicked { QModelIndex mIdx = ui.tableView_que->currentIndex(); m_iCurSelRow_Que = mIdx.row(); m_iCurSelCol_Que = mIdx.column(); SLT_ReadCommandFile_Que(mIdx); } void register_gui::SetCommandViewerText_Main(QStringList& strList) { int iCntLines = strList.count(); ui.plainTextEdit_CommandFile->clear(); for (int i = 0; i < iCntLines; i++) { ui.plainTextEdit_CommandFile->appendPlainText(strList.at(i)); } } void register_gui::SetCommandViewerText_Que(QStringList& strList) { int iCntLines = strList.count(); ui.plainTextEdit_Que->clear(); for (int i = 0; i < iCntLines; i++) { ui.plainTextEdit_Que->appendPlainText(strList.at(i)); } } //Read current viewer and save it to stringlist QStringList register_gui::GetCommandViewerText() { QStringList resultList; QString strTmp = ui.plainTextEdit_CommandFile->toPlainText(); //cout << strTmp.toLocal8Bit().constData() << endl; resultList = strTmp.split("\n"); return resultList; } QString register_gui::get_selected_command_template_name () { int curIdx = ui.listWidget_CommandLibrary->currentRow(); if (curIdx < 0) { return QString(""); } return ui.listWidget_CommandLibrary->currentItem()->text(); } void register_gui::set_selected_command_template_name ( const QString& template_name) { QList existing = ui.listWidget_CommandLibrary->findItems (template_name, Qt::MatchExactly); if (!existing.empty()) { existing.first()->setSelected(true); } } void register_gui::save_command_template ( const QString& template_name, QStringList& template_contents // Modified prior to saving ) { if (template_contents.count() < 1) { cout << "Error! No text exists." << endl; return; } // Set all the paths to "TBD" to avoid confusion QStringList::iterator it; for (it = template_contents.begin(); it != template_contents.end(); ++it) { QString strTempLine = (*it); if (strTempLine.contains("fixed=") || strTempLine.contains("fixed =")) { strTempLine = "fixed= TBD"; } else if (strTempLine.contains("moving=") || strTempLine.contains("moving =")) { strTempLine = "moving= TBD"; } else if (strTempLine.contains("fixed_roi=") || strTempLine.contains("fixed_roi =")) { strTempLine = "fixed_roi= TBD"; } else if (strTempLine.contains("img_out=") || strTempLine.contains("img_out =")) { strTempLine = "img_out= TBD"; } else if (strTempLine.contains("xform_out=") || strTempLine.contains("xform_out =")) { strTempLine = "xform_out= TBD"; } (*it) = strTempLine; } // Get App Dir Path, m_str... QDir curTemplateDir(m_strPathCommandTemplateDir); if (!curTemplateDir.exists()) { cout << "Error! No template dir exists" << endl; return; } QString strPathOut = m_strPathCommandTemplateDir + "/" + template_name + ".txt"; SaveCommandText (strPathOut, template_contents); // Update template list UpdateCommandFileTemplateList (m_strPathCommandTemplateDir); set_selected_command_template_name (template_name); } void register_gui::SLT_SaveCommandText() { QStringList strList = GetCommandViewerText();//from main QString strPath; if (m_iCurSelRow_Main >= 0 && m_iCurSelRow_Main < m_strlistPath_Command.count() && m_iCurSelCol_Main == 2) { strPath = m_strlistPath_Command.at(m_iCurSelRow_Main); SaveCommandText(strPath, strList); SetCommandViewerText_Main(strList); //Check, is this needed?? cout << strPath.toLocal8Bit().constData() << ": Text file was saved." << endl; } } void register_gui::SLT_CommandFileSaveAs() { QString template_name; bool got_name = false; while (true) { // Popup input box to ask the template name. // Abort if cancel. QInputDialog inputDlg; bool ok; template_name = QInputDialog::getText ( this, "Save a new Template", "Input Command Template Name", QLineEdit::Normal, "template name", &ok); if (!ok || template_name.isEmpty()) { return; } // Check to see if item already exists, if so, pop up again QList existing = ui.listWidget_CommandLibrary->findItems (template_name, Qt::MatchExactly); if (existing.count() > 0) { QMessageBox::warning (this, tr("Warning"), tr ("Template with that name already exists. Try another name."), QMessageBox::Ok); continue; } break; } QStringList strList = GetCommandViewerText(); save_command_template (template_name, strList); } void register_gui::SLT_CommandFileSave() { QString template_name = get_selected_command_template_name (); if (template_name.isEmpty()) { return; } QStringList template_contents = GetCommandViewerText(); save_command_template (template_name, template_contents); } void register_gui::SaveCommandText ( QString& strPathCommand, QStringList& strListLines) { ofstream fout; fout.open(strPathCommand.toLocal8Bit().constData()); int cnt = strListLines.count(); for (int i = 0; i < cnt; i++) { fout << strListLines.at(i).toLocal8Bit().constData() << endl; } fout.close(); } void register_gui::DeleteRemainingThreads() { cout << "Running into a while loop for deleting remaining threads..." ; int cntRunningThread = 1; if (m_pArrThreadRegi != NULL) { while (cntRunningThread != 0) { cntRunningThread = 0; for (int i = 0; i < m_iNumOfThreadAll; i++) { if (m_pArrThreadRegi[i] != NULL) { cntRunningThread++; if (!m_pArrThreadRegi[i]->isRunning()) { delete m_pArrThreadRegi[i]; m_pArrThreadRegi[i] = NULL; cout << "Thread ID " << i << " has been deleted" << endl; } } } } } delete[] m_pArrThreadRegi; m_pArrThreadRegi = NULL; cout << "Done!" << endl; } void register_gui::SetTableText(int row, int col, QString& inputStr) { m_pTableModelMain->setItem(row, col, new QStandardItem(inputStr)); } void register_gui::SLT_AddSingleToQue() { #if defined (commentout) QString strFixed, strMoving, strCommand; int curIndex_fixed = ui.comboBox_Fixed->currentIndex(); int curIndex_moving = ui.comboBox_Moving->currentIndex(); int curIndex_command = ui.comboBox_Command->currentIndex(); if (curIndex_fixed < 0 || curIndex_moving < 0 || curIndex_command < 0) return; int RowCnt = m_pTableModelQue->rowCount(); // int ColCnt = m_pTableModelQue->columnCount(); int curDataSize = m_vRegiQue.size(); if (curDataSize == RowCnt) { cout << "Error! Que Table is full! Current maximum size = " << RowCnt << " Inquire about it to plastimatch group." << endl; return; } //when only valid if (curIndex_fixed < m_strlistPath_Fixed.count() && curIndex_moving < m_strlistPath_Moving.count() && curIndex_command < m_strlistPath_Command.count()) { strFixed = m_strlistPath_Fixed.at(curIndex_fixed); strMoving = m_strlistPath_Moving.at(curIndex_moving); strCommand = m_strlistPath_Command.at(curIndex_command); if (m_vRegiQue.size() >= DEFAULT_MAXNUM_QUE) { cout << "Error! Maximum number of que items = " << DEFAULT_MAXNUM_QUE << endl; return; } AddSingleToQue(strFixed, strMoving, strCommand); //data only } else { cout << "Error. No data exists" << endl; } UpdateTable_Que(); #endif } //Read strlistPaths and get the min number of lines to add void register_gui::SLT_AddMultipleToQueByLine() { int iCntFixed = m_strlistPath_Fixed.count(); int iCntMoving = m_strlistPath_Moving.count(); int iCntCommand = m_strlistPath_Command.count(); int minCnt = 9999; if (iCntFixed < minCnt) minCnt = iCntFixed; if (iCntMoving < minCnt) minCnt = iCntMoving; if (iCntCommand < minCnt) minCnt = iCntCommand; cout << "Minimum number of count = " << minCnt << endl; QString strFixed, strMoving, strCommand; for (int i = 0; i < minCnt; i++) { strFixed = m_strlistPath_Fixed.at(i); strMoving = m_strlistPath_Moving.at(i); strCommand = m_strlistPath_Command.at(i); if (m_vRegiQue.size() >= DEFAULT_MAXNUM_QUE) { cout << "Error! Maximum number of que items = " << DEFAULT_MAXNUM_QUE << endl; return; } AddSingleToQue(strFixed, strMoving, strCommand); //data only } UpdateTable_Que(); } void register_gui::SLT_AddMultipleToQueByPermu() { QString strFixed, strMoving, strCommand; int iCntFixed = m_strlistPath_Fixed.count(); int iCntMoving = m_strlistPath_Moving.count(); int iCntCommand = m_strlistPath_Command.count(); int iCopyCnt = 0; for (int k = 0; k < iCntFixed; k++) { for (int i = 0; i < iCntMoving; i++) { for (int j = 0; j < iCntCommand; j++) { strFixed = m_strlistPath_Fixed.at(k); strMoving = m_strlistPath_Moving.at(i); strCommand = m_strlistPath_Command.at(j); QString endFix = "_" + QString::number(iCopyCnt); QString newStrCommandPath; if (iCopyCnt == 0) newStrCommandPath = strCommand; else { newStrCommandPath = QUTIL::GetPathWithEndFix(strCommand, endFix); //copy QFile::copy(strCommand, newStrCommandPath); } if (m_vRegiQue.size() >= DEFAULT_MAXNUM_QUE) { cout << "Error! Maximum number of que items = " << DEFAULT_MAXNUM_QUE << endl; return; } AddSingleToQue(strFixed, strMoving, newStrCommandPath); //data only } iCopyCnt++; } } UpdateTable_Que(); } Job_group_type register_gui::get_action_pattern () { if (ui.buttonGroup_actionPattern->checkedButton() == ui.radioButton_m2f) { return JOB_GROUP_MOVING_TO_FIXED; } if (ui.buttonGroup_actionPattern->checkedButton() == ui.radioButton_a2f) { return JOB_GROUP_ALL_TO_FIXED; } if (ui.buttonGroup_actionPattern->checkedButton() == ui.radioButton_a2a) { return JOB_GROUP_ALL_TO_ALL; } return JOB_GROUP_MOVING_TO_FIXED; } QString register_gui::get_fixed_pattern () { return ui.lineEdit_fixedPattern->text (); } QString register_gui::get_moving_pattern () { return ui.lineEdit_movingPattern->text (); } bool register_gui::get_repeat_for_peers () { return ui.checkBox_repeatForPeers->isChecked (); } void register_gui::SLT_BrowseFixedPattern () { QString pattern; if (get_action_pattern() == JOB_GROUP_ALL_TO_ALL) { QFileDialog::Options options = QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly; pattern = QFileDialog::getExistingDirectory ( this, tr("Choose directory"), ui.lineEdit_fixedPattern->text (), options); } else { QFileDialog::Options options = QFileDialog::DontResolveSymlinks; QString filters = tr( "Images (*.mha *.mhd *.nii *.nrrd);;All files (*)"); QString selected_filter = tr("Images (*.mha *.mhd *.nii *.nrrd)"); pattern = QFileDialog::getOpenFileName ( this, tr("Choose file"), ui.lineEdit_fixedPattern->text (), filters, &selected_filter, options); } ui.lineEdit_fixedPattern->setText (pattern); } void register_gui::SLT_BrowseMovingPattern () { QString dirPath = QFileDialog::getExistingDirectory (this, tr("Open Work Directory"), ui.lineEdit_movingPattern->text (), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); ui.lineEdit_movingPattern->setText (dirPath); } void register_gui::get_image_files ( QStringList& image_list, const QString& pattern, bool repeat_for_peers) { QFileInfo file_info (pattern); if (!file_info.exists ()) { return; } else if (file_info.isFile ()) { image_list.append (pattern); } else if (file_info.isDir ()) { QDir dir (pattern); QFileInfoList file_list = dir.entryInfoList (QDir::Files, QDir::Name); for (QFileInfoList::const_iterator i = file_list.begin (); i != file_list.end (); ++i) { printf ("FIXED: %s\n", QUTIL::c_str(i->fileName())); } } } void register_gui::SLT_AddImages () { Job_group_type action_pattern = get_action_pattern (); QString fixed_pattern = get_fixed_pattern (); QString moving_pattern = get_moving_pattern (); bool repeat_for_peers = get_repeat_for_peers (); printf ("Action: %d\n", action_pattern); printf ("Fixed: %s\n", fixed_pattern.toUtf8().constData()); printf ("Moving: %s\n", moving_pattern.toUtf8().constData()); printf ("Repeat: %s\n", repeat_for_peers ? "true" : "false"); m_actions.append (action_pattern); m_strlistPath_Fixed.append (fixed_pattern); m_strlistPath_Moving.append (moving_pattern); UpdateBaseAndComboFromFullPath(); UpdateTable_Main(DATA2GUI); } void register_gui::SLT_QueueJobs () { int num_actions = std::min ( m_actions.count(), std::min ( m_strlistPath_Fixed.count(), m_strlistPath_Moving.count())); int num_commands = m_strlistPath_Command.count(); printf ("Queuing jobs %d %d\n", num_actions, num_commands); bool repeat_for_peers = false; for (int i = 0; i < num_actions; i++) { Job_group_type action_pattern = m_actions.at(i); QString fixed_pattern = m_strlistPath_Fixed.at(i); QString moving_pattern = m_strlistPath_Moving.at(i); if (fixed_pattern == "" || moving_pattern == "") { printf ("Refused to queue ill-formed job\n"); continue; } // Action pattern = f2m QStringList fixed_images; QStringList moving_images; if (action_pattern == JOB_GROUP_MOVING_TO_FIXED) { get_image_files (fixed_images, fixed_pattern, repeat_for_peers); } for (int j = 0; j < num_commands; j++) { QString strCommand = m_strlistPath_Command.at(j); printf ("Action: %d\n", action_pattern); printf ("Fixed: %s\n", fixed_pattern.toUtf8().constData()); printf ("Moving: %s\n", moving_pattern.toUtf8().constData()); // Do something } } UpdateTable_Que(); } void register_gui::AddSingleToQue ( QString& strPathFixed, QString& strPathMoving, QString& strPathCommand) { QFileInfo finfo_fixed, finfo_moving, finfo_command; finfo_fixed = QFileInfo(strPathFixed); finfo_moving = QFileInfo(strPathMoving); finfo_command = QFileInfo(strPathCommand); if (finfo_fixed.exists() && finfo_moving.exists() && finfo_command.exists()) { AdaptCommandFileToNewPath(strPathCommand, strPathFixed, strPathMoving);//rewrite the text file according to input paths CRegiQueString RegiQue; RegiQue.m_quePathFixed = strPathFixed; RegiQue.m_quePathMoving = strPathMoving; RegiQue.m_quePathCommand = strPathCommand; m_vRegiQue.push_back(RegiQue); } else { cout << "Error! some files don't exist! ExistFlag: fixed-moving-command= x" << finfo_fixed.exists() << ", " << finfo_moving.exists() << ", " << finfo_command.exists() << endl; return; } } // //void register_gui::SLT_CopySelectionToAll_Command() //{ // int row = m_iCurSelRow_Main; // if (m_iCurSelCol_Main == 0) //fixed image: copy only memory, not whole image // { // QString strPathFixed = m_strlistPath_Fixed.at(row); // // int curFilledCnt = m_strlistPath_Fixed.count(); // // for (int i = curFilledCnt; i < m_iNumOfTableRow; i++) // { // m_strlistPath_Fixed.push_back(strPathFixed); // // QFileInfo tmpInfo = QFileInfo(strPathFixed); // m_strlistBaseName_Fixed.push_back(tmpInfo.fileName()); // } // } // else if (m_iCurSelCol_Main == 1) //mvoing image: copy only memory, not whole image // { // QString strPathMoving = m_strlistPath_Moving.at(row); // // int curFilledCnt = m_strlistPath_Moving.count(); // // QFileInfo tmpInfo = QFileInfo(strPathMoving); // // for (int i = curFilledCnt; i < m_iNumOfTableRow; i++) // { // m_strlistPath_Moving.push_back(strPathMoving); // m_strlistBaseName_Moving.push_back(tmpInfo.fileName()); // } // } // else if (m_iCurSelCol_Main == 2) //command file. copy and rename automatically // { // QString strPathCommand = m_strlistPath_Command.at(row); // int curFilledCnt = m_strlistPath_Command.count(); // QFileInfo tmpInfo = QFileInfo(strPathCommand); // // for (int i = curFilledCnt; i < m_iNumOfTableRow; i++) // { // QString endFix = QString::number(i + 1); // QString strPathCommandNew = tmpInfo.absolutePath() + "/" + tmpInfo.completeBaseName() + "_" + endFix + "." + tmpInfo.completeSuffix(); // // QFile::copy(strPathCommand, strPathCommandNew); // // m_strlistPath_Command.push_back(strPathCommandNew); // // QFileInfo tmpInfo2 = QFileInfo(strPathCommandNew); // m_strlistBaseName_Command.push_back(tmpInfo2.fileName()); // } // } // // // UpdateMainTable(DATA2GUI); //} void register_gui::SLT_CopyCommandFile() { #if defined (commentout) int row = m_iCurSelRow_Main; if (m_iCurSelCol_Main != 2) { cout << "Error! Select a single cell containing a command file." << endl; return; } if (row >= m_strlistPath_Command.count()) return; QString strPathCommand = m_strlistPath_Command.at(row); int curFilledCnt = m_strlistPath_Command.count(); QFileInfo tmpInfo = QFileInfo(strPathCommand); int iNumOfFiles = ui.lineEdit_NumOfCopy->text().toInt(); int iEndIndex = curFilledCnt + iNumOfFiles; for (int i = curFilledCnt; i < iEndIndex; i++) { QString endFix = QString::number(i + 1); QString strPathCommandNew = tmpInfo.absolutePath() + "/" + tmpInfo.completeBaseName() + "_" + endFix + "." + tmpInfo.completeSuffix(); QFile::copy(strPathCommand, strPathCommandNew); m_strlistPath_Command.push_back(strPathCommandNew); QFileInfo tmpInfo2 = QFileInfo(strPathCommandNew); m_strlistBaseName_Command.push_back(tmpInfo2.fileName()); } UpdateTable_Main(DATA2GUI); //should be called first! SLT_UpdateFileList(); #endif } void register_gui::SLT_ClearCommandFiles() { m_strlistPath_Command.clear(); //m_strlistBaseName_Command.clear(); UpdateBaseAndComboFromFullPath(); UpdateTable_Main(DATA2GUI); } void register_gui::SLT_SortSelectedColumn() { if (m_iCurSelCol_Main == 0) //fixed { m_strlistPath_Fixed.sort(); } if (m_iCurSelCol_Main == 1) { m_strlistPath_Moving.sort(); } if (m_iCurSelCol_Main == 2) { m_strlistPath_Command.sort(); } UpdateBaseAndComboFromFullPath(); UpdateTable_Main(DATA2GUI); } void register_gui::SLT_ClearQueAll() { m_vRegiQue.clear(); UpdateTable_Que(); } void register_gui::SLT_RemoveSelectedQue() { int iSelectedRowQue = m_iCurSelRow_Que; if (iSelectedRowQue >= m_vRegiQue.size() || iSelectedRowQue < 0) return; m_vRegiQue.erase(m_vRegiQue.begin() + iSelectedRowQue); UpdateTable_Que(); m_iCurSelRow_Que = -1; m_iCurSelCol_Que = -1; } //Thread ID = index of Que table (max = 200) void register_gui::SLT_RunSingleSelected() { int iSelected = m_iCurSelRow_Que; if (!RunRegistrationSingle(iSelected)) { cout << "Error in RunRegistrationSingle!" << endl; } } bool register_gui::RunRegistrationSingle(int index) { if (index >= m_vRegiQue.size() || index < 0) return false; // if the status is not waiting, do not. CRegiQueString RegiQue = m_vRegiQue.at(index); if (RegiQue.m_iStatus != ST_NOT_STARTED) { if (RegiQue.m_iStatus == ST_DONE) { cout << "Cannot perform the registration. This job is done already." << endl; return false; } else if (RegiQue.m_iStatus == ST_PENDING) { cout << "Cannot perform the registration. This job is currently pending." << endl; return false; } } else { QString strPathCommmand = RegiQue.m_quePathCommand; QString strFileCommmand = RegiQue.GetStrCommand(); m_pArrThreadRegi[index] = new YKThreadRegi(this, strPathCommmand, index); cout << "Starting thread ID= " << index << ". Command file name= " << strFileCommmand.toLocal8Bit().constData() << endl; m_pArrThreadRegi[index]->start(QThread::NormalPriority); m_pArrThreadRegi[index]->exit(); } return true; } void register_gui::SLT_RunBatchSequential() { if (m_timerRunMultiThread->isActive()) { cout << "Error! Finish MT timer first" << endl; return; } //if there is any pending, don't run int iCntPending = GetCountPendingJobs(); if (iCntPending == 0) { m_timerRunSequential->start(500);//Look up every 0.5 s and run next registration m_tTimeSeq = QTime::currentTime(); ui.lineEdit_TotalProcTimeSeq->setText(""); } else cout << "Cannot run! please wait until there is no pending job" << endl; } void register_gui::SLT_RunBatchMultiThread() { if (m_vRegiQue.empty()) return; if (m_timerRunSequential->isActive()) { cout << "Error! Finish Sequential timer first" << endl; return; } int iCntPending = GetCountPendingJobs(); int iCntStandBy = GetCountStandByJobs(); if (iCntPending == 0 && iCntStandBy > 0) { m_timerRunMultiThread->start(500);//Look up every 0.5 s and run next registration m_tTimeMT = QTime::currentTime(); ui.lineEdit_TotalProcTimeMT->setText(""); } else cout << "Cannot run due to pending jobs or all-done jobs" << endl; } int register_gui::GetCountPendingJobs() { int iCntPending = 0; int iCntQued = m_vRegiQue.size(); for (int i = 0; i < iCntQued; i++) { if (m_vRegiQue.at(i).m_iStatus == ST_PENDING) { iCntPending++; } } return iCntPending; } int register_gui::GetCountStandByJobs() { int iCntStandby = 0; int iCntQued = m_vRegiQue.size(); for (int i = 0; i < iCntQued; i++) { if (m_vRegiQue.at(i).m_iStatus == ST_NOT_STARTED) { iCntStandby++; } } return iCntStandby; } //Continue until there is no "NOt_Started" items. void register_gui::SLT_TimerRunSEQ() //monitor the value { if (m_vRegiQue.empty()) { m_timerRunSequential->stop(); QString strNum = QString::number(m_tTimeSeq.elapsed() / 1000.0, 'f', 2); ui.lineEdit_TotalProcTimeSeq->setText(strNum); cout << "Timer stopped. Empty que" << endl; return; } int iCntPending = GetCountPendingJobs(); if (iCntPending > 0) return; int iCntQued = m_vRegiQue.size(); //if no pending //find the target index int targetIdx = -1; for (int i = 0; i < iCntQued; i++) { if (m_vRegiQue.at(i).m_iStatus == ST_NOT_STARTED) { targetIdx = i; break; } } if (targetIdx < 0) //if there is no NOT_STARTED item { QString strNum = QString::number(m_tTimeSeq.elapsed() / 1000.0, 'f', 2); ui.lineEdit_TotalProcTimeSeq->setText(strNum); cout << "Timer stopped. No more items to register." << endl; m_timerRunSequential->stop(); } else { RunRegistrationSingle(targetIdx); } return; } void register_gui::SLT_TimerRunMT() { if (m_vRegiQue.empty()) { m_timerRunMultiThread->stop(); QString strNum = QString::number(m_tTimeMT.elapsed() / 1000.0, 'f', 2); ui.lineEdit_TotalProcTimeMT->setText(strNum); cout << "Timer stopped. Empty que" << endl; return; } int iMaxNumThread = ui.lineEdit_MaxNumberThread->text().toInt(); int iCntPending = GetCountPendingJobs(); int iAvailableSlots = iMaxNumThread - iCntPending; if (iAvailableSlots < 1) return; int iCntQued = m_vRegiQue.size(); vector vTargetIdx; vector vPendingIdx; //int targetIdx = -1; for (int i = 0; i < iCntQued; i++) { if (m_vRegiQue.at(i).m_iStatus == ST_NOT_STARTED) vTargetIdx.push_back(i); else if (m_vRegiQue.at(i).m_iStatus == ST_PENDING) vPendingIdx.push_back(i); if (vTargetIdx.size() >= iAvailableSlots) break; } if (vTargetIdx.empty() && vPendingIdx.empty()) //if there is no NOT_STARTED item { QString strNum = QString::number(m_tTimeMT.elapsed() / 1000.0, 'f', 2); ui.lineEdit_TotalProcTimeMT->setText(strNum); cout << "Timer stopped. No more items to register." << endl; m_timerRunMultiThread->stop(); } else { vector::iterator it; int curIdx = 0; for (it = vTargetIdx.begin(); it != vTargetIdx.end(); ++it) { curIdx = (*it); RunRegistrationSingle(curIdx); } } return; } void register_gui::SLT_OpenSelectedOutputDir() { int iSelected = m_iCurSelRow_Que; if (iSelected < 0 || iSelected >= m_vRegiQue.size()) { cout << "Error! Selection is not valid. Try other ones." << endl; return; } QString strPathCommand = m_vRegiQue.at(iSelected).m_quePathCommand; QString strDirPathOutput = GetStrInfoFromCommandFile(PLM_OUTPUT_DIR_PATH, strPathCommand); QDir dirOutput(strDirPathOutput); if (!dirOutput.exists()) { cout << "Error! The directory cannot found. You should run registration first" << endl; return; } cout << "Found output dir= " << strDirPathOutput.toLocal8Bit().constData() << endl; QString path = QDir::toNativeSeparators(strDirPathOutput);// ..(QApplication::applicationDirPath()); QDesktopServices::openUrl(QUrl("file:///" + path)); // Alternative: //#if defined Q_OS_WIN32 // // start explorer process here. E.g. "explorer.exe C:\windows" // QString strCommand = QString("explorer %1").arg(strDirPathOutput); //works in linux as well?? // //strCommand = explorer H:/CBCT2/CT1/command1 --> // strCommand.replace('/', '\\'); // ::system(strCommand.toLocal8Bit().constData()); //#elif defined Q_OS_LINUX // QString strCommand = QString("gnome-open %1").arg(strDirPathOutput); // ::system(strCommand.toLocal8Bit().constData()); //#elif defined Q_OS_MAC // // start WHATEVER filebrowser here // QString strCommand = QString("open %1").arg(strDirPathOutput); // ::system(strCommand.toLocal8Bit().constData()); //#endif } QString register_gui::GetStrInfoFromCommandFile(enPlmCommandInfo plmInfo, QString& strPathCommandFile) { QString resultStr; QStringList tmpStrList = GetStringListFromFile(strPathCommandFile); QString strTempLine; QString strLineExcerpt; int iCntLine = tmpStrList.count(); for (int i = 0; i < iCntLine; i++) { strTempLine = tmpStrList.at(i); if (plmInfo == PLM_OUTPUT_DIR_PATH && (strTempLine.contains("img_out=") || strTempLine.contains("img_out ="))) { strLineExcerpt = strTempLine; break; } /*else if (plmInfo == enPlmCommandInfo::PLM_OUTPUT_DIR_PATH && (strTempLine.contains("img_out=") || strTempLine.contains("img_out ="))) { strLineImgOut = strTempLine; break; }*/ } QStringList infoStrList = strLineExcerpt.split("="); QString infoStr; if (infoStrList.count() > 1) infoStr = infoStrList.at(1); infoStr = infoStr.trimmed(); //remove only first and last spaces if (plmInfo == PLM_OUTPUT_DIR_PATH) { QFileInfo fInfo(infoStr); if (fInfo.exists()) { resultStr = fInfo.absolutePath(); } } return resultStr; } QStringList register_gui::GetImagePathListFromCommandFile(QString& strPathCommandFile) { QStringList listImgPath; QStringList tmpStrList = GetStringListFromFile(strPathCommandFile); QString strLineExcerpt; int iCntLine = tmpStrList.count(); QString strTempLine; for (int i = 0; i < iCntLine; i++) { strTempLine = tmpStrList.at(i); if (strTempLine.contains("fixed=") || strTempLine.contains("fixed =") || strTempLine.contains("moving=") || strTempLine.contains("moving =") || strTempLine.contains("img_out=") || strTempLine.contains("img_out =") ) { QString strPath; QStringList infoStrList = strTempLine.split("="); if (infoStrList.count() > 1) strPath = infoStrList.at(1); strPath = strPath.trimmed(); if (strPath.length() > 1) listImgPath.push_back(strPath); } } return listImgPath; } //Put final command file on void register_gui::CopyCommandFileToOutput(QString& strPathOriginCommandFile) { QFileInfo fInfo(strPathOriginCommandFile); if (!fInfo.exists()) { cout << "Error! Orinal file doesn't exist" << endl; return; } QString strOutputDir = GetStrInfoFromCommandFile(PLM_OUTPUT_DIR_PATH, strPathOriginCommandFile); QString strNewPath = strOutputDir + "/" + fInfo.fileName(); QFile::copy(strPathOriginCommandFile, strNewPath); } void register_gui::ExportQueResult(QString& strPathOut) { if (m_vRegiQue.empty()) return; int iCnt = m_vRegiQue.size(); ofstream fout; fout.open(strPathOut.toLocal8Bit().constData()); if (fout.fail()) { cout << "File open failed." << endl; return; } fout << "Registration report-" << QUTIL::GetTimeStampDirName().toLocal8Bit().constData() << endl; fout << "Fixed" << "\t" << "Moving" << "\t" << "CommandFile" << "\t" << "Status" << "\t" << "Time(s)" << "\t" << "Score1" << "\t" << "Score2" << endl; for (int i = 0; i < iCnt; i++) { CRegiQueString curItem = m_vRegiQue.at(i); fout << curItem.m_quePathFixed.toLocal8Bit().constData() << "\t" << curItem.m_quePathMoving.toLocal8Bit().constData() << "\t" << curItem.m_quePathCommand.toLocal8Bit().constData() << "\t" << curItem.GetStrStatus().toLocal8Bit().constData() << "\t" << curItem.GetStrTime().toLocal8Bit().constData() << "\t" << curItem.GetStrScore().toLocal8Bit().constData() << "\t" << curItem.GetStrScore().toLocal8Bit().constData() << endl; } fout.close(); //QString timeStamp = QUTIL::GetTimeStampDirName(); //QString strPathDirAnalysis = m_strPathDirWorkDir + "/" + strSubAnalysis } void register_gui::SLTM_ExportQueResult() { QString strFilePath = QFileDialog::getSaveFileName(this, "Save registration report file", m_strPathDirDefault, "report (*.txt)", 0, 0); if (strFilePath.length() < 1) return; QFileInfo fInfo(strFilePath); if (fInfo.suffix() != "txt" && fInfo.suffix() != "TXT") { strFilePath = strFilePath + ".txt"; } ExportQueResult(strFilePath); } void register_gui::SLT_CopyTableQueToClipboard() { if (m_vRegiQue.empty()) return; qApp->clipboard()->clear(); QStringList list; int rowCnt = m_pTableModelQue->rowCount(); int columnCnt = m_pTableModelQue->columnCount(); list << "\n"; list << "Fixed"; list << "Moving"; list << "CommandFile"; list << "Status"; list << "Processing_Time(s)"; list << "Score1"; list << "Score2"; list << "\n"; for (int j = 0; j < rowCnt; j++) { for (int i = 0; i < columnCnt; i++) { QStandardItem* item = m_pTableModelQue->item(j, i); list << item->text(); } list << "\n"; } qApp->clipboard()->setText(list.join("\t")); } void register_gui::SLT_ViewSelectedImg() { int iSelected = m_iCurSelRow_Que; if (iSelected < 0 || iSelected >= m_vRegiQue.size()) { cout << "Error! Selection is not valid. Try other ones." << endl; return; } QString strPathCommand = m_vRegiQue.at(iSelected).m_quePathCommand; QStringList strlistFilePath = GetImagePathListFromCommandFile(strPathCommand); //Check available app first QFileInfo fInfoApp(m_strPathReadImageApp); if (!fInfoApp.exists()) { QUTIL::ShowErrorMessage("Error! Viewer application is not found!"); return; } int iCntPath = strlistFilePath.count(); QString curPath; QStringList validFiles; for (int i = 0; i < iCntPath; i++) { curPath = strlistFilePath.at(i); QFileInfo fInfoimg(curPath); if (fInfoimg.exists()) { validFiles.push_back(curPath); } } //Shell command QString strShellCommand = m_strPathReadImageApp; strShellCommand = "\"" + strShellCommand + "\""; //IMPORTANT! due to the "Program Files" space issue int iCntValidImg = validFiles.count(); for (int i = 0; i < iCntValidImg; i++) { strShellCommand = strShellCommand + " " + validFiles.at(i); } // strShellCommand = "\"" + strShellCommand + "\""; if (!QProcess::startDetached(strShellCommand)) cout << "Failed to run viewer app. Command= " << strShellCommand.toLocal8Bit().constData() << endl; } void register_gui::write_application_settings() { QSettings settings; //QString test = QFileInfo(settings.fileName()).absolutePath(); //H:HKEY_CURRENTUSER_SOFTWARE/Plastimatch --> no such folder settings.setValue ("DEFAULT_WORK_DIR", m_strPathDirDefault); settings.setValue ("DEFAULT_VIEWER_PATH", m_strPathReadImageApp); //settings.setValue("DEFAULT_TEMPLATE_DIR_PATH", m_strPathCommandTemplateDir); } bool register_gui::read_application_settings() { QSettings settings; QVariant val = settings.value ("DEFAULT_WORK_DIR"); if (!val.isNull()) { SetWorkDir(val.toString()); } else { // Set workdir to folder of current directory QString strPathCurrent = QDir::current().absolutePath(); SetWorkDir(strPathCurrent); } val = settings.value ("DEFAULT_VIEWER_PATH"); if (!val.isNull()) { SetReadImageApp(val.toString()); } return true; } void register_gui::CreateDefaultCommandFile(enRegisterOption option) { QString strPathDefaultCommand; if (option == PLAST_RIGID) { strPathDefaultCommand = m_strPathCommandTemplateDir + "/" + "Default_Rigid.txt"; } else if (option == PLAST_BSPLINE) { strPathDefaultCommand = m_strPathCommandTemplateDir + "/" + "Default_B-spline.txt"; } else if (option == PLAST_AFFINE) { strPathDefaultCommand = m_strPathCommandTemplateDir + "/" + "Default_Affine.txt"; } else if (option == PLAST_GRADIENT) { strPathDefaultCommand = m_strPathCommandTemplateDir + "/" + "Default_Gradient.txt"; } else { return; } QUTIL::GenDefaultCommandFile(strPathDefaultCommand, option); } void register_gui::UpdateCommandFileTemplateList (QString& strPathTemplateDir) { //Search in default template directory if (strPathTemplateDir.length() < 1) return; //Look into the specified directory and load all the text files QDir dirCmdTemplate(strPathTemplateDir); if (!dirCmdTemplate.exists()) return; ui.listWidget_CommandLibrary->clear(); QFileInfoList listFile = dirCmdTemplate.entryInfoList(QDir::Files, QDir::Name); //search for DICOM RS file if (listFile.size() <= 0) { cout << "No template file was found." << endl; return; } else { for (int i = 0; i < listFile.size(); i++) { if (listFile.at(i).suffix().contains("txt", Qt::CaseInsensitive)) { QString strBaseName = listFile.at(i).baseName(); ui.listWidget_CommandLibrary->addItem(strBaseName); } } } } // This gets called when an item in the command file library listbox // gets selected void register_gui::SLT_CommandTemplateSelected() { int curIdx = ui.listWidget_CommandLibrary->currentRow(); if (curIdx < 0) { return; } QString strBase = ui.listWidget_CommandLibrary->currentItem()->text(); QString curTemplateFilePath = m_strPathCommandTemplateDir + "/" + strBase + ".txt"; QStringList listCurCommand; ReadCommandFile(curTemplateFilePath, listCurCommand); SetCommandViewerText_Main(listCurCommand); QString strDisp = strBase; ui.label_CommandFileCurrent->setText(strDisp); } void register_gui::EnableUIForCommandfile(bool bEnable) { ui.groupBox_CommandFile->setEnabled(bEnable); //could be individualized for each components such as.. //ui.plainTextEdit->setEnabled(false); } void register_gui::SLT_CopyCommandTemplateToDataPool() { int curIdx = ui.listWidget_CommandLibrary->currentRow(); if (curIdx < 0) return; QString curFileBase = ui.listWidget_CommandLibrary->currentItem()->text(); QString strPathSrc = m_strPathCommandTemplateDir + "/" + curFileBase + ".txt"; QFileInfo fInfo(strPathSrc); if (!fInfo.exists()) return; //Remove "Default" QString strNewBase; if (curFileBase.contains("Default_", Qt::CaseInsensitive)) strNewBase = curFileBase.replace("Default_", "Custom_", Qt::CaseInsensitive); else strNewBase = "Custom_" + curFileBase; //working directory QString strPathTarget = m_strPathDirDefault + "/" + strNewBase + ".txt"; QString strPathTargetMod; //final file path to avoid overwritten if (!WriteCommandNoOverwriting(strPathSrc, strPathTarget, strPathTargetMod)) //write it with end fix if it is to be overwritten { cout << "Error in writing." << endl; return; } // QFile::copy(strPathCommand, strPathCommandNew); m_strlistPath_Command.push_back(strPathTargetMod); QFileInfo tmpInfo2 = QFileInfo(strPathTargetMod); m_strlistBaseName_Command.push_back(tmpInfo2.fileName()); UpdateTable_Main(DATA2GUI); SLT_UpdateFileList(); } bool register_gui::WriteCommandNoOverwriting(QString& strPathSrc, QString& strPathTarget, QString& strPathTargetMod) { //strPathSrc exists --> chekced already //Check target path QFileInfo fInfoTargOriginal(strPathTarget); QString strBaseName = fInfoTargOriginal.baseName(); QString curPathOutput = strPathTarget; int iEndFix = 0; QString strEndFix = ""; while (true) { QFileInfo fInfoTarg(curPathOutput); if (!fInfoTarg.exists()) //good { strPathTargetMod = curPathOutput; break; } else { ++iEndFix; strEndFix = "_" + QString::number(iEndFix); curPathOutput = fInfoTargOriginal.absolutePath() + "/" + strBaseName + strEndFix + "." + fInfoTargOriginal.suffix(); } } QFile::copy(strPathSrc, strPathTargetMod); return true; } void register_gui::SLT_BrowseWorkingDir() { QString strPathDir = m_strPathDirDefault; QDir dir(strPathDir); if (!dir.exists()) { cout << "Error! No dir exists" << endl; return; } QString path = QDir::toNativeSeparators(strPathDir);// ..(QApplication::applicationDirPath()); QDesktopServices::openUrl(QUrl("file:///" + path)); } void register_gui::SLT_BrowseTemplateDir() { QString strPathDir = m_strPathCommandTemplateDir; QDir dir(strPathDir); if (!dir.exists()) { cout << "Error! No dir exists" << endl; return; } QString path = QDir::toNativeSeparators(strPathDir);// ..(QApplication::applicationDirPath()); QDesktopServices::openUrl(QUrl("file:///" + path)); } void register_gui::SLT_DeleteSingleTemplate() { int curIdx = ui.listWidget_CommandLibrary->currentRow(); if (curIdx < 0) return; QString curFileBase = ui.listWidget_CommandLibrary->currentItem()->text(); QString strPathSrc = m_strPathCommandTemplateDir + "/" + curFileBase + ".txt"; QFileInfo fInfo(strPathSrc); if (!fInfo.exists()) return; //Get confirmation QMessageBox msgBox; QString strMsg = "Command template: " + curFileBase + " will be permanently deleted from the folder. Are you sure?"; msgBox.setText(strMsg); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); int res = msgBox.exec(); if (res == QMessageBox::Ok) { //delete the file bool bSuccess = QFile::remove(strPathSrc); if (bSuccess) cout << "Template file: " << strPathSrc.toLocal8Bit().constData() << " was removed. Default templates will be regenerated when restarting the application." << endl; else { cout << "Error! Template file: " << strPathSrc.toLocal8Bit().constData() << " couldn't be removed." << endl; return; } } UpdateCommandFileTemplateList(m_strPathCommandTemplateDir); } void register_gui::SLTM_ImportDataPool() { QString filePath = QFileDialog::getOpenFileName(this, "Open Data pool log file", m_strPathDirDefault, "Data pool log file (*.dpl)", 0, 0); /*if (filePath.length() < 1) return;*/ QFileInfo fInfo(filePath); if (!fInfo.exists()) return; ImportDataPool(filePath); } void register_gui::ImportDataPool(QString& strPathImportTxt) { QStringList strList = GetStringListFromFile(strPathImportTxt); if (strList.count() < 1) return; m_strlistPath_Fixed.clear(); m_strlistPath_Moving.clear(); m_strlistPath_Command.clear(); m_strlistBaseName_Fixed.clear(); m_strlistBaseName_Moving.clear(); m_strlistBaseName_Command.clear(); QStringList::const_iterator it = strList.constBegin(); QString curStr; QString curStrSub; while (it != strList.constEnd()) { curStr = (*it); if (curStr.contains("FIXED_FILE_BEGIN", Qt::CaseSensitive)) { ++it; while (it != strList.end()) { curStrSub = (*it); if (curStrSub.contains("FIXED_FILE_END", Qt::CaseSensitive)) break; else { QFileInfo finfo(curStrSub); if (finfo.exists()) m_strlistPath_Fixed.push_back(curStrSub); } ++it; } } else if (curStr.contains("MOVING_FILE_BEGIN", Qt::CaseSensitive)) { ++it; while (it != strList.end()) { curStrSub = (*it); if (curStrSub.contains("MOVING_FILE_END", Qt::CaseSensitive)) break; else { QFileInfo finfo(curStrSub); if (finfo.exists()) m_strlistPath_Moving.push_back(curStrSub); } ++it; } } else if (curStr.contains("COMMAND_FILE_BEGIN", Qt::CaseSensitive)) { ++it; while (it != strList.end()) { curStrSub = (*it); if (curStrSub.contains("COMMAND_FILE_END", Qt::CaseSensitive)) break; else { QFileInfo finfo(curStrSub); if (finfo.exists()) m_strlistPath_Command.push_back(curStrSub); } ++it; } } ++it; }//end of while main UpdateBaseAndComboFromFullPath(); UpdateTable_Main(DATA2GUI); //When updating table, also do it for combo boxes } void register_gui::SLTM_ExportDataPool() { QString strFilePath = QFileDialog::getSaveFileName(this, "Save Data pool log file", m_strPathDirDefault, "Datafile (*.dpl)", 0, 0); if (strFilePath.length() < 1) return; QFileInfo fInfo(strFilePath); if (fInfo.suffix() != "dpl" && fInfo.suffix() != "DPL") { strFilePath = strFilePath + ".dpl"; } ExportDataPool(strFilePath); } void register_gui::ExportDataPool(QString& strPathExportTxt) { ofstream fout; fout.open(strPathExportTxt.toLocal8Bit().constData()); if (fout.fail()) { cout << "Writing to file failed" << endl; return; } /*QStringList m_strlistPath_Fixed; QStringList m_strlistPath_Moving; QStringList m_strlistPath_Command;*/ fout << "#Data pool log file (*.dpl) for plastimatch register_gui" << endl; fout << "%FIXED_FILE_BEGIN%" << endl; QStringList::const_iterator it; for (it = m_strlistPath_Fixed.begin(); it != m_strlistPath_Fixed.end(); ++it) { fout << (*it).toLocal8Bit().constData() << endl; } fout << "%FIXED_FILE_END%" << endl; fout << "%MOVING_FILE_BEGIN%" << endl; for (it = m_strlistPath_Moving.begin(); it != m_strlistPath_Moving.end(); ++it) { fout << (*it).toLocal8Bit().constData() << endl; } fout << "%MOVING_FILE_END%" << endl; fout << "%COMMAND_FILE_BEGIN%" << endl; for (it = m_strlistPath_Command.begin(); it != m_strlistPath_Command.end(); ++it) { fout << (*it).toLocal8Bit().constData() << endl; } fout << "%COMMAND_FILE_END%" << endl; fout.close(); } register_gui.h000066400000000000000000000157561321604176500315470ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef REGISTER_GUI_H #define REGISTER_GUI_H #include #include #include #include #include #include "ui_register_gui.h" #include "yk_config.h" #include "YKThreadRegi.h" class QStandardItemModel; class YKThreadRegi; class QTimer; class Datapool_item { public: QString m_group; QString m_path; QString m_role; }; enum Job_group_type { JOB_GROUP_MOVING_TO_FIXED, JOB_GROUP_ALL_TO_FIXED, JOB_GROUP_ALL_TO_ALL }; class register_gui : public QMainWindow { Q_OBJECT public: register_gui(QWidget *parent = 0, Qt::WFlags flags = 0); ~register_gui(); void SetCommandViewerText_Main(QStringList& strList); void SetCommandViewerText_Que(QStringList& strList); QStringList GetCommandViewerText(); QStringList GetStringListFromFile(const QString& strFile); QStringList ModifyCommandFile(QStringList& strlistOriginal, QString& strPathFixed, QString& strPathMoving, QString& strPathOut); void SaveCommandText(QString& strPathCommand, QStringList& strListLines); void UpdateStrListFromBase(QStringList& strListBase, QStringList& strListFull); void DeleteRemainingThreads(); void EmptyTableModel(QStandardItemModel* pTableModel); void UpdateBaseAndComboFromFullPath();//Base and ComboList void AdaptCommandFileToNewPath(QString& strPathCommand, QString& strPathFixed, QString& strPathMoving); void AddSingleToQue(QString& strPathFixed, QString& strPathMoving, QString& strPathCommand); bool RunRegistrationSingle(int index); int GetCountPendingJobs(); int GetCountStandByJobs(); QString GetStrInfoFromCommandFile(enPlmCommandInfo plmInfo, QString& strPathCommandFile); QStringList GetImagePathListFromCommandFile(QString& strPathCommandFile); void CopyCommandFileToOutput(QString& strPathOriginCommandFile); void ExportQueResult(QString& strPathOut); void InitConfig(); void WriteDefaultTemplateFiles(QString& targetDirPath); void ReadCommandFile(QString& strPathCommandFile, QStringList& strListOutput); bool WriteCommandNoOverwriting(QString& strPathSrc, QString& strPathTarget, QString& strPathTargetMod); void EnableUIForCommandfile(bool bEnable); void ImportDataPool(QString& strPathImportTxt); void ExportDataPool(QString& strPathImportTxt); public slots: void SLT_SetDefaultDir(); void SLT_LoadImages(); void SLT_LoadFixedFiles(); void SLT_LoadMovingFiles(); void SLT_LoadCommandFiles(); void SLT_ReadCommandFile_Main(QModelIndex index); //(QModelIndex& index) didn't work void SLT_ReadCommandFile_Que(QModelIndex index); //(QModelIndex& index) didn't work void SLT_SelectionChangedMain(QItemSelection curItem, QItemSelection prevItem); //prevItem is not being used now void SLT_ItemClickedMain(); //single clicked void SLT_SelectionChangedQue(QItemSelection curItem, QItemSelection prevItem); void SLT_ItemClickedQue(); //single clicked void SLT_SaveCommandText(); void SLT_CommandFileSaveAs(); void SLT_CommandFileSave(); void SLT_AddSingleToQue(); void SLT_AddMultipleToQueByLine(); void SLT_AddMultipleToQueByPermu(); //void SLT_CopySelectionToAll_Command(); void SLT_CopyCommandFile(); void SLT_ClearCommandFiles(); void SLT_UpdateFileList();//renaming, etc void SLT_SortSelectedColumn(); //main only void SLT_ClearQueAll(); void SLT_RemoveSelectedQue(); void SLT_RunSingleSelected(); void SLT_RunBatchSequential(); void SLT_RunBatchMultiThread(); void SLT_TimerRunSEQ(); void SLT_TimerRunMT(); void SLTM_ExportQueResult(); void SLT_CopyTableQueToClipboard(); void SLT_SetDefaultViewer(); void SLT_OpenSelectedOutputDir(); void SLT_ViewSelectedImg(); //void SLT_CreateSampleRigid(); //void SLT_CreateSampleDeform(); void SLT_CommandTemplateSelected(); void SLT_CopyCommandTemplateToDataPool(); void SLT_BrowseWorkingDir(); void SLT_BrowseTemplateDir(); void SLT_DeleteSingleTemplate(); void SLTM_ImportDataPool(); void SLTM_ExportDataPool(); void SLT_BrowseFixedPattern (); void SLT_BrowseMovingPattern (); void SLT_AddImages (); void SLT_QueueJobs (); public: void UpdateTable_Main(enUpdateDirection updateDirection); void UpdateTable_Que(); //only Data2Gui direction protected: // Handle registration pattern, images Job_group_type get_action_pattern (); QString get_fixed_pattern (); QString get_moving_pattern (); bool get_repeat_for_peers (); void get_image_files ( QStringList& image_list, const QString& pattern, bool repeat_for_peers); // Handle command library QString get_selected_command_template_name (); void set_selected_command_template_name ( const QString& template_name); void save_command_template ( const QString& template_name, QStringList& template_contents // Modified prior to saving ); void SetWorkDir(const QString& strPath); void SetReadImageApp(const QString& strPath); void SetCommandTemplateDir(const QString& strDirPath); void InitTableMain(int rowCnt, int columnCnt); void InitTableQue(int rowCnt, int columnCnt); void SetTableText(int row, int col, QString& inputStr); //m_strFileDefaultConfig, m_strPathDirDefault, m_strPathReadImageApp void write_application_settings(); bool read_application_settings(); void CreateDefaultCommandFile(enRegisterOption option); void UpdateCommandFileTemplateList(QString& strPathTemplateDir); public: QList m_actions; QStringList m_strlistPath_Fixed; QStringList m_strlistPath_Moving; QStringList m_strlistPath_Command; QStringList m_strlistBaseName_Fixed; QStringList m_strlistBaseName_Moving; QStringList m_strlistBaseName_Command; QStringList m_strlistPathOutputImg; QStringList m_strlistPathOutputXf; std::list m_datapoolItems; int m_iCurSelRow_Main; int m_iCurSelCol_Main; int m_iCurSelRow_Que; int m_iCurSelCol_Que; QStandardItemModel *m_pTableModelMain; QStandardItemModel *m_pTableModelQue; //QStandardItemModel *m_pTableModelQue; YKThreadRegi** m_pArrThreadRegi; //Thread ID = index of Que table (max = 200) int m_iNumOfThreadAll; QMutex m_mutex; vector m_vRegiQue; QTimer* m_timerRunSequential; QTimer* m_timerRunMultiThread; QTime m_tTimeSeq; QTime m_tTimeMT; // Application settings QString m_strPathDirDefault; QString m_strPathReadImageApp; QString m_strPathCommandTemplateDir; private: Ui::register_guiClass ui; }; #endif register_gui.ui000066400000000000000000001076331321604176500317310ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone register_guiClass 0 0 941 913 RegiAid - Plastimatch Working directory Image viewer path Set Set Browse 0 Staging Registration pattern One moving to one fixed true buttonGroup_actionPattern Many moving to one fixed buttonGroup_actionPattern Many moving to many fixed buttonGroup_actionPattern Images Fixed pattern Browse Moving pattern Browse Repeat for peer directories Qt::Horizontal 40 20 Stage Stage true QAbstractItemView::SingleSelection Qt::Horizontal 40 20 Queue jobs Command library true 0 0 100 Qt::Horizontal 40 20 Delete Browse Stage true Command file 0 0 Current file 16777215 16777215 Qt::Horizontal 40 20 Save Save as ... Stage Queue true QAbstractItemView::SingleSelection QAbstractItemView::SelectRows Edit Que Remove selection Clear all Run Que Run sequentially Run selection Run multi-thread Total time (s) 0 Total time (s) 0 Number of threads 4 Review View selected img Open selected dir Copy To Clipboard Command File Viewer false 0 0 941 19 File View TopToolBarArea false false Volume Viewer Load command files Save queue Import data pool Export data pool pushButton_WorkingDirSet released() register_guiClass SLT_SetDefaultDir() 131 64 103 76 pushButton_CommandFileStage clicked() register_guiClass SLT_SaveCommandText() 703 583 682 700 actionLoad_command_files triggered() register_guiClass SLT_LoadCommandFiles() -1 -1 434 352 pushButton_ClearQue released() register_guiClass SLT_ClearQueAll() 125 837 6 658 pushButton_RemoveSel released() register_guiClass SLT_RemoveSelectedQue() 125 790 167 688 pushButton_RunSelected released() register_guiClass SLT_RunSingleSelected() 241 772 323 680 pushButton_RunAll_Seq released() register_guiClass SLT_RunBatchSequential() 241 801 484 675 pushButton_RunAll_MultiThread released() register_guiClass SLT_RunBatchMultiThread() 241 830 105 678 pushButton_OpenSelectedOutput released() register_guiClass SLT_OpenSelectedOutputDir() 568 813 666 680 pushButton_CopyTableToClipboard released() register_guiClass SLT_CopyTableQueToClipboard() 568 848 635 677 actionSave_Que_Table_To_Text triggered() register_guiClass SLTM_ExportQueResult() -1 -1 530 350 pushButton_ImageViewerPathSet released() register_guiClass SLT_SetDefaultViewer() 161 90 978 101 pushButtonViewSelectedImg released() register_guiClass SLT_ViewSelectedImg() 568 778 565 891 listWidget_CommandLibrary itemClicked(QListWidgetItem*) register_guiClass SLT_CommandTemplateSelected() 534 207 831 182 pushButton_CommandLibraryStage released() register_guiClass SLT_CopyCommandTemplateToDataPool() 771 172 832 135 pushButton_CommandFileSaveAs clicked() register_guiClass SLT_CommandFileSaveAs() 770 575 833 585 pushButton_WorkingDirBrowse released() register_guiClass SLT_BrowseWorkingDir() 805 57 837 87 pushButton_CommandLibraryBrowse released() register_guiClass SLT_BrowseTemplateDir() 779 240 835 267 pushButton_CommandLibraryDelete released() register_guiClass SLT_DeleteSingleTemplate() 771 204 832 219 actionImport_data_pool triggered() register_guiClass SLTM_ImportDataPool() -1 -1 418 456 actionExport_data_pool triggered() register_guiClass SLTM_ExportDataPool() -1 -1 418 456 tableView_Stage clicked(QModelIndex) register_guiClass SLT_ItemClickedMain() 54 387 7 389 tableView_que clicked(QModelIndex) register_guiClass SLT_ItemClickedQue() 483 164 248 40 pushButton_StageQueueJobs released() register_guiClass SLT_QueueJobs() 214 338 451 456 pushButton_browseFixed released() register_guiClass SLT_BrowseFixedPattern() 317 320 470 456 pushButton_browseMoving released() register_guiClass SLT_BrowseMovingPattern() 317 353 470 456 pushButton_ImagesStage released() register_guiClass SLT_AddImages() 194 415 470 456 pushButton_CommandFileSave clicked() register_guiClass SLT_CommandFileSave() 707 847 470 456 SLT_SetDefaultDir() SLT_LoadFixedFiles() SLT_LoadMovingFiles() SLT_LoadCommandFiles() SLT_ReadCommandFile(QModelIndex) SLT_SaveCommandText() SLT_AddSingleToQue() SLT_AddMultipleToQueByLine() SLT_AddMultipleToQueByPermu() SLT_CopyCommandFile() SLT_ClearCommandFiles() SLT_UpdateFileList() SLT_SortSelectedColumn() SLT_ClearQueAll() SLT_RemoveSelectedQue() SLT_RunSingleSelected() SLT_RunBatchSequential() SLT_RunBatchMultiThread() SLT_OpenSelectedOutputDir() SLT_CopyTableQueToClipboard() SLTM_ExportQueResult() SLT_SetDefaultViewer() SLT_ViewSelectedImg() SLT_CreateSampleRigid() SLT_CreateSampleDeform() SLT_CommandTemplateSelected() SLT_CopyCommandTemplateToDataPool() SLT_CommandFileSaveAs() SLT_BrowseWorkingDir() SLT_BrowseTemplateDir() SLT_DeleteSingleTemplate() SLTM_ImportDataPool() SLTM_ExportDataPool() SLT_ItemClickedMain() SLT_ItemClickedQue() SLT_LoadImages() SLT_QueueJobs() SLT_AddImages() SLT_BrowseFixedPattern() SLT_BrowseMovingPattern() SLT_CommandFileSave() register_gui_main.cpp000066400000000000000000000002601321604176500330660ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone#include "register_gui.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); register_gui w; w.show(); return a.exec(); } shuffle_mha_main.cxx000066400000000000000000000050151321604176500327020ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* Correct mha files which have incorrect patient orientations */ #include "plm_config.h" #include #include #include "itkImageSliceConstIteratorWithIndex.h" #include "itkImageSliceIteratorWithIndex.h" #include "itk_image.h" #include "itk_image_load.h" #include "itk_image_save.h" #include "itk_image_type.h" int main (int argc, char* argv[]) { if (argc != 3 && argc != 4) { printf ("Usage: %s shuffle infile [outfile]\n", argv[0]); printf ("If you don't specify an outfile, the infile will be overwritten.\n"); printf ("Shuffle value hard coded to flipping Z axis\n"); exit (1); } char* fn_out; if (argc == 4) { fn_out = argv[3]; } else { fn_out = argv[2]; } /* Load input */ FloatImageType::Pointer v_in = itk_image_load_float(argv[2], 0); /* Allocate memory for output */ FloatImageType::Pointer v_out = FloatImageType::New(); v_out->SetRegions (v_in->GetLargestPossibleRegion()); v_out->SetOrigin (v_in->GetOrigin()); v_out->SetSpacing (v_in->GetSpacing()); v_out->Allocate(); /* Set up slice iterators */ typedef itk::ImageSliceConstIteratorWithIndex ConstIteratorType; typedef itk::ImageSliceIteratorWithIndex IteratorType; ConstIteratorType it_in (v_in, v_in->GetLargestPossibleRegion()); IteratorType it_out (v_out, v_out->GetLargestPossibleRegion()); RegionType rgn_out = v_out->GetLargestPossibleRegion(); it_in.SetFirstDirection(0); it_in.SetSecondDirection(1); it_out.SetFirstDirection(0); it_out.SetSecondDirection(1); /* Still setting up slice iterators. The ITK class is missing functionality of reverse iteration for each direction independently. */ FloatImageType::IndexType idx_out; idx_out[0] = 0; idx_out[1] = 0; idx_out[2] = rgn_out.GetSize()[2] - 1; it_in.GoToBegin (); it_out.SetIndex (idx_out); /* For each slice of input, copy to output */ while (!it_in.IsAtEnd()) { while (!it_in.IsAtEndOfSlice()) { while (!it_in.IsAtEndOfLine()) { it_out.Set (it_in.Get()); ++it_in; ++it_out; } it_in.NextLine (); it_out.NextLine (); } it_in.NextSlice (); idx_out[0] = 0; idx_out[1] = 0; idx_out[2] --; it_out.SetIndex (idx_out); } itk_image_save_float (v_out, fn_out); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/sobp_main.cxx000066400000000000000000000045601321604176500314470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "rt_mebs.h" int main (int argc, char* argv[]) { float dmin, dmax; int Emin, Emax; int particle; Particle_type particle_type; if (argc < 4) { printf ( "Usage:\n" " sobp d dmin dmax // Optimize in mm from dmin to dmax\n" " sobp e emin emax // Optimize in MeV from emin to emax\n"); exit (0); } sscanf(argv[1],"%d", &particle); if(particle ==1) { particle_type = PARTICLE_TYPE_P; } else if (particle ==2) { particle_type = PARTICLE_TYPE_HE; } else if (particle ==3) { particle_type = PARTICLE_TYPE_LI; } else if (particle ==4) { particle_type = PARTICLE_TYPE_BE; } else if (particle ==5) { particle_type = PARTICLE_TYPE_B; } else if (particle ==6) { particle_type = PARTICLE_TYPE_C; } else if (particle ==8) { particle_type = PARTICLE_TYPE_O; } else { particle_type = PARTICLE_TYPE_P; printf("Invalid particle type"); } if (particle_type != PARTICLE_TYPE_P) // no data for ions... to be implemented (ion bragg peaks!!) { particle_type = PARTICLE_TYPE_P; printf("Ions data are not ready yet - beam switched to proton beams"); } Rt_mebs mebs(particle_type); // construction of the sobp using the proximal and distal limits if (argv[2][0]=='d') { sscanf (argv[3], "%f", &dmin); sscanf (argv[4], "%f", &dmax); mebs.set_prescription_depths(dmin, dmax); } // construction of the sobp using the lower and higher energy else if (argv[2][0]=='e') { sscanf (argv[3], "%d", &Emin); sscanf (argv[4], "%d", &Emax); mebs.set_energies(Emin, Emax); } std::vector weight; std::vector energy; mebs.optimizer(&weight, &energy); for (size_t i = 0; i < energy.size(); i++) { mebs.add_peak(energy[i], mebs.get_spread(), weight[i]); } mebs.generate(); mebs.printparameters(); return 0; } vf_invert_main.cxx000066400000000000000000000254341321604176500324320ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "itkImage.h" #include "itk_image_load.h" #include "mha_io.h" #include "plm_clp.h" #include "plm_int.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_math.h" #include "vf_convolve.h" #include "vf_invert.h" #include "volume.h" class Vf_invert_parms { public: std::string vf_in_fn; std::string vf_out_fn; std::string fixed_img_fn; bool have_dim; bool have_origin; bool have_spacing; plm_long dim[3]; float origin[3]; float spacing[3]; bool old_algorithm; int iterations; public: Vf_invert_parms () { vf_in_fn = ""; vf_out_fn = ""; fixed_img_fn = ""; for (int d = 0; d < 3; d++) { dim[d] = 0; origin[d] = 0.f; spacing[d] = 1.f; } have_dim = false; have_origin = false; have_spacing = false; old_algorithm = false; iterations = 20; } }; #if defined (commentout) void vf_invert_itk (Vf_Invert_Parms* parms) { typedef itk::InverseDeformationFieldImageFilter < DeformationFieldType, DeformationFieldType > FilterType; Plm_image_header pih; if (parms->fixed_img_fn[0]) { /* if given, use the parameters from user-supplied fixed image */ FloatImageType::Pointer fixed = load_float (parms->fixed_img_fn); pih.set_from_itk_image (fixed); } else { pih.set_from_gpuit (parms->origin, parms->spacing, parms->dim); } FilterType::Pointer filter = FilterType::New (); DeformationFieldType::Pointer vf_in = load_float_field (parms->vf_in_fn); filter->SetInput (vf_in); filter->SetOutputOrigin (pih.origin); filter->SetOutputSpacing (pih.spacing); filter->SetSize (pih.m_region.GetSize()); //filter->SetOutsideValue( 0 ); filter->Update(); DeformationFieldType::Pointer vf_out = filter->GetOutput(); save_image (vf_out, parms->vf_out_fn); } #endif void do_vf_invert_old (Vf_invert_parms* parms) { plm_long i, j, k, v; int its; float x, y, z; Plm_image_header pih; Volume *mask, *vf_in, *vf_inv, *vf_smooth, *vf_out; float *img_in, *img_inv, *img_smooth, *img_out; unsigned char *img_mask; float ker[3] = { 0.3, 0.4, 0.3 }; if (parms->fixed_img_fn != "") { /* if given, use the parameters from user-supplied fixed image */ FloatImageType::Pointer fixed = itk_image_load_float ( parms->fixed_img_fn.c_str(), 0); pih.set_from_itk_image (fixed); pih.get_origin (parms->origin); pih.get_spacing (parms->spacing); pih.get_dim (parms->dim); pih.set_from_gpuit (parms->dim, parms->origin, parms->spacing, 0); } /* GCS FIX: Need direction cosines */ /* Create mask volume */ mask = new Volume (parms->dim, parms->origin, parms->spacing, 0, PT_UCHAR, 1); /* GCS FIX: Need direction cosines */ /* Create tmp volume */ vf_inv = new Volume (parms->dim, parms->origin, parms->spacing, 0, PT_VF_FLOAT_INTERLEAVED, 1); /* Load input vf */ vf_in = read_mha (parms->vf_in_fn.c_str()); vf_convert_to_interleaved (vf_in); /* Populate mask & tmp volume */ img_mask = (unsigned char*) mask->img; img_in = (float*) vf_in->img; img_inv = (float*) vf_inv->img; for (z = vf_in->origin[2], k = 0, v = 0; k < vf_in->dim[2]; k++, z+=vf_in->spacing[2]) { for (y = vf_in->origin[1], j = 0; j < vf_in->dim[1]; j++, y+=vf_in->spacing[1]) { for (x = vf_in->origin[0], i = 0; i < vf_in->dim[0]; v++, i++, x+=vf_in->spacing[0]) { plm_long mijk[3], midx; float mxyz[3]; mxyz[0] = x + img_in[3*v+0]; mijk[0] = ROUND_INT ((mxyz[0] - vf_inv->origin[0]) / vf_inv->spacing[0]); mxyz[1] = y + img_in[3*v+1]; mijk[1] = (mxyz[1] - vf_inv->origin[1]) / vf_inv->spacing[1]; mxyz[2] = z + img_in[3*v+2]; mijk[2] = (mxyz[2] - vf_inv->origin[2]) / vf_inv->spacing[2]; if (mijk[0] < 0 || mijk[0] >= vf_inv->dim[0]) continue; if (mijk[1] < 0 || mijk[1] >= vf_inv->dim[1]) continue; if (mijk[2] < 0 || mijk[2] >= vf_inv->dim[2]) continue; midx = (mijk[2] * vf_inv->dim[1] + mijk[1]) * vf_inv->dim[0] + mijk[0]; img_inv[3*midx+0] = -img_in[3*v+0]; img_inv[3*midx+1] = -img_in[3*v+1]; img_inv[3*midx+2] = -img_in[3*v+2]; img_mask[midx] ++; } } } /* We're done with input volume now. */ delete vf_in; /* GCS FIX: Need direction cosines */ /* Create tmp & output volumes */ vf_out = new Volume (parms->dim, parms->origin, parms->spacing, 0, PT_VF_FLOAT_INTERLEAVED, 3); img_out = (float*) vf_out->img; /* GCS FIX: Need direction cosines */ vf_smooth = new Volume (parms->dim, parms->origin, parms->spacing, 0, PT_VF_FLOAT_INTERLEAVED, 3); img_smooth = (float*) vf_smooth->img; /* Iterate, pasting and smoothing */ printf ("Paste and smooth loop\n"); for (its = 0; its < parms->iterations; its++) { printf ("Iteration %d/%d\n", its, parms->iterations); /* Paste */ for (v = 0, k = 0; k < vf_out->dim[2]; k++) { for (j = 0; j < vf_out->dim[1]; j++) { for (i = 0; i < vf_out->dim[0]; i++, v++) { if (img_mask[v]) { img_smooth[3*v+0] = img_inv[3*v+0]; img_smooth[3*v+1] = img_inv[3*v+1]; img_smooth[3*v+2] = img_inv[3*v+2]; } else { img_smooth[3*v+0] = img_out[3*v+0]; img_smooth[3*v+1] = img_out[3*v+1]; img_smooth[3*v+2] = img_out[3*v+2]; } } } } /* Smooth the estimate into vf_out. The volumes are ping-ponged. */ printf ("Convolving\n"); vf_convolve_x (vf_out, vf_smooth, ker, 3); vf_convolve_y (vf_smooth, vf_out, ker, 3); vf_convolve_z (vf_out, vf_smooth, ker, 3); } printf ("Done.\n"); /* We're done with the mask & smooth image. */ delete mask; delete vf_smooth; /* Write the output */ write_mha (parms->vf_out_fn.c_str(), vf_out); delete vf_out; } void do_vf_invert_new (Vf_invert_parms* parms) { Vf_invert vf_invert; vf_invert.set_input_vf (parms->vf_in_fn.c_str()); if (parms->fixed_img_fn != "") { vf_invert.set_fixed_image (parms->fixed_img_fn.c_str()); } if (parms->have_dim) { vf_invert.set_dim (parms->dim); } if (parms->have_origin) { vf_invert.set_origin (parms->origin); } if (parms->have_spacing) { vf_invert.set_spacing (parms->spacing); } #if defined (commentout) /* GCS FIX: direction cosines */ if (parms->have_direction_cosines) { vf_invert.set_direction_cosines (parms->direction_cosines); } #endif vf_invert.set_iterations (parms->iterations); /* Invert the vf */ vf_invert.run (); /* Write the output */ write_mha (parms->vf_out_fn.c_str(), vf_invert.get_output_volume()); #if defined (commentout) plm_image_save_vol (parms->vf_out_fn.c_str(), vf_invert.get_output_volume()); #endif } void do_vf_invert (Vf_invert_parms* parms) { if (parms->old_algorithm) { do_vf_invert_old (parms); } else { do_vf_invert_new (parms); } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { std::cout << "Usage: vf_invert [options]\n"; parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Vf_invert_parms *parms, dlib::Plm_clp *parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Basic options */ parser->add_long_option ("", "input", "input vector field file name", 1, ""); parser->add_long_option ("", "output", "output vector field file name", 1, ""); parser->add_long_option ("", "dim", "size of output vector field in voxels \"x [y z]\"", 1, ""); parser->add_long_option ("", "origin", "location of first voxel of output vector field in mm \"x y z\"", 1, ""); parser->add_long_option ("", "spacing", "voxel spacing of output vector field in mm \"x [y z]\"", 1, ""); parser->add_long_option ("", "fixed", "fixed image (match output vector field size to this image)", 1, ""); parser->add_long_option ("", "old-algorithm", "use the old algorithm", 0); parser->add_long_option ("", "iterations", "number of iterations to run (default = 20)", 1, ""); /* Parse the command line arguments */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Check that an input file was given */ if (!parser->option ("input")) { throw (dlib::error ("Error. Please specify an input file " "using the --input options")); } /* Check that an output file was given */ if (!parser->option ("output")) { throw (dlib::error ("Error. Please specify an output file " "using the --output options")); } /* Check that output dimensions are known */ if (!parser->option ("dim") || !parser->option("origin") || !parser->option("spacing")) { if (!parser->option ("fixed")) { throw (dlib::error ("Error. Please specify either dim, origin, " " and spacing -or- a fixed file")); } } /* Copy values into parameter struct */ parms->vf_in_fn = parser->get_string("input"); parms->vf_out_fn = parser->get_string("output"); if (parser->option ("fixed")) { parms->fixed_img_fn = parser->get_string("fixed"); } if (parser->option ("dim")) { parms->have_dim = true; parser->assign_plm_long_13 (parms->dim, "dim"); } if (parser->option ("origin")) { parms->have_origin = true; parser->assign_float_13 (parms->origin, "origin"); } if (parser->option ("spacing")) { parms->have_spacing = true; parser->assign_float_13 (parms->spacing, "spacing"); } if (parser->option ("old-algorithm")) { parms->old_algorithm = true; } if (parser->option ("iterations")) { parser->get_value (parms->iterations, "iterations"); } } int main (int argc, char *argv[]) { Vf_invert_parms parms; plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv); do_vf_invert (&parms); printf ("Finished!\n"); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/viscous.cxx000066400000000000000000000005311321604176500311650ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "viscous.h" int main (int argc, char *argv[]) { return viscous (argc, argv); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/wed_main.cxx000066400000000000000000000327331321604176500312660ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "aperture.h" #include "plm_image.h" #include "plm_math.h" #include "print_and_exit.h" #include "proj_volume.h" #include "ray_trace_probe.h" #include "rpl_volume.h" #include "rt_beam.h" #include "rt_plan.h" #include "volume.h" #include "volume_limit.h" #include "wed_parms.h" Volume* create_wed_volume (Wed_Parms* parms, Rpl_volume* rpl_vol) { /* water equivalent depth volume has the same x,y dimensions as the rpl * volume. Note: this means the wed x,y dimensions are equal to the * aperture dimensions and the z-dimension is equal to the sampling * resolution chosen for the rpl */ plm_long wed_dims[3]; Volume *vol = rpl_vol->get_vol (); wed_dims[0] = vol->dim[0]; wed_dims[1] = vol->dim[1]; wed_dims[2] = vol->dim[2]; ///////////////////////////// //Should be insenstive to aperture rotation? /* Proj_volume *proj_vol = d_ptr->proj_vol; double iso_src_vec[3]; //vector from isocenter to source proj_vol->get_proj_matrix()->get_nrm(iso_src_vec); */ float xoff = -(vol->dim[0] - parms->ic[0]); float yoff = -(vol->dim[1] - parms->ic[1]); float wed_off[3] = {xoff, yoff, 0.0f}; float wed_ps[3] = {1.0f, 1.0f, 1.0f}; return new Volume (wed_dims, wed_off, wed_ps, NULL, PT_FLOAT, 1); } static Volume* create_dew_volume (Wed_Parms* parms, const Volume::Pointer& patient_vol) { float dew_off[3]; dew_off[0] = patient_vol->origin[0]; dew_off[1] = patient_vol->origin[1]; dew_off[2] = patient_vol->origin[2]; float dew_ps[3]; dew_ps[0] = patient_vol->spacing[0]; dew_ps[1] = patient_vol->spacing[1]; dew_ps[2] = patient_vol->spacing[2]; plm_long dew_dims[3]; dew_dims[0] = patient_vol->dim[0]; dew_dims[1] = patient_vol->dim[1]; dew_dims[2] = patient_vol->dim[2]; //If output volume dimensions were set in .cfg file, use these. if (parms->dew_dim[0]!=-999.) {dew_dims[0]=parms->dew_dim[0];} if (parms->dew_dim[1]!=-999.) {dew_dims[1]=parms->dew_dim[1];} if (parms->dew_dim[2]!=-999.) {dew_dims[2]=parms->dew_dim[2];} if (parms->dew_origin[0]!=-999.) {dew_off[0]=parms->dew_origin[0];} if (parms->dew_origin[1]!=-999.) {dew_off[1]=parms->dew_origin[1];} if (parms->dew_origin[2]!=-999.) {dew_off[2]=parms->dew_origin[2];} if (parms->dew_spacing[0]!=-999.) {dew_ps[0]=parms->dew_spacing[0];} if (parms->dew_spacing[1]!=-999.) {dew_ps[1]=parms->dew_spacing[1];} if (parms->dew_spacing[2]!=-999.) {dew_ps[2]=parms->dew_spacing[2];} return new Volume (dew_dims, dew_off, dew_ps, NULL, PT_FLOAT, 1); } Volume* create_proj_wed_volume (Rpl_volume* rpl_vol) { float proj_wed_off[3] = {0.0f, 0.0f, 0.0f}; float proj_wed_ps[3] = {1.0f, 1.0f, 1.0f}; plm_long proj_wed_dims[3]; Volume *vol = rpl_vol->get_vol (); proj_wed_dims[0] = vol->dim[0]; proj_wed_dims[1] = vol->dim[1]; proj_wed_dims[2] = 1; return new Volume (proj_wed_dims, proj_wed_off, proj_wed_ps, NULL, PT_FLOAT, 1); } Volume* create_proj_sinogram_volume (Wed_Parms* parms, Volume *proj_wed_vol) { float proj_wed_off[3]; proj_wed_off[0] = proj_wed_vol->origin[0]; proj_wed_off[1] = proj_wed_vol->origin[1]; proj_wed_off[2] = proj_wed_vol->origin[2]; float proj_wed_ps[3]; proj_wed_ps[0] = proj_wed_vol->spacing[0]; proj_wed_ps[1] = proj_wed_vol->spacing[1]; proj_wed_ps[2] = proj_wed_vol->spacing[2]; plm_long proj_wed_dims[3]; proj_wed_dims[0] = proj_wed_vol->dim[0]; proj_wed_dims[1] = proj_wed_vol->dim[1]; proj_wed_dims[2] = parms->sinogram_res; return new Volume (proj_wed_dims, proj_wed_off, proj_wed_ps, NULL, PT_FLOAT, 1); } static int skin_ct (Volume* ct_volume, Volume* skin_volume, float background) { float *ct_img = (float*) ct_volume->img; float *skin_img = (float*) skin_volume->img; const plm_long *ct_dim = ct_volume->dim; const plm_long *skin_dim = skin_volume->dim; if ((ct_dim[0]!=skin_dim[0])||(ct_dim[1]!=skin_dim[1])||(ct_dim[2]!=skin_dim[2])) { fprintf (stderr, "\n** ERROR: CT dimensions do not match skin dimensions.\n"); return -1; } plm_long n_voxels = ct_dim[0]*ct_dim[1]*ct_dim[2]; for (plm_long i=0; i!=n_voxels; ++i) { if (skin_img[i] == 0) {ct_img[i] = background;} else if (skin_img[i] == 1) {continue;} else { fprintf (stderr, "\n** ERROR: Value other than '0' or '1' in skin input.\n"); return -1; } } return 0; } #if defined (commentout) void wed_ct_compute_mode_2 ( const std::string& out_fn, Wed_Parms* parms, Plm_image::Pointer& ct_vol, // This is not always ct, // sometimes it is dose or // sometimes it is target mask. Rt_plan *scene, Rt_beam *beam, float background ) { Rpl_volume* rpl_vol = beam->rpl_vol; /* Compute the aperture and range compensator */ rpl_vol->compute_beam_modifiers_passive_scattering (ct_vol->get_volume_float().get()); /* Save files as output */ Plm_image::Pointer& ap = rpl_vol->get_aperture()->get_aperture_image(); Plm_image::Pointer& rc = rpl_vol->get_aperture()->get_range_compensator_image(); #if defined (commentout) ap->save_image (parms->output_ap_fn.c_str()); rc->save_image (out_fn); #endif } void wed_ct_compute_mode_3 ( const std::string& out_fn, Wed_Parms* parms, Plm_image::Pointer& ct_vol, // This is not always ct, // sometimes it is dose or // sometimes it is target mask. Rt_plan *scene, Rt_beam *beam, float background ) { Rpl_volume* rpl_vol = beam->rpl_vol; Volume* proj_wed_vol; Volume* sinogram_vol; proj_wed_vol = create_proj_wed_volume(rpl_vol); if (parms->sinogram!=0) { sinogram_vol = create_proj_sinogram_volume(parms, proj_wed_vol); float *sin_img = (float*) sinogram_vol->img; float *proj_img = (float*) proj_wed_vol->img; plm_long n_voxels_sin = sinogram_vol->dim[0]*sinogram_vol->dim[1]*sinogram_vol->dim[2]; plm_long n_voxels_proj = proj_wed_vol->dim[0]*proj_wed_vol->dim[1]*proj_wed_vol->dim[2]; float *sin_array = new float[n_voxels_sin]; float *proj_array = new float[n_voxels_proj]; //Loop over angles determined by the resolution, and calcaulate a projective //volume for each. Then fill the sinogram volume with each slice. int angles = parms->sinogram_res; float src[3] = {parms->src[0], parms->src[1], parms->src[2]}; float iso[3] = {parms->isocenter[0], parms->isocenter[1], parms->isocenter[2]}; float src2[3] = {0, 0, parms->src[2]}; float radius[2] = {src[0]-iso[0], src[1]-iso[1]}; float radius_len = sqrt( (src[0]-iso[0])*(src[0]-iso[0]) + (src[1]-iso[1])*(src[1]-iso[1])); float init_angle = atan2(radius[1],radius[0]); float angle = 0; for (int i=0; i!=angles; ++i) { angle = init_angle + ( i / (float) parms->sinogram_res)*2.*M_PI; src2[0] = cos(angle)*radius_len + iso[0]; src2[1] = sin(angle)*radius_len + iso[1]; beam->set_source_position (src2); scene->prepare_beam_for_calc (beam); rpl_vol = beam->rpl_vol; rpl_vol->compute_proj_wed_volume (proj_wed_vol, background); //Fill proj array with voxel values. for (plm_long zz=0; zz!=n_voxels_proj; ++zz) { proj_array[zz] = proj_img[zz]; } for (int j=0; j!=proj_wed_vol->dim[0]; ++j) { for (int k=0; k!=proj_wed_vol->dim[1]; ++k) { sin_array[sinogram_vol->index(j,k,i)] = proj_array[proj_wed_vol->index(j,k,0)]; } } } //Fill sinogram image with voxel values from assembled array. for (plm_long zz=0; zz!=n_voxels_sin; ++zz) { sin_img[zz] = sin_array[zz]; } Plm_image(sinogram_vol).save_image(out_fn); delete[] sin_array; delete[] proj_array; } else { rpl_vol->compute_proj_wed_volume (proj_wed_vol, background); Plm_image(proj_wed_vol).save_image(out_fn); } } #endif void do_wed (Wed_Parms *parms) { float background[4]; //Background value for wed ct output background[0] = -1000.; //Background value for wed dose output background[1] = 0.; //Background value for radiation length output background[2] = 0.; //Background value for projection of wed background[3] = 0.; /* load the input ct */ Plm_image::Pointer ct_vol = Plm_image::New ( parms->input_ct_fn, PLM_IMG_TYPE_ITK_FLOAT); if (!ct_vol) { print_and_exit ("** ERROR: Unable to load patient volume.\n"); } /* Load the input dose */ Plm_image::Pointer dose_vol; if (parms->input_dose_fn != "") { printf("Loading input dose: %s\n",parms->input_dose_fn.c_str()); dose_vol = plm_image_load (parms->input_dose_fn.c_str(), PLM_IMG_TYPE_ITK_FLOAT); } /* Load the input proj_wed */ Rpl_volume::Pointer proj_wed = Rpl_volume::New (); if (parms->input_proj_wed_fn != "") { proj_wed->load_rpl (parms->input_proj_wed_fn); } /* Load the input wed_dose */ Plm_image::Pointer wed_dose; if (parms->input_wed_dose_fn != "") { printf("Loading input wed_dose: %s\n",parms->input_wed_dose_fn.c_str()); wed_dose = plm_image_load (parms->input_wed_dose_fn.c_str(), PLM_IMG_TYPE_ITK_FLOAT); } /* Load the skin */ if (parms->input_skin_fn != "") { printf ("Skin file defined. Modifying input ct...\n"); Volume* ct_volume = ct_vol->get_volume_float().get(); Plm_image::Pointer skin_vol = plm_image_load (parms->input_skin_fn, PLM_IMG_TYPE_ITK_FLOAT); if (!skin_vol) { print_and_exit ("\n** ERROR: Unable to load skin input.\n"); } Volume* skin_volume = skin_vol->get_volume_float().get(); if (skin_ct(ct_volume, skin_volume, background[0])) { print_and_exit ("\n** ERROR: Unable to apply skin input to ct input.\n"); } } /* Set up the beam */ Aperture::Pointer aperture = Aperture::New(); aperture->set_distance (parms->ap_offset); aperture->set_spacing (parms->ap_spacing); if (parms->have_ires) { aperture->set_dim (parms->ires); } if (parms->have_ic) { aperture->set_center (parms->ic); } double src[3], isocenter[3]; for (int i = 0; i < 3; i++) { src[i] = parms->src[i]; isocenter[i] = parms->isocenter[i]; } Rpl_volume rpl; rpl.set_ct_volume (ct_vol); rpl.set_aperture (aperture); rpl.set_geometry ( src, isocenter, aperture->vup, aperture->get_distance(), aperture->get_dim(), aperture->get_center(), aperture->get_spacing(), parms->ray_step); if (proj_wed) { proj_wed->set_ct_volume (ct_vol); proj_wed->set_aperture (aperture); proj_wed->set_geometry ( src, isocenter, aperture->vup, aperture->get_distance(), aperture->get_dim(), aperture->get_center(), aperture->get_spacing(), parms->ray_step); } /* Compute the rpl volume */ rpl.compute_rpl_PrSTRP_no_rgc (); if (parms->output_proj_wed_fn != "") { rpl.save (parms->output_proj_wed_fn); } if (parms->output_dew_ct_fn != "") { Volume* dew_vol = create_dew_volume (parms, ct_vol->get_volume_float()); rpl.compute_dew_volume (ct_vol->get_volume_float().get(), dew_vol, -1000); Plm_image(dew_vol).save_image(parms->output_dew_ct_fn); } if (parms->output_dew_dose_fn != "") { if (!wed_dose) { print_and_exit ("Error, dew_dose requested but no wed_dose supplied.\n"); } Volume* dew_vol = create_dew_volume (parms, wed_dose->get_volume_float()); rpl.compute_dew_volume (wed_dose->get_volume_float().get(), dew_vol, 0); Plm_image(dew_vol).save_image(parms->output_dew_dose_fn); } if (parms->output_wed_ct_fn != "") { printf ("Computing wed ct volume...\n"); Volume *wed_vol = create_wed_volume (parms, &rpl); rpl.compute_wed_volume (wed_vol, ct_vol->get_volume_float().get(), background[0]); Plm_image(wed_vol).save_image(parms->output_wed_ct_fn); printf ("done.\n"); } if (parms->output_wed_dose_fn != "") { printf ("Computing wed dose volume...\n"); Volume *wed_vol = create_wed_volume (parms, &rpl); rpl.compute_wed_volume (wed_vol, dose_vol->get_volume_float().get(), background[1]); Plm_image(wed_vol).save_image(parms->output_wed_dose_fn); printf ("done.\n"); } /* Compute the proj_ct volume */ if (parms->output_proj_ct_fn != "") { rpl.compute_rpl_HU (); rpl.save (parms->output_proj_ct_fn); } } int main (int argc, char* argv[]) { Wed_Parms *parms = new Wed_Parms(); //sets parms if input with .cfg file, skips with group option if (!parms->parse_args (argc, argv)) { exit (0); } do_wed (parms); return 0; } xf_to_empirefmt.cxx000066400000000000000000000077021321604176500326110ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "itkImage.h" #include "itkImageRegionConstIterator.h" #define BUFLEN 1024 char header_pat[] = "ObjectType = Image\n" "NDims = 3\n" "BinaryData = True\n" "BinaryDataByteOrderMSB = False\n" "TransformMatrix = 1 0 0 0 1 0 0 0 1\n" "Offset = 0 0 0\n" "CenterOfRotation = 0 0 0\n" "ElementSpacing = %f %f %f\n" "DimSize = %d %d %d\n" "AnatomicalOrientation = RPI\n" "ElementNumberOfChannels = 1\n" "ElementType = MET_FLOAT\n" "ElementDataFile = %s\n" ; int main (int argc, char* argv[]) { // File pointers FILE *ofpx, *ofpy, *ofpz; Plm_image_header pih; FloatImageType::Pointer img_fixed; DeformationFieldType::Pointer vf; // input xform from bspline Xform xf_in, xf_out; if (argc!=4) { std::cerr << "Wrong Parameters " << std::endl; std::cerr << "Usage: " << argv[0]; std::cerr << " "; std::cerr << " "; std::cerr << " " << std::endl;; return 1; } xform_load (&xf_in, argv[1]); img_fixed = itk_image_load_float (argv[2], 0); xform_to_itk_vf (&xf_out, &xf_in, img_fixed); vf = xf_out.get_itk_vf(); // need to write to 3 separate files, named as defX.mhd defY.mhd and defZ.mhd char ofn1[255], ofn2[255], ofn3[255]; sprintf(ofn1, "%s%s", argv[3], "defX.mhd"); ofpx = fopen(ofn1, "w"); if (ofpx == NULL) { fprintf(stdout, "open file %s failed\n", ofn1); exit(-1); } sprintf(ofn2, "%s%s", argv[3], "defY.mhd"); ofpy = fopen(ofn2, "w"); if (ofpx == NULL) { fprintf(stdout, "open file %s failed\n", ofn2); exit(-1); } sprintf(ofn3, "%s%s", argv[3], "defZ.mhd"); ofpz = fopen(ofn3, "w"); if (ofpz == NULL) { fprintf(stdout, "open file %s failed\n", ofn3); exit(-1); } // print file header pih.set_from_itk_image (img_fixed); // write deformation field to separate binary files fprintf(ofpx, header_pat, pih.m_spacing[0], pih.m_spacing[1], pih.m_spacing[2], pih.m_region.GetSize()[0], pih.m_region.GetSize()[1], pih.m_region.GetSize()[2], "defX.raw"); fclose(ofpx); fprintf(ofpy, header_pat, pih.m_spacing[0], pih.m_spacing[1], pih.m_spacing[2], pih.m_region.GetSize()[0], pih.m_region.GetSize()[1], pih.m_region.GetSize()[2], "defY.raw"); fclose(ofpy); fprintf(ofpz, header_pat, pih.m_spacing[0], pih.m_spacing[1], pih.m_spacing[2], pih.m_region.GetSize()[0], pih.m_region.GetSize()[1], pih.m_region.GetSize()[2], "defZ.raw"); fclose(ofpz); sprintf(ofn1, "%s%s", argv[3], "defX.raw"); ofpx = fopen(ofn1, "wb"); sprintf(ofn2, "%s%s", argv[3], "defY.raw"); ofpy = fopen(ofn2, "wb"); sprintf(ofn3, "%s%s", argv[3], "defZ.raw"); ofpz = fopen(ofn3, "wb"); // iterate through the deformation field pixel by pixel and write each x, y, z // component to the corresponding binary files typedef itk::ImageRegionConstIterator< DeformationFieldType > RegionIteratorType; fprintf (stdout, "requested region size %ld %ld %ld\n", vf->GetRequestedRegion().GetSize()[0], vf->GetRequestedRegion().GetSize()[1], vf->GetRequestedRegion().GetSize()[2]); RegionIteratorType vf_it(vf, vf->GetRequestedRegion() ); vf_it.GoToBegin(); while(! vf_it.IsAtEnd() ) { DeformationFieldType::PixelType v(vf_it.Get()); fwrite(&v[0], 4, 1, ofpx); fwrite(&v[1], 4, 1, ofpy); fwrite(&v[2], 4, 1, ofpz); ++ vf_it; } fclose(ofpx); fclose(ofpy); fclose(ofpz); return 0; } xvi_archive.cxx000066400000000000000000000476441321604176500317420ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- Algorithm for doing an XVI archive. ** This algorithm does not use dbase file, which reduces need to access xvi computer ** (1) Get input directory from command line (2) Identify CBCT images according to /IMAGES/img_/Reconstruction/.SCAN (3) Load Reconstruction/.INI (3a) Parse this file to get Name, TreatmentID, (4) Load Reconstruction/.INI.XVI (4a) Parse this file to get Date, Xform (5) Identify reference image in Mosaiq (optional?) ** Needs fix for multiple reference studies ** ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include "INIReader.h" #if PLM_DCM_USE_DCMTK #include "dcmtk_config.h" #include "dcmtk/dcmdata/dctk.h" #endif #include "dcmtk_sro.h" #include "dir_list.h" #include "file_util.h" #include "path_util.h" #include "plm_clp.h" #include "plm_math.h" #include "print_and_exit.h" #include "rt_study.h" #include "string_util.h" #include "xvi_archive.h" Rt_study::Pointer load_reference_ct ( const std::string& patient_ct_set_dir, const std::string& cbct_ref_uid) { std::string reference_ct_dir = string_format ("%s/%s", patient_ct_set_dir.c_str(), cbct_ref_uid.c_str()); if (is_directory (reference_ct_dir)) { Rt_study::Pointer reference_study = Rt_study::New(); reference_study->load (reference_ct_dir); return reference_study; } else { printf ("Error. No matching reference CT found.\n"); return Rt_study::Pointer(); } } void do_xvi_archive (Xvi_archive_parms *parms) { std::string patient_ct_set_dir = compose_filename ( parms->patient_dir, "CT_SET"); std::string patient_images_dir = compose_filename ( parms->patient_dir, "IMAGES"); Dir_list images_dir (patient_images_dir); if (images_dir.num_entries == 0) { printf ("Error. No images found.\n"); return; } /* For potential CBCT image */ for (int i = 0; i < images_dir.num_entries; i++) { if (images_dir.entries[i][0] == '.') { continue; } /* Find pertinent filenames */ std::string recon_dir = string_format ("%s/%s/Reconstruction", patient_images_dir.c_str(), images_dir.entries[i]); Dir_list recon_list (recon_dir); std::string scan_fn, recon_ini_fn, recon_xvi_fn; for (int j = 0; j < recon_list.num_entries; j++) { if (!extension_is (recon_list.entries[j], "SCAN")) { continue; } scan_fn = compose_filename (recon_dir, recon_list.entries[j]); std::string recon_uid = strip_extension (std::string(recon_list.entries[j])); recon_ini_fn = compose_filename (recon_dir, string_format ("%s.INI", recon_uid.c_str())); recon_xvi_fn = compose_filename (recon_dir, string_format ("%s.INI.XVI", recon_uid.c_str())); break; } printf ("Recon dir is \"%s\".\n", recon_dir.c_str()); if (scan_fn == "" || !file_exists (scan_fn) || !file_exists (recon_ini_fn) || !file_exists (recon_xvi_fn)) { printf ("Missing file in Recon dir. Skipping.\n"); continue; } printf ("cbct_dir = %s/%s\n", patient_images_dir.c_str(), images_dir.entries[i]); /* Load the INI file */ INIReader recon_ini (recon_ini_fn); std::string cbct_ref_uid = recon_ini.Get ("IDENTIFICATION", "ReferenceUID", ""); std::string patient_name = string_format ("%s^%s", recon_ini.Get ("IDENTIFICATION", "LastName", "").c_str(), recon_ini.Get ("IDENTIFICATION", "FirstName", "").c_str()); std::string status_line_string = recon_ini.Get ("XVI", "StatusLineText", ""); std::string linac_string = ""; size_t n = status_line_string.find ("Plan Description:"); if (n != std::string::npos) { linac_string = status_line_string.substr ( n + strlen ("Plan Description:")); n = linac_string.find_first_not_of (" \t\r\n"); linac_string = linac_string.substr (n); n = linac_string.find_first_of (" \t\r\n"); if (n != std::string::npos) { linac_string = linac_string.substr (0, n); } } printf ("name = %s\n", patient_name.c_str()); printf ("reference_uid = %s\n", cbct_ref_uid.c_str()); printf ("linac_string = %s\n", linac_string.c_str()); #if defined (commentout) /* Verify if the file belongs to this reference CT */ if (cbct_ref_uid != reference_uid) { printf ("Reference UID mismatch. Skipping.\n"); continue; } #endif /* Load the matching reference CT */ Rt_study::Pointer reference_study = load_reference_ct ( patient_ct_set_dir, cbct_ref_uid); if (!reference_study) { printf ("No matching CT for this CBCT. Skipping.\n"); continue; } /* Extract metadata from reference CT */ Rt_study_metadata::Pointer& reference_meta = reference_study->get_rt_study_metadata (); printf ("Reference Meta: %s %s\n", reference_meta->get_patient_name().c_str(), reference_meta->get_patient_id().c_str()); /* Load the INI.XVI file */ INIReader recon_xvi (recon_xvi_fn); std::string date_time_string = recon_xvi.Get ("ALIGNMENT", "DateTime", ""); std::string date_string, time_string; size_t semicol_pos = date_time_string.find (";"); if (semicol_pos != std::string::npos) { printf ("semicol_pos = %d\n", (int) semicol_pos); date_string = string_trim (date_time_string.substr (0, semicol_pos)); printf ("date = |%s|\n", date_string.c_str()); time_string = string_trim (date_time_string.substr (semicol_pos+1)); while (1) { size_t colon_pos = time_string.find (":"); if (colon_pos == std::string::npos) { break; } time_string = time_string.substr (0, colon_pos) + time_string.substr (colon_pos+1); } printf ("time = |%s|\n", time_string.c_str()); } std::string unmatched_transform_string = recon_xvi.Get ("ALIGNMENT", "OnlineToRefTransformUnmatched", ""); printf ("unmatched xform = %s\n", unmatched_transform_string.c_str()); std::string registration_string = recon_xvi.Get ("ALIGNMENT", "OnlineToRefTransformCorrection", ""); printf ("correction xform = %s\n", registration_string.c_str()); if (unmatched_transform_string == "") { printf ("No unmatched xform for this CBCT. Skipping.\n"); continue; } /* Load the .SCAN */ Rt_study cbct_study; cbct_study.load_image (scan_fn); if (!cbct_study.have_image()) { printf ("ERROR: decompression failure with patient %s\n", reference_meta->get_patient_id().c_str()); exit (1); } /* Set DICOM image header fields */ Rt_study_metadata::Pointer& cbct_meta = cbct_study.get_rt_study_metadata (); cbct_meta->set_patient_name (patient_name); if (parms->patient_id_override != "") { cbct_meta->set_patient_id (parms->patient_id_override); } else { cbct_meta->set_patient_id ( reference_meta->get_patient_id().c_str()); } if (date_string != "" && time_string != "") { cbct_meta->set_study_date (date_string); cbct_meta->set_study_time (time_string); cbct_meta->set_image_metadata(DCM_InstanceCreationDate, date_string); cbct_meta->set_image_metadata(DCM_InstanceCreationTime, time_string); } std::string study_description = "CBCT: " + linac_string; cbct_meta->set_study_metadata (DCM_StudyDescription, study_description); cbct_meta->set_study_uid (reference_meta->get_study_uid()); cbct_meta->set_image_metadata (DCM_WindowCenter, "500"); cbct_meta->set_image_metadata (DCM_WindowWidth, "2000"); std::string patient_position = reference_meta->get_image_metadata (DCM_PatientPosition); cbct_meta->set_image_metadata (DCM_PatientPosition, patient_position); std::string cbct_series_description = "CBCT " + date_string + " " + time_string; cbct_meta->set_image_metadata (DCM_SeriesDescription, cbct_series_description); /* Set DICOM SRO header fields */ std::string sro_series_description = "REG " + date_string + " " + time_string; reference_meta->set_sro_metadata (DCM_SeriesDescription, sro_series_description); printf ("REF CT patient position is %s\n", patient_position.c_str()); // XiO incorrectly sets patient position metadata in their header // This maneuver is intended to correct this std::vector uta = parse_float_string (unmatched_transform_string); if (within_abs_tolerance (uta[2], 1.f, 0.001f) && within_abs_tolerance (uta[5], 1.f, 0.001f) && within_abs_tolerance (uta[8], -1.f, 0.001f)) { if (patient_position == "HFP") { patient_position = "FFP"; printf ("Patient position corrected to %s\n", patient_position.c_str()); } else if (patient_position == "HFS") { patient_position = "FFS"; printf ("Patient position corrected to %s\n", patient_position.c_str()); } } /* Fix patient orientation based on reference CT */ float dc[9] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; if (patient_position == "HFS") { /* Do nothing */ } else if (patient_position == "HFP") { // dc = { -1, 0, 0, 0, -1, 0, 0, 0, 1 }; dc[0] = dc[4] = -1; cbct_study.get_image()->get_volume()->set_direction_cosines (dc); } else if (patient_position == "FFS") { // dc = { -1, 0, 0, 0, 1, 0, 0, 0, -1 }; dc[0] = dc[8] = -1; cbct_study.get_image()->get_volume()->set_direction_cosines (dc); } else if (patient_position == "FFP") { // dc = { 1, 0, 0, 0, -1, 0, 0, 0, -1 }; dc[4] = dc[8] = -1; cbct_study.get_image()->get_volume()->set_direction_cosines (dc); } else { /* Punt */ patient_position = "HFS"; } float origin[3]; cbct_study.get_image()->get_volume()->get_origin(origin); origin[0] = dc[0] * origin[0]; origin[1] = dc[4] * origin[1]; origin[2] = dc[8] * origin[2]; cbct_study.get_image()->get_volume()->set_origin (origin); if (parms->write_debug_files) { /* Nb this has to be done before writing dicom, since that operation scrambles the image (!) */ cbct_study.save_image ("cbct.nrrd"); } /* Write the DICOM image */ std::string output_dir = string_format ( "cbct_output/%s/%s", reference_meta->get_patient_id().c_str(), images_dir.entries[i]); cbct_study.save_dicom (output_dir); /* Create the DICOM SRO */ AffineTransformType::Pointer aff = AffineTransformType::New(); AffineTransformType::ParametersType xfp(12); float xvip[16]; int rc = sscanf (registration_string.c_str(), "%f %f %f %f %f %f %f %f " "%f %f %f %f %f %f %f %f", &xvip[0], &xvip[1], &xvip[2], &xvip[3], &xvip[4], &xvip[5], &xvip[6], &xvip[7], &xvip[8], &xvip[9], &xvip[10], &xvip[11], &xvip[12], &xvip[13], &xvip[14], &xvip[15]); if (rc != 16) { printf ("Error parsing transform string.\n"); exit (1); } printf ("XVI\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", xvip[0], xvip[1], xvip[2], xvip[3], xvip[4], xvip[5], xvip[6], xvip[7], xvip[8], xvip[9], xvip[10], xvip[11], xvip[12], xvip[13], xvip[14], xvip[15]); if (patient_position == "HFS") { xfp[0] = xvip[8]; xfp[1] = xvip[9]; xfp[2] = xvip[10]; xfp[3] = xvip[4]; xfp[4] = xvip[5]; xfp[5] = xvip[6]; xfp[6] = - xvip[0]; xfp[7] = - xvip[1]; xfp[8] = - xvip[2]; // B xfp[9] = (xfp[0]*xvip[12] + xfp[3]*xvip[13] + xfp[6]*xvip[14]); xfp[10] = (xfp[1]*xvip[12] + xfp[4]*xvip[13] + xfp[7]*xvip[14]); xfp[11] = - (xfp[2]*xvip[12] + xfp[5]*xvip[13] + xfp[8]*xvip[14]); // "A", Verified xfp[9] = - (xfp[0]*xvip[12] + xfp[1]*xvip[13] + xfp[2]*xvip[14]); xfp[10] = - (xfp[3]*xvip[12] + xfp[4]*xvip[13] + xfp[5]*xvip[14]); xfp[11] = - (xfp[6]*xvip[12] + xfp[7]*xvip[13] + xfp[8]*xvip[14]); } else if (patient_position == "HFP") { xfp[0] = xvip[8]; xfp[1] = xvip[9]; xfp[2] = - xvip[10]; xfp[3] = xvip[4]; xfp[4] = xvip[5]; xfp[5] = - xvip[6]; xfp[6] = xvip[0]; xfp[7] = xvip[1]; xfp[8] = - xvip[2]; // "A", Unlikely xfp[9] = (xfp[0]*xvip[12] + xfp[1]*xvip[13] + xfp[2]*xvip[14]); xfp[10] = - (xfp[3]*xvip[12] + xfp[4]*xvip[13] + xfp[5]*xvip[14]); xfp[11] = - (xfp[6]*xvip[12] + xfp[7]*xvip[13] + xfp[8]*xvip[14]); // "B", Possible xfp[9] = (xfp[0]*xvip[12] + xfp[3]*xvip[13] + xfp[6]*xvip[14]); xfp[10] = (xfp[1]*xvip[12] + xfp[4]*xvip[13] + xfp[7]*xvip[14]); xfp[11] = - (xfp[2]*xvip[12] + xfp[5]*xvip[13] + xfp[8]*xvip[14]); } else if (patient_position == "FFS") { xfp[0] = - xvip[8]; xfp[1] = - xvip[9]; xfp[2] = - xvip[10]; xfp[3] = xvip[4]; xfp[4] = xvip[5]; xfp[5] = xvip[6]; xfp[6] = xvip[0]; xfp[7] = xvip[1]; xfp[8] = xvip[2]; // "B", Unlikely xfp[9] = - (xfp[0]*xvip[12] + xfp[3]*xvip[13] + xfp[6]*xvip[14]); xfp[10] = (xfp[1]*xvip[12] + xfp[4]*xvip[13] + xfp[7]*xvip[14]); xfp[11] = - (xfp[2]*xvip[12] + xfp[5]*xvip[13] + xfp[8]*xvip[14]); // "A", Possible xfp[9] = (xfp[0]*xvip[12] + xfp[1]*xvip[13] + xfp[2]*xvip[14]); xfp[10] = - (xfp[3]*xvip[12] + xfp[4]*xvip[13] + xfp[5]*xvip[14]); xfp[11] = - (xfp[6]*xvip[12] + xfp[7]*xvip[13] + xfp[8]*xvip[14]); // "C", Possible xfp[9] = - (xfp[0]*xvip[12] + xfp[1]*xvip[13] + xfp[2]*xvip[14]); xfp[10] = - (xfp[3]*xvip[12] + xfp[4]*xvip[13] + xfp[5]*xvip[14]); xfp[11] = - (xfp[6]*xvip[12] + xfp[7]*xvip[13] + xfp[8]*xvip[14]); } else if (patient_position == "FFP") { xfp[0] = - xvip[8]; xfp[1] = - xvip[9]; xfp[2] = xvip[10]; xfp[3] = xvip[4]; xfp[4] = xvip[5]; xfp[5] = - xvip[6]; xfp[6] = - xvip[0]; xfp[7] = - xvip[1]; xfp[8] = xvip[2]; // A xfp[9] = (xfp[0]*xvip[12] + xfp[1]*xvip[13] + xfp[2]*xvip[14]); xfp[10] = (xfp[3]*xvip[12] + xfp[4]*xvip[13] + xfp[5]*xvip[14]); xfp[11] = - (xfp[6]*xvip[12] + xfp[7]*xvip[13] + xfp[8]*xvip[14]); // "B", Mostly Verified xfp[9] = (xfp[0]*xvip[12] + xfp[3]*xvip[13] + xfp[6]*xvip[14]); xfp[10] = (xfp[1]*xvip[12] + xfp[4]*xvip[13] + xfp[7]*xvip[14]); xfp[11] = - (xfp[2]*xvip[12] + xfp[5]*xvip[13] + xfp[8]*xvip[14]); } // Convert cm to mm xfp[9] *= 10; xfp[10] *= 10; xfp[11] *= 10; #if defined (commentout) aff->SetParametersByValue (xfp); vnl_matrix_fixed< double, 3, 3 > xfp_rot_inv = aff->GetMatrix().GetInverse(); printf ("XFORM-R INV\n%f %f %f\n%f %f %f\n%f %f %f\n", xfp_rot_inv[0][0], xfp_rot_inv[0][1], xfp_rot_inv[0][2], xfp_rot_inv[1][0], xfp_rot_inv[1][1], xfp_rot_inv[1][2], xfp_rot_inv[2][0], xfp_rot_inv[2][1], xfp_rot_inv[2][2]); #endif // dicom translation = - 10 * dicom_rotation * xvi translation // Old, "perfect" HFS setting #if defined (commentout) xfp[9] = -10 * (xfp[0]*xvip[12] + xfp[1]*xvip[13] + xfp[2]*xvip[14]); xfp[10] = -10 * (xfp[3]*xvip[12] + xfp[4]*xvip[13] + xfp[5]*xvip[14]); xfp[11] = -10 * (xfp[6]*xvip[12] + xfp[7]*xvip[13] + xfp[8]*xvip[14]); xfp[9] = -10 * (xfp[0]*xvip[12] + xfp[3]*xvip[13] + xfp[6]*xvip[14]); xfp[10] = -10 * (xfp[1]*xvip[12] + xfp[4]*xvip[13] + xfp[7]*xvip[14]); xfp[11] = -10 * (xfp[2]*xvip[12] + xfp[5]*xvip[13] + xfp[8]*xvip[14]); #endif Xform::Pointer xf = Xform::New(); xf->set_aff (xfp); printf ("XFORM\n%f %f %f\n%f %f %f\n%f %f %f\n%f %f %f\n", xfp[0], xfp[1], xfp[2], xfp[3], xfp[4], xfp[5], xfp[6], xfp[7], xfp[8], xfp[9], xfp[10], xfp[11] ); if (parms->write_debug_files) { reference_study->save_image ("ct.nrrd"); xf->save ("xf.tfm"); } Dcmtk_sro::save ( xf, reference_study->get_rt_study_metadata (), cbct_study.get_rt_study_metadata (), output_dir, true); } } static void usage_fn (dlib::Plm_clp* parser, int argc, char *argv[]) { printf ("Usage: xvi_archive [options]\n"); parser->print_options (std::cout); std::cout << std::endl; } static void parse_fn ( Xvi_archive_parms* parms, dlib::Plm_clp* parser, int argc, char* argv[] ) { /* Add --help, --version */ parser->add_default_options (); /* Input files and directories */ parser->add_long_option ("", "patient-directory", "base directory containing patient images", 1, ""); /* Other options */ parser->add_long_option ("", "patient-id-override", "set the patient id", 1, ""); parser->add_long_option ("", "write-debug-files", "write converted image and xform files for debugging", 0); /* Parse options */ parser->parse (argc,argv); /* Handle --help, --version */ parser->check_default_options (); /* Input files */ parms->patient_dir = parser->get_string("patient-directory"); if (parms->patient_dir == "") { throw (dlib::error ( "Error. The use of --patient-directory is needed")); } /* Other options */ parms->patient_id_override = parser->get_string("patient-id-override"); if (parser->have_option ("write-debug-files")) { parms->write_debug_files = true; } } int main (int argc, char *argv[]) { Xvi_archive_parms parms; /* Parse command line parameters */ plm_clp_parse (&parms, &parse_fn, &usage_fn, argc, argv, 0); /* Do the job */ do_xvi_archive (&parms); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/xvi_archive.h000066400000000000000000000010031321604176500314210ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __xvi_archive_h__ #define __xvi_archive_h__ #include class Xvi_archive_parms { public: Xvi_archive_parms () { write_debug_files = false; } public: std::string patient_dir; std::string patient_id_override; bool write_debug_files; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/standalone/yk_config.h000066400000000000000000000055671321604176500311050ustar00rootroot00000000000000#ifndef YK_CONFIG_H #define YK_CONFIG_H //#include "itkImage.h" //#include "itkImageFileReader.h" //#include "itkImageFileWriter.h" #include #include #define DEFAULT_LABEL_SIZE1 512 #define DEFAULT_LABEL_SIZE2 256 #define DEFAULT_LABEL_SIZE3 256 #define MAX_LINE_LENGTH 1024 #define GY2YKIMG_MAG 700.0 //if 1000: 70Gy --> 70000 --> overflow, if 500: 70Gy --> 35000 cGy, if 700: 100Gy --> 70000 cGy ->OK #define GAMMA2YKIMG_MAG 1000.0 //2 --> 512: 0~1: 256, 1-2: 256 #define GY2CGY 100.0; #define NON_NEG_SHIFT 0.0 //2 --> 512: 0~1: 256, 1-2: 256 #define DEFAULT_LABEL_WIDTH 256 #define DEFAULT_LABEL_HEIGHT 256 struct VEC3D{ double x; double y; double z; }; // 1mm spacing, unit = cGy class ProtonSetFileMGH{ public: VEC3D fDim; VEC3D fOrigin; VEC3D fSpacing; QString strCTDir; QString strPathCompDose; QString strPathRefDose; }; enum enPLANE{ PLANE_AXIAL = 0, PLANE_FRONTAL, PLANE_SAGITTAL, }; enum enCOLOR_TABLE{ COL_TABLE_GAMMA = 0, COL_TABLE_JET, }; enum enPROFILE_DIRECTON{ PRIFLE_HOR = 0, PRIFLE_VER, }; enum enViewArrange{ AXIAL_FRONTAL_SAGITTAL = 0, FRONTAL_SAGITTAL_AXIAL, SAGITTAL_AXIAL_FRONTAL, }; enum enRegisterOption{ PLAST_RIGID = 0, PLAST_GRADIENT, PLAST_AFFINE, PLAST_BSPLINE, }; enum enUpdateDirection{ GUI2DATA = 0, DATA2GUI, }; #define DEFAULT_NUM_COLUMN_MAIN 3 #define DEFAULT_MAXNUM_MAIN 50 #define DEFAULT_NUM_COLUMN_QUE 7 #define DEFAULT_MAXNUM_QUE 500 enum enStatus{ ST_NOT_STARTED = 0, ST_PENDING, ST_ERROR, ST_DONE, }; enum enPlmCommandInfo{ PLM_OUTPUT_DIR_PATH = 0, PLM_TEMP1, PLM_TEMP2, }; class CRegiQueString { public: QString m_quePathFixed; //file name with extention QString m_quePathMoving; QString m_quePathCommand; int m_iStatus; //0: not started, 1: pending, 2: done double m_fProcessingTime; //sec double m_fScore; public: CRegiQueString(){ m_iStatus = ST_NOT_STARTED; m_fScore = 0.0; m_fProcessingTime = 0.0; } ~CRegiQueString(){ ; } QString GetStrFixed(){ QFileInfo fInfo(m_quePathFixed); return fInfo.fileName(); } QString GetStrMoving(){ QFileInfo fInfo(m_quePathMoving); return fInfo.fileName(); } QString GetStrCommand(){ QFileInfo fInfo(m_quePathCommand); return fInfo.fileName(); } QString GetStrStatus(){ if (m_iStatus == ST_NOT_STARTED) return QString("Wait"); else if (m_iStatus == ST_PENDING) return QString("Pending"); else if (m_iStatus == ST_DONE) return QString("Done"); else return QString(""); } QString GetStrScore(){ return QString::number(m_fScore, 'f', 2); } QString GetStrTime(){ return QString::number(m_fProcessingTime, 'f', 2); } }; #endif // YK_CONFIG_H plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/000077500000000000000000000000001321604176500254355ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/CMakeLists.txt000066400000000000000000000046001321604176500301750ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_sys) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/plmsys_config.h.in ${CMAKE_BINARY_DIR}/plmsys_config.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) ##----------------------------------------------------------------------------- ## SOURCE FILES ## GCS 2012-09-28: Please include non-private header files as well ##----------------------------------------------------------------------------- set (PLMSYS_LIBRARY_SRC compiler_warnings.h delayload.c delayload.h dir_list.cxx dir_list.h double_align8.h dlib_threads.cxx dlib_threads.h file_util.cxx file_util.h logfile.cxx logfile.h option_range.cxx option_range.h path_util.cxx path_util.h plm_endian.cxx plm_endian.h plm_exception.h plm_fwrite.cxx plm_fwrite.h plm_int.h plm_macros.h plm_math.h plm_return_code.h plm_sleep.cxx plm_sleep.h plm_timer.cxx plm_timer.h plm_timer_p.h plm_va_copy.h print_and_exit.cxx print_and_exit.h smart_pointer.h string_util.cxx string_util.h ) set (PLMSYS_LIBRARY_HEADERS "${CMAKE_BINARY_DIR}/plm_config.h" "${CMAKE_BINARY_DIR}/plmsys_config.h" ) foreach (ARG ${PLMSYS_LIBRARY_SRC}) string (REGEX MATCH ".*\\.h$" TMP "${ARG}") if (TMP) list (APPEND PLMSYS_LIBRARY_HEADERS "${TMP}") endif () endforeach () ##----------------------------------------------------------------------------- ## LIBRARY DEPENDENCIES ##----------------------------------------------------------------------------- set (PLMSYS_LIBRARY_DEPENDENCIES ${DLIB_LIBRARIES} ) if (LIBDL_FOUND) set (PLMSYS_LIBRARY_DEPENDENCIES ${PLMSYS_LIBRARY_DEPENDENCIES} dl ) endif () if (CYGWIN OR NOT WIN32) find_library (pthreadlib pthread) if (pthreadlib) set (PLMSYS_LIBRARY_DEPENDENCIES ${PLMSYS_LIBRARY_DEPENDENCIES} ${pthreadlib} ) endif () endif () ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- plm_add_library ( plmsys "${PLMSYS_LIBRARY_SRC}" "${PLMSYS_LIBRARY_DEPENDENCIES}" "" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "${PLMSYS_LIBRARY_HEADERS}") plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/compiler_warnings.h000066400000000000000000000005171321604176500313330ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _compiler_warnings_h_ #define _compiler_warnings_h_ #define UNUSED_VARIABLE(a) ((void) a) #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/delayload.c000066400000000000000000000172041321604176500275430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include "delayload.h" #include #include #if defined (_WIN32) #include // for LoadLibrary() #include // for _getcwd() #define get_cwd _getcwd #else #include // for dlopen() #include // for getcwd() #define get_cwd getcwd #endif /* Note: * Any utility that plans to use GPU functions should call the proper * delayload_X function to check if the CUDA or OpenCL runtimes are available. * * Return 1 if runtime found, 0 if runtime not found. */ // This makes things read easier and also // gives me an entry point later if I need // to do something fancy. static int find_lib (const char* lib) { #if defined (_WIN32) if (LoadLibrary (lib) != NULL) { return 1; /* Success */ } else { return 0; /* Failure */ } #else if (dlopen_ex (lib) != NULL) { return 1; /* Success */ } else { return 0; /* Failure */ } #endif } // This is a small helper function that will search around // for the desired libraries... this is to help out users // that don't configure their system paths correctly. // Checks: // * 1st: System Path / ld cache / etc // * 2nd: Current Working Directory // * 3rd: Default CUDA lib paths // * 4th: OpenCL paths // // Note: For Windows we ONLY check the current // path since we are at the mercy of the // link.exe /DELAYLOAD switch. Libraries // for Windows must, therefore, be found // at compile time... which makes the // Windows aspect of this a job for CMake. #if !defined (_WIN32) void* dlopen_ex (const char* lib) { char cwd[FILENAME_MAX]; char cudalib32[FILENAME_MAX]; char cudalib64[FILENAME_MAX]; char libopencl[FILENAME_MAX]; /* current working directory */ if (!get_cwd(cwd, sizeof(cwd))) { cwd[0] = '\0'; } strcat (cwd, "/"); strcat (cwd, lib); cwd[FILENAME_MAX - 1] = '\0'; /* default cuda lib paths */ strcpy (cudalib32, "/usr/local/cuda/lib/"); strcat (cudalib32, lib); strcpy (cudalib64, "/usr/local/cuda/lib64/"); strcat (cudalib64, lib); /* ubuntu opencl lib path (nvidia) */ strcpy (libopencl, "/usr/lib/nvidia-current/"); strcat (libopencl, lib); /* Search in order */ if (dlopen (lib, RTLD_LAZY) != NULL) { return dlopen (lib, RTLD_LAZY); } else if (dlopen (cwd, RTLD_LAZY) != NULL){ return dlopen (cwd, RTLD_LAZY); } else if (dlopen (cudalib32, RTLD_LAZY) != NULL){ return dlopen (cudalib32, RTLD_LAZY); } else if (dlopen (cudalib64, RTLD_LAZY) != NULL){ return dlopen (cudalib64, RTLD_LAZY); } else if (dlopen (libopencl, RTLD_LAZY) != NULL){ return dlopen (libopencl, RTLD_LAZY); } else { return NULL; /* Failure */ } } #endif // Note: We need special cases for Windows and POSIX compliant OSes static int delayload_cuda_internal (const char* windows_name, const char* unix_name) { #if defined (_WIN32) // Windows // For Windows we try to load the CUDA drivers: // * If they don't exist -> we should exit upon returning from this function. // * If they do exist -> windows has been told to delay load plmcuda.dll // when a cuda function is encountered, we will // load plmcuda.dll automagically, which we know // will work as intended since we have 1st checked // that the cuda drivers are installed on the // users system (nvcuda.dll). (See also // CMakeLists.txt for /DELAYLOAD configuration) // Because good ol' Windows can't do symlinks, there is no version safe // way to check for the runtime... the name of the file changes with every // new version release of the CUDA Toolkit. Users will just need to read // the documentation and install the version of the toolkit that was used // to build the plastimatch CUDA plugin (plmcuda.dll) OR compile from // source. if ( !find_lib ("nvcuda.dll") /* CUDA Driver */ #if defined (PLM_USE_GPU_PLUGINS) || !find_lib (windows_name) /* PLM CUDA Plugin */ #endif ) { printf ("Failed to load CUDA runtime!\n"); printf ("For GPU acceleration, please install:\n"); printf ("* the plastimatch GPU plugin\n"); printf ("* the CUDA Toolkit version needed by the GPU plugin\n\n"); printf ("Visit http://www.plastimatch.org/contents.html for more information.\n"); printf ("OR email for support.\n\n"); return 0; } else { // success return 1; } #elif defined (APPLE) #if defined (PLM_USE_GPU_PLUGINS) printf ("CUDA support of OS X is currently not available when building\n"); printf ("Plastimatch with BUILD_SHARED_LIBS enabled. Sorry.\n\n"); return 0; #endif return 1; #else // NOT Windows (most likely a POSIX compliant OS though...) // // Check for *both* the CUDA runtime & CUDA driver // // I think this is version safe due to the way nvidia does symlinks. // For example, on my system: // // libcuda.so -> libcuda.so.195.36.24 // *and* // libcudart.so -> libcudart.so.3 // libcudart.so.3 -> libcudart.so.3.0.14 // if ( !find_lib ("libcuda.so") /* CUDA Driver */ || !find_lib ("libcudart.so") /* CUDA RunTime */ #if defined (PLM_USE_GPU_PLUGINS) || !find_lib (unix_name) /* PLM CUDA Plugin */ #endif ) { printf ("Failed to load CUDA runtime!\n"); printf ("For GPU acceleration, please install:\n"); printf ("* the plastimatch GPU plugin\n"); printf ("* the CUDA Toolkit version needed by the GPU plugin\n\n"); printf ("Visit http://www.plastimatch.org/contents.html for more information.\n"); printf ("OR email for support.\n\n"); return 0; } else { // success return 1; } #endif } int delayload_libplmcuda (void) { return delayload_cuda_internal ("plmcuda.dll", "libplmcuda.so"); } int delayload_libplmreconstructcuda (void) { return delayload_cuda_internal ( "plmreconstructcuda.dll", "libplmreconstructcuda.so"); } int delayload_libplmregistercuda (void) { return delayload_cuda_internal ( "plmregistercuda.dll", "libplmregistercuda.so"); } int delayload_libplmopencl (void) { #if defined (_WIN32) if (!find_lib ("opencl.dll")) { printf ("Failed to load GPU Plugins (err: OpenCL)\n"); printf ("Visit http://www.plastimatch.org/contents.html for more information.\n"); printf ("OR email for support.\n\n"); return 0; } else { // success return 1; } #elif defined (APPLE) #if defined (PLM_USE_GPU_PLUGINS) printf ("OpenCL support of OS X is currently not available when building\n"); printf ("Plastimatch with BUILD_SHARED_LIBS enabled. Sorry.\n\n"); return 0; #endif return 1; #else if (!find_lib ("libOpenCL.so")) { printf ("Failed to load GPU Plugins! (err: OpenCL)\n"); printf ("Visit http://www.plastimatch.org/contents.html for more information.\n"); printf ("OR email for support.\n\n"); return 0; } else { // success return 1; } #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/delayload.h000066400000000000000000000060451321604176500275510ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _delayload_h_ #define _delayload_h_ #include "plmsys_config.h" #ifndef _WIN32 #include #endif #include // Needed for delay loading windows DLLs #if _MSC_VER #pragma comment(lib, "delayimp") #pragma comment(lib, "user32") #endif // JAS 2010.11.23 // ------------------------------------------------------------ // Because these macros contain declarations, their // usage is restricted under C89. C89-GNU, C99, and // C++ are all cool with using these macros pretty // much anywhere... be careful inside switch statements. // Still, their usage will determine the portability of // plastimatch. // Note: if you attempt to load a library that // does not exist or cannot be found, this // returns a null pointer. #if !defined(_WIN32) && defined(PLM_USE_GPU_PLUGINS) #define LOAD_LIBRARY(lib) \ void* lib = dlopen_ex (#lib".so"); #else #define LOAD_LIBRARY(lib) \ ; #endif // Note: if lib contains a null pointer here // (see above note), this will return a // null function pointer. Be careful pls. #if !defined(_WIN32) && defined(PLM_USE_GPU_PLUGINS) #define LOAD_SYMBOL(sym, lib) \ sym##_##t* sym = (sym##_##t*) dlsym (lib, #sym); #else #define LOAD_SYMBOL(sym, lib) \ ; #endif // ------------------------------------------------------------ // JAS 2012.03.29 // ------------------------------------------------------------ // Now that plastimatch is officially C++, we can now safely // define this macro, which reduces programmer error. This // should be used instead of LOAD_LIBRARY #if !defined(_WIN32) && defined(PLM_USE_GPU_PLUGINS) #define LOAD_LIBRARY_SAFE(lib) \ if (!delayload_##lib()) { exit (0); } \ void* lib = dlopen_ex (#lib".so"); #else #define LOAD_LIBRARY_SAFE(lib) \ if (!delayload_##lib()) { exit (0); } \ ; #endif // JAS 2010.12.09 // Despite what the man pages say, dlclose()ing NULL // was resulting in segfaults! So, now we check 1st. #if !defined(_WIN32) && defined(PLM_USE_GPU_PLUGINS) #define UNLOAD_LIBRARY(lib) \ if (lib != NULL) { \ dlclose (lib); \ } #else #define UNLOAD_LIBRARY(lib) \ ; #endif #define DELAYLOAD_WRAP(f, ...) \ f (__VA_ARGS__); typedef f##_t(__VA_ARGS__); PLMSYS_C_API int delayload_libplmcuda (void); PLMSYS_C_API int delayload_libplmreconstructcuda (void); PLMSYS_C_API int delayload_libplmregistercuda (void); PLMSYS_C_API int delayload_libplmopencl (void); PLMSYS_C_API void* dlopen_ex (const char* lib); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/dir_list.cxx000066400000000000000000000042131321604176500277720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include #include #include #if (defined(_WIN32) || defined(WIN32)) #include #include #else #include #endif #include "dir_list.h" #include "path_util.h" class Dir_list_private { public: std::string dir; }; Dir_list::Dir_list () { d_ptr = new Dir_list_private; this->init (); } Dir_list::Dir_list (const char* dir) { d_ptr = new Dir_list_private; this->init (); this->load (dir); } Dir_list::Dir_list (const std::string& dir) { d_ptr = new Dir_list_private; this->init (); this->load (dir.c_str()); } Dir_list::~Dir_list () { int i; if (this->entries) { for (i = 0; i < this->num_entries; i++) { free (this->entries[i]); } free (this->entries); } delete d_ptr; } void Dir_list::init () { this->num_entries = 0; this->entries = 0; } void Dir_list::load (const char* dir) { #if (_WIN32) intptr_t srch; struct _finddata_t d; char* buf; buf = (char*) malloc (strlen (dir) + 3); sprintf (buf, "%s/*", dir); srch = _findfirst (buf, &d); free (buf); if (srch == -1) return; do { this->num_entries ++; this->entries = (char**) realloc ( this->entries, this->num_entries * sizeof (char*)); this->entries[this->num_entries-1] = strdup (d.name); } while (_findnext (srch, &d) != -1); _findclose (srch); #else DIR* dp; struct dirent* d; dp = opendir (dir); if (!dp) return; for (d = readdir(dp); d; d = readdir(dp)) { this->num_entries ++; this->entries = (char**) realloc ( this->entries, this->num_entries * sizeof (char*)); this->entries[this->num_entries-1] = strdup (d->d_name); } closedir (dp); #endif d_ptr->dir = dir; } std::string Dir_list::entry (int idx) { if (idx < 0 || idx > num_entries) { return ""; } return compose_filename (d_ptr->dir, entries[idx]); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/dir_list.h000066400000000000000000000012321321604176500274150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dir_list_h_ #define _dir_list_h_ #include "plmsys_config.h" #include class Dir_list_private; class PLMSYS_API Dir_list { public: Dir_list_private *d_ptr; public: int num_entries; char** entries; public: Dir_list (); Dir_list (const char* dir); Dir_list (const std::string& dir); ~Dir_list (); void init (); void load (const char* dir); std::string entry (int idx); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/dlib_threads.cxx000066400000000000000000000066511321604176500306150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include #include "dlib/threads.h" #include "dlib_threads.h" /* ----------------------------------------------------------------------- Dlib_thread_function ----------------------------------------------------------------------- */ class Dlib_thread_function_private { public: dlib::thread_function tf; public: Dlib_thread_function_private ( void (*thread_routine) (void *), void *arg) : tf (thread_routine, arg) { } }; Dlib_thread_function::Dlib_thread_function ( void (*thread_routine) (void *), void *arg) { d_ptr = new Dlib_thread_function_private (thread_routine, arg); } Dlib_thread_function::~Dlib_thread_function () { delete d_ptr; } /* ----------------------------------------------------------------------- Dlib_semaphore ----------------------------------------------------------------------- */ class Dlib_semaphore_private { public: dlib::mutex rm; dlib::signaler rs; bool grabbed; public: Dlib_semaphore_private() : rs(rm) {} }; Dlib_semaphore::Dlib_semaphore (bool grabbed) { d_ptr = new Dlib_semaphore_private; d_ptr->grabbed = grabbed; } Dlib_semaphore::~Dlib_semaphore () { delete d_ptr; } void Dlib_semaphore::grab () { d_ptr->rm.lock (); while (d_ptr->grabbed == true) { d_ptr->rs.wait (); } d_ptr->grabbed = true; d_ptr->rm.unlock (); } void Dlib_semaphore::release () { d_ptr->rm.lock (); d_ptr->grabbed = false; d_ptr->rs.signal (); d_ptr->rm.unlock (); } /* ----------------------------------------------------------------------- Dlib_master_slave ----------------------------------------------------------------------- */ class Dlib_master_slave_private { public: dlib::mutex rm; dlib::signaler master_rs; dlib::signaler slave_rs; bool slave_active; bool slave_waits; public: Dlib_master_slave_private () : master_rs (rm), slave_rs (rm) { slave_active = false; slave_waits = false; } }; Dlib_master_slave::Dlib_master_slave () { d_ptr = new Dlib_master_slave_private; } Dlib_master_slave::~Dlib_master_slave () { delete d_ptr; } void Dlib_master_slave::master_grab_resource () { d_ptr->rm.lock (); d_ptr->slave_waits = true; while (d_ptr->slave_active) { d_ptr->master_rs.wait (); } d_ptr->rm.unlock (); } void Dlib_master_slave::master_release_resource () { d_ptr->rm.lock (); d_ptr->slave_waits = false; d_ptr->slave_rs.signal (); d_ptr->rm.unlock (); } void Dlib_master_slave::slave_grab_resource () { d_ptr->rm.lock (); while (d_ptr->slave_waits) { d_ptr->slave_rs.wait (); } d_ptr->slave_active = true; d_ptr->rm.unlock (); } void Dlib_master_slave::slave_release_resource () { d_ptr->rm.lock (); d_ptr->slave_active = false; d_ptr->master_rs.signal (); d_ptr->rm.unlock (); } #if !DLIB_HAVE_LIBRARY #include "dlib/threads/multithreaded_object_extension.cpp" #include "dlib/threads/threaded_object_extension.cpp" #include "dlib/threads/threads_kernel_1.cpp" #include "dlib/threads/threads_kernel_2.cpp" #include "dlib/threads/threads_kernel_shared.cpp" #include "dlib/threads/thread_pool_extension.cpp" #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/dlib_threads.h000066400000000000000000000021331321604176500302310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dlib_threads_h_ #define _dlib_threads_h_ #include "plmsys_config.h" class Dlib_master_slave_private; class Dlib_semaphore_private; class Dlib_thread_function_private; class PLMSYS_API Dlib_thread_function { public: Dlib_thread_function_private *d_ptr; public: Dlib_thread_function (void (*thread_routine) (void *), void *arg); ~Dlib_thread_function (); }; class PLMSYS_API Dlib_semaphore { public: Dlib_semaphore_private *d_ptr; public: Dlib_semaphore (bool grabbed = false); ~Dlib_semaphore (); public: void grab (); void release (); }; class PLMSYS_API Dlib_master_slave { public: Dlib_master_slave_private *d_ptr; public: Dlib_master_slave (); ~Dlib_master_slave (); public: void master_grab_resource (); void master_release_resource (); void slave_grab_resource (); void slave_release_resource (); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/double_align8.h000066400000000000000000000017511321604176500303260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __double_align8_h__ #define __double_align8_h__ /* JAS 2011.07.23 * The following is a fix that allows us to more selectively enforce * the -malign-double compatibility required by object files compiled * by nvcc. Any structures that are used by both nvcc compiled files * and gcc/g++ compiled files should use this. The reason we do not * simply pass -malign-double to gcc/g++ in order to achieve this * compatibility is because Slicer's ITK does not come compiled with * the -malign-double flag on 32-bit systems... so, believe it or not * this might be the cleanest solution */ #if (__GNUC__) && (MACHINE_IS_32_BIT) && (CUDA_FOUND) typedef double double_align8 __attribute__ ((aligned(8))); #else typedef double double_align8; #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/file_util.cxx000066400000000000000000000101421321604176500301330ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include #include #include #include #if (defined(_WIN32) || defined(WIN32)) #include #include #include #else #include /* sleep() */ #include #endif #if HAVE_SYS_STAT_H #include #endif #include "file_util.h" #include "path_util.h" int is_directory (const char *dir) { #if (defined(_WIN32) || defined(WIN32)) char *pwd; if ((pwd = _getcwd (NULL, 0)) == NULL) { return 0; } if (_chdir (dir) == -1) { free (pwd); return 0; } _chdir (pwd); free (pwd); return 1; #else /* UNIX */ DIR *dp; if ((dp = opendir (dir)) == NULL) { return 0; } closedir (dp); return 1; #endif } int is_directory (const std::string& dir) { return is_directory (dir.c_str()); } int file_exists (const char *filename) { FILE *f = fopen (filename, "r"); if (f) { fclose (f); return 1; } return 0; } int file_exists (const std::string& filename) { return file_exists (filename.c_str()); } uint64_t file_size (const char *filename) { struct stat fs; if (stat (filename, &fs) != 0) return 0; return (uint64_t) fs.st_size; } void touch_file (const std::string& filename) { make_parent_directories (filename); FILE *fp = fopen (filename.c_str(), "w"); fclose (fp); } /* N.b. there might be a faster way for MSVC debug mode: http://bytes.com/topic/c/answers/62145-filecopy-std-copy */ void copy_file (const std::string& dst_fn, const std::string& src_fn) { std::ifstream src (src_fn.c_str(), std::ios::binary); std::ofstream dst (dst_fn.c_str(), std::ios::binary); dst << src.rdbuf(); } void make_directory (const char *dirname) { int retries = 4; #if (_WIN32) mkdir (dirname); #else mkdir (dirname, 0777); #endif /* On various samba mounts, there is a delay in creating the directory. Here, we work around that problem by waiting until the directory is created */ while (--retries > 0 && !is_directory (dirname)) { #if (_WIN32) Sleep (1000); #else sleep (1); #endif } } void make_directory (const std::string& dirname) { make_directory (dirname.c_str()); } void make_parent_directories (const char *filename) { char *p, *tmp; if (!filename) return; tmp = strdup (filename); p = tmp; while (*p) { if (ISSLASH (*p) && p != tmp) { *p = 0; make_directory (tmp); *p = '/'; } p++; } free (tmp); } void make_parent_directories (const std::string& filename) { make_parent_directories (filename.c_str()); } void make_directory_recursive (const std::string& dirname) { make_parent_directories (dirname); make_directory (dirname.c_str()); } FILE* plm_fopen (const char *path, const char *mode) { if (mode && (mode[0] == 'w' || mode[0] == 'a')) { make_parent_directories (path); } return fopen (path, mode); } FILE* plm_fopen (const std::string& path, const char *mode) { return plm_fopen (path.c_str(), mode); } FILE* make_tempfile (void) { # if defined (_WIN32) /* tmpfile is broken on windows. It tries to create the temorary files in the root directory where it doesn't have permissions. http://msdn.microsoft.com/en-us/library/x8x7sakw(VS.80).aspx */ /* GCS FIX: The temporary file doesn't get deleted on windows */ char *parms_fn = _tempnam (0, "plastimatch_"); FILE *fp = fopen (parms_fn, "wb+"); # else FILE *fp = tmpfile (); # endif return fp; } /* cross platform getcwd */ char* plm_getcwd (char* s, int len) { #if (UNIX) return getcwd (s, len); #elif (WIN32) /* Microsoft declares POSIX as "deprecated" */ return _getcwd (s, len); #endif } /* cross platform chdir */ int plm_chdir (char* s) { #if (UNIX) return chdir (s); #elif (WIN32) /* Microsoft declares POSIX as "deprecated" */ return _chdir (s); #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/file_util.h000066400000000000000000000025151321604176500275650ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _file_util_h_ #define _file_util_h_ #include "plmsys_config.h" #include #include #include "plm_int.h" PLMSYS_API int file_exists (const char *filename); PLMSYS_API int file_exists (const std::string& filename); PLMSYS_API uint64_t file_size (const char *filename); PLMSYS_API int is_directory (const char *dir); PLMSYS_API int is_directory (const std::string& dir); PLMSYS_API void touch_file (const std::string& filename); PLMSYS_API void copy_file (const std::string& dst_fn, const std::string& src_fn); PLMSYS_API void make_directory (const char *dirname); PLMSYS_API void make_directory (const std::string& dirname); PLMSYS_API void make_parent_directories (const char *filename); PLMSYS_API void make_parent_directories (const std::string& filename); PLMSYS_API void make_directory_recursive (const std::string& dirname); PLMSYS_API FILE* make_tempfile (void); PLMSYS_API char* plm_getcwd (char* s, int len); PLMSYS_API int plm_chdir (char* s); PLMSYS_API FILE* plm_fopen (const char *path, const char *mode); PLMSYS_API FILE* plm_fopen (const std::string& path, const char *mode); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/logfile.cxx000066400000000000000000000023611321604176500276040ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include #include #include #include #include #include "logfile.h" #include "plm_version.h" #define LOGFILE_ECHO_ON 1 FILE* log_fp = 0; void logfile_open (const char* log_fn, const char* mode) { if (!log_fn[0]) return; if (!(log_fp)) { log_fp = fopen (log_fn, mode); if (!log_fp) { /* If failure (e.g. bad path), do nothing */ } } else { /* Already open? */ } logfile_printf ("Plastimatch " PLASTIMATCH_VERSION_STRING "\n"); } void logfile_close (void) { if (log_fp) { fclose (log_fp); log_fp = 0; } } void logfile_printf (const char* fmt, ...) { /* Write to console */ if (LOGFILE_ECHO_ON) { va_list argptr; va_start (argptr, fmt); vprintf (fmt, argptr); fflush (stdout); va_end (argptr); } if (log_fp) { va_list argptr; va_start (argptr, fmt); vfprintf (log_fp, fmt, argptr); fflush (log_fp); va_end (argptr); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/logfile.h000066400000000000000000000007701321604176500272330ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _logfile_h_ #define _logfile_h_ #include "plmsys_config.h" PLMSYS_API void logfile_open (const char* log_fn, const char* mode = "w"); PLMSYS_API void logfile_close (void); PLMSYS_API void logfile_printf (const char* fmt, ...); #define lprintf logfile_printf #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/option_range.cxx000066400000000000000000000055341321604176500306540ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include #include #include "option_range.h" #include "plm_math.h" #include "string_util.h" class Option_range_private { public: std::list range; }; Option_range::Option_range () { d_ptr = new Option_range_private; } Option_range::~Option_range () { delete d_ptr; } void Option_range::set_log_range (const std::string& range) { float min_value; float max_value; float incr; d_ptr->range.clear (); /* Create list of values from the string */ int rc = sscanf (range.c_str(), "%f:%f:%f", &min_value, &incr, &max_value); if (rc == 3) { /* Handle start:stride:stop form */ for (float log_value = min_value; log_value <= max_value; log_value += incr) { d_ptr->range.push_back (exp10_ (log_value)); } } else { /* Handle value,value,.. form */ const char *p = range.c_str(); int n = 0; do { float log_value; n = 0; rc = sscanf (p, " %f ,%n", &log_value, &n); p += n; if (rc >= 1) { d_ptr->range.push_back (exp10_ (log_value)); } } while (rc >= 1 && n > 0); } } void Option_range::set_linear_range (const std::string& range) { float min_value; float max_value; float incr; d_ptr->range.clear (); /* Create list of values from the string */ int rc = sscanf (range.c_str(), "%f:%f:%f", &min_value, &incr, &max_value); if (rc == 3) { /* Handle start:stride:stop form */ for (float lin_value = min_value; lin_value <= max_value; lin_value += incr) { d_ptr->range.push_back (lin_value); } } else { /* Handle value,value,.. form */ const char *p = range.c_str(); int n = 0; do { float lin_value; n = 0; rc = sscanf (p, " %f ,%n", &lin_value, &n); p += n; if (rc >= 1) { d_ptr->range.push_back (lin_value); } } while (rc >= 1 && n > 0); } } void Option_range::set_range (const std::string& range) { if (range.length() > 1 && range[0] == 'L') { printf ("Setting log range\n"); this->set_log_range (range.substr (1, std::string::npos)); } else { printf ("Setting linear range\n"); this->set_linear_range (range); } } void Option_range::set_range (float range) { d_ptr->range.clear (); d_ptr->range.push_back (range); } const std::list& Option_range::get_range () { return d_ptr->range; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/option_range.h000066400000000000000000000013471321604176500302770ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _option_range_h_ #define _option_range_h_ #include "plmsys_config.h" #include #include class Option_range_private; class PLMSYS_API Option_range { public: Option_range (); ~Option_range (); public: void set_log_range (const std::string& range); void set_linear_range (const std::string& range); void set_range (const std::string& range); void set_range (float range); const std::list& get_range (); public: Option_range_private *d_ptr; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/path_util.cxx000066400000000000000000000074051321604176500301600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include #include #include #include #include #include "file_util.h" #include "path_util.h" int extension_is (const char* fname, const char* ext) { return (strlen (fname) > strlen(ext)) && !strcmp (&fname[strlen(fname)-strlen(ext)], ext); } int extension_is (const std::string& fname, const char* ext) { return extension_is (fname.c_str(), ext); } void strip_extension (char* filename) { char *p; p = strrchr (filename, '.'); if (p) { *p = 0; } } std::string strip_extension (const std::string& filename) { size_t lastdot = filename.find_last_of("."); if (lastdot == std::string::npos) return filename; return filename.substr(0, lastdot); } std::string strip_extension_if ( const std::string& filename, const std::string& ext) { if (extension_is (filename, ext.c_str())) { return strip_extension (filename); } else { return filename; } } void trim_trailing_slashes (char *pathname) { char *p = pathname + strlen (pathname) - 1; while (p >= pathname && ISSLASH(*p)) { *p = 0; } } std::string trim_trailing_slashes (const std::string& pathname) { size_t s = pathname.find_last_not_of ("/"); return pathname.substr(0, s+1); } /* Caller must free memory */ char* file_util_parent (const char *filename) { char *tmp = 0; char *p = 0, *q = 0; if (!filename) return tmp; p = tmp = strdup (filename); trim_trailing_slashes (p); while (*p) { if (ISSLASH (*p)) { q = p; } p ++; } if (q) { *q = 0; return tmp; } else { /* No directory separators -- return "." */ free (tmp); return strdup ("."); } } std::string file_util_parent (const std::string& filename) { char *tmp = file_util_parent (filename.c_str()); std::string parent (tmp); free (tmp); return parent; } /* Caller must free memory */ char* file_util_dirname (const char *filename) { if (!filename) return 0; if (is_directory (filename)) { return strdup (filename); } return file_util_parent (filename); } std::string file_util_dirname_string (const char *filename) { std::string dirname = ""; char *c_dirname = file_util_dirname (filename); if (c_dirname) { dirname = c_dirname; free (c_dirname); } return dirname; } std::string strip_leading_dir (const std::string& fn) { size_t s = fn.find_first_of ("/"); if (s == fn.npos) { return fn; } return fn.substr(s+1); } std::string basename (const std::string& fn) { std::string tmp = trim_trailing_slashes (fn); size_t s = tmp.find_last_of ("/"); if (s == tmp.npos) { return tmp; } return tmp.substr(s+1); } std::string dirname (const std::string& fn) { std::string tmp = trim_trailing_slashes (fn); size_t s = tmp.find_last_of ("/"); if (s == tmp.npos) { return tmp; } tmp = tmp.substr(0, s+1); return trim_trailing_slashes (tmp); } std::string compose_filename (const char *a, const char *b) { std::string output_fn; char *tmp = strdup (a); trim_trailing_slashes (tmp); output_fn = tmp; free (tmp); output_fn.append ("/"); output_fn.append (b); return output_fn; } std::string compose_filename (const std::string& a, const std::string& b) { return compose_filename (a.c_str(), b.c_str()); } std::string make_windows_slashes (const std::string& s) { #if (_WIN32) std::string t = s; std::replace(t.begin(), t.end(), '/', '\\'); return t; #else return s; #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/path_util.h000066400000000000000000000031231321604176500275760ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _path_util_h_ #define _path_util_h_ #include "plmsys_config.h" #include #include #if (_WIN32) #define ISSLASH(c) (((c) == '/') || ((c) == '\\')) #else #define ISSLASH(c) ((c) == '/') #endif PLMSYS_API std::string basename (const std::string& fn); PLMSYS_API std::string dirname (const std::string& fn); PLMSYS_API int extension_is (const char* fname, const char* ext); PLMSYS_API int extension_is (const std::string& fname, const char* ext); PLMSYS_API void strip_extension (char* filename); PLMSYS_API std::string strip_extension (const std::string& filename); PLMSYS_API std::string strip_extension_if ( const std::string& filename, const std::string& ext); PLMSYS_API void trim_trailing_slashes (char *pathname); PLMSYS_API std::string trim_trailing_slashes (const std::string& pathname); PLMSYS_API char* file_util_parent (const char *filename); PLMSYS_API std::string file_util_parent (const std::string& filename); PLMSYS_API char* file_util_dirname (const char *filename); PLMSYS_API std::string file_util_dirname_string (const char *filename); PLMSYS_API std::string strip_leading_dir (const std::string& fn); PLMSYS_API std::string compose_filename (const std::string& a, const std::string& b); PLMSYS_API std::string compose_filename (const char *a, const char *b); PLMSYS_API std::string make_windows_slashes (const std::string& s); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_config.h.in000066400000000000000000000123201321604176500303260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plm_config_h__ #define __plm_config_h__ /* Architecture attributes */ #cmakedefine MACHINE_IS_32_BIT 1 #cmakedefine MACHINE_IS_64_BIT 1 /* Major OSes */ #cmakedefine WIN32 1 #cmakedefine UNIX 1 #cmakedefine APPLE 1 /* Compiler attributes */ #cmakedefine HAVE_SYS_STAT_H 1 #cmakedefine HAVE_STDINT_H 1 #cmakedefine HAVE_SYS_STAT_H 1 #cmakedefine OPENMP_FOUND 1 #cmakedefine SSE2_FOUND 1 #cmakedefine SHARED_PTR_USE_MEMORY 1 #cmakedefine TR1_SHARED_PTR_USE_MEMORY 1 #cmakedefine TR1_SHARED_PTR_USE_TR1_MEMORY 1 #define CMAKE_SIZEOF_UINT @CMAKE_SIZEOF_UINT@ #define CMAKE_SIZEOF_ULONG @CMAKE_SIZEOF_ULONG@ #define CMAKE_SIZEOF_SIZE_T @CMAKE_SIZEOF_SIZE_T@ #define PLM_BIG_ENDIAN @PLM_BIG_ENDIAN@ /* External libraries */ #cmakedefine CUDA_FOUND 1 #cmakedefine DCMTK_FOUND 1 #cmakedefine DCMTK_HAVE_CFUNIX_H 1 #cmakedefine DLIB_FOUND 1 #cmakedefine DLIB_HAVE_LIBRARY 1 #cmakedefine FFTW_FOUND 1 #cmakedefine GDCM_FOUND 1 #cmakedefine LIBLBFGS_FOUND 1 #cmakedefine NLOPT_FOUND 1 #cmakedefine OPENCL_FOUND 1 #cmakedefine PANTHEIOS_FOUND 1 #cmakedefine SPECFUN_FOUND 1 #cmakedefine READLINE_FOUND 1 #cmakedefine QT4_FOUND 1 /* User options */ #cmakedefine PLM_BUILD_SHARED_LIBS 1 #cmakedefine PLM_CONFIG_USE_PATCHED_ITK 1 #cmakedefine PLM_CONFIG_VOL_LIST 1 #cmakedefine PLM_CONFIG_LEGACY_BSPLINE_EXTEND 1 #cmakedefine PLM_CONFIG_LEGACY_BSPLINE_XFORM_IO 1 #cmakedefine PLM_CONFIG_LEGACY_MI_METRIC 1 /* Needed for dynamic loading */ #cmakedefine PLM_USE_GPU_PLUGINS 1 /* Dicom attributes. One and only one of these will be true. */ #cmakedefine PLM_DCM_USE_DCMTK 1 #cmakedefine PLM_DCM_USE_GDCM1 1 #cmakedefine PLM_DCM_USE_GDCM2 1 /* ITK attributes */ #cmakedefine ITK_FOUND 1 #cmakedefine ITK_USE_SYSTEM_GDCM 1 /* Make Microsoft compiler less whiny */ #if _MSC_VER >= 1400 /* 4244 warning convert double to float, etc. */ /* 4251 dll export of std c++ types http://msdn.microsoft.com/en-us/library/esew7y1w.aspx */ /* 4305 warning convert double to float, etc. */ /* 4819 warnings generated by itk headers */ /* 4800 warning convert int to bool */ /* 4996 warnings for using functions defined as deprecated */ #pragma warning( disable : 4244 4251 4305 4800 4819 4996 ) #endif /* Make GCC compiler less whiny */ #if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 2) && !defined(NVCC) /* -Wwrite-strings warnings generated when passing literal strings as (non-const?) function parameters */ #pragma GCC diagnostic ignored "-Wwrite-strings" /* -Wdepricated warnings generated by itk headers */ #pragma GCC diagnostic ignored "-Wdeprecated" /* -Wno-sign-conversion warnings are generated when comparing signed and unsigned integers -- these should be revisited occasionally to check for actual bugs. */ /* Unfortunately, the below doesn't actually work. We still get warnings. */ /**** #pragma GCC diagnostic ignored "-Wsign-conversion" */ /* -Wmissing-braces warnings are generated when nested braces aren't used for initialization of multi-dimensional array */ #pragma GCC diagnostic ignored "-Wmissing-braces" #endif #if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 8) && !defined(NVCC) /* -Wunused-local-typedefs is emitted by older versions of ITK */ # pragma GCC diagnostic ignored "-Wunused-local-typedefs" #endif /* Make clang compiler less whiny */ #if defined (__clang__) /* -Wgnu ignores GNU extensions, which is needed to suppress warnings caused by non-compliant vxl header files */ #pragma clang diagnostic ignored "-Wgnu" /* -Wtautological-compare warnings are generated by comparison expressions which are always true or always false -- usually caused by template expansions */ #pragma clang diagnostic ignored "-Wtautological-compare" #endif #if defined(_MSC_VER) && _MSC_VER < 1700 #define inline __inline #endif #if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf _snprintf #endif #ifdef __cplusplus #define EXTERNC extern "C" #else #define EXTERNC #endif #if ((defined(_WIN32) || defined(WIN32)) && (defined (PLM_USE_GPU_PLUGINS))) #ifdef plmcuda_EXPORTS #define plmcuda_EXPORT(f, ...) \ __declspec(dllexport) \ f (__VA_ARGS__); typedef f##_t(__VA_ARGS__); #else #define plmcuda_EXPORT(f, ...) \ __declspec(dllimport) \ f (__VA_ARGS__); typedef f##_t(__VA_ARGS__); #endif #ifdef plmopencl_EXPORTS #define plmopencl_EXPORT(f, ...) \ __declspec(dllexport) \ f (__VA_ARGS__); typedef f##_t(__VA_ARGS__); #else #define plmopencl_EXPORT(f, ...) \ __declspec(dllimport) \ f (__VA_ARGS__); typedef f##_t(__VA_ARGS__); #endif #else #define plmcuda_EXPORT(f, ...) \ f (__VA_ARGS__); typedef f##_t(__VA_ARGS__); #define plmopencl_EXPORT(f, ...) \ f (__VA_ARGS__); typedef f##_t(__VA_ARGS__); #endif #endif /* __plm_config_h__ */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_endian.cxx000066400000000000000000000047311321604176500302740ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include "plm_endian.h" #include "plm_int.h" /* Switch buffer endian between big and little (2 byte types) */ static void endian2_swap (void* buf, unsigned long len) { uint8_t *cbuf = (uint8_t*) buf; for (unsigned long i = 0; i < len; i++) { uint8_t tmp; tmp = cbuf[2*i+0]; cbuf[2*i+0] = cbuf[2*i+1]; cbuf[2*i+1] = tmp; } } /* Switch buffer endian between big and little (4 byte types) */ static void endian4_swap (void* buf, unsigned long len) { uint8_t *cbuf = (uint8_t*) buf; for (unsigned long i = 0; i < len; i++) { uint8_t tmp[4]; tmp[0] = cbuf[4*i+0]; tmp[1] = cbuf[4*i+1]; tmp[2] = cbuf[4*i+2]; tmp[3] = cbuf[4*i+3]; cbuf[4*i+0] = tmp[3]; cbuf[4*i+1] = tmp[2]; cbuf[4*i+2] = tmp[1]; cbuf[4*i+3] = tmp[0]; } } /* Switch buffer from big to native (2 byte types) */ void endian2_big_to_native (void* buf, unsigned long len) { #if PLM_BIG_ENDIAN /* do nothing */ #else endian2_swap (buf, len); #endif } /* Switch buffer from native to big (2 byte types) */ void endian2_native_to_big (void* buf, unsigned long len) { #if PLM_BIG_ENDIAN /* do nothing */ #else endian2_swap (buf, len); #endif } /* Switch buffer from little to native (2 byte types) */ void endian2_little_to_native (void* buf, unsigned long len) { #if PLM_BIG_ENDIAN endian2_swap (buf, len); #endif } /* Switch buffer from native to little (2 byte types) */ void endian2_native_to_little (void* buf, unsigned long len) { #if PLM_BIG_ENDIAN endian2_swap (buf, len); #endif } /* Switch buffer from big to native (4 byte types) */ void endian4_big_to_native (void* buf, unsigned long len) { #if PLM_BIG_ENDIAN /* do nothing */ #else endian4_swap (buf, len); #endif } /* Switch buffer from native to big (4 byte types) */ void endian4_native_to_big (void* buf, unsigned long len) { #if PLM_BIG_ENDIAN /* do nothing */ #else endian4_swap (buf, len); #endif } /* Switch buffer from little to native (4 byte types) */ void endian4_little_to_native (void* buf, unsigned long len) { #if PLM_BIG_ENDIAN endian4_swap (buf, len); #endif } /* Switch buffer from native to little (4 byte types) */ void endian4_native_to_little (void* buf, unsigned long len) { #if PLM_BIG_ENDIAN endian4_swap (buf, len); #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_endian.h000066400000000000000000000016031321604176500277140ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_endian_h_ #define _plm_endian_h_ #include "plmsys_config.h" PLMSYS_C_API void endian2_big_to_native (void* buf, unsigned long len); PLMSYS_C_API void endian2_native_to_big (void* buf, unsigned long len); PLMSYS_C_API void endian2_little_to_native (void* buf, unsigned long len); PLMSYS_C_API void endian2_native_to_little (void* buf, unsigned long len); PLMSYS_C_API void endian4_big_to_native (void* buf, unsigned long len); PLMSYS_C_API void endian4_native_to_big (void* buf, unsigned long len); PLMSYS_C_API void endian4_little_to_native (void* buf, unsigned long len); PLMSYS_C_API void endian4_native_to_little (void* buf, unsigned long len); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_exception.h000066400000000000000000000013131321604176500304520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_exception_h_ #define _plm_exception_h_ #include "plmsys_config.h" #include #include class Plm_exception : public std::exception { public: Plm_exception (const std::string& a) : info(a) { } virtual ~Plm_exception () throw() {} const char* what () const throw () { return info.c_str(); } public: /* Error message */ const std::string info; private: const Plm_exception& operator=(const Plm_exception&); }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_fwrite.cxx000066400000000000000000000052371321604176500303400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include #include #include #if (defined(_WIN32) || defined(WIN32)) #include #endif #include "plm_int.h" #include "plm_fwrite.h" #include "print_and_exit.h" #define LINELEN 128 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define WRITE_BLOCK (1024*1024) /* GCS Jun 18, 2008. When using MSVC 2005, large fwrite calls to files over samba mount fails. This seems to be a bug in the C runtime library. This function works around the problem by breaking up the large write into many "medium-sized" writes. */ /* GCS Apr 4, 2014. It seems this is a problem for writes > 4GB, even 64-bit builds and MSVC 2010. Sigh. */ #if _MSC_VER static size_t fwrite_internal (void* buf, size_t size, size_t count, FILE* fp) { size_t left_to_write = count * size; size_t cur = 0; char* bufc = (char*) buf; while (left_to_write > 0) { size_t this_write, rc; this_write = left_to_write; if (this_write > WRITE_BLOCK) this_write = WRITE_BLOCK; rc = fwrite (&bufc[cur], 1, this_write, fp); cur += rc; left_to_write -= rc; if (rc != this_write) { break; } } return (count * size - left_to_write) / size; } #else static size_t fwrite_internal (void* buf, size_t size, size_t count, FILE* fp) { return fwrite (buf, size, count, fp); } #endif void plm_fwrite (void* buf, size_t size, size_t count, FILE* fp, bool force_little_endian) { #if PLM_BIG_ENDIAN /* If we need to swap bytes, do it while writing into OS fwrite buffer */ if (force_little_endian && size > 1) { uint8_t *cbuf = (uint8_t*) buf; if (size == 2) { for (size_t i = 0; i < count; i++) { char tmp[2] = { cbuf[2*i+1], cbuf[2*i+1] }; size_t rc = fwrite (tmp, 1, 2, fp); if (rc != 2) { print_and_exit ("plm_fwrite error (rc = %u)\n", rc); } } return; } else if (size == 4) { for (size_t i = 0; i < count; i++) { char tmp[4] = { cbuf[2*i+3], cbuf[2*i+1], cbuf[2*i+1], cbuf[2*i+0] }; size_t rc = fwrite (tmp, 1, 4, fp); if (rc != 4) { print_and_exit ("plm_fwrite error (rc = %u)\n", rc); } } return; } else { print_and_exit ( "Error, plm_write encountered an unexpected input\n"); } } #endif /* Otherwise, we don't need to swap bytes. Just do regular. */ { size_t rc = fwrite_internal (buf, size, count, fp); if (rc != count) { print_and_exit ( "Error, plm_write write error (rc = %u)\n", rc); } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_fwrite.h000066400000000000000000000007141321604176500277600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_fwrite_h_ #define _plm_fwrite_h_ #include "plmsys_config.h" PLMSYS_C_API void plm_fwrite ( void* buf, size_t size, size_t count, FILE* fp, bool force_little_endian ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_int.h000066400000000000000000000031011321604176500272430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_int_h_ #define _plm_int_h_ #include "plmsys_config.h" #if defined (GDCMCOMMON_H) /* Gdcm 1.x has a broken header file gdcmCommon.h, which defines C99 types (e.g. int32_t) when missing on MSVC. It conflicts with plm_int.h (which also fixes missing C99 types). Here is a workaround for this issue. */ #if !defined (CMAKE_HAVE_STDINT_H) && !defined (CMAKE_HAVE_INTTYPES_H) \ && (defined(_MSC_VER) \ || defined(__BORLANDC__) && (__BORLANDC__ < 0x0560) \ || defined(__MINGW32__)) typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #endif /* GDCMCOMMON_H */ #elif defined (_MSC_VER) && (_MSC_VER < 1600) #include "msinttypes/stdint.h" #else #include #endif /* These are non-standard */ #ifndef UINT32_T_MAX #define UINT32_T_MAX (0xffffffff) #endif #ifndef INT32_T_MAX #define INT32_T_MAX (0x7fffffff) #endif #ifndef INT32_T_MIN #define INT32_T_MIN (-0x7fffffff - 1) #endif /* The data type plm_long is a signed integer with the same size as size_t. It is equivalent to the POSIX idea of ssize_t. It is used for OpenMP 2.0 loop variables which must be signed. */ #if (CMAKE_SIZEOF_SIZE_T == 8) typedef int64_t plm_long; #elif (CMAKE_SIZEOF_SIZE_T == 4) typedef int32_t plm_long; #else #error "Unexpected value for sizeof(size_t)" #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_macros.h000066400000000000000000000016061321604176500277450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_macros_h_ #define _plm_macros_h_ /* Nb. Doxygen values are substituted in PREDEFINED value of Doxyfile.in */ #define PLM_GET_SET(type, name) \ const type& get_##name () const; \ void set_##name (const type&) #define PLM_GET(type, name) \ type get_##name () const #define PLM_GET_CR(type, name) \ const type& get_##name () const #define PLM_SET(type, name) \ void set_##name (type) #define PLM_SET_CR(type, name) \ void set_##name (const type&) #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_math.h000077500000000000000000000164071321604176500274220ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_math_h_ #define _plm_math_h_ //#include "plmsys_config.h" #include #include #include #include #include "compiler_warnings.h" #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef M_SQRT2 #define M_SQRT2 1.41421356237309504880 #endif #ifndef M_SQRTPI #define M_SQRTPI 1.77245385090551602792981 #endif #ifndef M_TWOPI #define M_TWOPI (M_PI * 2.0) #endif #ifndef DBL_MAX #define DBL_MAX (1E+37) #endif #ifndef M_SQRT1_2 #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ #endif #ifndef M_SQRT3_OVER_2 #define M_SQRT3_OVER_2 0.866025403784439 /* sqrt(3)/2 - nonstandard */ #endif #ifndef M_SQRT2PI #define M_SQRT2PI 2.50662827463100 /* sqrt(2*pi) - nonstandard */ #endif #ifndef M_PI_2 #define M_PI_2 1.57079632679489661923 /* pi/2 */ #endif #ifndef M_PI_3 #define M_PI_3 1.04719755119660 /* pi/3 - nonstandard */ #endif #ifndef M_PI_4 #define M_PI_4 0.78539816339744830962 /* pi/4 */ #endif /* Returns integer data type */ #define ROUND_INT(x) (((x) >= 0) ? ((long)((x)+0.5)) : (long)(-(-(x)+0.5))) /* Returns plm_long data type */ #define FLOOR_PLM_LONG(x) ((plm_long) floor (x)) #define ROUND_PLM_LONG(x) \ (((x) >= 0) ? ((plm_long)((x)+0.5)) : (plm_long)(-(-(x)+0.5))) /* Returns unsigned integer data type */ #define FLOOR_SIZE_T(x) (((x) >= 0) ? ((size_t)(x)) : 0) #define ROUND_SIZE_T(x) (((x) >= 0) ? ((size_t)((x)+0.5)) : 0) /* Returns double data type -- note MSVC does not have C99 round(). */ #define ROUND(x) ((double) (ROUND_INT(x))) /* Returns +1 or -1, depeding on sign. Zero yeilds +1. */ #define SIGN(x) (((x) >= 0) ? (+1) : (-1)) // Fix for logf() under MSVC 2005 32-bit (math.h has an erronous semicolon) // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98751 #if _MSC_VER == 1400 #if !defined (_M_IA64) && !defined (_M_AMD64) && defined (_WIN32) #ifdef logf #undef logf #define logf(x) ((float)log((double)(x))) #endif #endif #endif /* How small is too small of a vector to normalize ? */ #define FLOAT_SMALL_VECTOR_LENGTH 1e-6 /* exp10() is not in C/C++ standard */ static inline double exp10_ (double m) { return exp (2.3025850929940456840179914546844 * m); } /* Primatives */ static inline void vec2_add2 (double* v1, const double* v2) { v1[0] += v2[0]; v1[1] += v2[1]; } static inline void vec3_add2 (double* v1, const double* v2) { v1[0] += v2[0]; v1[1] += v2[1]; v1[2] += v2[2]; } static inline void vec3_add3 (double* v1, const double* v2, const double* v3) { v1[0] = v2[0] + v3[0]; v1[1] = v2[1] + v3[1]; v1[2] = v2[2] + v3[2]; } template static inline void vec3_copy (T* v1, const T* v2) { v1[0] = v2[0]; v1[1] = v2[1]; v1[2] = v2[2]; } static inline void vec4_copy (double* v1, const double* v2) { v1[0] = v2[0]; v1[1] = v2[1]; v1[2] = v2[2]; v1[3] = v2[3]; } template static inline T vec3_dot (const T* v1, const T* v2) { return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; } template static inline float vec3_dot (const T* v1, const U* v2) { return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; } static inline double vec4_dot (const double* v1, const double* v2) { return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3]; } static inline void vec3_scale2 (double* v1, double a) { v1[0] *= a; v1[1] *= a; v1[2] *= a; } template static inline void vec3_scale3 (T* v1, const T* v2, U a) { v1[0] = a * v2[0]; v1[1] = a * v2[1]; v1[2] = a * v2[2]; } static inline void vec3_sub2 (double* v1, const double* v2) { v1[0] -= v2[0]; v1[1] -= v2[1]; v1[2] -= v2[2]; } #if defined (commentout) template static inline void vec3_sub3 (T* v1, const T* v2, const T* v3) { v1[0] = v2[0] - v3[0]; v1[1] = v2[1] - v3[1]; v1[2] = v2[2] - v3[2]; } #endif template static inline void vec3_sub3 (T* v1, const U* v2, const V* v3) { v1[0] = v2[0] - v3[0]; v1[1] = v2[1] - v3[1]; v1[2] = v2[2] - v3[2]; } static inline void vec3_invert (double* v1) { vec3_scale2 (v1, -1.0); } static inline void vec_zero (double* v1, int n) { memset (v1, 0, n*sizeof(double)); } /* Length & distance */ template static inline T vec3_lensq (const T* v1) { return vec3_dot(v1,v1); } template static T vec3_len (const T*); template<> inline double vec3_len<> (const double* v1) { return sqrt(vec3_dot(v1,v1)); } template<> inline float vec3_len (const float* v1) { return sqrtf(vec3_dot(v1,v1)); } static inline void vec3_normalize1 (double* v1) { vec3_scale2 (v1, 1 / vec3_len(v1)); } template static inline T vec3_distsq (const T* v1, const T* v2) { T tmp[3]; vec3_sub3 (tmp, v1, v2); return vec3_lensq(tmp); } template static inline T vec3_dist (const T* v1, const T* v2) { T tmp[3]; vec3_sub3 (tmp, v1, v2); return vec3_len(tmp); } /* Cross product */ template static inline void vec3_cross (T* v1, const T* v2, const T* v3) { v1[0] = v2[1] * v3[2] - v2[2] * v3[1]; v1[1] = v2[2] * v3[0] - v2[0] * v3[2]; v1[2] = v2[0] * v3[1] - v2[1] * v3[0]; } /* Outer product */ static inline void vec_outer (double* v1, const double* v2, const double* v3, const int n) { int i,j; for (j=0; j DBL_MAX || x < -DBL_MAX) return 0; #if defined (commentout) if (std::numeric_limits::has_infinity && x == std::numeric_limits::infinity()) { return 0; } #endif return 1; } template T clamp (T value, T min_value, T max_value) { if (value < min_value) return min_value; if (value > max_value) return max_value; return value; } // Cf. http://realtimecollisiondetection.net/blog/?p=89 // https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ static inline bool within_abs_tolerance (float value, float comp_value, float tolerance) { return (fabsf (value - comp_value) <= tolerance); } #define NLMIN(T) (-std::numeric_limits::max()) #define NLMAX(T) std::numeric_limits::max() #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_return_code.h000066400000000000000000000007501321604176500307710ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_return_code_h_ #define _plm_return_code_h_ #include "plmsys_config.h" enum Plm_return_code { PLM_UNINITIALIZED, /* Do not use */ PLM_SUCCESS, /* General success */ PLM_ERROR /* Unspecified error */ }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_sleep.cxx000066400000000000000000000007261321604176500301460ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #if _WIN32 #include #else #include #endif #include "plm_sleep.h" void plm_sleep (int milliseconds) { #if (_WIN32) Sleep (milliseconds); #else usleep (1000 * milliseconds); #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_sleep.h000066400000000000000000000005431321604176500275700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_sleep_h_ #define _plm_sleep_h_ #include "plmsys_config.h" PLMSYS_API void plm_sleep (int milliseconds); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_timer.cxx000066400000000000000000000035371321604176500301610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include #include #include "plm_timer_p.h" #include "plm_timer.h" #include "compiler_warnings.h" Plm_timer_private::Plm_timer_private () { #if defined (_WIN32) QueryPerformanceFrequency (&this->clock_freq); #endif acc_time = 0.; running = true; start_time = get_time (); } double Plm_timer_private::get_time () { #if defined (_WIN32) LARGE_INTEGER clock_count; QueryPerformanceCounter (&clock_count); return ((double) (clock_count.QuadPart)) / ((double) this->clock_freq.QuadPart); #else struct timeval tv; int rc; rc = gettimeofday (&tv, 0); UNUSED_VARIABLE (rc); return ((double) tv.tv_sec) + ((double) tv.tv_usec) / 1000000.; #endif } double Plm_timer_private::elapsed_time () { if (!this->running) { return 0.; } double current_time = this->get_time (); return current_time - this->start_time; } Plm_timer::Plm_timer () { this->d_ptr = new Plm_timer_private; } Plm_timer::~Plm_timer () { delete this->d_ptr; } void Plm_timer::start () { d_ptr->acc_time = 0.; d_ptr->running = true; d_ptr->start_time = d_ptr->get_time (); } void Plm_timer::stop () { if (d_ptr->running) { d_ptr->acc_time += d_ptr->elapsed_time (); d_ptr->running = false; } } void Plm_timer::reset () { this->stop (); d_ptr->acc_time = 0.; } void Plm_timer::resume () { if (!d_ptr->running) { /* Don't reset acc_time */ d_ptr->running = true; d_ptr->start_time = d_ptr->get_time (); } } double Plm_timer::report () { return d_ptr->acc_time + d_ptr->elapsed_time(); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_timer.h000066400000000000000000000010461321604176500275770ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_timer_h_ #define _plm_timer_h_ #include "plmsys_config.h" class Plm_timer_private; class PLMSYS_API Plm_timer { public: Plm_timer (); ~Plm_timer (); void start (); void stop (); void reset (); void resume (); double report (); private: Plm_timer_private *d_ptr; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_timer_p.h000066400000000000000000000010731321604176500301160ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #ifdef _WIN32 #include #else #include #endif class Plm_timer_private { public: Plm_timer_private (); public: bool running; double start_time; double acc_time; #ifdef _WIN32 LARGE_INTEGER clock_freq; #endif public: double get_time (); double elapsed_time (); }; plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_va_copy.h000066400000000000000000000006171321604176500301220ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plm_va_copy_h__ #define __plm_va_copy_h__ #if defined(__BORLANDC__) || defined(_MSC_VER) #ifndef va_copy #define va_copy(d,s) ((d) = (s)) #endif #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plm_version.h.in000066400000000000000000000005371321604176500305550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_version_h_ #define _plm_version_h_ #define PLASTIMATCH_VERSION_STRING "@PLASTIMATCH_VERSION_STRING@" #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/plmsys_config.h.in000066400000000000000000000012671321604176500310750ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plmsys_config_h__ #define __plmsys_config_h__ #include "plm_config.h" #if ((defined(_WIN32) || defined(WIN32)) && (defined (PLM_BUILD_SHARED_LIBS))) # ifdef plmsys_EXPORTS # define PLMSYS_C_API EXTERNC __declspec(dllexport) # define PLMSYS_API __declspec(dllexport) # else # define PLMSYS_C_API EXTERNC __declspec(dllimport) # define PLMSYS_API __declspec(dllimport) # endif #else # define PLMSYS_C_API EXTERNC # define PLMSYS_API #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/print_and_exit.cxx000066400000000000000000000016301321604176500311700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include #include #include #include "logfile.h" #include "plm_exception.h" #include "print_and_exit.h" #include "string_util.h" #if (defined(_WIN32) || defined(WIN32)) #define vsnprintf _vsnprintf #endif void print_and_exit (const char* prompt_fmt, ...) { if (prompt_fmt) { va_list argptr; va_start (argptr, prompt_fmt); std::string error_message = string_format_va (prompt_fmt, argptr); lprintf ("%s", error_message.c_str()); Plm_exception pe = Plm_exception (error_message); va_end (argptr); throw pe; } throw Plm_exception ("Plastimatch: unknown error."); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/print_and_exit.h000066400000000000000000000010551321604176500306160ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _print_and_exit_h_ #define _print_and_exit_h_ #include "plmsys_config.h" PLMSYS_API void print_and_exit (const char* prompt_fmt, ...); #define error_printf(fmt, ...) \ fprintf (stderr, "\nplastimatch has encountered an issue.\n" \ "file: %s (line:%i)\n" fmt, __FILE__, __LINE__,##__VA_ARGS__) #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/smart_pointer.h000066400000000000000000000074161321604176500305040ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _smart_pointer_h_ #define _smart_pointer_h_ #include "plm_config.h" #if PLM_CUDA_COMPILE /* There is a bug in Linux CUDA 4.x nvcc compiler which causes it to barf with either dlib::shared_ptr or std::shared_ptr */ # define SMART_POINTER_SUPPORT(T) \ typedef void* Pointer #else # if SHARED_PTR_USE_MEMORY # include # define plm_shared_ptr std::shared_ptr # elif TR1_SHARED_PTR_USE_TR1_MEMORY # include # define plm_shared_ptr std::tr1::shared_ptr # elif TR1_SHARED_PTR_USE_MEMORY # include # define plm_shared_ptr std::tr1::shared_ptr # else # include "dlib/smart_pointers.h" # define plm_shared_ptr dlib::shared_ptr # endif # define SMART_POINTER_SUPPORT(T) \ public: \ typedef T Self; \ typedef plm_shared_ptr Pointer; \ static T::Pointer New () { \ return T::Pointer (new T); \ } \ static T::Pointer New (T* t) { \ return T::Pointer (t); \ } \ template static T::Pointer New ( \ const U1& u1) { \ return T::Pointer ( \ new T(u1)); \ } \ template static T::Pointer New ( \ const U1& u1, const U2& u2) { \ return T::Pointer ( \ new T(u1, u2)); \ } \ template static T::Pointer New ( \ const U1& u1, const U2& u2, const U3& u3) { \ return T::Pointer ( \ new T(u1, u2, u3)); \ } \ template static T::Pointer New ( \ const U1& u1, const U2& u2, const U3& u3, \ const U4& u4, const U5& u5, const U6& u6) { \ return T::Pointer ( \ new T(u1, u2, u3, u4, u5, u6)); \ } /* A warning for the future. (1) Template parameter assignment produces types, and therefore arguments to New() are pass-by value (2a) Therefore, classes without copy constructors require explicit reference in signature; for example: template foo (U& u); (2b) In principle, using a reference should be faster, because a copy constructor is not needed. (3) However, you cannot overload based on reference. The gcc compiler (probably others too) can't resolve: template foo (U u); template foo (const U& u); */ #endif #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/string_util.cxx000066400000000000000000000254241321604176500305330ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmsys_config.h" #include #include #include #include #include #include #include #include #include #include #include "plm_va_copy.h" #include "string_util.h" bool string_starts_with (const std::string& s1, const char* s2) { return string_starts_with (s1.c_str(), s2); } bool string_starts_with (const char* s1, const char* s2) { return strncmp (s1, s2, strlen(s2)) == 0; } int plm_strcmp (const char* s1, const char* s2) { return strncmp (s1, s2, strlen(s2)); } std::string make_lowercase (const std::string& s) { std::string out; std::transform (s.begin(), s.end(), std::back_inserter(out), ::tolower); return out; } std::string make_uppercase (const std::string& s) { std::string out; std::transform (s.begin(), s.end(), std::back_inserter(out), ::toupper); return out; } static int regularize_string_callback (int c) { int o = ::tolower (c); if (o == '-') { o = '_'; } return o; } /* Make lower case, and convert dash '-' to underscore '_' */ std::string regularize_string (const std::string& s) { std::string out; std::transform (s.begin(), s.end(), std::back_inserter(out), regularize_string_callback); return out; } void string_util_rtrim_whitespace (char *s) { int len = (int)strlen (s); while (len > 0 && isspace(s[len-1])) { s[len-1] = 0; len--; } } Plm_return_code parse_int13 (int *arr, const char *string) { int rc; rc = sscanf (string, "%d %d %d", &arr[0], &arr[1], &arr[2]); if (rc == 3) { return PLM_SUCCESS; } else if (rc == 1) { arr[1] = arr[2] = arr[0]; return PLM_SUCCESS; } else { return PLM_ERROR; } } Plm_return_code parse_int13 (int *arr, const std::string& string) { return parse_int13 (arr, string.c_str()); } Plm_return_code parse_float13 (float *arr, const char *string) { int rc; rc = sscanf (string, "%g %g %g", &arr[0], &arr[1], &arr[2]); if (rc == 3) { return PLM_SUCCESS; } else if (rc == 1) { arr[1] = arr[2] = arr[0]; return PLM_SUCCESS; } else { return PLM_ERROR; } } Plm_return_code parse_float13 (float *arr, const std::string& string) { return parse_float13 (arr, string.c_str()); } int parse_dicom_float2 (float *arr, const char *string) { int rc; rc = sscanf (string, "%f\\%f", &arr[0], &arr[1]); if (rc == 2) { return 0; } else { /* Failure */ return 1; } } int parse_dicom_float3 (float *arr, const char *string) { int rc; rc = sscanf (string, "%f\\%f\\%f", &arr[0], &arr[1], &arr[2]); if (rc == 3) { return 0; } else { /* Failure */ return 1; } } int parse_dicom_float6 (float *arr, const char *string) { int rc; rc = sscanf (string, "%f\\%f\\%f\\%f\\%f\\%f", &arr[0], &arr[1], &arr[2], &arr[3], &arr[4], &arr[5]); if (rc == 6) { return 0; } else { /* Failure */ return 1; } } /* Parse a string of the form "3 22 -1; 3 4 66; 3 1 0" */ std::vector parse_int3_string (const char* s) { std::vector int_list; const char* p = s; int rc = 0; int n; do { int v[3]; n = 0; rc = sscanf (p, "%d %d %d;%n", &v[0], &v[1], &v[2], &n); p += n; if (rc >= 3) { int_list.push_back (v[0]); int_list.push_back (v[1]); int_list.push_back (v[2]); } } while (rc >= 3 && n > 0); return int_list; } /* Parse a string of the form "3 22 -1; 3 4 66; 3 1 0" */ std::vector parse_float3_string (const char* s) { std::vector float_list; const char* p = s; int rc = 0; int n; do { float v[3]; n = 0; rc = sscanf (p, "%f %f %f;%n", &v[0], &v[1], &v[2], &n); p += n; if (rc >= 3) { float_list.push_back (v[0]); float_list.push_back (v[1]); float_list.push_back (v[2]); } } while (rc >= 3 && n > 0); return float_list; } std::vector parse_float3_string (const std::string& s) { return parse_float3_string (s.c_str()); } /* Parse a string of the form "3 0.2 1e-3" or "3,0.2,1e-3"*/ std::vector parse_float_string (const char* s) { std::vector float_list; const char* p = s; int rc = 0; int n; do { float v; n = 0; rc = sscanf (p, " %f%n", &v, &n); if (rc == 0) { rc = sscanf (p, " , %f%n", &v, &n); } if (rc == 0 || rc == EOF) { break; } p += n; float_list.push_back (v); } while (1); return float_list; } std::vector parse_float_string (const std::string& s) { return parse_float_string (s.c_str()); } /* String trimming by GMan. http://stackoverflow.com/questions/1798112/removing-leading-and-trailing-spaces-from-a-string/1798170#1798170 Distributed under Attribution-ShareAlike 3.0 Unported license (CC BY-SA 3.0) http://creativecommons.org/licenses/by-sa/3.0/ */ const std::string string_trim ( const std::string& str, const std::string& whitespace ) { const size_t begin_str = str.find_first_not_of (whitespace); if (begin_str == std::string::npos) { // no content return ""; } const size_t end_str = str.find_last_not_of(whitespace); const size_t range = end_str - begin_str + 1; return str.substr (begin_str, range); } std::string slurp_file (const char* fn) { /* Read file into string */ std::ifstream t (fn); std::stringstream buffer; buffer << t.rdbuf(); return buffer.str(); } std::string slurp_file (const std::string& fn) { return slurp_file (fn.c_str()); } /* std::string formatting by Erik Aronesty http://stackoverflow.com/questions/2342162/stdstring-formating-like-sprintf Distributed under Attribution-ShareAlike 3.0 Unported license (CC BY-SA 3.0) http://creativecommons.org/licenses/by-sa/3.0/ */ std::string string_format_va (const char *fmt, va_list ap) { int size=100; std::string str; while (1) { str.resize(size); va_list ap_copy; va_copy (ap_copy, ap); //int n = vsnprintf((char *)str.c_str(), size, fmt, ap_copy); int n = vsnprintf((char *)str.data(), size, fmt, ap_copy); va_end (ap_copy); if (n > -1 && n < size) { str = std::string (str.c_str()); /* Strip excess padding */ return str; } if (n > -1) size=n+1; else size*=2; } } std::string string_format (const char *fmt, ...) { va_list ap; va_start (ap, fmt); std::string string = string_format_va (fmt, ap); va_end (ap); return string; } /* Case-insensitive string::find() by Kirill V. Lyadvinsky http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find Distributed under Attribution-ShareAlike 3.0 Unported license (CC BY-SA 3.0) http://creativecommons.org/licenses/by-sa/3.0/ */ // templated version of my_equal so it could work with both char and wchar_t struct my_equal { bool operator()(char ch1, char ch2) { #ifdef _WIN32 return toupper(ch1) == toupper(ch2); #else return std::toupper(ch1) == std::toupper(ch2); #endif } }; // find substring (case insensitive) size_t ci_find (const std::string& str1, const std::string& str2) { std::string::const_iterator it = std::search (str1.begin(), str1.end(), str2.begin(), str2.end(), my_equal()); if (it != str1.end()) return it - str1.begin(); else return std::string::npos; } // Return true for "true", "1", or "on" bool string_value_true (const char* s) { return string_value_true (std::string(s)); } bool string_value_true (const std::string& s) { std::string t = make_lowercase (s); return t == "1" || t == "true" || t == "on" || t == "yes"; } bool string_value_false (const char* s) { return string_value_false (std::string(s)); } bool string_value_false (const std::string& s) { return !string_value_true (s); } // compiler does not recognize the std::to_string (c++11), so made our own template std::string PLM_to_string(T value) { std::ostringstream os ; os << value; return os.str(); } // fancy version for arrays template std::string PLM_to_string(T* value, int n) { std::ostringstream os ; for (int i = 0; i < n; i++) { if (i > 0) os << " "; os << value[i]; } return os.str(); } /* http://stackoverflow.com/questions/236129/split-a-string-in-c This version also trims, therefore different than the one described in stackoverflow. */ std::vector& string_split ( const std::string &s, char delim, std::vector &elems) { std::stringstream ss(s); std::string item; while (std::getline(ss, item, delim)) { item = string_trim (item); elems.push_back(item); } return elems; } std::vector string_split ( const std::string &s, char delim) { std::vector elems; string_split (s, delim, elems); return elems; } bool split_key_val ( const std::string& s, std::string& key, std::string& val, char delim) { size_t loc = s.find (delim); if (loc == std::string::npos) { key = string_trim (s); val = ""; return false; } key = string_trim (s.substr (0, loc)); val = string_trim (s.substr (loc + 1)); return true; } bool split_array_index ( const std::string& s, std::string& array, std::string& index) { size_t start_loc = s.find ('['); size_t end_loc = s.find (']'); if (start_loc == std::string::npos && end_loc == std::string::npos) { array = string_trim (s); index = ""; return true; } if (start_loc != std::string::npos && end_loc != std::string::npos && end_loc > start_loc + 1) { array = string_trim (s.substr (0, start_loc)); index = string_trim (s.substr (start_loc + 1, end_loc - start_loc - 1)); return true; } array = string_trim (s); index = ""; return false; } /* Explicit instantiations */ template PLMSYS_API std::string PLM_to_string(int value); template PLMSYS_API std::string PLM_to_string(size_t value); template PLMSYS_API std::string PLM_to_string(float value); template PLMSYS_API std::string PLM_to_string(double value); template PLMSYS_API std::string PLM_to_string(int *value, int n); template PLMSYS_API std::string PLM_to_string(double *value, int n); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/sys/string_util.h000066400000000000000000000055671321604176500301660ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _string_util_h_ #define _string_util_h_ #include "plmsys_config.h" #include #include #include #include "plm_return_code.h" PLMSYS_API bool string_starts_with (const std::string& s1, const char* s2); PLMSYS_API bool string_starts_with (const char* s1, const char* s2); PLMSYS_API int plm_strcmp (const char* s1, const char* s2); PLMSYS_API std::string make_lowercase (const std::string& s); PLMSYS_API std::string make_uppercase (const std::string& s); PLMSYS_API std::string regularize_string (const std::string& s); PLMSYS_API void string_util_rtrim_whitespace (char *s); PLMSYS_API Plm_return_code parse_int13 (int *arr, const char *string); PLMSYS_API Plm_return_code parse_int13 (int *arr, const std::string& string); PLMSYS_API Plm_return_code parse_float13 (float *arr, const char *string); PLMSYS_API Plm_return_code parse_float13 (float *arr, const std::string& string); PLMSYS_API int parse_dicom_float2 (float *arr, const char *string); PLMSYS_API int parse_dicom_float3 (float *arr, const char *string); PLMSYS_API int parse_dicom_float6 (float *arr, const char *string); PLMSYS_API std::vector parse_int3_string (const char* s); PLMSYS_API std::vector parse_float3_string (const char* s); PLMSYS_API std::vector parse_float3_string (const std::string& s); PLMSYS_API std::vector parse_float_string (const char* s); PLMSYS_API std::vector parse_float_string (const std::string& s); PLMSYS_API const std::string string_trim ( const std::string& str, const std::string& whitespace = " \t\r\n" ); PLMSYS_API std::string slurp_file (const char* fn); PLMSYS_API std::string slurp_file (const std::string& fn); PLMSYS_API std::string string_format_va (const char *fmt, va_list ap); PLMSYS_API std::string string_format (const char* fmt, ...); PLMSYS_API size_t ci_find (const std::string& str1, const std::string& str2); PLMSYS_API bool string_value_true (const char* s); PLMSYS_API bool string_value_true (const std::string& s); PLMSYS_API bool string_value_false (const char* s); PLMSYS_API bool string_value_false (const std::string& s); template PLMSYS_API std::string PLM_to_string(T value); template PLMSYS_API std::string PLM_to_string(T *value, int n); PLMSYS_API std::vector& string_split (const std::string &s, char delim, std::vector &elems); PLMSYS_API std::vector string_split (const std::string &s, char delim); PLMSYS_API bool split_key_val (const std::string& s, std::string& key, std::string& val, char delim = '='); PLMSYS_API bool split_array_index (const std::string& s, std::string& array, std::string& index); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/000077500000000000000000000000001321604176500255765ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/CMakeLists.txt000066400000000000000000000171051321604176500303420ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_test) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) if (CUDA_FOUND) add_subdirectory (cuda) include_directories (BEFORE "${CMAKE_CURRENT_SOURCE_DIR}/cuda") endif () ##----------------------------------------------------------------------------- ## CMAKE FLAGS ##----------------------------------------------------------------------------- option (PLM_CONFIG_BUILD_TEST_PROGRAMS "Build extra test program executables" OFF) ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- # Test executable -- plastimatch api if (PLM_CONFIG_BUILD_TEST_PROGRAMS) plm_add_executable (api_test api_test.cxx "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) # Test executable -- c++ properties plm_add_executable (cpp_eps_test cpp_eps_test.cxx "" "" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (cpp_floating_point_test cpp_floating_point_test.cxx "" "" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (cpp_limits_test cpp_limits_test.cxx "" "" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (cpp_overflow_test cpp_overflow_test.cxx "" "" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (cpp_template_test cpp_template_test.cxx "" "" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) plm_add_executable (cpp_sizeof_test cpp_sizeof_test.cxx "${PLASTIMATCH_LIBS}" "${GPUIT_EXE_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) # Test executable -- dcmtk if (ITK_FOUND AND DCMTK_FOUND) plm_add_executable (dcmtk_test dcmtk_test.cxx "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) plm_add_executable (rtplan_test rtplan_test.cxx "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) endif () # Test executable -- dlib plm_add_executable (dlib_test dlib_test.cxx "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) plm_add_executable (dlib_thread_test dlib_thread_test.cxx "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) # Test executable -- gabor_test plm_add_executable (gabor_test gabor_test.cxx "${PLASTIMATCH_LIBS}" "${GPUIT_EXE_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) # Test executables -- itk if (ITK_FOUND) plm_add_executable (itk_test itk_test.cxx "${PLASTIMATCH_LIBS}" "${GPUIT_EXE_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) plm_add_executable (itk_test_directions itk_test_directions.cxx "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) plm_add_executable (itk_test_threads itk_thread_test.cxx "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) endif () # Test executable -- libyaml if (LIBYAML_FOUND) plm_add_executable (libyaml_test libyaml_test.cxx "${LIBYAML_LIBRARIES}" "" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) endif () # Test executable -- matlab if (MATLAB_FOUND) file (WRITE "${CMAKE_BINARY_DIR}/compile_mex_test.m" "mex \"${CMAKE_SOURCE_DIR}/mex_test.c\";exit;\n") file (WRITE "${CMAKE_BINARY_DIR}/mex_test.cmake" "EXECUTE_PROCESS (COMMAND ${MATLAB_EXE} -nosplash -nodesktop -nojvm -r compile_mex_test RESULT_VARIABLE RESULT OUTPUT_VARIABLE STDOUT ERROR_VARIABLE STDERR)\n") add_custom_command ( OUTPUT "${CMAKE_BINARY_DIR}/mex_test${MATLAB_MEXEXT}" COMMAND ${CMAKE_COMMAND} -P "${CMAKE_BINARY_DIR}/mex_test.cmake" DEPENDS "${CMAKE_SOURCE_DIR}/mex_test.c") add_custom_target (mat_mex_test DEPENDS "${CMAKE_BINARY_DIR}/mex_test${MATLAB_MEXEXT}") target_link_libraries (mex_test ${MATLAB_LIBRARIES}) endif () # Test executable -- octave if (OCTAVE_FOUND) add_custom_command ( OUTPUT "${CMAKE_BINARY_DIR}/mex_test.mex" COMMAND ${OCTAVE_MKOCTFILE} --mex -o "${CMAKE_BINARY_DIR}/mex_test.mex" "${CMAKE_SOURCE_DIR}/mex_test.c" DEPENDS "${CMAKE_SOURCE_DIR}/mex_test.c") add_custom_target (oct_mex_test DEPENDS "${CMAKE_BINARY_DIR}/mex_test.mex") endif () # Test executable -- nlopt if (NLOPT_FOUND) set (NLOPT_TEST_LIBS ${GPUIT_LIBRARIES} ${NLOPT_LIBRARIES}) plm_add_executable (nlopt_test nlopt_test.c "${NLOPT_TEST_LIBS}" "${OPENMP_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) set_target_properties (nlopt_test PROPERTIES LINKER_LANGUAGE CXX) endif () # Test executable -- nm plm_add_executable (nelder_mead_test nelder_mead_test.cxx "${PLASTIMATCH_LIBS}" "${OPENMP_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) # Test executable -- opencl if (OPENCL_FOUND) set (OPENCL_TEST_SRC opencl_test.cxx opencl_test.h opencl_test.cl "${CMAKE_BINARY_DIR}/opencl_test.cl" ) set (OPENCL_TEST_LIBS ${OPENCL_LIBRARIES} ${PLASTIMATCH_LIBS}) plm_add_executable (opencl_test "${OPENCL_TEST_SRC}" "${OPENCL_TEST_LIBS}" "" ${BUILD_ALWAYS} ${INSTALL_NEVER}) # I don't yet know how to bundle the .cl file within the executable. # Therefore, copy the .cl into binary directory. add_custom_command ( OUTPUT "${CMAKE_BINARY_DIR}/opencl_test.cl" COMMAND ${CMAKE_COMMAND} "-E" "copy" "${CMAKE_CURRENT_SOURCE_DIR}/opencl_test.cl" "${CMAKE_BINARY_DIR}/opencl_test.cl" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/opencl_test.cl") endif () # Test executable -- openmp if (OPENMP_FOUND) set_source_files_properties (openmp_test.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) plm_add_executable (openmp_test openmp_test.cxx "${PLASTIMATCH_LIBS}" "${OPENMP_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) endif () # Test executable -- plm plm_add_executable (plm_restart_test plm_restart_test.cxx "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) # Test executable -- qt if (Qt5_FOUND) set (QT5_TEST_LIBRARIES Qt5::Network Qt5::Widgets Qt5::Gui Qt5::Core) plm_add_executable (qt5_test qt_test.cxx "${QT5_TEST_LIBRARIES}" "" ${BUILD_ALWAYS} ${INSTALL_NEVER}) endif () if (QT4_FOUND) set (QT4_TEST_INCLUDES ${PLASTIMATCH_INCLUDES} ${QT_QTGUI_INCLUDE_DIR} ${QT_INCLUDE_DIR} ${QT_QTCORE_INCLUDE_DIR}) set (QT4_TEST_LIBRARIES ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY}) plm_add_executable_v2 (qt4_test qt_test.cxx "${QT4_TEST_INCLUDES}" "${QT4_TEST_LIBRARIES}" "" ${BUILD_ALWAYS} ${INSTALL_NEVER}) endif () # Test executable -- ransac plm_add_executable (ransac_test ransac_test.cxx "${PLASTIMATCH_LIBS}" "${GPUIT_EXE_LDFLAGS}" ${BUILD_IF_NOT_SLICER_EXT} ${INSTALL_NEVER}) # Test executable -- rapidjson if (RAPIDJSON_FOUND) plm_add_executable (rapidjson_test rapidjson_test.cxx "${PLASTIMATCH_LIBS}" "${PLASTIMATCH_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) endif () # Test executable -- smart pointers I ## find_package (TR1) plm_add_executable (smartp_test_i smartp_test_i.cxx "${PLASTIMATCH_LIBS}" "${GPUIT_EXE_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) # Test executable -- smart pointers II plm_add_executable (smartp_test_ii smartp_test_ii.cxx "${PLASTIMATCH_LIBS}" "${GPUIT_EXE_LDFLAGS}" ${BUILD_ALWAYS} ${INSTALL_NEVER}) endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/api_test.cxx000066400000000000000000000042611321604176500301350ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "itk_image.h" #include "rt_study.h" template typename T::Pointer make_image (float value) { typename T::Pointer image = T::New(); typename T::IndexType start; typename T::SizeType size; typename T::RegionType region; typename T::PointType origin; typename T::SpacingType sp; typename T::PixelType fill_value = (typename T::PixelType) value; for (int d = 0; d < 3; d++) { start[d] = 0; size[d] = 100; origin[d] = 0; sp[d] = 1; } region.SetSize (size); region.SetIndex (start); image->SetRegions (region); image->SetOrigin (origin); image->SetSpacing (sp); image->Allocate (); image->FillBuffer (fill_value); return image; } int main (int argc, char *argv[]) { /* Make some synthetic data */ ShortImageType::Pointer image = make_image (100); FloatImageType::Pointer dose = make_image (50); UCharImageType::Pointer body = make_image (0); UCharImageType::Pointer tumor = make_image (0); for (unsigned int s = 20; s < 80; s++) { for (unsigned int r = 20; r < 80; r++) { for (unsigned int c = 20; c < 80; c++) { UCharImageType::IndexType idx; idx[0] = s; idx[1] = r; idx[2] = c; body->SetPixel(idx, 1); if (s > 40 && s < 60 && r > 40 && r < 60 && c > 40 && c < 60) { tumor->SetPixel(idx, 1); } } } } /* Add it into the Rt_study structure */ Rt_study::Pointer rt_study = Rt_study::New (); rt_study->set_image (image); rt_study->add_structure (body, "Body", "255\\0\\0"); rt_study->add_structure (tumor); rt_study->set_dose (dose); /* Write dicom output to a directory */ rt_study->save_dicom ("api_test_1"); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cpp_eps_test.cxx000066400000000000000000000014601321604176500310130ustar00rootroot00000000000000#include #include typedef union { long long i64; double d64; } dbl_64; double machine_eps (double value) { dbl_64 s; s.d64 = value; s.i64++; return (s.i64 < 0 ? value - s.d64 : s.d64 - value); } int main (int argc, char* argv[]) { printf ("DBL_EPSILON = %G\n", DBL_EPSILON); printf ("Machine epsilon (alg 1) = %G\n", machine_eps((double)1.0)); double machEps = 1.0f; printf( "current Epsilon, 1 + current Epsilon\n" ); do { printf( "%G\t%.20f\n", machEps, (1.0f + machEps) ); machEps /= 2.0f; // If next epsilon yields 1, then break, because current // epsilon is the machine epsilon. } while ((double)(1.0 + (machEps/2.0)) != 1.0); printf( "Calculated Machine epsilon: %G\n", machEps ); return 0; } cpp_floating_point_test.cxx000066400000000000000000000007621321604176500331650ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test#include #include int main () { float o = -24.34210586547851562500; float s = 2.63158011436462402344; float vo = -25.00000000000000000000; float vs = 1.31579005718231201172; int i; float z; for (i = 0, z = o; i < 2; i++, z += s) { float t = (z - vo) / vs; printf ("0> %.20f\n", t); } printf ("----\n"); for (i = 0, z = o; i < 3; i++, z += s) { float t = (z - vo) / vs; printf ("0> %.20f\n", t); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cpp_limits_test.cxx000066400000000000000000000034771321604176500315370ustar00rootroot00000000000000#include #include //#include "itkNumericTraits.h" int main ( int argc, char* argv[] ) { short min_short = std::numeric_limits::min(); short max_short = std::numeric_limits::max(); unsigned short min_ushort = std::numeric_limits::min(); unsigned short max_ushort = std::numeric_limits::max(); int min_int = std::numeric_limits::min(); int max_int = std::numeric_limits::max(); unsigned int min_uint = std::numeric_limits::min(); unsigned int max_uint = std::numeric_limits::max(); long min_long = std::numeric_limits::min(); long max_long = std::numeric_limits::max(); unsigned long min_ulong = std::numeric_limits::min(); unsigned long max_ulong = std::numeric_limits::max(); float min_float = std::numeric_limits::min(); float max_float = std::numeric_limits::max(); printf ("short %ld %ld\n", (long) min_short, (long) max_short); printf ("ushort %ld %ld\n", (long) min_ushort, (long) max_ushort); printf ("int %d %d\n", min_int, max_int); printf ("uint %u %u\n", min_uint, max_uint); printf ("long %ld %ld\n", min_long, max_long); printf ("ulong %lu %lu\n", min_ulong, max_ulong); printf ("float %e %e\n", min_float, max_float); short ss1 = -33; printf ("%d < %d == %s\n", ss1, min_ushort, (ss1 < min_ushort) ? "true" : "false"); unsigned short us1 = 44000; printf ("%d > %d == %s\n", us1, max_short, (us1 > max_short) ? "true" : "false"); long sl1 = -33; printf ("%ld < %lu == %s\n", sl1, min_ulong, (sl1 < min_ulong) ? "true" : "false"); unsigned long ul1 = max_long + 100; printf ("%lu > %ld == %s\n", ul1, max_long, (ul1 > max_long) ? "true" : "false"); } cpp_overflow_test.cxx000066400000000000000000000014251321604176500320110ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test#include #define VSIZE 900 int main ( int argc, char* argv[] ) { int dim[3] = { VSIZE, VSIZE, VSIZE }; int fudge = 100; int ijk[3]; size_t v; for (ijk[2] = 0; ijk[2] < VSIZE; ijk[2]++) { for (ijk[1] = 0; ijk[1] < VSIZE; ijk[1]++) { for (ijk[0] = 0; ijk[0] < VSIZE; ijk[0]++) { v = ((ijk[2] * dim[1] + ijk[1]) * dim[0] + ijk[0]) * fudge; if (v % (30 * dim[1] * dim[0] * fudge) == 0) { printf ("v = %zu (%zu)\n", v, v / (30 * dim[1] * dim[0] * fudge)); } if (v % (((size_t) 30) * dim[1] * dim[0] * fudge) == 0) { printf ("v = %zu (%zu)\n", v, v / (((size_t) 30) * dim[1] * dim[0] * fudge)); } } } } printf ("pct = %zu\n", (30 * dim[1] * dim[0] * fudge)); printf ("v = %zu\n", v); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cpp_sizeof_test.cxx000066400000000000000000000010711321604176500315210ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include int main (int argc, char *argv[]) { printf ("sizeof(int) = %d\n", sizeof(int)); printf ("sizeof(long) = %d\n", sizeof(long)); printf ("sizeof(void*) = %d\n", sizeof(void*)); printf ("sizeof(size_t) = %d\n", sizeof(size_t)); return 0; } cpp_template_test.cxx000066400000000000000000000030451321604176500317610ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test#include #include #include /* Simple test */ typedef void (*B) (int); void c (int x) { printf ("x = %d\n", x); } template void a (int x) { b(x); } /* More complex */ #if defined (commentout) /* This is illegal, typedef's can't be templated */ typedef template void (*E) (F); void g (int x) { printf ("x = %d\n", x); } #endif template class G { public: static void g (F x) { printf ("x = %d\n", x); } }; template < class G > void d (int x) { G::g (x); } /* Even more complex */ #if defined (commentout) /* This doesn't compile on gcc 6.3 */ template < class J, template class I> void h (J x) { I::g (x); } #endif template < template class I, class J > void k (J x) { I::g (x); } #if defined (commentout) /* This doesn't seem to work */ template < template class I > void l (J x) { I::g (x); } #endif /* This is an example inheriting from std::map */ /* Cf. http://stackoverflow.com/questions/10477839/c-inheriting-from-stdmap (The answer from Emilio Garavaglia, not the others) */ template class M : public std::map { public: typename std::map::iterator get_default (std::string s) { return this->begin(); } }; int main ( int argc, char* argv[] ) { int x = 1; a(x); G::g (x); d< G >(x); #if defined (commentout) h< int, G >(x); #endif k< G, int >(x); M m; M::iterator mit = m.get_default("FOO"); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cuda/000077500000000000000000000000001321604176500265125ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cuda/CMakeLists.txt000066400000000000000000000013671321604176500312610ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_test_cuda) set_directory_properties (PROPERTIES INCLUDE_DIRECTORIES "") set_directory_properties (PROPERTIES COMPILE_DEFINITIONS "") # Test executable -- cuda if (CUDA_FOUND) cuda_compile (CUDA_TEST_WRAPPERS cuda_test.cu) plm_add_executable (cuda_test "${CUDA_TEST_WRAPPERS}" "${CUDA_LIBRARIES}" "" ${BUILD_ALWAYS} ${INSTALL_NEVER}) set_target_properties (cuda_test PROPERTIES LINKER_LANGUAGE CXX) # Test executable -- cuda_tex_test add_subdirectory (CUDA_tex_test) endif () plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cuda/CUDA_tex_test/000077500000000000000000000000001321604176500311455ustar00rootroot00000000000000CMakeLists.txt000077500000000000000000000011271321604176500336320ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cuda/CUDA_tex_test##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (CUDA_tex_test) if (CUDA_FOUND) cuda_compile (CUDA_TEX_TEST_WRAPPERS tex_kernels.cu tex_stubs.cu) set (CUDA_TEX_TEST_SRC ${CUDA_TEX_TEST_WRAPPERS} tex_kernels.h tex_stubs.h textures.c ) plm_add_executable (cuda_tex_test "${CUDA_TEX_TEST_SRC}" "${CUDA_LIBRARIES}" "" ${BUILD_ALWAYS} ${INSTALL_NEVER}) endif () tex_kernels.cu000066400000000000000000000031141321604176500337410ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cuda/CUDA_tex_test#include "tex_kernels.h" __global__ void kernel_texture(float* dev_return, int test_size) { // -- Setup Thread Attributes ----------------------------- int blockIdxInGrid = (gridDim.x * blockIdx.y) + blockIdx.x; int threadsPerBlock = (blockDim.x * blockDim.y * blockDim.z); int threadIdxInBlock = (blockDim.x * blockDim.y * threadIdx.z) + (blockDim.x * threadIdx.y) + threadIdx.x; int threadIdxInGrid = (blockIdxInGrid * threadsPerBlock) + threadIdxInBlock; // -------------------------------------------------------- // Return excess threads if ( threadIdxInGrid > (test_size/sizeof(float)) ) return; // Read element from texture, increment it, and then // place it into the return array. dev_return[threadIdxInGrid] = tex1Dfetch(tex_test, threadIdxInGrid) + 1.0; } __global__ void kernel_no_texture(float* dev_test_data, float* dev_return, int test_size) { // -- Setup Thread Attributes ----------------------------- int blockIdxInGrid = (gridDim.x * blockIdx.y) + blockIdx.x; int threadsPerBlock = (blockDim.x * blockDim.y * blockDim.z); int threadIdxInBlock = (blockDim.x * blockDim.y * threadIdx.z) + (blockDim.x * threadIdx.y) + threadIdx.x; int threadIdxInGrid = (blockIdxInGrid * threadsPerBlock) + threadIdxInBlock; // -------------------------------------------------------- // Return excess threads if ( threadIdxInGrid > (test_size/sizeof(float)) ) return; // Read element from texture, increment it, and then // place it into the return array. dev_return[threadIdxInGrid] = dev_test_data[threadIdxInGrid] + 1.0; } tex_kernels.h000066400000000000000000000004271321604176500335650ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cuda/CUDA_tex_test#ifndef _tex_kernels_h_ #define _tex_kernels_h_ __global__ void kernel_texture(float* dev_return, int test_size); __global__ void kernel_no_texture(float* dev_test_data, float* dev_return, int test_size); texture tex_test; #endif tex_stubs.cu000066400000000000000000000035321321604176500334420ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cuda/CUDA_tex_test#include #include "tex_stubs.h" #include "tex_kernels.h" extern "C" void CUDA_texture_test(float* test_data, int elements) { float* dev_test_data; float* dev_return; size_t test_size = elements * sizeof(float); // Allocate some global memory on the GPU cudaMalloc((void**)&dev_test_data, test_size); checkCUDAError("cudaMalloc(): dev_test_data"); cudaMalloc((void**)&dev_return, test_size); checkCUDAError("cudaMalloc(): dev_return"); // Copy test data to GPU global memory cudaMemcpy(dev_test_data, test_data, test_size, cudaMemcpyHostToDevice); checkCUDAError("cudaMemcpy(): test_data -> dev_test_data"); cudaMemset(dev_return, 0, test_size); checkCUDAError("cudaMemset(): dev_return"); memset(test_data, 0, test_size); // Bind allocated global memory to texture reference cudaBindTexture(0, tex_test, dev_test_data, test_size); checkCUDAError("cudaBindTexture(): dev_test_data -> tex_test"); // Define the execution configuration int threads_per_block = 128; int num_threads = elements; int num_blocks = (int)ceil(num_threads / (float)threads_per_block); dim3 dimGrid(num_blocks, 1, 1); dim3 dimBlock(threads_per_block, 1, 1); // Invoke the kernel kernel_texture<<>>(dev_return, test_size); checkCUDAError("Kernel Panic!"); // Copy results back cudaMemcpy(test_data, dev_return, test_size, cudaMemcpyDeviceToHost); checkCUDAError("cudaMemcpy(): dev_return -> test_data"); // Cleanup cudaUnbindTexture(tex_test); cudaFree(dev_test_data); cudaFree(dev_return); } extern "C" void checkCUDAError(const char *msg) { cudaError_t err = cudaGetLastError(); if( cudaSuccess != err) { fprintf(stderr, "\n\nCUDA ERROR: %s (%s).\n", msg, cudaGetErrorString( err) ); exit(EXIT_FAILURE); } } tex_stubs.h000066400000000000000000000003651321604176500332630ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cuda/CUDA_tex_test#ifndef _tex_stubs_h_ #define _tex_stubs_h_ #if defined __cplusplus extern "C" { #endif void CUDA_texture_test(float* test_data, int elements); void checkCUDAError(const char *msg); #if defined __cplusplus } #endif #endif textures.c000066400000000000000000000007301321604176500331150ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cuda/CUDA_tex_test#include #include #include "tex_stubs.h" int main() { int elements = 100; float* test_data = (float*)malloc(elements*sizeof(float)); // Generate some work int i; for (i = 0; i < elements; i++) test_data[i] = (float)i; // Invoke the texture kernel CUDA_texture_test(test_data, elements); // Print results for (i = 0; i < elements; i++) printf("%f\n", test_data[i]); free(test_data); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/cuda/cuda_test.cu000066400000000000000000000074161321604176500310260ustar00rootroot00000000000000#include #include // Simple utility function to check for CUDA runtime errors void checkCUDAError (const char *msg); class A { public: int a; float b; public: int get_a (); void set_a (int val); }; int A::get_a () { return this->a; } void A::set_a (int val) { this->a = val; } // Part 3 of 5: implement the kernel __global__ void myFirstKernel(int *d_a) { int idx = blockIdx.x * blockDim.x + threadIdx.x; d_a[idx] = idx; } __global__ void reduce(float *idata, float *odata) { extern __shared__ float sdata[]; unsigned int tid = threadIdx.x; unsigned int i = blockIdx.x * blockDim.x + threadIdx.x; sdata[tid] = idata[i]; __syncthreads(); for(unsigned int s = blockDim.x / 2; s > 0; s >>= 1) { if(tid < s) { sdata[tid] += sdata[tid + s]; } __syncthreads(); } if(tid == 0) { odata[blockIdx.x] = sdata[0]; } } int cuda_test_1 (int argc, char** argv) { // pointer for host memory int *h_a; // pointer for device memory int *d_a; // define grid and block size int numBlocks = 8; int numThreadsPerBlock = 8; // Part 1 of 5: allocate host and device memory size_t memSize = numBlocks * numThreadsPerBlock * sizeof(int); h_a = (int *) malloc(memSize); cudaMalloc((void **) &d_a, memSize); checkCUDAError("cudaMalloc"); // Part 2 of 5: launch kernel dim3 dimGrid(numBlocks, 1, 1); dim3 dimBlock(numThreadsPerBlock, 1, 1); myFirstKernel<<>>(d_a); // block until the device has completed cudaThreadSynchronize(); // check if kernel execution generated an error checkCUDAError("kernel execution"); // Part 4 of 5: device to host copy cudaMemcpy( h_a, d_a, memSize, cudaMemcpyDeviceToHost ); // Check for any CUDA errors checkCUDAError("cudaMemcpy"); // Part 5 of 5: verify the data returned to the host is correct for (int i = 0; i < numBlocks; i++) { for (int j = 0; j < numThreadsPerBlock; j++) { assert (h_a[i * numThreadsPerBlock + j] == i * numThreadsPerBlock + j); } } // free device memory cudaFree(d_a); // free host memory free(h_a); // If the program makes it this far, then the results are correct and // there are no run-time errors. Good work! printf("Correct!\n"); return 0; } void checkCUDAError (const char *msg) { cudaError_t err = cudaGetLastError(); if (cudaSuccess != err) { fprintf (stderr, "Cuda error: %s: %s.\n", msg, cudaGetErrorString (err)); exit(-1); } } int cuda_mem_test (int argc, char** argv) { void *test[4]; int alloc_mb; const int MB = (1024*1024); //for (alloc_mb = 1024; alloc_mb <= 1024*1024*1024; alloc_mb *= 2) { for (alloc_mb = 100; alloc_mb <= 1100; alloc_mb += 100) { printf ("Alloc = 4 x %d MB = %d MB\n", alloc_mb, 4*alloc_mb); cudaMalloc ((void**) &test[0], alloc_mb * MB); checkCUDAError ("cudaMalloc[0]"); cudaMalloc ((void**) &test[1], alloc_mb * MB); checkCUDAError ("cudaMalloc[1]"); cudaMalloc ((void**) &test[2], alloc_mb * MB); checkCUDAError ("cudaMalloc[2]"); cudaMalloc ((void**) &test[3], alloc_mb * MB); checkCUDAError ("cudaMalloc[3]"); cudaFree (test[0]); checkCUDAError ("cudaFree"); cudaFree (test[1]); checkCUDAError ("cudaFree"); cudaFree (test[2]); checkCUDAError ("cudaFree"); cudaFree (test[3]); checkCUDAError ("cudaFree"); } return 0; } int main (int argc, char** argv) { // do some c++ here A a1; a1.set_a (32); printf ("C++ test: %d\n", a1.get_a()); // cuda_test_1 (argc, argv); return cuda_mem_test (argc, argv); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/dcmtk_test.cxx000066400000000000000000000023141321604176500304630ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "compiler_warnings.h" #include "dcmtk_rt_study.h" #if defined (GCS_FIX) void dcmtk_series_set_test (char *dicom_dir) { Dcmtk_rt_study drs; printf ("Searching directory: %s\n", dicom_dir); drs.insert_directory (dicom_dir); drs.sort_all (); //drs.debug (); Rt_study rtds; drs.load_rtds (&rtds); if (rtds.m_img) { rtds.m_img->save_image ("img.mha"); } if (rtds.m_rtss) { printf ("Trying to save ss.cxt\n"); rtds.m_rtss->save_cxt (0, Pstring("ss.cxt"), false); } if (rtds.m_dose) { rtds.m_dose->save_image ("dose.mha"); } } #endif int main (int argc, char *argv[]) { char *dicom_dir; UNUSED_VARIABLE (dicom_dir); if (argc == 2) { dicom_dir = argv[1]; } else { printf ("Usage: dcmtk_test dicom_dir\n"); exit (1); } #if defined (GCS_FIX) dcmtk_series_set_test (dicom_dir); #endif return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/dlib_test.cxx000066400000000000000000000046171321604176500303030ustar00rootroot00000000000000#include "plm_clp.h" static void print_usage (dlib::Plm_clp& parser) { std::cout << "Usage: dlib_test [options] --in input_file [file ...]\n"; parser.print_options (std::cout); std::cout << std::endl; } static void parse_args (dlib::Plm_clp& parser, int argc, char* argv[]) { try { // Algorithm-independent options parser.add_long_option ("a","algorithm", "Choose the learning algorithm: {krls,krr,mlp,svr}. " "Choose the learning algorithm: {krls,krr,mlp,svr}. " "Choose the learning algorithm: {krls,krr,mlp,svr}. ", 1,"Foob"); parser.add_long_option ("b","","The 'b' option",1); parser.add_long_option ("h","help","Display this help message."); parser.add_long_option ("k","kernel", "Learning kernel (for krls,krr,svr methods): {lin,rbk}.",1); parser.add_long_option ("","in","A libsvm-formatted file to test.",1); parser.add_long_option ("","normalize", "Normalize the sample inputs to zero-mean unit variance?"); parser.add_long_option ("","train-best", "Train and save a network using best parameters", 1); parser.add_long_option ("", "verbose", "Use verbose trainers"); parser.add_long_option ("c","cool-option", "The 'c/cool' option",1,"default-c-value"); // Parse the command line arguments parser.parse(argc,argv); // Check that options aren't given multiple times const char* one_time_opts[] = {"a", "h", "help", "in"}; parser.check_one_time_options(one_time_opts); // Check if the -h option was given if (parser.option("h") || parser.option("help")) { print_usage (parser); exit (0); } // Check that an input file was given if (!parser.option("in")) { std::cout << "Error. " "You must specify an input file with the --in option.\n"; print_usage (parser); exit (0); } } catch (std::exception& e) { // Catch cmd_line_parse_error exceptions and print usage message. std::cout << "Error. " << e.what() << std::endl; print_usage (parser); exit (1); } catch (...) { std::cout << "Some error occurred" << std::endl; } for (unsigned int i =0; i < parser.number_of_arguments(); ++i) { std::cout << "unlabeled option " << i << " is " << parser[i] << std::endl; } } int main (int argc, char* argv[]) { dlib::Plm_clp parser; parse_args(parser, argc, argv); } dlib_thread_test.cxx000066400000000000000000000023571321604176500315520ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test#include #include "dlib_threads.h" #if _WIN32 #include #define plm_sleep(x) Sleep(x) #else #include #define plm_sleep(x) usleep(1000*x) #endif bool time_to_die = false; void thread_func (void* param) { Dlib_master_slave *s = (Dlib_master_slave *) param; while (1) { s->slave_grab_resource (); plm_sleep (300); printf ("Child execute\n"); if (time_to_die) { break; } s->slave_release_resource (); } } int main () { Dlib_master_slave s; Dlib_thread_function tf (thread_func, &s); /* Parent and child execute simultaneously */ for (int i = 0; i < 3; i++) { plm_sleep (770); printf ("Parent execute\n"); } /* Only parent executes */ printf ("Parent tries to grab...\n"); s.master_grab_resource (); printf (">>> Parent only\n"); for (int i = 0; i < 15; i++) { plm_sleep (70); printf ("Parent execute\n"); } printf (">>> End parent only\n"); s.master_release_resource (); /* Parent and child execute simultaneously */ for (int i = 0; i < 3; i++) { plm_sleep (770); printf ("Parent execute\n"); } time_to_die = true; return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/gabor_test.cxx000066400000000000000000000015771321604176500304650ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include "gabor.h" int main (int argc, char *argv[]) { #if defined (commentout) if (argc != 2) { printf ("Usage: gabor_test image\n"); exit (-1); } FloatImageType::Pointer image = itk_image_load_float (argv[1], 0); #endif #if defined (commentout) /* Anti-functional itk gabor program */ plm_long dim[3] = { 11, 11, 11 }; float origin[3] = { -2.5, -2.5, -2.5 }; float spacing[3] = { .5, .5, .5 }; Plm_image_header pih (dim, origin, spacing); FloatImageType::Pointer g_img = itk_gabor_create (&pih); itk_image_save (g_img, "tmp.mha"); #endif return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/itk_test.cxx000066400000000000000000000055631321604176500301610ustar00rootroot00000000000000#include #include #include "itkCastImageFilter.h" #include "itkImageFileWriter.h" #include "file_util.h" #include "itk_metadata.h" #include "itk_image_save.h" #include "logfile.h" #include "path_util.h" #include "plm_image.h" #include "rt_study_metadata.h" #include "string_util.h" typedef itk::Image < float, 3 > FloatImageType; typedef itk::Image < unsigned char, 3 > UCharImageType; template void my_itk_image_save (T image, const char* fname) { typedef typename T::ObjectType ImageType; typedef itk::ImageFileWriter< ImageType > WriterType; logfile_printf ("Trying to write image to %s\n", fname); // printf ("Hello!\n"); typename WriterType::Pointer writer = WriterType::New(); writer->SetInput (image); writer->SetFileName (fname); make_parent_directories (fname); // printf ("Maybe gonna update...\n"); if (extension_is (fname, "nrrd")) { writer->SetUseCompression (true); } try { writer->Update(); } catch (itk::ExceptionObject& excp) { printf ("ITK exception writing image file.\n"); std::cout << excp << std::endl; } // printf ("Done ??\n"); } int main ( int argc, char* argv[] ) { FloatImageType::Pointer image = FloatImageType::New(); FloatImageType::RegionType rg; FloatImageType::IndexType start; FloatImageType::SizeType size; size[0] = 200; // size along X size[1] = 200; // size along Y size[2] = 200; // size along Z start[0] = 0; // first index on X start[1] = 0; // first index on Y start[2] = 0; // first index on Z FloatImageType::RegionType region; region.SetSize( size ); region.SetIndex( start ); image->SetRegions( region ); image->Allocate(); FloatImageType::PixelType initialValue = 0; image->FillBuffer( initialValue ); typedef itk::CastImageFilter < FloatImageType, UCharImageType > ClampCastFilterType; ClampCastFilterType::Pointer caster = ClampCastFilterType::New(); caster->SetInput(image); try { caster->Update(); } catch (itk::ExceptionObject & ex) { printf ("ITK exception in ClampCastFilter.\n"); std::cout << ex << std::endl; exit(1); } UCharImageType::Pointer tmp = caster->GetOutput(); // std::cout << tmp; // itk_image_save (image, "foo.mha"); // itk_image_save (tmp, "foo.mha"); // itk_image_save_float (tmp, "foo.mha"); // my_itk_image_save (tmp, "foo.mha"); itk::MetaDataDictionary& dict = tmp->GetMetaDataDictionary(); itk_metadata_set (&dict, "Hello", "World"); itk_image_save (tmp, "img_with_meta.nrrd"); itk_image_save (tmp, "img_with_meta.mha"); itk_image_save (tmp, "img_with_meta.hd5"); Plm_image::Pointer pli = Plm_image::New (image); Rt_study_metadata rsm; rsm.set_patient_name ("Hello^World"); rsm.set_patient_id ("ANON^Hello"); pli->save_short_dicom ("itk_dicom", &rsm); } itk_test_directions.cxx000066400000000000000000000050211321604176500323120ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test#include #include #include "itkCastImageFilter.h" #include "itkImageFileWriter.h" #include "file_util.h" #include "itk_image_save.h" #include "logfile.h" #include "path_util.h" #include "plm_image.h" #include "rt_study.h" #include "string_util.h" #include "volume.h" typedef itk::Image < float, 3 > FloatImageType; int main ( int argc, char* argv[] ) { FloatImageType::Pointer image = FloatImageType::New(); FloatImageType::RegionType rg; FloatImageType::SizeType size; FloatImageType::PointType og; FloatImageType::SpacingType sp; FloatImageType::DirectionType itk_dc; size[0] = 2; size[1] = 2; size[2] = 2; og[0] = 0; og[1] = 0; og[2] = 0; sp[0] = 1; sp[1] = 10; sp[2] = 100; itk_dc[0][0] = 1; itk_dc[0][1] = 0; itk_dc[0][2] = 0; itk_dc[1][0] = 0; itk_dc[1][1] = .7071; itk_dc[1][2] = -.7071; itk_dc[2][0] = 0; itk_dc[2][1] = .7071; itk_dc[2][2] = .7071; FloatImageType::RegionType region; region.SetSize (size); image->SetRegions (region); image->SetOrigin (og); image->SetSpacing (sp); image->SetDirection (itk_dc); image->Allocate(); FloatImageType::PixelType initialValue = 0; image->FillBuffer( initialValue ); typedef itk::ImageRegionIteratorWithIndex< FloatImageType > IteratorType; IteratorType it (image, image->GetLargestPossibleRegion()); for (it.GoToBegin(); !it.IsAtEnd(); ++it) { FloatImageType::IndexType idx = it.GetIndex (); FloatPoint3DType phys; image->TransformIndexToPhysicalPoint (idx, phys); std::cout << idx << " " << phys << "\n"; } Plm_image::Pointer pli = Plm_image::New (image); Volume::Pointer v = pli->get_volume_float(); plm_long ijk[3]; float proj_ijk[3]; float xyz[3]; LOOP_Z (ijk, xyz, v) { LOOP_Y (ijk, xyz, v) { LOOP_X (ijk, xyz, v) { proj_ijk[0] = PROJECT_X (xyz, v->proj); proj_ijk[1] = PROJECT_Y (xyz, v->proj); proj_ijk[2] = PROJECT_Z (xyz, v->proj); printf ("[%d %d %d] %f %f %f -> [%f %f %f]\n", (int) ijk[0], (int) ijk[1], (int) ijk[2], xyz[0], xyz[1], xyz[2], proj_ijk[0], proj_ijk[1], proj_ijk[2]); } } } pli->save_image ("itk_test_directions.mha"); pli->save_image ("itk_test_directions.nrrd"); Rt_study rt; rt.set_image (pli); rt.save_dicom ("itk_test_directions_dicom"); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/itk_thread_test.cxx000066400000000000000000000043711321604176500315040ustar00rootroot00000000000000#include #include "itkConditionVariable.h" #include "itkMultiThreader.h" #include "itkMutexLock.h" #if _WIN32 #include #define plm_sleep(x) Sleep(x) #else #include #define plm_sleep(x) usleep(1000*x) #endif class Thread_struct { public: itk::SimpleMutexLock mutex; itk::ConditionVariable::Pointer condition; bool semaphore_available; bool die; public: Thread_struct () { this->condition = itk::ConditionVariable::New(); this->die = false; this->semaphore_available = true; } ~Thread_struct () { } void release_semaphore () { this->mutex.Lock(); this->semaphore_available = true; this->mutex.Unlock(); this->condition->Signal (); } void grab_semaphore () { this->mutex.Lock(); while (this->semaphore_available == false) { this->condition->Wait (&mutex); } this->semaphore_available = false; this->mutex.Unlock(); } }; ITK_THREAD_RETURN_TYPE thread_func (void* param) { itk::MultiThreader::ThreadInfoStruct *info = (itk::MultiThreader::ThreadInfoStruct*) param; Thread_struct* ts = (Thread_struct*) info->UserData; while (1) { ts->grab_semaphore (); plm_sleep (300); printf ("Child execute\n"); ts->release_semaphore (); if (ts->die) { break; } } return ITK_THREAD_RETURN_VALUE; } int main () { Thread_struct ts; itk::MultiThreader::Pointer threader = itk::MultiThreader::New(); int thread_no = threader->SpawnThread (thread_func, (void*) &ts); /* Parent and child execute simultaneously */ for (int i = 0; i < 3; i++) { plm_sleep (770); printf ("Parent execute\n"); } /* Only parent executes */ ts.grab_semaphore (); printf (">>> Parent only\n"); for (int i = 0; i < 15; i++) { plm_sleep (70); printf ("Parent execute\n"); } printf (">>> End parent only\n"); ts.release_semaphore (); /* Parent and child execute simultaneously */ for (int i = 0; i < 3; i++) { plm_sleep (770); printf ("Parent execute\n"); } ts.die = true; threader->TerminateThread (thread_no); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/libyaml_test.cxx000066400000000000000000000026501321604176500310150ustar00rootroot00000000000000#include #include "yaml.h" int main () { yaml_parser_t parser; yaml_event_t event; int done = 0; /* Create the Parser object. */ yaml_parser_initialize(&parser); /* Set a string input. */ const char *input = "..."; size_t length = strlen(input); yaml_parser_set_input_string(&parser, (const unsigned char*) input, length); /* Set a file input. */ FILE *fp = fopen("...", "rb"); yaml_parser_set_input_file(&parser, fp); /* Set a generic reader. */ #if defined (commentout) void *ext = ...; int read_handler(void *ext, char *buffer, int size, int *length) { /* ... */ *buffer = ...; *length = ...; /* ... */ return error ? 0 : 1; } yaml_parser_set_input(&parser, read_handler, ext); #endif /* Read the event sequence. */ while (!done) { /* Get the next event. */ if (!yaml_parser_parse(&parser, &event)) goto error; /* ... Process the event. ... */ /* Are we finished? */ done = (event.type == YAML_STREAM_END_EVENT); /* The application is responsible for destroying the event object. */ yaml_event_delete(&event); } /* Destroy the Parser object. */ yaml_parser_delete(&parser); return 1; /* On error. */ error: /* Destroy the Parser object. */ yaml_parser_delete(&parser); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/mex_test.c000077500000000000000000000003561321604176500276010ustar00rootroot00000000000000#include "mex.h" void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { mxArray *v = mxCreateDoubleMatrix (1, 1, mxREAL); double *data = mxGetPr (v); *data = 1.23456789; plhs[0] = v; } nelder_mead_test.cxx000066400000000000000000000027111321604176500315420ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include "vnl/algo/vnl_amoeba.h" #include "vnl/vnl_cost_function.h" /* Rosenbrock function */ double myfunc (const double *x) { double value = (1 - x[0])*(1 - x[0]) + 100 * (x[1] - x[0]*x[0]) * (x[1] - x[0]*x[0]); printf ("%g %g -> %g\n", x[0], x[1], value); return value; } /* vxl needs you to wrap the function within a class */ class Rosenbrock_function : public vnl_cost_function { public: virtual double f (vnl_vector const& vnl_x) { /* vxl requires you using their own vnl_vector type, therefore we copy into a standard C/C++ array. */ double x[2]; x[0] = vnl_x[0]; x[1] = vnl_x[1]; return myfunc(x); } }; int main (int argc, char* argv[]) { /* Create function object (for function to be minimized) */ Rosenbrock_function rb; /* Create optimizer object */ vnl_amoeba nm (rb); /* Set some optimizer parameters */ nm.set_x_tolerance (0.00001); nm.set_f_tolerance (0.00001); nm.set_max_iterations (100); /* Set the starting point */ vnl_vector x(2); x[0] = 0; x[1] = 0; /* Run the optimizer */ nm.minimize (x); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/nlopt_test.c000066400000000000000000000027551321604176500301460ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include "nlopt.h" typedef struct { double a, b; } my_constraint_data; double myfunc (int n, const double *x, double *grad, void *my_func_data) { if (grad) { grad[0] = 0.0; grad[1] = 0.5 / sqrt(x[1]); } return sqrt(x[1]); } double myconstraint(int n, const double *x, double *grad, void *data) { my_constraint_data *d = (my_constraint_data *) data; double a = d->a, b = d->b; if (grad) { grad[0] = 3 * a * (a*x[0] + b) * (a*x[0] + b); grad[1] = -1.0; } return ((a*x[0] + b) * (a*x[0] + b) * (a*x[0] + b) - x[1]); } int main (int argc, char* argv[]) { my_constraint_data data[2] = { {2,0}, {-1,1} }; double x[2] = { 1.234, 5.678 }; /* some initial guess */ double lb[2] = { -HUGE_VAL, 0 }, ub[2] = { HUGE_VAL, HUGE_VAL }; /* lower and upper bounds */ double minf; /* the minimum objective value, upon return */ if (nlopt_minimize_constrained(NLOPT_LD_MMA, 2, myfunc, NULL, 2, myconstraint, data, sizeof(my_constraint_data), lb, ub, x, &minf, -HUGE_VAL, 0.0, 0.0, 1e-4, NULL, 0, 0.0) < 0) { printf("nlopt failed!\n"); } else { printf("found minimum at f(%g,%g) = %g\n", x[0], x[1], minf); } return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/openmp_test.cxx000066400000000000000000000043041321604176500306600ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #if (OPENMP_FOUND) #include #endif #include "plm_timer.h" #define LOOP1 2000 #define LOOP2 20000 void initialize_vector (double input[LOOP1]) { int i; for (i = 0; i < LOOP1; i++) { input[i] = sqrt ((double) i); } } #if (OPENMP_FOUND) void display_num_threads (void) { int nthreads, tid; #pragma omp parallel private(tid) { /* Obtain and print thread id */ tid = omp_get_thread_num(); //printf("Hello World from thread = %d\n", tid); /* Only master thread does this */ if (tid == 0) { nthreads = omp_get_num_threads(); printf("Number of threads = %d\n", nthreads); } } /* All threads join master thread and terminate */ } void speedtest_openmp_1 (double output[LOOP1], double input[LOOP1]) { int i; #pragma omp parallel for for (i = 0; i < LOOP1; i++) { int j; double d1 = input[i]; double d2 = 1.0; for (j = 0; j < LOOP2; j++) { d1 += 0.872013; d2 *= d1; if (d2 > 1.0) { d2 -= floor(d2); } } output[i] = d2; } } void speedtest_openmp_2 (double output[LOOP1], double input[LOOP1]) { int i; for (i = 0; i < LOOP1; i++) { int j; double d1 = input[i]; double d2 = 1.0; for (j = 0; j < LOOP2; j++) { d1 += 0.872013; d2 *= d1; if (d2 > 1.0) { d2 -= floor(d2); } } output[i] = d2; } } #endif /* OPENMP_FOUND */ int main (int argc, char* argv[]) { Plm_timer* timer = new Plm_timer; double input[LOOP1], output[LOOP1]; #if (OPENMP_FOUND) display_num_threads (); initialize_vector (input); timer->start (); speedtest_openmp_1 (output, input); printf ("Time [openmp] = %f seconds\n", timer->report ()); initialize_vector (input); timer->start (); speedtest_openmp_2 (output, input); printf ("Time [serial] = %f seconds\n", timer->report ()); delete timer; #else printf ("Sorry, openmp was not supported by your compiler\n"); #endif return 0; } plm_restart_test.cxx000066400000000000000000000040071321604176500316370ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test#include #include "plm_sleep.h" #include "registration.h" #include "rt_study.h" #include "synthetic_mha.h" int main () { Registration r; std::string s = "[GLOBAL]\n" #if defined (commentout) "fixed=c:/tmp/fixed.mha\n" "moving=c:/tmp/moving.mha\n" "fixed=/home/gcs6/tmp/fixed_1.mha\n" "moving=/home/gcs6/tmp/moving.mha\n" #endif "fixed=/home/gcs6/tmp/fixed.mha\n" "moving=/home/gcs6/tmp/moving_1.mha\n" "[STAGE]\n" "xform=bspline\n" "max_its=1\n" "flavor=c\n" #if defined (commentout) "max_its=100\n" #endif "[STAGE]\n" ; r.set_command_string (s); Plm_image::Pointer fixed; float origin[3]; for (int i = 0; i < 3; i++) origin[i] = -245.5; /* Fast */ for (int i = 0; i < 3; i++) origin[i] = 0; /* Slow */ { Rt_study rtds; Synthetic_mha_parms sm_parms; sm_parms.pattern = PATTERN_RECT; for (int i = 0; i < 3; i++) {sm_parms.origin[i] = origin[i];} synthetic_mha (&rtds, &sm_parms); fixed = rtds.get_image(); } Plm_image::Pointer moving; { Rt_study rtds; Synthetic_mha_parms sm_parms; sm_parms.pattern = PATTERN_SPHERE; for (int i = 0; i < 3; i++) {sm_parms.origin[i] = origin[i];} synthetic_mha (&rtds, &sm_parms); moving = rtds.get_image(); } // fixed->save_image ("/home/gcs6/tmp/fixed_1.mha"); // moving->save_image ("/home/gcs6/tmp/moving_1.mha"); #if defined (commentout) r.load_global_inputs (); #endif r.set_fixed_image (fixed); r.set_moving_image (moving); printf ("Calling start_registration\n"); #if defined (commentout) r.start_registration (); plm_sleep (1000); printf (">>> PAUSE\n"); r.pause_registration (); printf (">>> PAUSE RETURNED\n"); plm_sleep (3000); printf (">>> PAUSE COMPLETE\n"); r.resume_registration (); r.wait_for_complete (); #endif #if defined (commentout) r.do_registration_pure_old (); #endif return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/qt_test.cxx000066400000000000000000000022611321604176500300060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK (5,0,0) #include #endif int main (int argc, char **argv) { // Display designer path QStringList paths = QCoreApplication::libraryPaths(); for (QStringList::iterator it = paths.begin(); it!=paths.end(); it++) { std::cout << "Looking for plugins at path: " << it->toStdString() << std::endl; } QApplication app(argc, argv); QLabel *label = new QLabel("Hello World!"); label->show(); qDebug() << "Qt version is " << qVersion(); #if QT_VERSION >= QT_VERSION_CHECK (5,4,0) qDebug() << "Qt was built with SSL " << QSslSocket::sslLibraryBuildVersionString(); #endif #if QT_VERSION >= QT_VERSION_CHECK (5,0,0) qDebug() << "Qt is linked with SSL " << QSslSocket::sslLibraryVersionString(); #endif return app.exec(); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/ransac_test.cxx000066400000000000000000000050221321604176500306270ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include "RANSAC.h" #include "PlaneParametersEstimator.h" #include "RandomNumberGenerator.h" #include "autolabel_ransac_est.h" #include "itk_point.h" #include "print_and_exit.h" void load_data ( Autolabel_point_vector& data, const char* filename ) { std::ifstream is (filename); std::string line; Autolabel_point datum; while (std::getline (is, line)) { float x, y; int rc = sscanf (line.c_str(), "%f %f", &x, &y); if (rc != 2) { print_and_exit ("Error parsing file %s for read\n", filename); } datum[0] = x; datum[1] = y; data.push_back (datum); } } int main (int argc, char *argv[]) { typedef itk::RANSAC< Autolabel_point, double> RANSACType; if (argc != 3) { printf ("Usage: ransac_test infile outfile\n"); exit (0); } Autolabel_point_vector data; load_data (data, argv[1]); std::vector planeParameters; itk::Autolabel_ransac_est::Pointer planeEstimator = itk::Autolabel_ransac_est::New(); planeEstimator->SetDelta (0.5); //create and initialize the RANSAC algorithm double desiredProbabilityForNoOutliers = 0.999; double percentageOfDataUsed; RANSACType::Pointer ransacEstimator = RANSACType::New(); ransacEstimator->SetData( data ); ransacEstimator->SetParametersEstimator( planeEstimator.GetPointer() ); percentageOfDataUsed = ransacEstimator->Compute ( planeParameters, desiredProbabilityForNoOutliers); if (planeParameters.empty()) { std::cout<<"RANSAC estimate failed, degenerate configuration?\n"; } else { printf ("RANSAC parameters: [s,i] = [%f,%f]\n", planeParameters[0], planeParameters[1]); printf ("Used %f percent of data.\n", percentageOfDataUsed); } // Dump output FILE *fp = fopen (argv[2], "w"); Autolabel_point_vector::iterator it; double slope = planeParameters[0]; double intercept = planeParameters[1]; for (it = data.begin(); it != data.end(); it++) { double x = (*it)[0]; double y = (*it)[1]; double ry = intercept + slope * x; fprintf (fp, "%f,%f,%f\n", x, y, ry); } std::cout << std::endl; fclose (fp); return EXIT_SUCCESS; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/rapidjson_test.cxx000066400000000000000000000012011321604176500313440ustar00rootroot00000000000000#include #include #include "rapidjson/document.h" #include "rapidjson/writer.h" #include "rapidjson/stringbuffer.h" using namespace rapidjson; int main() { // 1. Parse a JSON string into DOM. const char* json = "{\"project\":\"rapidjson\",\"stars\":10}"; Document d; d.Parse(json); // 2. Modify it by DOM. Value& s = d["stars"]; s.SetInt(s.GetInt() + 1); // 3. Stringify the DOM StringBuffer buffer; Writer writer(buffer); d.Accept(writer); // Output {"project":"rapidjson","stars":11} std::cout << buffer.GetString() << std::endl; return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/rtplan_test.cxx000066400000000000000000000066701321604176500306720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include "compiler_warnings.h" #include "dcmtk_rt_study.h" #include "rtplan.h" #include "rtplan_beam.h" #include "rtplan_control_pt.h" #include "string_util.h" int main (int argc, char *argv[]) { char *dicom_dir; UNUSED_VARIABLE (dicom_dir); if (argc == 2) { dicom_dir = argv[1]; } else { printf ("Usage: rtplan_test output_dir\n"); exit (1); } Dcmtk_rt_study drs; Rt_study_metadata::Pointer rsm = Rt_study_metadata::New (); Rtplan::Pointer rtplan = Rtplan::New (); drs.set_rt_study_metadata (rsm); drs.set_rtplan (rtplan); /* Fill in metadata */ rsm->set_patient_name ("Test^Rtplan"); /* Fill in plan data */ rtplan->number_of_fractions_planned = 5; rtplan->snout_id = "Standard snout"; rtplan->general_accessory_id = "General accessory A"; rtplan->general_accessory_code = "1"; rtplan->range_shifter_id = "Range shifter A"; rtplan->range_shifter_code = "3"; rtplan->range_modulator_id = "Range modulator A"; rtplan->range_modulator_code = "6"; rtplan->tolerance_table_label = "Standard"; rtplan->tolerance_gantry_angle = "0.3"; rtplan->tolerance_patient_support_angle = "0.3"; rtplan->tolerance_table_top_vertical = "1.0"; rtplan->tolerance_table_top_longitudinal = "1.0"; rtplan->tolerance_table_top_lateral = "1.0"; rtplan->tolerance_snout_position = "0.3"; /* Fill in beam data */ for (size_t i = 0; i < 1; i++) { std::string beam_name = string_format ("Beam %d", (int) i); Rtplan_beam *beam = rtplan->add_beam (beam_name, (int) i); beam->description = string_format ("Beam %d description", (int) i); beam->beam_dose_specification_point = "0\\-10.5\\0"; beam->beam_dose = 2.f; float snout_pos = 250.f; beam->snout_position = snout_pos; float cum_gp = 0.f; for (size_t seg = 0; seg < 3; seg++) { float energy = 100.f + seg * 25.f; float gp = 25.f; for (size_t cpi = 0; cpi < 2; cpi++) { Rtplan_control_pt *cp = beam->add_control_pt (); cp->cumulative_meterset_weight = cum_gp + cpi * gp; cp->nominal_beam_energy = energy; cp->meterset_rate = 400; cp->scan_spot_position_map.push_back (-10.f - seg); cp->scan_spot_position_map.push_back (-10.f); cp->scan_spot_position_map.push_back (+10.f + seg); cp->scan_spot_position_map.push_back (-10.f); cp->scan_spot_position_map.push_back (-10.f - seg); cp->scan_spot_position_map.push_back (+10.f); cp->scan_spot_position_map.push_back (+10.f + seg); cp->scan_spot_position_map.push_back (+10.f); cp->scan_spot_meterset_weights.push_back (5); cp->scan_spot_meterset_weights.push_back (5); cp->scan_spot_meterset_weights.push_back (10); cp->scan_spot_meterset_weights.push_back (5); } cum_gp += gp; } beam->final_cumulative_meterset_weight = cum_gp; } /* Save to file */ drs.save (dicom_dir); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/sizeof.f000066400000000000000000000004711321604176500272460ustar00rootroot00000000000000 subroutine sizeof_int (bits) integer bits integer i,j i=0 j=1 10 i=i+1 j=j+j if (j.ne.0) go to 10 bits = i / 8 end program hello integer bits call sizeof_int (bits) write (*,*) 'Size of integer: ', bits end program hello plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/smartp_test_i.cxx000066400000000000000000000045621321604176500312060ustar00rootroot00000000000000#include #include "smart_pointer.h" # if SHARED_PTR_USE_MEMORY # include # define plm_shared_ptr std::shared_ptr # elif TR1_SHARED_PTR_USE_TR1_MEMORY # include # define plm_shared_ptr std::tr1::shared_ptr # elif TR1_SHARED_PTR_USE_MEMORY # include # define plm_shared_ptr std::tr1::shared_ptr # endif #include "dlib/smart_pointers.h" class A { public: int *val; public: A () { val = new int; *val = 3; } ~A () { delete val; } private: A (const A&); }; void foo_1 (dlib::shared_ptr a) { (*a->val) ++; printf ("A %d\n", *(a->val)); } void test_1 () { dlib::shared_ptr a (new A); for (int i = 0; i < 10; i++) { foo_1 (a); } } class B { public: /* Smart pointer support */ // typedef B Self; // typedef plm_shared_ptr Pointer; SMART_POINTER_SUPPORT (B); public: int *val; public: B () { val = new int; *val = 3; } ~B () { delete val; } //public: // static B::Pointer New () { // return B::Pointer (new B); // } private: B (const B&); }; void foo_2 (B::Pointer b) { (*b->val) ++; printf ("B %d\n", *(b->val)); } void test_2 () { B::Pointer b = B::New (new B); for (int i = 0; i < 10; i++) { foo_2 (b); } #if defined (commentout) /* This doesn't compile */ b = 0; #endif } class C { public: typedef plm_shared_ptr Pointer; #if defined (commentout) template static C::Pointer New ( U1 u1, U2 u2, U3 u3, U4 u4, U5 u5, U6 u6 ) { return C::Pointer (new C (u1, u2, u3, u4, u5, u6)); } #endif template static C::Pointer New ( U1& u1, U2& u2, U3& u3, U4& u4, U5& u5, U6& u6 ) { return C::Pointer (new C (u1, u2, u3, u4, u5, u6)); } public: int *val; public: C (const A& a, B& b, A& c, B& d, B& e, A& f) { val = new int; *val = 3; } ~C () { delete val; } }; void test_3 () { A a; B b; C::Pointer c = C::New (a, b, a, b, b, a); } int main (int argc, char* argv[]) { test_1(); test_2(); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/smartp_test_ii.cxx000066400000000000000000000012411321604176500313460ustar00rootroot00000000000000#include #include "smart_pointer.h" class A { public: SMART_POINTER_SUPPORT(A); public: int *val; public: A () { val = new int; *val = 3; } ~A () { delete val; } }; int main (int argc, char* argv[]) { A::Pointer a; if (a) { printf ("a is non-null\n"); } else { printf ("a is null\n"); } A::Pointer b = A::New(); if (b) { printf ("b is non-null\n"); } else { printf ("b is null\n"); } A::Pointer c = A::New(); c.reset(); if (c) { printf ("c is non-null\n"); } else { printf ("c is null\n"); } return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/test/yamlcpp_test.cxx000066400000000000000000000010101321604176500310160ustar00rootroot00000000000000#include "yaml-cpp/yaml.h" int main () { YAML::Node config = YAML::LoadFile("config.yaml"); if (config["lastLogin"]) { std::cout << "Last logged in: " << config["lastLogin"].as() << "\n"; } const std::string username = config["username"].as(); const std::string password = config["password"].as(); login(username, password); config["lastLogin"] = getCurrentDateTime(); std::ofstream fout("config.yaml"); fout << config; return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/000077500000000000000000000000001321604176500255745ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/CMakeLists.txt000066400000000000000000000057741321604176500303510ustar00rootroot00000000000000##----------------------------------------------------------------------------- ## See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ##----------------------------------------------------------------------------- project (src_plastimatch_util) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/plmutil_config.h.in ${CMAKE_BINARY_DIR}/plmutil_config.h ) include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories (AFTER ${DEVILLARD_INCLUDE_DIR}) ##----------------------------------------------------------------------------- ## SOURCE FILES ##----------------------------------------------------------------------------- set (PLMUTIL_LIBRARY_SRC bspline_correspond.cxx dice_statistics.cxx dice_statistics.h dicom_sro_save.cxx distance_map.cxx diff.cxx dvh.cxx dvh.h gamma_dose_comparison.cxx gamma_dose_comparison.h geometry_chooser.cxx geometry_chooser.h hausdorff_distance.cxx hausdorff_distance.h image_boundary.cxx image_boundary.h image_center.cxx image_center.h itk_adjust.cxx itk_adjust.h itk_distance_map.cxx itk_crop.cxx itk_gabor.cxx itk_mask.cxx itk_scale.cxx itk_threshold.cxx itk_union.cxx landmark_diff.cxx proj_image_filter.cxx plm_series.cxx plm_study.cxx rt_study_warp.cxx rt_study_warp.h sift.cxx simplify_points.cxx ss_img_stats.cxx synthetic_mha.cxx synthetic_vf.cxx threshbox.cxx volume_adjust.cxx volume_adjust.h vf_invert.cxx ) if (FFTW_FOUND) set (PLMUTIL_LIBRARY_SRC ${PLMUTIL_LIBRARY_SRC} gabor.cxx gabor.h ramp_filter.cxx ramp_filter.h ) endif () set (PLMUTIL_LIBRARY_HEADERS "${CMAKE_BINARY_DIR}/plmutil_config.h" ) foreach (ARG ${PLMUTIL_LIBRARY_SRC}) string (REGEX MATCH ".*\\.h$" TMP "${ARG}") if (TMP) list (APPEND PLMUTIL_LIBRARY_HEADERS "${TMP}") endif () endforeach () ##----------------------------------------------------------------------------- ## LIBRARY DEPENDENCIES ##----------------------------------------------------------------------------- set (PLMUTIL_LIBRARY_DEPENDENCIES ${FFTW_LIBRARIES} devillard plmbase plmsys ) ##----------------------------------------------------------------------------- ## SPECIAL BUILD RULES: OpenMP & SSE2 ##----------------------------------------------------------------------------- if (OPENMP_FOUND) set (PLMUTIL_LIBRARY_LDFLAGS "${OPENMP_LDFLAGS}") set_source_files_properties (dice_statistics.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) set_source_files_properties (image_center.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) set_source_files_properties (vf_invert.cxx PROPERTIES COMPILE_FLAGS ${OPENMP_FLAGS}) endif () ##----------------------------------------------------------------------------- ## BUILD TARGETS ##----------------------------------------------------------------------------- plm_add_library ( plmutil "${PLMUTIL_LIBRARY_SRC}" "${PLMUTIL_LIBRARY_DEPENDENCIES}" "${PLMUTIL_LIBRARY_LDFLAGS}" "${PLASTIMATCH_INCLUDE_DIRECTORIES}" "${PLMUTIL_LIBRARY_HEADERS}") bspline_correspond.cxx000066400000000000000000000075241321604176500321430ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include "bspline_correspond.h" #include "plm_int.h" #include "volume.h" static void float_to_plm_long_clamp (plm_long* p, float* f, const plm_long* max) { float p_f[3]; p_f[0] = f[0]; p_f[1] = f[1]; p_f[2] = f[2]; /* x */ if (p_f[0] < 0.f) { p[0] = 0; } else if (p_f[0] >= max[0]) { p[0] = max[0] - 1; } else { p[0] = FLOOR_PLM_LONG (p_f[0]); } /* y */ if (p_f[1] < 0.f) { p[1] = 0; } else if (p_f[1] >= max[1]) { p[1] = max[1] - 1; } else { p[1] = FLOOR_PLM_LONG (p_f[1]); } /* z */ if (p_f[2] < 0.f) { p[2] = 0; } else if (p_f[2] >= max[2]) { p[2] = max[2] - 1; } else { p[2] = FLOOR_PLM_LONG (p_f[2]); } } int inside_roi (float* xyz, const Volume* roi) { float p_f[3]; float tmp[3]; plm_long p[3]; tmp[0] = xyz[0] - roi->origin[0]; tmp[1] = xyz[1] - roi->origin[1]; tmp[2] = xyz[2] - roi->origin[2]; p_f[0] = PROJECT_X (tmp, roi->proj); p_f[1] = PROJECT_Y (tmp, roi->proj); p_f[2] = PROJECT_Z (tmp, roi->proj); float_to_plm_long_clamp (p, p_f, roi->dim); unsigned char *m = (unsigned char*)roi->img; plm_long i = volume_index (roi->dim, p); /* 0 outside roi, 1 inside */ return (int)m[i]; } /* Find location and index of corresponding voxel in moving image. * This version takes direction cosines into consideration Return 1 if corresponding voxel lies within the moving image, return 0 if outside the moving image. */ int bspline_find_correspondence_dcos ( float *mxyz, /* Output: xyz coordinates in moving image (mm) */ float *mijk, /* Output: ijk indices in moving image (vox) */ const float *fxyz, /* Input: xyz coordinates in fixed image (mm) */ const float *dxyz, /* Input: displacement from fixed to moving (mm) */ const Volume *moving /* Input: moving image */ ) { float tmp[3]; mxyz[0] = fxyz[0] + dxyz[0]; mxyz[1] = fxyz[1] + dxyz[1]; mxyz[2] = fxyz[2] + dxyz[2]; tmp[0] = mxyz[0] - moving->origin[0]; tmp[1] = mxyz[1] - moving->origin[1]; tmp[2] = mxyz[2] - moving->origin[2]; mijk[0] = PROJECT_X (tmp, moving->proj); mijk[1] = PROJECT_Y (tmp, moving->proj); mijk[2] = PROJECT_Z (tmp, moving->proj); if (!moving->is_inside (mijk)) return 0; return 1; } /* Find location and index of corresponding voxel in moving image. * This version takes direction cosines and true roiing into consideration Return 1 if corresponding voxel lies within the moving image, return 0 if outside the moving image. */ int bspline_find_correspondence_dcos_roi ( float *mxyz, /* Output: xyz coordinates in moving image (mm) */ float *mijk, /* Output: ijk indices in moving image (vox) */ const float *fxyz, /* Input: xyz coordinates in fixed image (mm) */ const float *dxyz, /* Input: displacement from fixed to moving (mm) */ const Volume *moving, /* Input: moving image */ const Volume *moving_roi /* Input: moving image roi */ ) { float tmp[3]; mxyz[0] = fxyz[0] + dxyz[0]; mxyz[1] = fxyz[1] + dxyz[1]; mxyz[2] = fxyz[2] + dxyz[2]; tmp[0] = mxyz[0] - moving->origin[0]; tmp[1] = mxyz[1] - moving->origin[1]; tmp[2] = mxyz[2] - moving->origin[2]; mijk[0] = PROJECT_X (tmp, moving->proj); mijk[1] = PROJECT_Y (tmp, moving->proj); mijk[2] = PROJECT_Z (tmp, moving->proj); if (!moving->is_inside (mijk)) return 0; if (moving_roi) { return inside_roi (mxyz, moving_roi); } return 1; } bspline_correspond.h000066400000000000000000000024701321604176500315630ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _bspline_correspond_h_ #define _bspline_correspond_h_ #include "plmutil_config.h" class Volume; PLMUTIL_API int inside_roi (float* xyz, const Volume* roi); PLMUTIL_API int bspline_find_correspondence_dcos ( float *mxyz, /* Output: xyz coordinates in moving image (mm) */ float *mijk, /* Output: ijk indices in moving image (vox) */ const float *fxyz, /* Input: xyz coordinates in fixed image (mm) */ const float *dxyz, /* Input: displacement from fixed to moving (mm) */ const Volume *moving /* Input: moving image */ ); PLMUTIL_API int bspline_find_correspondence_dcos_roi ( float *mxyz, /* Output: xyz coordinates in moving image (mm) */ float *mijk, /* Output: ijk indices in moving image (vox) */ const float *fxyz, /* Input: xyz coordinates in fixed image (mm) */ const float *dxyz, /* Input: displacement from fixed to moving (mm) */ const Volume *moving, /* Input: moving image */ const Volume *moving_roi /* Input: moving image roi */ ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/dice_statistics.cxx000066400000000000000000000154171321604176500315060ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageMomentsCalculator.h" #include "itkImageRegionIteratorWithIndex.h" #include "itkImageSliceConstIteratorWithIndex.h" #include "compiler_warnings.h" #include "dice_statistics.h" #include "itk_image.h" #include "itk_image_load.h" #include "itk_image_save.h" #include "itk_resample.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "volume.h" class Dice_statistics_private { public: Dice_statistics_private () { TP = TN = FP = FN = 0; } public: size_t TP, TN, FP, FN; float dice; size_t ref_num_vox; size_t cmp_num_vox; DoubleVector3DType ref_cog; DoubleVector3DType cmp_cog; double ref_vol; double cmp_vol; UCharImageType::Pointer ref_image; UCharImageType::Pointer cmp_image; }; Dice_statistics::Dice_statistics () { d_ptr = new Dice_statistics_private; } Dice_statistics::~Dice_statistics () { delete d_ptr; } void Dice_statistics::set_reference_image (const char* image_fn) { d_ptr->ref_image = itk_image_load_uchar (image_fn, 0); } void Dice_statistics::set_reference_image ( const UCharImageType::Pointer& image) { d_ptr->ref_image = image; } void Dice_statistics::set_compare_image (const char* image_fn) { d_ptr->cmp_image = itk_image_load_uchar (image_fn, 0); } void Dice_statistics::set_compare_image ( const UCharImageType::Pointer& image) { d_ptr->cmp_image = image; } void Dice_statistics::run () { /* Resample and/or expand images based on geometry of reference */ if (!itk_image_header_compare (d_ptr->ref_image, d_ptr->cmp_image)) { Plm_image_header pih; pih.set_geometry_to_contain ( Plm_image_header (d_ptr->cmp_image), Plm_image_header (d_ptr->ref_image)); d_ptr->cmp_image = resample_image (d_ptr->cmp_image, pih, 0, 0); d_ptr->ref_image = resample_image (d_ptr->ref_image, pih, 0, 0); } /* Initialize counters */ d_ptr->ref_num_vox = 0; d_ptr->cmp_num_vox = 0; d_ptr->TP = 0; d_ptr->TN = 0; d_ptr->FP = 0; d_ptr->FN = 0; /* Convert to Plm_image type */ Plm_image ref (d_ptr->ref_image); Volume::Pointer vol_ref = ref.get_volume_uchar (); unsigned char *img_ref = (unsigned char*) vol_ref->img; Plm_image cmp (d_ptr->cmp_image); Volume::Pointer vol_cmp = cmp.get_volume_uchar (); unsigned char *img_cmp = (unsigned char*) vol_cmp->img; size_t tp = 0; size_t tn = 0; size_t fp = 0; size_t fn = 0; double rx = 0, ry = 0, rz = 0; double cx = 0, cy = 0, cz = 0; #pragma omp parallel for reduction(+:tp,tn,fp,fn,cx,cy,cz,rx,ry,rz) LOOP_Z_OMP (k, vol_ref) { plm_long fijk[3]; /* Index within fixed image (vox) */ float fxyz[3]; /* Position within fixed image (mm) */ fijk[2] = k; fxyz[2] = vol_ref->origin[2] + fijk[2] * vol_ref->step[2*3+2]; LOOP_Y (fijk, fxyz, vol_ref) { LOOP_X (fijk, fxyz, vol_ref) { plm_long v = volume_index (vol_ref->dim, fijk); unsigned char vox_ref = img_ref[v]; unsigned char vox_cmp = img_cmp[v]; if (vox_ref) { if (vox_cmp) { tp++; } else { fn++; } } else { if (vox_cmp) { fp++; } else { tn++; } } if (vox_ref) { rx += fxyz[0]; ry += fxyz[1]; rz += fxyz[2]; } if (vox_cmp) { cx += fxyz[0]; cy += fxyz[1]; cz += fxyz[2]; } } } } d_ptr->TP = tp; d_ptr->FP = fp; d_ptr->TN = tn; d_ptr->FN = fn; d_ptr->ref_num_vox = tp + fn; d_ptr->cmp_num_vox = tp + fp; /* Compute volume and center of mass */ /* Voxel size is same for both images */ double vox_size = vol_ref->spacing[0] * vol_ref->spacing[1] * vol_ref->spacing[2]; d_ptr->ref_vol = d_ptr->ref_num_vox * vox_size; d_ptr->cmp_vol = d_ptr->cmp_num_vox * vox_size; d_ptr->ref_cog[0] = d_ptr->ref_cog[1] = d_ptr->ref_cog[2] = 0.f; d_ptr->cmp_cog[0] = d_ptr->cmp_cog[1] = d_ptr->cmp_cog[2] = 0.f; if (d_ptr->ref_num_vox > 0) { d_ptr->ref_cog[0] = rx / d_ptr->ref_num_vox; d_ptr->ref_cog[1] = ry / d_ptr->ref_num_vox; d_ptr->ref_cog[2] = rz / d_ptr->ref_num_vox; } if (d_ptr->ref_num_vox > 0) { d_ptr->cmp_cog[0] = cx / d_ptr->cmp_num_vox; d_ptr->cmp_cog[1] = cy / d_ptr->cmp_num_vox; d_ptr->cmp_cog[2] = cz / d_ptr->cmp_num_vox; } } float Dice_statistics::get_dice () { float dice = 0.f; if ((d_ptr->ref_num_vox + d_ptr->cmp_num_vox) > 0) { dice = ((float) (2 * d_ptr->TP)) / ((float) (d_ptr->ref_num_vox + d_ptr->cmp_num_vox)); } return dice; } float Dice_statistics::get_sensitivity() { return ((float) d_ptr->TP) / ((float) (d_ptr->TP + d_ptr->FN)); } float Dice_statistics::get_specificity() { return ((float) d_ptr->TN) / ((float) (d_ptr->TN + d_ptr->FP)); } size_t Dice_statistics::get_true_positives () { return d_ptr->TP; } size_t Dice_statistics::get_true_negatives () { return d_ptr->TN; } size_t Dice_statistics::get_false_positives () { return d_ptr->FP; } size_t Dice_statistics::get_false_negatives () { return d_ptr->FN; } DoubleVector3DType Dice_statistics::get_reference_center () { return d_ptr->ref_cog; } DoubleVector3DType Dice_statistics::get_compare_center () { return d_ptr->cmp_cog; } double Dice_statistics::get_reference_volume () { return d_ptr->ref_vol; } double Dice_statistics::get_compare_volume () { return d_ptr->cmp_vol; } void Dice_statistics::debug () { lprintf ("CENTER_OF_MASS\n"); lprintf ("ref\t %13g\t %13g\t %13g\n", d_ptr->ref_cog[0], d_ptr->ref_cog[1], d_ptr->ref_cog[2]); lprintf ("cmp\t %13g\t %13g\t %13g\n", d_ptr->cmp_cog[0], d_ptr->cmp_cog[1], d_ptr->cmp_cog[2]); lprintf ("TP: %13d\n",d_ptr->TP); lprintf ("TN: %13d\n",d_ptr->TN); lprintf ("FN: %13d\n",d_ptr->FN); lprintf ("FP: %13d\n",d_ptr->FP); lprintf ("DICE: %13f\n", this->get_dice()); lprintf ("SE: %13f\n", this->get_sensitivity()); lprintf ("SP: %13f\n", this->get_specificity()); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/dice_statistics.h000066400000000000000000000063031321604176500311250ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dice_statistics_h_ #define _dice_statistics_h_ #include "plmutil_config.h" #include "itk_image_type.h" class Plm_image; class Dice_statistics_private; /*! \brief * The Dice_statistics class computes a Dice statistic for the * overlap between two regions. Dice is defined as * \f[ * D = \frac{2 |X| \cup |Y|}{|X| + |Y|}. * \f] * A value of zero means X and Y have no overlap, where a value of one means * the two regions are the same. * * If the images do not have the same size and resolution, the compare * image will be resampled onto the reference image geometry prior * to comparison. */ class PLMUTIL_API Dice_statistics { public: Dice_statistics (); ~Dice_statistics (); public: Dice_statistics_private *d_ptr; public: /*! \name Inputs */ ///@{ /*! \brief Set the reference image. The image will be loaded from the specified filename. */ void set_reference_image (const char* image_fn); /*! \brief Set the reference image as an ITK image. */ void set_reference_image (const UCharImageType::Pointer& image); /*! \brief Set the compare image. The image will be loaded from the specified filename. */ void set_compare_image (const char* image_fn); /*! \brief Set the compare image as an ITK image. */ void set_compare_image (const UCharImageType::Pointer& image); ///@} /*! \name Execution */ ///@{ /*! \brief Compute dice statistics */ void run (); ///@} /*! \name Outputs */ ///@{ /*! \brief Return the Dice coefficient value */ float get_dice (); /*! \brief Return sensitivity coefficient value */ float get_sensitivity (); /*! \brief Return specificity coefficient value */ float get_specificity (); /*! \brief Return the number of true positive voxels, i.e. positive reference voxels that are positive in compare image */ size_t get_true_positives (); /*! \brief Return the number of true negative voxels, i.e. negative reference voxels that are negative in compare image */ size_t get_true_negatives (); /*! \brief Return the number of false positive voxels, i.e. negative reference voxels that are positive in compare image */ size_t get_false_positives (); /*! \brief Return the number of false negative voxels, i.e. positive reference voxels that are negative in compare image */ size_t get_false_negatives (); /*! \brief Return the location of the center of mass of the reference image structure */ DoubleVector3DType get_reference_center (); /*! \brief Return the location of the center of mass of the compare image structure */ DoubleVector3DType get_compare_center (); /*! \brief Return the volume of the reference image structure */ double get_reference_volume (); /*! \brief Return the volume of the compare image structure */ double get_compare_volume (); /*! \brief Display debugging information to stdout */ void debug (); ///@} }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/dicom_sro_save.cxx000066400000000000000000000102631321604176500313160ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #if PLM_DCM_USE_DCMTK #include "dcmtk_sro.h" #endif #include "dicom_sro_save.h" #include "plm_image.h" #include "rt_study.h" #include "rt_study_metadata.h" #include "xform.h" class Dicom_sro_save_private { public: Dicom_sro_save_private () { output_dir = "sro_export"; } public: std::string fixed_image_path; std::string moving_image_path; Plm_image::Pointer fixed_image; Plm_image::Pointer moving_image; Xform::Pointer xform; std::string output_dir; public: Rt_study_metadata::Pointer load_rt_study ( Plm_image::Pointer& image, const std::string& path, const std::string& output_suffix); }; /* Utility function */ Rt_study_metadata::Pointer Dicom_sro_save_private::load_rt_study ( Plm_image::Pointer& image, const std::string& path, const std::string& output_suffix) { if (image) { Rt_study::Pointer rtds = Rt_study::New (); rtds->set_image (image); std::string fixed_path = this->output_dir + "/" + output_suffix; rtds->save_dicom (fixed_path); return rtds->get_rt_study_metadata(); } if (path != "") { Plm_file_format format = plm_file_format_deduce (path); if (format == PLM_FILE_FMT_DICOM_DIR) { return Rt_study_metadata::load (path); } Plm_image::Pointer new_image = Plm_image::New (); new_image->load_native (path); return this->load_rt_study (new_image, path, output_suffix); } /* Return null pointer */ return Rt_study_metadata::Pointer(); } Dicom_sro_save::Dicom_sro_save () { d_ptr = new Dicom_sro_save_private; } Dicom_sro_save::~Dicom_sro_save () { delete d_ptr; } void Dicom_sro_save::set_fixed_image (const char* path) { d_ptr->fixed_image_path = path; } void Dicom_sro_save::set_fixed_image (const Plm_image::Pointer& fixed_image) { d_ptr->fixed_image = fixed_image; } void Dicom_sro_save::set_moving_image (const char* path) { d_ptr->moving_image_path = path; } void Dicom_sro_save::set_moving_image (const Plm_image::Pointer& moving_image) { d_ptr->moving_image = moving_image; } void Dicom_sro_save::set_xform (const Xform::Pointer& xform) { d_ptr->xform = xform; } void Dicom_sro_save::set_output_dir (const std::string& output_dir) { d_ptr->output_dir = output_dir; } void Dicom_sro_save::run () { /* Load referenced image sets */ #if PLM_DCM_USE_DCMTK Rt_study_metadata::Pointer rtm_reg; Rt_study_metadata::Pointer rtm_src; /* Fixed image */ rtm_reg = d_ptr->load_rt_study ( d_ptr->fixed_image, d_ptr->fixed_image_path, "fixed"); /* Moving image */ rtm_src = d_ptr->load_rt_study ( d_ptr->moving_image, d_ptr->moving_image_path, "moving"); Dcmtk_sro::save ( d_ptr->xform, rtm_src, rtm_reg, d_ptr->output_dir, true); #if defined (commentout) /* Fixed image */ if (!parms->fixed_image.empty()) { lprintf ("Loading fixed...\n"); Rt_study::Pointer rtds = Rt_study::New (); rtds->load_image (parms->fixed_image); std::string fixed_path = parms->output_dicom_dir + "/fixed"; rtds->save_dicom (fixed_path); rtm_reg = rtds->get_rt_study_metadata(); } else if (!parms->registered_rcs.empty()) { lprintf ("Loading registered...\n"); rtm_reg = Rt_study_metadata::load (parms->registered_rcs); } /* Moving image */ if (!parms->moving_image.empty()) { lprintf ("Loading moving...\n"); Rt_study::Pointer rtds = Rt_study::New (); rtds->load_image (parms->fixed_image); std::string moving_path = parms->output_dicom_dir + "/moving"; rtds->save_dicom (moving_path); rtm_src = rtds->get_rt_study_metadata(); } else if (!parms->source_rcs.empty()) { lprintf ("Loading source...\n"); rtm_src = Rt_study_metadata::load (parms->source_rcs); } Dcmtk_sro::save ( xfc->m_xf_out, rtm_src, rtm_reg, parms->output_dicom_dir); #endif #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/dicom_sro_save.h000066400000000000000000000040241321604176500307410ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dicom_sro_save_h_ #define _dicom_sro_save_h_ #include "plmutil_config.h" #include "plm_image.h" #include "xform.h" class Dicom_sro_save_private; /*! \brief * The Dicom_sro_save is a utility class for saving DICOM Spatial * Registration objects from different input sources. * The input images may either already exist as DICOM, in which * case the SRO will reference the existing series, or they may * be written by this class. */ class PLMUTIL_API Dicom_sro_save { public: Dicom_sro_save (); ~Dicom_sro_save (); public: Dicom_sro_save_private *d_ptr; public: /*! \name Inputs */ ///@{ /*! \brief Set the reference image. If it is a non-DICOM volume, the volume will be loaded and exported as DICOM. If it is a DICOM volume, it will be loaded and referenced. */ void set_fixed_image (const char* path); /*! \brief Set the reference image. The volume will be exported as DICOM. */ void set_fixed_image (const Plm_image::Pointer& fixed_image); /*! \brief Set the moving image. If it is a non-DICOM volume, the volume will be loaded and exported as DICOM. If it is a DICOM volume, it will be loaded and referenced */ void set_moving_image (const char* path); /*! \brief Set the moving image. The volume will be exported as DICOM. */ void set_moving_image (const Plm_image::Pointer& moving_image); /*! \brief Set the transform, which will be exported as DICOM. */ void set_xform (const Xform::Pointer& xform); /*! \brief Set the path to the output directory where the DICOM SRO and images will be saved */ void set_output_dir (const std::string& output_dir); ///@} /*! \name Execution */ ///@{ /*! \brief Save the SRO and maybe some images too. */ void run (); ///@} }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/diff.cxx000066400000000000000000000031661321604176500272360ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include "itkSubtractImageFilter.h" #include "itkImageRegionIterator.h" #include "diff.h" #include "itk_image_save.h" #include "plm_image.h" #include "print_and_exit.h" Diff_parms::Diff_parms () { } void diff_main (Diff_parms* parms) { Plm_image::Pointer img1, img2; img1 = plm_image_load_native (parms->img_in_1_fn); if (!img1) { print_and_exit ("Error: could not open '%s' for read\n", parms->img_in_1_fn.c_str()); } img2 = plm_image_load_native (parms->img_in_2_fn); if (!img2) { print_and_exit ("Error: could not open '%s' for read\n", parms->img_in_2_fn.c_str()); } if (!Plm_image::compare_headers (img1, img2)) { print_and_exit ("Error: image sizes do not match\n"); } FloatImageType::Pointer fi1 = img1->itk_float (); FloatImageType::Pointer fi2 = img2->itk_float (); typedef itk::SubtractImageFilter< FloatImageType, FloatImageType, FloatImageType > SubtractFilterType; SubtractFilterType::Pointer sub_filter = SubtractFilterType::New(); sub_filter->SetInput1 (fi1); sub_filter->SetInput2 (fi2); try { sub_filter->Update(); } catch (itk::ExceptionObject & excep) { std::cerr << "ITK exception caught: " << excep << std::endl; exit (-1); } FloatImageType::Pointer diff = sub_filter->GetOutput (); itk_image_save_float (diff, parms->img_out_fn.c_str()); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/diff.h000066400000000000000000000010121321604176500266470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _diff_h_ #define _diff_h_ #include "plmutil_config.h" #include class PLMUTIL_API Diff_parms { public: std::string img_in_1_fn; std::string img_in_2_fn; std::string img_out_fn; public: Diff_parms (); }; PLMUTIL_API void diff_main (Diff_parms* parms); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/distance_map.cxx000066400000000000000000000322351321604176500307540ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "itkImage.h" #include "image_boundary.h" #include "distance_map.h" #include "itk_distance_map.h" #include "itk_image_type.h" #include "plm_image.h" #include "volume.h" #include "volume_header.h" class Distance_map_private { public: Distance_map_private () { inside_is_positive = false; use_squared_distance = false; maximum_distance = FLT_MAX; algorithm = Distance_map::DANIELSSON; vbb = ADAPTIVE_PADDING; } public: Distance_map::Algorithm algorithm; bool inside_is_positive; bool use_squared_distance; float maximum_distance; Volume_boundary_behavior vbb; UCharImageType::Pointer input; FloatImageType::Pointer output; public: void run_native_danielsson (); void run_itk_signed_danielsson (); void run_itk_signed_maurer (); void run_itk_signed_native (); void run (); protected: void forward_propagate_i ( float *dm, const Volume::Pointer& vb, const float* sp2, plm_long j, plm_long k); void backward_propagate_i ( float *dm, const Volume::Pointer& vb, const float* sp2, plm_long j, plm_long k); void forward_propagate_j ( float *dm, const Volume::Pointer& vb, const float* sp2, plm_long k); void backward_propagate_j ( float *dm, const Volume::Pointer& vb, const float* sp2, plm_long k); }; /* Define some macros */ #define SQ_DIST(idx,sp2) \ dm[3*idx+0]*dm[3*idx+0]*sp2[0] \ + dm[3*idx+1]*dm[3*idx+1]*sp2[1] \ + dm[3*idx+2]*dm[3*idx+2]*sp2[2] #define SQ_DIST_I(idx,sp2) \ (dm[3*idx+0]+1)*(dm[3*idx+0]+1)*sp2[0] \ + dm[3*idx+1]*dm[3*idx+1]*sp2[1] \ + dm[3*idx+2]*dm[3*idx+2]*sp2[2] #define SQ_DIST_J(idx,sp2) \ dm[3*idx+0]*dm[3*idx+0]*sp2[0] \ + (dm[3*idx+1]+1)*(dm[3*idx+1]+1)*sp2[1] \ + dm[3*idx+2]*dm[3*idx+2]*sp2[2] #define SQ_DIST_K(idx,sp2) \ dm[3*idx+0]*dm[3*idx+0]*sp2[0] \ + dm[3*idx+1]*dm[3*idx+1]*sp2[1] \ + (dm[3*idx+2]+1)*(dm[3*idx+2]+1)*sp2[2] #define COPY_I(new_idx,old_idx) \ dm[3*new_idx+0] = dm[3*old_idx+0] + 1; \ dm[3*new_idx+1] = dm[3*old_idx+1]; \ dm[3*new_idx+2] = dm[3*old_idx+2]; #define COPY_J(new_idx,old_idx) \ dm[3*new_idx+0] = dm[3*old_idx+0]; \ dm[3*new_idx+1] = dm[3*old_idx+1] + 1; \ dm[3*new_idx+2] = dm[3*old_idx+2]; #define COPY_K(new_idx,old_idx) \ dm[3*new_idx+0] = dm[3*old_idx+0]; \ dm[3*new_idx+1] = dm[3*old_idx+1]; \ dm[3*new_idx+2] = dm[3*old_idx+2] + 1; void Distance_map_private::forward_propagate_i ( float *dm, const Volume::Pointer& vb, const float* sp2, plm_long j, plm_long k) { /* Forward propagate i */ for (plm_long i = 1; i < vb->dim[0]; i++) { plm_long vo = vb->index (i-1, j, k); /* "old" voxel */ plm_long vn = vb->index (i, j, k); /* "new" voxel */ if (dm[3*vo] == FLT_MAX) { continue; } if (dm[3*vn] == FLT_MAX) { COPY_I (vn, vo); continue; } float odist = SQ_DIST_I(vo,sp2); float ndist = SQ_DIST(vn,sp2); if (odist < ndist) { COPY_I (vn, vo); } } } void Distance_map_private::backward_propagate_i ( float *dm, const Volume::Pointer& vb, const float* sp2, plm_long j, plm_long k) { /* Backward propagate i */ for (plm_long i = vb->dim[0] - 2; i >= 0; i--) { plm_long vo = vb->index (i+1, j, k); /* "old" voxel */ plm_long vn = vb->index (i, j, k); /* "new" voxel */ if (dm[3*vo] == FLT_MAX) { continue; } if (dm[3*vn] == FLT_MAX) { COPY_I (vn, vo); continue; } float odist = SQ_DIST_I(vo,sp2); float ndist = SQ_DIST(vn,sp2); if (odist < ndist) { COPY_I (vn, vo); } } } void Distance_map_private::forward_propagate_j ( float *dm, const Volume::Pointer& vb, const float* sp2, plm_long k) { /* Propagate within j = 0 */ this->forward_propagate_i (dm, vb, sp2, 0, k); this->backward_propagate_i (dm, vb, sp2, 0, k); /* Forward scan j */ for (plm_long j = 1; j < vb->dim[1]; j++) { /* Propagate j */ for (plm_long i = 0; i < vb->dim[0]; i++) { plm_long vo = vb->index (i, j-1, k); /* "old" voxel */ plm_long vn = vb->index (i, j, k); /* "new" voxel */ if (dm[3*vo] == FLT_MAX) { continue; } if (dm[3*vn] == FLT_MAX) { COPY_J (vn, vo); continue; } float odist = SQ_DIST_J(vo,sp2); float ndist = SQ_DIST(vn,sp2); if (odist < ndist) { COPY_J (vn, vo); } } /* Propagate along i */ this->forward_propagate_i (dm, vb, sp2, j, k); this->backward_propagate_i (dm, vb, sp2, j, k); } } void Distance_map_private::backward_propagate_j ( float *dm, const Volume::Pointer& vb, const float* sp2, plm_long k) { /* Backward scan j */ for (plm_long j = vb->dim[1] - 2; j >= 0; j--) { /* Propagate j */ for (plm_long i = 0; i < vb->dim[0]; i++) { plm_long vo = vb->index (i, j+1, k); /* "old" voxel */ plm_long vn = vb->index (i, j, k); /* "new" voxel */ if (dm[3*vo] == FLT_MAX) { continue; } if (dm[3*vn] == FLT_MAX) { COPY_J (vn, vo); continue; } float odist = SQ_DIST_J(vo,sp2); float ndist = SQ_DIST(vn,sp2); if (odist < ndist) { COPY_J (vn, vo); } } /* Propagate along i */ this->forward_propagate_i (dm, vb, sp2, j, k); this->backward_propagate_i (dm, vb, sp2, j, k); } } void Distance_map_private::run_native_danielsson () { /* Compute boundary of image vb = volume of boundary, imgb = img of boundary */ Image_boundary ib; ib.set_volume_boundary_behavior (vbb); ib.set_input_image (this->input); ib.run (); UCharImageType::Pointer itk_ib = ib.get_output_image (); Plm_image pib (itk_ib); Volume::Pointer vb = pib.get_volume_uchar(); unsigned char *imgb = (unsigned char*) vb->img; /* Convert image to native volume vs = volume of set, imgs = img of set */ Plm_image pi (this->input); Volume::Pointer vs = pi.get_volume_uchar(); unsigned char *imgs = (unsigned char*) vs->img; /* Allocate and initialize "Danielsson array" */ float *dm = new float[3*vb->npix]; for (plm_long v = 0; v < vb->npix; v++) { bool inside = (bool) imgb[v]; if (inside) { dm[3*v+0] = 0; dm[3*v+1] = 0; dm[3*v+2] = 0; } else { dm[3*v+0] = FLT_MAX; dm[3*v+1] = FLT_MAX; dm[3*v+2] = FLT_MAX; } } float sp2[3] = { vb->spacing[0] * vb->spacing[0], vb->spacing[1] * vb->spacing[1], vb->spacing[2] * vb->spacing[2] }; /* GCS FIX -- I'm not entirely sure if it is required to scan both forward and backward for j direction. Need to test. */ /* Propagate within k = 0 */ this->forward_propagate_j (dm, vb, sp2, 0); this->backward_propagate_j (dm, vb, sp2, 0); /* Forward scan k */ for (plm_long k = 1; k < vb->dim[2]; k++) { /* Propagate from prev to curr k */ for (plm_long j = 0; j < vb->dim[1]; j++) { for (plm_long i = 0; i < vb->dim[0]; i++) { plm_long vo = vb->index (i, j, k-1); /* "old" voxel */ plm_long vn = vb->index (i, j, k); /* "new" voxel */ if (dm[3*vo] == FLT_MAX) { continue; } if (dm[3*vn] == FLT_MAX) { COPY_K (vn, vo); continue; } float odist = SQ_DIST_K(vo,sp2); float ndist = SQ_DIST(vn,sp2); if (odist < ndist) { COPY_K (vn, vo); } } } /* Propagate within curr k */ this->forward_propagate_j (dm, vb, sp2, k); this->backward_propagate_j (dm, vb, sp2, k); } /* Backward scan k */ for (plm_long k = vb->dim[2] - 2; k >= 0; k--) { /* Propagate from prev to curr k */ for (plm_long j = 0; j < vb->dim[1]; j++) { for (plm_long i = 0; i < vb->dim[0]; i++) { plm_long vo = vb->index (i, j, k+1); /* "old" voxel */ plm_long vn = vb->index (i, j, k); /* "new" voxel */ if (dm[3*vo] == FLT_MAX) { continue; } if (dm[3*vn] == FLT_MAX) { COPY_K (vn, vo); continue; } float odist = SQ_DIST_K(vo,sp2); float ndist = SQ_DIST(vn,sp2); if (odist < ndist) { COPY_K (vn, vo); } } } /* Propagate within curr k */ this->forward_propagate_j (dm, vb, sp2, k); this->backward_propagate_j (dm, vb, sp2, k); } /* Fill in output image */ Plm_image::Pointer dmap = Plm_image::New ( new Plm_image ( new Volume (Volume_header (vb), PT_FLOAT, 1))); Volume::Pointer dmap_vol = dmap->get_volume_float (); float *dmap_img = (float*) dmap_vol->img; for (plm_long v = 0; v < vb->npix; v++) { if (!this->use_squared_distance) { dmap_img[v] = sqrt(SQ_DIST(v,sp2)); } if (dmap_img[v] >= maximum_distance) { dmap_img[v] = maximum_distance; } if ((this->inside_is_positive && !imgs[v]) || (!this->inside_is_positive && imgs[v])) { dmap_img[v] = -dmap_img[v]; } } /* Free temporary memory */ delete[] dm; /* Fixate distance map into private class */ this->output = dmap->itk_float (); } void Distance_map_private::run_itk_signed_danielsson () { this->output = itk_distance_map_danielsson ( this->input, this->use_squared_distance, this->inside_is_positive); } void Distance_map_private::run_itk_signed_maurer () { this->output = itk_distance_map_maurer ( this->input, this->use_squared_distance, this->inside_is_positive); } void Distance_map_private::run () { switch (this->algorithm) { case Distance_map::DANIELSSON: this->run_native_danielsson (); break; case Distance_map::ITK_DANIELSSON: this->run_itk_signed_danielsson (); break; case Distance_map::ITK_MAURER: default: this->run_itk_signed_maurer (); break; } } Distance_map::Distance_map () { d_ptr = new Distance_map_private; } Distance_map::~Distance_map () { delete d_ptr; } void Distance_map::set_input_image (const std::string& image_fn) { Plm_image pli (image_fn); d_ptr->input = pli.itk_uchar(); } void Distance_map::set_input_image (const char* image_fn) { Plm_image pli (image_fn); d_ptr->input = pli.itk_uchar(); } void Distance_map::set_input_image (UCharImageType::Pointer image) { d_ptr->input = image; } void Distance_map::set_input_image (const Plm_image::Pointer& image) { Plm_image::Pointer pi_clone = image->clone (); d_ptr->input = pi_clone->itk_uchar (); } void Distance_map::set_use_squared_distance (bool use_squared_distance) { d_ptr->use_squared_distance = use_squared_distance; } void Distance_map::set_maximum_distance (float maximum_distance) { d_ptr->maximum_distance = maximum_distance; } void Distance_map::set_volume_boundary_behavior (Volume_boundary_behavior vbb) { d_ptr->vbb = vbb; } void Distance_map::set_inside_is_positive (bool inside_is_positive) { d_ptr->inside_is_positive = inside_is_positive; } void Distance_map::set_algorithm (const std::string& algorithm) { if (algorithm == "danielsson" || algorithm == "native_danielsson") { d_ptr->algorithm = Distance_map::DANIELSSON; } else if (algorithm == "itk-danielsson") { d_ptr->algorithm = Distance_map::ITK_DANIELSSON; } else if (algorithm == "maurer") { d_ptr->algorithm = Distance_map::ITK_MAURER; } else if (algorithm == "itk-maurer" || algorithm == "itk_maurer") { d_ptr->algorithm = Distance_map::ITK_MAURER; } /* Else do nothing */ } void Distance_map::run () { d_ptr->run (); } FloatImageType::Pointer Distance_map::get_output_image () { return d_ptr->output; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/distance_map.h000066400000000000000000000043641321604176500304030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _distance_map_h_ #define _distance_map_h_ #include "plmutil_config.h" #include "itk_image_type.h" #include "plm_image.h" #include "volume_boundary_behavior.h" class Distance_map_private; class Plm_image; class PLMUTIL_API Distance_map { public: Distance_map (); ~Distance_map (); public: Distance_map_private *d_ptr; public: /*! \brief Different distance map algorithms. */ enum Algorithm { DANIELSSON, ITK_DANIELSSON, ITK_MAURER, }; public: /*! \name Inputs */ ///@{ /*! \brief Set the input image. The image will be loaded from the specified filename as a binary mask (unsigned char) image. */ void set_input_image (const std::string& image_fn); void set_input_image (const char* image_fn); /*! \brief Set the input image as an ITK image. */ void set_input_image (const UCharImageType::Pointer image); /*! \brief Set the input image as a Plm_image. */ void set_input_image (const Plm_image::Pointer& image); /*! \brief Choose whether the output image is distance or squared distance. The default is not squared distance. */ void set_use_squared_distance (bool use_squared_distance); /*! \brief Choose whether the inside is positive or negative. The default is inside negative */ void set_inside_is_positive (bool inside_is_positive); /*! \brief Choose which algorithm to use */ void set_algorithm (const std::string& algorithm); /*! \brief Set maximum distance */ void set_maximum_distance (float max_distance); /*! \brief Set the volume boundary behavior, either ZERO_PADDING, EDGE_PADDING, or ADAPTIVE_PADDING */ void set_volume_boundary_behavior (Volume_boundary_behavior vbb); ///@} /*! \name Execution */ ///@{ /*! \brief Compute gamma value at each location in the input image */ void run (); ///@} /*! \name Outputs */ ///@{ /*! \brief Return the gamma image as an ITK image. */ FloatImageType::Pointer get_output_image (); ///@} }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/dvh.cxx000066400000000000000000000201741321604176500271050ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include "itkSubtractImageFilter.h" #include "itkImageRegionIterator.h" #include "dvh.h" #include "dvh_p.h" #include "file_util.h" #include "itk_resample.h" #include "make_string.h" #include "plm_image.h" #include "plm_image_header.h" #include "print_and_exit.h" #include "rt_study.h" #include "rtss_roi.h" #include "rtss.h" #include "segmentation.h" Dvh_private::Dvh_private () { this->dose_units = Dvh::default_dose_units (); this->normalization = Dvh::default_normalization (); this->histogram_type = Dvh::default_histogram_type (); this->num_bins = Dvh::default_histogram_num_bins (); this->bin_width = Dvh::default_histogram_bin_width (); } Dvh_private::~Dvh_private () { } Dvh::Dvh () { this->d_ptr = new Dvh_private; } Dvh::~Dvh () { delete this->d_ptr; } void Dvh::set_structure_set_image ( const char* ss_image_fn, const char *ss_list_fn) { d_ptr->rtss = new Segmentation; d_ptr->rtss->load (ss_image_fn, ss_list_fn); } void Dvh::set_dose_image (const char* image_fn) { d_ptr->dose = plm_image_load_native (image_fn); } void Dvh::set_dose_units (enum Dvh_units units) { d_ptr->dose_units = units; } void Dvh::set_dvh_parameters (enum Dvh_normalization normalization, enum Histogram_type histogram_type, int num_bins, float bin_width) { d_ptr->normalization = normalization; d_ptr->histogram_type = histogram_type; d_ptr->num_bins = num_bins; d_ptr->bin_width = bin_width; } void Dvh::run () { int *hist; int *struct_vox; int bin; float dose_spacing[3]; float ss_spacing[3]; float ss_ori[3]; plm_long ss_dim[3]; FloatImageType::Pointer dose_img = d_ptr->dose->itk_float (); UCharVecImageType::Pointer ss_img = d_ptr->rtss->get_ss_img_uchar_vec (); /* GCS HACK: This should go into rtss.cxx */ Rtss *ss_list; if (d_ptr->rtss->have_structure_set()) { ss_list = d_ptr->rtss->get_structure_set_raw(); } else { ss_list = new Rtss; int num_structures = ss_img->GetVectorLength() * 8; for (int i = 0; i < num_structures; i++) { ss_list->add_structure ("Unknown Structure", "255 255 0", i+1, i); } } /* Create histogram */ std::cout << "Creating Histogram..." << std::endl; printf ("Your Histogram will have %d bins and will be %f Gy large\n", d_ptr->num_bins, d_ptr->bin_width); hist = (int*) malloc (sizeof(int) * ss_list->num_structures * d_ptr->num_bins); memset (hist, 0, sizeof(int) * ss_list->num_structures * d_ptr->num_bins); struct_vox = (int*) malloc (sizeof(int) * ss_list->num_structures); memset (struct_vox, 0, sizeof(int) * ss_list->num_structures); /* Is voxel size the same? */ std::cout << "checking voxel size..." << std::endl; dose_spacing[0]=dose_img->GetSpacing()[0]; dose_spacing[1]=dose_img->GetSpacing()[1]; dose_spacing[2]=dose_img->GetSpacing()[2]; std::cout << dose_spacing[0] << " " << dose_spacing[1] << " " << dose_spacing[2] << "\n"; ss_spacing[0]=ss_img->GetSpacing()[0]; ss_spacing[1]=ss_img->GetSpacing()[1]; ss_spacing[2]=ss_img->GetSpacing()[2]; std::cout << ss_spacing[0] << " " << ss_spacing[1] << " " << ss_spacing[2] << "\n"; if (dose_spacing[0] != ss_spacing[0] || dose_spacing[1] != ss_spacing[1] || dose_spacing[2] != ss_spacing[2]) { std::cout << "dose voxel " << dose_spacing[0] << " " << dose_spacing[1] << " " << dose_spacing[2] << std::endl; std::cout << "ss voxel " << ss_spacing[0] << " " << ss_spacing[1] << " " << ss_spacing[2] << std::endl; std::cout << "Resampling" << std::endl; /*resample volume*/ ss_ori[0]=ss_img->GetOrigin()[0]; ss_ori[1]=ss_img->GetOrigin()[1]; ss_ori[2]=ss_img->GetOrigin()[2]; ss_dim[0]=ss_img->GetLargestPossibleRegion().GetSize()[0]; ss_dim[1]=ss_img->GetLargestPossibleRegion().GetSize()[1]; ss_dim[2]=ss_img->GetLargestPossibleRegion().GetSize()[2]; /* GCS FIX: Direction cosines */ Plm_image_header pih (ss_dim, ss_ori, ss_spacing, 0); FloatImageType::Pointer resampled = resample_image (dose_img, &pih, 0, 1); dose_img=resampled; } else { std::cout << "Dose and ss-img have the same size. Resample not necessary.\n"; } /* Declare iterators */ typedef itk::ImageRegionConstIterator < FloatImageType > FloatIteratorType; FloatIteratorType it_d (dose_img, dose_img->GetRequestedRegion ()); typedef itk::ImageRegionConstIterator < UCharVecImageType > UCharVecIteratorType; UCharVecIteratorType it_s (ss_img, ss_img->GetRequestedRegion ()); /* Loop through dose & ss images */ for (it_d.GoToBegin(), it_s.GoToBegin(); !it_d.IsAtEnd(); ++it_d, ++it_s) { float d = it_d.Get(); itk::VariableLengthVector s = it_s.Get(); /* Convert from cGy to Gy */ if (d_ptr->dose_units == DVH_UNITS_CGY) { d = d / 100; } /* Compute the bin */ bin = (int) floor ((d+(0.5*d_ptr->bin_width)) / d_ptr->bin_width); if (bin < 0) { bin = 0; } else if (bin > (d_ptr->num_bins-1)) { bin = d_ptr->num_bins - 1; } for (size_t sno = 0; sno < ss_list->num_structures; sno++) { Rtss_roi *curr_structure = ss_list->slist[sno]; /* Is this pixel in the current structure? */ int curr_bit = curr_structure->bit; unsigned int uchar_no = curr_bit / 8; unsigned int bit_no = curr_bit % 8; unsigned char bit_mask = 1 << bit_no; if (uchar_no > ss_img->GetVectorLength()) { print_and_exit ( "Error: bit %d was requested from image of %d bits\n", curr_bit, ss_img->GetVectorLength() * 8); } bool in_struct = s[uchar_no] & bit_mask; /* If so, update histogram & structure size */ if (in_struct) { struct_vox[sno] ++; hist[bin*ss_list->num_structures + sno] ++; } } } /* Convert histogram to cumulative histogram */ if (d_ptr->histogram_type == DVH_CUMULATIVE_HISTOGRAM) { for (size_t sno = 0; sno < ss_list->num_structures; sno++) { int cum = 0; for (bin = d_ptr->num_bins - 1; bin >= 0; bin--) { cum = cum + hist[bin*ss_list->num_structures + sno]; hist[bin*ss_list->num_structures + sno] = cum; } } } /* Create output string */ d_ptr->output_string = "Dose (Gy)"; for (size_t sno = 0; sno < ss_list->num_structures; sno++) { Rtss_roi *curr_structure = ss_list->slist[sno]; d_ptr->output_string += ","; d_ptr->output_string += curr_structure->name.c_str(); } d_ptr->output_string += "\n"; for (plm_long bin = 0; bin < d_ptr->num_bins; bin++) { d_ptr->output_string += make_string (bin * d_ptr->bin_width); for (size_t sno = 0; sno < ss_list->num_structures; sno++) { int val = hist[bin*ss_list->num_structures + sno]; d_ptr->output_string += ","; if (struct_vox[sno] == 0) { d_ptr->output_string += "0"; } else if (d_ptr->normalization == DVH_NORMALIZATION_PCT) { float fval = ((float) val) / struct_vox[sno]; d_ptr->output_string += make_string (fval); } else { d_ptr->output_string += make_string (val); } } d_ptr->output_string += "\n"; } } void Dvh::save_csv (const char* csv_fn) { FILE *fp = plm_fopen (csv_fn, "w"); fprintf (fp, "%s", d_ptr->output_string.c_str()); fclose (fp); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/dvh.h000066400000000000000000000060031321604176500265250ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dvh_h_ #define _dvh_h_ #include "plmutil_config.h" #include #include "itk_image_type.h" class Dvh_private; class Plm_image; class Segmentation; class PLMUTIL_API Dvh { public: Dvh (); ~Dvh (); public: Dvh_private *d_ptr; public: enum Dvh_units { DVH_UNITS_GY, DVH_UNITS_CGY, }; enum Dvh_normalization { DVH_NORMALIZATION_PCT, DVH_NORMALIZATION_VOX, }; enum Histogram_type { DVH_CUMULATIVE_HISTOGRAM, DVH_DIFFERENTIAL_HISTOGRAM }; public: /*! \name Defaults */ ///@{ /*! \brief Return the default value for dose units */ static Dvh::Dvh_units default_dose_units () { return Dvh::DVH_UNITS_GY; } /*! \brief Return the default value for DVH normalization */ static Dvh::Dvh_normalization default_normalization () { return Dvh::DVH_NORMALIZATION_PCT; } /*! \brief Return the default value for histogram type */ static Dvh::Histogram_type default_histogram_type () { return Dvh::DVH_CUMULATIVE_HISTOGRAM; } /*! \brief Return the default number of bins in the histogram */ static int default_histogram_num_bins () { return 256; } /*! \brief Return the default bin width (in Gy) in the histogram */ static float default_histogram_bin_width () { return 0.5; } ///@} /*! \name Inputs */ ///@{ /*! \brief Set the structure set image. The image will be loaded from the specified filename, and an optional file containing the image list will be loaded. */ void set_structure_set_image (const char* ss_image_fn, const char *ss_list_fn); /*! \brief Set the structure set image as an Segmentation */ void set_structure_set_image (Segmentation* image); /*! \brief Set the dose image. The image will be loaded from the specified filename. */ void set_dose_image (const char* image_fn); /*! \brief Set the dose image as a Plm image. */ void set_dose_image (Plm_image* image); /*! \brief Set the dose image as an ITK image. */ void set_dose_image (const FloatImageType::Pointer image); /*! \brief Set the units for dose image. */ void set_dose_units (enum Dvh_units units); /*! \brief Set the units for dvh computation. Normalization in either percent or voxels, choice of cumulative or differential histogram, number of bins, and bin width. */ void set_dvh_parameters (enum Dvh_normalization normalization, enum Histogram_type histogram_type, int num_bins, float bin_width); ///@} /*! \name Execution */ ///@{ /*! \brief Compute dvh */ void run (); ///@} /*! \name Outputs */ ///@{ /*! \brief Save the DVH as a csv file */ void save_csv (const char* csv_fn); ///@} }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/dvh_p.h000066400000000000000000000013441321604176500270470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _dvh_p_h_ #define _dvh_p_h_ #include "plmutil_config.h" #include #include "dvh.h" #include "itk_image_type.h" #include "plm_image.h" class Segmentation; class Dvh_private { public: Dvh_private (); ~Dvh_private (); public: Segmentation *rtss; Plm_image::Pointer dose; enum Dvh::Dvh_units dose_units; enum Dvh::Dvh_normalization normalization; enum Dvh::Histogram_type histogram_type; int num_bins; float bin_width; std::string output_string; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/gabor.cxx000066400000000000000000000020631321604176500274130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include "fftw3.h" #include "gabor.h" #include "direction_cosines.h" #include "plm_image_header.h" class Gabor_private { public: Plm_image_header pih; public: Gabor_private () { plm_long dim[3]; float origin[3]; float spacing[3]; Direction_cosines dc; for (int d = 0; d < 3; d++) { dim[d] = 10; origin[d] = 0.f; spacing[d] = 1.f; } this->pih.set (dim, origin, spacing, dc); } }; Gabor::Gabor () { d_ptr = new Gabor_private; } Gabor::~Gabor () { delete d_ptr; } Plm_image::Pointer Gabor::get_filter () { Plm_image::Pointer f = Plm_image::New ( PLM_IMG_TYPE_GPUIT_FLOAT, d_ptr->pih); float *img = f->get_volume_float()->get_raw (); UNUSED_VARIABLE (img); return f; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/gabor.h000066400000000000000000000007431321604176500270430ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gabor_h_ #define _gabor_h_ #include "plmutil_config.h" #include "plm_image.h" class Gabor_private; class Gabor { public: Gabor_private *d_ptr; public: Gabor (); ~Gabor (); public: Plm_image::Pointer get_filter (); }; #endif gamma_dose_comparison.cxx000066400000000000000000001037561321604176500326030ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include #include #include #include "itkImageRegionIteratorWithIndex.h" #include "itkImageRegion.h" #include "gamma_dose_comparison.h" #include "itk_resample.h" #include "itk_threshold.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_math.h" #include "string_util.h" //21 = 20 +1, to make a room for >2.0 histogram #define MAX_NUM_HISTOGRAM_BIN 21 /*! \enum Gamma_output_mode Selector for output image type (gamma, or binary pass/fail) */ enum Gamma_labelmap_mode { NONE, /*!< disable output binary uchar labelmap for gamma */ PASS, /*!< output binary (1/0) image of type uchar, 1 if gamma<1 */ FAIL /*!< output binary (1/0) image of type uchar, 1 if gamma>1 */ }; class Gamma_dose_comparison_private { public: Gamma_dose_comparison_private () { labelmap_out = 0; have_gamma_image = false; gamma_image = Plm_image::New(); dta_tolerance = 3.0; dose_difference_tolerance = 0.03; gamma_max = 2.0; mode = NONE; have_reference_dose = false; reference_dose = 0.f; dose_max = 0.f; have_analysis_thresh = false; analysis_thresh = 0.f; analysis_num_vox = 0; analysis_num_pass = 0; str_gamma_report =""; b_local_gamma = false; b_compute_full_region = false; f_inherent_resample_mm = -1.0; voxels_in_mask = 0; voxels_in_image = 0; b_resample_nn = false; b_interp_search = false; b_ref_only_threshold = false; for (int i = 0; i < MAX_NUM_HISTOGRAM_BIN; i++) { arr_gamma_histo[i] = 0; } progress_callback = 0; } public: Plm_image::Pointer img_in1; /*!< input dose image 1 for gamma analysis*/ Plm_image::Pointer img_in2; /*!< input dose image 2 for gamma analysis*/ Plm_image::Pointer img_mask; /*!< input mask image for gamma analysis*/ Plm_image *labelmap_out; /*!< output uchar type labelmap, voxel value = 1/0 for pass/fail */ /* Gamma image is float type image, voxel value = calculated gamma value */ bool have_gamma_image; Plm_image::Pointer gamma_image; /* distance-to-agreement (DTA) criterion, input parameter */ float dta_tolerance; /* dose-difference criterion, in percent. Either as percent of prescription (as requested by user), or as percent of computed dose_max */ float dose_difference_tolerance; /* maximum gamma to calculate */ float gamma_max; Gamma_labelmap_mode mode; /*!< output mode selector for 3D Slicer plugin*/ /* reference dose value, used for gamma analysis and analysis thresholding. */ bool have_reference_dose; float reference_dose; /* maximum dose (max voxel value) in the reference dose, set by find_reference_max_dose() */ float dose_max; /* analysis thresholding, limits statistics to dose values above the threshold */ bool have_analysis_thresh; float analysis_thresh; plm_long analysis_num_vox; plm_long analysis_num_pass; /*extended features by YK*/ std::string str_gamma_report; //used option information, gamma histogram bool b_local_gamma; bool b_compute_full_region; float f_inherent_resample_mm; bool b_ref_only_threshold;//this option is needed for a situation where a ref region is below threshold and comp region is above threshold. plm_long voxels_in_mask; plm_long voxels_in_image; bool b_resample_nn; bool b_interp_search; //0~ max (default: 2.0), bin size: 0.1 int arr_gamma_histo[MAX_NUM_HISTOGRAM_BIN]; /* callback routine for updating progress bar in SlicerRT */ void (*progress_callback) (float); public: void do_mask_threshold (); void find_reference_max_dose (); void do_gamma_analysis (); void do_gamma_threshold (); void compose_report();//fill str_gamma_report; }; Gamma_dose_comparison::Gamma_dose_comparison () { d_ptr = new Gamma_dose_comparison_private; } Gamma_dose_comparison::~Gamma_dose_comparison () { delete d_ptr; } void Gamma_dose_comparison::set_reference_image (const char* image_fn) { d_ptr->img_in1 = Plm_image::New (image_fn); } void Gamma_dose_comparison::set_reference_image (const FloatImageType::Pointer image) { d_ptr->img_in1 = Plm_image::New (image); } void Gamma_dose_comparison::set_reference_image (const Plm_image::Pointer& image) { d_ptr->img_in1 = image; } void Gamma_dose_comparison::set_compare_image (const char* image_fn) { d_ptr->img_in2 = Plm_image::New (image_fn); } void Gamma_dose_comparison::set_compare_image (const Plm_image::Pointer& image) { d_ptr->img_in2 = image; } void Gamma_dose_comparison::set_compare_image (const FloatImageType::Pointer image) { d_ptr->img_in2 = Plm_image::New (image); } void Gamma_dose_comparison::set_mask_image (const std::string& image_fn) { d_ptr->img_mask = Plm_image::New (image_fn); } void Gamma_dose_comparison::set_mask_image (const char* image_fn) { d_ptr->img_mask = Plm_image::New (image_fn); } void Gamma_dose_comparison::set_mask_image (const Plm_image::Pointer& image) { d_ptr->img_mask = image; } void Gamma_dose_comparison::set_mask_image (const UCharImageType::Pointer image) { d_ptr->img_mask = Plm_image::New (image); } float Gamma_dose_comparison::get_spatial_tolerance () { return d_ptr->dta_tolerance; } void Gamma_dose_comparison::set_spatial_tolerance (float spatial_tol) { d_ptr->dta_tolerance = spatial_tol; } float Gamma_dose_comparison::get_dose_difference_tolerance () { return d_ptr->dose_difference_tolerance; } void Gamma_dose_comparison::set_dose_difference_tolerance (float dose_tol) { d_ptr->dose_difference_tolerance = dose_tol; } void Gamma_dose_comparison::set_reference_dose (float dose) { d_ptr->reference_dose = dose; d_ptr->have_reference_dose = true; } void Gamma_dose_comparison::set_analysis_threshold (float thresh) { d_ptr->have_analysis_thresh = true; d_ptr->analysis_thresh = thresh; //0.1 = 10% } void Gamma_dose_comparison::set_gamma_max (float gamma_max) { d_ptr->gamma_max = gamma_max; } void Gamma_dose_comparison::set_progress_callback ( void (*progress_callback)(float)) { d_ptr->progress_callback = progress_callback; } void Gamma_dose_comparison::run () { if (!d_ptr->have_reference_dose) { d_ptr->find_reference_max_dose (); d_ptr->reference_dose = d_ptr->dose_max; } d_ptr->have_gamma_image = true; //Edited by YK // if the reference image is too sparse, resample it with smaller // spacing. (e.g. 1 mm) if (d_ptr->f_inherent_resample_mm > 0.0){ float spacing[3]; spacing[0] = d_ptr->f_inherent_resample_mm; spacing[1] = d_ptr->f_inherent_resample_mm; spacing[2] = d_ptr->f_inherent_resample_mm; resample_image_with_fixed_spacing(d_ptr->img_in1, spacing); } // Resample mask if (d_ptr->img_mask) { // Set values to either 1 or 0 d_ptr->do_mask_threshold (); // Resample as float resample_image_to_reference (d_ptr->img_in1, d_ptr->img_mask); // Threshold float image at value of 0.5 d_ptr->img_mask->set_itk ( itk_threshold_above (d_ptr->img_mask->itk_float(), 0.5)); } resample_image_to_reference (d_ptr->img_in1, d_ptr->img_in2); lprintf("Gamma calculation is under progress...\n"); //YKdebug //d_ptr->img_in1->save_image(""); //d_ptr->img_in2->save_image(""); //YKdebug d_ptr->do_gamma_analysis (); //compose a report string d_ptr->compose_report(); } Plm_image::Pointer Gamma_dose_comparison::get_gamma_image () { if (!d_ptr->have_gamma_image) { this->run(); } return d_ptr->gamma_image; } FloatImageType::Pointer Gamma_dose_comparison::get_gamma_image_itk () { return get_gamma_image()->itk_float(); } Plm_image* Gamma_dose_comparison::get_pass_image () { if (!d_ptr->have_gamma_image) { this->run(); } d_ptr->mode = PASS; d_ptr->do_gamma_threshold (); return d_ptr->labelmap_out; } UCharImageType::Pointer Gamma_dose_comparison::get_pass_image_itk () { return get_pass_image()->itk_uchar(); } Plm_image* Gamma_dose_comparison::get_fail_image () { if (!d_ptr->have_gamma_image) { this->run(); } d_ptr->mode = FAIL; d_ptr->do_gamma_threshold (); return d_ptr->labelmap_out; } UCharImageType::Pointer Gamma_dose_comparison::get_fail_image_itk () { return get_fail_image()->itk_uchar(); } float Gamma_dose_comparison::get_pass_fraction () { if (d_ptr->analysis_num_vox < 1) { return 0.f; } return d_ptr->analysis_num_pass / (float) d_ptr->analysis_num_vox; } int Gamma_dose_comparison::get_analysis_num_vox() { return (int)d_ptr->analysis_num_vox; } int Gamma_dose_comparison::get_passed_num_vox() { return (int)d_ptr->analysis_num_pass; } float Gamma_dose_comparison::get_reference_dose() { return (float)d_ptr->reference_dose; } void Gamma_dose_comparison::resample_image_to_reference ( const Plm_image::Pointer& image_reference, Plm_image::Pointer& image_moving) { Plm_image_header pih; pih.set_from_plm_image (image_reference); itk::Image::Pointer resampledMovingImage = resample_image ( image_moving->itk_float(), &pih, 0.f, !this->is_resample_nn() ); image_moving->set_itk(resampledMovingImage); } void Gamma_dose_comparison::resample_image_with_fixed_spacing ( Plm_image::Pointer& input_img, float spacing[3]) { Plm_image_header pih; pih.set_from_plm_image (input_img); ///* Auto-adjust, keep same image extent */ float extent[3]; pih.get_image_extent (extent); plm_long new_dim[3]; for (int d = 0; d < 3; d++) { new_dim[d] = 1 + FLOOR_PLM_LONG (extent[d] / spacing[d]); } pih.set_spacing(spacing); pih.set_dim (new_dim); itk::Image::Pointer resampledImage = resample_image ( input_img->itk_float(), &pih, 0.f, !this->is_resample_nn() ); input_img->set_itk(resampledImage); } /* ------------------------------------------------------------------------- Private functions ------------------------------------------------------------------------- */ void Gamma_dose_comparison_private::find_reference_max_dose () { FloatImageType::Pointer itk_1 = img_in1->itk_float(); typedef itk::ImageRegionIteratorWithIndex< FloatImageType > FloatIteratorType; typedef itk::ImageRegion<3> FloatRegionType; FloatRegionType all_of_img1 = itk_1->GetLargestPossibleRegion(); FloatIteratorType itk_1_iterator (itk_1, all_of_img1); float maxlevel1=-1e20; for (itk_1_iterator.GoToBegin(); !itk_1_iterator.IsAtEnd(); ++itk_1_iterator) { float level1 = itk_1_iterator.Get(); if (level1 > maxlevel1) maxlevel1 = level1; } this->dose_max = maxlevel1; lprintf ("Gamma dose max is %f\n", this->dose_max); } void Gamma_dose_comparison_private::do_gamma_analysis () { float spacing_in[3], origin_in[3]; plm_long dim_in[3]; Plm_image_header pih; float gamma; FloatImageType::Pointer itk_1 = img_in1->itk_float(); FloatImageType::Pointer itk_2 = img_in2->itk_float(); UCharImageType::Pointer mask_img; if (img_mask) { mask_img = img_mask->itk_uchar(); } pih.set_from_itk_image (itk_1); pih.get_dim (dim_in); pih.get_origin (origin_in); pih.get_spacing (spacing_in); // Create ITK image for gamma output, "pass", "fail" and combined FloatImageType::SizeType sz; FloatImageType::IndexType st; FloatImageType::RegionType rg; FloatImageType::PointType og; FloatImageType::SpacingType sp; FloatImageType::DirectionType dc; for (int d1 = 0; d1 < 3; d1++) { st[d1] = 0; sz[d1] = dim_in[d1]; sp[d1] = spacing_in[d1]; og[d1] = origin_in[d1]; } rg.SetSize (sz); rg.SetIndex (st); dc = pih.GetDirection(); FloatImageType::Pointer gamma_img = FloatImageType::New(); UCharImageType::Pointer gamma_labelmap = UCharImageType::New(); gamma_img->SetRegions (rg); gamma_img->SetOrigin (og); gamma_img->SetSpacing (sp); gamma_img->SetDirection (dc); gamma_img->Allocate(); gamma_labelmap->SetRegions (rg); gamma_labelmap->SetOrigin (og); gamma_labelmap->SetSpacing (sp); gamma_labelmap->SetDirection (dc); gamma_labelmap->Allocate(); typedef itk::ImageRegionIteratorWithIndex< UCharImageType > UCharIteratorType; typedef itk::ImageRegionIteratorWithIndex< FloatImageType > FloatIteratorType; typedef itk::ImageRegion<3> FloatRegionType; FloatRegionType all_of_img1 = itk_1->GetLargestPossibleRegion(); FloatRegionType all_of_img2 = itk_2->GetLargestPossibleRegion(); FloatRegionType subset_of_img2, sub2set_of_img2; FloatIteratorType itk_1_iterator (itk_1, all_of_img1); FloatIteratorType gamma_img_iterator (gamma_img, gamma_img->GetLargestPossibleRegion()); UCharIteratorType mask_img_iterator; if (mask_img) { mask_img_iterator = UCharIteratorType (mask_img, mask_img->GetLargestPossibleRegion()); } FloatImageType::IndexType k1, k2, k3; //k1: img1_pos (index), k2: img2_pos(moving, index), k3: img2_pos (moving, subregion2 for interp-search) FloatImageType::IndexType sub1_start, sub2_start; FloatImageType::OffsetType offset, sub2_offset; FloatImageType::SizeType region_size, sub2_region_size; FloatPoint3DType phys; //int reg_pixsize; float level1, level2, level3, dr2, dd2, gg; float f0,f1,f2,f3; float fixedlevel2;//corresponding position pixel value of level1 to apply threshold ////interpolated voxel position (float) for interp-search //float sub2_interp_index[3]; //float dose_diff1, dose_diff2, dose_diff3; //float p_factor;//interpolation factor for interp-search // vox-to-mm-to-gamma conversion factors // strictly, these should come from IMAGE2, not 1 f0 = spacing_in[0]/this->dta_tolerance; f0=f0*f0; f1 = spacing_in[1]/this->dta_tolerance; f1=f1*f1; f2 = spacing_in[2]/this->dta_tolerance; f2=f2*f2; // if this is 2D, f(dim) is forced to be 0 not to contribute to // gamma value below: if (dim_in[0] == 1) f0 = 0.0; if (dim_in[1] == 1) f1 = 0.0; if (dim_in[2] == 1) f2 = 0.0; // dose_difference_tolerance: e.g.: 0.03 // hence, dose_tol [Gy] // To add local-gamma feature, this should be modified // float dose_tol = this->reference_dose * this->dose_difference_tolerance; f3 = 1. / this->dose_difference_tolerance; f3 = f3*f3; // compute search region size float gmax_dist = this->dta_tolerance * this->gamma_max; offset[0] = (int) ceil (gmax_dist /fabs(spacing_in[0])); offset[1] = (int) ceil (gmax_dist /fabs(spacing_in[1])); offset[2] = (int) ceil (gmax_dist /fabs(spacing_in[2])); // for interp-search sub2_offset[0] = 1.0; sub2_offset[1] = 1.0; sub2_offset[2] = 1.0; // for 2D image this might not be necessary if itk image can deal // with boundary condition for (int i = 0; i < 3; i++) { if (dim_in[i] == 1) { offset[i] = 0.0; sub2_offset[i] = 0.0; } } //analysis_threshold in Gy float analysis_threshold_in_Gy = this->analysis_thresh * this->reference_dose; //default: if no option of analysis threshold is used: analysis_threshold = 0.0 lprintf("analysis threshold = %3.2f Gy \n", analysis_threshold_in_Gy); gamma_img_iterator.GoToBegin(); if (mask_img) { mask_img_iterator.GoToBegin(); } //This value is -1.0 in OmniproIMRT float NoProcessGammaValue = 0.0f; int idx_histo = 0; int num_histo_bin = MAX_NUM_HISTOGRAM_BIN-1; //last slot is reserved for > max_gamma cases plm_long voxels_processed = 0; voxels_in_image = pih.get_num_voxels (); voxels_in_mask = 0; //For interp-search option //Convert all the components to scaled ones //From now on, scaled gamma coordinate is used. float gamma_comp_r1[4]; // 0,1,2,3 --> X, Y, Z, dose with scaling, r1 = ref point float gamma_comp_r2[4]; // 0,1,2,3 --> X, Y, Z, dose with scaling r2 = current searching point float gamma_comp_r3[4]; //r3: sub2-region moving point float gamma_comp_rn[4]; //rn: normal_vector point (will give the smallest gamma value in gamma space) float ref_dose_general;//in local gamma option, this should be a local dose, not a reference dose. float sum_up = 0.0; float sum_down = 0.0; int i = 0; for (itk_1_iterator.GoToBegin(); !itk_1_iterator.IsAtEnd(); ++itk_1_iterator) { voxels_processed++; // skip masked out voxels // (mask may be interpolated so we use a value of 0.5 for threshold) if (mask_img) { unsigned char mask_value = mask_img_iterator.Get(); ++mask_img_iterator; // if voxel not inside mask, gamma value is 0.0 (passed) if (mask_value == 0) { //YK: is 0.0 Safe? how about -1.0? gamma_img_iterator.Set (NoProcessGammaValue); ++gamma_img_iterator; continue; } } voxels_in_mask ++; //calculate gamma for this voxel of input image level1 = itk_1_iterator.Get(); if (b_local_gamma) ref_dose_general = level1; else //global, default ref_dose_general = this->reference_dose; //by default, this is coming from ref dose (max dose if not defined) k1 = itk_1_iterator.GetIndex(); itk_1->TransformIndexToPhysicalPoint(k1, phys); itk_2->TransformPhysicalPointToIndex(phys, k2); if (b_ref_only_threshold) //don't care the corresponding pixel value fixedlevel2 = -1.0; else fixedlevel2 = itk_2->GetPixel(k2);//just for comparison to corresponding value //if this option is on, computation will be much faster because dose comparison will not be perforemd. if (!this->b_compute_full_region){ if (this->have_analysis_thresh){ //if (level1 < analysis_threshold_in_Gy){ if (level1 < analysis_threshold_in_Gy && fixedlevel2 < analysis_threshold_in_Gy){ gamma_img_iterator.Set (NoProcessGammaValue);//YK: is 0.0 Safe? how about -1.0? ++gamma_img_iterator; continue;//skip the rest of the loop. This point will not be counted in analysis } } } /*k1=itk_1_iterator.GetIndex(); itk_1->TransformIndexToPhysicalPoint( k1, phys ); itk_2->TransformPhysicalPointToIndex( phys, k2 ); */ //k2 is the voxel index of the k1's physical (mm) position in img2 // set subset_of_img2 to the following region: // k1[0]-region_size < k2[0] < k1[0]+region_size, same for y,z // assume (approx) same pix spacing in img1 and img2 // crop the region by the entire image to be safe sub1_start = k2 - offset; subset_of_img2.SetIndex(sub1_start); region_size[0] = 2 * offset[0] + 1; region_size[1] = 2 * offset[1] + 1; region_size[2] = 2 * offset[2] + 1; //seems to be fine even in 2D case subset_of_img2.SetSize (region_size); subset_of_img2.Crop (all_of_img2); FloatIteratorType itk_2_iterator (itk_2, subset_of_img2); // calculate gamma, take a minimum of ... over the subset_of_img2 gamma = 1e20; for (itk_2_iterator.GoToBegin(); !itk_2_iterator.IsAtEnd(); ++itk_2_iterator) { //original method: w/o interp-search option //k2: moving index from sub1_start k2 = itk_2_iterator.GetIndex(); level2 = itk_2_iterator.Get(); dr2 = (k2[0]-k1[0])*(k2[0]-k1[0])*f0 + (k2[1]-k1[1])*(k2[1]-k1[1])*f1 + (k2[2]-k1[2])*(k2[2]-k1[2])*f2 ; //dd2: (dose diff./D)^2 //dd2 = ((level1 - level2) / reference_dose) * ((level1 - level2) / reference_dose) * f3; // (if local gamma is on, {[(d1-d2)/d1]*100 (%) / tol_dose(%)}^2) dd2 = ((level1 - level2) / ref_dose_general) * ((level1 - level2) / ref_dose_general) * f3; // (if local gamma is on, {[(d1-d2)/d1]*100 (%) / tol_dose(%)}^2) gg = dr2 + dd2; // in this subregion, only minimum value is take. if (gg < gamma) gamma=gg; if (!this->b_interp_search) continue; ///////////////////interp-search begin//////////////// //if some option is on (e.g. interp-search) sub2_start = k2 - sub2_offset; //for 3x3x3 region of interp-search (in 3D) sub2_region_size[0] = 2 * sub2_offset[0] + 1; sub2_region_size[1] = 2 * sub2_offset[1] + 1; sub2_region_size[2] = 2 * sub2_offset[2] + 1; sub2set_of_img2.SetIndex(sub2_start); sub2set_of_img2.SetSize(sub2_region_size); sub2set_of_img2.Crop(all_of_img2); FloatIteratorType sub2_iterator(itk_2, sub2set_of_img2); //scaling to go to the gamma calculation space. all components (x,y,z,d) are now in sampe weighting / space gamma_comp_r1[0] = k1[0] * sqrt(f0); gamma_comp_r1[1] = k1[1] * sqrt(f1); gamma_comp_r1[2] = k1[2] * sqrt(f2); gamma_comp_r1[3] = level1 / ref_dose_general * sqrt(f3); gamma_comp_r2[0] = k2[0] * sqrt(f0); gamma_comp_r2[1] = k2[1] * sqrt(f1); gamma_comp_r2[2] = k2[2] * sqrt(f2); gamma_comp_r2[3] = level2 / ref_dose_general * sqrt(f3); //maximum 3x3x3 iterations for (sub2_iterator.GoToBegin(); !sub2_iterator.IsAtEnd(); ++sub2_iterator) { k3 = sub2_iterator.GetIndex(); //voxel position (pix) level3 = sub2_iterator.Get(); //Dose in Gy gamma_comp_r3[0] = k3[0] * sqrt(f0); gamma_comp_r3[1] = k3[1] * sqrt(f1); gamma_comp_r3[2] = k3[2] * sqrt(f2); gamma_comp_r3[3] = level3 / ref_dose_general * sqrt(f3); //in 4D space, find the normal vector and its crossection point on the line (r2-r3) // vector equation for the line: rx = r2 + t(r3-r2) //VECTOR PRODUCT[(rx - r1),(r2-r3)] = 0 //if t is determined, then we can get the point for gamma calculation. sum_up = 0.0; sum_down = 0.0; for (i = 0; i < 4; i++) { sum_up += (gamma_comp_r2[i] - gamma_comp_r3[i])*(gamma_comp_r2[i] - gamma_comp_r1[i]); sum_down += (gamma_comp_r2[i] - gamma_comp_r3[i])*(gamma_comp_r2[i] - gamma_comp_r3[i]); } float scalar_t = sum_up / sum_down; //Only interpolation is allowed. exterapolation should not be used. if (scalar_t > 0.0 && scalar_t < 1.0){ for (i = 0; i < 4; i++) { gamma_comp_rn[i] = gamma_comp_r2[i] + scalar_t * (gamma_comp_r3[i] - gamma_comp_r2[i]); } gg = (gamma_comp_r1[0] - gamma_comp_rn[0])*(gamma_comp_r1[0] - gamma_comp_rn[0]) + (gamma_comp_r1[1] - gamma_comp_rn[1])*(gamma_comp_r1[1] - gamma_comp_rn[1]) + (gamma_comp_r1[2] - gamma_comp_rn[2])*(gamma_comp_r1[2] - gamma_comp_rn[2]) + (gamma_comp_r1[3] - gamma_comp_rn[3])*(gamma_comp_r1[3] - gamma_comp_rn[3]); // in this subregion, only minimum value is take. if (gg < gamma) gamma = gg; }//only scalar_t is in btw. 0 and 1 (interpolation) }// end of sub2_iteration for interp-search } gamma = sqrt(gamma); //gamma_max: e.g. 2.0 if (gamma > this->gamma_max) { gamma = this->gamma_max; } gamma_img_iterator.Set (gamma); ++gamma_img_iterator; /*determine gamma histogram bin */ idx_histo = floor(gamma / gamma_max * (double)num_histo_bin); /* Get statistics */ if (this->have_analysis_thresh) { //if (level1 > analysis_threshold_in_Gy) { /* include this voxel */ /*fixedlevel2 = -1 if include hig dose Comp is off*/ if (!(level1 < analysis_threshold_in_Gy && fixedlevel2 < analysis_threshold_in_Gy)){ this->analysis_num_vox ++; if (gamma <= 1) { this->analysis_num_pass ++; } arr_gamma_histo[idx_histo]++; } } //if no analysis threshold was used: every dose point will be counted as analysis point else{ this->analysis_num_vox++; if (gamma <= 1) { this->analysis_num_pass++; } arr_gamma_histo[idx_histo]++; } if (progress_callback && voxels_processed % 1000 == 0) { progress_callback ( (float) voxels_processed / (float) this->voxels_in_image); } } /* One last time, just to be sure */ if (progress_callback) { progress_callback (1.0); } this->gamma_image->set_itk (gamma_img); } void Gamma_dose_comparison_private::do_gamma_threshold () { FloatImageType::Pointer ref_img = img_in1->itk_float(); FloatImageType::Pointer gamma_img = this->gamma_image->itk_float(); /* Create labelmap image if not already created */ if (!labelmap_out) { labelmap_out = new Plm_image; UCharImageType::Pointer gamma_labelmap = UCharImageType::New(); itk_image_header_copy (gamma_labelmap, gamma_img); gamma_labelmap->Allocate(); labelmap_out = new Plm_image (gamma_labelmap); } UCharImageType::Pointer gamma_labelmap = labelmap_out->itk_uchar(); typedef itk::ImageRegionIteratorWithIndex< UCharImageType > UCharIteratorType; typedef itk::ImageRegionIteratorWithIndex< FloatImageType > FloatIteratorType; typedef itk::ImageRegion<3> FloatRegionType; FloatIteratorType ref_it (gamma_img, ref_img->GetLargestPossibleRegion()); FloatIteratorType gam_it (gamma_img, gamma_img->GetLargestPossibleRegion()); UCharIteratorType lab_it (gamma_labelmap, gamma_labelmap->GetLargestPossibleRegion()); /* Loop through gamma image, compare against threshold */ for (ref_it.GoToBegin(), gam_it.GoToBegin(), lab_it.GoToBegin(); !ref_it.IsAtEnd(); ++ref_it, ++gam_it, ++lab_it) { float ref_dose = ref_it.Get(); float gamma = gam_it.Get(); switch (mode) { case PASS: if ((gamma >=0) && (gamma <= 1) && ref_dose > 0) { lab_it.Set (1); } else { lab_it.Set (0); } break; case FAIL: if (gamma > 1) { lab_it.Set (1); } else { lab_it.Set (0); } break; case NONE: default: lab_it.Set (0); break; } } } void Gamma_dose_comparison_private::do_mask_threshold () { UCharImageType::Pointer mask_img = img_mask->itk_uchar(); typedef itk::ImageRegionIteratorWithIndex< UCharImageType > UCharIteratorType; UCharIteratorType mask_it (mask_img, mask_img->GetLargestPossibleRegion()); /* Loop through mask image, set to either 0 or 1 */ for (mask_it.GoToBegin(); !mask_it.IsAtEnd(); ++mask_it) { unsigned char mask_val = mask_it.Get(); mask_it.Set (mask_val > 0 ? 1 : 0); } } void Gamma_dose_comparison_private::compose_report() { str_gamma_report =""; int iStrSize = 128; char itemStr[128]; std::string item; memset(itemStr, 0, iStrSize); sprintf(itemStr, "%s\t%3.2f\n", "pass_rate(%)", analysis_num_pass / (float)analysis_num_vox*100.0); str_gamma_report = str_gamma_report + std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf(itemStr, "%s\t%d\n", "interp_search", this->b_interp_search); str_gamma_report = str_gamma_report + std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf(itemStr, "%s\t%d\n", "local_gamma_on", this->b_local_gamma); str_gamma_report = str_gamma_report + std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf( itemStr, "%s\t%3.2f\n","analysis_threshold", this->analysis_thresh); str_gamma_report= str_gamma_report+std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf( itemStr, "%s\t%d\n","compute_full_region", this->b_compute_full_region); str_gamma_report= str_gamma_report+std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf(itemStr, "%s\t%d\n", "resample-nn", this->b_resample_nn); str_gamma_report = str_gamma_report + std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf( itemStr, "%s\t%3.2f\n","gamma_max", this->gamma_max); str_gamma_report= str_gamma_report+std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf( itemStr, "%s\t%3.2f\n","inherent_resample(mm)", this->f_inherent_resample_mm); str_gamma_report= str_gamma_report+std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf(itemStr, "%s\t%d\n", "ref-only-threshold", this->b_ref_only_threshold); str_gamma_report = str_gamma_report + std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf( itemStr, "%s\t%3.2f\n","reference_dose_Gy", this->reference_dose); str_gamma_report= str_gamma_report+std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf( itemStr, "%s\t%3.2f\n","dose_difference_tolerance", this->dose_difference_tolerance); str_gamma_report= str_gamma_report+std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf( itemStr, "%s\t%3.2f\n","dta_tolerance", this->dta_tolerance); str_gamma_report= str_gamma_report+std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf( itemStr, "%s\t%3.2f\n","dose_max", this->dose_max); str_gamma_report= str_gamma_report+std::string(itemStr); str_gamma_report += string_format ("%s\t%d\n","voxels_in_mask", (int) this->voxels_in_mask); str_gamma_report += string_format ("%s\t%d\n","number_of_total_voxels", (int) this->voxels_in_image); memset(itemStr, 0, iStrSize); sprintf( itemStr, "%s\t%d\n","number_of_total_voxels", (int) this->voxels_in_image); str_gamma_report= str_gamma_report+std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf(itemStr, "%s\t%d\n", "number_of_analysis_voxels", (int) this->analysis_num_vox); str_gamma_report = str_gamma_report + std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf(itemStr, "%s\t%d\n", "number_of_pass_voxels", (int) this->analysis_num_pass); str_gamma_report = str_gamma_report + std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf(itemStr, "%s\t%3.2f\n", "pass_rate(%)", analysis_num_pass / (float)analysis_num_vox*100.0); str_gamma_report = str_gamma_report + std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf(itemStr, "[BEGIN GAMMA HISTOGRAM]\n"); str_gamma_report = str_gamma_report + std::string(itemStr); //print out histogram int iMaxNumBin = MAX_NUM_HISTOGRAM_BIN-1; double bin_interval = gamma_max / (double)iMaxNumBin; for (int i = 0; i < iMaxNumBin; i++){ memset(itemStr, 0, iStrSize); sprintf(itemStr, "%3.2f-%3.2f\t%d\n", (double)i*bin_interval, (double)(i + 1)*bin_interval, arr_gamma_histo[i]); str_gamma_report = str_gamma_report + std::string(itemStr); } memset(itemStr, 0, iStrSize); sprintf(itemStr, "gamma>=%3.2f\t%d\n", (double)gamma_max, arr_gamma_histo[iMaxNumBin]); str_gamma_report = str_gamma_report + std::string(itemStr); memset(itemStr, 0, iStrSize); sprintf(itemStr, "[END GAMMA HISTOGRAM]\n"); str_gamma_report = str_gamma_report + std::string(itemStr); } std::string Gamma_dose_comparison::get_report_string() { return d_ptr->str_gamma_report; } void Gamma_dose_comparison::set_report_string(std::string& report_str) { d_ptr->str_gamma_report = report_str; } bool Gamma_dose_comparison::is_local_gamma() { return d_ptr->b_local_gamma; } void Gamma_dose_comparison::set_local_gamma(bool bLocalGamma) { d_ptr->b_local_gamma = bLocalGamma; } bool Gamma_dose_comparison::is_compute_full_region() { return d_ptr->b_compute_full_region; } void Gamma_dose_comparison::set_compute_full_region(bool b_compute_full_region) { d_ptr->b_compute_full_region = b_compute_full_region; } float Gamma_dose_comparison::get_inherent_resample_mm() { return d_ptr->f_inherent_resample_mm; } void Gamma_dose_comparison::set_inherent_resample_mm(float inherent_spacing_mm) { d_ptr->f_inherent_resample_mm = inherent_spacing_mm; } bool Gamma_dose_comparison::is_resample_nn() { return d_ptr->b_resample_nn; } void Gamma_dose_comparison::set_resample_nn(bool b_resample_nn) { d_ptr->b_resample_nn = b_resample_nn; } bool Gamma_dose_comparison::is_interp_search() { return d_ptr->b_interp_search; } void Gamma_dose_comparison::set_interp_search(bool b_interp_search) { d_ptr->b_interp_search = b_interp_search; } Plm_image* Gamma_dose_comparison::get_ref_image() { return d_ptr->img_in1.get(); } Plm_image* Gamma_dose_comparison::get_comp_image() { return d_ptr->img_in2.get(); } bool Gamma_dose_comparison::is_ref_only_threshold() { return d_ptr->b_ref_only_threshold; } void Gamma_dose_comparison::set_ref_only_threshold(bool b_ref_only_threshold) { d_ptr->b_ref_only_threshold = b_ref_only_threshold; } gamma_dose_comparison.h000066400000000000000000000170141321604176500322170ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _gamma_dose_comparison_h_ #define _gamma_dose_comparison_h_ #include "plmutil_config.h" #include "plm_image.h" #include "plm_macros.h" #include "itk_image_type.h" class Gamma_dose_comparison_private; class Plm_image; /*! \brief * The Gamma_dose_comparison class executes a comparison between * two dose distributions based on the "gamma index" defined by * Dan Low et al. in the following reference: * \n\n * Low et al, * A technique for the quantitative evaluation of dose distributions, * Med Phys. 1998 May;25(5):656-61. * \n\n * The comparison is based on searching a local neighborhood for the * most similar dose. The similarity is computed as the geometric mean * of the dose difference and spatial distance. The gamma value at * a point is then the minimum of this similarity value over the * the neighborhood. * Generally, the gamma value is normalized based on a spatial tolerance * and a dose difference tolerance such that gamma values of less than * 1.0 are acceptable, and gamma values greater than 1.0 are unacceptable. */ class PLMUTIL_API Gamma_dose_comparison { public: Gamma_dose_comparison (); ~Gamma_dose_comparison (); public: Gamma_dose_comparison_private *d_ptr; public: /*! \name Inputs */ ///@{ /*! \brief Set the reference image. The image will be loaded from the specified filename. */ void set_reference_image (const char* image_fn); /*! \brief Set the reference image as a Plm image. */ void set_reference_image (const Plm_image::Pointer& image); /*! \brief Set the reference image as an ITK image. */ void set_reference_image (const FloatImageType::Pointer image); /*! \brief Set the compare image. The image will be loaded from the specified filename. */ void set_compare_image (const char* image_fn); /*! \brief Set the compare image as a Plm image. */ void set_compare_image (const Plm_image::Pointer& image); /*! \brief Set the compare image as an ITK image. */ void set_compare_image (const FloatImageType::Pointer image); /*! \brief Set the mask image. The image will be loaded from the specified filename. */ void set_mask_image (const char* image_fn); void set_mask_image (const std::string& image_fn); /*! \brief Set the mask image as a Plm image. */ void set_mask_image (const Plm_image::Pointer& image); /*! \brief Set the mask image as an ITK image. */ void set_mask_image (const UCharImageType::Pointer image); /*! \brief Get the distance to agreement (DTA) tolerance, in mm. */ float get_spatial_tolerance (); /*! \brief Set the distance to agreement (DTA) tolerance, in mm. */ void set_spatial_tolerance (float spatial_tol); /*! \brief Get the dose difference tolerance, in float (fraction of reference dose). */ float get_dose_difference_tolerance (); /*! \brief Set the dose difference tolerance, in float type. If a reference dose (prescription dose) is specified, the dose difference tolerance is treated as a fraction of the reference dose. Otherwise it is treated as a fraction of the maximum dose in the reference volume. With local-gamma option, it is treated as a fraction of the local dose in the reference image To use a 3% dose tolerance, you would set this value to 0.03. */ void set_dose_difference_tolerance (float dose_tol); /*! \brief Set the reference dose (prescription dose). The reference dose is used for dose comparison and analysis threshold. If the reference dose is not set, the maximum dose in the reference dose volume is used as the reference dose. */ void set_reference_dose (float dose); /*! \brief Unset the reference dose (prescription dose). The reference dose is used for dose comparison and analysis threshold. If the reference dose is not set, the maximum dose in the reference dose volume is used as the reference dose. */ void unset_reference_dose (); /*! \brief Set a dose threshold for gamma analysis, as a fraction of the reference dose. This is used to ignore voxels which have dose below a certain value. For example, to consider only voxels which have dose greater than 10% of the maximum dose, you would call set_analysis_threshold (0.1). The threshold is applied to dose voxels in the reference dose volume. */ void set_analysis_threshold (float thresh); /*! \brief Set the maximum gamma computed by the class. This is used to speed up computation. A typical value is 2 or 3. */ /* */ void set_gamma_max (float gamma_max); /*! \brief Set a callback routine for reporting progress */ void set_progress_callback (void (*progress_callback)(float)); ///@} /*! \name Execution */ ///@{ /*! \brief Compute gamma value at each location in the input image */ void run (); ///@} /*! \name Outputs */ ///@{ /*! \brief Return the gamma image as a Plm_image. */ Plm_image::Pointer get_gamma_image (); /*! \brief Return the gamma image as an ITK image. */ FloatImageType::Pointer get_gamma_image_itk (); /*! \brief Return a binary image of passing voxels as a Plm image. */ Plm_image* get_pass_image (); /*! \brief Return a binary image of passing voxels as an ITK image. */ UCharImageType::Pointer get_pass_image_itk (); /*! \brief Return a binary image of failing voxels as a Plm image. */ Plm_image* get_fail_image (); /*! \brief Return a binary image of failing voxels as an ITK image. */ UCharImageType::Pointer get_fail_image_itk (); /*! \brief Return ref. image used for gamma evaluation */ Plm_image* get_ref_image(); /*! \brief Return comp. image used for gamma evaluation */ Plm_image* get_comp_image(); /*! \brief Return fraction of passing points, subject to reference dose being greater than analysis threshold */ float get_pass_fraction (); int get_analysis_num_vox(); int get_passed_num_vox(); float get_reference_dose(); ///@} std::string get_report_string(); void set_report_string(std::string& report_str); bool is_local_gamma(); void set_local_gamma(bool bLocalGamma); bool is_compute_full_region(); void set_compute_full_region(bool b_compute_full_region); float get_inherent_resample_mm(); void set_inherent_resample_mm(float inherent_spacing_mm); bool is_resample_nn(); void set_resample_nn(bool b_resample_nn); bool is_interp_search(); void set_interp_search(bool b_interp_search); bool is_ref_only_threshold(); /*! \brief By default, when analysis is limited to areas with dose higher than a percent threshold, this threshold is based on the dose in either reference or compare image. If set_ref_only_threshold() is called with a value of true, the analysis will only consider dose higher than the threshold in the compare image */ void set_ref_only_threshold(bool b_ref_only_threshold); protected: /*! \brief Resample ref image with fixed spacing */ void resample_image_with_fixed_spacing (Plm_image::Pointer& input_img, float spacing[3]); /*! \brief Resample image_moving to image_reference */ void resample_image_to_reference (const Plm_image::Pointer& image_reference, Plm_image::Pointer& image_moving); }; #endif geometry_chooser.cxx000066400000000000000000000162511321604176500316230ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "compiler_warnings.h" #include "logfile.h" #include "geometry_chooser.h" #include "itk_image_load.h" #include "itk_resample.h" #include "plm_file_format.h" #include "plm_image_header.h" class Geometry_chooser_private { public: Geometry_chooser_private () { have_dim = false; have_origin = false; have_spacing = false; have_direction_cosines = false; have_pih_fix = false; have_pih_ref = false; have_pih_cmp = false; } public: bool have_dim; bool have_origin; bool have_spacing; bool have_direction_cosines; Plm_image_header pih_manual; bool have_pih_fix; Plm_image_header pih_fix; bool have_pih_ref; Plm_image_header pih_ref; bool have_pih_cmp; Plm_image_header pih_cmp; Plm_image_header pih_best; }; Geometry_chooser::Geometry_chooser () { d_ptr = new Geometry_chooser_private; } Geometry_chooser::~Geometry_chooser () { delete d_ptr; } void Geometry_chooser::set_reference_image (const char* image_fn) { FloatImageType::Pointer image = itk_image_load_float (image_fn, 0); this->set_reference_image (image); } template void Geometry_chooser::set_reference_image ( const T& image) { d_ptr->pih_ref.set_from_itk_image (image); d_ptr->have_pih_ref = true; } void Geometry_chooser::set_compare_image (const char* image_fn) { FloatImageType::Pointer image = itk_image_load_float (image_fn, 0); this->set_compare_image (image); } void Geometry_chooser::set_compare_image ( const UCharImageType::Pointer image) { d_ptr->pih_cmp.set_from_itk_image (image); d_ptr->have_pih_cmp = true; } void Geometry_chooser::set_compare_image ( const FloatImageType::Pointer image) { d_ptr->pih_cmp.set_from_itk_image (image); d_ptr->have_pih_cmp = true; } void Geometry_chooser::set_fixed_image (const char* image_fn) { Plm_file_format ff = plm_file_format_deduce (image_fn); if (ff == PLM_FILE_FMT_VF) { DeformationFieldType::Pointer fixed = itk_image_load_float_field ( image_fn); this->set_fixed_image (fixed); } else { /* Hope for the best... */ FloatImageType::Pointer fixed = itk_image_load_float (image_fn, 0); this->set_fixed_image (fixed); } } void Geometry_chooser::set_fixed_image (const std::string& image_fn) { this->set_fixed_image (image_fn.c_str()); } template void Geometry_chooser::set_fixed_image ( const T& image) { d_ptr->pih_fix.set_from_itk_image (image); d_ptr->have_pih_fix = true; } void Geometry_chooser::set_dim (const plm_long dim[3]) { d_ptr->pih_manual.set_dim (dim); d_ptr->have_dim = true; } void Geometry_chooser::set_origin (const float origin[3]) { d_ptr->pih_manual.set_origin (origin); d_ptr->have_origin = true; } void Geometry_chooser::set_spacing (const float spacing[3]) { d_ptr->pih_manual.set_spacing (spacing); d_ptr->have_spacing = true; } void Geometry_chooser::set_direction_cosines ( const Direction_cosines& direction_cosines) { d_ptr->pih_manual.set_direction_cosines (direction_cosines); d_ptr->have_direction_cosines = true; } const Plm_image_header * Geometry_chooser::get_geometry () { if (d_ptr->have_pih_ref) { if (d_ptr->have_pih_cmp) { d_ptr->pih_best.set_geometry_to_contain ( d_ptr->pih_ref, d_ptr->pih_cmp); } else { d_ptr->pih_best.set (d_ptr->pih_ref); } } if (d_ptr->have_pih_fix) { d_ptr->pih_best.set (d_ptr->pih_fix); } if (d_ptr->have_dim) { plm_long dim[3]; d_ptr->pih_manual.get_dim (dim); /* Auto-adjust, keep same image extent */ if ((d_ptr->have_pih_ref || d_ptr->have_pih_fix) && !d_ptr->have_spacing) { float extent[3]; d_ptr->pih_best.get_image_extent (extent); float new_spacing[3]; for (int d = 0; d < 3; d++) { if (dim[d] < 2) { new_spacing[d] = 1.0; } else { new_spacing[d] = extent[d] / (dim[d] - 1); } } d_ptr->pih_best.set_spacing(new_spacing); lprintf ("Optimizing spacing: %g %g %g\n", new_spacing[0], new_spacing[1], new_spacing[2]); } d_ptr->pih_best.set_dim (dim); } if (d_ptr->have_origin) { float origin[3]; d_ptr->pih_manual.get_origin (origin); d_ptr->pih_best.set_origin (origin); } if (d_ptr->have_spacing) { float spacing[3]; d_ptr->pih_manual.get_spacing (spacing); /* Auto-adjust, keep same image extent */ if ((d_ptr->have_pih_ref || d_ptr->have_pih_fix) && !d_ptr->have_dim) { float extent[3]; d_ptr->pih_best.get_image_extent (extent); plm_long new_dim[3]; for (int d = 0; d < 3; d++) { new_dim[d] = 1 + FLOOR_PLM_LONG (extent[d] / spacing[d]); } d_ptr->pih_best.set_dim (new_dim); lprintf ("Optimizing dim: %d %d %d\n", new_dim[0], new_dim[1], new_dim[2]); } d_ptr->pih_best.set_spacing (spacing); } if (d_ptr->have_direction_cosines) { float direction_cosines[9]; d_ptr->pih_manual.get_direction_cosines (direction_cosines); d_ptr->pih_best.set_direction_cosines (direction_cosines); } return &d_ptr->pih_best; } /* Explicit instantiations */ template PLMUTIL_API void Geometry_chooser::set_fixed_image (const UCharImageType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_fixed_image (const FloatImageType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_fixed_image (const DeformationFieldType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_reference_image (const UCharImageType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_reference_image (const CharImageType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_reference_image (const UShortImageType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_reference_image (const ShortImageType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_reference_image (const UInt32ImageType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_reference_image (const Int32ImageType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_reference_image (const FloatImageType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_reference_image (const DoubleImageType::Pointer&); template PLMUTIL_API void Geometry_chooser::set_reference_image (const DeformationFieldType::Pointer&); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/geometry_chooser.h000066400000000000000000000055101321604176500313230ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _geometry_chooser_h_ #define _geometry_chooser_h_ #include "plmutil_config.h" #include "itk_image_type.h" #include "plm_int.h" class Direction_cosines; class Geometry_chooser_private; class Plm_image_header; /*! \brief * The Geometry_chooser class provides a convenient method for * choosing the right output geometry for a function. * * The output geometry is selected based on preferential selection * from a set of possible inputs which might or might not be * available. In order of preference, the geometry is set according to: * * - Manual setting of dim, origin, spacing, direction_cosines * - Copying the geometry from a specific image (called the "fixed image") * - Setting the geometry from an input image (called the "reference image") * * In the last case, the geometry can be expanded to also include the * union of the regions spanned by another image (called the "compare image") */ class PLMUTIL_API Geometry_chooser { public: Geometry_chooser (); ~Geometry_chooser (); public: Geometry_chooser_private *d_ptr; public: /*! \name Inputs */ ///@{ /*! \brief Set the reference image. The geometry will be from the specified filename. */ void set_reference_image (const char* image_fn); /*! \brief Set the reference image as an ITK image. */ template void set_reference_image (const T& image); /*! \brief Set the compare image. The image will be loaded from the specified filename. */ void set_compare_image (const char* image_fn); /*! \brief Set the compare image as an ITK image. */ void set_compare_image (const UCharImageType::Pointer image); void set_compare_image (const FloatImageType::Pointer image); /*! \brief Set the fixed image. The image will be loaded from the specified filename. */ void set_fixed_image (const char* image_fn); void set_fixed_image (const std::string& image_fn); /*! \brief Set the fixed image as an ITK image. */ template void set_fixed_image (const T& image); /*! \brief Set the image dimension (number of voxels) manually. */ void set_dim (const plm_long dim[3]); /*! \brief Set the image origin manually. */ void set_origin (const float origin[3]); /*! \brief Set the image spacing manually. */ void set_spacing (const float spacing[3]); /*! \brief Set the image direction cosines manually. */ void set_direction_cosines (const Direction_cosines& direction_cosines); ///@} /*! \name Outputs */ ///@{ /*! \brief Return the best fitting geometry */ const Plm_image_header *get_geometry (); ///@} }; #endif hausdorff_distance.cxx000066400000000000000000000232521321604176500321000ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "itkImage.h" #include "wirth.h" #include "distance_map.h" #include "hausdorff_distance.h" #include "image_boundary.h" #include "itk_image_load.h" #include "itk_image_save.h" #include "itk_resample.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "volume.h" class Hausdorff_distance_private { public: Hausdorff_distance_private () { pct_hausdorff_distance_fraction = 0.95; dmap_alg = ""; maximum_distance = FLT_MAX; vbb = ADAPTIVE_PADDING; this->clear_statistics (); } public: void clear_statistics () { hausdorff_distance = 0.f; avg_avg_hausdorff_distance = 0.f; max_avg_hausdorff_distance = 0.f; pct_hausdorff_distance = 0.f; boundary_hausdorff_distance = 0.f; avg_avg_boundary_hausdorff_distance = 0.f; max_avg_boundary_hausdorff_distance = 0.f; pct_boundary_hausdorff_distance = 0.f; } public: float hausdorff_distance; float avg_avg_hausdorff_distance; float max_avg_hausdorff_distance; float pct_hausdorff_distance; float boundary_hausdorff_distance; float avg_avg_boundary_hausdorff_distance; float max_avg_boundary_hausdorff_distance; float pct_boundary_hausdorff_distance; float pct_hausdorff_distance_fraction; std::string dmap_alg; float maximum_distance; Volume_boundary_behavior vbb; UCharImageType::Pointer ref_image; UCharImageType::Pointer cmp_image; }; Hausdorff_distance::Hausdorff_distance () { d_ptr = new Hausdorff_distance_private; } Hausdorff_distance::~Hausdorff_distance () { delete d_ptr; } void Hausdorff_distance::set_reference_image (const char* image_fn) { d_ptr->ref_image = itk_image_load_uchar (image_fn, 0); } void Hausdorff_distance::set_reference_image ( const UCharImageType::Pointer image) { d_ptr->ref_image = image; } void Hausdorff_distance::set_compare_image (const char* image_fn) { d_ptr->cmp_image = itk_image_load_uchar (image_fn, 0); } void Hausdorff_distance::set_compare_image ( const UCharImageType::Pointer image) { d_ptr->cmp_image = image; } void Hausdorff_distance::set_hausdorff_distance_fraction ( float hausdorff_distance_fraction) { d_ptr->pct_hausdorff_distance_fraction = hausdorff_distance_fraction; } void Hausdorff_distance::set_distance_map_algorithm (const std::string& dmap_alg) { d_ptr->dmap_alg = dmap_alg; } void Hausdorff_distance::set_maximum_distance (float maximum_distance) { d_ptr->maximum_distance = maximum_distance; } void Hausdorff_distance::set_volume_boundary_behavior (Volume_boundary_behavior vbb) { d_ptr->vbb = vbb; } void Hausdorff_distance::run_internal ( UCharImageType::Pointer image1, UCharImageType::Pointer image2 ) { /* Compute distance map */ Distance_map dmap_filter; dmap_filter.set_algorithm (d_ptr->dmap_alg); dmap_filter.set_input_image (image2); dmap_filter.set_inside_is_positive (false); dmap_filter.set_use_squared_distance (false); dmap_filter.set_maximum_distance (d_ptr->maximum_distance); dmap_filter.set_volume_boundary_behavior (d_ptr->vbb); dmap_filter.run (); FloatImageType::Pointer dmap = dmap_filter.get_output_image (); /* Convert to Plm_image type */ Plm_image pli_uchar (image1); Volume::Pointer vol_uchar = pli_uchar.get_volume_uchar (); unsigned char *img_uchar = (unsigned char*) vol_uchar->img; Plm_image pli_dmap (dmap); Volume::Pointer vol_dmap = pli_dmap.get_volume_float (); float *img_dmap = (float*) vol_dmap->img; /* Find boundary pixels */ Image_boundary ib; ib.set_volume_boundary_behavior (d_ptr->vbb); ib.set_input_image (image1); ib.run (); UCharImageType::Pointer itk_ib = ib.get_output_image (); /* Convert to plm_image */ Plm_image pli_ib (itk_ib); Volume::Pointer vol_ib = pli_ib.get_volume_uchar (); unsigned char *img_ib = (unsigned char*) vol_ib->img; /* Make an array to store the distances */ float *h_distance_array = new float[vol_uchar->npix]; float *bh_distance_array = new float[vol_uchar->npix]; /* Loop through voxels, find distances */ float max_h_distance = 0; float max_bh_distance = 0; double sum_h_distance = 0; double sum_bh_distance = 0; plm_long num_h_vox = 0; plm_long num_bh_vox = 0; for (plm_long i = 0; i < vol_uchar->npix; i++) { if (!img_uchar[i]) { continue; } /* Get distance map value for this voxel */ float h_dist = img_dmap[i]; /* dist for set hausdorff */ float bh_dist = img_dmap[i]; /* dist for boundary hausdorff */ if (img_dmap[i] < 0) { h_dist = 0; bh_dist = - bh_dist; } /* Update statistics for hausdorff */ if (h_dist > max_h_distance) { max_h_distance = h_dist; } sum_h_distance += h_dist; h_distance_array[num_h_vox] = h_dist; num_h_vox ++; /* Update statistics for boundary hausdorff */ if (img_ib[i]) { if (bh_dist > max_bh_distance) { max_bh_distance = bh_dist; } sum_bh_distance += bh_dist; bh_distance_array[num_bh_vox] = bh_dist; num_bh_vox ++; } } /* Figure out HD95 stuff */ float h_pct = 0, bh_pct = 0; if (num_h_vox > 0) { int ordinal = (int) floor ( d_ptr->pct_hausdorff_distance_fraction * num_h_vox-1); if (ordinal > num_h_vox - 1) { ordinal = num_h_vox - 1; } h_pct = kth_smallest (h_distance_array, num_h_vox, ordinal); } if (num_bh_vox > 0) { int ordinal = (int) floor ( d_ptr->pct_hausdorff_distance_fraction * num_bh_vox-1); if (ordinal > num_bh_vox - 1) { ordinal = num_bh_vox - 1; } bh_pct = kth_smallest (bh_distance_array, num_bh_vox, ordinal); } /* Record results */ if (max_h_distance > d_ptr->hausdorff_distance) { d_ptr->hausdorff_distance = max_h_distance; } if (max_bh_distance > d_ptr->boundary_hausdorff_distance) { d_ptr->boundary_hausdorff_distance = max_bh_distance; } if (num_h_vox > 0) { float ahd = sum_h_distance / num_h_vox; d_ptr->avg_avg_hausdorff_distance += 0.5 * ahd; d_ptr->max_avg_hausdorff_distance = std::max ( d_ptr->max_avg_hausdorff_distance, ahd); d_ptr->pct_hausdorff_distance += 0.5 * h_pct; } if (num_bh_vox > 0) { float abhd = sum_bh_distance / num_bh_vox; d_ptr->avg_avg_boundary_hausdorff_distance += 0.5 * abhd; d_ptr->max_avg_boundary_hausdorff_distance = std::max ( d_ptr->max_avg_boundary_hausdorff_distance, abhd); d_ptr->pct_boundary_hausdorff_distance += 0.5 * bh_pct; } delete[] h_distance_array; delete[] bh_distance_array; } void Hausdorff_distance::run () { /* Resample and/or expand images based on geometry of reference */ if (!itk_image_header_compare (d_ptr->ref_image, d_ptr->cmp_image)) { Plm_image_header pih; pih.set_geometry_to_contain ( Plm_image_header (d_ptr->cmp_image), Plm_image_header (d_ptr->ref_image)); d_ptr->cmp_image = resample_image (d_ptr->cmp_image, pih, 0, 0); d_ptr->ref_image = resample_image (d_ptr->ref_image, pih, 0, 0); } d_ptr->clear_statistics (); this->run_internal (d_ptr->ref_image, d_ptr->cmp_image); this->run_internal (d_ptr->cmp_image, d_ptr->ref_image); } float Hausdorff_distance::get_hausdorff () { return d_ptr->hausdorff_distance; } float Hausdorff_distance::get_avg_average_hausdorff () { return d_ptr->avg_avg_hausdorff_distance; } float Hausdorff_distance::get_max_average_hausdorff () { return d_ptr->max_avg_hausdorff_distance; } float Hausdorff_distance::get_percent_hausdorff () { return d_ptr->pct_hausdorff_distance; } float Hausdorff_distance::get_boundary_hausdorff () { return d_ptr->boundary_hausdorff_distance; } float Hausdorff_distance::get_avg_average_boundary_hausdorff () { return d_ptr->avg_avg_boundary_hausdorff_distance; } float Hausdorff_distance::get_max_average_boundary_hausdorff () { return d_ptr->max_avg_boundary_hausdorff_distance; } float Hausdorff_distance::get_percent_boundary_hausdorff () { return d_ptr->pct_boundary_hausdorff_distance; } void Hausdorff_distance::debug () { lprintf ( "Hausdorff distance = %f\n" "Avg average Hausdorff distance = %f\n" "Max average Hausdorff distance = %f\n" "Percent (%.2f) Hausdorff distance = %f\n" "Hausdorff distance (boundary) = %f\n" "Avg average Hausdorff distance (boundary) = %f\n" "Max average Hausdorff distance (boundary) = %f\n" "Percent (%.2f) Hausdorff distance (boundary) = %f\n", this->get_hausdorff (), this->get_avg_average_hausdorff (), this->get_max_average_hausdorff (), d_ptr->pct_hausdorff_distance_fraction, this->get_percent_hausdorff (), this->get_boundary_hausdorff (), this->get_avg_average_boundary_hausdorff (), this->get_max_average_boundary_hausdorff (), d_ptr->pct_hausdorff_distance_fraction, this->get_percent_boundary_hausdorff () ); } void do_hausdorff ( UCharImageType::Pointer image_1, UCharImageType::Pointer image_2 ) { Hausdorff_distance hd; hd.set_reference_image (image_1); hd.set_compare_image (image_2); hd.run (); hd.debug (); } hausdorff_distance.h000066400000000000000000000136001321604176500315210ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _hausdorff_distance_h_ #define _hausdorff_distance_h_ #include "plmutil_config.h" #include "itk_image.h" #include "volume_boundary_behavior.h" class Plm_image; class Hausdorff_distance_private; /*! \brief * The Hausdorff class computes the worst-case distance between * two regions. There are many variants of the Hausdorff. * See for example: * * "A Modified Hausdorff Distance for Object Matching," * MP Dubuisson and AK Jain, * Proc. International Conference on Pattern Recognition, pp 566–568, 1994. * * To understand the variants, we first define the directed Hausdorff * and the boundary Hausdorff. * * The directed Hausdorff measure from X to Y is defined as the * maximum distance, for all points in X, to the closest point in Y. * Mathematically this is given as: * * \f[ * \vec{d}_{H}(X,Y) = \max_{x \in X} { \min_{y \in Y} d (x,y) } * \f] * * The (undirected) Hausdorff distance is the maximum of the two directed * Hausdorff measures. * * \f[ * d_H(X,Y) = \max \left\{ \vec{d}_{H}(X,Y), \vec{d}_{H}(Y,X) \right\} * \f] * * The (directed or undirected) boundary Hausdorff is a * Hausdorff distance which is computed on the boundary of a set * rather than the set itself. For example, the (undirected) * boundary Hausdorff distance is given as: * * \f[ * d_H(\partial X,\partial Y) * \f] * * The directed average Hausdorff measure is the average distance of * a point in X to its closest point in Y. That is: * * \f[ * \vec{d}_{H,\mathrm{avg}}(X,Y) = \frac{1}{|X|} \sum_{x \in X} \min_{y \in Y} d (x,y) * \f] * * The (undirected) average Hausdorff measure is the average * of the two directed average Hausdorff measures: * * \f[ * d_{H,\mathrm{avg}}(X,Y) = \frac{\vec{d}_{H,\mathrm{avg}}(X,Y) + \vec{d}_{H,\mathrm{avg}}(Y,X)}{2} * \f] * * The (undirected) max average Hausdorff measure is the maximum * of the two directed average Hausdorff measures: * * \f[ * d_{H,\mathrm{m-avg}}(X,Y) = \max \left\{ \vec{d}_{H,\mathrm{avg}}(X,Y) , \vec{d}_{H,\mathrm{avg}}(Y,X) \right\} * \f] * * The directed percent Hausdorff measure, for a percentile \f$r\f$, * is the \f$r\f$th percentile distance over all distances from points * in X to their closest point in Y. For example, the directed 95% * Hausdorff distance is the point in X with distance to its closest * point in Y is greater or equal to exactly 95% of the other points in X. * In mathematical terms, denoting the * \f$r\f$th percentile as * \f$K_r\f$, this is given as: * * \f[ * \vec{d}_{H,r}(X,Y) = K_{r} \left( \min_{y \in Y} d (x,y) \right) \forall x \in X * \f] * * The (undirected) percent Hausdorff measure is defined again with the mean: * * \f[ * d_{H,r}(X,Y) = \frac{\vec{d}_{H,r}(X,Y) + \vec{d}_{H,r}(Y,X)}{2} * \f] * * If the images do not have the same size and resolution, the compare * image will be resampled onto the reference image geometry prior * to comparison. */ class PLMUTIL_API Hausdorff_distance { public: Hausdorff_distance (); ~Hausdorff_distance (); public: Hausdorff_distance_private *d_ptr; public: /*! \name Inputs */ ///@{ /*! \brief Set the reference image. The image will be loaded from the specified filename. */ void set_reference_image (const char* image_fn); /*! \brief Set the reference image as an ITK image. */ void set_reference_image (const UCharImageType::Pointer image); /*! \brief Set the compare image. The image will be loaded from the specified filename. */ void set_compare_image (const char* image_fn); /*! \brief Set the compare image as an ITK image. */ void set_compare_image (const UCharImageType::Pointer image); /*! \brief Set the fraction of voxels to include when computing the percent hausdorff distance. The input value should be a number between 0 and 1. The default value is 0.95. */ void set_hausdorff_distance_fraction ( float hausdorff_distance_fraction); /*! \brief Choose which distance map algorithm to use */ void set_distance_map_algorithm (const std::string& dmap_alg); /*! \brief Choose the maximum distance that is returned when computing the distance map */ void set_maximum_distance (float maximum_distance); /*! \brief Set the volume boundary behavior, either ZERO_PADDING, EDGE_PADDING, or ADAPTIVE_PADDING */ void set_volume_boundary_behavior (Volume_boundary_behavior vbb); ///@} /*! \name Execution */ ///@{ /*! \brief Compute hausdorff distances */ void run (); ///@} /*! \name Outputs */ ///@{ /*! \brief Return the Hausdorff distance */ float get_hausdorff (); /*! \brief Return the average Hausdorff distance */ float get_avg_average_hausdorff (); /*! \brief Return the max average Hausdorff distance */ float get_max_average_hausdorff (); /*! \brief Return the percent Hausdorff distance */ float get_percent_hausdorff (); /*! \brief Return the boundary Hausdorff distance */ float get_boundary_hausdorff (); /*! \brief Return the average boundary Hausdorff distance */ float get_avg_average_boundary_hausdorff (); /*! \brief Return the max average boundary Hausdorff distance */ float get_max_average_boundary_hausdorff (); /*! \brief Return the percent boundary Hausdorff distance */ float get_percent_boundary_hausdorff (); /*! \brief Display debugging information to stdout */ void debug (); ///@} protected: void run_internal ( UCharImageType::Pointer image1, UCharImageType::Pointer image2); }; PLMUTIL_API void do_hausdorff( UCharImageType::Pointer image_1, UCharImageType::Pointer image_2); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/image_boundary.cxx000066400000000000000000000135141321604176500313110ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "itkImage.h" #include "image_boundary.h" #include "itk_image_load.h" #include "plm_image.h" #include "plm_image_header.h" #include "volume.h" #include "volume_boundary_behavior.h" class Image_boundary_private { public: Image_boundary_private () { vbb = ADAPTIVE_PADDING; } public: UCharImageType::Pointer input_image; UCharImageType::Pointer output_image; Volume_boundary_behavior vbb; public: void run (); protected: unsigned char classify_zp ( const Volume::Pointer& vol_in, const unsigned char *img_in, plm_long i, plm_long j, plm_long k, plm_long v) { /* If not inside volume, then not on boundary */ if (!img_in[v]) { return 0; } /* Non-zero edge pixels are boundary */ if (k == 0 || k == vol_in->dim[2]-1 || j == 0 || j == vol_in->dim[1]-1 || i == 0 || i == vol_in->dim[0]-1) { return 1; } /* Look for neighboring zero voxel in six-neighborhood */ if (img_in[volume_index (vol_in->dim, i-1, j, k)] == 0) { return 1; } if (img_in[volume_index (vol_in->dim, i+1, j, k)] == 0) { return 1; } if (img_in[volume_index (vol_in->dim, i, j-1, k)] == 0) { return 1; } if (img_in[volume_index (vol_in->dim, i, j+1, k)] == 0) { return 1; } if (img_in[volume_index (vol_in->dim, i, j, k-1)] == 0) { return 1; } if (img_in[volume_index (vol_in->dim, i, j, k+1)] == 0) { return 1; } return 0; } unsigned char classify_ep ( const Volume::Pointer& vol_in, const unsigned char *img_in, plm_long i, plm_long j, plm_long k, plm_long v) { /* If not inside volume, then not on boundary */ if (!img_in[v]) { return 0; } return 0; } unsigned char classify_ap ( const Volume::Pointer& vol_in, const unsigned char *img_in, plm_long i, plm_long j, plm_long k, plm_long v) { /* If not inside volume, then not on boundary */ if (!img_in[v]) { return 0; } /* Check for non-zero edge pixels; these are boundary if dimension > 1 */ if (vol_in->dim[2] > 1 && (k == 0 || k == vol_in->dim[2]-1) || vol_in->dim[1] > 1 && (j == 0 || j == vol_in->dim[1]-1) || vol_in->dim[0] > 1 && (i == 0 || i == vol_in->dim[0]-1)) { return 1; } /* Look for neighboring zero voxel in six-neighborhood, ignoring voxels beyond boundary */ if (i != 0 && img_in[volume_index (vol_in->dim, i-1, j, k)] == 0) { return 1; } if (i != vol_in->dim[0]-1 && img_in[volume_index (vol_in->dim, i+1, j, k)] == 0) { return 1; } if (j != 0 && img_in[volume_index (vol_in->dim, i, j-1, k)] == 0) { return 1; } if (j != vol_in->dim[1]-1 && img_in[volume_index (vol_in->dim, i, j+1, k)] == 0) { return 1; } if (k != 0 && img_in[volume_index (vol_in->dim, i, j, k-1)] == 0) { return 1; } if (k != vol_in->dim[2]-1 && img_in[volume_index (vol_in->dim, i, j, k+1)] == 0) { return 1; } return 0; } }; void Image_boundary_private::run () { /* Convert to Plm_image type */ Plm_image pli_in (this->input_image); Volume::Pointer vol_in = pli_in.get_volume_uchar (); unsigned char *img_in = (unsigned char*) vol_in->img; /* Allocate output image */ Plm_image::Pointer pli_out = pli_in.clone (); Volume::Pointer vol_out = pli_out->get_volume_uchar (); unsigned char *img_out = (unsigned char*) vol_out->img; /* Compute the boundary */ for (plm_long k = 0, v = 0; k < vol_in->dim[2]; k++) { for (plm_long j = 0; j < vol_in->dim[1]; j++) { for (plm_long i = 0; i < vol_in->dim[0]; i++, v++) { switch (this->vbb) { case ZERO_PADDING: img_out[v] = classify_zp (vol_in, img_in, i, j, k, v); break; case EDGE_PADDING: img_out[v] = classify_ep (vol_in, img_in, i, j, k, v); break; case ADAPTIVE_PADDING: default: img_out[v] = classify_ap (vol_in, img_in, i, j, k, v); break; } } } } /* Save the output image */ this->output_image = pli_out->itk_uchar (); } Image_boundary::Image_boundary () { d_ptr = new Image_boundary_private; } Image_boundary::~Image_boundary () { delete d_ptr; } void Image_boundary::set_input_image (const char* image_fn) { d_ptr->input_image = itk_image_load_uchar (image_fn, 0); } void Image_boundary::set_input_image ( const UCharImageType::Pointer image) { d_ptr->input_image = image; } void Image_boundary::set_volume_boundary_behavior (Volume_boundary_behavior vbb) { d_ptr->vbb = vbb; } void Image_boundary::run () { d_ptr->run (); } UCharImageType::Pointer Image_boundary::get_output_image () { return d_ptr->output_image; } UCharImageType::Pointer do_image_boundary (UCharImageType::Pointer image) { Image_boundary ib; ib.set_input_image (image); ib.run (); return ib.get_output_image (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/image_boundary.h000066400000000000000000000033001321604176500307260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _image_boundary_h_ #define _image_boundary_h_ #include "plmutil_config.h" #include "itk_image.h" #include "volume_boundary_behavior.h" class Plm_image; class Image_boundary_private; /*! \brief * The Image_boundary class takes an input image (binary) and computes * an output image. Voxels of the output image will be one * if they are (1) non-zero in the input image, and (2) have a zero * voxel in their six-neighborhood. Other output image voxels will have * value zero. */ class PLMUTIL_API Image_boundary { public: Image_boundary (); ~Image_boundary (); public: Image_boundary_private *d_ptr; public: /*! \name Inputs */ ///@{ /*! \brief Set the input image. The image will be loaded from the specified filename. */ void set_input_image (const char* image_fn); /*! \brief Set the input image as an ITK image. */ void set_input_image (const UCharImageType::Pointer image); /*! \brief Set the volume boundary behavior, either ZERO_PADDING, EDGE_PADDING, or ADAPTIVE_PADDING */ void set_volume_boundary_behavior (Volume_boundary_behavior vbb); ///@} /*! \name Execution */ ///@{ /*! \brief Compute image boundary */ void run (); ///@} /*! \name Outputs */ ///@{ /*! \brief Return the boundary image as an ITK image. */ UCharImageType::Pointer get_output_image (); ///@} }; PLMUTIL_API UCharImageType::Pointer do_image_boundary (UCharImageType::Pointer image); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/image_center.cxx000066400000000000000000000047101321604176500307440ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageMomentsCalculator.h" #include "itkImageRegionIteratorWithIndex.h" #include "itkImageSliceConstIteratorWithIndex.h" #include "compiler_warnings.h" #include "image_center.h" #include "itk_image.h" #include "itk_image_load.h" #include "itk_image_save.h" #include "itk_resample.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "volume.h" class Image_center_private { public: DoubleVector3DType center_of_mass; Plm_image::Pointer image; }; Image_center::Image_center () { d_ptr = new Image_center_private; } Image_center::~Image_center () { delete d_ptr; } void Image_center::set_image ( const UCharImageType::Pointer& image) { d_ptr->image = Plm_image::New(image); } void Image_center::set_image ( const Plm_image::Pointer& pli) { d_ptr->image = pli; } void Image_center::run () { /* Convert image to Volume type */ Volume::Pointer vol = d_ptr->image->get_volume_uchar (); double x = 0, y = 0, z = 0; size_t num_vox = 0; unsigned char *img = vol->get_raw(); #pragma omp parallel for reduction(+:num_vox,x,y,z) LOOP_Z_OMP (k, vol) { plm_long ijk[3]; /* Index within image (vox) */ float xyz[3]; /* Position within image (mm) */ ijk[2] = k; xyz[2] = vol->origin[2] + ijk[2] * vol->step[2*3+2]; LOOP_Y (ijk, xyz, vol) { LOOP_X (ijk, xyz, vol) { plm_long v = volume_index (vol->dim, ijk); unsigned char vox_img = img[v]; if (vox_img) { num_vox++; x += xyz[0]; y += xyz[1]; z += xyz[2]; } } } } /* Compute volume and center of mass */ /* Voxel size is same for both images */ if (num_vox > 0) { d_ptr->center_of_mass[0] = x / num_vox; d_ptr->center_of_mass[1] = y / num_vox; d_ptr->center_of_mass[2] = z / num_vox; } } DoubleVector3DType Image_center::get_image_center_of_mass () { return d_ptr->center_of_mass; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/image_center.h000066400000000000000000000021711321604176500303700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _image_center_h_ #define _image_center_h_ #include "plmutil_config.h" #include "itk_image_type.h" #include "plm_image.h" class Image_center_private; /*! \brief * The Image_center class computes the center of mass of a binary image. */ class PLMUTIL_API Image_center { public: Image_center (); ~Image_center (); public: Image_center_private *d_ptr; public: /*! \name Inputs */ ///@{ /*! \brief Set the reference image as a Plm image. */ void set_image (const UCharImageType::Pointer& image); /*! \brief Set the reference image as an ITK image. */ void set_image (const Plm_image::Pointer& image); ///@} /*! \name Execution */ ///@{ /*! \brief Compute dice statistics */ void run (); ///@} /*! \name Outputs */ ///@{ /*! \brief Return the center of mass */ DoubleVector3DType get_image_center_of_mass (); ///@} }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_adjust.cxx000066400000000000000000000040731321604176500304650ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include "itkImageRegionIterator.h" #include "float_pair_list.h" #include "itk_adjust.h" #include "itk_image_clone.h" #include "plm_math.h" #include "print_and_exit.h" #include "pwlut.h" FloatImageType::Pointer itk_adjust (FloatImageType::Pointer image_in, const Float_pair_list& al) { FloatImageType::Pointer image_out = itk_image_clone (image_in); typedef itk::ImageRegionIterator< FloatImageType > FloatIteratorType; FloatImageType::RegionType rg = image_out->GetLargestPossibleRegion (); FloatIteratorType it (image_out, rg); Pwlut pwlut; pwlut.set_lut (al); for (it.GoToBegin(); !it.IsAtEnd(); ++it) { it.Set (pwlut.lookup (it.Get())); } return image_out; } FloatImageType::Pointer itk_adjust (FloatImageType::Pointer image_in, const std::string& adj_string) { Float_pair_list al = parse_float_pairs (adj_string); if (al.empty()) { print_and_exit ("Error: couldn't parse adjust string: %s\n", adj_string.c_str()); } return itk_adjust (image_in, al); } FloatImageType::Pointer itk_auto_adjust (FloatImageType::Pointer image_in) { typedef itk::ImageRegionIterator< FloatImageType > FloatIteratorType; FloatImageType::RegionType rg = image_in->GetLargestPossibleRegion (); FloatIteratorType it (image_in, rg); Float_pair_list::const_iterator ait; /* GCS: This is just something for spark, works for CT image differencing -- make a better method later */ Float_pair_list al; al.push_back (std::make_pair (-std::numeric_limits::max(), 0.0)); al.push_back (std::make_pair (-200.0,0)); al.push_back (std::make_pair (0.0,127.5)); al.push_back (std::make_pair (+200.0,255)); al.push_back (std::make_pair (std::numeric_limits::max(), 0.0)); return itk_adjust (image_in, al); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_adjust.h000066400000000000000000000013031321604176500301030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_adjust_h_ #define _itk_adjust_h_ #include "plmutil_config.h" #include #include #include "itk_image_type.h" #include "float_pair_list.h" PLMUTIL_API FloatImageType::Pointer itk_adjust (FloatImageType::Pointer image, const Float_pair_list& al); PLMUTIL_API FloatImageType::Pointer itk_adjust (FloatImageType::Pointer image, const std::string& adj_string); PLMUTIL_API FloatImageType::Pointer itk_auto_adjust (FloatImageType::Pointer image); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_crop.cxx000066400000000000000000000037331321604176500301400ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include "itkExtractImageFilter.h" #include "itkImage.h" #include "itk_crop.h" #include "itk_image_type.h" template T itk_crop ( T& image, const int new_size[6]) { typedef typename T::ObjectType ImageType; typedef typename T::ObjectType::PixelType PixelType; typedef itk::ExtractImageFilter < ImageType, ImageType > FilterType; typename FilterType::Pointer filter = FilterType::New(); typename ImageType::IndexType extract_index; typename ImageType::SizeType extract_size; typename ImageType::RegionType extract_region; #if ITK_VERSION_MAJOR > 3 filter->SetDirectionCollapseToGuess(); #endif for (int d = 0; d < 3; d++) { extract_index[d] = new_size[d*2]; extract_size[d] = new_size[d*2+1] - new_size[d*2] + 1; } extract_region.SetSize (extract_size); extract_region.SetIndex (extract_index); filter->SetInput (image); filter->SetExtractionRegion (extract_region); try { //filter->Update(); filter->UpdateLargestPossibleRegion (); } catch(itk::ExceptionObject & ex) { printf ("Exception running itkExtractImageFilter.\n"); std::cout << ex << std::endl; getchar(); exit(1); } T out_image = filter->GetOutput(); return out_image; } /* Explicit instantiations */ template PLMUTIL_API UCharImageType::Pointer itk_crop (UCharImageType::Pointer&, const int*); template PLMUTIL_API ShortImageType::Pointer itk_crop (ShortImageType::Pointer&, const int*); template PLMUTIL_API UShortImageType::Pointer itk_crop (UShortImageType::Pointer&, const int*); template PLMUTIL_API UInt32ImageType::Pointer itk_crop (UInt32ImageType::Pointer&, const int*); template PLMUTIL_API FloatImageType::Pointer itk_crop (FloatImageType::Pointer&, const int*); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_crop.h000066400000000000000000000005771321604176500275700ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_crop_h_ #define _itk_crop_h_ #include "plmutil_config.h" template PLMUTIL_API T itk_crop (T& image, const int *new_size); #endif itk_distance_map.cxx000066400000000000000000000063031321604176500315410ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include #include #include #include #include "itkApproximateSignedDistanceMapImageFilter.h" #include "itkImage.h" #include "itkSignedDanielssonDistanceMapImageFilter.h" #include "itkSignedMaurerDistanceMapImageFilter.h" #include "itk_distance_map.h" #include "itk_image_type.h" /* itk::ApproximateSignedDistanceMapImageFilter apparently doesn't work */ #if defined (commentout) FloatImageType::Pointer itk_distance_map_approximate ( UCharImageType::Pointer& ref_image, bool use_squared_distance, bool inside_positive ) { typedef itk::ApproximateSignedDistanceMapImageFilter< UCharImageType, FloatImageType > FilterType; FilterType::Pointer filter = FilterType::New (); #if defined (commentout) if (this->use_squared_distance) { filter->SetSquaredDistance (true); } else { filter->SetSquaredDistance (false); } /* Always compute map in millimeters, never voxels */ filter->SetUseImageSpacing (true); if (this->inside_is_positive) { filter->SetInsideIsPositive (true); } else { filter->SetInsideIsPositive (false); } #endif /* ITK is very odd... */ filter->SetOutsideValue (0); filter->SetInsideValue (1); /* Run the filter */ filter->SetInput (this->input); filter->Update(); this->output = filter->GetOutput (); } #endif FloatImageType::Pointer itk_distance_map_danielsson ( const UCharImageType::Pointer& ref_image, bool use_squared_distance, bool inside_positive ) { typedef itk::SignedDanielssonDistanceMapImageFilter< UCharImageType, FloatImageType > FilterType; FilterType::Pointer filter = FilterType::New (); if (use_squared_distance) { filter->SetSquaredDistance (true); } else { filter->SetSquaredDistance (false); } /* Always compute map in millimeters, never voxels */ filter->SetUseImageSpacing (true); if (inside_positive) { filter->SetInsideIsPositive (true); } else { filter->SetInsideIsPositive (false); } /* Run the filter */ filter->SetInput (ref_image); filter->Update(); return filter->GetOutput (); } FloatImageType::Pointer itk_distance_map_maurer ( const UCharImageType::Pointer& ref_image, bool use_squared_distance, bool inside_positive ) { typedef itk::SignedMaurerDistanceMapImageFilter< UCharImageType, FloatImageType > FilterType; FilterType::Pointer filter = FilterType::New (); if (use_squared_distance) { filter->SetSquaredDistance (true); } else { filter->SetSquaredDistance (false); } /* Always compute map in millimeters, never voxels */ filter->SetUseImageSpacing (true); if (inside_positive) { filter->SetInsideIsPositive (true); } else { filter->SetInsideIsPositive (false); } /* Run the filter */ filter->SetInput (ref_image); filter->Update(); return filter->GetOutput (); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_distance_map.h000066400000000000000000000012631321604176500312450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_distance_map_h_ #define _itk_distance_map_h_ #include "plmutil_config.h" #include "itk_image_type.h" PLMUTIL_API FloatImageType::Pointer itk_distance_map_danielsson ( const UCharImageType::Pointer& ref_image, bool use_squared_distance, bool inside_positive ); PLMUTIL_API FloatImageType::Pointer itk_distance_map_maurer ( const UCharImageType::Pointer& ref_image, bool use_squared_distance, bool inside_positive ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_gabor.cxx000066400000000000000000000025401321604176500302620ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include "itkGaborImageSource.h" #include "itkGaborKernelFunction.h" #include "itkImage.h" #include "itk_gabor.h" #include "itk_image_save.h" void itk_gabor (FloatImageType::Pointer image) { typedef itk::GaborImageSource< FloatImageType > GaborSourceType; GaborSourceType::Pointer GaborKernelImage = GaborSourceType::New(); GaborKernelImage->Update(); FloatImageType::Pointer img = GaborKernelImage->GetOutput(); itk_image_save (img, "tmp.mha"); } FloatImageType::Pointer itk_gabor_create (const Plm_image_header *pih) { typedef itk::GaborImageSource< FloatImageType > GaborSourceType; GaborSourceType::Pointer gabor = GaborSourceType::New(); //gabor->SetSize (pih->GetSize()); //gabor->SetSpacing (pih->m_spacing); //gabor->SetOrigin (pih->m_origin); #if defined (commentout) #endif FloatImageType::PointType origin; origin.Fill (15); gabor->SetOrigin (origin); FloatImageType::SpacingType spacing; spacing.Fill (0.25); gabor->SetSpacing (spacing); gabor->Update(); FloatImageType::Pointer img = gabor->GetOutput(); return img; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_gabor.h000066400000000000000000000007731321604176500277150ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_gabor_h_ #define _itk_gabor_h_ #include "plmutil_config.h" #include "itk_image_type.h" class Plm_image_header; PLMUTIL_API void itk_gabor (FloatImageType::Pointer image); PLMUTIL_API FloatImageType::Pointer itk_gabor_create (const Plm_image_header *pih); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_mask.cxx000066400000000000000000000114421321604176500301240ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include "itkImageRegionIterator.h" #include "itk_mask.h" template T mask_image ( T input, UCharImageType::Pointer mask, Mask_operation mask_operation, float mask_value ) { typedef typename T::ObjectType ImageType; typedef typename T::ObjectType::PixelType PixelType; typedef typename itk::ImageRegionIterator< UCharImageType > UCharIteratorType; typedef typename itk::ImageRegionIterator< ImageType > ImageIteratorType; typename ImageType::RegionType rgn_input = input->GetLargestPossibleRegion(); typename UCharImageType::RegionType rgn_mask = mask->GetLargestPossibleRegion(); const typename ImageType::PointType& og = input->GetOrigin(); const typename ImageType::SpacingType& sp = input->GetSpacing(); const typename ImageType::DirectionType& dc = input->GetDirection(); typename ImageType::Pointer im_out = ImageType::New(); im_out->SetRegions (rgn_input); im_out->SetOrigin (og); im_out->SetSpacing (sp); im_out->SetDirection (dc); im_out->Allocate (); ImageIteratorType it_in (input, rgn_input); UCharIteratorType it_mask (mask, rgn_mask); ImageIteratorType it_out (im_out, rgn_input); for (it_in.GoToBegin(); !it_in.IsAtEnd(); ++it_in,++it_mask,++it_out) { PixelType p1 = it_in.Get(); unsigned char p2 = it_mask.Get(); if ((p2 > 0) ^ (mask_operation == MASK_OPERATION_MASK)) { it_out.Set (mask_value); } else { it_out.Set (p1); } } return im_out; } #if defined (commentout) void merge_pixels (ShortImageType::Pointer im_out, ShortImageType::Pointer im_1, UCharImageType::Pointer im_2, int mask_value) { typedef itk::ImageRegionIterator< UCharImageType > UCharIteratorType; typedef itk::ImageRegionIterator< ShortImageType > ShortIteratorType; ShortImageType::RegionType r_1 = im_1->GetLargestPossibleRegion(); UCharImageType::RegionType r_2 = im_2->GetLargestPossibleRegion(); //const ShortImageType::IndexType& st = r_1.GetIndex(); //const ShortImageType::SizeType& sz = r_1.GetSize(); //const InputImageType::SizeType& sz = image->GetLargestPossibleRegion().GetSize(); const ShortImageType::PointType& og = im_1->GetOrigin(); const ShortImageType::SpacingType& sp = im_1->GetSpacing(); im_out->SetRegions(r_1); im_out->SetOrigin(og); im_out->SetSpacing(sp); im_out->Allocate(); ShortIteratorType it_1 (im_1, r_1); UCharIteratorType it_2 (im_2, r_2); ShortIteratorType it_out (im_out, r_1); for (it_1.GoToBegin(); !it_1.IsAtEnd(); ++it_1,++it_2,++it_out) { short p1 = it_1.Get(); unsigned char p2 = it_2.Get(); if (p2 > 0) { it_out.Set (p1); } else { it_out.Set (mask_value); } } } void mask_vf(DeformationFieldType::Pointer vf_out, DeformationFieldType::Pointer vf, UCharImageType::Pointer mask, float mask_value[3]) { typedef itk::ImageRegionIterator< UCharImageType > UCharIteratorType; typedef itk::ImageRegionIterator< DeformationFieldType > DeformationFieldIteratorType; DeformationFieldType::RegionType r_1 = vf->GetLargestPossibleRegion(); UCharImageType::RegionType r_2 = mask->GetLargestPossibleRegion(); //const DeformationFieldType::IndexType& st = r_1.GetIndex(); //const DeformationFieldType::SizeType& sz = r_1.GetSize(); const DeformationFieldType::PointType& og = vf->GetOrigin(); const DeformationFieldType::SpacingType& sp = vf->GetSpacing(); vf_out->SetRegions(r_1); vf_out->SetOrigin(og); vf_out->SetSpacing(sp); vf_out->Allocate(); DeformationFieldIteratorType it_1 (vf, r_1); UCharIteratorType it_2 (mask, r_2); DeformationFieldIteratorType it_out (vf_out, r_1); for (it_1.GoToBegin(); !it_1.IsAtEnd(); ++it_1,++it_2,++it_out) { itk::Vector p1 = it_1.Get(); unsigned char p2 = it_2.Get(); if (p2 > 0) { it_out.Set (p1); } else { it_out.Set (mask_value); } } } #endif /* Explicit instantiations */ template PLMUTIL_API UCharImageType::Pointer mask_image (UCharImageType::Pointer, UCharImageType::Pointer, Mask_operation, float); template PLMUTIL_API UShortImageType::Pointer mask_image (UShortImageType::Pointer, UCharImageType::Pointer, Mask_operation, float); template PLMUTIL_API ShortImageType::Pointer mask_image (ShortImageType::Pointer, UCharImageType::Pointer, Mask_operation, float); template PLMUTIL_API UInt32ImageType::Pointer mask_image (UInt32ImageType::Pointer, UCharImageType::Pointer, Mask_operation, float); template PLMUTIL_API FloatImageType::Pointer mask_image (FloatImageType::Pointer, UCharImageType::Pointer, Mask_operation, float); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_mask.h000066400000000000000000000016551321604176500275560ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_mask_h_ #define _itk_mask_h_ #include "plmutil_config.h" #include "itk_image_type.h" enum Mask_operation { MASK_OPERATION_FILL, MASK_OPERATION_MASK }; #if defined (commentout) template T vector_mask_image (T& vf_image, U& ref_image); template T vector_mask_image (T& image, float x_spacing, float y_spacing, float z_spacing); template T vector_mask_image (T& vf_image, float* origin, float* spacing, int* size); template T vector_mask_image (T& vf_image, Plm_image_header* pih); #endif template T mask_image ( T input, UCharImageType::Pointer mask, Mask_operation mask_operation, float mask_value ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_scale.cxx000066400000000000000000000035511321604176500302620ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include "itkImage.h" #if ITK_VERSION_MAJOR >= 4 #include "itkMultiplyImageFilter.h" #else #include "itkMultiplyByConstantImageFilter.h" #endif #include "itk_image_type.h" #include "itk_scale.h" template T itk_scale ( const T& image, float weight) { typedef typename T::ObjectType ImageType; typedef typename T::ObjectType::PixelType PixelType; #if ITK_VERSION_MAJOR >= 4 typedef typename itk::MultiplyImageFilter< ImageType, FloatImageType, ImageType > MulFilterType; #else typedef typename itk::MultiplyByConstantImageFilter< ImageType, float, ImageType > MulFilterType; #endif typename MulFilterType::Pointer multiply = MulFilterType::New(); multiply->SetInput (image); multiply->SetConstant (weight); try { multiply->Update(); } catch(itk::ExceptionObject & ex) { printf ("Exception running itkMultiplyByConstantImageFilter.\n"); std::cout << ex << std::endl; getchar(); exit(1); } return multiply->GetOutput(); } /* Explicit instantiations */ template PLMUTIL_API UCharImageType::Pointer itk_scale (const UCharImageType::Pointer&, float); template PLMUTIL_API ShortImageType::Pointer itk_scale (const ShortImageType::Pointer&, float); template PLMUTIL_API UShortImageType::Pointer itk_scale (const UShortImageType::Pointer&, float); template PLMUTIL_API UInt32ImageType::Pointer itk_scale (const UInt32ImageType::Pointer&, float); template PLMUTIL_API FloatImageType::Pointer itk_scale (const FloatImageType::Pointer&, float); template PLMUTIL_API DeformationFieldType::Pointer itk_scale (const DeformationFieldType::Pointer&, float); plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_scale.h000066400000000000000000000005721321604176500277070ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_scale_h_ #define _itk_scale_h_ #include "plmutil_config.h" template PLMUTIL_API T itk_scale (const T& image, float); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_threshold.cxx000066400000000000000000000045651321604176500311750ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include #include "float_pair_list.h" #include "itk_image_create.h" #include "itk_threshold.h" #include "plm_image_header.h" UCharImageType::Pointer itk_threshold_above ( const FloatImageType::Pointer& image, float threshold) { typedef itk::BinaryThresholdImageFilter< FloatImageType, UCharImageType > ThresholdFilterType; ThresholdFilterType::Pointer thresh_filter = ThresholdFilterType::New (); thresh_filter->SetInput (image); thresh_filter->SetLowerThreshold (threshold); thresh_filter->SetOutsideValue (0); thresh_filter->SetInsideValue (1); try { thresh_filter->Update (); } catch (itk::ExceptionObject & excep) { std::cerr << "Exception caught !" << std::endl; std::cerr << excep << std::endl; } return thresh_filter->GetOutput (); } UCharImageType::Pointer itk_threshold ( const FloatImageType::Pointer& image_in, const Float_pair_list& fpl) { UCharImageType::Pointer image_out = itk_image_create ( Plm_image_header (image_in)); typedef itk::ImageRegionIterator< FloatImageType > FloatIteratorType; typedef itk::ImageRegionIterator< UCharImageType > UCharIteratorType; FloatImageType::RegionType rg = image_out->GetLargestPossibleRegion (); FloatIteratorType it_in (image_in, rg); UCharIteratorType it_out (image_out, rg); for (it_in.GoToBegin(), it_out.GoToBegin(); !it_in.IsAtEnd(); ++it_in, ++it_out) { float vin = it_in.Get(); unsigned char vout = 0; Float_pair_list::const_iterator fpl_it = fpl.begin(); while (fpl_it != fpl.end()) { if (vin >= fpl_it->first && vin <= fpl_it->second) { vout = 1; break; } fpl_it ++; } it_out.Set (vout); } return image_out; } UCharImageType::Pointer itk_threshold ( const FloatImageType::Pointer& image_in, const std::string& fpl_string) { Float_pair_list fpl = parse_float_pairs (fpl_string); return itk_threshold (image_in, fpl); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_threshold.h000066400000000000000000000013761321604176500306170ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_threshold_h_ #define _itk_threshold_h_ #include "plmutil_config.h" #include "float_pair_list.h" #include "itk_image_type.h" PLMUTIL_API UCharImageType::Pointer itk_threshold_above ( const FloatImageType::Pointer& image, float threshold); PLMUTIL_API UCharImageType::Pointer itk_threshold ( const FloatImageType::Pointer& image_in, const Float_pair_list& fpl); PLMUTIL_API UCharImageType::Pointer itk_threshold ( const FloatImageType::Pointer& image_in, const std::string& fpl_string); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_union.cxx000066400000000000000000000027041321604176500303220ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #include "itkImageRegionIterator.h" #include "itk_image.h" #include "itk_union.h" #include "print_and_exit.h" UCharImageType::Pointer itk_union ( const UCharImageType::Pointer image_1, const UCharImageType::Pointer image_2) { typedef itk::ImageRegionIterator< UCharImageType > IteratorType; UCharImageType::RegionType r_1 = image_1->GetLargestPossibleRegion(); UCharImageType::RegionType r_2 = image_2->GetLargestPossibleRegion(); const UCharImageType::PointType& og = image_1->GetOrigin(); const UCharImageType::SpacingType& sp = image_1->GetSpacing(); if (!itk_image_header_compare (image_1, image_2)) { print_and_exit ("Sorry, input images to itk_union must have " "the same geometry."); } UCharImageType::Pointer im_out = UCharImageType::New(); im_out->SetRegions(r_1); im_out->SetOrigin(og); im_out->SetSpacing(sp); im_out->Allocate(); IteratorType it_1 (image_1, r_1); IteratorType it_2 (image_2, r_2); IteratorType it_out (im_out, r_2); for (it_1.GoToBegin(); !it_1.IsAtEnd(); ++it_1,++it_2,++it_out) { unsigned char p1 = it_1.Get(); unsigned char p2 = it_2.Get(); it_out.Set (p1 | p2); } return im_out; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/itk_union.h000066400000000000000000000007241321604176500277470ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _itk_union_h_ #define _itk_union_h_ #include "plmutil_config.h" #include "itk_image_type.h" PLMUTIL_API UCharImageType::Pointer itk_union (const UCharImageType::Pointer image_1, const UCharImageType::Pointer image_2); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/landmark_diff.cxx000066400000000000000000000037461321604176500311130ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include #include #include "landmark_diff.h" #include "raw_pointset.h" static float get_sd ( float *P1, float *P2 ) { return sqrt ( (P2[0]-P1[0])*(P2[0]-P1[0]) + (P2[1]-P1[1])*(P2[1]-P1[1]) + (P2[2]-P1[2])*(P2[2]-P1[2]) ); } static void print_pointset (Raw_pointset *rps) { for (int i=0; inum_points; i++) { printf (" [%i] %f, %f, %f\n", i, rps->points[3*i+0], rps->points[3*i+1], rps->points[3*i+2] ); } } static void print_sd_stats ( Raw_pointset *rps0, Raw_pointset *rps1 ) { float *sd = (float*)malloc (rps0->num_points * sizeof(float)); float avg = 0.0f; for (int i=0; inum_points; i++) { sd[i] = get_sd (&rps0->points[3*i], &rps1->points[3*i]); avg += sd[i]; } avg /= rps0->num_points; float var = 0.0f; for (int i=0; inum_points; i++) { var += (sd[i]-avg)*(sd[i]-avg); printf (" [%i] %f\n", i, sd[i]); } var /= rps0->num_points; free (sd); printf ("\n"); printf (" Avg: %f\n", avg); printf (" Var: %f\n", var); printf ("Stdev: %f\n", sqrt(var)); } int landmark_diff ( Raw_pointset *rps0, Raw_pointset *rps1 ) { /* make sure both sets have same # of landmarks */ if (rps0->num_points != rps1->num_points) { printf ("error: sets must contain same number of landmarks\n"); return -1; } printf ("1st Pointset:\n"); print_pointset (rps0); printf ("\n"); printf ("2nd Pointset:\n"); print_pointset (rps1); printf ("\n"); printf ("Separation Distances:\n"); print_sd_stats (rps0, rps1); return 0; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/landmark_diff.h000066400000000000000000000007251321604176500305320ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _landmark_diff_h_ #define _landmark_diff_h_ #include "plmutil_config.h" typedef struct raw_pointset Raw_pointset; PLMUTIL_C_API int landmark_diff ( Raw_pointset *rps0, Raw_pointset *rps1 ); #endif /* _landmark_diff_h_ */ plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/plm_series.cxx000066400000000000000000000010311321604176500304550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "plm_series.h" class Plm_series_private { public: public: Plm_series_private () { } ~Plm_series_private () { } }; Plm_series::Plm_series () { } Plm_series::~Plm_series () { } void Plm_series::debug () const { } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/plm_series.h000066400000000000000000000007471321604176500301170ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_series_h_ #define _plm_series_h_ #include "plmbase_config.h" class Plm_series_private; class Plm_series { public: Plm_series (); ~Plm_series (); public: Plm_series_private *d_ptr; public: void debug (void) const; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/plm_study.cxx000066400000000000000000000010201321604176500303310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmbase_config.h" #include #include #include "plm_study.h" class Plm_study_private { public: public: Plm_study_private () { } ~Plm_study_private () { } }; Plm_study::Plm_study () { } Plm_study::~Plm_study () { } void Plm_study::debug () const { } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/plm_study.h000066400000000000000000000007401321604176500277660ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _plm_study_h_ #define _plm_study_h_ #include "plmbase_config.h" class Plm_study_private; class Plm_study { public: Plm_study (); ~Plm_study (); public: Plm_study_private *d_ptr; public: void debug (void) const; }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/plmutil_config.h.in000066400000000000000000000013001321604176500313570ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef __plmutil_config_h__ #define __plmutil_config_h__ #include "plm_config.h" #if ((defined(_WIN32) || defined(WIN32)) && (defined (PLM_BUILD_SHARED_LIBS))) # ifdef plmutil_EXPORTS # define PLMUTIL_C_API EXTERNC __declspec(dllexport) # define PLMUTIL_API __declspec(dllexport) # else # define PLMUTIL_C_API EXTERNC __declspec(dllimport) # define PLMUTIL_API __declspec(dllimport) # endif #else # define PLMUTIL_C_API EXTERNC # define PLMUTIL_API #endif #endif proj_image_filter.cxx000066400000000000000000000007211321604176500317220ustar00rootroot00000000000000plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include "proj_image.h" #include "proj_image_filter.h" #include "ramp_filter.h" void proj_image_filter (Proj_image *proj) { #if (FFTW_FOUND) ramp_filter (proj->img, proj->dim[0], proj->dim[1]); #endif } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/proj_image_filter.h000066400000000000000000000006221321604176500314260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _proj_image_filter_h_ #define _proj_image_filter_h_ #include "plmutil_config.h" class Proj_image; PLMUTIL_C_API void proj_image_filter (Proj_image *proj); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/ramp_filter.cxx000066400000000000000000000070631321604176500306320ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include #include #include "fftw3.h" #include "ramp_filter.h" #include "print_and_exit.h" #ifndef PI static const double PI = 3.14159265; #endif #ifndef DEGTORAD static const double DEGTORAD = 3.14159265 / 180.0; #endif #ifndef MARGIN static const unsigned int MARGIN = 5; #else #error "MARGIN IS DEFINED" #endif /* GCS: Dec 12, 2009 Change from unsigned short to float, Change to destructive update */ //! In-place ramp filter for greyscale images //! \param data The pixel data of the image //! \param width The width of the image //! \param height The height of the image //! \template_param T The type of pixel in the image void ramp_filter ( float *data, unsigned int width, unsigned int height ) { unsigned int i, r, c; unsigned int N; fftw_complex *in; fftw_complex *fft; fftw_complex *ifft; fftw_plan fftp; fftw_plan ifftp; double *ramp; ramp = (double*) malloc (width * sizeof(double)); if (!ramp) { print_and_exit ("Error allocating memory for ramp\n"); } N = width * height; in = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * N); fft = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * N); ifft = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * N); if (!in || !fft || !ifft) { print_and_exit ("Error allocating memory for fft\n"); } for (r = 0; r < MARGIN; ++r) memcpy (data + r * width, data + MARGIN * width, width * sizeof(float)); for (r = height - MARGIN; r < height; ++r) memcpy (data + r * width, data + (height - MARGIN - 1) * width, width * sizeof(float)); for (r = 0; r < height; ++r) { for (c = 0; c < MARGIN; ++c) data[r * width + c] = data[r * width + MARGIN]; for (c = width - MARGIN; c < width; ++c) data[r * width + c] = data[r * width + width - MARGIN - 1]; } /* Fill in ramp filter in frequency space */ for (i = 0; i < N; ++i) { in[i][0] = (double)(data[i]); //in[i][0] /= 65535; //in[i][0] = (in[i][0] == 0 ? 1 : in[i][0]); //in[i][0] = -log (in[i][0]); in[i][1] = 0.0; } /* Add padding */ for (i = 0; i < width / 2; ++i) ramp[i] = i; for (i = width / 2; i < (unsigned int) width; ++i) ramp[i] = width - i; /* Roll off ramp filter */ for (i = 0; i < width; ++i) ramp[i] *= (cos (i * DEGTORAD * 360 / width) + 1) / 2; for (r = 0; r < height; ++r) { fftp = fftw_plan_dft_1d (width, in + r * width, fft + r * width, FFTW_FORWARD, FFTW_ESTIMATE); if (!fftp) { print_and_exit ("Error creating fft plan\n"); } ifftp = fftw_plan_dft_1d (width, fft + r * width, ifft + r * width, FFTW_BACKWARD, FFTW_ESTIMATE); if (!ifftp) { print_and_exit ("Error creating ifft plan\n"); } fftw_execute (fftp); // Apply ramp for (c = 0; c < width; ++c) { fft[r * width + c][0] *= ramp[c]; fft[r * width + c][1] *= ramp[c]; } fftw_execute (ifftp); fftw_destroy_plan (fftp); fftw_destroy_plan (ifftp); } for (i = 0; i < N; ++i) ifft[i][0] /= width; for (i = 0; i < N; ++i) data[i] = (float)(ifft[i][0]); fftw_free (in); fftw_free (fft); fftw_free (ifft); free (ramp); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/ramp_filter.h000066400000000000000000000006231321604176500302520ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _ramp_filter_h_ #define _ramp_filter_h_ #include "plmutil_config.h" void ramp_filter ( float *data, unsigned int width, unsigned int height ); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/rt_study_warp.cxx000066400000000000000000000400701321604176500312270ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include "file_util.h" #include "itk_image_load.h" #include "itk_image_save.h" #include "itk_image_type.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_warp.h" #include "print_and_exit.h" #include "rt_study.h" #include "rt_study_metadata.h" #include "rt_study_warp.h" #include "rtss.h" #include "segmentation.h" #include "simplify_points.h" #include "string_util.h" #include "warp_parms.h" #include "volume.h" #include "xform.h" #include "xio_dose.h" static void load_input_files (Rt_study *rt_study, Plm_file_format file_type, Warp_parms *parms) { if (parms->input_fn != "") { rt_study->load (parms->input_fn.c_str(), file_type); } if (parms->input_cxt_fn != "") { rt_study->load_cxt (parms->input_cxt_fn.c_str()); } if (parms->input_prefix != "") { rt_study->load_prefix (parms->input_prefix.c_str()); } if (parms->input_ss_img_fn != "") { if (!file_exists (parms->input_ss_img_fn)) { print_and_exit ("Error: cannot open file %s for read\n", parms->input_ss_img_fn.c_str()); } rt_study->load_ss_img ( parms->input_ss_img_fn.c_str(), parms->input_ss_list_fn.c_str()); } if (parms->input_dose_img_fn != "") { rt_study->load_dose_img (parms->input_dose_img_fn.c_str()); } if (parms->input_dose_xio_fn != "") { rt_study->load_dose_xio (parms->input_dose_xio_fn.c_str()); } if (parms->input_dose_ast_fn != "") { rt_study->load_dose_astroid (parms->input_dose_ast_fn.c_str()); } if (parms->input_dose_mc_fn != "") { rt_study->load_dose_mc (parms->input_dose_mc_fn.c_str()); } if (!rt_study->have_image() && !rt_study->have_segmentation() && !rt_study->have_dose()) { print_and_exit ("Sorry, could not load input as any known type.\n"); } } static void save_ss_img ( Rt_study *rt_study, const Xform *xf, Plm_image_header *pih, Warp_parms *parms ) { Segmentation::Pointer seg = rt_study->get_segmentation(); /* labelmap */ if (parms->output_labelmap_fn != "") { lprintf ("save_ss_img: save_labelmap\n"); seg->save_labelmap (parms->output_labelmap_fn.c_str()); } /* ss_img */ if (parms->output_ss_img_fn != "") { lprintf ("save_ss_img: save_ss_image\n"); seg->save_ss_image (parms->output_ss_img_fn); } /* list of structure names */ if (parms->output_ss_list_fn != "") { lprintf ("save_ss_img: save_ss_list\n"); seg->save_ss_list (parms->output_ss_list_fn); } /* prefix images */ if (parms->output_prefix != "") { lprintf ("save_ss_img: save_prefix\n"); seg->save_prefix (parms->output_prefix, parms->prefix_format); } /* prefix fcsv files */ if (parms->output_prefix_fcsv != "") { lprintf ("save_ss_img: save_prefix_fcsv\n"); lprintf ("save_ss_img: save_prefix_fcsv (%s)\n", parms->output_prefix_fcsv.c_str()); seg->save_prefix_fcsv (parms->output_prefix_fcsv.c_str()); } /* 3D Slicer color table */ if (parms->output_colormap_fn != "") { lprintf ("save_ss_img: save_colormap\n"); seg->save_colormap (parms->output_colormap_fn.c_str()); } /* cxt */ if (parms->output_cxt_fn != "") { lprintf ("save_ss_img: save_cxt\n"); seg->save_cxt (rt_study->get_rt_study_metadata (), parms->output_cxt_fn.c_str(), false); } /* xio */ if (parms->output_xio_dirname != "") { lprintf ("save_ss_img: save_xio (dirname = %s)\n", parms->output_xio_dirname.c_str()); seg->save_xio ( rt_study->get_rt_study_metadata (), rt_study->get_xio_ct_transform (), parms->output_xio_version, parms->output_xio_dirname); } } static void warp_and_save_ss ( Rt_study *rt_study, const Xform::Pointer& xf, Plm_image_header *pih, Warp_parms *parms) { if (!rt_study->have_segmentation()) { return; } Segmentation::Pointer seg = rt_study->get_segmentation(); /* If we have need to create image outputs, or if we have to warp something, then we need to rasterize the volume */ /* GCS FIX: If there is an input m_ss_img, we still do this because we might need the labelmap */ if (parms->output_labelmap_fn != "" || parms->output_ss_img_fn != "" || parms->xf_in_fn != "" || parms->output_prefix != "") { /* In the following cases, we should use the default rasterization geometry (i.e. cxt->rast_xxx): (a) Warping (b) No known output geometry (c) Output geometry doesn't match slice locations GCS FIX: Only case (a) is handled. In the other cases we can directly rasterize to the output geometry. */ Plm_image_header pih; Rtss *cxt = seg->get_structure_set_raw (); if (parms->xf_in_fn != "") { pih.set_from_gpuit (cxt->rast_dim, cxt->rast_offset, cxt->rast_spacing, 0); } else { pih.set_from_gpuit (cxt->m_dim, cxt->m_offset, cxt->m_spacing, 0); } lprintf ("Warp_and_save_ss: seg->rasterize\n"); seg->rasterize (&pih, parms->output_labelmap_fn != "", parms->xor_contours); } /* Do the warp */ if (parms->xf_in_fn != "") { lprintf ("Warp_and_save_ss: seg->warp\n"); seg->warp (xf, pih, parms); } /* If we are warping, re-extract polylines into cxt */ /* GCS FIX: This is only necessary if we are outputting polylines. Otherwise it is wasting users time. */ if (parms->xf_in_fn != "") { lprintf ("Warp_and_save_ss: seg->cxt_re_extract\n"); seg->cxt_re_extract (); } /* If we need to reduce the number of points (aka if simplify-perc was set), purge the excessive points...*/ if (parms->simplify_perc > 0. && parms->simplify_perc < 100.) { lprintf ("Warp_and_save_ss: do_simplify\n"); do_simplify(rt_study, parms->simplify_perc); } /* Save non-dicom formats, such as mha, cxt, xio */ lprintf ("Warp_and_save_ss: save_ss_img\n"); save_ss_img (rt_study, xf.get(), pih, parms); } void rt_study_warp (Rt_study *rt_study, Plm_file_format file_type, Warp_parms *parms) { DeformationFieldType::Pointer vf = DeformationFieldType::New(); Xform::Pointer xform = Xform::New (); Plm_image_header pih; /* Load referenced DICOM directory */ if (parms->referenced_dicom_dir != "") { lprintf ("Loading RDD\n"); rt_study->load_rdd (parms->referenced_dicom_dir.c_str()); lprintf ("Loading RDD complete\n"); } /* Set user-supplied metadata also prior to loading files, because the user supplied patient position is needed to load XiO data */ rt_study->set_study_metadata (parms->m_study_metadata); /* Load input file(s) */ load_input_files (rt_study, file_type, parms); /* Set user-supplied metadata (overrides metadata in input files) */ rt_study->set_study_metadata (parms->m_study_metadata); rt_study->set_image_metadata (parms->m_image_metadata); rt_study->set_dose_metadata (parms->m_dose_metadata); rt_study->set_rtstruct_metadata (parms->m_rtstruct_metadata); // UIDs are handled differently when saving. Normally they are // generated fresh, you need to explicitly force if (!parms->retain_study_uids) { rt_study->generate_new_study_uids (); } if (parms->image_series_uid_forced) { const std::string& series_uid = rt_study->get_image_metadata()->get_metadata (0x0020, 0x000e); rt_study->force_ct_series_uid (series_uid); } /* Load transform */ if (parms->xf_in_fn != "") { lprintf ("Loading xform (%s)\n", parms->xf_in_fn.c_str()); xform = xform_load (parms->xf_in_fn); } /* Try to guess the proper dimensions and spacing for output image */ Xform_type xform_type = xform->get_type (); if (parms->fixed_img_fn != "") { /* use the spacing of user-supplied fixed image */ lprintf ("Setting PIH from FIXED\n"); FloatImageType::Pointer fixed = itk_image_load_float ( parms->fixed_img_fn, 0); pih.set_from_itk_image (fixed); } else if (xform_type == XFORM_ITK_VECTOR_FIELD) { /* use the spacing from input vector field */ lprintf ("Setting PIH from VF\n"); pih.set_from_itk_image (xform->get_itk_vf()); } else if (xform_type == XFORM_GPUIT_BSPLINE) { /* use the spacing from input bxf file */ lprintf ("Setting PIH from XFORM\n"); pih.set_from_gpuit_bspline (xform->get_gpuit_bsp()); } else if (rt_study->get_rt_study_metadata()->slice_list_complete()) { /* use spacing from referenced CT */ lprintf ("Setting PIH from RDD\n"); Plm_image_header::clone (&pih, rt_study->get_rt_study_metadata()->get_image_header()); } else if (rt_study->have_image()) { /* use the spacing of the input image */ lprintf ("Setting PIH from M_IMG\n"); pih.set_from_plm_image (rt_study->get_image().get()); } else if (rt_study->have_segmentation() && rt_study->get_segmentation()->have_ss_img()) { /* use the spacing of the input image */ lprintf ("Setting PIH from M_SS_IMG\n"); pih.set_from_plm_image (rt_study->get_segmentation()->get_ss_img()); } else if (rt_study->have_segmentation() && /* use the spacing of the structure set */ rt_study->get_segmentation()->have_structure_set() && rt_study->get_segmentation()->get_structure_set()->have_geometry) { pih.set_from_gpuit ( rt_study->get_segmentation()->get_structure_set()->m_dim, rt_study->get_segmentation()->get_structure_set()->m_offset, rt_study->get_segmentation()->get_structure_set()->m_spacing, 0); } else if (rt_study->has_dose()) { /* use the spacing of dose */ lprintf ("Setting PIH from DOSE\n"); pih.set_from_plm_image (rt_study->get_dose()); } else if (rt_study->have_segmentation() && rt_study->get_segmentation()->have_structure_set()) { /* we have structure set, but without geometry. use heuristics to find a good geometry for rasterization */ rt_study->get_segmentation()->find_rasterization_geometry (&pih); } else { /* use some generic default parameters */ plm_long dim[3] = { 500, 500, 500 }; float origin[3] = { -249.5, -249.5, -249.5 }; float spacing[3] = { 1., 1., 1. }; pih.set_from_gpuit (dim, origin, spacing, 0); } if (parms->m_have_dim) { pih.set_dim (parms->m_dim); } if (parms->m_have_origin) { pih.set_origin (parms->m_origin); } if (parms->m_have_spacing) { pih.set_spacing (parms->m_spacing); } if (parms->m_have_direction_cosines) { /* GCS FIX: This will do illogical things unless the user sets the origin properly */ pih.set_direction_cosines (parms->m_dc); } lprintf ("PIH is:\n"); pih.print (); /* Check if output image geometry matches input image geometry. If it doesn't we need to resample to get the output geometry. We need to supply an identity xform if none was supplied, so that the warp function can do the resample. */ bool pih_changed = false; if (rt_study->get_image()) { Plm_image_header pih_input_image (rt_study->get_image()); if (!Plm_image_header::compare (&pih_input_image, &pih)) { pih_changed = true; if (parms->xf_in_fn == "") { TranslationTransformType::Pointer trn = TranslationTransformType::New(); xform->set_trn(trn); } } } /* Warp the image and create vf */ if (rt_study->have_image() && (parms->xf_in_fn != "" || pih_changed) && (parms->output_img_fn != "" || parms->output_vf_fn != "" || parms->output_dicom != "")) { Plm_image::Pointer im_out = Plm_image::New(); lprintf ("Rt_study_warp: Warping m_img\n"); plm_warp (im_out, &vf, xform, &pih, rt_study->get_image(), parms->default_val, parms->use_itk, parms->interp_lin); rt_study->set_image (im_out); } /* Save output image */ if (parms->output_img_fn != "" && rt_study->have_image()) { lprintf ("Rt_study_warp: Saving m_img (%s)\n", parms->output_img_fn.c_str()); rt_study->get_image()->convert_and_save ( parms->output_img_fn.c_str(), parms->output_type); } /* Warp the dose image */ if (rt_study->has_dose() && parms->xf_in_fn != "" && (parms->output_dose_img_fn != "" || parms->output_xio_dirname != "" || parms->output_dicom != "")) { lprintf ("Rt_study_warp: Warping dose\n"); Plm_image::Pointer im_out = Plm_image::New(); plm_warp (im_out, 0, xform, &pih, rt_study->get_dose(), 0, parms->use_itk, 1); rt_study->set_dose (im_out); } /* Scale the dose image */ if (rt_study->has_dose() && parms->have_dose_scale) { rt_study->get_dose_volume_float()->scale_inplace (parms->dose_scale); } /* Save output dose image */ if (parms->output_dose_img_fn != "" && rt_study->has_dose()) { lprintf ("Rt_study_warp: Saving dose image (%s)\n", parms->output_dose_img_fn.c_str()); rt_study->save_dose ( parms->output_dose_img_fn.c_str(), parms->output_type); } /* Save output XiO dose */ if (parms->output_xio_dirname != "" && rt_study->get_xio_dose_filename() != "" && rt_study->has_dose()) { lprintf ("Rt_study_warp: Saving xio dose.\n"); std::string fn = string_format ("%s/%s", parms->output_xio_dirname.c_str(), "dose"); xio_dose_save ( rt_study->get_dose(), rt_study->get_study_metadata(), rt_study->get_xio_ct_transform(), fn.c_str(), rt_study->get_xio_dose_filename().c_str()); } /* Save output vector field */ if (parms->xf_in_fn != "" && parms->output_vf_fn != "") { lprintf ("Rt_study_warp: Saving vf.\n"); itk_image_save (vf, parms->output_vf_fn.c_str()); } /* Preprocess structure sets */ if (rt_study->have_segmentation()) { Segmentation::Pointer seg = rt_study->get_segmentation(); /* Convert ss_img to cxt */ lprintf ("Rt_study_warp: Convert ss_img to cxt.\n"); seg->convert_ss_img_to_cxt (); /* Delete empty structures */ if (parms->prune_empty) { lprintf ("Rt_study_warp: Prune empty structures.\n"); seg->prune_empty (); } /* Set the DICOM reference info -- this sets the internal geometry of the ss_image so we rasterize on the same slices as the CT? */ lprintf ("Rt_study_warp: Apply dicom_dir.\n"); seg->apply_dicom_dir (rt_study->get_rt_study_metadata()); /* Set the output geometry */ lprintf ("Rt_study_warp: Set geometry from PIH.\n"); seg->set_geometry (&pih); /* Set rasterization geometry */ lprintf ("Rt_study_warp: Set rasterization geometry.\n"); seg->get_structure_set()->set_rasterization_geometry (); } /* Warp and save structure set (except dicom) */ lprintf ("Rt_study_warp: warp and save ss.\n"); warp_and_save_ss (rt_study, xform, &pih, parms); /* Save dicom */ if (parms->output_dicom != "") { lprintf ("Rt_study_warp: Save dicom.\n"); rt_study->save_dicom (parms->output_dicom.c_str(), parms->dicom_with_uids); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/rt_study_warp.h000066400000000000000000000007471321604176500306630ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _rt_study_warp_h_ #define _rt_study_warp_h_ #include "plmutil_config.h" #include "base/plm_file_format.h" class Rt_study; class Warp_parms; PLMUTIL_API void rt_study_warp ( Rt_study *rtds, Plm_file_format file_type, Warp_parms *parms); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/sift.cxx000066400000000000000000000576051321604176500273020ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include #include //#include //#include //#include //#include //#include #include "itk_image_type.h" #include "plm_image.h" #include "print_and_exit.h" #include "sift.h" typedef itk::ScaleInvariantFeatureImageFilter< FloatImageType, 3> SiftFilterType; class Sift_private { public: Sift_private () { image_doubled = false; octave = 3; initial_sigma1 = 2; initial_sigma2 = 2; descriptor_dimension = 8; contrast = 0.03; curvature = 172.3025; flag_curve = true; normalization = true; match_ratio = 0.9; image = 0; } ~Sift_private () { delete image; } public: bool image_doubled; //false: no doubling; true: doubling unsigned int octave; //number of octave float initial_sigma1; //float initial_sigma_sy = 1.5; float initial_sigma2; float descriptor_dimension; float contrast; //if we assume image pixel value in the range [0,1] float curvature; //if we assume image pixel value in the range [0,1] bool flag_curve; //1: curvature; 0: no curvature; bool normalization; //true: normalization of input image for //contrast&curvature thresholds definition float match_ratio; //from 0 (no matches) to 1 (all matches) Plm_image *image; SiftFilterType::PointSetTypePointer keypoints; SiftFilterType sift_filter; }; Sift::Sift () { d_ptr = new Sift_private; } Sift::~Sift () { delete d_ptr; } void Sift::set_image (const char* image_fn) { d_ptr->image = new Plm_image (image_fn); } void Sift::set_image (const std::string& image_fn) { this->set_image (image_fn.c_str()); } void Sift::set_contrast_threshold (float contrast_threshold) { d_ptr->contrast = contrast_threshold; } void Sift::set_curvature_threshold (float curvature_threshold) { if (curvature_threshold > 0.f) { /* Use curvature */ d_ptr->flag_curve = true; } else { /* Don't use curvature */ d_ptr->flag_curve = false; } d_ptr->curvature = curvature_threshold; } void Sift::run () { if (!d_ptr->image) { print_and_exit ("Error: image not defined for Sift::run()\n"); } d_ptr->sift_filter.SetDoubling(d_ptr->image_doubled); d_ptr->sift_filter.SetNumScales(d_ptr->octave); d_ptr->sift_filter.SetInitialSigma(d_ptr->initial_sigma1); d_ptr->sift_filter.SetContrast(d_ptr->contrast); d_ptr->sift_filter.SetCurvature(d_ptr->curvature); d_ptr->sift_filter.SetDescriptorDimension(d_ptr->descriptor_dimension); d_ptr->sift_filter.SetMatchRatio(d_ptr->match_ratio); printf ("Contrast threshold = %f\n", d_ptr->contrast); printf ("Curvature threshold = %f\n", d_ptr->curvature); /* output keypoints from image */ d_ptr->keypoints = d_ptr->sift_filter.getSiftFeatures ( d_ptr->image->itk_float(), d_ptr->flag_curve, d_ptr->normalization, "", "", "", "", "", ""); /* d_ptr->keypoints = d_ptr->sift_filter.getSiftFeatures ( d_ptr->image->itk_float(), d_ptr->flag_curve, d_ptr->normalization, "phy_max1.fcsv", "phy_max2.fcsv", "imagecoord_max1.txt", "imagecoord_min1.txt", "point_rej_contrast1.fcsv", "point_rej_curvature1.fcsv" ); */ } itk::ScaleInvariantFeatureImageFilter::PointSetTypePointer Sift::get_keypoints () { return d_ptr->keypoints; } void Sift::save_pointset (const char* filename) { d_ptr->sift_filter.save_pointset (filename); } void Sift::match_features ( Sift& sift1, Sift& sift2, const char* filename1, const char* filename2, float match_ratio) { itk::ScaleInvariantFeatureImageFilter ::PointSetTypePointer keypoints1, keypoints2; keypoints1 = sift1.get_keypoints (); keypoints2 = sift2.get_keypoints (); SiftFilterType::MatchKeypointsFeatures ( keypoints1, keypoints2, filename1, filename2, match_ratio); } /* *********************************************************************** * The below is left here for reference. *************************************************************************/ #if defined (commentout) #define DIMENSION 3 // Command Line Arguments int ARG_IMG1=2; int ARG_IMG2=3; int main( int argc, char *argv[] ) { const unsigned int Dimension = DIMENSION; // ---- DEFAULT PARAMETERS: bool image_doubled = false; //false: no doubling; true: doubling unsigned int octave = 3; //number of octave float initial_sigma1 = 2; //float initial_sigma_sy = 1.5; float initial_sigma2 = 2; float descriptor_dimension = 8; float contrast = 0.03; //if we assume image pixel value in the range [0,1] float curvature = 172.3025; //if we assume image pixel value in the range [0,1] bool flag_curve = true; //1: curvature; 0: no curvature; bool normalization = true; //true: normalization of input image for //contrast&curvature thresholds definition float match_ratio = 0.9; //from 0 (no matches) to 1 (all matches) double test_scale = 1.0; // Default scale is 1.0 float test_rotate = 0.0; // 0 degrees float test_translate = 0.0; //0 mm //float test_rotate = 0.0874; // 5 degrees //float test_rotate = 0.1748; // 10 degrees int mode = 'i'; /* defaults to comparing 2 images */; int transform_middle=0; /* defaults to applying transformations around the origin */ //output: char *point_match1="phy_match1.fcsv"; char *point_match2="phy_match2.fcsv"; char *point_max1="phy_max1.fcsv"; char *point_max2="phy_max2.fcsv"; char *point_min1="phy_min1.fcsv"; char *point_min2="phy_min2.fcsv"; // ---- OPTIONS: #define OPT_OCTAVE 'o' #define OPT_DOUBLING 'di' #define OPT_INITIAL_SIGMA1 'z1' #define OPT_INITIAL_SIGMA2 'z2' #define OPT_DESCRIPTOR 'de' #define OPT_CONTRAST 'co' #define OPT_CURVATURE 'cu' #define OPT_MATCH 'm' #define OPT_SCALE 'x' #define OPT_ROTATE 'r' #define OPT_TRANSLATE 't' //#define OPT_DIM 'd' while(1) { static struct option long_options[] = { // Modalities (These options set a flag). {"synthetic", 0, &mode, 's'}, {"image", 0, &mode, 'i'}, {"transform-middle", 0, &transform_middle, 1}, // Parameters (These options don't set a flag) {"double", required_argument, 0, OPT_DOUBLING}, {"octave", required_argument, 0, OPT_OCTAVE}, {"initial-sigma1", required_argument, 0, OPT_INITIAL_SIGMA1}, {"initial-sigma2", required_argument, 0, OPT_INITIAL_SIGMA2}, {"contrast", required_argument, 0, OPT_CONTRAST}, {"curvature", required_argument, 0, OPT_CURVATURE}, {"descr-dim", required_argument, 0, OPT_DESCRIPTOR}, {"match-ratio", required_argument, 0, OPT_MATCH}, //{"dimension", required_argument, 0, OPT_DIM}, {"scale", required_argument, 0, OPT_SCALE}, {"rotate", required_argument, 0, OPT_ROTATE}, {"translate", required_argument, 0, OPT_TRANSLATE}, //Output {"out-match1", required_argument, 0, 1}, {"out-match2", required_argument, 0, 2}, {"out-max1", required_argument, 0, 3}, {"out-min1", required_argument, 0, 4}, {"out-max2", required_argument, 0, 5}, {"out-min2", required_argument, 0, 6}, {0, 0, 0, 0} }; int optindex; int val = getopt_long(argc, argv, "", long_options, &optindex); if (val == -1) break; switch(val) { case OPT_DOUBLING: image_doubled = atof(optarg); break; case OPT_OCTAVE: octave = atof(optarg); break; case OPT_INITIAL_SIGMA1: initial_sigma1 = atof(optarg); break; case OPT_INITIAL_SIGMA2: initial_sigma2 = atof(optarg); break; case OPT_CONTRAST: contrast = atof(optarg); if(contrast<0.0|| contrast>1.0) {normalization=false; flag_curve=false;} break; case OPT_CURVATURE: if(atof(optarg)==0) flag_curve=false; if(!normalization && atof(optarg)!=0) flag_curve=true; curvature = atof(optarg); break; case OPT_DESCRIPTOR: descriptor_dimension = atof(optarg); break; case OPT_MATCH: match_ratio = atof(optarg); break; //case OPT_DIM: // Dimension = atoi(optarg); // break; case OPT_SCALE: test_scale = atof(optarg); break; case OPT_ROTATE: if (atof(optarg) >= 0.0 && atof(optarg) <= 360.0) test_rotate = atof(optarg) * PI * 2.0 / 360.0; break; case OPT_TRANSLATE: test_translate = atof(optarg); break; //Output: case 1: point_match1=optarg; break; case 2: point_match2=optarg; break; case 3: point_max1=optarg; break; case 4: point_min1=optarg; break; case 5: point_max2=optarg; break; case 6: point_min2=optarg; break; } } ARG_IMG1 = optind; ARG_IMG2 = optind+1; FILE* match1=0;match1=fopen(point_match1,"w");fclose(match1); FILE* match2=0;match2=fopen(point_match2,"w");fclose(match2); FILE* max1=0;max1=fopen(point_max1,"w");fclose(max1); FILE* min1=0;min1=fopen(point_min1,"w");fclose(min1); FILE* max2=0;max2=fopen(point_max2,"w");fclose(max2); FILE* min2=0;min2=fopen(point_min2,"w");fclose(min2); typedef float PixelType; typedef itk::Image< PixelType, Dimension > FixedImageType; typedef itk::ScaleInvariantFeatureImageFilter SiftFilterType; typedef itk::ImageSource< FixedImageType > ImageSourceType; ImageSourceType::Pointer fixedImageReader, fixedImageReader2; // ---- USAGE: if( argc <= ARG_IMG1 || (mode == 'i' && argc <= ARG_IMG2)) { std::cerr << "Incorrect number of parameters " << std::endl; std::cerr << std::endl; std::cerr << "USAGE: \n"; std::cerr << argv[0] << " [options] ImageFile [ImageFile2]\n"; std::cerr << "This program takes as input 3D images and generates Scale Invariant Feature Transform" << std::endl; std::cerr << std::endl; std::cerr << "**IMAGE PROCESSING OPTIONS (Choose ONE):" << std::endl; std::cerr << "--image " << std::endl; std::cerr << " compare ImageFile.mha and ImageFile2.mha" << std::endl; std::cerr << "OR\n" << std::endl; std::cerr << "--synthetic " << std::endl; std::cerr << " compare ImageFile to synthetically generated version" << std::endl; std::cerr << " return the synthetic image as output (image_transform.mha)" << std::endl; std::cerr << " Synthetic Image Options:" << std::endl; std::cerr << " --rotate " << std::endl; std::cerr << " rotate synthetic image on first axis [degree]" << std::endl; std::cerr << " --translate " << std::endl; std::cerr << " translate synthetic image [mm]" << std::endl; std::cerr << " --scale " << std::endl; std::cerr << " scale all axes of synthetic image" << std::endl; std::cerr << " --transform-middle"<< std::endl; std::cerr << " center of transformation: center of the image (default origin)" << std::endl; std::cerr << "\n**PARAMETERS:\n" << std::endl; /*std::cerr << "--dimension " << std::endl; std::cerr << " image dimension (default 3)" << std::endl;*/ std::cerr << "--double " << std::endl; std::cerr << " image doubling -> yes:1 or no:0 (default 0)" << std::endl; std::cerr << "--octave " << std::endl; std::cerr << " set number of octaves (default 3)" << std::endl; //the number of octave is a function of the image dimension! std::cerr << "--initial-sigma1 " << std::endl; std::cerr << " set Gaussian blur initial sigma for ImageFile (default 2mm)" << std::endl; std::cerr << "--initial-sigma2 " << std::endl; std::cerr << " set Gaussian blur initial sigma for ImageFile2/synthetic version" << std::endl; std::cerr << " (default 2mm)" << std::endl; std::cerr << "--contrast " << std::endl; std::cerr << " threshold on image contrast (default 0.03 for image value in [0,1])" << std::endl; std::cerr << " if contrast value is 0, the contrast threshold is not performed" << std::endl; std::cerr << " if contrast value is greater than 1, the curvature threshold" << std::endl; std::cerr << " is not performed in default modality" << std::endl; std::cerr << "--curvature " << std::endl; std::cerr << " threshold on image curvature (default 172.3 for image value in [0,1])" << std::endl; std::cerr << " if curvature value is 0, the curvature threshold is not performed" << std::endl; std::cerr << "--descr-dim " << std::endl; std::cerr << " half of the keypoint descriptor region size" << std::endl; std::cerr << " (default 8 voxels -> 16x16x16 region size)" << std::endl; std::cerr << "--match-ratio " << std::endl; std::cerr << " set matching ratio in the range [0,1] (default 0.9)" << std::endl; std::cerr << "\n**OUTPUT:\n" << std::endl; std::cerr << "Default: Feature in physical coordinates in RAS system (file format .fcsv)" << std::endl; std::cerr << "--out-max1 " << std::endl; std::cerr << " maxima keypoints of ImageFile (default phy_max1.fcsv)" << std::endl; std::cerr << "--out-min1 " << std::endl; std::cerr << " minima keypoints of ImageFile (default phy_min1.fcsv)" << std::endl; std::cerr << "--out-max2 " << std::endl; std::cerr << " maxima keypoints of ImageFile2 (default phy_max2.fcsv)" << std::endl; std::cerr << "--out-min2 " << std::endl; std::cerr << " minima keypoints of ImageFile2 (default phy_max2.fcsv)" << std::endl; std::cerr << "--out-match1 " << std::endl; std::cerr << " matching keypoints of ImageFile (default point_match1.fcsv)" << std::endl; std::cerr << "--out-match2 " << std::endl; std::cerr << " matching keypoints of ImageFile2 (default point_match2.fcsv)" << std::endl; std::cerr << std::endl; return 1; } std::cerr << "Dimension = " << Dimension << "\n"; /*std::cerr << "Test Scale = " << test_scale << "\n"; std::cerr << "Test Rotate = " << test_rotate << "\n"; std::cerr << "Test Translate = " << test_translate << "\n";*/ std::cerr << "Mode = " << (char) mode << "\n"; std::cerr << "ImageFile1 = " << argv[optind] << "\n"; /*std::cerr << "curvature = " << curvature << "\n"; std::cerr << "flag_curve = " << flag_curve << "\n"; std::cerr << "contrast = " << contrast << "\n"; std::cerr << "normalization = " << normalization << "\n";*/ std::cerr << "SIFT Feature\n" << std::endl; //Read Input Image1 typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType; FixedImageReaderType::Pointer tmpImageReader = FixedImageReaderType::New(); tmpImageReader = FixedImageReaderType::New(); tmpImageReader->SetFileName( argv[ARG_IMG1] ); fixedImageReader=tmpImageReader; fixedImageReader->Update(); FixedImageType::Pointer fixedImage= FixedImageType::New(); try{ fixedImage = fixedImageReader->GetOutput(); } catch (itk::ExceptionObject &err) { std::cout << "ExceptionObject caught !" << std::endl; std::cout << err << std::endl; return -1; } SiftFilterType::PointSetTypePointer keypoints1, keypoints2; SiftFilterType siftFilter1, siftFilter2; //siftFilter1.writeImage(fixedImage, "InputImage1.mha"); //set parameters: siftFilter1.SetDoubling(image_doubled); siftFilter1.SetNumScales(octave); siftFilter1.SetInitialSigma(initial_sigma1); siftFilter1.SetContrast(contrast); siftFilter1.SetCurvature(curvature); siftFilter1.SetDescriptorDimension(descriptor_dimension); siftFilter1.SetMatchRatio(match_ratio); //output keypoints from first Image keypoints1 = siftFilter1.getSiftFeatures(fixedImage, flag_curve,normalization, point_max1,point_min1,"imagecoord_max1.txt","imagecoord_min1.txt","point_rej_contrast1.fcsv","point_rej_curvature1.fcsv"); typedef itk::AffineTransform< double, Dimension > TestTransformType; typedef TestTransformType::InputVectorType VectorType; typedef TestTransformType::ParametersType ParametersType; TestTransformType::Pointer test_transform = TestTransformType::New(); test_transform->SetIdentity(); FixedImageType::Pointer scaledImage = FixedImageType::New(); // ---- SYNTHETIC TEST IMAGE: if (mode=='s') { std::cerr << std::endl << "Synthetic image mode\n"; const unsigned int np = test_transform->GetNumberOfParameters(); ParametersType parameters( np ); // Number of parameters TestTransformType::InputPointType translate_vector; FixedImageType::PointType origin = fixedImage->GetOrigin(); FixedImageType::SpacingType spacing = fixedImage->GetSpacing(); FixedImageType::SizeType size = fixedImage->GetLargestPossibleRegion().GetSize(); if (transform_middle) { std::cerr << "Transformation centred at middle of image." << std::endl; /* Cycle through each dimension and shift by half, taking into account the element spacing*/ for (int k = 0; k < Dimension; ++k) translate_vector[k] = origin[k]+(size[k]/2.0)*spacing[k]; test_transform->SetCenter(translate_vector); std::cout<<"Center of Transformation: "<GetOrigin()<SetCenter( origin ); std::cout<<"Center of Transformation: "<GetCenter()<GetOrigin()<Rotate(0,1,test_rotate); test_transform->Rotate3D(rot,test_rotate); //TRANSLATION: TestTransformType::OutputVectorType tr; tr[0]=tr[1]=tr[2]=test_translate; test_transform->Translate(tr); //SCALING: TestTransformType::OutputVectorType scaling; scaling[0]=scaling[1]=scaling[2]= test_scale; test_transform->Scale(scaling); std::cout << "Transform Parms: " << std::endl; std::cout << test_transform->GetParameters() << std::endl; /*std::cout << "MATRIX: " << std::endl; std::cout << test_transform->GetMatrix() << std::endl;*/ FixedImageType::Pointer scaledImage; typedef itk::ResampleImageFilter ResampleFilterType; ResampleFilterType::Pointer scaler = ResampleFilterType::New(); scaler->SetInput(fixedImage); //scaler->SetSize(size); //scaler->SetOutputSpacing(spacing); //scaler->SetOutputOrigin(origin); //scaler->SetOutputDirection( fixedImage->GetDirection() ); FixedImageType::SizeType newsize; FixedImageType::PointType offset; for (int k = 0; k < Dimension; ++k) newsize[k] = (unsigned int) size[k] / test_scale; scaler->SetSize( newsize ); std::cout << "New size: " << newsize << std::endl; scaler->SetOutputSpacing(spacing); if(newsize!=size && transform_middle) //scaling centred at middle of image { for (int k = 0; k < Dimension; ++k) offset[k]=translate_vector[k]-(newsize[k]/2.0)*spacing[k]; std::cout<<"New Origin: "<SetOutputOrigin(offset); } else {scaler->SetOutputOrigin(origin);} scaler->SetOutputDirection( fixedImage->GetDirection() ); //INTERPOLATION: // Linear Interpolation: typedef itk::LinearInterpolateImageFunction< FixedImageType, double > InterpolatorType; InterpolatorType::Pointer interpolator = InterpolatorType::New(); // B-spline Interpolation: /* typedef itk::BSplineInterpolateImageFunction< FixedImageType, double > InterpolatorType; InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetSplineOrder(3); interpolator->SetInputImage(fixedImage); interpolator->UseImageDirectionOn();*/ scaler->SetInterpolator( interpolator ); scaler->SetDefaultPixelValue( (PixelType) -1200 ); scaler->SetTransform(test_transform); scaler->Update(); scaledImage = scaler->GetOutput(); //set parameters for synthetic image siftFilter2.SetDoubling(image_doubled); siftFilter2.SetNumScales(octave); siftFilter2.SetDescriptorDimension(descriptor_dimension); siftFilter2.SetInitialSigma(initial_sigma2); siftFilter2.SetContrast(contrast); siftFilter2.SetCurvature(curvature); siftFilter2.SetMatchRatio(match_ratio); siftFilter2.writeImage(scaledImage, "image_transform.mha"); //output keypoints of synthetic image keypoints2 = siftFilter2.getSiftFeatures(scaledImage,flag_curve,normalization,point_max2,point_min2,"imagecoord_max2.txt","imagecoord_min2.txt","point_rej_contrast2.fcsv","point_rej_curvature2.fcsv"); /*std::cerr << "Test Image Scale: " << test_scale << std::endl; std::cerr << "Test Translate: " << test_translate << std::endl; std::cerr << "Test Image Rotate: " << test_rotate << std::endl;*/ } // ---- IMAGE COMPARISON MODE: else if (mode == 'i') { std::cerr << std::endl << "Image Comparison mode\n"; //Read ImageFile2 typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType; FixedImageReaderType::Pointer tmpImageReader = FixedImageReaderType::New(); tmpImageReader = FixedImageReaderType::New(); tmpImageReader->SetFileName( argv[ARG_IMG2] ); fixedImageReader2 = tmpImageReader; fixedImageReader2->Update(); FixedImageType::Pointer fixedImage2 = fixedImageReader2->GetOutput(); //set parameters for ImageFile2 siftFilter2.SetDoubling(image_doubled); siftFilter2.SetNumScales(octave); siftFilter2.SetDescriptorDimension(descriptor_dimension); siftFilter2.SetInitialSigma(initial_sigma2); siftFilter2.SetContrast(contrast); siftFilter2.SetCurvature(curvature); siftFilter2.SetMatchRatio(match_ratio); //output keypoints from ImageFile2 keypoints2 = siftFilter2.getSiftFeatures(fixedImage2,flag_curve,normalization,point_max2,point_min2,"imagecoord_max2.txt","imagecoord_min2.txt","point_rej_contrast2.fcsv","point_rej_curvature2.fcsv"); } // ---- MATCHING: std::cerr << std::endl << "Matching Keypoints\n"; siftFilter2.MatchKeypointsFeatures(keypoints1, keypoints2, point_match1, point_match2); return 0; } #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/sift.h000066400000000000000000000042401321604176500267120ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _sift_h_ #define _sift_h_ #include "plmutil_config.h" #include #include #include "plm_macros.h" #include "itk_image_type.h" class Sift_private; class Plm_image; /*! \brief * The Sift class implements a SIFT feature detector. */ class PLMUTIL_API Sift { public: Sift (); ~Sift (); public: Sift_private *d_ptr; public: /*! \name Inputs */ ///@{ /*! \brief Set the input image. The image will be loaded from the specified filename. */ void set_image (const char* image_fn); /*! \brief Set the input image. The image will be loaded from the specified filename. */ void set_image (const std::string& image_fn); /*! \brief Set the input image as a Plm image. */ void set_image (Plm_image* image); /*! \brief Set the input image as an ITK image. */ void set_image (const FloatImageType::Pointer image); /*! \brief Set the contrast threshold */ void set_contrast_threshold (float contrast_threshold); /*! \brief Set the curvature threshold */ void set_curvature_threshold (float curvature_threshold); ///@} /*! \name Execution */ ///@{ /*! \brief Compute SIFT feature locations in the input image. */ void run (); /*! \brief Do feature matching, and write output to file. This should be a separate class. */ static void match_features (Sift& sift1, Sift& sift2, const char* filename1, const char* filename2, float match_ratio); ///@} /*! \name Outputs */ ///@{ /*! \brief Return the detected keypoints. Unfortunately, the SIFT keypoints are not (yet) compatible with ordinary plastimatch (native or itk) pointsets. */ itk::ScaleInvariantFeatureImageFilter::PointSetTypePointer get_keypoints (); /*! \brief Save the sift-detected points to a fcsv file. */ void save_pointset (const char* filename); ///@} }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/simplify_points.cxx000066400000000000000000000106751321604176500315610ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include "vnl/vnl_random.h" #include "itk_pointset.h" #include "logfile.h" #include "rt_study.h" #include "rtss_contour.h" #include "rtss_roi.h" #include "rtss.h" #include "simplify_points.h" /* ----------------------------------------------------------------------- Resorting method for the simplified vector of points ----------------------------------------------------------------------- */ int compare (const void * a, const void * b) { return ( *(int*)a < *(int*)b ); } /* ----------------------------------------------------------------------- Actual function that simplifies the contours ----------------------------------------------------------------------- */ void do_simplify (Rt_study *rtds, float percentage) { int num_structures=0; int first_index_to_remove=0; Rtss_roi *curr_struct; Rtss_contour *curr_polyline; vnl_random gnr; lprintf ("Hello from simplify_points! \n" "You are going to delete %f percent of points from your dataset\n", percentage); /* Check file_type */ // if (file_type != PLM_FILE_FMT_DICOM_RTSS) { // printf("Error: the input file is not a dicom RT struct!"); // exit(-1); // } Rtss *rtss_ss = rtds->get_segmentation()->get_structure_set_raw (); num_structures = rtss_ss->num_structures; for(int j=0;jslist[j]; for(size_t k=0;knum_contours;k++){ int *index, *ordered_index; gnr.restart(); curr_polyline=curr_struct->pslist[k]; ShortPointSetType::PointType curr_point; ShortPointsContainer::Pointer points = ShortPointsContainer::New(); ShortPointsContainer::Pointer shuffled_points = ShortPointsContainer::New(); //index = (int*) malloc (sizeof (int) * curr_polyline->num_vertices); //ordered_index = (int*) malloc (sizeof (int) * curr_polyline->num_vertices); index = new int[curr_polyline->num_vertices]; ordered_index = new int[curr_polyline->num_vertices]; //extract vertices of the current contour and extract random indices for (size_t j = 0; j < curr_polyline->num_vertices; j++) { curr_point[0]=curr_polyline->x[j]; curr_point[1]=curr_polyline->y[j]; curr_point[2]=curr_polyline->z[j]; points->InsertElement( j , curr_point ); index[j]=gnr.drand64()*curr_polyline->num_vertices+0; } first_index_to_remove= int(double(curr_polyline->num_vertices) * ((100.0-percentage)/100.0)); //removes the points according to the user-defined percentage for(int pointId=0; pointIdnum_vertices=first_index_to_remove; new_polyline->slice_no=curr_polyline->slice_no; new_polyline->ct_slice_uid=curr_polyline->ct_slice_uid; new_polyline->x = new float[first_index_to_remove+1]; new_polyline->y = new float[first_index_to_remove+1]; new_polyline->z = new float[first_index_to_remove+1]; //get the final points for(int pointId=0; pointIdGetElement(ordered_index[pointId]); new_polyline->x[pointId]=curr_point[0]; new_polyline->y[pointId]=curr_point[1]; new_polyline->z[pointId]=curr_point[2]; } curr_point=points->GetElement(ordered_index[0]); new_polyline->x[first_index_to_remove]=curr_point[0]; new_polyline->y[first_index_to_remove]=curr_point[1]; new_polyline->z[first_index_to_remove]=curr_point[2]; curr_struct->pslist[k]=new_polyline; free (index); free (ordered_index); } } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/simplify_points.h000066400000000000000000000006261321604176500312010ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _simplify_points_h_ #define _simplify_points_h_ #include "plmutil_config.h" class Rt_study; PLMUTIL_C_API void do_simplify (Rt_study *rtds, float percentage); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/ss_img_stats.cxx000066400000000000000000000025461321604176500310260ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include "itkImageRegionIterator.h" #include "itkVariableLengthVector.h" #include "itk_image_type.h" #include "plm_int.h" #include "ss_img_stats.h" void ss_img_stats ( UCharVecImageType::Pointer img ) { UCharVecImageType::RegionType rg = img->GetLargestPossibleRegion (); typedef itk::ImageRegionIterator< UCharVecImageType > UCharVecIteratorType; UCharVecIteratorType it (img, rg); int vector_length = img->GetVectorLength(); printf ("SS_IMAGE: At most %d structures\n", vector_length * 8); uint32_t *hist = new uint32_t[vector_length * 8]; for (int i = 0; i < vector_length; i++) { for (int j = 0; j < 8; j++) { hist[i*8+j] = 0; } } for (it.GoToBegin(); !it.IsAtEnd(); ++it) { itk::VariableLengthVector< unsigned char > v = it.Get(); for (int i = 0; i < vector_length; i++) { unsigned char c = v[i]; for (int j = 0; j < 8; j++) { if (c & (1 << j)) { hist[i*8+j] ++; } } } } for (int i = 0; i < vector_length; i++) { for (int j = 0; j < 8; j++) { printf ("S %4d NVOX %10d\n", i*8+j, hist[i*8+j]); } } delete[] hist; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/ss_img_stats.h000066400000000000000000000006321321604176500304450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _ss_img_stats_h_ #define _ss_img_stats_h_ #include "plmutil_config.h" #include "itk_image_type.h" PLMUTIL_C_API void ss_img_stats (UCharVecImageType::Pointer img); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/synthetic_mha.cxx000066400000000000000000000652441321604176500311720ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include #include #include #include "itkImageRegionIteratorWithIndex.h" #include "vnl/vnl_random.h" #include "itk_directions.h" #include "itk_image_type.h" #include "itk_point.h" #include "logfile.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_math.h" #include "rt_study.h" #include "rtss.h" #include "segmentation.h" #include "synthetic_mha.h" class Synthetic_mha_parms_private { public: vnl_random v; float gabor_freq; float gabor_proj[3]; }; Synthetic_mha_parms::Synthetic_mha_parms () { d_ptr = new Synthetic_mha_parms_private; output_type = PLM_IMG_TYPE_ITK_FLOAT; pattern = PATTERN_GAUSS; input_fn = ""; for (int i = 0; i < 3; i++) { spacing[i] = 5.0f; dim[i] = 100; origin[i] = 0.0f; gauss_center[i] = 0.0f; gauss_std[i] = 100.0f; sphere_center[i] = 0.0f; sphere_radius[i] = 50.0f; donut_center[i] = 0.0f; lung_tumor_pos[i] = 0.0f; dose_center[i] = 0.0f; cylinder_center[i] = 0.0f; cylinder_radius[i] = 0.0f; } background = -1000.0f; foreground = 0.0f; background_alpha = 1.0f; foreground_alpha = 1.0f; m_want_ss_img = false; m_want_dose_img = false; image_normalization = NORMALIZATION_NONE; rect_size[0] = -50.0f; rect_size[1] = +50.0f; rect_size[2] = -50.0f; rect_size[3] = +50.0f; rect_size[4] = -50.0f; rect_size[5] = +50.0f; donut_radius[0] = 50.0f; donut_radius[1] = 50.0f; donut_radius[2] = 20.0f; donut_rings = 2; grid_spacing[0] = 10; grid_spacing[1] = 10; grid_spacing[2] = 10; penumbra = 5.0f; dose_size[0] = -50.0f; dose_size[1] = +50.0f; dose_size[2] = -50.0f; dose_size[3] = +50.0f; dose_size[4] = -50.0f; dose_size[5] = +50.0f; num_multi_sphere = 33; noise_mean = 0; noise_std = 1.f; gabor_use_k_fib = false; gabor_k_fib[0] = 0; gabor_k_fib[1] = 1; gabor_k[0] = 1.; gabor_k[1] = 0.; gabor_k[2] = 0.; } Synthetic_mha_parms::~Synthetic_mha_parms () { delete d_ptr; } static void synth_dose ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { /* sorry for this mess... */ float x,x0,x1,y,y0,y1,f0,f1; float p[3]; p[0] = phys[0] - parms->dose_center[0]; p[1] = phys[1] - parms->dose_center[1]; p[2] = phys[2] - parms->dose_center[2]; /* uniform central dose */ if (p[0] >= parms->dose_size[0] + parms->penumbra && p[0] <= parms->dose_size[1] - parms->penumbra && p[1] >= parms->dose_size[2] + parms->penumbra && p[1] <= parms->dose_size[3] - parms->penumbra && p[2] >= parms->dose_size[4] && p[2] <= parms->dose_size[5]) { *intens = parms->foreground; *label = 1; } else { *intens = parms->background; *label = 0; } if (p[2] >= parms->dose_size[4] && p[2] <= parms->dose_size[5]) { /* penumbra edges */ if (p[1] > parms->dose_size[2]+parms->penumbra && p[1] < parms->dose_size[3]-parms->penumbra){ x = p[0]; x0 = parms->dose_size[0]; x1 = parms->dose_size[0] + parms->penumbra; f0 = parms->background; f1 = parms->foreground; if (x >= x0 && x < x1) { *intens = f0 + (x-x0)*((f1-f0)/(x1-x0)); } x0 = parms->dose_size[1] - parms->penumbra; x1 = parms->dose_size[1]; f0 = parms->foreground; f1 = parms->background; if (x >= x0 && x < x1) { *intens = f0 + (x-x0)*((f1-f0)/(x1-x0)); } } if (p[0] > parms->dose_size[0]+parms->penumbra && p[0] < parms->dose_size[1]-parms->penumbra){ y = p[1]; y0 = parms->dose_size[2]; y1 = parms->dose_size[2] + parms->penumbra; f0 = parms->background; f1 = parms->foreground; if ((p[1] >= y0 && p[1] < y1)) { *intens = f0 + (y-y0)*((f1-f0)/(y1-y0)); } y0 = parms->dose_size[3] - parms->penumbra; y1 = parms->dose_size[3]; f0 = parms->foreground; f1 = parms->background; if (y >= y0 && y < y1) { *intens = f0 + (y-y0)*((f1-f0)/(y1-y0)); } } /* penumbra corners */ x = p[0]; y = p[1]; x0 = parms->dose_size[0]; x1 = parms->dose_size[0] + parms->penumbra; y0 = parms->dose_size[2]; y1 = parms->dose_size[2] + parms->penumbra; f0 = parms->background; f1 = parms->foreground; if (x > x0 && x < x1 && y > y0 && y < y1) { *intens = ((f0)/((x1-x0)*(y1-y0)))*(x1-x)*(y1-y) + ((f0)/((x1-x0)*(y1-y0)))*(x-x0)*(y1-y) + ((f0)/((x1-x0)*(y1-y0)))*(x1-x)*(y-y0) + ((f1)/((x1-x0)*(y1-y0)))*(x-x0)*(y-y0); } x = p[0]; y = p[1]; x0 = parms->dose_size[1] - parms->penumbra; x1 = parms->dose_size[1]; y0 = parms->dose_size[2]; y1 = parms->dose_size[2] + parms->penumbra; f0 = parms->background; f1 = parms->foreground; if (x > x0 && x < x1 && y > y0 && y < y1) { *intens = ((f0)/((x1-x0)*(y1-y0)))*(x1-x)*(y1-y) + ((f0)/((x1-x0)*(y1-y0)))*(x-x0)*(y1-y) + ((f1)/((x1-x0)*(y1-y0)))*(x1-x)*(y-y0) + ((f0)/((x1-x0)*(y1-y0)))*(x-x0)*(y-y0); } x = p[0]; y = p[1]; x0 = parms->dose_size[0]; x1 = parms->dose_size[0] + parms->penumbra; y0 = parms->dose_size[3] - parms->penumbra; y1 = parms->dose_size[3]; f0 = parms->background; f1 = parms->foreground; if (x > x0 && x < x1 && y > y0 && y < y1) { *intens = ((f0)/((x1-x0)*(y1-y0)))*(x1-x)*(y1-y) + ((f1)/((x1-x0)*(y1-y0)))*(x-x0)*(y1-y) + ((f0)/((x1-x0)*(y1-y0)))*(x1-x)*(y-y0) + ((f0)/((x1-x0)*(y1-y0)))*(x-x0)*(y-y0); } x = p[0]; y = p[1]; x0 = parms->dose_size[1] - parms->penumbra; x1 = parms->dose_size[1]; y0 = parms->dose_size[3] - parms->penumbra; y1 = parms->dose_size[3]; f0 = parms->background; f1 = parms->foreground; if (x > x0 && x < x1 && y > y0 && y < y1) { *intens = ((f1)/((x1-x0)*(y1-y0)))*(x1-x)*(y1-y) + ((f0)/((x1-x0)*(y1-y0)))*(x-x0)*(y1-y) + ((f0)/((x1-x0)*(y1-y0)))*(x1-x)*(y-y0) + ((f0)/((x1-x0)*(y1-y0)))*(x-x0)*(y-y0); } } } /* z-direction */ static void synth_gauss ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { double f = 0; for (int d = 0; d < 3; d++) { double f1 = phys[d] - (double) parms->gauss_center[d]; f1 = f1 / (double) parms->gauss_std[d]; f += f1 * f1; } f = exp (-0.5 * f); /* f \in (0,1] */ *intens = (1 - f) * parms->background + f * parms->foreground; *label = (f > 0.2) ? 1 : 0; } static void synth_grid ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { int ijk[3]; ijk[0] = (phys[0]/parms->spacing[0]) + (parms->dim[0]/2); ijk[1] = (phys[1]/parms->spacing[1]) + (parms->dim[1]/2); ijk[2] = (phys[2]/parms->spacing[2]) + (parms->dim[2]/2); if ( ((ijk[0] % parms->grid_spacing[0] == 0) && (ijk[1] % parms->grid_spacing[1] == 0)) || ((ijk[1] % parms->grid_spacing[1] == 0) && (ijk[2] % parms->grid_spacing[2] == 0)) || ((ijk[2] % parms->grid_spacing[2] == 0) && (ijk[1] % parms->grid_spacing[1] == 0)) || ((ijk[2] % parms->grid_spacing[2] == 0) && (ijk[0] % parms->grid_spacing[0] == 0)) ) { *intens = parms->foreground; *label = 1; } else { *intens = parms->background; *label = 0; } } static void synth_rect ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { if (phys[0] >= parms->rect_size[0] && phys[0] <= parms->rect_size[1] && phys[1] >= parms->rect_size[2] && phys[1] <= parms->rect_size[3] && phys[2] >= parms->rect_size[4] && phys[2] <= parms->rect_size[5]) { *intens = (1 - parms->foreground_alpha) * (*intens) + parms->foreground_alpha * parms->foreground; *label = 1; } else { *intens = (1 - parms->background_alpha) * (*intens) + parms->background_alpha * parms->background; *label = 0; } } static void synth_sphere ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { float f = 0; for (int d = 0; d < 3; d++) { float f1 = phys[d] - parms->sphere_center[d]; f1 = f1 / parms->sphere_radius[d]; f += f1 * f1; } if (f > 1.0) { *intens = (1 - parms->background_alpha) * (*intens) + parms->background_alpha * parms->background; *label = 0; } else { *intens = (1 - parms->foreground_alpha) * (*intens) + parms->foreground_alpha * parms->foreground; *label = 1; } } static void synth_multi_sphere ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { float f = 0; for (int d = 0; d < 3; d++) { float f1 = phys[d] - parms->sphere_center[d]; f1 = f1 / parms->sphere_radius[d]; f += f1 * f1; } if (f > 1.0) { *intens = parms->background; *label = 0; } else { *intens = parms->foreground; *label = 1; } } static void synth_donut ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { /* Set default values */ *intens = parms->background; *label = 0; float p[3]; for (int d = 0; d < 3; d++) { p[d] = (phys[d] - parms->donut_center[d]) / parms->donut_radius[d]; } float dist = sqrt (p[0]*p[0] + p[1]*p[1]); /* Compute which ring we are inside */ float ring_width = 1 / (float) parms->donut_rings; int ring_no = floor (dist / ring_width); /* If outside of all rings, return */ if (ring_no >= parms->donut_rings) { return; } /* If within "background ring", return */ if ((parms->donut_rings - ring_no) % 2 == 0) { return; } /* Compute distance from ring center */ float ring_offset_1 = dist - ring_no * ring_width; float ring_offset_2 = (ring_no + 1) * ring_width - dist; float ring_offset = 0.5 * ring_width - std::min (ring_offset_1, ring_offset_2); ring_offset = ring_offset / ring_width; /* If distance within donut, set to foreground */ float dist_3d_sq = ring_offset * ring_offset + p[2] * p[2]; if (dist_3d_sq < 1.) { *intens = parms->foreground; *label = 1; } } static void synth_lung ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { /* Set default values */ *intens = parms->background; *label = 0; /* Get distance from central axis */ float d2 = sqrt (phys[0]*phys[0] + phys[1]*phys[1]); /* If outside chest wall, return */ if (d2 > 150) { return; } /* If within chest wall, set chest wall intensity */ if (d2 > 130) { *intens = parms->foreground; *label = 1; return; } /* Get distance from tumor */ float p[3] = { phys[0] - parms->lung_tumor_pos[0], phys[1] - parms->lung_tumor_pos[1], phys[2] - parms->lung_tumor_pos[2] }; float d3 = sqrt (p[0]*p[0] + p[1]*p[1] + p[2]*p[2]); /* If within tumor, set tumor density */ if (d3 < 20) { *label = 3; *intens = parms->foreground; return; } /* Otherwise, must be lung */ *intens = -700; *label = 5; } static void synth_ramp ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { /* Get distance from origin */ float d; if (parms->pattern == PATTERN_XRAMP) { d = phys[0] - parms->origin[0]; } else if (parms->pattern == PATTERN_YRAMP) { d = phys[1] - parms->origin[1]; } else { d = phys[2] - parms->origin[2]; } /* Set intensity */ *label = 0; *intens = d; } static void synth_noise ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { double r = parms->d_ptr->v.normal64(); /* Set intensity */ *label = 0; *intens = parms->noise_mean + (float) r * parms->noise_std; } static void synth_cylinder ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { float f = 0; for (int d = 0; d < 2; d++) { float f1 = phys[d] - parms->cylinder_center[d]; f1 = f1 / parms->cylinder_radius[d]; f += f1 * f1; } if (f > 1.0) { *intens = (1 - parms->background_alpha) * (*intens) + parms->background_alpha * parms->background; *label = 0; } else { *intens = (1 - parms->foreground_alpha) * (*intens) + parms->foreground_alpha * parms->foreground; *label = 1; } } static void synth_gabor ( float *intens, unsigned char *label, const FloatPoint3DType& phys, const Synthetic_mha_parms *parms ) { /* Do gaussian first */ float f = 0; float rel[3]; for (int d = 0; d < 3; d++) { rel[d] = phys[d] - parms->gauss_center[d]; float f1 = rel[d] / parms->gauss_std[d]; f += f1 * f1; } f = exp (-0.5 * f); /* f \in (0,1] */ *intens = (1 - f) * parms->background + f * parms->foreground; *label = (f > 0.2) ? 1 : 0; /* Get the distance from the central plane in direction of projection vector ("k" vector) */ float proj_dist = 0.f; for (int d = 0; d < 3; d++) { proj_dist += rel[d] * parms->d_ptr->gabor_proj[d]; } /* Modulate by cos for real part, or sin for imaginary part */ *intens *= cos(parms->d_ptr->gabor_freq * proj_dist); } void synthetic_mha ( Rt_study *rt_study, Synthetic_mha_parms *parms ) { FloatImageType::SizeType sz; FloatImageType::IndexType st; FloatImageType::RegionType rg; FloatImageType::PointType og; FloatImageType::SpacingType sp; FloatImageType::DirectionType itk_dc; FloatImageType::Pointer im_out; if (parms->input_fn != "") { /* Input image was specified */ Plm_image pi (parms->input_fn); im_out = pi.itk_float (); /* GCS FIX: Ideally, the calling code will set the alpha values properly. Instead, here we set the background alpha to 0, with the understanding that the caller probably wants to paste a sphere or rectangle onto the existing image */ parms->background_alpha = 0.0f; } else { /* No input image specified */ if (parms->fixed_fn != "") { /* Get geometry from fixed image */ Plm_image pi (parms->fixed_fn); Plm_image_header pih; pih.set_from_plm_image (&pi); og = pih.GetOrigin(); sp = pih.GetSpacing(); rg = pih.GetRegion(); itk_dc = pih.GetDirection(); for (int d1 = 0; d1 < 3; d1++) { parms->origin[d1] = og[d1]; } } else { /* Get geometry from command line parms */ for (int d1 = 0; d1 < 3; d1++) { st[d1] = 0; sz[d1] = parms->dim[d1]; sp[d1] = parms->spacing[d1]; og[d1] = parms->origin[d1]; } rg.SetSize (sz); rg.SetIndex (st); itk_direction_from_dc (&itk_dc, parms->dc); } /* Create new ITK image for intensity */ im_out = FloatImageType::New(); im_out->SetRegions (rg); im_out->SetOrigin (og); im_out->SetSpacing (sp); im_out->SetDirection (itk_dc); im_out->Allocate (); /* Initialize to background */ im_out->FillBuffer (parms->background); } /* Create new ITK images for ss and dose */ UCharImageType::Pointer ss_img = UCharImageType::New(); typedef itk::ImageRegionIteratorWithIndex< UCharImageType > UCharIteratorType; UCharIteratorType ss_img_it; if (parms->m_want_ss_img) { ss_img->SetRegions (rg); ss_img->SetOrigin (og); ss_img->SetSpacing (sp); ss_img->Allocate(); ss_img_it = UCharIteratorType (ss_img, ss_img->GetLargestPossibleRegion()); ss_img_it.GoToBegin(); } FloatImageType::Pointer dose_img = FloatImageType::New(); typedef itk::ImageRegionIteratorWithIndex< FloatImageType > FloatIteratorType; FloatIteratorType dose_img_it; if (parms->m_want_dose_img) { dose_img->SetRegions (rg); dose_img->SetOrigin (og); dose_img->SetSpacing (sp); dose_img->Allocate(); dose_img_it = FloatIteratorType (dose_img, dose_img->GetLargestPossibleRegion()); dose_img_it.GoToBegin(); } /* Figure out Gabor settings */ if (parms->pattern == PATTERN_GABOR) { /* Figure out projection direction */ if (parms->gabor_use_k_fib) { /* Fibonacci method selected. */ /* N.b. I'm not sure which is the better value for phi. So let's use the golden section value. */ //float phi = (3. - sqrt(5.)) * M_PI; float phi = (((sqrt(5.) + 1.) / 2.) - 1.) * M_PI; float longitude = fmodf (phi * parms->gabor_k_fib[0], 2 * M_PI); float latitude_sin = -1. + 2. * ((float) parms->gabor_k_fib[0]) / parms->gabor_k_fib[1]; float latitude = asinf (latitude_sin); float latitude_cos = cos (latitude); parms->d_ptr->gabor_proj[0] = latitude_cos * cos (longitude); parms->d_ptr->gabor_proj[1] = latitude_cos * sin (longitude); parms->d_ptr->gabor_proj[2] = latitude_sin; lprintf ("Gabor: %d %d -> (%f %f) -> (%f %f %f)\n", parms->gabor_k_fib[0], parms->gabor_k_fib[1], longitude, latitude, parms->d_ptr->gabor_proj[0], parms->d_ptr->gabor_proj[1], parms->d_ptr->gabor_proj[2]); } else { /* Standard "k" vector supplied. Need to normalize it. */ float len = vec3_len (parms->gabor_k); if (len < FLOAT_SMALL_VECTOR_LENGTH) { parms->gabor_k[0] = 1.; parms->gabor_k[1] = 0.; parms->gabor_k[2] = 0.; len = 1.; } vec3_scale3 (parms->d_ptr->gabor_proj, parms->gabor_k, len); } /* Automatically set frequency based on width. The value 1.5 is a heuristic. */ float sum = 0.f; for (int d = 0; d < 3; d++) { sum += parms->gauss_std[d] * parms->gauss_std[d]; } parms->d_ptr->gabor_freq = M_PI * 1.5 / sqrt(sum); parms->image_normalization = Synthetic_mha_parms::NORMALIZATION_GABOR; } /* Iterate through image, setting values */ typedef itk::ImageRegionIteratorWithIndex< FloatImageType > IteratorType; IteratorType it_out (im_out, im_out->GetLargestPossibleRegion()); for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { FloatPoint3DType phys; //float intens = 0.0f; float intens = it_out.Get(); unsigned char label_uchar = 0; /* Get 3D coordinates of voxel */ FloatImageType::IndexType idx = it_out.GetIndex (); im_out->TransformIndexToPhysicalPoint (idx, phys); /* Compute intensity and label */ switch (parms->pattern) { case PATTERN_GAUSS: synth_gauss (&intens, &label_uchar, phys, parms); break; case PATTERN_RECT: synth_rect (&intens, &label_uchar, phys, parms); break; case PATTERN_SPHERE: synth_sphere (&intens, &label_uchar, phys, parms); break; case PATTERN_MULTI_SPHERE: synth_multi_sphere (&intens, &label_uchar, phys, parms); break; case PATTERN_DONUT: synth_donut (&intens, &label_uchar, phys, parms); break; case PATTERN_DOSE: synth_dose (&intens, &label_uchar, phys, parms); break; case PATTERN_GRID: synth_grid (&intens, &label_uchar, phys, parms); break; case PATTERN_LUNG: synth_lung (&intens, &label_uchar, phys, parms); break; case PATTERN_XRAMP: case PATTERN_YRAMP: case PATTERN_ZRAMP: synth_ramp (&intens, &label_uchar, phys, parms); break; case PATTERN_NOISE: synth_noise (&intens, &label_uchar, phys, parms); break; case PATTERN_CYLINDER: synth_cylinder (&intens, &label_uchar, phys, parms); break; case PATTERN_GABOR: synth_gabor (&intens, &label_uchar, phys, parms); break; default: intens = 0.0f; label_uchar = 0; break; } /* Set intensity */ it_out.Set (intens); /* Set structure */ if (parms->m_want_ss_img) { ss_img_it.Set (label_uchar); ++ss_img_it; } /* Set dose */ if (parms->m_want_dose_img) { float dose = 0.; const float thresh = parms->background + 0.5 * (parms->foreground - parms->background); if (parms->foreground > parms->background && intens > thresh) { dose = 15; } else if (parms->foreground < parms->background && intens < thresh) { dose = 15; } else { dose = 0; } dose_img_it.Set (dose); ++dose_img_it; } } /* Normalize if requested */ if (parms->image_normalization == Synthetic_mha_parms::NORMALIZATION_SUM_ONE) { float sum = 0.f; for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { sum += it_out.Get(); } if (sum > 1e-10) { for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { it_out.Set(it_out.Get() / sum); } } } else if (parms->image_normalization == Synthetic_mha_parms::NORMALIZATION_SUM_SQR_ONE) { float sum = 0.f; for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { float v = it_out.Get(); sum += v * v; } sum = sqrt(sum); if (sum > 1e-10) { for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { it_out.Set(it_out.Get() / sum); } } } else if (parms->image_normalization == Synthetic_mha_parms::NORMALIZATION_ZERO_MEAN_STD_ONE) { /* GCS FIX: I should really compute in a single pass. Oh God almighty, when did I get so lazy? */ int num_vox = 0; float sum_1 = 0.f, sum_2 = 0.f; for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { float v = it_out.Get(); sum_1 += v; num_vox ++; } sum_1 = sum_1 / num_vox; for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { float v = it_out.Get() - sum_1; it_out.Set(v); sum_2 += v * v; } sum_2 = sqrt(sum_2); if (sum_2 > 1e-10) { for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { it_out.Set(it_out.Get() / sum_2); } } } else if (parms->image_normalization == Synthetic_mha_parms::NORMALIZATION_GABOR) { float sum_lo_1 = 0.f, sum_hi_1 = 0.f; float sum_lo_2 = 0.f, sum_hi_2 = 0.f; for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { float v = it_out.Get(); if (v < 0) { sum_lo_1 += v; sum_lo_2 += v * v; } else if (v > 0) { sum_hi_1 += v; sum_hi_2 += v * v; } } sum_lo_2 = M_SQRT1_2 * sqrt(sum_lo_2); sum_hi_2 = M_SQRT1_2 * sqrt(sum_hi_2); float sum_lo_3 = 0.f, sum_hi_3 = 0.f; if (sum_lo_2 > 1e-10 && sum_hi_2 > 1e-10) { if (sum_lo_2 < sum_hi_2) { sum_lo_2 = sum_hi_2 * -sum_lo_1 / sum_hi_1; } else { sum_hi_2 = sum_lo_2 * -sum_hi_1 / sum_lo_1; } for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { float v = it_out.Get(); if (v < 0) { it_out.Set(v / sum_lo_2); sum_lo_3 += v / sum_lo_2; } else if (v > 0) { it_out.Set(v / sum_hi_2); sum_hi_3 += v / sum_hi_2; } } } } /* Insert images into rt_study */ Plm_image::Pointer pli = Plm_image::New(); pli->set_itk (im_out); rt_study->set_image (pli); if (parms->m_want_ss_img) { /* Create rtss & set into rt_study */ Segmentation::Pointer seg = Segmentation::New (); rt_study->set_segmentation (seg); /* Insert ss_image into rtss */ seg->set_ss_img (ss_img); /* Insert structure set into rtss */ Rtss *rtss_ss = new Rtss; seg->set_structure_set (rtss_ss); /* Add structure names */ switch (parms->pattern) { case PATTERN_LUNG: rtss_ss->add_structure ( std::string ("Body"), std::string(), 1, 0); rtss_ss->add_structure ( std::string ("Tumor"), std::string(), 2, 1); rtss_ss->add_structure ( std::string ("Lung"), std::string(), 3, 2); break; default: rtss_ss->add_structure ( std::string ("Foreground"), std::string(), 1, 0); } } if (parms->m_want_dose_img) { rt_study->set_dose (dose_img); } } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/synthetic_mha.h000066400000000000000000000041151321604176500306050ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _synthetic_mha_h_ #define _synthetic_mha_h_ #include "plmutil_config.h" #include #include "direction_cosines.h" #include "plm_image_type.h" class Rt_study; enum Pattern_type { PATTERN_DOSE, PATTERN_GAUSS, PATTERN_RECT, PATTERN_SPHERE, PATTERN_MULTI_SPHERE, PATTERN_DONUT, PATTERN_GRID, PATTERN_LUNG, PATTERN_XRAMP, PATTERN_YRAMP, PATTERN_ZRAMP, PATTERN_NOISE, PATTERN_CYLINDER, PATTERN_GABOR }; class Synthetic_mha_parms_private; class PLMUTIL_API Synthetic_mha_parms { public: Synthetic_mha_parms_private *d_ptr; public: enum Image_normalization { NORMALIZATION_NONE, NORMALIZATION_SUM_ONE, NORMALIZATION_SUM_SQR_ONE, NORMALIZATION_ZERO_MEAN_STD_ONE, NORMALIZATION_GABOR }; public: Plm_image_type output_type; Pattern_type pattern; std::string fixed_fn; std::string input_fn; int dim[3]; float origin[3]; float spacing[3]; Direction_cosines dc; float background; float foreground; float background_alpha; float foreground_alpha; bool m_want_ss_img; bool m_want_dose_img; Image_normalization image_normalization; float gauss_center[3]; float gauss_std[3]; float penumbra; float dose_size[6]; float dose_center[3]; float rect_size[6]; float sphere_center[3]; float sphere_radius[3]; float donut_center[3]; float donut_radius[3]; int donut_rings; int grid_spacing[3]; float lung_tumor_pos[3]; float noise_mean; float noise_std; float cylinder_radius[3]; float cylinder_center[3]; bool gabor_use_k_fib; int gabor_k_fib[2]; float gabor_k[3]; int num_multi_sphere; public: Synthetic_mha_parms (); ~Synthetic_mha_parms (); }; PLMUTIL_API void synthetic_mha (Rt_study *rtds, Synthetic_mha_parms *parms); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/synthetic_vf.cxx000066400000000000000000000055241321604176500310330ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ /* Correct mha files which have incorrect patient orientations */ #include "plmutil_config.h" #include #include #include #include "itkImageRegionIteratorWithIndex.h" #include "plm_math.h" #include "synthetic_vf.h" DeformationFieldType::Pointer synthetic_vf (Synthetic_vf_parms* parms) { /* Create ITK vf */ DeformationFieldType::Pointer vf_out = DeformationFieldType::New(); printf ("Setting header\n"); parms->pih.print (); itk_image_set_header (vf_out, &parms->pih); printf ("Header was set\n"); vf_out->Allocate(); /* Iterate through vf, setting values */ typedef itk::ImageRegionIteratorWithIndex< DeformationFieldType > IteratorType; IteratorType it_out (vf_out, vf_out->GetRequestedRegion()); /* Stock displacements can be initialized outside of loop */ FloatVector3DType disp; for (int d = 0; d < 3; d++) { switch (parms->pattern) { case Synthetic_vf_parms::PATTERN_ZERO: default: disp[d] = 0; break; case Synthetic_vf_parms::PATTERN_TRANSLATION: disp[d] = parms->translation[d]; break; } } for (it_out.GoToBegin(); !it_out.IsAtEnd(); ++it_out) { FloatPoint3DType phys; /* Get 3D coordinate of voxel */ DeformationFieldType::IndexType idx = it_out.GetIndex (); vf_out->TransformIndexToPhysicalPoint (idx, phys); switch (parms->pattern) { case Synthetic_vf_parms::PATTERN_GAUSSIAN: { float diff[3]; float dist_2 = 0; float f; for (int d = 0; d < 3; d++) { diff[d] = (phys[d] - parms->gaussian_center[d]) / parms->gaussian_std[d]; dist_2 += diff[d] * diff[d]; } f = exp (-0.5 * dist_2); for (int d = 0; d < 3; d++) { disp[d] = parms->gaussian_mag[d] * f; } break; } case Synthetic_vf_parms::PATTERN_RADIAL: { float diff[3]; float dist_2 = 0; for (int d = 0; d < 3; d++) { diff[d] = (phys[d] - parms->radial_center[d]) / parms->radial_mag[d] / 3; dist_2 += diff[d] * diff[d]; } for (int d = 0; d < 3; d++) { if (dist_2 > 1.) { diff[d] = diff[d] / sqrt(dist_2); } disp[d] = parms->radial_mag[d] * diff[d]; } break; } case Synthetic_vf_parms::PATTERN_ZERO: case Synthetic_vf_parms::PATTERN_TRANSLATION: default: /* Don't change disp */ break; } it_out.Set (disp); } return vf_out; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/synthetic_vf.h000066400000000000000000000022361321604176500304550ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _synthetic_vf_h_ #define _synthetic_vf_h_ #include "plmutil_config.h" #include "plm_image_header.h" // TODO: change type of pih to Plm_image_header* //class Plm_image_header; class Synthetic_vf_parms { public: enum Pattern { PATTERN_ZERO, PATTERN_TRANSLATION, PATTERN_RADIAL, PATTERN_GAUSSIAN, PATTERN_UNKNOWN }; public: Pattern pattern; Plm_image_header pih; float gaussian_center[3]; float gaussian_mag[3]; float gaussian_std[3]; float radial_center[3]; float radial_mag[3]; float translation[3]; public: Synthetic_vf_parms () { pattern = PATTERN_UNKNOWN; for (int i = 0; i < 3; i++) { gaussian_center[i] = 0.0f; gaussian_mag[i] = 0.0f; gaussian_std[i] = 0.0f; radial_center[i] = 0.0f; radial_mag[i] = 0.0f; translation[i] = 0.0f; } } }; PLMUTIL_API DeformationFieldType::Pointer synthetic_vf (Synthetic_vf_parms* parms); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/threshbox.cxx000066400000000000000000000456461321604176500303450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include #include #include #include "itkImageRegionIteratorWithIndex.h" #include "compiler_warnings.h" #include "itk_directions.h" #include "itk_image_type.h" #include "plm_image.h" #include "plm_image_header.h" #include "plm_int.h" #include "plm_math.h" #include "threshbox.h" void do_threshbox( Threshbox_parms *parms) { float spacing_in[3], origin_in[3]; plm_long dim_in[3]; Plm_image_header pih; unsigned char label_uchar, label_box; FloatImageType::Pointer img_in = parms->img_in->itk_float(); pih.set_from_itk_image (img_in); pih.get_dim (dim_in); pih.get_origin (origin_in ); pih.get_spacing (spacing_in ); // direction cosines?? /* Create ITK image for labelmap */ FloatImageType::SizeType sz; FloatImageType::IndexType st; FloatImageType::RegionType rg; FloatImageType::PointType og; FloatImageType::SpacingType sp; FloatImageType::DirectionType itk_dc; for (int d1 = 0; d1 < 3; d1++) { st[d1] = 0; sz[d1] = dim_in[d1]; sp[d1] = spacing_in[d1]; og[d1] = origin_in[d1]; } rg.SetSize (sz); rg.SetIndex (st); itk_direction_from_dc (&itk_dc, parms->dc); // labelmap thresholded image UCharImageType::Pointer uchar_img = UCharImageType::New(); uchar_img->SetRegions (rg); uchar_img->SetOrigin (og); uchar_img->SetSpacing (sp); uchar_img->Allocate(); // box image UCharImageType::Pointer box_img = UCharImageType::New(); box_img->SetRegions (rg); box_img->SetOrigin (og); box_img->SetSpacing (sp); box_img->Allocate(); typedef itk::ImageRegionIteratorWithIndex< UCharImageType > UCharIteratorType; UCharIteratorType uchar_img_iterator; uchar_img_iterator = UCharIteratorType (uchar_img, uchar_img->GetLargestPossibleRegion()); uchar_img_iterator.GoToBegin(); UCharIteratorType box_img_iterator; box_img_iterator = UCharIteratorType (box_img, box_img->GetLargestPossibleRegion()); box_img_iterator.GoToBegin(); typedef itk::ImageRegionIteratorWithIndex< FloatImageType > FloatIteratorType; FloatIteratorType img_in_iterator (img_in, img_in->GetLargestPossibleRegion()); FloatImageType::IndexType k, k_max; FloatPoint3DType phys, phys_max; phys_max[0] = phys_max[1] = phys_max[2] = 0.f; float level, maxlevel=-1e20; for (img_in_iterator.GoToBegin(); !img_in_iterator.IsAtEnd(); ++img_in_iterator) { k=img_in_iterator.GetIndex(); // img_in->TransformIndexToPhysicalPoint( k, phys ); level = img_in_iterator.Get(); //NSh 2012-05-30 - find position of the max over the entire image, disregarding the box /* if ( (parms->center[0]- parms->boxsize[0]/2 <= k[0] && k[0] < parms->center[0]+parms->boxsize[0]/2) && (parms->center[1]- parms->boxsize[1]/2 <= k[1] && k[1] < parms->center[1]+parms->boxsize[1]/2) && (parms->center[2]- parms->boxsize[2]/2 <= k[2] && k[2] < parms->center[2]+parms->boxsize[2]/2) ) */ { if (level> maxlevel) { maxlevel = level; k_max = img_in_iterator.GetIndex(); img_in->TransformIndexToPhysicalPoint(k_max, phys_max); } } } //char fn_tmp[1024]; //sprintf(fn_tmp, "c:\\cygwin\\home\\nadya\\%s", parms->max_coord_fn_out); FILE *fp0 = fopen( parms->max_coord_fn_out, "w"); //FILE *fp0 = fopen( fn_tmp, "w"); if (fp0) { fprintf(fp0, "max_coord\n%.3f %.3f %.3f\n", phys_max[0],phys_max[1],phys_max[2]); fclose(fp0); } int label_onecount=0; for (img_in_iterator.GoToBegin(); !img_in_iterator.IsAtEnd(); ++img_in_iterator) { level = img_in_iterator.Get(); k=img_in_iterator.GetIndex(); //img_in->TransformIndexToPhysicalPoint( k, phys ); label_uchar = 0; label_box = 0; if ( (parms->center[0]- parms->boxsize[0]/2 <= k[0] && k[0] < parms->center[0]+parms->boxsize[0]/2) && (parms->center[1]- parms->boxsize[1]/2 <= k[1] && k[1] < parms->center[1]+parms->boxsize[1]/2) && (parms->center[2]- parms->boxsize[2]/2 <= k[2] && k[2] < parms->center[2]+parms->boxsize[2]/2) ) { /* label_uchar = 2; */ label_box=1; } if ( (parms->center[0] - parms->boxsize[0]/2 <= k[0] && k[0] < parms->center[0]+parms->boxsize[0]/2) && (parms->center[1] - parms->boxsize[1]/2 <= k[1] && k[1] < parms->center[1]+parms->boxsize[1]/2) && (parms->center[2] - parms->boxsize[2]/2 <= k[2] && k[2] < parms->center[2]+parms->boxsize[2]/2) ) if (level > parms->threshold/100.*maxlevel) { label_uchar = 1; label_onecount++; } uchar_img_iterator.Set ( label_uchar ); box_img_iterator.Set ( label_box ); ++uchar_img_iterator; ++box_img_iterator; } parms->img_out = new Plm_image; parms->img_out->set_itk( uchar_img); parms->img_box = new Plm_image; parms->img_box->set_itk( box_img); } void do_overlap_fraction( Threshbox_parms *parms) { double vol_img1=0, vol_img2=0, vol_min=0, vol_overlap=0, max_sep; int level1, level2, level11, level22; int vol_img1_int = 0, vol_img2_int=0; FloatPoint3DType phys_max1, phys_max2; UCharImageType::IndexType k_max1, k_max2; UCharImageType::IndexType kcurr; FloatPoint3DType phys; UCharImageType::Pointer img1 = parms->overlap_labelmap1->itk_uchar(); UCharImageType::Pointer img2 = parms->overlap_labelmap2->itk_uchar(); typedef itk::ImageRegionIteratorWithIndex< UCharImageType > UCharIteratorType; UCharIteratorType img1_iterator; img1_iterator = UCharIteratorType (img1, img1->GetLargestPossibleRegion()); img1_iterator.GoToBegin(); UCharIteratorType img2_iterator; img2_iterator = UCharIteratorType (img2, img2->GetLargestPossibleRegion()); img2_iterator.GoToBegin(); for (img1_iterator.GoToBegin(); !img1_iterator.IsAtEnd(); ++img1_iterator) { level1 = img1_iterator.Get(); if ( level1>0 ) { vol_img1++; vol_img1_int++;} } for (img2_iterator.GoToBegin(); !img2_iterator.IsAtEnd(); ++img2_iterator) { level2 = img2_iterator.Get(); if ( level2>0 ) { vol_img2++; vol_img2_int++;} } // diameter of the labelmap thresholded image float *xone = (float *)malloc(vol_img1_int*sizeof(float)); float *yone = (float *)malloc(vol_img1_int*sizeof(float)); float *zone = (float *)malloc(vol_img1_int*sizeof(float)); int j=0; for (img1_iterator.GoToBegin(); !img1_iterator.IsAtEnd(); ++img1_iterator) { int level = img1_iterator.Get(); if (level>0) { kcurr=img1_iterator.GetIndex(); img1->TransformIndexToPhysicalPoint( kcurr, phys ); xone[j]=phys[0];yone[j]=phys[1];zone[j]=phys[2]; if (j>vol_img1_int) { fprintf(stderr,"inconsistent labelmap vox count!\n"); exit(1);} j++; } } int i1,i2; float diam1=-1; for(i1=0;i1diam1) diam1=d; } free(xone);free(yone);free(zone); xone = (float *)malloc(vol_img2_int*sizeof(float)); yone = (float *)malloc(vol_img2_int*sizeof(float)); zone = (float *)malloc(vol_img2_int*sizeof(float)); j=0; for (img2_iterator.GoToBegin(); !img2_iterator.IsAtEnd(); ++img2_iterator) { int level = img2_iterator.Get(); if (level>0) { kcurr=img2_iterator.GetIndex(); img2->TransformIndexToPhysicalPoint( kcurr, phys ); xone[j]=phys[0];yone[j]=phys[1];zone[j]=phys[2]; if (j>vol_img2_int) { fprintf(stderr,"inconsistent labelmap vox count!\n"); exit(1);} j++; } } // int i1,i2; float diam2=-1; for(i1=0;i1diam2) diam2=d; } free(xone);free(yone);free(zone); printf("%s\n%s\n", parms->max_coord_fn_in1, parms->max_coord_fn_in2); FILE *fp1 = fopen( parms->max_coord_fn_in1, "r"); char tmpbuf[1024]; if (fp1) { fscanf(fp1, "%s", tmpbuf); fscanf(fp1, "%f %f %f", &phys_max1[0], &phys_max1[1], &phys_max1[2]); printf("read %f %f %f from %s\n", phys_max1[0],phys_max1[1],phys_max1[2], parms->max_coord_fn_in1); fclose(fp1); } FILE *fp2 = fopen( parms->max_coord_fn_in2, "r"); //char tmpbuf[1024]; if (fp2) { fscanf(fp2, "%s", tmpbuf); fscanf(fp2, "%f %f %f", &phys_max2[0], &phys_max2[1], &phys_max2[2]); printf("read %f %f %f from %s\n", phys_max2[0],phys_max2[1],phys_max2[2], parms->max_coord_fn_in2); fclose(fp2); } max_sep = (phys_max1[0] - phys_max2[0])*(phys_max1[0] - phys_max2[0])+ (phys_max1[1] - phys_max2[1])*(phys_max1[1] - phys_max2[1])+ (phys_max1[2] - phys_max2[2])*(phys_max1[2] - phys_max2[2]); max_sep = sqrt(max_sep); printf("max_sep %f\n", max_sep); // FloatPoint3DType phys; bool in_image; UCharImageType::IndexType k1; UCharImageType::IndexType k2; img1_iterator = UCharIteratorType (img1, img1->GetLargestPossibleRegion()); img1_iterator.GoToBegin(); for (img1_iterator.GoToBegin(); !img1_iterator.IsAtEnd(); ++img1_iterator) { /*make sure we can process images with different offsets etc*/ k1=img1_iterator.GetIndex(); img1->TransformIndexToPhysicalPoint( k1, phys ); in_image = img2->TransformPhysicalPointToIndex( phys, k2) ; if (in_image) { level1 = img1->GetPixel(k1); level2 = img2->GetPixel(k2); if (level1 >0 && level2 > 0) vol_overlap++; } } if (vol_img1TransformPhysicalPointToIndex(phys_max1, k_max1); img2->TransformPhysicalPointToIndex(phys_max1, k_max2); level11 = img1->GetPixel(k_max1); level22 = img2->GetPixel(k_max2); if (level11 > 0 && level22 > 0 ) max1_in = 1; else max1_in = 0; int max2_in; img1->TransformPhysicalPointToIndex(phys_max2, k_max1); img2->TransformPhysicalPointToIndex(phys_max2, k_max2); level11 = img1->GetPixel(k_max1); level22 = img2->GetPixel(k_max2); if (level11 > 0 && level22 > 0 ) max2_in = 1; else max2_in = 0; int over_max = -1; UNUSED_VARIABLE (over_max); if ( max1_in==1 && max2_in==1 ) over_max = 0; // two suv max are in the overlap volume if ( max1_in==1 && max2_in==0 ) over_max = 1; // suv max 1 is in the overlap volume, suv max 2 is outside if ( max1_in==0 && max2_in==1 ) over_max = 2; // suv max 2 is in the overlap volume, suv max 1 is outside if ( max1_in==0 && max2_in==0 ) over_max = 3; // both suv max are outside overlap volume printf("trying to write %s\n", parms->overlap_fn_out); //return; FILE *fpout = fopen( parms->overlap_fn_out, "w"); if (fpout) { fprintf(fpout, "Vol1 %.1f Vol2 %.1f Volmin %.1f Vover %.1f (voxels)\n", vol_img1,vol_img2, vol_min, vol_overlap); /*fprintf(fpout, "Vover/Volmin = %.3f MaxSep = %.3f SUV max location = %d\n", vol_overlap/vol_min, max_sep, over_max );*/ fprintf(fpout, "Vover/Volmin = %.3f", vol_overlap/vol_min ); float voxvol1; float spacing1[3]; Plm_image_header pih_overlap1 ( parms->overlap_labelmap1 ); pih_overlap1.get_spacing(spacing1); voxvol1=spacing1[0]*spacing1[1]*spacing1[2]; float voxvol2; float spacing2[3]; Plm_image_header pih_overlap2 ( parms->overlap_labelmap2 ); pih_overlap2.get_spacing(spacing2); voxvol2=spacing2[0]*spacing2[1]*spacing2[2]; fprintf(fpout, "Vol1cm3 %.4f Vol2cm3 %.4f\n", vol_img1*voxvol1/1000., vol_img2*voxvol2/1000. ); fprintf(fpout, "diam1mm %f diam2mm %f\n",diam1,diam2); fclose(fpout); } } /* void remove_face_connected_regions(img...) http://www.itk.org/Doxygen314/html/classitk_1_1ConnectedThresholdImageFilter.html iterate over src image { if (! on_threshbox_face) continue; if GetPix(src)==0 continue; seed on the threshbox face = current voxel create itk::ConnectedThresholdImageFilter virtual void itk::ImageToImageFilter< TInputImage, TOutputImage >::SetInput ( const InputImageType * image ) [virtual] virtual void itk::ConnectedThresholdImageFilter< TInputImage, TOutputImage >::SetReplaceValue ( OutputImagePixelType _arg ) [virtual] //Set/Get value to replace thresholded pixels. Pixels that lie * within Lower and Upper //(inclusive) will be replaced with this value. The default is 1. void itk::ConnectedThresholdImageFilter< TInputImage, TOutputImage >::SetSeed ( const IndexType & seed ) virtual void itk::ConnectedThresholdImageFilter< TInputImage, TOutputImage >::SetUpper ( InputImagePixelType ) [virtual] //also SetLower? -> set both to 1. someFilter->Update(); image = someFilter->GetOutput(); iterate over src image if ( GetPix( src)>0 && GetPix(filtered)==filterlabel ) Pix(src)=0 delete filter } subtract 1 from nonzero pixels in src */ /* thresholders for dose comparison plugin*/ static void do_single_threshold( Threshbox_parms *parms ,int thresh_id ) { float spacing_in[3], origin_in[3]; plm_long dim_in[3]; Plm_image_header pih; unsigned char label_uchar; float cutoff = 0; if (thresh_id == 1 ) cutoff = parms->isodose_value1; if (thresh_id == 2 ) cutoff = parms->isodose_value2; if (thresh_id == 3 ) cutoff = parms->isodose_value3; if (thresh_id == 4 ) cutoff = parms->isodose_value4; if (thresh_id == 5 ) cutoff = parms->isodose_value5; FloatImageType::Pointer img_in = parms->img_in->itk_float(); pih.set_from_itk_image (img_in); pih.get_dim (dim_in); pih.get_origin (origin_in ); pih.get_spacing (spacing_in ); // direction cosines?? /* Create ITK image for labelmap */ FloatImageType::SizeType sz; FloatImageType::IndexType st; FloatImageType::RegionType rg; FloatImageType::PointType og; FloatImageType::SpacingType sp; FloatImageType::DirectionType itk_dc; for (int d1 = 0; d1 < 3; d1++) { st[d1] = 0; sz[d1] = dim_in[d1]; sp[d1] = spacing_in[d1]; og[d1] = origin_in[d1]; } rg.SetSize (sz); rg.SetIndex (st); itk_direction_from_dc (&itk_dc, parms->dc); // labelmap thresholded image UCharImageType::Pointer uchar_img = UCharImageType::New(); uchar_img->SetRegions (rg); uchar_img->SetOrigin (og); uchar_img->SetSpacing (sp); uchar_img->Allocate(); typedef itk::ImageRegionIteratorWithIndex< UCharImageType > UCharIteratorType; UCharIteratorType uchar_img_iterator; uchar_img_iterator = UCharIteratorType (uchar_img, uchar_img->GetLargestPossibleRegion()); uchar_img_iterator.GoToBegin(); typedef itk::ImageRegionIteratorWithIndex< FloatImageType > FloatIteratorType; FloatIteratorType img_in_iterator (img_in, img_in->GetLargestPossibleRegion()); FloatImageType::IndexType k; FloatPoint3DType phys; float level; for (img_in_iterator.GoToBegin(); !img_in_iterator.IsAtEnd(); ++img_in_iterator) { level = img_in_iterator.Get(); k=img_in_iterator.GetIndex(); //img_in->TransformIndexToPhysicalPoint( k, phys ); label_uchar = 0; if (level > cutoff ) label_uchar = thresh_id; uchar_img_iterator.Set ( label_uchar ); ++uchar_img_iterator; } if (thresh_id == 1 ) { parms->dose_labelmap1 = new Plm_image; parms->dose_labelmap1->set_itk( uchar_img); } if (thresh_id == 2 ) { parms->dose_labelmap2 = new Plm_image; parms->dose_labelmap2->set_itk( uchar_img); } if (thresh_id == 3 ) { parms->dose_labelmap3 = new Plm_image; parms->dose_labelmap3->set_itk( uchar_img); } if (thresh_id == 4 ) { parms->dose_labelmap4 = new Plm_image; parms->dose_labelmap4->set_itk( uchar_img); } if (thresh_id == 5 ) { parms->dose_labelmap5 = new Plm_image; parms->dose_labelmap5->set_itk( uchar_img); } } void do_composite_labelmap( Threshbox_parms *parms) { float spacing_in[3], origin_in[3]; plm_long dim_in[3]; Plm_image_header pih; unsigned char label_uchar; unsigned char level[5]; UCharImageType::Pointer map1 = parms->dose_labelmap1->itk_uchar(); UCharImageType::Pointer map2 = parms->dose_labelmap2->itk_uchar(); UCharImageType::Pointer map3 = parms->dose_labelmap3->itk_uchar(); UCharImageType::Pointer map4 = parms->dose_labelmap4->itk_uchar(); UCharImageType::Pointer map5 = parms->dose_labelmap5->itk_uchar(); pih.set_from_itk_image (map1); pih.get_dim (dim_in); pih.get_origin (origin_in ); pih.get_spacing (spacing_in ); // direction cosines?? /* Create ITK image for labelmap */ FloatImageType::SizeType sz; FloatImageType::IndexType st; FloatImageType::RegionType rg; FloatImageType::PointType og; FloatImageType::SpacingType sp; FloatImageType::DirectionType itk_dc; for (int d1 = 0; d1 < 3; d1++) { st[d1] = 0; sz[d1] = dim_in[d1]; sp[d1] = spacing_in[d1]; og[d1] = origin_in[d1]; } rg.SetSize (sz); rg.SetIndex (st); itk_direction_from_dc (&itk_dc, parms->dc); // labelmap thresholded image UCharImageType::Pointer uchar_img = UCharImageType::New(); uchar_img->SetRegions (rg); uchar_img->SetOrigin (og); uchar_img->SetSpacing (sp); uchar_img->Allocate(); typedef itk::ImageRegionIteratorWithIndex< UCharImageType > UCharIteratorType; UCharIteratorType it1, it2, it3, it4, it5, it_compo; it1 = UCharIteratorType (map1, map1->GetLargestPossibleRegion()); it2 = UCharIteratorType (map2, map2->GetLargestPossibleRegion()); it3 = UCharIteratorType (map3, map3->GetLargestPossibleRegion()); it4 = UCharIteratorType (map4, map4->GetLargestPossibleRegion()); it5 = UCharIteratorType (map5, map5->GetLargestPossibleRegion()); it_compo = UCharIteratorType (uchar_img, uchar_img->GetLargestPossibleRegion()); it1.GoToBegin(); it2.GoToBegin();it3.GoToBegin();it4.GoToBegin();it5.GoToBegin(); it_compo.GoToBegin(); for (it1.GoToBegin(); !it1.IsAtEnd(); ++it1) { level[0] = it1.Get(); level[1] = it2.Get(); level[2] = it3.Get(); level[3] = it4.Get(); level[4] = it5.Get(); label_uchar = level[0]; int i; for(i=0; i<5; i++) { if (level[i]>label_uchar) label_uchar = level[i]; } it_compo.Set ( label_uchar ); ++it2; ++it3; ++it4; ++it5; ++it_compo; } parms->composite_labelmap = new Plm_image; parms->composite_labelmap->set_itk( uchar_img); } void do_multi_threshold (Threshbox_parms *parms) { do_single_threshold( parms, 1); do_single_threshold( parms, 2); do_single_threshold( parms, 3); do_single_threshold( parms, 4); do_single_threshold( parms, 5); /* assumes that threshold increases with thresh_id!! */ do_composite_labelmap( parms ); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/threshbox.h000066400000000000000000000026371321604176500277630ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _threshbox_h_ #define _threshbox_h_ #include "plmutil_config.h" #include "direction_cosines.h" #include "plm_image.h" class Threshbox_parms { public: int center[3]; int boxsize[3]; int threshold; Direction_cosines dc; Plm_image::Pointer img_in; Plm_image *img_out; Plm_image *img_box; Plm_image::Pointer overlap_labelmap1; Plm_image::Pointer overlap_labelmap2; char overlap_fn_out[1024]; char max_coord_fn_out[1024]; char max_coord_fn_in1[1024]; char max_coord_fn_in2[1024]; /* for dose comparison plugin */ int isodose_value1, isodose_value2, isodose_value3, isodose_value4, isodose_value5; Plm_image *dose_labelmap1, *dose_labelmap2, *dose_labelmap3, *dose_labelmap4, *dose_labelmap5, *composite_labelmap; public: Threshbox_parms () { center[0]=100; center[1]=100; center[2]=100; boxsize[0]=10; boxsize[1]=10; boxsize[2]=10; threshold=80; } }; PLMUTIL_C_API void do_threshbox (Threshbox_parms *parms); PLMUTIL_C_API void do_overlap_fraction (Threshbox_parms *parms); PLMUTIL_C_API void do_multi_threshold (Threshbox_parms *parms); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/vf_invert.cxx000066400000000000000000000136661321604176500303360ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plm_config.h" #if (OPENMP_FOUND) #include #endif #include "geometry_chooser.h" #include "itk_image_load.h" #include "logfile.h" #include "plm_image_header.h" #include "plm_int.h" #include "vf_convolve.h" #include "vf_invert.h" #include "volume.h" #include "volume_header.h" #include "xform.h" class Vf_invert_private { public: Vf_invert_private () { iterations = 20; vf_out = 0; } ~Vf_invert_private () { delete vf_out; } public: int iterations; Geometry_chooser gchooser; DeformationFieldType::Pointer input_vf; Volume *vf_out; }; Vf_invert::Vf_invert () { this->d_ptr = new Vf_invert_private; } Vf_invert::~Vf_invert () { delete this->d_ptr; } void Vf_invert::set_input_vf (const char* vf_fn) { d_ptr->input_vf = itk_image_load_float_field (vf_fn); d_ptr->gchooser.set_reference_image (d_ptr->input_vf); } void Vf_invert::set_input_vf ( const DeformationFieldType::Pointer vf) { d_ptr->input_vf = vf; d_ptr->gchooser.set_reference_image (d_ptr->input_vf); } void Vf_invert::set_fixed_image (const char* image_fn) { d_ptr->gchooser.set_fixed_image (image_fn); } void Vf_invert::set_fixed_image ( const FloatImageType::Pointer image) { d_ptr->gchooser.set_fixed_image (image); } void Vf_invert::set_dim (const plm_long dim[3]) { d_ptr->gchooser.set_dim (dim); } void Vf_invert::set_origin (const float origin[3]) { d_ptr->gchooser.set_origin (origin); } void Vf_invert::set_spacing (const float spacing[3]) { d_ptr->gchooser.set_spacing (spacing); } void Vf_invert::set_direction_cosines (const float direction_cosines[9]) { Direction_cosines dc (direction_cosines); d_ptr->gchooser.set_direction_cosines (dc); } void Vf_invert::set_iterations (int iterations) { d_ptr->iterations = iterations; } void Vf_invert::run () { /* Compute geometry of output volume */ const Plm_image_header *pih = d_ptr->gchooser.get_geometry (); Volume_header vh (pih); /* Create mask volume */ Volume *mask = new Volume (vh, PT_UCHAR, 1); /* Create tmp volume */ Volume *vf_inv = new Volume (vh, PT_VF_FLOAT_INTERLEAVED, 1); /* Convert input vf to native, interleaved format */ Xform xf_itk; xf_itk.set_itk_vf (d_ptr->input_vf); Xform *xf = new Xform; const Plm_image_header pih_in (d_ptr->input_vf); xform_to_gpuit_vf (xf, &xf_itk, &pih_in); Volume::Pointer vf_in = xf->get_gpuit_vf (); vf_convert_to_interleaved (vf_in.get()); /* Populate mask & tmp volume */ unsigned char *img_mask = (unsigned char*) mask->img; float *img_in = (float*) vf_in->img; float *img_inv = (float*) vf_inv->img; #pragma omp parallel for LOOP_Z_OMP (k, vf_in) { plm_long fijk[3]; /* Index within fixed image (vox) */ float fxyz[3]; /* Position within fixed image (mm) */ fijk[2] = k; fxyz[2] = vf_in->origin[2] + fijk[2] * vf_in->step[2*3+2]; LOOP_Y (fijk, fxyz, vf_in) { LOOP_X (fijk, fxyz, vf_in) { float mijk[3]; plm_long mijk_r[3], midx; plm_long v = volume_index (vf_in->dim, fijk); float *dxyz = &img_in[3*v]; float mo_xyz[3] = { fxyz[0] + dxyz[0] - vf_inv->origin[0], fxyz[1] + dxyz[1] - vf_inv->origin[1], fxyz[2] + dxyz[2] - vf_inv->origin[2] }; mijk[2] = PROJECT_Z(mo_xyz,vf_inv->proj); mijk[1] = PROJECT_Y(mo_xyz,vf_inv->proj); mijk[0] = PROJECT_X(mo_xyz,vf_inv->proj); if (!vf_inv->is_inside (mijk)) continue; mijk_r[2] = ROUND_PLM_LONG (mijk[2]); mijk_r[1] = ROUND_PLM_LONG (mijk[1]); mijk_r[0] = ROUND_PLM_LONG (mijk[0]); midx = volume_index (vf_inv->dim, mijk_r); img_inv[3*midx+0] = -img_in[3*v+0]; img_inv[3*midx+1] = -img_in[3*v+1]; img_inv[3*midx+2] = -img_in[3*v+2]; img_mask[midx] ++; } } } /* We're done with input volume now. */ delete xf; /* Create tmp & output volumes */ Volume *vf_out = new Volume (vh, PT_VF_FLOAT_INTERLEAVED, 3); float *img_out = (float*) vf_out->img; Volume *vf_smooth = new Volume (vh, PT_VF_FLOAT_INTERLEAVED, 3); float *img_smooth = (float*) vf_smooth->img; /* Iterate, pasting and smoothing */ printf ("Paste and smooth loop\n"); for (int it = 0; it < d_ptr->iterations; it++) { printf ("Iteration %d/%d\n", it, d_ptr->iterations); /* Paste */ for (plm_long v = 0, k = 0; k < vf_out->dim[2]; k++) { for (plm_long j = 0; j < vf_out->dim[1]; j++) { for (plm_long i = 0; i < vf_out->dim[0]; i++, v++) { if (img_mask[v]) { img_smooth[3*v+0] = img_inv[3*v+0]; img_smooth[3*v+1] = img_inv[3*v+1]; img_smooth[3*v+2] = img_inv[3*v+2]; } else { img_smooth[3*v+0] = img_out[3*v+0]; img_smooth[3*v+1] = img_out[3*v+1]; img_smooth[3*v+2] = img_out[3*v+2]; } } } } /* Smooth the estimate into vf_out. The volumes are ping-ponged. */ float ker[3] = { 0.3, 0.4, 0.3 }; printf ("Convolving\n"); vf_convolve_x (vf_out, vf_smooth, ker, 3); vf_convolve_y (vf_smooth, vf_out, ker, 3); vf_convolve_z (vf_out, vf_smooth, ker, 3); } printf ("Done.\n"); /* We're done with all these images now */ delete mask; delete vf_inv; delete vf_smooth; /* Save the output image! */ d_ptr->vf_out = vf_out; } const Volume* Vf_invert::get_output_volume () { return d_ptr->vf_out; } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/vf_invert.h000066400000000000000000000042111321604176500277450ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _vf_invert_h_ #define _vf_invert_h_ #include "plmutil_config.h" #include "itk_image_type.h" class Vf_invert_private; class PLMUTIL_API Vf_invert { public: Vf_invert (); ~Vf_invert (); public: Vf_invert_private *d_ptr; public: /*! \name Inputs */ ///@{ /*! \brief Set the input vector field to be inverted. The vector field will be loaded from the specified filename. */ void set_input_vf (const char* vf_fn); /*! \brief Set the input vector field to be inverted as an ITK image. */ void set_input_vf (const DeformationFieldType::Pointer vf); /*! \brief Set the geometry of the output vector field to match another image. The image will be loaded from the specified filename. */ void set_fixed_image (const char* image_fn); /*! \brief Set the geometry of the output vector field to match another image, specified as an ITK image. */ void set_fixed_image (const FloatImageType::Pointer image); /*! \brief Set the image dimension (number of voxels) of the output vector field. */ void set_dim (const plm_long dim[3]); /*! \brief Set the image origin of the output vector field. */ void set_origin (const float origin[3]); /*! \brief Set the image spacing of the output vector field. */ void set_spacing (const float spacing[3]); /*! \brief Set the image direction cosines of the output vector field. */ void set_direction_cosines (const float direction_cosines[9]); /*! \brief Set the number of iterations to run the inversion routine (default is 20 iterations). */ void set_iterations (int iterations); ///@} /*! \name Execution */ ///@{ /*! \brief Compute inverse vector field */ void run (); ///@} /*! \name Outputs */ ///@{ /*! \brief Return the inverse vector field as a Volume*. */ const Volume* get_output_volume (); ///@} }; #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/volume_adjust.cxx000066400000000000000000000021451321604176500312030ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #include "plmutil_config.h" #include #include "float_pair_list.h" #include "plm_math.h" #include "print_and_exit.h" #include "pwlut.h" #include "volume.h" #include "volume_adjust.h" Volume::Pointer volume_adjust (const Volume::Pointer& image_in, const Float_pair_list& al) { Volume::Pointer vol_out = image_in->clone (PT_FLOAT); float *vol_img = vol_out->get_raw (); Pwlut pwlut; pwlut.set_lut (al); for (plm_long v = 0; v < vol_out->npix; v++) { vol_img[v] = pwlut.lookup (vol_img[v]); } return vol_out; } Volume::Pointer volume_adjust (const Volume::Pointer& image_in, const std::string& adj_string) { Float_pair_list al = parse_float_pairs (adj_string); if (al.empty()) { print_and_exit ("Error: couldn't parse adjust string: %s\n", adj_string.c_str()); } return volume_adjust (image_in, al); } plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/volume_adjust.h000066400000000000000000000010571321604176500306310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _volume_adjust_h_ #define _volume_adjust_h_ #include "plmutil_config.h" #include "float_pair_list.h" PLMUTIL_API Volume::Pointer volume_adjust (const Volume::Pointer& image_in, const Float_pair_list& al); PLMUTIL_API Volume::Pointer volume_adjust (const Volume::Pointer& image_in, const std::string& adj_string); #endif plastimatch-v1.7.0-7440a8cfff7b7dcf317c40d6b04029827065303f/src/plastimatch/util/warp_parms.h000066400000000000000000000063461321604176500301310ustar00rootroot00000000000000/* ----------------------------------------------------------------------- See COPYRIGHT.TXT and LICENSE.TXT for copyright and license information ----------------------------------------------------------------------- */ #ifndef _warp_parms_h_ #define _warp_parms_h_ #include "plmutil_config.h" #include #include "direction_cosines.h" #include "plm_image_type.h" #include "plm_int.h" #include "xio_studyset.h" class Warp_parms { public: /* Input files */ std::string input_fn; std::string xf_in_fn; std::string referenced_dicom_dir; std::string input_cxt_fn; std::string input_prefix; std::string input_ss_img_fn; std::string input_ss_list_fn; std::string input_dose_img_fn; std::string input_dose_xio_fn; std::string input_dose_ast_fn; std::string input_dose_mc_fn; std::string fixed_img_fn; std::string dif_in_fn; /* Output files */ std::string output_colormap_fn; std::string output_cxt_fn; std::string output_dicom; std::string output_dij_fn; std::string output_dose_img_fn; std::string output_img_fn; std::string output_labelmap_fn; std::string output_pointset_fn; std::string output_prefix; std::string output_prefix_fcsv; std::string output_ss_img_fn; std::string output_ss_list_fn; std::string output_vf_fn; std::string output_xio_dirname; /* Output options */ Plm_image_type output_type; std::string prefix_format; bool dicom_with_uids; Xio_version output_xio_version; bool output_dij_dose_volumes; /* Algorithm options */ bool force_resample; float default_val; bool have_dose_scale; /* should we scale the dose image? */ float dose_scale; /* how much to scale the dose image */ int interp_lin; /* trilinear (1) or nn (0) */ int prune_empty; /* remove empty structures (1) or not (0) */ int use_itk; /* force use of itk (1) or not (0) */ int simplify_perc; /* percentage of points to be purged */ bool xor_contours; /* or/xor overlapping structure contours */ /* Geometry options */ bool m_have_dim; bool m_have_origin; bool m_have_spacing; bool m_have_direction_cosines; plm_long m_dim[3]; float m_origin[3]; float m_spacing[3]; Direction_cosines m_dc; /* Metadata options */ std::vector m_study_metadata; std::vector m_image_metadata; std::vector m_dose_metadata; std::vector m_rtstruct_metadata; bool retain_study_uids; bool image_series_uid_forced; public: Warp_parms () { /* Geometry options */ m_have_dim = false; m_have_origin = false; m_have_spacing = false; m_have_direction_cosines = false; /* Misc options */ have_dose_scale = false; dose_scale = 1.0f; force_resample = false; default_val = 0.0f; interp_lin = 1; output_type = PLM_IMG_TYPE_UNDEFINED; prefix_format = "mha"; dicom_with_uids = true; output_xio_version = XIO_VERSION_4_2_1; output_dij_dose_volumes = false; prune_empty = 0; use_itk = 0; simplify_perc = 0; xor_contours = false; retain_study_uids = false; image_series_uid_forced = false; } }; #endif